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.
A short theory.
There are 4 ways a binary (an executable or a dynamic library) references its dependencies:
- by an absolute or relative path (the latter is relative to your working directory);
- by @executable_path, expanding to the path of the executable which is the root of the dependency tree (in case you have recursive dependencies);
- by @loader_path, expanding to the path of the executable or a library for which the dependency is searched, i.e. it's the path of the direct parent in the dependency tree;
- by @rpath, which is substituted in turn by each rpath found in your binary, and this is the most flexible way as you can search in several directories by having multiple rpaths.
Now the question is how to ensure the dependencies are correctly referenced. As @mattmilten pointed out, there are 2 methods for that:
- make your build system/build script/manual build commands ensure the references are correct;
- use install_name_tool to correct the broken references.
Making it automatic during the build.
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.
Manual fixing.
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).