我的问题与.so共享库有关。我正在构建一个在一台 ubuntu 机器上使用 cmake 但在另一台 ubuntu 机器上运行该应用程序的项目。
在 CMakeLists.txt 文件中,我有以下几行:
project (clientapp)
add_executable(${PROJECT_NAME} ${SOURCES} ${WAKAAMA_SOURCES} ${SHARED_SOURCES})
LINK_DIRECTORIES(/home/user//mraa-master-built/build/src)
target_link_libraries (clientapp libmraa.so)
target_link_libraries(clientapp m)
这些行将两个库 libmraa.so 和数学库添加到可执行文件中,并在另一台计算机上成功运行。
我对共享库的理解是,它们必须在编译时和应用程序启动时存在。但是我在另一台机器上没有 libmraa.so 文件,并且应用程序运行正常。我以为它不起作用。
我的假设正确吗?
通常,gcc
和clang
支持符号的延迟链接/绑定,但不支持整个库。这意味着所有共享对象(即:.so
文件)至少应在应用程序启动时存在。一个例外是,如果您修改了makefile以不链接到这些库,并且通过dlopen()
/dlsym()
等手动调用库函数。
这些库中各个符号的绑定可以推迟到需要它们之后,或者您可以分别使用-z lazy
或-z now
强制在启动时解析所有符号。
奇怪的是,您的应用程序在没有libmraa.so
的情况下运行。应用程序在没有库的情况下运行的两个最可能的原因是:
- 应用程序未使用库中定义的任何符号,因此链接器在生成时忽略库(尝试
ldd app_name
并查看库是否存在于ldd
提供的库列表中)。 - 构建脚本中存在问题,并且您正在静态链接到库的
.a
存档。
编辑:为了响应应用程序知道如何查找库的方式,链接器(在本例中为ld
)将使用rpath
查找来决定在搜索相应库时使用哪些目录。您可以通过从命令行执行类似LD_DEBUG=libs app_name
的操作来了解其工作原理。您还可以通过LD_LIBRARY_PATH=/some/path app_name
添加额外的路径。
我的假设正确吗?
是的。
对于应用程序运行的原因,有两种可能的解释:
- 你错了,机器上的某个地方有
libmraa.so
(尽管可能不在你看的地方),或者 - 默认情况下,编译器默认为
-Wl,--as-needed
,并且您的二进制文件实际上并不依赖于libmraa.so
,尽管它出现在链接行上。
您可以简单地确认或反驳上述任何一种猜测。
要确认猜测 2,请执行以下操作:
readelf -d clientapp | grep NEED | grep libmraa
# if there is no output, guess 2 is correct
如果猜测 2 是错误的,要确认猜测 1,请执行以下操作(在没有libmrra.so
的机器上):
ldd clientapp | grep libmraa.so
# if guess 2 is incorrect, and this command produces no output, then
# your dynamic loader is broken, which is very unlikely.