我正在尝试使用库编写C程序。该库提供了一个include/
和lib/
目录,分别包含头文件和.dylib
文件。
我的文件与include/
和lib/
在同一目录中。我正在尝试使用以下命令进行编译:
clang -I"./include/" -L"./lib/" -lcsfml-graphics -lcsfml-window test.c
但是,当我运行程序时,出现以下错误:
% ./a.out
dyld: Library not loaded: @rpath/libcsfml-graphics.2.4.dylib
Referenced from: ~/src/CSFML-2.4-osx-clang/./a.out
Reason: image not found
zsh: abort ./a.out
使用这些库进行编译的正确方法是什么?我宁愿在编写小型程序时简单地使用命令行,而不必设置Xcode等。
% ls -l lib/
-rwxr-xr-x@ 1 staff 50296 Mar 1 2017 libcsfml-audio.2.4.0.dylib*
lrwxr-xr-x@ 1 staff 26 Mar 1 2017 libcsfml-audio.2.4.dylib@ -> libcsfml-audio.2.4.0.dylib
lrwxr-xr-x@ 1 staff 24 Mar 1 2017 libcsfml-audio.dylib@ -> libcsfml-audio.2.4.dylib
-rwxr-xr-x@ 1 staff 163680 Mar 1 2017 libcsfml-graphics.2.4.0.dylib*
lrwxr-xr-x@ 1 staff 29 Mar 1 2017 libcsfml-graphics.2.4.dylib@ -> libcsfml-graphics.2.4.0.dylib
lrwxr-xr-x@ 1 staff 27 Mar 1 2017 libcsfml-graphics.dylib@ -> libcsfml-graphics.2.4.dylib
-rwxr-xr-x@ 1 staff 67272 Mar 1 2017 libcsfml-network.2.4.0.dylib*
lrwxr-xr-x@ 1 staff 28 Mar 1 2017 libcsfml-network.2.4.dylib@ -> libcsfml-network.2.4.0.dylib
lrwxr-xr-x@ 1 staff 26 Mar 1 2017 libcsfml-network.dylib@ -> libcsfml-network.2.4.dylib
答案 0 :(得分:4)
似乎用clang -I"./include/" -L"./lib/" -lcsfml-graphics -lcsfml-window -Wl,-rpath,"@executable_path/lib" test.c
修复了rpath之后,您仍然缺少SFML库。我刚刚检查了CSFML是否依赖于SFML,并且基于您的ls -l lib/
清单,lib /中显然没有SFML。我的猜测是,修复rpath之后,您可能没有注意到缺少的依赖项已更改为@rpath/libsfml-graphics.2.4.dylib
而不是@rpath/libcsfml-graphics.2.4.dylib
。请下载SFML库并将其放入lib/。
现在,您的问题是如何从命令行在macOS上构建。您的构建步骤是正确的,因此我认为最困难的部分是dyld如何搜索依赖项,而不是它们如何与ld链接。
二进制文件(可执行文件或动态库)有4种引用其依赖项的方式:
现在的问题是如何确保正确引用依赖项。正如@mattmilten指出的那样,有两种方法:
为了使第一种方法起作用,您需要确保依赖性库的标识名称是正确的。假设您要针对某个库libA.dylib
链接二进制文件。 libA.dylib的标识名称是默认引用,在构建二进制文件时,链接器(ld)将使用该默认引用。您可以通过查看otool -L libA.dylib
的第一行(或者在otool -l libA.dylib
的LC_ID_DYLIB部分中找到它)。如果是libcsfml-graphics.2.4.dylib
,它是@rpath/libcsfml-graphics.2.4.dylib
,并且在链接时被传递给a.out,这就是为什么当dyld无法满足它时,您会在错误消息中看到它的原因。
设置正确的标识名是libA.dylib作者的责任。根据他们对libA.dylib放置位置的期望(使用@rpath是一个不错的选择)以及其版本控制方案(如果CSFML版本2.4.0可以替换为2.4.x而不会丢失二进制文件)进行设置兼容性)。如果您要自己构建libA.dylib,则可以使用-install_name
参数(例如clang -Wl,-dylib -Wl,-install_name,@executable_path/libA.dylib -o libA.dylib liba.c
)进行设置。如果它是第三方库,则可以使用install_name_tool -id @rpath/libA.dylib libA.dylib
进行更改。
据我所知,标识名仅在链接期间使用,而在加载二进制文件时不使用,因此,如果您更喜欢使用install_name_tool修复不正确引用的第二种方法,则可以忽略它。
使用install_name_tool修复引用很简单,但很乏味。当有很多不正确的引用时,您可能需要一个脚本。您所需要做的只是以下命令(显然binary
占位符应替换为实际的二进制名称):
install_name_tool -change @executable_path/libA.dylib @rpath/libA.dylib binary
更改引用@executable_path/libA.dylib
-> @rpath/libA.dylib
; install_name_tool -add_rpath @executable_path/lib binary
将@executable_path/lib
添加到rpaths; install_name_tool -delete_rpath @executable_path/lib binary
从rpaths中删除@executable_path/lib
; otool -l binary
检查现有的rpath(只需查看LC_RPATH部分)。答案 1 :(得分:1)
您应该检查环境变量DYLD_LIBRARY_PATH
。它应包含到libcsfml-graphics.2.4.dylib
的路径。另一个解决方案可能是将此路径添加到您的PATH
变量中。
您可以使用otool -L
检查二进制文件的路径,并使用install_name_tool -change
对其进行修改。不过,理想情况下,在链接/编译时,应该使用-R
构建二进制文件以包含正确的rpath到其依赖项。