Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Facility to load dynamic libraries  (Read 11233 times)

0 Members and 1 Guest are viewing this topic.

binary1248

  • SFML Team
  • Hero Member
  • *****
  • Posts: 1405
  • I am awesome.
    • View Profile
    • The server that really shouldn't be running
Facility to load dynamic libraries
« on: January 08, 2015, 08:22:00 pm »
It is not uncommon for applications these days to require loading optional libraries at runtime.

Probably the most common example of this would be to automatically load optional plug-ins/add-ons that the user wants the program to load during runtime.

Currently, the developer would need to resort to OS-specific code to achieve this, which can become annoying if you have to do this in many projects.

SFML would allow the developer to load libraries (possibly appending the correct filename suffix depending on the OS) and check for and load specific functions from those libraries.
SFGUI # SFNUL # GLS # Wyrm <- Why do I waste my time on such a useless project? Because I am awesome (first meaning).

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Facility to load dynamic libraries
« Reply #1 on: January 08, 2015, 08:33:55 pm »
Yes this can be useful, but is this really in the scope of SFML?

PS: I'm really curious to know what you're developing to suddenly need such features :P
Laurent Gomila - SFML developer

FRex

  • Hero Member
  • *****
  • Posts: 1848
  • Back to C++ gamedev with SFML in May 2023
    • View Profile
    • Email
Re: Facility to load dynamic libraries
« Reply #2 on: January 08, 2015, 09:24:55 pm »
Easy enough for C style names, but what if someone wants to query C++ symbols? C++ names are mangled, is there a way around it?
Back to C++ gamedev with SFML in May 2023

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Facility to load dynamic libraries
« Reply #3 on: January 08, 2015, 09:49:03 pm »
Quote
Easy enough for C style names, but what if someone wants to query C++ symbols? C++ names are mangled, is there a way around it?
That's why you usually export C symbols from a plugin. I don't think anybody really tries to dynamically import C++ functions from a shared library. Even if you use C++ classes, the entry point is always a C function.
Laurent Gomila - SFML developer

binary1248

  • SFML Team
  • Hero Member
  • *****
  • Posts: 1405
  • I am awesome.
    • View Profile
    • The server that really shouldn't be running
Re: Facility to load dynamic libraries
« Reply #4 on: January 08, 2015, 09:49:49 pm »
Yes this can be useful, but is this really in the scope of SFML?
Well... if you have a reason to use SFML, you probably might need such a feature somewhere down the road, if you intend on working on a project for a longer period of time (and for "serious" purposes ;)).
Quote
PS: I'm really curious to know what you're developing to suddenly need such features :P
I don't need it now, but I remember a while ago when I was working on an old project of mine, I wanted to be able to swap out modules that provide the same API but different implementations at runtime.

That and we made it one of our "soft goals" to try to make the library more attractive to... "less casual" users :P.

Easy enough for C style names, but what if someone wants to query C++ symbols? C++ names are mangled, is there a way around it?
Declare your function extern "C". You can use C++ code in it, but the interface will be treated like a C function.

Searching on the web yielded this guide: http://tldp.org/HOWTO/C++-dlopen/index.html

I've seen applications do it often enough to know it is possible somehow :P.
SFGUI # SFNUL # GLS # Wyrm <- Why do I waste my time on such a useless project? Because I am awesome (first meaning).

FRex

  • Hero Member
  • *****
  • Posts: 1848
  • Back to C++ gamedev with SFML in May 2023
    • View Profile
    • Email
Re: Facility to load dynamic libraries
« Reply #5 on: January 08, 2015, 10:09:30 pm »
I know all that - I was just asking what's the point if it's for C named symbols only, since we are oh-so-modern, oh-so-C++, etc.
It's.. weird... to see something like that come up in here from someone that reasonable so I was that disoriented. :P
I like the idea, just didn't expect it and wouldn't ask because I didn't have a need for that (yet).

Yes, it's kinda possible if you apply some tricks (BTW, if you know mangled name then you can look up that symbol no problem, but mangled names suck that bad...).
Irrlicht, Irrklang and Doom 3 do it with C++ classes, they have pure virtual interface for all classes that gets used across dll/exe boundary with dynamic linker and then they have some C named (extern "C") function to do a "handshake".
Irrlicht and Irrklang have just one or two functions to create the "main" device class from which all others are accessed/created.
Doom 3 has a GetGameAPI in the game dll that doom.exe calls to give it the filesytem, audio, renderer, etc. pointers and retrieve game, gameedit etc. pointers (you can read about it a bit here: http://fabiensanglard.net/doom3/ ).
Pure C code or C code with C++ inside (like CSFML) is of course no problem.
Back to C++ gamedev with SFML in May 2023

Mario

  • SFML Team
  • Hero Member
  • *****
  • Posts: 879
    • View Profile
Re: Facility to load dynamic libraries
« Reply #6 on: January 30, 2015, 05:00:47 pm »
I think this could be something interesting for an utility section of sfml-system. It's not like this is a massive feature or anything like that. It would really just be a small wrapper around some basic functionality that could be useful in many programs, especially if you consider the upcoming audio reader/writer changes.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Facility to load dynamic libraries
« Reply #7 on: January 30, 2015, 05:08:20 pm »
Good point. The changes in sfml-audio are oriented towards the development of audio plugins (for MIDI, which requires 50 MB of instruments bank, or MP3 which has license issues, etc.), and a sf::Library/Plugin class would then be needed.
Laurent Gomila - SFML developer

Klaim

  • Full Member
  • ***
  • Posts: 137
    • View Profile
Re: Facility to load dynamic libraries
« Reply #8 on: January 31, 2015, 05:45:52 pm »
Something with of a similar limited scope but SFML-like interface than Boost.DLL (currently proposed for inclusion in boost but not yet officially reviewed) would be useful indeed even for simple applications or games (I never developped a pc game not needing dynamically loading dlls, but I might be doing strange stuffs).

So maybe Boost.DLL will gives ideas or at least some data to think with: http://apolukhin.github.io/Boost.DLL/index.html

There was also Boost.SharedObject and a few other proposals.
See this discussion: http://boost.2283326.n4.nabble.com/Checking-interest-in-DynamicLoad-DLL-DSO-Plugin-library-td4666378.html
EDIT: Also this one: http://boost.2283326.n4.nabble.com/Boost-DLL-Formal-Review-request-td4668079.html

I like the lasts Boost.DLL versions but it is based on shared_ptr and I'm not sure if it would be a good design for SFML. I suspect Laurent to prefer a specific type with simple ownership semantic to represent a loaded module (even if it's a shared_ptr inside).
« Last Edit: January 31, 2015, 06:17:33 pm by Klaim »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Facility to load dynamic libraries
« Reply #9 on: January 31, 2015, 07:48:24 pm »
We don't need something complicated, just a thin wrapper that contains 3 functions:
- loading a shared library
- importing symbols
- releasing the library
Laurent Gomila - SFML developer

Klaim

  • Full Member
  • ***
  • Posts: 137
    • View Profile
Re: Facility to load dynamic libraries
« Reply #10 on: February 01, 2015, 01:27:43 am »
Indeed! I think that's a good candidate for a very simple RAII object.

The only part that might be difficult to make simple is to provide a way to demangle symbols, like the BOOST_DLL_AUTO_ALIAS, otherwise it makes interfacing with C++ functions very hard for cross-platform code (because of different mangled names depending on compilers).
Or you could just forget it and let users use only C interfaces, at least for a start (that's what Boost.SharedObject from CPPCMS does, I believe).

Boost.DLL doesn't offer much more than these features either (except maybe the function to list available dlls). The author made sure it's very customizable to match all cases, including very advanced usage. Of course I agree that SFML need to go that far.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Facility to load dynamic libraries
« Reply #11 on: February 01, 2015, 11:38:20 am »
We don't care about demangling C++ symbols, supporting C interfaces is more than enough.
Laurent Gomila - SFML developer

Mario

  • SFML Team
  • Hero Member
  • *****
  • Posts: 879
    • View Profile
Re: Facility to load dynamic libraries
« Reply #12 on: February 03, 2015, 11:30:49 am »
I'd vote for a simple object representing the actual library being loaded, something like this:

Code: [Select]
sf::Library plugin("myplugin");
initfuncsig init = plugin.getFunction("init");
if (!init)
    init("init my plugin", 123);
else
    std::cerr << "This is no valid plugin." << std::endl;

This code snippet would try to load "myplugin.dll" or "libmyplugin.so" (depending on platforms) and then try to retrieve and call "init()" within it.

In addition, there could be further members for other SFML types, e.g.:

Code: [Select]
sf::Texture image;
image.createFromResource(plugin, som_special_way_to_identify_resource);

FRex

  • Hero Member
  • *****
  • Posts: 1848
  • Back to C++ gamedev with SFML in May 2023
    • View Profile
    • Email
Re: Facility to load dynamic libraries
« Reply #13 on: February 03, 2015, 03:51:24 pm »
There is no reason for additional loaders,  you can just use char array and loadFromMemory or create image from pixels.
There is also no type safety at all, so there is no (sane) way to do this:
initfuncsig init = plugin.getFunction("init");
But this should be possible:
initfuncsig init = plugin.getFunction<initfuncsig>("init");
Back to C++ gamedev with SFML in May 2023

ratzlaff

  • Newbie
  • *
  • Posts: 33
    • View Profile
Re: Facility to load dynamic libraries
« Reply #14 on: February 03, 2015, 05:26:52 pm »
In the codebase I work with, we use this interface to do dynamic library loading across all the platforms we support (windows, macosx, linux) both 32 and 64-bit:

Code: [Select]
class DynamicLoader
{
public:
class Library
{
friend class DynamicLoader;
public:

// We dont unload our plugins manually, but here is where we would do it
// ~Library();

// return a named, exported function pointer
virtual void * getFunction(const char* inName);

// system-specific path to this loaded library
virtual const std::string& getPath() const;

protected:
void * mLibrary;
std::string mPath;

private:
Library(const char* inFile);
};

static Library * Load(const std::string& inName);
protected:
DynamicLoader();
};

Unfortunately I cannot provide our specific implementation, but in general to load the dynamic library:
Code: [Select]
#ifdef _WIN32
mLibrary = (void *) LoadLibrary(inName);
#else
mLibrary = (void *) dlopen(inName, DL_OPEN_MODE);
#endif

And to get the function pointer:
Code: [Select]
#ifdef _WIN32
void* funcAddr = (void *) GetProcAddress((HMODULE) mLibrary, inName);
#else
void* funcAddr = (void *) dlsym(mLibrary, inName);
#endif

When we build a plugin, we export a specific function like so:
Code: [Select]
extern "C"
#ifdef _WIN32
__declspec( dllexport )
#endif
Plugin* MakePlugin()
{
return new ThisSpecificPlugin();
}

Usage:
Code: [Select]
DynamicLoader::Library *l = DynamicLoader::Load(plugin.c_str());

if (!l) {
throw "specified plugin '" + plugin + "' can't load!";
}

typedef Plugin* (*Plugin_Factory)();
Plugin_Factory makeit;

try {
makeit = (Plugin_Factory)l->getFunction("MakePlugin");
if (!makeit) {
throw "plugin function 'MakePlugin' not found in library!";
}

Plugin* p = makeit();
...
} catch (...) {
printf("Error during plugin initialization\n");
}
« Last Edit: February 03, 2015, 05:30:20 pm by ratzlaff »