leedm777
leedm777

Reputation: 24072

Xcode 7.3 + linking to relative paths = ld: file not found: ../lib/lib_.dylib

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

Answers (1)

trojanfoe
trojanfoe

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 Makefiles 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

Related Questions