Reputation: 4840
I'm trying to write a C program using a library. The library has provided a include/
and lib/
directory with header files and .dylib
files, respectively.
My file is in the same directory as include/
and lib/
. I'm trying to compile it with the following command:
clang -I"./include/" -L"./lib/" -lcsfml-graphics -lcsfml-window test.c
However, when I go to run my program, I get the following error:
% ./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
What is the correct way to compile using these libraries? I'd prefer to simply use the command line as I'm writing a small program, without having to set up Xcode, etc.
% 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
Upvotes: 5
Views: 8767
Reputation: 336
It seems that after fixing rpath with clang -I"./include/" -L"./lib/" -lcsfml-graphics -lcsfml-window -Wl,-rpath,"@executable_path/lib" test.c
you're still missing SFML libraries. I've just checked that CSFML depends on SFML, and based on your ls -l lib/
listing, SFML is clearly absent in lib/. My guess is that after fixing rpath you may not have noticed that the absent dependency has changed to @rpath/libsfml-graphics.2.4.dylib
instead of @rpath/libcsfml-graphics.2.4.dylib
. Please, download SFML libraries and put them into lib/.
Now to your question, how to build on macOS from the command line. Your building steps are correct, so I suppose the difficult part is how the dependencies are searched by dyld, not how they're linked with ld.
There are 4 ways a binary (an executable or a dynamic library) references its dependencies:
Now the question is how to ensure the dependencies are correctly referenced. As @mattmilten pointed out, there are 2 methods for that:
In order for the first method to work you need to make sure the identification names of the dependency libraries are correct. Suppose you're linking a binary against some library libA.dylib
. The identification name of libA.dylib is the default reference which will be used by the linker (ld) when building your binary. You can find it by looking at the first line of otool -L libA.dylib
(or alternatively at the LC_ID_DYLIB section of otool -l libA.dylib
). In case of libcsfml-graphics.2.4.dylib
it's @rpath/libcsfml-graphics.2.4.dylib
and it was passed to a.out on linking, that's why you're seeing it in the error message when dyld fails to meet it.
Setting a correct identification name is a responsibility of the libA.dylib authors. It is set according to their expectations as to where libA.dylib could be placed (using @rpath is a good choice) as well as their versioning scheme (in case of CSFML version 2.4.0 could be replaced with 2.4.x without losing binary compatibility). If you're building libA.dylib yourself you can set it with -install_name
param (e.g. clang -Wl,-dylib -Wl,-install_name,@executable_path/libA.dylib -o libA.dylib liba.c
). If it's a 3rd party library you can change it with install_name_tool -id @rpath/libA.dylib libA.dylib
.
Identification name, to the best of my knowledge, is only used during linking and not used when loading a binary, so if you prefer the second method of fixing incorrect references with install_name_tool you can ignore it.
Fixing the references with install_name_tool is simple but tedious. You'll probably need a script when there are a lot of incorrect references. All you need is the following set of commands (the binary
placeholder should obviously be replaced with an actual binary name):
install_name_tool -change @executable_path/libA.dylib @rpath/libA.dylib binary
to change reference @executable_path/libA.dylib
-> @rpath/libA.dylib
;install_name_tool -add_rpath @executable_path/lib binary
to add @executable_path/lib
to rpaths;install_name_tool -delete_rpath @executable_path/lib binary
to remove @executable_path/lib
from rpaths;otool -l binary
to check existing rpaths (just look at the LC_RPATH sections).Upvotes: 10
Reputation: 6706
You should check the environment variable DYLD_LIBRARY_PATH
. It should contain the path to libcsfml-graphics.2.4.dylib
. Another solution might be to add this path to your PATH
variable.
You can inspect the paths of your binary with otool -L
and modify them with install_name_tool -change
. Ideally, though, you should build your binary to contain the correct rpath to its dependencies using -R
when linking/compiling.
Upvotes: 1