Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/rust/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 动态库依赖于可执行文件(依赖项反转)_C++_Linux_Dynamic Library - Fatal编程技术网

C++ 动态库依赖于可执行文件(依赖项反转)

C++ 动态库依赖于可执行文件(依赖项反转),c++,linux,dynamic-library,C++,Linux,Dynamic Library,主程序提供一些服务来注册插件 插件通过dlopen动态加载 插件使用主程序提供的一些符号,但在加载时,它们不会被库看到 以下是Main.cpp的代码: #include "SampleMain.h" #include <dlfcn.h> #include <iostream> #include <map> #include <string> typedef std::map<std::string, Service&g

主程序提供一些服务来注册插件

插件通过
dlopen
动态加载

插件使用主程序提供的一些符号,但在加载时,它们不会被库看到

以下是
Main.cpp
的代码:

#include "SampleMain.h"

#include <dlfcn.h>
#include <iostream>
#include <map>
#include <string>

typedef std::map<std::string, Service> Services;

static Services services;

extern "C" void AddService( const char * name, Service service ) {
   std::cerr << "AddService( " << name << " )" << std::endl;
   services[name] = service;
}

int main( void ) {
   void * hLib = dlopen( "lib/libsample.so", RTLD_LAZY );
   if( hLib ) {
      typedef bool ( * RegisterServices )( void );
      RegisterServices registerServices =
         (RegisterServices)dlsym( hLib, "RegisterServices" );
      if( registerServices ) {
         if( registerServices()) {
            Services::iterator it = services.find( "MyService" );
            if( it != services.end()) {
               Service service = it->second;
               int retCode = service( 0 );
               std::cerr << "'MyService' returns " << retCode << std::endl;
            }
            else {
               std::cerr << "'MyService' not found!" << std::endl;
            }
         }
         else {
            std::cerr << "Registration failed" << std::endl;
         }
      }
      else {
         std::cerr << "dlsym error: " << dlerror() << std::endl;
      }
      dlclose( hLib );
   }
   else {
      std::cerr << "dlopen error: " << dlerror() << std::endl;
   }
   return 0;
}
#include "SampleMain.h"

#if defined __linux__
#  define API extern "C" __attribute((visibility("default")))
#elif defined WIN32
#  define API extern "C" __declspec(dllexport)
#else
#  error Unsupported platform
#endif

#include <iostream>
#include <vector>

static int ServiceOffer( void * arg ) {
   std::cerr << "ServiceOffer|entry" << std::endl;
   std::vector<void *> v;
   v.push_back( arg );
   v.push_back( arg );
   v.push_back( arg );
   size_t val = v.size();
   std::cerr << "ServiceOffer|exit, val: " << val << std::endl;
   return 0;
}

API bool RegisterServices( void ) {
   AddService( "MyService", ServiceOffer );
   return true;
}
这是
Makefile

run: Main lib/libsample.so
    LD_LIBRARY_PATH=./lib ./Main

lib/libsample.so: SampleLib.cpp
    g++ -fPIC -shared -o $@ $<

Main: SampleMain.cpp
    g++ -fPIC -o $@ $< -ldl
.PHONY: all clean

all: Main lib/libsample.so
    LD_LIBRARY_PATH=./lib ./Main

clean:
    rm -f lib/libsample.so Main

Main: SampleMain.cpp
    g++ -o $@ $< -rdynamic -Wl,--dynamic-list=main-api -ldl

lib/libsample.so: SampleLib.cpp
    g++ -o $@ $< -fvisibility=hidden -fpic -shared
这是带有
RTLD\u LAZY
的执行日志:

$ make run
g++ -fPIC -o Main SampleMain.cpp -ldl
LD_LIBRARY_PATH=./lib ./Main
./Main: symbol lookup error: lib/libsample.so: undefined symbol: AddService

如何导出符号
AddService

正如预期的那样,解决方案处于链接器级别

以下是
Makefile
的内容:

run: Main lib/libsample.so
    LD_LIBRARY_PATH=./lib ./Main

lib/libsample.so: SampleLib.cpp
    g++ -fPIC -shared -o $@ $<

Main: SampleMain.cpp
    g++ -fPIC -o $@ $< -ldl
.PHONY: all clean

all: Main lib/libsample.so
    LD_LIBRARY_PATH=./lib ./Main

clean:
    rm -f lib/libsample.so Main

Main: SampleMain.cpp
    g++ -o $@ $< -rdynamic -Wl,--dynamic-list=main-api -ldl

lib/libsample.so: SampleLib.cpp
    g++ -o $@ $< -fvisibility=hidden -fpic -shared
执行日志变成:

$ make run
g++ -o Main SampleMain.cpp -rdynamic -Wl,--dynamic-list=main-api -ldl
g++ -o lib/libsample.so SampleLib.cpp -fvisibility=hidden -fpic -shared
LD_LIBRARY_PATH=./lib ./Main
AddService( MyService )
ServiceOffer|entry
ServiceOffer|exit, val: 3
'MyService' returns 0

完整的交叉编译解决方案可用。

您没有。您的主应用程序应该通过
registerService
的函数指针参数公开它,即重新工具
RegisterServices
以获取库代码可以调用的函数指针。调用看起来像
registerService(AddServices)。仅供参考,您可能希望使用一个可以容纳多个函数指针的结构来设置它,并传递该结构的地址,而不仅仅是一个函数指针。我想你迟早会需要它的。完成了,看看我的解决方案。所以是为了技术帮助,保留您的意见。这种协作模式很大程度上受到了N-API本机模块Node.JS的启发。“为您保留您的意见”-这不是一种意见;这是简单的逻辑。您指定的平台绝对没有任何允许或限制。如果您包括了可接受的条件,那么这仅限于Linux,我的评论会有很大的不同。很高兴你找到了一个解决方案,顺便说一句。我已经交叉编译了这个解决方案。插件使用mingw交叉编译器在Linux下完成,由Visual Studio 2017编译的主插件托管。