www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Frontend and backend communication

reply "Dainius (GreatEmerald)" <pastas4 gmail.com> writes:
I have one program design problem and I wonder if anyone here could
give any suggestions about it. The situation is like this: I am
splitting a game into a frontend (a library) and a backend (an
executable). The backend is going to handle all the game mechanics,
while the frontend is going to handle I/O. But there are certain
problems. For example, now I have a function Shuffle() that calls
PlaySound(SHUFFLE). Shuffle() is a backend function, while PlaySound()
is a frontend one, so obviously it won't work that way after the
split. It would be ideal if there was a way to create hooks - say an
empty PlaySound() function that the frontend could receive calls to.
But I can't see a way to do that. Another way to do that that was
suggested to me was to use an event loop - set a global variable, then
have the frontend monitor it for changes and then respond as
necessary, but that just isn't a very clean way to do it.

And then there is the fact that the backend is going to be written in
D (right now it's a mix of C and D), while the frontend will be in C
(one of the frontends, anyway - the second one will also be in D). Any
suggestions about this?
Jul 27 2011
next sibling parent reply "Nick Sabalausky" <a a.a> writes:
"Dainius (GreatEmerald)" <pastas4 gmail.com> wrote in message 
news:mailman.1931.1311788506.14074.digitalmars-d-learn puremagic.com...
 For example, now I have a function Shuffle() that calls
 PlaySound(SHUFFLE). Shuffle() is a backend function, while PlaySound()
 is a frontend one, so obviously it won't work that way after the
 split.

Why not?
Jul 27 2011
next sibling parent reply novice2 <sorry noem.ail> writes:
Dainius (GreatEmerald) Wrote:

 No no. It's the other way round. Shuffle() is in the library
 (backend). PlaySound() is in the executable (frontend). Since I don't
 want the library to be dependent on any sound libraries, I can't have

would you pass playSound() as parameter (callback) to shuffle()?
Jul 27 2011
parent Kai Meyer <kai unixlords.com> writes:
On 07/28/2011 01:18 AM, Dainius (GreatEmerald) wrote:
 Hmm, there are still a whole lot of functions that call Shuffle(), so
 it might not be ideal. However, this gives me an idea - if a pointer
 to a function can be a parameter, can it be a global variable? In that
 case, the frontend would indeed be able to overwrite the function that
 the backend calls by simply altering that pointer.

Yes, you could create a "function table" and keep a list of all the functions that need to be called. You can then alter the behavior of one method at runtime with out having to pass a function as a parameter. Of course, global variables are tricky things, especially whe you're threaded. It's probably simplest to just pass the function pointer as a parameter to Shuffle(). If Shuffle() indeed has multiple entry points, and they all fight to have their version of PlaySound() run at the end of Shuffle(), then you may run into problems. -Kai Meyer
Jul 28 2011
prev sibling parent reply Kai Meyer <kai unixlords.com> writes:
On 07/27/2011 04:40 PM, Dainius (GreatEmerald) wrote:
 No no. It's the other way round. Shuffle() is in the library
 (backend). PlaySound() is in the executable (frontend). Since I don't
 want the library to be dependent on any sound libraries, I can't have
 PlaySound() in it. And there is no other way that I can think of to
 execute PlaySound() just at the end of Shuffle() without capturing
 events (since Shuffle() itself is called by a whole lot of different
 functions across the library, and not from the executable itself).

One reason for the confusing responses is that in your original post you said: "a frontend (a library)", "a backend (an executable)", "Shuffle() is a backend function", and "PlaySound() is a frontend one". Frontend->library->Shuffle() Backend->executable->PlaySound() Then in this email, you say: "Shuffle() is in the library (backend)", and "PlaySound() is in the executable (frontend)" Backend->library->Shuffle() Frontend->executable->PlaySound() I'm assuming that this is the more correct version. Depending on what PlaySound needs, you can pass the function as a parameter to Shuffle().
Jul 28 2011
parent reply Jacob Carlborg <doob me.com> writes:
On 2011-07-28 21:55, Dainius (GreatEmerald) wrote:
 On Thu, Jul 28, 2011 at 10:37 PM, Kai Meyer<kai unixlords.com>  wrote:
 On 07/27/2011 04:40 PM, Dainius (GreatEmerald) wrote:

 One reason for the confusing responses is that in your original post you
 said:
 "a frontend (a library)", "a backend (an
 executable)", "Shuffle() is a backend function", and "PlaySound()
 is a frontend one".

D'oh I missed! I did indeed mean the other way round. But yea, I have already implemented a function table. It seems to be working relatively fine for now - it compiled, but doesn't want to link just yet. On Windows, it says that there are undefined symbols, even though they are quite clearly defined, and then also quite a few more mangled linker errors; On Linux, my main development platform, however, I have hit a pretty obvious issue - there is no libphobos2.so, and I can't link against libphobos2.a because of this: ld: /lib64/libphobos2.a(object_.o): relocation R_X86_64_32 against `.data' can not be used when making a shared object; recompile with -fPIC And then there's another problem in that right now the backend is still written in C and it uses D as a static library, and linking against that provides a similar error. Of course, since I will have to rewrite the backend in D to begin with, this might not be such a big of an issue as the first one.

Yeah, phobos/druntime doesn't work as a dynamic library yet on Linux or Windows. -- /Jacob Carlborg
Jul 28 2011
parent reply Jesse Phillips <jessekphillips+D gmail.com> writes:
Dainius (GreatEmerald) Wrote:

 So, now my (static) library nearly links in Win32. There is only one
 link error, and apparently it's generated by phobos:
 
     ..\lib\phobos.lib(dmain2)
      Error 42: Symbol Undefined __end
 
 Any clues about what is happening? Admittedly, that phobos.lib is from
 March 20, 2011, so it's rather old by now.

I didn't follow this discussion, but it is telling you there is no main function. Are you compiling a library? Maybe you should try giving your program a main?
Jul 29 2011
parent Jacob Carlborg <doob me.com> writes:
On 2011-11-29 12:53, Dainius (GreatEmerald) wrote:
 I seem to have another problem with the function pointer approach. I
 am trying to set up a function that would pass the function pointers
 from C to D, and DMD refuses to compile it:

 If I have the function pointer struct with D calling convention
 pointers, like this:

      struct S_FrontendFunctions {
          void function(int) SoundPlay;
          void function() RedrawScreen;
      }
      S_FrontendFunctions FrontendFunctions;

 And I try to set it in D like this:

      FrontendFunctions.SoundPlay = function(int){};
      FrontendFunctions.RedrawScreen = function(){};

 And have a function for transferring the pointer from C like this:

      extern (C):
      void SetRedrawScreen(void function() RedrawScreen)
      {
          FrontendFunctions.RedrawScreen = RedrawScreen;
      }

 DMD throws an error in the last function:

      Error: cannot implicitly convert expression (RedrawScreen) of type
 extern (C) void function() to void function()

 Now if I define the two function pointers as extern(C) like this:

      struct S_FrontendFunctions {
          extern (C) void function(int) SoundPlay;
          extern (C)  void function() RedrawScreen;
      }

 DMD still complains, but this time about when I set the pointers from
 D directly:

      Error: cannot implicitly convert expression (__funcliteral3) of
 type void function() pure nothrow  safe to extern (C) void function()

 Any ideas about how to make it work from both D and C sides?

In stead of doing this: FrontendFunctions.SoundPlay = function(int){}; FrontendFunctions.RedrawScreen = function(){}; Do something like this: extern (C) { void playSound (int) {}; void redrawScreen () {}; } FrontendFunctions.SoundPlay = &playSound; FrontendFunctions.RedrawScreen = &RedrawScreen; -- /Jacob Carlborg
Nov 29 2011
prev sibling next sibling parent reply "Dainius (GreatEmerald)" <pastas4 gmail.com> writes:
Hm, well, at least I don't know how it's possible for a binary to
overwrite/capture a library's function. Would you care to give an
example?
Jul 27 2011
parent "Nick Sabalausky" <a a.a> writes:
"Dainius (GreatEmerald)" <pastas4 gmail.com> wrote in message 
news:mailman.1933.1311797423.14074.digitalmars-d-learn puremagic.com...
 Hm, well, at least I don't know how it's possible for a binary to
 overwrite/capture a library's function. Would you care to give an
 example?

I'm not sure what you mean "overwrite/capture". I thought you just needed to call a function in a library?
Jul 27 2011
prev sibling next sibling parent "Dainius (GreatEmerald)" <pastas4 gmail.com> writes:
No no. It's the other way round. Shuffle() is in the library
(backend). PlaySound() is in the executable (frontend). Since I don't
want the library to be dependent on any sound libraries, I can't have
PlaySound() in it. And there is no other way that I can think of to
execute PlaySound() just at the end of Shuffle() without capturing
events (since Shuffle() itself is called by a whole lot of different
functions across the library, and not from the executable itself).
Jul 27 2011
prev sibling next sibling parent "Dainius (GreatEmerald)" <pastas4 gmail.com> writes:
Hmm, there are still a whole lot of functions that call Shuffle(), so
it might not be ideal. However, this gives me an idea - if a pointer
to a function can be a parameter, can it be a global variable? In that
case, the frontend would indeed be able to overwrite the function that
the backend calls by simply altering that pointer.
Jul 28 2011
prev sibling next sibling parent reply Pelle <pelle.mansson gmail.com> writes:
On Wed, 27 Jul 2011 19:41:37 +0200, Dainius (GreatEmerald)  
<pastas4 gmail.com> wrote:

 I have one program design problem and I wonder if anyone here could
 give any suggestions about it. The situation is like this: I am
 splitting a game into a frontend (a library) and a backend (an
 executable). The backend is going to handle all the game mechanics,
 while the frontend is going to handle I/O. But there are certain
 problems. For example, now I have a function Shuffle() that calls
 PlaySound(SHUFFLE). Shuffle() is a backend function, while PlaySound()
 is a frontend one, so obviously it won't work that way after the
 split. It would be ideal if there was a way to create hooks - say an
 empty PlaySound() function that the frontend could receive calls to.
 But I can't see a way to do that. Another way to do that that was
 suggested to me was to use an event loop - set a global variable, then
 have the frontend monitor it for changes and then respond as
 necessary, but that just isn't a very clean way to do it.

 And then there is the fact that the backend is going to be written in
 D (right now it's a mix of C and D), while the frontend will be in C
 (one of the frontends, anyway - the second one will also be in D). Any
 suggestions about this?

You could use a struct of function pointers to define the interface, if you need it to work both in C and D. extern (C) struct FrontEndFunctions { void function(sound) playSound; ... } backend does myFrontEndFunctions.playSound(SHUFFLE); The front end: void myPlaySound(...) { ... } void main() { FrontEndFunctions functions; functions.playSound = &myPlaySound; ... etc for other functions ...; backend.initialize(functions); backend.run(); }
Jul 28 2011
parent novice2 <sorry noem.ail> writes:
Pelle Wrote:

 On Wed, 27 Jul 2011 19:41:37 +0200, Dainius (GreatEmerald)  
 You could use a struct of function pointers to define the interface, if

This is known approach in app, using plugin. For example, then open source FAR (File Archive Manager) exe load pluging dll, it fill strcuct with exe functions pointers, so plugin dll can use it
Jul 28 2011
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Wed, 27 Jul 2011 13:41:37 -0400, Dainius (GreatEmerald)  
<pastas4 gmail.com> wrote:

 I have one program design problem and I wonder if anyone here could
 give any suggestions about it. The situation is like this: I am
 splitting a game into a frontend (a library) and a backend (an
 executable). The backend is going to handle all the game mechanics,
 while the frontend is going to handle I/O. But there are certain
 problems. For example, now I have a function Shuffle() that calls
 PlaySound(SHUFFLE). Shuffle() is a backend function, while PlaySound()
 is a frontend one, so obviously it won't work that way after the
 split. It would be ideal if there was a way to create hooks - say an
 empty PlaySound() function that the frontend could receive calls to.
 But I can't see a way to do that. Another way to do that that was
 suggested to me was to use an event loop - set a global variable, then
 have the frontend monitor it for changes and then respond as
 necessary, but that just isn't a very clean way to do it.

Actually, an event loop is a good way to do it. If your front end is a GUI, it's already likely running an event loop. All you need to do is stick an event in the event queue. I'd examine how to create custom events for your front end's probably already existing event loop. -Steve
Jul 28 2011
prev sibling next sibling parent "Dainius (GreatEmerald)" <pastas4 gmail.com> writes:
On Thu, Jul 28, 2011 at 10:37 PM, Kai Meyer <kai unixlords.com> wrote:
 On 07/27/2011 04:40 PM, Dainius (GreatEmerald) wrote:

 One reason for the confusing responses is that in your original post you
 said:
 "a frontend (a library)", "a backend (an
 executable)", "Shuffle() is a backend function", and "PlaySound()
 is a frontend one".

D'oh I missed! I did indeed mean the other way round. But yea, I have already implemented a function table. It seems to be working relatively fine for now - it compiled, but doesn't want to link just yet. On Windows, it says that there are undefined symbols, even though they are quite clearly defined, and then also quite a few more mangled linker errors; On Linux, my main development platform, however, I have hit a pretty obvious issue - there is no libphobos2.so, and I can't link against libphobos2.a because of this: ld: /lib64/libphobos2.a(object_.o): relocation R_X86_64_32 against `.data' can not be used when making a shared object; recompile with -fPIC And then there's another problem in that right now the backend is still written in C and it uses D as a static library, and linking against that provides a similar error. Of course, since I will have to rewrite the backend in D to begin with, this might not be such a big of an issue as the first one.
Jul 28 2011
prev sibling next sibling parent "Dainius (GreatEmerald)" <pastas4 gmail.com> writes:
I see. Well, I guess I'll have to stick to static ones until this gets
sorted out.
Jul 29 2011
prev sibling next sibling parent "Dainius (GreatEmerald)" <pastas4 gmail.com> writes:
So, now my (static) library nearly links in Win32. There is only one
link error, and apparently it's generated by phobos:

    ..\lib\phobos.lib(dmain2)
     Error 42: Symbol Undefined __end

Any clues about what is happening? Admittedly, that phobos.lib is from
March 20, 2011, so it's rather old by now.
Jul 29 2011
prev sibling next sibling parent "Dainius (GreatEmerald)" <pastas4 gmail.com> writes:
Yes, this is a library, so a main() there would be rather pointless.
However, it seems that on many occasions compilers will simply not
acknowledge anything without one, so I guess at least a declaration is
in order... I'll have to try that out once I get back on Windows.

Meanwhile, on Linux, I am getting these linker errors instead:

    /usr/lib64/gcc/x86_64-suse-linux/4.5/../../../../lib64/libphobos2.a(datetime_3a6_1ec.o):
In function `_D3std8datetime5Clock11currStdTimeFNdNeZl':
    std/datetime.d:(.text._D3std8datetime5Clock11currStdTimeFNdNeZl+0x1d):
undefined reference to `clock_gettime'
    /usr/lib64/gcc/x86_64-suse-linux/4.5/../../../../lib64/libphobos2.a(time_c6_4d1.o):
In function `_D4core4time12TickDuration12_staticCtor7OFNeZv':
    src/core/time.d:(.text._D4core4time12TickDuration12_staticCtor7OFNeZv+0x1f):
undefined reference to `clock_getres'
    /usr/lib64/gcc/x86_64-suse-linux/4.5/../../../../lib64/libphobos2.a(time_c6_4d1.o):
In function `_D4core4time12TickDuration14currSystemTickFNdNeZS4core4time12TickDuration':
    src/core/time.d:(.text._D4core4time12TickDuration14currSystemTickFNdNeZS4core4time12TickDuration+0x1f):
undefined reference to `clock_gettime'

Is it related, or is it a different issue altogether?

Also, apparently SDL and Lua don't like being statically linked. Good
thing the backend doesn't use SDL any more, then! And Lua does link,
although reluctantly and with linker warnings. Reportedly they are
nothing to worry about too much, but still...
Jul 29 2011
prev sibling next sibling parent "Dainius (GreatEmerald)" <pastas4 gmail.com> writes:
I seem to have run into a problem with the function pointer method
here. I have this code:

arco.d:

    struct FrontendFunctions {
        void function(SoundTypes) Sound_Play;
        void function() RedrawScreenFull;
        void function(const char*, int) PrecacheCard;
        void function(CardInfo, int) PlayCardAnimation;
    }

cards.d:

    void InitLuaFunctions()
    {
        lua["Damage"] = (int Who, int Amount)
        {
            FrontendFunctions.Sound_Play(SoundTypes.Damage);
        };
    }

Essentially I am trying to get Lua (via LuaD) to call a function in D
that calls a frontend function. But when I compile the code, I get
this: "cards.d(5): Error: 'this' is only defined in non-static member
functions, not __dgliteral14". Why is this and what can I do about it?
Aug 10 2011
prev sibling next sibling parent Pelle <pelle.mansson gmail.com> writes:
On Wed, 10 Aug 2011 10:35:46 +0200, Dainius (GreatEmerald)  
<pastas4 gmail.com> wrote:

 I seem to have run into a problem with the function pointer method
 here. I have this code:

 arco.d:

     struct FrontendFunctions {
         void function(SoundTypes) Sound_Play;
         void function() RedrawScreenFull;
         void function(const char*, int) PrecacheCard;
         void function(CardInfo, int) PlayCardAnimation;
     }

 cards.d:

     void InitLuaFunctions()
     {
         lua["Damage"] = (int Who, int Amount)
         {
             FrontendFunctions.Sound_Play(SoundTypes.Damage);
         };
     }

 Essentially I am trying to get Lua (via LuaD) to call a function in D
 that calls a frontend function. But when I compile the code, I get
 this: "cards.d(5): Error: 'this' is only defined in non-static member
 functions, not __dgliteral14". Why is this and what can I do about it?

FrontendFunctions frontendFunctions; use frontendFunctions everywhere. OR (this makes them global): struct FrontendFunctions { static: ... }
Aug 10 2011
prev sibling next sibling parent "Dainius (GreatEmerald)" <pastas4 gmail.com> writes:
Oh, so structs themselves are only definitions and not global
variables, I see. Thanks.
Aug 10 2011
prev sibling next sibling parent "Dainius (GreatEmerald)" <pastas4 gmail.com> writes:
I'm trying to implement the function pointer system right now, and it
seems to work on the C side, but not D. I assume I'm missing some kind
of syntax here. I have these global variables:

        struct S_FrontendFunctions {
            void function() RedrawScreen;
            void function(const char*, int) PrecacheCard;
        }
        shared S_FrontendFunctions FrontendFunctions;

And if I try to set the pointers D style, like this:

        FrontendFunctions.RedrawScreen = function(){};
        FrontendFunctions.PrecacheCard = function(const char*, int){};

I get errors:

        Error: cannot implicitly convert expression (__funcliteral3)
of type _error_ function() to shared(void function())
        Error: cannot implicitly convert expression (__funcliteral4)
of type _error_ function(const const(char*), int) to shared(void
function(const const(char*), int))

So how do I define those functions as shared?
Oct 18 2011
prev sibling next sibling parent "Dainius (GreatEmerald)" <pastas4 gmail.com> writes:
I seem to have another problem with the function pointer approach. I
am trying to set up a function that would pass the function pointers
from C to D, and DMD refuses to compile it:

If I have the function pointer struct with D calling convention
pointers, like this:

    struct S_FrontendFunctions {
        void function(int) SoundPlay;
        void function() RedrawScreen;
    }
    S_FrontendFunctions FrontendFunctions;

And I try to set it in D like this:

    FrontendFunctions.SoundPlay = function(int){};
    FrontendFunctions.RedrawScreen = function(){};

And have a function for transferring the pointer from C like this:

    extern (C):
    void SetRedrawScreen(void function() RedrawScreen)
    {
        FrontendFunctions.RedrawScreen = RedrawScreen;
    }

DMD throws an error in the last function:

    Error: cannot implicitly convert expression (RedrawScreen) of type
extern (C) void function() to void function()

Now if I define the two function pointers as extern(C) like this:

    struct S_FrontendFunctions {
        extern (C) void function(int) SoundPlay;
        extern (C)  void function() RedrawScreen;
    }

DMD still complains, but this time about when I set the pointers from
D directly:

    Error: cannot implicitly convert expression (__funcliteral3) of
type void function() pure nothrow  safe to extern (C) void function()

Any ideas about how to make it work from both D and C sides?
Nov 29 2011
prev sibling parent "Dainius (GreatEmerald)" <pastas4 gmail.com> writes:
Ah, I see, that makes sense. And it now compiles correctly, thanks.
Nov 29 2011