Missing symbols from static library in linked executable - c++

I have a problem with static library symbols missed in linked executable.
Here is the description of my problem:
I have static library built from several object files. These object files provides sevaral groups of symbols, associated with:
A set of C functions and structs (several object files). Let's call corresponding symbols level1 symbols.
A set of C++ wrapper classes for this C functions and structs (another object file). Let's call corresponding symbols level2 symbols.
A set of C++ wrapper classes inhereted from level 2 classes (another object file) with extended functionality. Let's call corresponding symbols level3 symbols.
Undeground C code uses several other project and external libs. Some of them are static, so currently this lib is static too.
Library is linked with executable file. This file used directly only level2 symbols from lib. But some dynamic libraries loaded by this executable during execution needs level3 symbols.
The problem is, that level3 symbols for some reason are missed into this executable(nm approved).
Library itself contains all groups of symbols. ALso there is another executable linked with this library and it also contains all groups of symbols. The main difference between these executables is that second executable (where all symbols are presented) uses leve3 symbols directly.
The whole project is built with CMake in debug configuration (this means "-g" option is presented in g++ commands). The underlying OS is GNU/Linux x86_64. g++ version is 4.4.
I've checked several similiar questions on StackOverflow but I haven't found any acceptable solution.
I've already tried several linking options to solve the problem (--export-dynamic, --whole_archive) but neither helps.
I'll be glad to see any ideas to solve this problem or, at least, possible reasons of this strange behaviour.
This is command line used to build executable. Command was generated by CMake. I only add --whole_archive option, then delete executable and rerun command. I also hope you will excuse me for replacing all project specific names with "???".
exec_name - name of executable we are talking about
lib_name - name of library we are talking about
/usr/bin/c++ - symlink to g++ v4.4 executable
/usr/bin/c++ -Wextra -g -fPIC CMakeFiles/exec_dir.dir/main.cpp.o CMakeFiles/exec_dir.dir/options.cpp.o CMakeFiles/exec_dir.dir/runtime.cpp.o CMakeFiles/exec_dir.dir/plugins.cpp.o CMakeFiles/exec_dir.dir/CServer.cpp.o -o exec_name -rdynamic ../lib/???/lib???.a --whole-archive ../../lib/???/???/lib_name.a ../lib/???/lib???.so ../../lib/???/???/lib???.a ../../???/???/lib???.a ../../lib/???/lib???.a -ldl -lboost_filesystem -lboost_signals -lboost_system -lboost_thread ../../lib/???/lib???.so /usr/local/ssl/lib64/libcrypto.so -ldl -luuid -lodbc ../lib/log/lib???.so ../lib/config/lib???a -lpthread ../../???/???/lib???.a -Wl,-rpath,/home/beduin/???/build/deb/???/lib/???:/home/beduin/???/build/deb/lib/???:/usr/local/ssl/lib64

Use -rdynamic -Wl,-whole-archive <all your libs> -Wl,-no-whole-archive <boost, pthread and so on> - one of your libs aren't within --whole-archive

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.

Using --whole-archive linker option with CMake and libraries with other library dependencies

I've got a project that used to be a giant set of source files that all got compiled and then linked as one executable. As a first step in making the project more modular, I am breaking up the build into several smaller chunks and making them static libraries. There's a hierarchy, so Exe1 will link against static libs Lib2A and Lib2B. Lib2A will depend on static Lib3A, lib3B, lib3C, etc. The numbers here show their layer in the hierarchy.
The problem is that I need to use --whole-archive when linking or else some symbols from the underlying libraries are not found.
When I add the below for the linking of Exe1:
target_link_libraries(Exe1 -Wl,--whole-archive Lib2A Lib2B -Wl,--no-whole-archive)
I end up with an actual link stage command like:
g++ -o Exe1 -Wl,--whole-archive libLib2A.a libLib2B.a -Wl,--no-whole-archive libLib3A.a libLib3B.a libLib3C.a
Inevitably, symbols from some of the layer 3 static libraries get lost and I get missing symbol errors.
I expected that because Lib2A has Lib3* libraries as dependencies, that they would also be "inside" the --whole-archive part of the linker command, but they show up outside.
I've tried many different combinations (e.g. putting the --whole-archive stuff at lower layers), but haven't come across an approach that works using CMake. What am I doing wrong?
Thanks
For 3.12 and newer versions of CMake, I would use object libraries.
The workaround I found for versions earlier than that was to create an intermediate static library that used some property magic to place all linkage dependencies inside the --whole-archive section. For me, the top-level static library was called 'source'. It contained actually nothing itself, but had linkage dependencies on a bunch of other static libraries. I created 'source-combined' as follows:
add_library(source-combined STATIC "")
set_target_properties(source-combined PROPERTIES LINKER_LANGUAGE CXX)
target_link_libraries(source-combined PUBLIC
-Wl,--whole-archive
$<TARGET_PROPERTY:source,INTERFACE_LINK_LIBRARIES>
-Wl,--no-whole-archive
)
Now when I create an executable or a shared library by linking against this souce-combined library, I get the --whole-archive and --no-whole-archive as bookends around the entire set of static libraries that were the link dependencies of 'source'. It took forever to stumble across this technique, so I'm sharing it.
The following worked for me. Consider two libraries:
my_platform
my_clib
We want the whole archive of my_clib, and my_platform links to it.
add_library(my_platform INTERFACE) # this could also be a regular library
add_library(my_clib STATIC)
target_sources(my_clib
PRIVATE
gcc_newlib_nano.c
gcc_newlib_nano_cpp.cc
)
# Link my_clib and any other libs
target_link_libraries(my_platform
INTERFACE
my_clib
)
# Ensure the whole archive is linked
target_link_options(my_platform
INTERFACE
-Wl,--whole-archive ${CMAKE_CURRENT_BINARY_DIR}/libmy_clib.a -Wl,--no-whole-archive
)
As an alternative to the above answer, I needed to get something quick and dirty to see if the effort to add whole archive target flags (or convert the code base to object libraries...) was the right solution. By following the CMake Source Code for the default link command, I modified my project's command to:
set(CMAKE_CXX_LINK_EXECUTABLE "<CMAKE_CXX_COMPILER> <FLAGS> <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> -Wl,--start-group -Wl,--whole-archive <LINK_LIBRARIES> -Wl,--no-whole-archive -Wl,--end-group")
It worked a treat! While not the greatest solution, it will at least get some results quickly.
If you need to use the linker option --whole-archive, then you definably should use object libraries:
# Lib2A/CMakeLists.txt
add_library(Lib2A OBJECT ${Lib2A_SRC})
# Lib2B/CMakeLists.txt
add_library(Lib2B OBJECT ${Lib2B_SRC})
It is portable and does not require use the linker option --whole-archive.

Static and Dynamic/Shared Linking with MinGW

I want to start with a simple linking usage to explain my problem. Lets assume that there is a library z which could be compiled to shared library libz.dll(D:/libs/z/shared/libz.dll) or to static library libz.a (D:/libs/z/static/libz.a).
Let I want to link against it, then I do this:
gcc -o main.exe main.o -LD:/libs/z/static -lz
According to this documentation, gcc would search for libz.a, which is
archive files whose members are object files
I also can do the following:
gcc -o main.exe main.o -LD:/libs/z/shared -lz
It is not mentioned in the documentation above that -l flag will search for lib<name>.so.
What will happen if I libz.a and libz.dll will be in the same directory? How the library will be linked with a program? Why I need the flags -Wl,-Bstatic and -Wl,-Bdynamic if -l searches both for shared and static libraries?
Why some developers provide .a files with .dll files for the same modules, if I compile a shared library distribution?
For example, Qt provides .dll files in bin directory with .a files in lib directory. Is it the same library, but built like shared and static, respectively? Or .a files are some kind of dummy libraries which provide linking with shared libraries, where there are real library implementations?
Another example is OpenGL library on Windows. Why every compiler must provide the static OpenGL lib like libopengl32.a in MingW?
What are files with .dll.a and .la extensions used for?
P.S. There are a lot of questions here, but I think each one depends on the previous one and there is no need to split them into several questions.
Please, have a look at ld and WIN32 (cygwin/mingw). Especially, the direct linking to a dll section for more information on the behavior of -l flag on Windows ports of LD. Extract:
For instance, when ld is called with the argument -lxxx it will attempt to find, in the first directory of its search path,
libxxx.dll.a
xxx.dll.a
libxxx.a
cygxxx.dll (*)
libxxx.dll
xxx.dll
before moving on to the next directory in the search path.
(*) Actually, this is not cygxxx.dll but in fact is <prefix>xxx.dll, where <prefix> is set by the ld option -dll-search-prefix=<prefix>. In the case of cygwin, the standard gcc spec file includes -dll-search-prefix=cyg, so in effect we actually search for cygxxx.dll.
NOTE: If you have ever built Boost with MinGW, you probably recall that the naming of Boost libraries exactly obeys the pattern described in the link above.
In the past there were issues in MinGW with direct linking to *.dll, so it was advised to create a static library lib*.a with exported symbols from *.dll and link against it instead. The link to this MinGW wiki page is now dead, so I assume that it should be fine to link directly against *.dll now. Furthermore, I did it myself several times with the latest MinGW-w64 distribution, and had no issues, yet.
You need link flags -Wl,-Bstatic and -Wl,-Bdynamic because sometimes you want to force static linking, for example, when the dynamic library with the same name is also present in a search path:
gcc object1.o object2.o -lMyLib2 -Wl,-Bstatic -lMyLib1 -Wl,-Bdynamic -o output
The above snippet guarantees that the default linking priority of -l flag is overridden for MyLib1, i.e. even if MyLib1.dll is present in the search path, LD will choose libMyLib1.a to link against. Notice that for MyLib2 LD will again prefer the dynamic version.
NOTE: If MyLib2 depends on MyLib1, then MyLib1 is dynamically linked too, regardless of -Wl,-Bstatic (i.e. it is ignored in this case). To prevent this you would have to link MyLib2 statically too.

Correctly linking GLX library in Ubuntu

I'm trying to compile one of these mixes of X11 + OpenGL, but I'm not having luck with the compiler. In particular, I get:
undefined symbol: glXMakeCurrent
I have tried
-lX11 -lGLU -lGL -lXext
as arguments to the linker, and some permutations of them, with no luck so far.
I'm running Ubuntu 12.04, and I have installed all the development packages related to opengl that I had a fuzzy idea could be related. I'm also developing in C++, something that could cause problems if the opengl headers are not prepared for it... but they are right?
I even looked for the symbol explicitly with an fgrep in /usr/lib/x86_64-linux-gnu/, but it is not there, and furthermore, `nm' says that there are no symbols.
So, what's the correct way of linking with glx?
EDIT: It is linking problem, the error is produced when python tries to load the compiled (and incorrectly linked) module. Not at compilation time.
EDIT: Here is the compilation log
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
g++ -o build/debug/objects/alve/layouter/flowing_data.os -c -std=c++0x -g -I/usr /include/python2.7 -fPIC -I/opt/cairo_new/include/cairo/ -I/opt/boost_1_48_0/include -DMIC_RT_SPEED_BACKS -Icsrc csrc/alve/layouter/flowing_data.cpp
g++ -o build/debug/objects/alve/layouter/liblayouter.so -L/opt/cairo_new/lib -L/opt/boost_1_48_0/lib -shared build/debug/objects/alve/layouter/flowing_data.os build/debug/objects/alve/layouter/show_network.os -Lbuild/debug/lib -Llibdeps
Install file: "build/debug/objects/alve/layouter/liblayouter.so" as "build/debug/lib/liblayouter.so"
g++ -o build/debug/objects/alve/layouter/liblayouter_mod.so -L/opt/cairo_new/lib -L/opt/boost_1_48_0/lib -shared build/debug/objects/alve/layouter/module.os Lbuild/debug/lib -Llibdeps -lboost_python build/debug/objects/alve/layouter/liblayouter.so -lcairo -lX11 -lGL -lGLU -lXext
scons: done building targets.
and here is how the function is called:
glXMakeCurrent (dpy, win, ctx);
The message "undefined symbol" indicates that it's not a linker, but a compilation unit problem: The compiler does not know the symbol glXMakeCurrent because it has been neither declared, nor defined, but you use it.
Probably the GLX header has not been included.
Add
#include <GL/glx.h>
As it turns out OPs problem was related to the fact, that the build consisted of cascading shared objects forming a Python module. One shared object implements the actual OpenGL operations, while the other does the interfacing to the Python interpreter.
Now shared objects (.so) are fully qualified ELF binaries themself, each with their own import and export symbol table. A shared object can be configured to expose all the symbols of other shared object it links to. However a shared object will not see any symbols of the compilation units they're linked into (if you think about it, this is to be expected, as a shared object can not and should not make any assumptions about the environment it's going to be linked into).
Hence, when compiling and linking multiple shared object in a larger build it's important to individually link each shared object to any libraries it will need at runtime.
As #datenwolf ways, special precautions are needed for linking. Which are them is a mystery for me, but using ldd helps. So basically what I did was to use ldd in both the final and the intermediate shared objects. Despite the command line arguments, my library didn't get linked with libGL and its dependencies until I also included the '-lGL -lGLU -lX11' in the intermediate step (production of 'liblayouter.so').

how to build a static library properly?

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.