How does a linker actually look for a library? A strange case of a missing path

Viewed 176

I have the following linker command:

/usr/bin/c++ CMakeFiles/test.dir/main.cpp.o -L/home/nc/code/linker_search_order_test/build/libb -lmylib

I hope it's pretty clear what I'm doing - I'm linking a compiled object file with some library mylib. Also, I specified a search path with -L option.

In the search folder instead of the binary file libmylib.so I put a linker script with the content:

 /* GNU ld script
   Use the shared library, but some functions are only in
   the static library, so try that secondarily.  */
OUTPUT_FORMAT(elf64-x86-64)
GROUP ( /lib/noexisting.so.0 )

This is what I see when I run the aforementioned command in verbose mode -Wl,--verbose (only the relevant part):

/usr/bin/c++ CMakeFiles/test.dir/main.cpp.o -L/home/nc/code/linker_search_order_test/build/libb -lmylib -Wl,--verbose
...
attempt to open /home/nc/code/linker_search_order_test/build/libb/libmylib.so succeeded
opened script file /home/nc/code/linker_search_order_test/build/libb/libmylib.so
opened script file /home/nc/code/linker_search_order_test/build/libb/libmylib.so
attempt to open /lib/noexisting.so.0 failed
/usr/bin/ld: cannot find /lib/noexisting.so.0

So this is what happened:

  • the linker found the linker script
  • the linker parsed the text and found the library to load
  • in my case the path points to the no existing file and the link process fails.

That's all fine and expected.

Now I want to alter the search path by providing a --sysroot option. According to documentation:

--sysroot=dir

Use dir as the logical root directory for headers and libraries. For example, if the compiler normally searches for headers in /usr/include and libraries in /usr/lib, it instead searches dir/usr/include and dir/usr/lib.

I'm trying the new command:

/usr/bin/c++ CMakeFiles/test.dir/main.cpp.o --sysroot=/home/nc/code -
L/home/nc/code/linker_search_order_test/build/libb -lmylib -Wl,--verbose
...
attempt to open /home/nc/code/linker_search_order_test/build/libb/libmylib.so succeeded
opened script file /home/nc/code/linker_search_order_test/build/libb/libmylib.so
opened script file /home/nc/code/linker_search_order_test/build/libb/libmylib.so
attempt to open /home/nc/code/lib/noexisting.so.0 failed
/usr/bin/ld: cannot find /lib/noexisting.so.0 inside /home/nc/code

Please note how the linker tries to open a library and appends a sysroot path (/home/nc/code/lib/noexisting.so.0). This is again perfectly fine, and the library is still not there.

But this is what puzzles me - if I change the sysroot to some different path, which is not a subpath of the linker script, this path simply ignored:

/usr/bin/c++ CMakeFiles/test.dir/main.cpp.o --sysroot=/home/nc/tools -L/home/nc/code/linker_search_order_test/build/libb -lmylib -Wl,--verbose
...
attempt to open /home/nc/code/linker_search_order_test/build/libb/libmylib.so succeeded
opened script file /home/nc/code/linker_search_order_test/build/libb/libmylib.so
opened script file /home/nc/code/linker_search_order_test/build/libb/libmylib.so
attempt to open /lib/noexisting.so.0 failed

Please note that now the sysroot (/home/nc/tools) is not a subpath of the linker script (/home/nc/code/..) and how it's ignored in an attempt to open the library.

I'm searching through different docs but can't find any explanation of this behavior and how to legally bypass the problem. In my real project, I'm cross-compiling and the sysroot is essential. Also, the -L path is generated by the CMake, and there is nothing I can do.

Update.

According to this page:

-L searchdir --library-path=searchdir

If searchdir begins with "=", then the "=" will be replaced by the sysroot prefix, a path specified when the linker is configured.

I tried to add = to my linker script. And it worked. So apparently, there's a way to tell the linker to search in other sub-paths. Unfortunately, I can't change scripts for the real project because a) there're lots of them and b) they are system scripts, like libc.so or pthread.so.

0 Answers
Related