Good evening, I'm currently working on a Plugin system in C++/Linux based on the Plux.net model.
To keep it simple, I basicly declare a symbol (lets call it pluginInformation) with extern C (to unmangle) and my plugin manager look for that symbol in the pre configured imports (.so).
The thing is that the main application declares the same symbol, not only that but any dependency it have may have the symbol aswell. (since in this pluginInformation, modules can publish plugs and/or slots).
So when my PluginManager starts, it first try to find the symbol in the main program (passing NULL to dlopen), then it tries to find the symbol in any of its dependencies (using dl_iterate_phdr). And last it will dlopen a set of configure imports (it will read the path of the .so that the user configured, dlopen them and finally dlsym the pluginInformation symbol).
The collection of pluginInformation found in all the modules is used then to build the extension three.
If I declare the symbol in the main program and load the imports using dlopen, it works (as long as I pass the flag RTLD_DEEPBIND when dlopening the imports).
But for the application dependencies I dont have the option of passing the flag (I can but it doesnt do anything) since this .sos were loaded at the start up of the application.
Now when I try to use any of the symbols I got from the dependencies (the ones loaded at start up) I get a segmentation fault. I assume the problem is that I have several symbols with the same name in the symbol table, the weird thing is that it seems to correctly identify that there are several symbols and it even gives me the correct path of the .so where the symbol is declared, but as soon as I access the symbol a segmentation fault occurs. If I only declare the symbol in the main program or in one of the dependencies everything works correctly.
How can I manage duplicate symbols between the main program and the strat up imports with dlsym?.
I have been thinking in keep the mangling and then just try to find my symbol pasring the symbol table, but im not sure this is even possible (listing all the symbols in a module programmatically).
PD: Sorry I didnt post any code, but im not at home right now, I hope the description of what im trying to do is clear enough, if not I can post some code tomorrow.
Here is an alternate approach.
The application itself exports one or more plugin item registration functions. For example:
int register_plugin_item(const char *const text,
const char *const icon,
void (*enter)(void *),
void (*click)(void *),
void (*leave)(void *),
void *data);
Per registered item, there are two string slots (text and icon), three function slots (enter, click, and leave), and an opaque reference that is given to the functions as a parameter when called.
(Note that you'll need to use the -rdynamic compiler option when compiling the main application (the object file implementing the above function), to make sure the linker adds the register_plugin_item symbol to the dynamic symbol table.)
Each plugin calls the register_plugin_item() function for each of the items it wants, in a constructor function (that is automatically run at library load time). It is possible, and often useful, for the function to first examine the environment it runs in to determine which features to register, or which optimized variants of functions to use for each plugin item.
Here is a trivial example plugin. Note how all the symbols are static, so that the plugin does not pollute the dynamic symbol table, or cause any symbol conflicts.
#include <stdlib.h>
#include <stdio.h>
extern int register_plugin_item(const char *const,
const char *const,
void (*enter)(void *),
void (*click)(void *),
void (*leave)(void *),
void *);
static void enter(void *msg)
{
fprintf(stderr, "Plugin: Enter '%s'\n", (char *)msg);
}
static void leave(void *msg)
{
fprintf(stderr, "Plugin: Leave '%s'\n", (char *)msg);
}
static void click(void *msg)
{
fprintf(stderr, "Plugin: Click '%s'\n", (char *)msg);
}
static void init(void) __attribute__((constructor));
static void init(void)
{
register_plugin_item("one", "icon-one.gif",
enter, leave, click,
"1");
register_plugin_item("two", "icon-two.gif",
enter, leave, click,
"2");
}
The above plugin exports two items. For testing, create at least a couple of variants of the above; you will see that there are no symbol conflicts even if the plugins use same (static) variables and function names.
Here is an example application that loads the specified plugins, and tests each registered item:
#include <stdlib.h>
#include <dlfcn.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
struct item {
struct item *next;
const char *text;
const char *icon;
void *data;
void (*enter)(void *);
void (*leave)(void *);
void (*click)(void *);
};
static struct item *list = NULL;
int register_plugin_item(const char *const text,
const char *const icon,
void (*enter)(void *),
void (*click)(void *),
void (*leave)(void *),
void *data)
{
struct item *curr;
curr = malloc(sizeof *curr);
if (!curr)
return ENOMEM;
curr->text = text;
curr->icon = icon;
curr->data = data;
curr->enter = enter;
curr->leave = leave;
curr->click = click;
/* Prepend to list */
curr->next = list;
list = curr;
return 0;
}
int main(int argc, char *argv[])
{
int arg;
void *handle;
struct item *curr;
if (argc < 2 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
fprintf(stderr, "\n");
fprintf(stderr, "Usage: %s [ -h | --help ]\n", argv[0]);
fprintf(stderr, " %s PLUGIN.so ... \n", argv[0]);
fprintf(stderr, "\n");
fprintf(stderr, "Please supply full plugin paths, unless\n");
fprintf(stderr, "the plugins reside in a standard library directory,\n");
fprintf(stderr, "or in a directory listed in LD_LIBRARY_PATH.\n");
fprintf(stderr, "\n");
return 1;
}
for (arg = 1; arg < argc; arg++) {
handle = dlopen(argv[arg], RTLD_NOW);
if (handle != NULL)
fprintf(stderr, "%s: Loaded.\n", argv[arg]);
else
fprintf(stderr, "%s.\n", dlerror());
/* Note: We deliberately "leak" the handle,
* so that the plugin is not unloaded. */
}
for (curr = list; curr != NULL; curr = curr->next) {
if (curr->text)
printf("Item '%s':\n", curr->text);
else
printf("Unnamed item:\n");
if (curr->icon)
printf("\tIcon is '%s'\n", curr->icon);
else
printf("\tNo icon\n");
if (curr->data)
printf("\tCustom data at %p\n", curr->data);
else
printf("\tNo custom data\n");
if (curr->enter)
printf("\tEnter handler at %p\n", curr->enter);
else
printf("\tNo enter handler\n");
if (curr->click)
printf("\tClick handler at %p\n", curr->click);
else
printf("\tNo click handler\n");
if (curr->leave)
printf("\tLeave handler at %p\n", curr->leave);
else
printf("\tNo leave handler\n");
if (curr->enter || curr->click || curr->leave) {
printf("\tTest calls:\n");
if (curr->enter)
curr->enter(curr->data);
if (curr->click)
curr->click(curr->data);
if (curr->leave)
curr->leave(curr->data);
printf("\tTest calls done.\n");
}
}
return 0;
}
If the application is app.c, and you have plugins plugin-foo.c and plugin-bar.c, you can compile them using e.g.
gcc -W -Wall -rdynamic app.c -ldl -o app
gcc -W -Wall -fpic -c plugin-foo.c
gcc -shared -Wl,-soname,plugin-foo.so plugin-foo.o -o plugin-foo.so
gcc -W -Wall -fpic -c plugin-bar.c
gcc -shared -Wl,-soname,plugin-bar.so plugin-bar.o -o plugin-bar.so
and run using e.g.
./app --help
./app ./plugin-foo.so
./app ./plugin-foo.so ./plugin-bar.so
Note that if the same plugin is defined more than once, the constructor is only executed once for that library. There will be no duplicate registrations.
The interface between the plugins and the application is completely up to you. In this example, there is only one function. A real application would probably have more. The application can also export other functions, for example for the plugin to query application configuration.
Designing a good interface is a whole different topic, and definitely deserves at least as much thought as you put in the implementation.
The Plux.NET plugin platform allows plugins to export their own slots, too. This alternate approach allows that in many ways. One of them is to export a plugin registration function -- that is, for registering plugins instead of individual items -- that takes a function pointer:
int register_plugin(const char *const name,
int (*extend)(const char *const, ...));
If the plugin provides slots, it provides its own registration function as the extend function pointer. The application also exports a function, for example
int plugin_extend(const char *const name, ...);
that the plugins can use to call other plugins' registration functions. (The implementation of plugin_extend() in the main application involves searching for a suitable extend function already registered, then calling it/them.)
Implementation-wise, allowing plugins to export slots complicates implementation quite a bit. In particular, when and in which order should the slots exported by the plugins become available? Is there a specific order in which plugins must be loaded, to make sure all possible slots are exported? What happens if there is a circular dependency? Should plugins specify which other plugins they rely on before the registrations commence?
If each plugin is a separate entity that does not export any slots of its own, only plugs into main application slots, you avoid most of the complexity in the implementation.
The order in which registered items are examined is a detail you probably need to think about, though. The above example program uses a linked list, in which the items end up in reverse order compared to the registration order, and registration order is the same as the order in which the plugin file names are first specified on the command line. If you have a plugin directory, which is automatically scanned (using e.g. opendir()/readdir()/dlopen()/closedir() loop), then the plugin registration order is semi-random (depending on the filesystem; usually changing only when plugins are added or removed).
Corrections? Questions? Comments?
Related
I have some code that is compiled as a shared library and used with a universal driver, which can be used with other shared libraries that are specific to a particular application.
My question pertains to obtaining some sort of indicator of the name of the binary containing a code that lives in that shared library.
For example, let's say I have 3 files, the first is driver.cpp, the universal driver:
#include "interface.h"
#include <stdio.h>
int main(int argc, char *argv[]) {
//perform a function from the shared library
std::cout << foobar() << std::endl;
}
The second is sharedlibrary.cpp, the specific implementation for one case of many:
#include "interface.h"
char* foobar() {
return x;
}
Where x is some indicator that this function is defined in sharedlibrary.cpp, or that this function is linked from sharedlibrary.so, or the current stack frame is using the specific binary rather than just being included in driver.cpp.
The last file is interface.h, which provides the interface to the library via extern "C"
extern "C" {
char foobar();
}
I would like to reiterate, for clarity, that I am looking for some indication that this function is being linked from sharedlibrary.so. Many solutions looking for runtime filenames give the executable name using either argv[0] or readlink(), but I have no control over the actual naming of driver.cpp or its executable name. Rather, I can distribute sharedlibrary.so, and would like to be able to use its name from within itself, if possible.
If it helps, I know that a microsoft-specific solution could be to use AfxGetApp()->m_pszAppName to obtain the DLL name. However, I am looking for a linux solution that does not necessarily need to be portable.
EDIT: I do not know or control the names of driver.cpp, sharedlibrary.cpp, or sharedlibrary.h at compile time. I wish to discover the name of sharedlibrary.cpp at run time.
The updated sharedlibrary.cpp with x replaced with the solution looks like this
#include "interface.h"
#include <dlfcn.h>
void func() {
//Some function that is defined in sharedlibrary.cpp
}
char* foobar() {
Dl_info DlInfo;
if(!dladdr((void*)func, &DlInfo)) {
return "default_name";
}
return DlInfo.dli_fname;
}
Obtaining filename at runtime for a shared library c++
My question pertains to obtaining some sort of indicator of the name of the binary containing a code that lives in that shared library.
You can use int dladdr(void *addr, Dl_info *info. It fills a following structure for you:
typedef struct {
const char *dli_fname; /* Pathname of shared object that contains address */
void *dli_fbase;
const char *dli_sname;
void *dli_saddr;
} Dl_info;
You can pass the address of a function exported by the shared library as the argument addr. Or within such function, you could use the instruction pointer value of the current stack frame - if you know how to obtain it.
I believe you must link with the libdl library.
You can use the buildsystem to generate the dynamic library name for linking and preprocess that inside of a header with a function that return a defined macro, in cmake you can see how to do that here.
Then you use the configured-file to return the defined value in a function that's exported from within the dll.
#include "library_name_macro.h"
auto __dllexport libraryName() -> std::string { return LIBRARY_NAME_MACRO; }
I hope, I have understood your question correctly. I hope my answer helps. You know the shared library name, you link that shared library to your program, Later in run time you want to figure out whether a particular function is present in library or not and this logic should be part of shared library itself.
Let's take an example that you have shared library called librandom.so, You have linked this library to your application. You can implement the following function in a librandom.so library, You can pass function name which you want to check whether it is present or not. I have not tested this code, there may be errors. The idea I am proposing is library loads itself again to check whether the function is present when this function is called. May not be ideal method but should serve your purpose.
int isFuncPresent(char funcName[])
{
int isFuncFound = 1;
void *lib_handle;
int x;
char *error;
lib_handle = dlopen("librandom.so", RTLD_LAZY);
if (!lib_handle)
{
fprintf(stderr, "%s\n", dlerror());
isFuncFound = 0;
}
fn = dlsym(lib_handle, funcName);
if ((error = dlerror()) != NULL)
{
fprintf(stderr, "%s\n", error);
isFuncFound = 0;
}
dlclose(lib_handle);
return isFuncFound;
}
I want to write a very, very small program that parses the launch arguments and chooses one of several DLLs to "boot into."
I've already written an application that I'd like to "run" as a DLL by writing it as an application, then changing the Visual Studio project properties to build it as a DLL instead. I know I need to use LoadLibrary and GetProcAddress in concert to get the functionality I want, but I'm having trouble finding clear and comprehensive documentation on this, as a lot of the use cases aren't really of this nature. Also, I have to go this route based on the project and platform restrictions.
I found this page, which has some information, but it's not clear enough for me to adapt for my purposes.
Edit: Here's where I'm at right now.
I have a DLL project whose main function signature looks something like this:
__declspec(dllexport) int cdecl main(int argc, char *argv[])
I also have an application project whose attempt at loading the DLL and running the above function looks like this:
typedef int (CALLBACK* LPFNDLLFUNC1)(int, char *);
...
HMODULE dllHandle = NULL;
BOOL freeResult, runTimeLinkSuccess = FALSE;
LPFNDLLFUNC1 lpfnDllFunc1; // Function pointer
if (args->IsEmpty())
{
dllHandle = LoadLibrary(L"TrueApplication.dll");
if (NULL != dllHandle)
{
lpfnDllFunc1 = (LPFNDLLFUNC1)GetProcAddress(dllHandle, "main");
if (lpfnDllFunc1)
{
int retVal = lpfnDllFunc1(0, "1");
}
Currently, the LoadLibrary call works, but not GetProcAddress.
First of all, changing project type from executable to DLL is not enough to make a DLL. You also need to export some symbols to create your API. At least, you need to decorate the functions you are exporting with __declspec(dllexport). However, I recommend that you export C API, meaning extern "C" functions with C-compatible arguments. So, the functions you export should be prepended with extern "C" __declspec(dllexport).
Once you have done that, you can dynamically load your DLL like this:
const char* dllname = "myfile.dll";
h = LoadLibrary(dllname);
if( h == nullptr )
{
/*handle error*/
}
using myfunc_type = bool (*)(int x, double y); //example
auto myfunc = reinterpret_cast<myfunc_type>(GetProcAddress(h, "myfunc"));
//......
myfunc(x,y); //call the imported function
This solution takes more work than static loading with /delayload shown by Jerry Coffin, but it has an advantage: if a DLL is required but not found, you can give users your own error message instead of relying on the message coming from Windows (which is often unacceptable for non-tech people). You can also include API version verification with its own custom error message in the API.
Edit: the code sample will work if you change it like this
extern "C" __declspec(dllexport) int main(int argc, char *argv[]){...}
typedef int (* LPFNDLLFUNC1)(int, char **);
You do not need GetProcAddress (...) to do this, though that approach (Option #2) is simpler once you understand how the compiler generates symbol names.
Option #1
DllMain Spawns a Main Thread
Never do anything complicated inside of DllMain, you may deadlock your software.
DLLs have their own entry-point (and exit-point and thread attach-point ... it's a really busy function). Just calling LoadLibrary (...) on your DLL causes at minimum one call to DllMain (...) for process attach.
BOOL
APIENTRY
DllMain ( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved )
You can actually treat ul_reason_for_call == DLL_PROCESS_ATTACH as a mandate to execute DllMain as if it were your program's main function.
Now, by no means should you actually start a program loop here... anytime DllMain runs it holds a very important operating system lock (DLL Loader) and you need to release that by returning for normal program operation.
That means if you want to use DllMain as your program's entry-point, it needs to spawn a thread and your original main method must not return until that thread finishes...
Option #2
DLL Exports a main Function.
Be very mindful of calling convention, the compiler will rename the symbols for you and make locating functions in a DLL with GetProcAddress less than intuitive.
In your DLL, export main:
__declspec (dllexport)
int
__cdecl main (int argc, char *argv [])
{
printf ("foobar");
return 0;
}
In your program, import main from the DLL:
// Need a typedef for the function you are going to get from the DLL
typedef int (__cdecl *main_pfn)(int argc, char *argv[]);
int main (int argc, char *argv[])
{
HMODULE hModMyDLL = LoadLibraryA ("MyDll.dll");
if (hModMyDLL != 0) {
//
// The preceding underscore deals with automatic decorations
// the compiler added to the __cdecl function name.
//
// It is possible to do away with this completely if you use a .def
// file to assign export names and ordinals manually, but then you
// lose the ability to tell a function's calling convention by its
// name alone.
//
main_pfn MyMain = (main_pfn)
GetProcAddress (hModMyDLL, "_main");
// Call the main function in your DLL and return when it does
if (MyMain != nullptr)
return MyMain (argc, argv);
}
return -1;
}
Both approaches have their merits.
Spawning a thread from DllMain avoids knowing anything at all about how the DLL you want to load is is implemented, but it also requires you to design your main function never to return -- the DLL will call ExitProcess (...).
Exporting functions and later importing them by name allows you to avoid pussyfooting around the Windows DLL loaderlock. However, if you do not use a .def file to explicitly name the exported symbols, the compiler is going to add decorations such as _... (__cdecl) or ...#n (__stdcall) to the names and you have to learn these conventions to do anything useful with GetProcAddress.
You don't have to use LoadLibrary and GetProcAddress to invoke the functionality in the DLL.
More often, you'd create your DLLs, each with its own entry point. For the moment, let's assume you want to parse the command line, choose a DLL, and invoke its entry point without arguments. You end up with something like this:
void DLL_a();
void DLL_b();
void DLL_c();
int main(int argc, char **argv) {
// we'll assume DLL_a is the default:
if (argc < 2)
DLL_a();
// For now, we'll do a *really* trivial version of parsing the command line
// to choose the right DLL:
if (argv[1][0] == 'A')
DLL_a();
else if (argv[1]][0] == 'B')
DLL_b();
else if (argv[1][0] == 'C')
DLL_c();
else {
std::cerr << "Unrecognized argument\n";
return 1;
}
}
When you link your main, you'll specify the .lib corresponding to each DLL, and you'll probably want to specify the /delayload flag to the linker. This means a DLL won't be loaded until a function in the DLL is actually invoked. If, for example, you want to distribute a reduced-functionality version of your program that only includes DLL A, it'll still be able run (without DLL B or C present on the user's system) as long as no function from DLL B or C is ever called. If you don't specify /delayload, the loader will attempt to map all the DLLs to RAM as the program starts up, run their DllMain to initialize them for use, do the same recursively for all the DLLs they depend on, etc.
/delayload has one other advantage: it avoids mapping the other DLLs to addresses at all if they're never used. It sounds like any given invocation will only use one DLL, so that's probably a win in your case.
I'm using a C library called GLC to record my OpenGL buffer programmatically.
GLC listens to key presses, which is not really a nice solution to trigger programmatically.
Therefore I want to execute the recording from GLC via a function call in my software.
My C++ software is linking to the library which includes the desired function start_capture(). Via nm I can see this function is local, marked with a lower case t.
Since it has to be global to access it in my software I want to recompile the library (which I've already done). But I have no idea what to change to make it accessible....
Here is the declaration from start_capture(), in the header file lib.h
...
__PRIVATE int start_capture(); // No idea where the __PRIVATE is coming from
...
This is the definition/implementation of the start_capture() function in the main.c:
int start_capture()
...
return ret;
}
And this is my dlopen to get the function:
void *handle_so;
void (*start_capture_custom)();
char *error_so;
handle_so = dlopen("/home/jrick/fuerte_workspace/sandbox/Bag2Film/helper/libglc-hook.so", RTLD_LAZY);
if (!handle_so)
{
fprintf(stderr, "%s\n", dlerror());
exit(1);
}
dlerror(); /* Clear any existing error */
start_capture_custom = (void (*)())dlsym(handle_so, "start_capture");
if ((error_so = dlerror()) != NULL)
{
fprintf(stderr, "%s\n", error_so);
exit(1);
}
start_capture_custom();
dlclose(handle_so);
start_capture();
So what am I supposed to change to access this via the library file?
I hope this was enough description to make the problem clear. If not, I'll answer as fast as I can.
__PRIVATE is a #define for a GCC extension to hide a symbol. See https://github.com/nullkey/glc/blob/master/src/glc/common/glc.h#L60 for the definition and http://gcc.gnu.org/wiki/Visibility for more info about the GCC extension.
https://stackoverflow.com/a/12011284/2146478 provides a solution that will unhide symbols without recompiling. You would want to do something like:
$ objcopy --globalize-symbol=start_capture /path/to/your/lib.a /path/to/new/lib.a
I've spent days reading and re-reading every tutorials I've found on the subject, and spent hours (and even days) browsing related questions here at SO, but I still can't get the following to work. Accept my apologies if this is a duplicate: chances are that I've seen and re-read many times the duplicate questions but couldn't understand the relevance of the answers to my problem. With that out of the way...
I'm trying to implement a plugin architecture for my Application. Plugins are compiled and installed as libraries. At run time, the Application then uses dlopen() / dlsym() to load and link to the plugin's functions.
The idea is that plugins (libraries) will implement a set of functions to return data to the main Application, or manipulate data passed from the Application.
In order to test this idea, I tried to implement a function (inside the plugin) that would return the (human readable) name of the plugin itself (as a std::string). I thought that would be something simple to start with.... :-/
Here is what I got so far:
// Plugin.cpp
extern "C" void plugin_name(std::string *name) {
name = new std::string("Example plugin name");
}
// Application.cpp
void* handle = dlopen("libplugin.so", RTLD_LAZY);
typedef void (*plugin_t)(std::string*);
dlerror(); // Reset errors.
plugin_t call_plugin_name = (plugin_t) dlsym(handle, "plugin_name");
// ... Some error handling code.
std::string my_plugin_name;
call_plugin_name(&my_plugin_name);
dlclose(handle);
// More code that displays my_plugin_name.
I've tried many different combinations, including one that seemed more straigtforward (but didn't work any better) where the plugin name is returned:
// Plugin.cpp
extern "C" std::string plugin_name(void) {
return std::string("Example plugin name");
}
I know I'm close: the code compiles and the Application stopped crashing ;)
However, I've got an empty space where I'd expect seeing the actual plugin name.
All the tutorials I've read so far go very quickly over the mechanism by which data is passed both ways: plugin <=> Application. What I'm trying to do with a "simple" std::string, I wish to do later with much more complex objects (i.e. a plugin function would take an object by reference and change some of its properties). The tutorials more or less all stop at the point of creating a pointer with dlsym() and do not give much examples on how to use this pointer.
So, how to do all that?
Another pertinent question: do I use a common header that I'd use both with the Application and with the plugin and where I'd define the function calls signature? How would I do this and how would that help?
The signature of a function is generated from its name and argument types (return value type doesn't matter). When you declare function with extern "C", C symbol naming scheme is used which apparently can't handle C++ types like std::string. That's why passing std::string as an arguments doesn't work.
I can't explain why returning std::string doesn't work. Maybe different calling conventions are used.
Anyway the correct way of importing C++ code from a shared library is to return pointers to C++ types from entry points. And this entry points have to have arguments with types available in C. (Entry point is a documented function exported from a shared library)
Here is a good article on basic aspects of loading C++ classes from shared libraries. This article will answer your question throughly.
Please note that there are pitfalls when using exceptions thrown from a shared library to the main applications. And with dynamic_cast of objects created inside a library. I've mentioned this topics so that you could be somewhat prepared when you face this problems.
[edit]
To make my answer more clear I'll add a couple of examples.
To get the plugin name you can use:
extern "C" const char * plugin_name() {
return "Example plugin name";
}
// main.cc:
void* handle = dlopen("libplugin.so", RTLD_LAZY);
// ...
typedef const char * (*plugin_t)();
plugin_t call_plugin_name = (plugin_t) dlsym(handle, "plugin_name");
// ...
std::string my_plugin_name(call_plugin_name());
// use it
To really use the plugin functionality you should declare a base class in a header:
// plugin.h
class Plugin {
public:
virtual void doStuff() = 0;
virtual ~Plugin() = 0;
};
// plugin.cc
Plugin::~Plugin() {
}
// myplugin.cc
class MyPlugin : public Plugin {
virtual void doStuff() {
std::cout << "Hello from plugin" << std::endl;
}
};
extern "C" Plugin *createMyPluginInstance() {
return new MyPlugin;
}
Try:
extern "C" void plugin_name(std::string **name) {
*name = new std::string("Example plugin name");
}
...
std::string *my_plugin_name;
call_plugin_name(&my_plugin_name);
As you are assigning a copy of the pointer you passed as the argument, not the one you intended to assign.
EDIT Here you go:
File main.cpp
#include <iostream>
#include <dlfcn.h>
#include <string>
// Application.cpp
int main() {
void* handle = dlopen("libplugin.so", RTLD_LAZY);
typedef void (*plugin_t)(std::string**);
dlerror(); // Reset errors.
plugin_t call_plugin_name = (plugin_t) dlsym(handle, "plugin_name");
// ... Some error handling code.
std::string *my_plugin_name;
call_plugin_name(&my_plugin_name);
dlclose(handle);
// More code that displays my_plugin_name.
std::cout << "Plugin name is " << *my_plugin_name << std::endl;
delete my_plugin_name;
return 0;
}
File plugin.cpp
#include <string>
extern "C" void plugin_name(std::string **name) {
*name = new std::string("example plugin name");
}
Just a word of warning. Although this compiles and runs, passing C++ types across the dll boundry is risky and the above code is just your code fixed enough to compile and run, it is not safe and has very explicit memory handling. You may want to attack the problem in a different way.
Please have a read of this question and its answers. There are many opportunities for incompatibilities across the shared lib boundaries in C++.
I have a shared object (a so - the Linux equivalent of a Windows dll) that I'd like to import and use with my test code.
I'm sure it's not this simple ;) but this is the sort of thing I'd like to do..
#include "headerforClassFromBlah.h"
int main()
{
load( "blah.so" );
ClassFromBlah a;
a.DoSomething();
}
I assume that this is a really basic question but I can't find anything that jumps out at me searching the web.
There are two ways of loading shared objects in C++
For either of these methods you would always need the header file for the object you want to use. The header will contain the definitions of the classes or objects you want to use in your code.
Statically:
#include "blah.h"
int main()
{
ClassFromBlah a;
a.DoSomething();
}
gcc yourfile.cpp -lblah
Dynamically (In Linux):
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
int main(int argc, char **argv) {
void *handle;
double (*cosine)(double);
char *error;
handle = dlopen ("libm.so", RTLD_LAZY);
if (!handle) {
fprintf (stderr, "%s\n", dlerror());
exit(1);
}
dlerror(); /* Clear any existing error */
cosine = dlsym(handle, "cos");
if ((error = dlerror()) != NULL) {
fprintf (stderr, "%s\n", error);
exit(1);
}
printf ("%f\n", (*cosine)(2.0));
dlclose(handle);
return 0;
}
*Stolen from dlopen Linux man page
The process under windows or any other platform is the same, just replace dlopen with the platforms version of dynamic symbol searching.
For the dynamic method to work, all symbols you want to import/export must have extern'd C linkage.
There are some words Here about when to use static and when to use dynamic linking.
It depends on the platform. To do it at runtime, on Linux, you use dlopen, on windows, you use LoadLibrary.
To do it at compile time, on windows you export the function name using dllexport and dllimport. On linux, gcc exports all public symbols so you can just link to it normally and call the function. In both cases, typically this requires you to have the name of the symbol in a header file that you then #include, then you link to the library using the facilities of your compiler.
You need to #include any headers associated with the shared library to get the declrarations of things like ClassFromBlah. You then need to link against the the .so - exactly how you do this depends on your compiler and general instalation, but for g++ something like:
g++ myfile.cpp -lblah
will probably work.
It is -l that link the archive file like libblah.a or if you add -PIC to gcc you will get a 'shared Object' file libblah.so (it is the linker that builds it).
I had a SUN once and have build this types of files.
The files can have a revision number that must be exact or higher (The code can have changed due to a bug). but the call with parameters must be the same like the output.