[Entrée CMake et avancé (2)] Paramètres de compilation CMake - compilation de fichiers sources multiples et génération de fichiers de bibliothèque (avec code)

plusieurs fichiers sources       

        Dans le dernier article, nous avons appris la compilation cmake d'un seul fichier source, mais l'exemple d'un fichier source semble dénué de sens, alors ajoutons un fichier d'en-tête hello.h et un fichier source hello.c. Une fonction hello est définie dans le fichier hello.c, puis la fonction sera appelée dans le fichier source main.c :

        ⚫ contenu du fichier hello.h

#ifndef __TEST_HELLO_
#define __TEST_HELLO_

void hello(const char *name);

#endif //__TEST_HELLO_

        ⚫ contenu du fichier hello.c

#include <stdio.h>
#include "hello.h"

void hello(const char *name){
 printf("Hello %s!\n", name);
}

        ⚫ contenu du fichier main.c

#include "hello.h"

int main(void){
 hello("World");
 return 0;
}

        ⚫ Préparez ensuite le fichier CMakeLists.txt

project(HELLO)
set(SRC_LIST main.c hello.c)
add_executable(hello ${SRC_LIST})

        La structure du répertoire du projet est la suivante :

├── build //文件夹
├── CMakeLists.txt
├── hello.c
├── hello.h
└── main.c

        De même, entrez dans le répertoire de construction, exécutez cmake, puis exécutez make pour compiler le projet, et enfin le fichier exécutable hello sera obtenu.

        Dans cet exemple, la commande set est utilisée dans le fichier CMakeLists.txt. La commande set est utilisée pour définir la variable. Si la variable n'existe pas, créez la variable et définissez-la ; dans cet exemple, nous définissons une variable SRC_LIST, et la variable SRC_LIST est une liste de fichiers source, enregistrez les fichiers source main.c et hello.c nécessaires pour générer le fichier exécutable hello, et cette variable est référencée dans la commande add_executable ; bien sûr, nous pouvons aussi directement écrire le fichier source list dans add_executable sans définir la variable SRC_LIST Dans la commande, comme suit :

add_executable(hello main.c hello.c)

Générer des fichiers de bibliothèque

       Dans cet exemple, en plus de générer le fichier exécutable hello, nous devons également compiler hello.c dans un fichier de bibliothèque statique ou un fichier de bibliothèque dynamique. Sur la base de l'exemple précédent, modifiez le fichier CMakeLists.txt comme suit :

project(HELLO)
add_library(libhello hello.c)
add_executable(hello main.c)
target_link_libraries(hello libhello)

        Entrez dans le répertoire de construction, exécutez cmake, puis exécutez make pour compiler le projet. Une fois la compilation terminée, le fichier exécutable hello et les fichiers de bibliothèque seront générés dans le répertoire de construction, comme indiqué ci-dessous :

         La structure du répertoire est la suivante :

├── build
│ ├── hello
│ └── liblibhello.a
├── CMakeLists.txt
├── hello.c
├── hello.h
└── main.c

Explication du fichier CMakeLists.txt

        Dans cet exemple, nous avons utilisé la commande add_library et la commande target_link_libraries. La commande add_library permet de générer un fichier de bibliothèque. Dans cet exemple, nous passons deux paramètres. Le premier paramètre indique le nom du fichier de bibliothèque. Il convient de noter que ce nom n'inclut pas le préfixe et le suffixe ; dans la version Linux system , le préfixe du fichier de bibliothèque est lib, le suffixe du fichier de bibliothèque dynamique est .so et le suffixe du fichier de bibliothèque statique est .a ; par conséquent, cela signifie que le nom correspondant au fichier de bibliothèque généré final sera automatiquement ajouter le préfixe et le suffixe.

        Le second paramètre indique le fichier source correspondant au fichier bibliothèque.

        Dans cet exemple, la commande add_library génère un fichier de bibliothèque statique liblibhello.a, si vous souhaitez générer un fichier de bibliothèque dynamique, vous pouvez le faire :

add_library(libhello SHARED hello.c) #生成动态库文件
add_library(libhello STATIC hello.c) #生成静态库文件

La commande target_link_libraries spécifie les bibliothèques dépendantes pour la cible. Dans cet exemple, hello.c est compilé en tant que fichier de bibliothèque et lié au programme hello.

Modifier le nom du fichier de bibliothèque généré

         Dans cet exemple, une chose est très inconfortable, la bibliothèque générée est liblibhello.a, et le nom est très moche ; que dois-je faire si je veux générer liblibhello.a ? Est-il possible de modifier directement les paramètres de la commande add_library comme suit ?

add_library(hello hello.c)

        La réponse est non, car la cible hello existe déjà (add_executable(hello main.c)), le nom de la cible est unique pour l'ensemble du projet et aucune cible portant le même nom ne peut apparaître, donc cette méthode n'est certainement pas possible. Ci-dessus, il suffit d'ajouter la commande suivante au fichier CMakeLists.txt :

set_target_properties(libhello PROPERTIES OUTPUT_NAME "hello")

        set_target_properties est utilisé pour définir les propriétés de la cible. Ici, la propriété OUTPUT_NAME de la cible libhello est définie via la commande set_target_properties, et elle est définie sur hello.

        Nous menons des expériences, et le contenu du fichier CMakeLists.txt est le suivant :

cmake_minimum_required(VERSION 3.5)
project(HELLO)
add_library(libhello SHARED hello.c)
set_target_properties(libhello PROPERTIES OUTPUT_NAME "hello")
add_executable(hello main.c)
target_link_libraries(hello libhello)

        En plus d'ajouter la commande set_target_properties, nous avons également ajouté la commande cmake_minimum_required, qui permet de définir le numéro de version minimum de cmake requis pour le projet en cours. Bien sûr, ce n'est pas obligatoire, mais il est préférable de l'ajouter. Accédez au répertoire de construction et utilisez cmake+make pour compiler l'ensemble du projet. Une fois la compilation terminée, vous constaterez que le fichier de bibliothèque généré est libhello.a au lieu de liblibhello.a.

├── build
│ ├── hello
│ └── libhello.so
├── CMakeLists.txt
├── hello.c
├── hello.h
└── main.c

Organiser les fichiers source dans différents répertoires

        Dans l'exemple ci-dessus, nous avons ajouté plusieurs fichiers sources, mais ces fichiers sources sont tous placés dans le même répertoire, ce qui n'est pas très formel. Nous devrions placer ces fichiers sources à des endroits différents selon le type, la fonction et le répertoire du module, donc l'auteur a organisé le code source du projet. La structure actuelle des répertoires est la suivante :

├── build #build 目录
├── CMakeLists.txt
├── libhello
│ ├── CMakeLists.txt
│ ├── hello.c
│ └── hello.h
└── src
 ├── CMakeLists.txt
 └── main.c

        Dans le répertoire du projet, nous avons créé les répertoires src et libhello, et déplacé les fichiers hello.c et hello.h vers le répertoire libhello, déplacé le fichier main.c vers le répertoire src, et dans le répertoire supérieur, répertoire libhello et src répertoire Il y a un fichier CMakeLists.txt sous. Le nombre de fichiers CMakeLists.txt est passé de 1 à 3, et je me suis soudain senti un peu pris au dépourvu ! Heureusement, aucun d'entre eux n'est compliqué ! Examinons le contenu de chaque fichier CMakeLists.txt.

        ⚫ CMakeLists.txt de niveau supérieur

cmake_minimum_required(VERSION 3.5)
project(HELLO)
add_subdirectory(libhello)
add_subdirectory(src)

        ⚫ CMakeLists.txt dans le répertoire src

include_directories(${PROJECT_SOURCE_DIR}/libhello)
add_executable(hello main.c)
target_link_libraries(hello libhello)

        ⚫ CMakeLists.txt sous le répertoire libhello

add_library(libhello hello.c)
set_target_properties(libhello PROPERTIES OUTPUT_NAME "hello")

        La commande add_subdirectory est utilisée dans le CMakeLists.txt de niveau supérieur, qui indique à cmake de trouver un nouveau fichier CMakeLists.txt dans le sous-répertoire et de l'analyser ; et dans le fichier CMakeList.txt de src, une nouvelle commande include_directories est ajoutée pour indiquer où se trouve le fichier d'en-tête chemin, et la variable PROJECT_SOURCE_DIR est utilisée, qui pointe vers un chemin. D'après la dénomination, cette variable représente le répertoire du code source du projet.

        Comme précédemment, allez dans le répertoire build pour compiler et compiler, et enfin récupérez le fichier exécutable hello (build/src/hello) et le fichier de bibliothèque libhello.a (build/libhello/libhello.a) :

├── build
│ ├── libhello
│ │ └── libhello.a
│ └── src
│   └── hello
├── CMakeLists.txt
├── libhello
│ ├── CMakeLists.txt
│ ├── hello.c
│ └── hello.h
└── src
 ├── CMakeLists.txt
 └── main.c

Placez les fichiers exécutables et bibliothèques générés dans des répertoires séparés

        Il y a tout de même un petit inconfort en façade, par défaut, les fichiers exécutables et bibliothèques générés par make compilation seront mixés avec les fichiers intermédiaires (CMakeCache.txt, CmakeFiles, cmake_install.cmake et Makefile, etc.) générés par le cmake commande, c'est-à-dire qu'ils se trouvent dans le même répertoire ; si je veux que le fichier exécutable soit placé séparément dans le répertoire bin et que le fichier de bibliothèque soit placé séparément dans le répertoire lib, comme ceci :

├── build
├── lib
│ └── libhello.a
└── bin
  └── hello

        Stockez les fichiers de la bibliothèque dans le répertoire lib sous le répertoire de construction et stockez les fichiers exécutables dans le répertoire bin sous le répertoire de construction. Que dois-je faire à ce stade ? A ce moment, nous pouvons le réaliser à travers deux variables, et modifier le fichier CMakeList.txt dans le répertoire src, comme suit :

include_directories(${PROJECT_SOURCE_DIR}/libhello)
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
add_executable(hello main.c)
target_link_libraries(hello libhello)

        Modifiez ensuite le fichier CMakeList.txt dans le répertoire libhello, comme suit :

set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
add_library(libhello hello.c)
set_target_properties(libhello PROPERTIES OUTPUT_NAME "hello")

        Une fois la modification terminée, compilez et compilez à nouveau le projet en suivant les étapes. À ce stade, le fichier exécutable généré bonjour sera placé dans le répertoire build/bin et le fichier de bibliothèque libhello.a sera placé dans le répertoire build/lib répertoire selon nos exigences. La structure finale du répertoire ressemble à ceci :

├── build
│ ├── bin
│ │ └── hello
│ └── lib
│   └── libhello.a
├── CMakeLists.txt
├── libhello
│ ├── CMakeLists.txt
│ ├── hello.c
│ └── hello.h
└── src
  ├── CMakeLists.txt
  └── main.c

        En fait, il est très simple de réaliser cette exigence. Cela peut être fait en définissant les variables LIBRARY_OUTPUT_PATH et EXECUTABLE_OUTPUT_PATH ; la variable EXECUTABLE_OUTPUT_PATH contrôle le chemin de sortie des fichiers exécutables, tandis que la variable LIBRARY_OUTPUT_PATH contrôle le chemin de sortie des fichiers de bibliothèque.

Je suppose que tu aimes

Origine blog.csdn.net/cj_lsk/article/details/131001173
conseillé
Classement