how to build a static library properly? - c++

I use log4cxx logging library. I need to link with its static version to avoid additional binary dependencies. I use it in my dynamic library. Default build of log4cxx produces static library but I cannot link with it because it was compiled w/o -fPIC flag. So I changed log4cxx bulding as:
CPPFLAGS="-fPIC -static" ./configure
make
As a result I received a liblog4cxx.a that I can link with my .so library. Linking was done by Cmake, something like:
target_link_libraries(my_dynamic_lib log4cxx)
link_directories(relative_path_to_dir_where_liblog4cxx.a_lives)
Everything looked fine until runtime. I cannot load my_dynamic_lib.so because of undefined symbol "logger"
Please explain me what's wrong and how to resolve this problem.
thanks

You can verify whether the shared library contains the symbol by using
nm -g my_dynamic_lib.so | grep logger
If it is shown with symbol type U it means it's undefined.
Normally a shared library will not resolve all the symbols it needs until run-time, so it is possible (and perfectly normal) to link a shared library with missing symbols.
If you put -llog4cxx at the start of the linker command line for my_dynamic_lib.so then it won't link to any of the code in there, and will leave the logger symbol unresolved until run-time. To force it to use the symbols in the static library make sure you list the static library after the objects that need it:
g++ -fPIC -shared -o my_dynamic_lib.so obj1.o obj2.o -llog4cxx ...
I don't know how to do that with cmake, but it looks as though your CMakefile only links to log4cxx when linking the main executable, not the dynamic library.

Usually you would link liblog4cxx.a with your executable and not with your my_dynamic_lib.so. I don't think you can link like in your example unless you can provide documentation that says otherwise.

Related

How to embed a static library in a shared library (Linux)?

I have a static library which I do not have the source code, and need its symbols to be called dynamically from the LuaJIT FFI.
As it is static, I can't load it dynamically, so I'm trying to embed it in a shared library and then load the shared library at runtime.
Problem is that exported symbols of the static library are present in the symbols table of the shared lib, but are undefined.
nm libUSBDevices.a
shows a lot of lines, among which the symbols that interest me:
00001d80 T _ZN9USBDevice16FlightControllerC1EPKc
00001e30 T _ZN9USBDevice16FlightControllerD1Ev
00000140 T _ZN9USBDevice7AxisFctC1Ev
00000180 T _ZN9USBDevice7AxisFctclEv
Then I compiled the shared library using these two g++ commands :
g++ -m32 -c -Wall -Werror -fpic USBDevicesLoader.cpp -llibUSBDevices.a
which outputs USBDevicesLoader.o (USBDevicesLoader.cpp contains some exported functions which call symbols inside the static library, those ones are correctly present in the .so)
g++ -m32 -shared -o libUSBDevicesLoader.so USBDevicesLoader.o
This outputs the shared lib, but when loaded at runtime, it shows this:
[...] symbol lookup error: /home/me/USBDevices-loader/libUSBDevicesLoader.so: undefined symbol: _ZN9USBDevice16FlightControllerC1EPKc
And when I run nm on the shared lib, it shows the symbols as undefined:
U _ZN9USBDevice16FlightControllerC1EPKc
U _ZN9USBDevice7AxisFctclEv
I suggest the problem is somewhere in the compilation commands, I also tried to build the shared lib directly out of the .a without compiling the cpp first (just replace USBDevicesLoader.o in the second command by the .a, skip the first command) but the problem stays the same.
So, is there a way to embed all symbols of a static library (without having the source) in a dynamic lib which can then be loaded and used at runtime? Thanks
You can use the --whole-archive option to achieve this as seen here and in the docs:
--whole-archive: For each archive mentioned on the command line after the --whole-archive option, include every object file in the archive in the link, rather than searching the archive for the required object files. This is normally used to turn an archive file into a shared library, forcing every object to be included in the resulting shared library. This option may be used more than once.
As an example:
g++ -shared -o libnew.so -Wl,--whole-archive libmylib_static.a -Wl,--no-whole-archive
You can then link to the shared libnew.so library as you would normally do.

Linking in a static library failes, but linking a shared library succeeds

I can build my application against the shared library but I'm getting the unresolved symbol errors when linking it against the static version of the same library:
I can build my application this way:
g++ -lutils application.cpp -o application.exe
The above command links in the shared version of an utils library.
I'm trying link against the static version of the library like this:
g++ -l:utils.a application.cpp -o application.exe
Both times I'm using
export LD_LIBRARY_PATH=path/to/utils:$LD_LIBRARY_PATH
to inform g++ where utils.a is placed.
The unresolved symbol reported by ld is present in the output of the nm:
nm --defined-only path/to/utils.a
and is marked with the "T" (meaning that it is from the code section).
I'm trying to figure out what can be the reason of the problem.
Is it correct to use LD_LIBRARY_PATH to specify where to search for utils.a?
What is the exact command to verify that a static library defines (resolves) the symbol? Is the command
nm --defined-only path/to/utils.a
enough or should I use any additional options like
nm --defined-only --demangle path/to/utils.a
e.g.?
Just option -static should be enough for compiler. In case only one library has to be static, then -static- and lib name is short name not file name.
Is it correct to use LD_LIBRARY_PATH to specify where to search for utils.a?
As mentioned by #user10605163, LD_LIBRARY_PATH is not to find path to static library at compile and link time. It is an environment variable used in some Linux distribution to search shared libraries during run time. Please find more documentation here It is useful for build and test environment but not a recommended way of linking in production systems.
What is the exact command to verify that a static library defines (resolves) the symbol? Is the command nm --defined-only path/to/utils.a
Yes, that is correct. However based on the information provided this error is not likely an error with symbols not present in utils(as it worked with shared library), but with the linking.
Refer GNU documentation GCC link options
Excerpt:
-l library : Search the library named library when linking. The linker searches a standard list of directories for the library. The directories searched include several standard system directories plus any that you specify with -L.
Also, with -l link option you need to provide the library name (without 'lib' and extension) or full file name.
-lutils or -llibutils.a
You can also provide direct full path here only, if required.

How can I link dynamic library depending on another dynamic library?

I make a program using a dynamic library, libexample.so. The dynamic library depends on another dynamic library, libtool.so.
It looks linker succeeded linking the libexample.so because of message from gcc.
Building target: libexample.so
Invoking: GCC C++ Linker
g++ -L/home/takehiro/Documents/documents/code/lib/tool -shared -o "libexample.so" ./classes/example.o ./classes/example_template.o ./classes/example_test.o ./classes/impl.o -ltool
Finished building target: libexample.so
cp libexample.so /home/takehiro/Documents/documents/code/lib/example
However, it failed to link it with the libtool.so.
ldd /home/takehiro/Documents/documents/code/lib/example/libexample.so
...
libtool.so => not found
...
I checked existence of the libtool.so under /home/takehiro/Documents/documents/code/lib/tool which is pointed by -L optoin at above linker by
ls /home/takehiro/Documents/documents/code/lib/tool
libtool.so
This is the first time to use a dynamic library depending another dynamic library. So I am so confused. Is it normal or malfunction? Why it cannot link them?
Does someone have a suggestion or a solution to me? I am very glad it.
Thank you very much.
All that the -L option does is tell the linker where the shared library is, at link time.
This does not have any effect on where the runtime loader searches for shared libraries. That's why the shared library fails to be loaded at runtime.
You also need to pass the -rpath option to the linker, when you're linking your shared library, in order to set the RPATH attribute on the shared library, that specifies where its dependencies are to be searched for. Something like
g++ -L/home/takehiro/Documents/documents/code/lib/tool \
-Wl,-rpath=/home/takehiro/Documents/documents/code/lib/tool \
... remaining options

How to add specific symbols from static library

I am trying to use --whole-archive option, but it seems to not work with -Xlinker. How can I add this option by using -Xlinker ?
Here is the whole story:
I write a main program A, and several shared libraries B1,B2,etc. main program will use dlopen to load these shared libraries at runtime. I compile main program A linking with ALL the possible static libraries used by main program (S1,S2...etc) or shared libraries (S3,S4...etc). then I compile shared library without static library.
When calling dlopen, the program fail because of undefined symbol in shared library. this symbol does exist in static library S3, but I can not find it in symbol table of main program.
So I add --whole-archive option when compiling main program, but the symbol still not exists in final binary. how can I add this symbol to main program while it is not direct used in main program.
So I add --whole-archive option when compiling main program
You still have not answered the question: what command line you used. Adding linker options when compiling in generally pointless: they only matter when linking.
The correct link line for the situation you described is (assuming you are using GCC on a UNIX/ELF system):
gcc -rdynamic -o exename main.c \
-Wl,--whole-archive -lS1 -lS2 -Wl,--no-whole-archive
Explanation of important points:
The -rdynamic is needed so that symbols defined in the main
executable are visible to dlopened shared libraries.
Libraries should follow sources on the link line (order of libraries and sources matters).
Libraries which you want to link in entirely should be surrounded by --whole-archive and --no-whole-archive options.

CMake: Shared library that uses static library

I am trying to create a shared library (really a Python module) that links against a static library. Both libraries are part of the same project and built using cmake.
Now, the shared library is built like this:
add_library(MyLibPython SHARED ${PYTHON_WRAPPERS_SRC})
set_target_properties(MyLibPython PROPERTIES PREFIX "")
target_link_libraries(MyLibPython MyLibStatic ${LIBS})
This builds without error, but when I try to import the Python module, I get:
ImportError:
lib/python/MyLibPython.so: undefined symbol: _Zone_of_my_MyLibStatic_functions
I also have a number of executables (unit tests) that are built in a similar way, and they work perfectly.
I should add, this is using gcc on Linux.
Check your linker command line. Is it passing something like -Wl,--as-needed? If so, it might not be including everything required by the static library.
I don't think your technique is portable in general. Can you get a shared library to link against? I think that there are some platforms where everything that goes into a shared library needs to be compiled as PIC.
Anyway, to link an entire archive with GNU ld (look up man ld):
gcc -o foo foo.o bar.o baz.o -Wl,--whole-archive libfoo.a -Wl,--no-whole-archive [rest-of-linker-args]