Reputation: 24072
I have a project which compiles fine on Xcode 7.2 and earlier, but gets linker errors when compiling with Xcode 7.3. I've been able to narrow it down to a simple example project that duplicates the problem.
The basic project structure is like this:
.
├── one
│ ├── lib
│ │ └── lib1.dylib
│ └── src
│ └── one.c
├── two
│ ├── lib
│ │ └── lib2.dylib
│ └── src
│ └── three.c
└── three
├── lib
│ └── lib3.dylib
└── src
└── two.c
lib3
links with lib2
, and lib2
links with lib1
. When the library is compiled, its output is in the ../lib
directory relative to its src
directory.
When I try to compile lib3
, it errors with file not found: ../lib/lib1.dylib
, even though ../../one/lib
is in the library search path.
What strange and mystical linker flag can I use to get the search paths to work out okay? Or is this a bug with Xcode?
/Applications/Xcode.app/Contents/Developer/usr/bin/make -C one/src
cc -I ../../include -c -o one.o one.c
cc -dynamiclib -undefined dynamic_lookup -flat_namespace -o ../lib/lib1.dylib one.o
/Applications/Xcode.app/Contents/Developer/usr/bin/make -C two/src
cc -I ../../include -c -o two.o two.c
cc -dynamiclib -undefined dynamic_lookup -flat_namespace -L ../../one/lib -o ../lib/lib2.dylib two.o -l1
/Applications/Xcode.app/Contents/Developer/usr/bin/make -C three/src
cc -I ../../include -c -o three.o three.c
cc -dynamiclib -undefined dynamic_lookup -flat_namespace -L ../../two/lib -L ../../one/lib -o ../lib/lib3.dylib three.o -l2
ld: file not found: ../lib/lib1.dylib for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make[1]: *** [../lib/lib3.dylib] Error 1
make: *** [all] Error 2
Upvotes: 1
Views: 261
Reputation: 122468
OK it took me a while to fix this error. I knew that part of the issue was setting the runpath and the install name of the libraries, so they could be found during linking and at runtime, which would be the next issue you faced.
I settled for building the libraries into a common top-level lib
directory, however at the end of the day I'm pretty sure that actually wasn't necessary, but it did cut down on command line options being passed to the linker which is very cumbersome as it needs to be done with -Wl,-linker-option
and -Wl,linker-option-argument
as you are using cc
for linking rather than ld
directly.
I think the actual answer is to add -l1
to your three/src/Makefile
line:
$(LD) -o $@ $< -l2 -l1
It's not clear to me why this was necessary as if lib3
depends on lib2
then it shouldn't be necessary to add lib2
's dependencies into the linker line. It's perhaps something to do with your use of -undefined dynamic_lookup
, as I've never seen that option used before. However I didn't have time to experiment fully with this.
If you make this change to your version of the Makefile
s you will likely have runtime issues as the runpath and install name are implied from whatever you passed to -L
(which was ../../one/lib
and ../../two/lib
and they will almost certainly be wrong at runtime). Therefore it's better to explicitly set the runpath and install name, and every library had their runpath set to @loader_path/
and their install name set to @rpath/libX.dylib
. The executable that uses these libraries will likely want a different runpath in order to find the libraries.
See my pull request for the changes I made.
I would like to commend you on how you presented this question with a testable project hosted on github; without that you would be unlikely to get any decent feedback.
Upvotes: 1