I want to create a shared library that uses functions from a 3rd-party static library. For example, foo and bar from libfoobar.a. I know that my main application is also using foo and will be exporting that symbol. So I simply want to link in bar to save code size and leave ‘foo’ unresolved (as it will be provided by main application). If I include libfoobar.a, the linker ld will include both functions in my shared library. If I don’t include libfoobar.a, my library will not have access to function bar because the application itself is not linking in bar. Questions:
- Is there a way to tell ld to only resolve certain symbols when building the shared library?
- Turn
libfoobar.ainto a shared library? - Extract file containing function
barfromlibfoobar.aand specify that on the linker line? - Don’t worry about it, the run-time loader will use
barfrom your application so the copy ofbarin the shared library will not be loaded?
The following points attempt to answer the questions I had posed:
--just-symbolsor--undefined(or theEXTERNlinker script command) will not prevent ld from linking the symbols.To convert a static library, libfoobar.a, into a shared one, libfoobar.so.1.0, and exporting all visible symbols. You can also use
--version-scriptand other methods to export only a subset of symbols.ld -shared -soname libfoobar.so.1 -o libfoobar.so.1.0 --whole-archive libfoobar.a --no-whole-archiveIt is better to delete archive members from a copy of your static library than it is to extract them because there may be internal dependencies you have to manage. For example, assuming you are exporting all symbols, you can generate a map file from your main executable. You can then grep for all the archive members that the executable pulled in from the copy of the static library and delete them from the copy. So when your DSO is linking in the static library, it will leave the same symbols unresolved.
It is possible to specify your main executable as a shared library for your DSO if you compile the executable with the
--pieoption. Your DSO will link first to your executable if it preceded the static library in the link command. The caveat is that the main executable must be available viaLD_LIBRARY_PATHor-rpath. Furthermore, using strace reveals that, since the executable is a dependency of your library, it is loaded again when your DSO loads.ld -shared -rpath '$ORIGIN' -L. -lc -ldl -o DSO.so DSO.o app libfoobar.aThe dynamic linker will use the executable’s version of foo first unless you call dlopen() with the
RTLD_DEEPBINDflag. Using strace reveals that the entire DSO is file mapped mmap2() into memory. However, Wikipedia claims that for mmap “The actual reads from disk are performed in “lazy” manner, after a specific location is accessed.” If this is true, then the duplicate foo will not be loaded. Note that the override only happens if your DSO exported the function foo. Otherwise, the function foo that was statically linked into your DSO will be used whenever your DSO calls foo.In conclusion, if mmap() uses a lazy read, then the best solution is to link your DSO in the normal manner and let the dynamic linker and linux take care of the rest.