Well, I have something working. But I do not really understand why it works. This feels like a bug in ld to me.
I ran strace -f -o /var/tmp/strace.out -- g++ ...
for the main.run compilation. The static linker is actually trying to open files whose literal name looks like "$ORIGIN/lib/dir/sub/bar.so", among 20-30 other things. (In other words, it is looking for an actual directory named $ORIGIN
. Seriously.)
It also appears to be searching the -rpath-link path for the name "lib/dir/sub/bar.so", not just "bar.so". I have no clue why.
Anyway, this is the link for main.run that is working for me:
g++ -o run/main.run obj/main.o -Wl,-rpath,'$ORIGIN/../lib/dir' -Wl,-rpath-link,. -Llib/dir -l:foo.so
It is identical to yours but with -Wl,-rpath-link,.
inserted.
[addendum]
OK I think I see what is going on. First, the static linker (GNU ld) simply does not honor $ORIGIN in the libraries it links against.
Second, the behavior when you use -lbar
versus -l:bar.so
is very different.
Run readelf -a
on foo.so
. In your build, it shows a dependency on "lib/dir/sub/bar.so". This is why setting the rpath-link to "." fixes the build of main.run; it causes the static linker to search "." for "lib/dir/sub/bar.so", which it finds.
If you rename bar.so to libbar.so, and link foo.so to use -lbar
instead of -l:bar.so
, the same readelf shows that foo.so now depends on "libbar.so" (with no path component). With that foo.so, you can get the main.run link to work using -Wl,-rpath-link,lib/dir/sub
, as you would expect if you knew that the static linker simply does not honor $ORIGIN.
By the way, I do not see the -l:bar.so
syntax documented anywhere in the GNU ld manual. Out of curiosity, how did you come up with it?
Assuming it is a supported feature, this looks a bit like a bug (-l:bar.so creating a dependency on lib/dir/sub/bar.so instead of just bar.so). You can either deal with this bug by setting rpath-link to '.' for main.run, or you can rename stuff in the usual way (libxxx.so).