在linux上链接具有未解析符号的共享库



我有以下三个项目:

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

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

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

如何解决这个问题?


编辑:

以下是使用CMake的问题的可编译示例。

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

主机/主机.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)

插件/插件.h

#ifndef PLUGIN_H
#define PLUGIN_H

class Plugin
{
public:
Plugin();
};
#endif

插件/插件.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

插件/插件Func.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)

工具/工具.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上,我得到以下链接错误:

usr@debian64:~/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

另外两种方法是:

  • 在Tool中定义全局变量。值是什么并不重要,因为它没有被使用
  • 使用链接器命令可以定义具有虚构值的符号。对于GCC和GNU ld,它应该类似于gcc -Wl,--defsym=GlobalSymbol=0

有两种可能的方法:

  1. 将全局变量移动到HostPlugin都引用的单独DLL中
  2. Plugin拆分为提供给Tool的库功能和提供给Host的插件功能(通过调用库来实现插件)

这两种方法中的任何一种都适用。

链接失败是因为您正在根据PluginDLL链接Tool程序,此时链接器强制所有符号都是可解析的。虽然延迟查找原则上可以在运行时避免这个问题,但出于安全原因,系统策略可能会禁止延迟查找,这将在调用后立即终止Tool,因为过程中存在未定义的符号。

相关内容

  • 没有找到相关文章

最新更新