代码之家  ›  专栏  ›  技术社区  ›  Aubin

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

  •  0
  • Aubin  · 技术社区  · 4 年前

    插件是通过 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;
    }
    

    这是密码 SampleLib.cpp

    #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
    

    这是执行日志 RTLD_NOW :

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

    这是执行日志 RTLD_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 ?

    0 回复  |  直到 4 年前
        1
  •  0
  •   Aubin    4 年前

    以下是 Makefile :

    .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
    

    以下是 main-api 文本文件:

    {
       extern "C" {
          AddService;
       };
    };
    

    执行日志变成:

    $ 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
    

    under GitHub .