2014-02-08 65 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