Même source, tout ça, je veux juste une version statique et partagée à la fois. Facile à faire?
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 de nombreux fichiers sources, vous placez la liste des sources dans une variable cmake, donc c'est toujours facile à faire.
Sous Windows, vous devriez probablement donner à chaque bibliothèque un nom différent, car il existe un fichier ".lib" pour les fichiers partagés et statiques. Mais sur Linux et Mac, vous pouvez même donner aux deux bibliothèques le même nom (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 de la liaison statique ou dynamique sur la ligne de compilation pour les outils liés à la bibliothèque. Habituellement, je choisis des noms comme libMyLib.so
(partagé) et libMyLib_static.a
(statique). (Ce seraient les noms sur Linux.)
-fPIC
), ce qui ajoute une petite quantité de temps d'exécution lorsque ces bibliothèques statiques sont utilisées. Donc, pour des performances maximales, cette réponse est toujours la meilleure.Depuis la version 2.8.8 de CMake, vous pouvez utiliser des "bibliothèques d'objets" pour éviter la compilation dupliquée des fichiers objets . En utilisant l'exemple de Christopher Bruns d'une bibliothèque avec deux fichiers source:
À partir de la documentation CMake :
En termes simples, la
add_library(objlib OBJECT ${libsrc})
commande demande à CMake de compiler les fichiers source en fichiers*.o
objet. Cette collection de*.o
fichiers est alors appelée$<TARGET_OBJECT:objlib>
dans les deuxadd_library(...)
commandes qui invoquent les commandes de création de bibliothèque appropriées qui créent les bibliothèques partagées et statiques à partir du même ensemble de fichiers objets. Si vous avez beaucoup de fichiers source, la compilation des*.o
fichiers peut prendre un certain temps; avec les bibliothèques d'objets, vous ne les compilez qu'une seule fois.Le prix à payer 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 s'en moquent). Notez que le code indépendant de la position peut être moins efficace, donc si vous visez des performances maximales, vous opterez pour des bibliothèques statiques. De plus, il est plus facile de distribuer des exécutables liés statiquement.
la source
target_link_libraries()
appels ultérieurs qui dépendent de votre bibliothèque ne peuvent pas utiliser la «bibliothèque d'objets» pour établir un lien; ceux-ci doivent cibler les nouvelles bibliothèques partagées ou statiques (et peuvent être dupliqués). Mais contrairement à l'expérience des premiers commentateurs, cela a été très utile et m'a permis de supprimer toutes les cibles dupliquées et de réduire tous mesCMakeLists.txt
fichiers de près de la moitié.set_property
seul fonctionnait lorsque je l'utilisaisobjlib
et non lors de l'utilisation${objlib}
. Alors peut-être que cette réponse pourrait être corrigée?Il n'est généralement pas nécessaire de dupliquer les
ADD_LIBRARY
appels pour vos besoins. Utilisez simplementlors de la construction, d'abord (dans un répertoire hors source) avec
-DBUILD_SHARED_LIBS:BOOL=ON
et avecOFF
dans l'autre.la source
Il est possible de tout emballer dans le même souffle de compilation, comme suggéré dans les réponses précédentes, mais je vous le déconseille, car au final c'est un hack qui ne fonctionne que pour des projets simples. Par exemple, vous pouvez avoir besoin à un moment donné de différents indicateurs pour différentes versions de la bibliothèque (en particulier sur Windows où les indicateurs sont généralement utilisés pour basculer entre les symboles d'exportation ou non). Ou comme mentionné ci-dessus, vous voudrez peut-être mettre
.lib
fichiers dans différents répertoires selon qu'ils correspondent à des bibliothèques statiques ou partagées. Chacun de ces obstacles nécessitera un nouveau hack.Cela peut être évident, mais une alternative qui n'a pas été mentionnée précédemment est de faire du type de la bibliothèque un paramètre:
Le fait d'avoir des versions partagées et statiques de la bibliothèque dans deux arborescences binaires différentes facilite la gestion des différentes options de compilation. Je ne vois aucun inconvénient sérieux à garder les arbres de compilation distincts, surtout si vos compilations sont automatisées.
Notez que même si vous avez l'intention de mutualiser les compilations en utilisant une
OBJECT
bibliothèque intermédiaire (avec les mises en garde mentionnées ci-dessus, vous avez donc besoin d'une raison convaincante pour le faire), vous pourriez toujours avoir des bibliothèques de fin placées dans deux projets différents.la source
C'est en effet possible. Comme @Christopher Bruns l'a dit dans sa réponse, vous devez ajouter deux versions de la bibliothèque:
Ensuite, comme décrit ici , vous devez spécifier que les deux cibles doivent utiliser le même nom de sortie et ne pas écraser les fichiers de l'autre:
De cette façon, vous obtiendrez à la fois libmylib.a et libmylib.so (sous Linux) ou mylib.lib et mylib.dll (sous Windows).
la source