2014-02-08 64 views
4

我有以下三个项目:链接未解决的符号的共享库在Linux上

  • Host:由加载的运行时库:一个导出一个全局变量(声明为extern)
  • Plugin可执行Host和引用全球变量
  • Tool:一个可执行文件链接到Plugin并使用它的一些功能。它不以任何方式引用全局变量。

现在,如果我在Windows上构建这一切都很好。 Tool将只链接到Plugin的导出库,并且不会尝试解析全局变量。

在linux上,我遇到了一个问题。 Tool尝试链接到Plugin.so库(因为没有导出库),并且会找到它无法解析的全局变量的引用Host

如何解决这个问题?


编辑:

下面是使用C进行的问题可编译例子。

的CMakeLists.txt

SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/bin") 
SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/bin") 

SET(CMAKE_POSITION_INDEPENDENT_CODE ON) 

ADD_SUBDIRECTORY(Host) 
ADD_SUBDIRECTORY(Plugin) 
ADD_SUBDIRECTORY(Tool) 

主机/ Host.h

#ifndef HOST_H 
#define HOST_H 

#ifdef _MSC_VER 

#ifdef COMPILE_HOST 
#define HOST_EXPORT __declspec(dllexport) 
#else 
#define HOST_EXPORT __declspec(dllimport) 
#endif 

#else 
#define HOST_EXPORT 
#endif 


class HOST_EXPORT Host 
{ 
public: 
    int getAnswer(); 

}; 


extern HOST_EXPORT Host g_host; 


#endif 

主机/ Host.cpp

#include "Host.h" 
#include "../Plugin/Plugin.h" 
#include <iostream> 


Host g_host; 


int Host::getAnswer() 
{ 
    return 42; 
} 


int main() 
{ 
    std::cout << g_host.getAnswer() << std::endl; 

    // load plugin and use it 
} 

主机/的CMakeLists.txt

PROJECT(Host) 

ADD_EXECUTABLE(Host Host.cpp Host.h) 

ADD_DEFINITIONS(-DCOMPILE_HOST) 

SET_TARGET_PROPERTIES(Host PROPERTIES ENABLE_EXPORTS ON) 

插件/ Plugin.h

#ifndef PLUGIN_H 
#define PLUGIN_H 


class Plugin 
{ 
public: 
    Plugin(); 

}; 

#endif 

插件/ Plugin.cpp

#include "Plugin.h" 
#include "../Host/Host.h" 
#include <iostream> 


Plugin::Plugin() 
{ 
    std::cout << g_host.getAnswer() << std::endl; 
} 

插件/ PluginFunc.h

#ifndef PLUGINFUNC_H 
#define PLUGINFUNC_H 

#ifdef _MSC_VER 
#define PLUGIN_EXPORT __declspec(dllexport) 
#else 
#define PLUGIN_EXPORT 
#endif 


namespace plug 
{ 
    int PLUGIN_EXPORT getRandomNumber(); 
} 

#endif 

插件/ PluginFunc.cpp

#include "PluginFunc.h" 


int plug::getRandomNumber() 
{ 
    return 4; 
} 

插件/的CMakeLists.txt

PROJECT(Plugin) 

ADD_LIBRARY(Plugin SHARED Plugin.cpp Plugin.h PluginFunc.cpp PluginFunc.h) 

TARGET_LINK_LIBRARIES(Plugin Host) 

工具/ Tool.cpp

#include "../Plugin/PluginFunc.h" 
#include <iostream> 


int main() 
{ 
    std::cout << plug::getRandomNumber() << std::endl; 
} 

工具/ CMakeLists。TXT

PROJECT(Tool) 

ADD_EXECUTABLE(Tool Tool.cpp) 

TARGET_LINK_LIBRARIES(Tool Plugin) 

在Windows上建立和运行。 Host.exe显示“42”,而Tool.exe显示“4”。

在Linux上,我得到以下链接错误:

[email protected]:~/vbox/testlink/build$ make 
Scanning dependencies of target Host 
[ 25%] Building CXX object Host/CMakeFiles/Host.dir/Host.o 
Linking CXX executable Host 
[ 25%] Built target Host 
Scanning dependencies of target Plugin 
[ 50%] Building CXX object Plugin/CMakeFiles/Plugin.dir/Plugin.o 
[ 75%] Building CXX object Plugin/CMakeFiles/Plugin.dir/PluginFunc.o 
Linking CXX shared library libPlugin.so 
[ 75%] Built target Plugin 
Scanning dependencies of target Tool 
[100%] Building CXX object Tool/CMakeFiles/Tool.dir/Tool.o 
Linking CXX executable Tool 
../Plugin/libPlugin.so: undefined reference to `Host::getAnswer()' 
../Plugin/libPlugin.so: undefined reference to `g_host' 
collect2: error: ld returned 1 exit status 
make[2]: *** [Tool/Tool] Error 1 
make[1]: *** [Tool/CMakeFiles/Tool.dir/all] Error 2 
make: *** [all] Error 2 
+0

你可以发布一些代码/构建脚本,以便我们可以看到如何在Win/Linux上构建? – txtechhelp

+0

@txtechhelp我用一个完整的例子更新了我的问题。 – typ1232

+0

静态链接到可执行文件非常传统。为什么你需要这样做,我们只是好奇而已? – ComicSansMS

回答

1

有两种方法:

  • 定义工具中的全局变量。因为它没有被使用,所以它的价值并不重要。
  • 使用链接器命令来定义具有组成值的符号。使用GCC和GNU ld,它应该类似gcc -Wl,--defsym=GlobalSymbol=0
1

有两种可能的方法:

  1. 移动的全局成由两HostPlugin引用一个单独的DLL。
  2. Plugin拆分为提供给Tool的库功能和提供给Host的插件功能(通过调用库来实现插件)。

这些都应该适合你。

链接失败,因为您正在将Tool程序与Plugin DLL链接起来,此时链接器强制所有符号均可解析。虽然惰性查找原则上可以避免运行时出现问题,但系统策略可能因安全原因而禁止懒惰查找,因为在调用后会立即终止您的Tool,因为进程中存在未定义的符号。其他

+0

谢谢。这是我应该瞄准的长期解决方案,但我已经知道了。我正在寻找一个能够解决我的问题而不需要太多工作的答案。 – typ1232