CMake and Static Linking

2019-01-16 14:45发布

问题:

I'm using CMake in a project, and I'm trying to statically link some libraries. I've set:

set(BUILD_SHARED_LIBS OFF)
set(CMAKE_EXE_LINKER_FLAGS "-static-libgcc -static-libstdc++ -static")
set_target_properties(icarus PROPERTIES LINK_SEARCH_END_STATIC 1)

And I've made sure when looking for the actual libraries that I have the *.a version of them.

Currently the project imports:

libPocoNet.a 
libPocoUtil.a 
libPocoXML.a 
libPocoFoundation.a 
libmysqlclient.a 
libmysqlpp.a 
libcrypto++.a 
CUDA

All libraries are found, and when doing a dynamic/shared linkage, they work fine. I have also tried to set compilation flags:

set(GCC_CXX_FLAGS ${GCC_CXX_FLAGS} "-static-libgcc -static-libstdc++ -static")

But to no avail. While I get no issues while compiling, linkage is throwing alot of undefined reference errors for calls found in the above libraries, i.e:

undefined reference to `mysql_thread_init'
undefined reference to `mysql_real_query'
undefined reference to `pthread_mutex_unlock'
undefined reference to `Poco::ErrorHandler::handle()'

Not in that particular order, and numerous errors for each library.

Looking at the last line of GCC I see:

/usr/bin/c++   -g -g  -static-libgcc -static-libstdc++ -static [list of *.cpp files]
-o icarus -rdynamic /usr/local/lib/libPocoFoundation.a /usr/local/lib/libPocoNet.a
/usr/local/lib/libPocoUtil.a /usr/local/lib/libPocoXML.a 
-Wl,-Bstatic -lmysqlclient -lmysqlpp -lcrypto++

Which makes me wonder:

  1. Why are Poco libraries linked as -rdynamic, and there is no -Wl -Bstatic flag? As if they are skipped/excluded from static linkage.
  2. mysqlclient, mysqlpp and crypto++ seem to be set for static linkage, yet I still get errors

So, could someone please explain to me:

  1. How do I setup for partial static linkage using CMake
  2. Is CMAKE_EXE_LINKER_FLAGS the only one I need to set?
  3. Should I be forcing static linking for mentioned libraries but not for entire project?

Please excuse me if those are too many or too localized questions, I haven't tried this before, and I can't seem to find much info on the net.

回答1:

I've managed to solve my problem by using the following:

#Dynamic/Shared Libs
...
#Static start
set_target_properties(icarus PROPERTIES LINK_SEARCH_START_STATIC 1)
set_target_properties(icarus PROPERTIES LINK_SEARCH_END_STATIC 1)
set(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
#Static Libs
...
#Set Linker flags
set(CMAKE_EXE_LINKER_FLAGS "-static-libgcc -static-libstdc++")

This works without passing a -static which creates other big issues, and can essentially mix static and dynamic libraries.

As long as the order of static libraries is correct, and as long as dependencies of static libraries are satisfied, I get an ELF which loads what are are dynamic (i.e. in my case mysqlclient, libmysql++) and static all the rest (crypto++, PocoNet, PocoUtil, PocoXML, PocoFoundation).

Bear in mind that static linked libraries have their own dependencies. Examining my debug application using readelf -d app, I see:

Dynamic section at offset 0x508f88 contains 28 entries:
  Tag        Type                         Name/Value
 0x0000000000000001 (NEEDED)             Shared library: [libmysqlpp.so.3]
 0x0000000000000001 (NEEDED)             Shared library: [libmysqlclient.so.18]
 0x0000000000000001 (NEEDED)             Shared library: [libm.so.6]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
 0x0000000000000001 (NEEDED)             Shared library: [ld-linux-x86-64.so.2]
 0x0000000000000001 (NEEDED)             Shared library: [libpthread.so.0]

I know that pthread is imported by Poco::Runnable, libm is for math operations, etc. I am still unaware if this is the right way to use CMake for partial static linking.

In the case of Debian packaged libraries, such as crypto++, mysql++, mysqlclient, simply finding the *.a library worked, but in case of Poco Libraries, which only got me the full path and name of the library, but not a flag, -Bdynamic could only be turned off by using the above lines.

Note: Poco could not be linked statically, without -static-libstdc++

I hope this helps anyone stuck at something similar.



回答2:

How do I setup for static linkage using CMake

Well... you don't :) That's not how CMake works: in CMake, you first find the absolute path of a library, then link to it with target_link_libraries.

So, if you want to link to a static library, you need to search for that static library:

find_library(SOMELIB libsomelib.a)

instead of:

find_library(SOMELIB somelib)