web-dev-qa-db-fra.com

Est-il possible d’obtenir que CMake construise à la fois une version statique et une version partagée de la même bibliothèque?

Même source, tout ça, je veux juste une version statique et partagée à la fois. Facile à faire?

123
gct

Oui, c'est modérément facile. Utilisez simplement deux commandes "add_library":

add_library(MyLib SHARED source1.c source2.c)
add_library(MyLibStatic STATIC source1.c source2.c)

Même si vous avez plusieurs fichiers sources, vous placeriez la liste des sources dans une variable cmake, afin que ce soit toujours facile à faire.

Sous Windows, vous devriez probablement attribuer un nom différent à chaque bibliothèque, car il existe un fichier ".lib" pour les fichiers partagé et statique. Mais sous Linux et Mac, vous pouvez même donner le même nom aux deux bibliothèques (par exemple, libMyLib.a et libMyLib.so):

set_target_properties(MyLibStatic PROPERTIES OUTPUT_NAME MyLib)

Mais je ne recommande pas de donner le même nom aux versions statiques et dynamiques de la bibliothèque. Je préfère utiliser des noms différents, car cela facilite le choix du lien statique/dynamique sur la ligne de compilation pour les outils liés à la bibliothèque. En général, je choisis des noms tels que libMyLib.so (partagé) et libMyLib_static.a (statique). (Ce sont les noms sur linux.)

115
Christopher Bruns

Depuis la version 2.8.8 de CMake, vous pouvez utiliser des "bibliothèques d'objets" pour éviter la compilation en double des fichiers objets . En utilisant l'exemple de Christopher Bruns d'une bibliothèque avec deux fichiers source:

# list of source files
set(libsrc source1.c source2.c)

# this is the "object library" target: compiles the sources only once
add_library(objlib OBJECT ${libsrc})

# shared libraries need PIC
set_property(TARGET objlib PROPERTY POSITION_INDEPENDENT_CODE 1)

# shared and static libraries built from the same object files
add_library(MyLib_shared SHARED $<TARGET_OBJECTS:objlib>)
add_library(MyLib_static STATIC $<TARGET_OBJECTS:objlib>)

Depuis le CMake docs :

Une bibliothèque d'objets compile des fichiers source mais ne les archive pas et ne les lie pas dans une bibliothèque. Au lieu de cela, d'autres cibles créées par add_library() ou add_executable() peuvent référencer les objets en utilisant une expression de la forme $<TARGET_OBJECTS:objlib> Comme source, où objlib est le nom de la bibliothèque d'objets.

En termes simples, la commande add_library(objlib OBJECT ${libsrc}) demande à CMake de compiler les fichiers source en fichiers objet *.o. Cette collection de fichiers *.o Est ensuite appelée $<TARGET_OBJECT:objlib> Dans les deux commandes add_library(...) qui appellent les commandes de création de bibliothèque appropriées qui créent les bibliothèques partagées et statiques à partir de same set de fichiers objets. Si vous avez beaucoup de fichiers sources, la compilation des fichiers *.o Peut prendre un certain temps. avec les bibliothèques d'objets, vous ne les compilez qu'une seule fois.

Le prix que vous payez est que les fichiers objets doivent être construits en tant que code indépendant de la position, car les bibliothèques partagées en ont besoin (les bibliothèques statiques ne sont pas importantes). Notez que le code indépendant de la position peut être moins efficace. Par conséquent, si vous visez une performance maximale, optez pour des bibliothèques statiques. De plus, il est plus facile de distribuer des exécutables liés statiquement.

74
Laryx Decidua

Il n’est généralement pas nécessaire de dupliquer les appels ADD_LIBRARY à cette fin. Juste utiliser

$> man cmake | grep -A6 '^ *BUILD_SHARED_LIBS$' 
   BUILD_SHARED_LIBS
          Global flag to cause add_library to create shared libraries if on.

          If present and true, this will cause all libraries to be built shared unless the library was
          explicitly added as a static library.  This variable is often added to projects as an OPTION
          so  that each user of a project can decide if they want to build the project using shared or
          static libraries.

en construisant d'abord (dans un répertoire hors source) avec -DBUILD_SHARED_LIBS: BOOL = ON et avec OFF dans l'autre

23
Yaroslav Halchenko