Linux动态库链接题目常见错误(/usr/bin/ld或者undefined reference to)报
Linux体系下编译和运行步伐时候,经常出现动态库链接的题目,主要有两种环境,一种是编译的时候链接题目,另一种是运行的时候链接。编译链接题目
起首我们要明白C++编译的过程,主要有两步。
[*] 编译阶段:
编译阶段,编译器会将源码编译为目的文件(.o文件)。编译会将源码中函数转换特定的链接符号。
[*] 链接阶段
链接阶段,会根据目的文件中链接符号信息,去链接对应动态库,并记录一些信息,如函数的内存地址偏移量等信息。
在链接阶段需要知道要链接的动态库或者静态库的名字和地址,编译器是如何知道的了,答案是CMakeLists.txt中target_link_libraries()函数
target_link_libraries(my_executable /path/to/*.so)
有的时候target_link_libraries()只指定了对应动态库函数的名称,并没有指定动态库函数的地址,比方:
target_link_libraries(my_executable gtsam)#链接到gtsam库
target_link_libraries(my_executable ${OpenCV_LIBRARIES})#链接到Opencv的动态库
这时候编译如何找到对应动态库的地址,答案是find_package()和link_directories() 函数。find_package()会在动态库对应的cmake文件中设置动态库变量的路径(比方${OpenCV_LIBRARIES})。或在在link_directories()指定路径,比方:
link_directories(/path/to/lib)
因此编译步伐的时候如果没有指定链接库的路径或在链接的库的名称,就会报以下两种错误:
[*] undefined reference to
这种是因为没有指定要链接的库,即target_link_libraries()中没有添加对应的动态的名称。源码编译阶段,生成了库函数的链接符号。却在链接的时候找不到具体的实现方式。这里根据undefined reference to的具体内容,来检察是哪个库函数。以_ZN3tbb8internal23allocate_via_handler_v3Em 为例。_ZN3tbb8internal23allocate_via_handler_v3Em 是一个经过 C++ 名字修饰(name mangling)处理的符号名。这个符号名代表了一个特定的函数或变量,具体来说,它是 Intel TBB(Threading Building Blocks)库中的一个内部函数。我们可以通过名字修饰的规则来剖析这个符号。
名字修饰剖析
[*] _Z: 这是一个前缀,表示这是一个经过修饰的符号。
[*] N3tbb: 这部分表示定名空间。N3 表示定名空间的长度为 3,反面的 tbb 是定名空间的名称。因此,这里表示 tbb 定名空间。
[*] 8internal: 这部分表示一个类或布局体的名称。8 表示名称的长度为 8,反面的 internal 是类名。因此,这里表示 internal 类。
[*] 23allocate_via_handler_v3: 这部分表示函数的名称。23 表示名称的长度为 23,反面的 allocate_via_handler_v3 是函数的名称。
[*] Em: 这部分表示函数的参数类型。E 表示该函数担当一个 size_t 类型的参数(通常用于表示内存巨细),而 m 表示该参数是一个 double 类型(在某些环境下可能表示其他类型,具体取决于上下文)。
[*] 因此,_ZN3tbb8internal23allocate_via_handler_v3Em 代表的是 tbb::internal::allocate_via_handler_v3(double) 这个函数。这个函数可能用于在 TBB 中处理内存分配的某种方式。符号名根据 定名空间-类名-函数名-函数参数来定名的
当然,也存在链接的库里没有对应的函数,这个也需要考虑对应的函数版本是否精确。通过 ldd -r xxx.so 下令检察so库链接状态和错误信息。
[*]/usr/bin/ld
/usr/bin/ld报错,是因为指定了要链接库的名称却没有指定其路径。虽然指定了动态库的名称,链接器找不到要链接的库在哪。
find_package(GTSAM REQUIRED QUIET)
target_link_libraries(my_executable gtsam)#链接到gtsam库
比方上述式子,虽然指定了gtsam动态库,并且通过find_package(GTSAM REQUIRED QUIET)指定了gtsam包的路径。但是gtsam的cmake文件中并没有指出对应gtsam动态库的路径。有的包cmake文件并不会指出动态的路径。如果找不到就手动设定,target_link_libraries()中添加动态库完整路径或在link_directories()设置链接库的路径。
运行链接题目
步伐运行时,需要链接对应的动态库。体系会从LD_LIBRARY_PATH和/etc/ld.so.conf设置文件中探求对应的动态库。如果运行/usr/bin/ld报错,就将对应动态库的路径添加到上述环境变量或在文件中。
在~/.bashrc中添加:
export LD_LIBRARY_PATH=/path/to/your/libs:$LD_LIBRARY_PATH
或在/etc/ld.so.conf中添加动态库的conf文件。
注意:环境变量$LD_LIBRARY_PATH和/etc/ld.so.conf中的设置只对运行时有效,编译不是按照这个路径探求的
运行时undefined refrence to的题目
理论上编译步伐的时候链接没有题目,运行的时候应该不会出现undefined refrence to的错误。但是,偶然候纵然编译成功了也会出现这种题目:
成功链接但在运行时出现未定义符号的环境通常与以下几个因素有关:
[*] 动态链接库缺失:
[*]如果步伐依靠于某个动态链接库(shared library),但在运行时找不到该库,或者库的版本不匹配,可能会导致未定义符号的错误。
[*] 符号的实现缺失:
[*]在某些环境下,链接器可能会找到符号的声明(比方,函数原型或类定义),但找不到其实现。比方,某个库的头文件中声明了一个函数,但在链接时没有提供该函数的实现。
[*] 条件编译:
[*]如果代码中利用了条件编译(如 #ifdef、#ifndef 等),某些符号可能在特定条件下被排除在外,导致在运行时找不到这些符号。
[*] C++ 名字修饰(Name Mangling):
[*]在 C++ 中,函数名会被编译器修饰以支持函数重载。如果链接时利用了不匹配的函数署名,可能会导致未定义符号的错误。
[*] 库的链接序次:
[*]在某些环境下,链接库的序次可能会影响符号的剖析。如果一个库依靠于另一个库,而链接序次不精确,可能会导致未定义符号的错误。
[*] 运行时环境题目:
[*]如果步伐在不同的环境中运行(比方,开发环境与生产环境),可能会因为环境中缺少某些库或版本不匹配而导致未定义符号的错误。
[*] 静态链接与动态链接的肴杂:
[*]如果在编译时利用了静态链接,但在运行时又试图利用动态链接库,可能会导致符号未定义的题目。
[*] 利用了不兼容的库版本:
[*]如果步伐依靠于某个库的特定版本,而在运行时利用了不兼容的版本,可能会导致未定义符号的错误。
解决方法
[*]检查依靠:利用工具(如 ldd)检查全部依靠库是否存在。
[*]确保符号实现:确保全部声明的符号都有对应的实现。
[*]检查条件编译:确认条件编译的宏定义是否精确。
[*]检查链接序次:确保链接库的序次精确。
[*]利用精确的库版本:确保利用的库版本与编译时一致。
通过以上方法,可以有效地排查息争决运行时未定义符号的题目。
undefined symbol题目的查找、定位与解决方法
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页:
[1]