cmake: target_link_libraries utilise une bibliothèque statique non partagée

Est-il possible de dire à cmake de se lier à une bibliothèque statique au lieu de la partager ?

En haut de mon CMakeLists.txt j’ai configuré les éléments suivants:

 set(CMAKE_FIND_LIBRARY_SUFFIXES .a ${CMAKE_FIND_LIBRARY_SUFFIXES}) 

Plus tard, j’ajoute un binary et lui dis de lier avec tcmalloc en mode release:

 target_link_libraries(${BIN_NAME} optimized tcmalloc_minimal) 

Les liens makefile résultants contre la version partagée de tcmalloc :

 $ make VERBOSE=1 | grep tcmalloc /usr/bin/c++ ... -Wl,-Bdynamic ltcmalloc_minimal 

Preuve supplémentaire:

 $ ldd app ... libtcmalloc_minimal.so.4 => /usr/local/lib/libtcmalloc_minimal.so.4 (0x00007eff89733000) ... 

Les versions statiques et partagées de tcmalloc existent:

 $ ls -1 /usr/local/lib/libtcmalloc_minimal* /usr/local/lib/libtcmalloc_minimal.a /usr/local/lib/libtcmalloc_minimal_debug.a /usr/local/lib/libtcmalloc_minimal_debug.la /usr/local/lib/libtcmalloc_minimal_debug.so /usr/local/lib/libtcmalloc_minimal_debug.so.4 /usr/local/lib/libtcmalloc_minimal_debug.so.4.2.6 /usr/local/lib/libtcmalloc_minimal.la /usr/local/lib/libtcmalloc_minimal.so /usr/local/lib/libtcmalloc_minimal.so.4 /usr/local/lib/libtcmalloc_minimal.so.4.2.6 

Question:

Comment configurer cmake pour créer un lien avec la version statique de tcmalloc ?

Si vous avez uniquement besoin de prendre en charge des plates-formes autres que Windows, cet ancien message de la liste de diffusion CMake de l’un des développeurs Kitware vous offre la méthode la plus simple. Essentiellement, utilisez find_library() pour trouver l’emplacement de la bibliothèque réelle, en privilégiant les bibliothèques statiques par rapport aux bibliothèques partagées en les répertoriant d’abord dans les noms à rechercher. c’est à dire

 find_library(TCMALLOC_LIB NAMES libtcmalloc_minimal.a tcmalloc_minimal) 

Vous feriez alors un lien vers la bibliothèque trouvée de la manière habituelle:

 target_link_libraries(${BIN_NAME} ${TCMALLOC_LIB}) 

Vous pourriez être plus intelligent sur la façon dont vous définissez le nom de la bibliothèque statique si vous devez prendre en charge des plates-formes où une bibliothèque statique s’appelle autre chose que lib???.a . Vous utiliseriez les variables CMAKE_STATIC_LIBRARY_PREFIX et CMAKE_STATIC_LIBRARY_SUFFIX pour cela.

Sous Windows, le problème est que vous ne pouvez pas faire la distinction entre une bibliothèque statique et la bibliothèque d’importation pour une DLL, comme indiqué dans cet ancien problème du gestionnaire de bogues de Kitware. Les deux ont l’extension de fichier .lib , vous ne pouvez donc pas utiliser l’extension pour déterminer si un fichier particulier est une bibliothèque statique ou non, contrairement aux plates-formes Unix où vous le pouvez.

Vous pouvez créer une fonction d’assistance qui définit CMAKE_FIND_LIBRARY_SUFFIXES à la scope de la fonction ( n’affecte donc pas la scope parent ) qui recherche la bibliothèque en question et définit une variable de sortie avec le résultat.

 function(find_static_library LIB_NAME OUT) if (WIN32 OR MSVC) set(CMAKE_FIND_LIBRARY_SUFFIXES ".lib") elseif (UNIX) set(CMAKE_FIND_LIBRARY_SUFFIXES ".a") endif() find_library( FOUND_${LIB_NAME}_STATIC ${LIB_NAME} ) if (FOUND_${LIB_NAME}_STATIC) get_filename_component(ABS_FILE ${FOUND_${LIB_NAME}_STATIC} ABSOLUTE) else() message(SEND_ERROR "Unable to find library ${LIB_NAME}") endif() set(${OUT} ${ABS_FILE} PARENT_SCOPE) endfunction() 

Vous pouvez ensuite appeler cette fonction à partir de quelque part dans CMakeLists.txt pour remplir une variable avec l’emplacement de la bibliothèque.

Si vous ne le trouvez pas, cela entraîne une défaillance grave

 find_static_library(tcmalloc_minimal TCMALLOC) 

Vous pouvez ensuite utiliser cette variable dans votre appel à target_link_libraries et vous assurer que vous êtes target_link_libraries à la version statique.

 target_link_libraries(${BIN_NAME} optimized ${TCMALLOC}) 

Ici vous pouvez voir le résultat:

 $ make VERBOSE=1 | grep tcmalloc 
 /usr/bin/c++ ... /usr/local/lib/libtcmalloc_minimal.a ... 

Vous devez définir votre variable CMAKE_FIND_LIBRARY_SUFFIXES de cette manière:

 set(CMAKE_FIND_LIBRARY_SUFFIXES .a) 

car par défaut CMAKE_FIND_LIBRARY_SUFFIXES, il y a aussi le suffixe .so (et il ne semble pas chercher dans l’ordre d’insertion). Pour permettre la portabilité, d’autres suffixes doivent être ajoutés (voir ici les valeurs par défaut de CMAKE_FIND_LIBRARY_SUFFIXES sur différentes plates-formes).