问题描述
在链接过程中,动态库链接成功,但被其他人调用时,编译器无法找到动态库中的符号,导致编译失败。例如:
undefined reference to `math::Geometry::Point’
可能原因
静态库未正确包含在链接过程中:静态库可能没有被正确添加到链接命令中。
静态库中的符号未被使用:如果静态库中的符号未被使用,链接器可能会优化掉这些符号。
头文件未正确包含:使用符号的代码中可能没有正确包含相关头文件。
链接顺序不正确:链接顺序不正确可能导致符号未解析。
我这里的动态库libmathtoolkit.so链接libGeometry.a成功,但是在提供给第三方使用时发现找不到定义,原因是静态库中的符号未被使用,链接器优化掉了这些符号
nm libmathtoolkit.so | grep Point
找不到符号
解决方案
如果inline 函数没有被调用,链接器会将其优化掉。加上__attribute__((used))防止被链接器优化
attribute((used)) 是 GCC 和 Clang 编译器特有的一个属性,用于告诉编译器,即使这个函数或变量在代码中没有被显式使用,也不要将其移除。这在某些情况下非常有用,例如函数或变量是通过反射、动态加载或其他间接方式使用的。
inline __attribute__((used)) void NotUsedFunc()
{
std::cout << __PRETTY_FUNCTION__;
}
如果是动态库,使用 --whole-archive 链接选项,强制链接静态库
在链接时使用 --whole-archive 选项,强制链接器包含静态库中的所有符号。例如:
target_link_libraries(${PROJECT_NAME}
-Wl,--whole-archive /path/to/libGeometry.a -Wl,--no-whole-archive
OtherLibrary1
OtherLibrary2
)
或者确保使用符号
确保在代码中实际使用了静态库中的符号。例如:
#include "Geometry.h"
namespace example {
class ExampleClass {
// 使用符号
math::Geometry::Point point;
// 其他代码
};
} // namespace example
检查符号表
使用 nm 命令检查静态库中的符号表,确保符号存在且未被隐藏。例如:
nm libmathtoolkit.so | grep Point
检查链接命令
确保链接命令中包含了正确的库路径和库文件。例如,在构建配置文件中添加以下行打印库路径:
message(STATUS "Linking with Geometry: ${Geometry_LIB}")
清理和重新构建
尝试清理构建目录并重新构建项目,以确保没有旧的构建文件干扰。例如:
rm -rf /path/to/build/directory
mkdir -p /path/to/build/directory
cd /path/to/build/directory
cmake /path/to/source/directory
make
示例:CMake 配置示例,展示如何确保静态库中的符号被正确链接:
链接静态库
target_link_libraries(${PROJECT_NAME}
-Wl,--whole-archive ${Geometry_LIB} -Wl,--no-whole-archive
OtherLibrary1
OtherLibrary2
)
通过以上方法,可以有效解决链接过程中找不到符号的问题,确保静态库中的符号被正确链接到最终的可执行文件或动态库中。