web-dev-qa-db-fra.com

CMake et liaison statique

J'utilise CMake dans un projet et j'essaie de lier statiquement certaines bibliothèques. J'ai réglé:

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)

Et je me suis assuré lors de la recherche des bibliothèques réelles que j'en ai la version * .a.

Actuellement, le projet importe:

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

Toutes les bibliothèques sont trouvées, et lorsque vous effectuez une liaison dynamique/partagée, elles fonctionnent correctement. J'ai également essayé de définir des drapeaux de compilation:

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

Mais en vain. Bien que je n'obtienne aucun problème lors de la compilation, la liaison génère de nombreuses erreurs référence non définie pour les appels trouvés dans les bibliothèques ci-dessus, à savoir:

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

Pas dans cet ordre particulier, et de nombreuses erreurs pour chaque bibliothèque.

En regardant la dernière ligne de GCC, je vois:

/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++

Ce qui me fait me demander:

  1. Pourquoi les bibliothèques Poco sont-elles liées en tant que -rdynamic, et il n'y a pas d'indicateur -Wl -Bstatic? Comme s'ils étaient ignorés/exclus de la liaison statique.
  2. mysqlclient, mysqlpp et crypto ++ semblent être définis pour la liaison statique, mais je reçois toujours des erreurs

Alors, quelqu'un pourrait-il m'expliquer:

  1. Comment configurer la liaison statique partielle à l'aide de CMake
  2. CMAKE_EXE_LINKER_FLAGS est-il le seul que je dois définir?
  3. Dois-je forcer la liaison statique pour les bibliothèques mentionnées mais pas pour l'ensemble du projet?

Veuillez m'excuser s'il s'agit de questions trop nombreuses ou trop localisées, je n'ai jamais essayé cela auparavant et je n'arrive pas à trouver beaucoup d'informations sur le net.

26
Ælex

J'ai réussi à résoudre mon problème en utilisant ce qui suit:

#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++")

Cela fonctionne sans passer un -static ce qui crée d'autres gros problèmes, et peut essentiellement mélanger des bibliothèques statiques et dynamiques.

Tant que l'ordre des bibliothèques statiques est correct, et tant que les dépendances des bibliothèques statiques sont satisfaites, j'obtiens un ELF qui charge ce qui est dynamique (c'est-à-dire dans mon cas mysqlclient, libmysql ++) et statique tout le reste (crypto ++, PocoNet , PocoUtil, PocoXML, PocoFoundation).

Gardez à l'esprit que les bibliothèques liées statiques ont leurs propres dépendances. En examinant mon application de débogage à l'aide de l'application readelf -d, je vois:

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]

Je sais que pthread est importé par Poco :: Runnable, libm est pour les opérations mathématiques, etc. Je ne sais toujours pas si c'est la bonne façon d'utiliser CMake pour la liaison statique partielle.

Dans le cas des bibliothèques packagées Debian, telles que crypto ++, mysql ++, mysqlclient, trouver simplement la bibliothèque * .a a fonctionné, mais dans le cas des bibliothèques Poco, qui ne m'ont obtenu que le chemin d'accès complet et le nom de la bibliothèque, mais pas un indicateur, -Bdynamic n'a pu être désactivé qu'en utilisant les lignes ci-dessus.

Remarque: Poco n'a pas pu être lié statiquement, sans -static-libstdc++

J'espère que cela aide toute personne coincée à quelque chose de similaire.

28
Ælex

Comment configurer la liaison statique à l'aide de CMake

Eh bien ... vous ne le faites pas :) Ce n'est pas ainsi que CMake fonctionne: dans CMake, vous trouvez d'abord le chemin absolu d'une bibliothèque, puis vous y liez avec target_link_libraries.

Donc, si vous souhaitez créer un lien vers une bibliothèque statique, vous devez rechercher cette bibliothèque statique:

find_library(SOMELIB libsomelib.a)

au lieu de:

find_library(SOMELIB somelib)
15
Guillaume