Explication détaillée de la construction du projet CMake

Table des matières

1. Introduction et installation de CMake

1.1 Installer CMake sur Ubuntu

1.2 Installer CMake dans l'environnement VScode

1.3 Structure du répertoire de construction du projet CMake

1.4 Compilation et liaison du projet

1.5 Variables prédéfinies couramment utilisées par CMake

1.6 Types de build CMake

2. Utilisation simple de la construction CMake : Helloworld

3. CMake build : plusieurs fichiers sources dans le répertoire racine

Élémentaire : peu de fichiers sources utilisent add_executable()

Avancé : Plus de fichiers sources utilisent aux_source_directory() ou set()

Quatrièmement, build CMake : fichiers multi-sources multi-répertoires

5. Construction CMake : structure organisationnelle formelle

Méthode 1 : deux CMakeLists.txt

Méthode 2 : un CMakeLists.txt

Six, CMake build : compiler une bibliothèque dynamique et une bibliothèque statique

Seven, build CMake : bibliothèque de liens

Huit, build CMake : ajouter des options de compilation

Neuf, build CMake : ajouter des options de contrôle

9.1 À l'origine, je voulais générer plusieurs fichiers bin ou bibliothèque, mais maintenant je souhaite uniquement générer certains fichiers bin ou bibliothèque spécifiés.

 9.2 Pour le même fichier bin, je souhaite uniquement compiler une partie du code (utiliser la macro pour contrôler)

10. Résumé


1. Introduction et installation de CMake

CMake : il est simple et pratique à utiliser et peut créer un environnement de compilation de projets sur plusieurs plates-formes. C'est plus simple que d'écrire directement Makefile (lors de la création d'une compilation de projet à grande échelle, vous devez écrire un grand nombre de dépendances de fichiers), vous pouvez générer le fichier Makefile local responsable via une simple configuration CMake, et une commande compilera le fichier exécutable et Bibliothèque statique que nous voulons compiler, Les bibliothèques dynamiques sont compilées. De plus, le fichier de configuration peut être directement utilisé sur d’autres plateformes sans modification, ce qui est très pratique.


1.1 Installer CMake sur Ubuntu

Installez CMake à l'aide de la commande :

sudo apt install cmake

cmake -versionUne fois l'installation terminée, entrez la version de cmake dans le terminal :

fff@ubuntu:~$ cmake -version
cmake version 3.22.1

CMake suite maintained and supported by Kitware (kitware.com/cmake).

1.2 Installer CMake dans l'environnement VScode

1.2.1 vscode télécharge le plug-in correspondant.

1.2.2 Trouvez l'emplacement de cmake sous le terminal shell, le chemin sur notre système est /usr/bin/camke.

fff@ubuntu:~$ whereis cmake
cmake: /usr/bin/cmake /usr/share/cmake /opt/cmake-3.23.0-linux-x86_64/bin/cmake /usr/share/man/man1/cmake.1.gz

1.2.3 Cliquez sur les paramètres étendus de CMake Tools.

 1.2.4 Sélectionnez la configuration de l'hôte distant, recherchez Cmake:Build Environment et ajoutez les variables d'environnement correspondantes.


1.3 Structure du répertoire de construction du projet CMake

Généralement, lors du développement réel, nous distinguerons clairement les répertoires correspondants, afin que la structure du projet paraisse plus claire. Par exemple, la structure de répertoires suivante :

bin : fichier exécutable généré (  fichier .elf )
lib : fichier de bibliothèque intermédiaire généré
include : fichier d'en-tête
src : fichier source
build : fichier intermédiaire temporaire généré lors de la compilation du projet
test : fichier de test
3ème : bibliothèque tierce dépendante (telle que .a . donc fichiers .la, etc.)
CMakeLists.txt : fichier de configuration CMake
autobuild.sh : script de compilation en un clic

1.4 Compilation et liaison du projet

Lorsque nous utilisons habituellement des commandes pour compiler des fichiers de liens sous Linux, les éléments suivants peuvent être impliqués :

 Par exemple, nous avons un fichier muduo_server.cpp, la commande est la suivante :

fff@ubuntu:~/home/Desktop/muduocode$ g++ -o server moduo_server.cpp -lmuduo_net -lmuduo_base -lpthread

Nous pouvons utiliser le fichier de configuration CMake pour accomplir la même fonction. Créez un fichier CMakeList.txt dans le répertoire racine du projet et la commande cmake le trouvera dans le répertoire racine du projet.

fff@ubuntu:~/home/Desktop/muduocode$ arbre
.
├── CMakeLists.txt
├── muduo_server
├── muduo_server.cpp

 La commande cmake exécutera les éléments de configuration dans le fichier de configuration CMakeLists.txt dans le répertoire. Le contenu d'un simple fichier de configuration CMakeLists.txt est le suivant :


1.5 Variables prédéfinies couramment utilisées par CMake

1. PROJECT_NAME : spécifiez le nom du projet via project();
2. PROJECT_SOURCE_DIR : le répertoire racine du projet;
3. PROJECT_BINARY_DIR : le répertoire où la commande cmake est exécutée;
4. CMAKE_CURRENT_SOURCE_DIR : le répertoire où se trouve le fichier CMakeList.txt actuel. se trouve ;
5. CMAKE_CURRENT_BIN ARY_DIR : répertoire de compilation, peut être modifié en utilisant un sous-répertoire ajouté ;
6. EXECUTABLE_OUTPUT_PATH : emplacement de sortie du fichier exécutable binaire ;
7. LIBRARY_OUTPUT_PATH : emplacement de sortie du fichier de bibliothèque ;
8. BUILD_SHARED_LIBS : méthode de compilation de bibliothèque par défaut (partagée ou statique) ), la valeur par défaut est statique ;
9, CMAKE_C_FLAGS : définir les options de compilation C ;
10, CMAKE_CXX_FLAGS : définir les options de compilation C++ ;
11, CMAKE_CXX_FLAGS_DEBUG: Options de compilation lors de la définition du type de compilation Debug ;
12. CMAKE_CXX_FLAGS_RELEASE : Options de compilation lors de la définition du type de compilation Release ;
13. CMAKE_GENERATOR : Nom du compilateur ;
14. CMAKE_COMMAND : Le chemin complet du fichier exécutable CMake lui-même ;
15. CMAKE_BUILD_TYPE : Compilation du projet Version générée, Debug / Release ;

1.6 Types de build CMake

La différence entre définir le type de build sur Release et Debug se reflète principalement dans le niveau d'optimisation du compilateur et les caractéristiques du fichier exécutable généré.

1. Niveau d'optimisation :

  • Mode Release : en mode Release, le compilateur effectuera des optimisations de niveau supérieur pour améliorer l’efficacité et les performances de l’exécution du code. Cela inclut, sans toutefois s'y limiter, des techniques d'optimisation telles que l'intégration de fonctions, le déroulement de boucles et le repliement constant pour réduire le temps d'exécution du code et l'utilisation de la mémoire. Cependant, cela peut augmenter le temps de compilation et rendre le code moins lisible.
  • Mode débogage : en mode débogage, le compilateur n'effectue généralement pas d'optimisations pour mieux comprendre et tracer le code lors du débogage. Cela signifie que l'exécutable résultant sera plus volumineux, mais plus pratique pour le débogage et le dépannage.

2. Informations de débogage :

  • Mode Release : en mode Release, le compilateur supprime généralement les informations de débogage pour réduire la taille de l'exécutable résultant. Cela signifie que les informations complètes sur les symboles peuvent ne pas être disponibles lors du débogage, ce qui rend le processus de débogage plus difficile.
  • Mode débogage : en mode débogage, le compilateur conservera les informations complètes de débogage afin que le code puisse être localisé et suivi avec précision dans le débogueur. Cela rend le processus de débogage plus facile et plus précis.

Pour résumer , le mode Release est adapté à la version finale publiée, en se concentrant sur les performances et la taille du fichier exécutable ; tandis que le mode Debug est adapté à la phase de débogage et de développement, en se concentrant sur le débogage et le dépannage pratiques.

 Le type de build est Release, écrit comme suit :

SET(CMAKE_BUILD_TYPE "Release")
SET(CMAKE_C_FLAGS_RELEASE "$ENV{CXXFLAGS} -Os -s -Wall -std=gnu11  -Werror")
SET(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -Os  -s -Wall -std=c++1y -Werror")

Les paramètres spécifiques sont expliqués comme suit :

1. SET(CMAKE_BUILD_TYPE "Release")  Définissez le type de build sur Release , ce qui signifie que le code sera compilé de manière optimisée pour améliorer les performances.

2.SET(CMAKE_C_FLAGS_RELEASE "$ENV{CXXFLAGS} -Os -s -Wall -std=gnu11 -Werror")  Définissez les paramètres de compilation du compilateur C en mode Release . Les paramètres spécifiques sont expliqués comme suit :

  • $ENV{CXXFLAGS} est une variable d'environnement permettant d'obtenir des paramètres supplémentaires pour le compilateur C++ afin qu'il puisse être utilisé avec d'autres paramètres.
  • -Os Indique l'optimisation de la compilation pour réduire la taille de l'exécutable résultant.
  • -s Indique que les informations de débogage sont supprimées pour réduire la taille de l'exécutable résultant.
  • -Wall Indique que tous les messages d'avertissement sont activés.
  • -std=gnu11 Indique une compilation à l'aide de la norme GNU C11.
  • -Werror Indique de traiter tous les avertissements comme des erreurs.

3. Définissez les paramètres de compilation du SET(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -Os -s -Wall -std=c++1y -Werror") compilateur C++ en mode Release . Similaire aux paramètres du compilateur C ci-dessus, sauf que la norme C++11 est utilisée pour la compilation.

En définissant ces paramètres, vous pouvez effectuer une compilation optimisée en mode Release et traiter les avertissements comme des erreurs lors de la compilation pour garantir la qualité et les performances de l' exécutable généré.

Le type de build est Debug, écrit comme suit :

SET(CMAKE_BUILD_TYPE "Debug")
SET(CMAKE_C_FLAGS_DEBUG "$ENV{CXXFLAGS} -g -Wall -std=gnu11 -Werror")
SET(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -g -Wall -std=c++1y -Werror")

Les paramètres spécifiques sont expliqués comme suit :

1.SET(CMAKE_BUILD_TYPE "Debug") Définissez le type de build sur Debug pour compiler en mode débogage.

2.SET(CMAKE_C_FLAGS_DEBUG "$ENV{CXXFLAGS} -g -Wall -std=gnu11 -Werror")Définissez les paramètres de compilation du  compilateur C en mode Debug . Les paramètres spécifiques sont expliqués comme suit :

  • $ENV{CXXFLAGS} est une variable d'environnement permettant d'obtenir des paramètres supplémentaires pour le compilateur C++ afin qu'il puisse être utilisé avec d'autres paramètres.
  • -g Indique de conserver les informations de débogage dans l’exécutable pour le débogage dans un débogueur.
  • -Wall Indique que tous les messages d'avertissement sont activés.
  • -std=gnu11 Indique une compilation à l'aide de la norme GNU C11.
  • -Werror Indique de traiter tous les avertissements comme des erreurs.

3.SET(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -g -Wall -std=c++1y -Werror")Définissez les paramètres de compilation du  compilateur C++ en mode Debug . Similaire aux paramètres du compilateur C ci-dessus, sauf que la norme C++11 est utilisée pour la compilation.

En définissant ces paramètres, des fichiers exécutables contenant des informations de débogage peuvent être générés en mode débogage et les avertissements sont traités comme des erreurs pour faciliter le débogage et le dépannage.


2. Utilisation simple de la construction CMake : Helloworld

2.1 Écrivez unhello.c :

#include "stdio.h"

int main(void)
{       
    printf("Hello World!\r\n");
    return 0;
}

2.2 Ecrire dans le même répertoire CMakeLists.txt:

cmake_minimum_required (VERSION 2.8)
        
project (demo)
        
add_executable(hello hello.c)

2.3 Pour exécuter CMake dans le même répertoire, vous devez saisir la commande :

fff@ubuntu:~/Desktop/cmake_test$ cmake .
-- The C compiler identification is GNU 5.4.0
-- The CXX compiler identification is GNU 5.4.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/liefyuan/Desktop/cmake_test

2.4 sera généré dans le même répertoire :

fff@ubuntu:~/Desktop/cmake_test$ ls -l
总用量 36
-rw-rw-r-- 1 liefyuan liefyuan 11542 Nov  7 14:50 CMakeCache.txt
drwxrwxr-x 5 liefyuan liefyuan  4096 Nov  7 14:50 CMakeFiles
-rw-rw-r-- 1 liefyuan liefyuan  1377 Nov  7 14:50 cmake_install.cmake
-rw-rw-r-- 1 liefyuan liefyuan    84 Nov  7 14:45 CMakeLists.txt
-rw-rw-r-- 1 liefyuan liefyuan    80 Nov  7 14:44 hello.c
-rw-rw-r-- 1 liefyuan liefyuan  4734 Nov  7 14:50 Makefile

2.5 Comme indiqué ci-dessus, le fichier Makefile a été généré, et il existe également des fichiers générés automatiquement par cmake en cours d'exécution.
Ensuite, vous pouvez utiliser makela commande pour compiler.

fff@ubuntu:~/Desktop/cmake_test$ make
Scanning dependencies of target hello
[ 50%] Building C object CMakeFiles/hello.dir/hello.c.o
[100%] Linking C executable hello
[100%] Built target hello

2.6 Regardez à nouveau le fichier généré :

fff@ubuntu:~/Desktop/cmake_test$ ls -l
总用量 48
-rw-rw-r-- 1 liefyuan liefyuan 11542 Nov  7 14:50 CMakeCache.txt
drwxrwxr-x 5 liefyuan liefyuan  4096 Nov  7 14:53 CMakeFiles
-rw-rw-r-- 1 liefyuan liefyuan  1377 Nov  7 14:50 cmake_install.cmake
-rw-rw-r-- 1 liefyuan liefyuan    84 Nov  7 14:45 CMakeLists.txt
-rwxrwxr-x 1 liefyuan liefyuan  8600 Nov  7 14:53 hello
-rw-rw-r-- 1 liefyuan liefyuan    80 Nov  7 14:44 hello.c
-rw-rw-r-- 1 liefyuan liefyuan  4734 Nov  7 14:50 Makefile

2.7 Vous pouvez voir qu'un fichier hello exécutable a été généré, entrez et ./helloexécutez le fichier exécutable :

fff@ubuntu:~/Desktop/cmake_test$ ./hello
Hello World!

2.8 Exécutez avec succès !

PS : Si vous avez besoin de recompiler, vous pouvez utiliser make cleanla commande pour nettoyer (supprimer l'ancien exécutable).


3. CMake build : plusieurs fichiers sources dans le répertoire racine

Élémentaire : peu de fichiers sources utilisent add_executable()

3.1 Répertoire de fichiers :

fff@ubuntu:~/Desktop/cmake_multi_test$ ls -l
rw-rw-r-- 1   fff fff    93 Nov   7 16:41 CMakeLists.txt
-rw-rw-r-- 1  fff fff    107 Nov  7 16:34 function.c
-rw-rw-r-- 1  fff fff    86 Nov   7 16:38 function.h
-rw-rw-r-- 1  fff fff    85 Nov   7 16:30 main.c

3.2 fonction.h

#ifndef __FUNCTION_H__
#define __FUNCTION_H__

void func(unsigned int var);

#endif

3.3 fonction.c

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

void func(unsigned int var)
{
	printf("para var:%d\r\n", var);
}

3.4 main.c

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

int main(void)
{
	func(200);
	return 0;
}

CMakeListes .txt

cmake_minimum_required (VERSION 2.8)

project (demo)

add_executable(main main.c function.c)

3.5 Exécuter cmake .pour générer Makefile et exécuter make

fff@ubuntu:~/Desktop/cmake_multi_test$ cmake .
-- The C compiler identification is GNU 5.4.0
-- The CXX compiler identification is GNU 5.4.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/fff/Desktop/cmake_multi_test
fff@ubuntu:~/Desktop/cmake_multi_test$ make
Scanning dependencies of target main
[ 33%] Building C object CMakeFiles/main.dir/main.c.o
[ 66%] Building C object CMakeFiles/main.dir/function.c.o
[100%] Linking C executable main
[100%] Built target main

3.6 Vous pouvez voir qu'un fichier principal exécutable a été généré, saisissez et ./mainexécutez le fichier exécutable :

fff@ubuntu:~/Desktop/cmake_multi_test$ ./main
para var:200

3.7 Exécutez avec succès !

PS : Résumé

Par analogie, s'il existe plusieurs fichiers sources dans le même répertoire, ajoutez simplement tous les fichiers sources dans add_executable.


Avancé : Plus de fichiers sources utilisent aux_source_directory() ou set()

PS : Mais s'il y a une centaine de fichiers sources, ce serait un peu délicat de refaire cela, et cela ne peut pas refléter la supériorité de cmake. cmake fournit une commande pour stocker tous les fichiers sources d'un répertoire spécifié dans une variable. Cette commande est aux_source_directory(dir  var).
Le premier paramètre dir est le répertoire spécifié et le deuxième paramètre var est la variable utilisée pour stocker la liste des fichiers sources.

3.8 Ajouter à nouveau des fichiersfunction2.c

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

void func2(unsigned int var)
{
	printf("para var2:%d\r\n", var);
}

3.9 Ajouter un fichier function2.h

#ifndef __FUNCTION2_H__
#define __FUNCTION2_H__

void func2(unsigned int var);

#endif

3.10 Modifier main.c

#include <stdio.h>
#include "function.h"
#include "function2.h"

int main(void)
{
	func(200);
	func2(100);
	
	return 0;
}

3.11 Modifier CMakeLists.txt

cmake_minimum_required (VERSION 2.8)

project (demo)

aux_source_directory(. SRC_LIST)

add_executable(main ${SRC_LIST})

3.12 Puis exécutez cmake .et make

fff@ubuntu:~/Desktop/cmake_multi_test$ cmake .
-- Configuring done
-- Generating done
-- Build files have been written to: /home/fff/Desktop/cmake_multi_test
fff@ubuntu:~/Desktop/cmake_multi_test$ make
Scanning dependencies of target main
[ 25%] Building C object CMakeFiles/main.dir/function.c.o
[ 50%] Building C object CMakeFiles/main.dir/function2.c.o
[ 75%] Building C object CMakeFiles/main.dir/main.c.o
[100%] Linking C executable main
[100%] Built target main

3.13 Exécution d'exécutables./main

liefyuan@ubuntu:~/Desktop/cmake_multi_test$ ./main
para var:200
para var2:100

3.14 Exécutez avec succès !

PS : Pour résumer ,
aux_source_directory() présente également des inconvénients. Il ajoutera tous les fichiers sources dans le répertoire spécifié, et peut ajouter certains fichiers dont nous n'avons pas besoin. À ce stade, nous pouvons utiliser la commande set pour créer des variables pour stockez les fichiers source requis., comme suit :

cmake_minimum_required (VERISON 2.8)

project (demo)

set(SRC_LIST 
		./main.c
		./function.c
		./function2.c)

add_executable(main ${SRC_LIST})

Quatrièmement, build CMake : fichiers multi-sources multi-répertoires

 D'une manière générale, lorsqu'il y a de nombreux fichiers de programme, nous les gérerons par catégorie, et placerons les codes dans différents répertoires en fonction de leurs fonctions, afin qu'ils soient faciles à retrouver. Alors comment écrire CMakeLists.txt dans ce cas ?

4.1 Trions les fichiers sources précédents (créons 2 répertoires function et function2 ), et la structure globale des fichiers est la suivante :

fff@ubuntu:~/Desktop/cmake_multi_dir_test$ tree
.
├── CMakeLists.txt
├── function
│   ├── function.c
│   └── function.h
├── function2
│   ├── function2.c
│   └── function2.h
└── main.c

4.2 Modifier le fichier CmakeLists.txt

cmake_minimum_required (VERSION 2.8)

project (demo)

include_directories (function function2)
        
aux_source_directory(function SRC_LIST)
aux_source_directory(function2 SRC_LIST2)

add_executable(main main.c ${SRC_LIST} ${SRC_LIST2})

Comme ci-dessus :

  • Le aux_source_directory est utilisé 2 fois, car les fichiers sources sont répartis dans 2 répertoires, ajoutez donc 2 fois.

ou:

  • Stockez les deux ajouts dans la même variable
cmake_minimum_required (VERSION 2.8)

project (demo)

include_directories (function function2)
        
aux_source_directory(function SRC_LIST)
aux_source_directory(function2 SRC_LIST)

add_executable(main main.c ${SRC_LIST})

4.3 Puis réexécutezcmake .make./main

fff@ubuntu:~/Desktop/cmake_multi_dir_test$ cmake .
-- The C compiler identification is GNU 5.4.0
-- The CXX compiler identification is GNU 5.4.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/fff/Desktop/cmake_multi_dir_test
fff@ubuntu:~/Desktop/cmake_multi_dir_test$ make
Scanning dependencies of target main
[ 25%] Building C object CMakeFiles/main.dir/main.c.o
[ 50%] Building C object CMakeFiles/main.dir/function/function.c.o
[ 75%] Building C object CMakeFiles/main.dir/function2/function2.c.o
[100%] Linking C executable main
[100%] Built target main
fff@ubuntu:~/Desktop/cmake_multi_dir_test$ ./main
para var:200
para var2:100

fonctionnement normal!

PS : nouvelle commande : include_directories()

Voici une nouvelle commande : include_directories() . Cette commande est utilisée pour ajouter des chemins de recherche pour plusieurs fichiers d'en-tête spécifiés au projet, et les chemins sont séparés par des espaces.

 Étant donné que function.h et function2.h sont inclus dans main.c, s'il n'y a pas de commande pour spécifier l'emplacement du fichier d'en-tête, il ne pourra pas être compilé. Bien entendu, vous pouvez également utiliser include pour spécifier le chemin dans main.c, comme suit :

#include "function/function.h"
#include "function2/function2.h"

Cette façon d’écrire n’est pas belle !

5. Construction CMake : structure organisationnelle formelle

Créez d’abord une arborescence de répertoires, comme suit :

fff@ubuntu:~/Desktop/cmake_dir$ tree
.
├── bin
├── build
├── include
│   ├── function2.h
│   └── function.h
└── src
    ├── function2.c
    ├── function.c
    └── main.c

Méthode 1 : deux CMakeLists.txt

Créez un nouveau fichier dans le répertoire racineCMakeLists.txt avec le contenu suivant :

cmake_minimum_required (VERSION 2.8)

project (demo)

add_subdirectory (src)

Vous devez également créer un nouveau fichier dans le répertoire srcCMakeLists.txt , le contenu est le suivant :

aux_source_directory (. SRC_LIST)

include_directories (../include)

add_executable (main ${SRC_LIST})

set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)

Un nouveau jeu de commandes est utilisé ici, qui est utilisé pour définir des variables, EXECUTABLE_OUT_PATHet est une variable prédéfiniePROJECT_SOURCE_DIR fournie avec CMake . Sa signification est la suivante :

  • EXECUTABLE_OUTPUT_PATH : L'emplacement où l'exécutable binaire cible est stocké
  • PROJECT_SOURCE_DIR : le répertoire racine du projet

Par conséquent, définir ici signifie définir l'emplacement où le fichier elf est stocké dans le répertoire bin sous le répertoire racine du projet . (cmake a de nombreuses variables prédéfinies, vous pouvez rechercher des détails en ligne)

Après avoir ajouté les deux CMakeLists.txt ci-dessus, la structure globale du fichier est la suivante :

fff@ubuntu:~/Desktop/cmake_dir$ tree
.
├── bin
├── build
├── CMakeLists.txt
├── include
│   ├── function2.h
│   └── function.h
└── src
    ├── CMakeLists.txt
    ├── function2.c
    ├── function.c
    └── main.c

construire, compiler, exécuter

  • Étape 1 : Accédez au dossier build et exécutez la commande :cmake ..
  • Étape 2 : Après l'étape précédente, le Makefile sera généré dans le répertoire de construction, puis exécuté pour compiler, et un fichier exécutable sera généré dans le répertoire binmake du répertoire racinemain
  • Étape 3 : Entrez le fichier bin dans le répertoire racine pour exécuter le fichier exécutable./main
fff@ubuntu:~/Desktop/cmake_dir/build$ cmake ..
-- The C compiler identification is GNU 5.4.0
-- The CXX compiler identification is GNU 5.4.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/fff/Desktop/cmake_dir/build
fff@ubuntu:~/Desktop/cmake_dir/build$ make
Scanning dependencies of target main
[ 25%] Building C object src/CMakeFiles/main.dir/function.c.o
[ 50%] Building C object src/CMakeFiles/main.dir/function2.c.o
[ 75%] Building C object src/CMakeFiles/main.dir/main.c.o
[100%] Linking C executable ../../bin/main
[100%] Built target main
fff@ubuntu:~/Desktop/cmake_dir/build$ cd ..
fff@ubuntu:~/Desktop/cmake_dir$ cd bin
fff@ubuntu:~/Desktop/cmake_dir/bin$ ls
main
fff@ubuntu:~/Desktop/cmake_dir/bin$ ./main
para var:200
para var2:100

fonctionnement normal!

PS : Pourquoi exécuter cmake sous le répertoire build ? Comme le montrent les exemples précédents, si cela n'est pas fait, les fichiers d'accompagnement générés lors de l'exécution de cmake seront mélangés avec les fichiers de code source, ce qui polluera la structure des répertoires du programme, et exécutera cmake dans le répertoire de construction, les fichiers joints générés ne resteront que dans le répertoire build. Si nous ne voulons pas de ces fichiers, nous pouvons directement effacer le répertoire build, ce qui est très pratique.


Méthode 2 : un CMakeLists.txt

Le projet précédent utilisait 2 CMakeLists.txt, le CMakeLists.txt le plus externe est utilisé pour contrôler la situation globale et add_subdirectory est utilisé pour contrôler le fonctionnement de CMakeLists.txt dans d'autres répertoires.

 L'exemple ci-dessus peut également utiliser un seul CMakeLists.txt et modifier le contenu du CMakeLists.txt le plus externe comme suit :

cmake_minimum_required (VERSION 2.8)

project (demo)

set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)

aux_source_directory (src SRC_LIST)

include_directories (include)

add_executable (main ${SRC_LIST})

Supprimez ensuite le CMakeLists.txt dans le répertoire src . Le répertoire est le suivant :

fff@ubuntu:~/Desktop/cmake_dir2$ tree
.
├── bin
├── build
├── CMakeLists.txt
├── include
│   ├── function2.h
│   └── function.h
└── src
    ├── function2.c
    ├── function.c
    └── main.c

construire, compiler, exécuter

  • Étape 1 : Entrez d’abord dans le dossier de construction , puis exécutez la commande :cmake ..
  • Étape 2 : Après l'étape précédente, le Makefile sera généré dans le répertoire de construction, puis exécuté pour compiler, et un fichier exécutable sera généré dans le répertoire binmake du répertoire racinemain
  • Étape 3 : Entrez le fichier bin dans le répertoire racine pour exécuter le fichier exécutable./main
fff@ubuntu:~/Desktop/cmake_dir2/build$ cmake ..
-- The C compiler identification is GNU 5.4.0
-- The CXX compiler identification is GNU 5.4.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/fff/Desktop/cmake_dir2/build
liefyuan@ubuntu:~/Desktop/cmake_dir2/build$ ls
CMakeCache.txt  CMakeFiles  cmake_install.cmake  Makefile
fff@ubuntu:~/Desktop/cmake_dir2/build$ make
Scanning dependencies of target main
[ 25%] Building C object CMakeFiles/main.dir/src/function.c.o
[ 50%] Building C object CMakeFiles/main.dir/src/function2.c.o
[ 75%] Building C object CMakeFiles/main.dir/src/main.c.o
[100%] Linking C executable ../bin/main
[100%] Built target main
fff@ubuntu:~/Desktop/cmake_dir2/build$ cd ..
fff@ubuntu:~/Desktop/cmake_dir2$ cd bin
fff@ubuntu:~/Desktop/cmake_dir2/bin$ ls
main
fff@ubuntu:~/Desktop/cmake_dir2/bin$ ./main
para var:200
para var2:100

fonctionnement normal!


Six, CMake build : compiler une bibliothèque dynamique et une bibliothèque statique

6.1 Construire une structure de fichiers :

fff@ubuntu:~/Desktop/cmake_lib$ tree
.
├── build
├── CMakeLists.txt
├── function
│   ├── function.c
│   └── function.h
└── lib

Exécutez cmake dans le répertoire build et stockez les fichiers de bibliothèque générés dans le répertoire lib .

6.2 Le contenu du fichier CMakeLists.txt nouvellement créé est :

cmake_minimum_required (VERSION 2.8)
        
project (demo)
        
set (SRC_LIST ${PROJECT_SOURCE_DIR}/function/function.c)
        
add_library (function_shared SHARED ${SRC_LIST})
add_library (function_static STATIC ${SRC_LIST})
        
set_target_properties (function_shared PROPERTIES OUTPUT_NAME "function")
set_target_properties (function_static PROPERTIES OUTPUT_NAME "function")
        
set (LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)

PS : De nouvelles commandes et variables prédéfinies apparaissent ici :

  • add_library : Génère une bibliothèque dynamique ou une bibliothèque statique (le premier paramètre précise le nom de la bibliothèque ; le deuxième paramètre détermine si elle est dynamique ou statique, sinon, elle est par défaut statique ; le troisième paramètre précise le fichier source du généré bibliothèque)
  • set_target_properties : Définissez le nom de la bibliothèque finale générée et d'autres fonctions, telles que la définition du numéro de version de la bibliothèque, etc.
  • LIBRARY_OUTPUT_PATH : Le chemin de sortie par défaut du fichier de bibliothèque, défini ici dans le répertoire lib sous le répertoire du projet

6.3 Entrez dans le répertoire de construction pour exécuter la commande cmake .., générez le Makefile puis exécutez-le make.

fff@ubuntu:~/Desktop/cmake_lib/build$ cmake ..
-- The C compiler identification is GNU 5.4.0
-- The CXX compiler identification is GNU 5.4.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/fff/Desktop/cmake_lib/build
fff@ubuntu:~/Desktop/cmake_lib/build$ make
Scanning dependencies of target function_static
[ 25%] Building C object CMakeFiles/function_static.dir/function/function.c.o
[ 50%] Linking C static library ../lib/libfunction.a
[ 50%] Built target function_static
Scanning dependencies of target function_shared
[ 75%] Building C object CMakeFiles/function_shared.dir/function/function.c.o
[100%] Linking C shared library ../lib/libfunction.so
[100%] Built target function_shared

6.4 Une fois la compilation réussie, entrez dans le répertoire lib pour vérifier et constater que la bibliothèque dynamique et la bibliothèque statique ont été générées avec succès.

fff@ubuntu:~/Desktop/cmake_lib/build$ cd ..
fff@ubuntu:~/Desktop/cmake_lib$ cd lib
fff@ubuntu:~/Desktop/cmake_lib/lib$ ls
libfunction.a  libfunction.so

PS : Set_target_properties a été utilisé pour redéfinir le nom de sortie de la bibliothèque. Si vous n'utilisez pas set_target_properties , alors le nom de la bibliothèque est le nom défini dans add_library , mais lorsque vous utilisez add_library pour spécifier le nom de la bibliothèque (le premier paramètre) deux fois dans une rangée , les noms ne peuvent pas être identiques, mais set_target_properties peut définir les noms pour qu'ils soient identiques, mais les suffixes des fichiers de bibliothèque générés finaux sont différents (l'un est .so, l'autre est .a), ce qui ressemblera à relativement bon.


Seven, build CMake : bibliothèque de liens

La bibliothèque a déjà été générée et le lien vers la bibliothèque est maintenant effectué.

fff@ubuntu:~/Desktop/cmake_lib_link$ tree
.
├── bin
├── build
├── CMakeLists.txt
├── function
│   ├── inc
│   │   └── function.h
│   └── lib
│       ├── libfunction.a
│       └── libfunction.so
└── src
    └── main.c

7.1 main.c

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

int main(void)
{       
    func(300);

    return 0;
} 

7.2 CMakeLists.txt

cmake_minimum_required (VERSION 2.8)
        
project (demo)
        
set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
        
set (SRC_LIST ${PROJECT_SOURCE_DIR}/src/main.c)
        
include_directories (${PROJECT_SOURCE_DIR}/function/inc)
        
find_library(FUNCTION_LIB function HINTS ${PROJECT_SOURCE_DIR}/function/lib)
        
add_executable (main ${SRC_LIST})
        
target_link_libraries (main ${FUNCTION_LIB})

Explication des nouvelles commandes :

  • find_library : recherche la bibliothèque spécifiée dans le répertoire spécifié et stocke le chemin absolu de la bibliothèque dans une variable. Le premier paramètre est le nom de la variable, le deuxième paramètre est le nom de la bibliothèque, le troisième paramètre est HINTS et le quatrième paramètre est Chemin, d'autres utilisations peuvent se référer à la documentation cmake
  • target_link_libraries : Lier les fichiers cibles avec les fichiers de bibliothèque

 L'avantage d' utiliser find_library est qu'il cmake ..vérifiera si la bibliothèque existe pendant l'exécution, afin que les erreurs puissent être trouvées à l'avance sans attendre l'heure de la liaison.

 cd dans le répertoire build, puis exécutez-le cmake .. && make, et enfin entrez dans le répertoire bin pour vérifier, et constatez que le main a été généré, exécutez-le simplement.

fff@ubuntu:~/Desktop/cmake_lib_link/build$ cmake ..&& make
-- The C compiler identification is GNU 5.4.0
-- The CXX compiler identification is GNU 5.4.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/fff/Desktop/cmake_lib_link/build
Scanning dependencies of target main
[ 50%] Building C object CMakeFiles/main.dir/src/main.c.o
[100%] Linking C executable ../bin/main
[100%] Built target main

7.3 Exécuter :

fff@ubuntu:~/Desktop/cmake_lib_link/build$ cd ..
fff@ubuntu:~/Desktop/cmake_lib_link$ cd bin
fff@ubuntu:~/Desktop/cmake_lib_link/bin$ ./main
para var:300

Exécutez avec succès ! PS :

Il existe des bibliothèques statiques et des bibliothèques dynamiques de fonctions dans le répertoire lib, find_library(FUNCTION_LIB function ... consiste à rechercher la bibliothèque dynamique par défaut, si vous souhaitez spécifier directement si vous souhaitez utiliser la bibliothèque dynamique ou la bibliothèque statique, vous pouvez écrire find_library(FUNCTION_LIB libfunction.so ...ou find_library(FUNCTION_LIB libfunction.a…

Huit, build CMake : ajouter des options de compilation

Parfois, vous devez ajouter des options de compilation lors de la compilation du programme, telles que -Wall, -std=c++11etc., vous pouvez les utiliser add_compile_optionpour fonctionner.

8.1 main.cpp

#include <iostream>

int main(void)
{
	auto data = 100;
	std::cout << "data:" << data << "\n";
	return 0;
}

8.2 CMakeLists.txt

cmake_minimum_required (VERSION 2.8)

project (demo)

set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)

add_compile_options(-std=c++11 -Wall)

add_executable(main main.cpp)

L'arborescence des répertoires est la suivante :

fff@ubuntu:~/Desktop/cmake_cpp$ tree
.
├── bin
├── build
├── CMakeLists.txt
└── main.cpp

Ensuite, cd dans le répertoire build , exécutez la commande cmake ... && make , vous pouvez obtenir le fichier elf principal dans le répertoire bin


Neuf, build CMake : ajouter des options de contrôle

Parfois lors de la compilation du code, seuls certains codes spécifiés sont compilés, vous pouvez utiliser la commande option de cmake, il y a principalement deux types de situations rencontrées :

  • À l'origine, je voulais générer plusieurs fichiers bin ou bibliothèque, mais maintenant je souhaite uniquement générer certains fichiers bin ou bibliothèque spécifiés.
  • Pour le même fichier bin, je souhaite uniquement compiler une partie du code (en utilisant des macros pour contrôler)

9.1 À l'origine, je voulais générer plusieurs fichiers bin ou bibliothèque, mais maintenant je souhaite uniquement générer certains fichiers bin ou bibliothèque spécifiés.

En supposant que notre projet actuel génère deux fichiers bin, main1 et main2, la structure globale est désormais la suivante :

fff@ubuntu:~/Desktop/cmake_2bin$ tree
.
├── bin
├── build
├── CMakeLists.txt
└── src
    ├── CMakeLists.txt
    ├── main1.c
    └── main2.c

Le contenu de main1.c et main2.c est le suivant,

// main1.c
#include <stdio.h>

int main(void)
{
    printf("hello, this main1\n");
    
    return 0;
}
// main2.c
#include <stdio.h>

int main(void)
{
    printf("hello, this main2\n");
    
    return 0;
}

Le contenu du fichier CMakeLists.txt externe est le suivant :

cmake_minimum_required(VERSION 3.5)

project(demo)

option(MYDEBUG "enable debug compilation" OFF)

set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)

add_subdirectory(src)

La commande option est utilisée ici , le premier paramètre est le nom de l'option, le deuxième paramètre est une chaîne, qui est utilisée pour décrire à quoi sert l'option, et le troisième est la valeur de l'option, ON ou OFF, vous peut également Ne pas écrire, ne pas écrire est la valeur OFF par défaut.

Ensuite, écrivez CMakeLists.txt dans le répertoire src , comme suit

cmake_minimum_required (VERSION 3.5)

add_executable(main1 main1.c)

if (MYDEBUG)
    add_executable(main2 main2.c)
else()
    message(STATUS "Currently is not in debug mode")    
endif()

Remarque : if-else est utilisé ici pour décider s'il faut compiler main2.c selon l'option

Ensuite, allez dans le répertoire de construction et entrez cmake .. && makepour compiler uniquement main1. Si vous souhaitez compiler main2, définissez MYDEBUG sur ON et entrez à nouveau cmake .. && makepour recompiler.

PS : Chaque fois que vous souhaitez modifier MYDEBUG, vous devez modifier CMakeLists.txt, ce qui est un peu gênant. En fait, vous pouvez le faire fonctionner via la ligne de commande cmake. Par exemple, si nous voulons définir MYDEBUG sur OFF, d'abord cd dans le répertoire build, puis entrez cmake .. - DMYDEBUG=ON , afin que main1 et main2 puissent être compilés (dans le répertoire bin )

 9.2 Pour le même fichier bin, je souhaite uniquement compiler une partie du code (utiliser la macro pour contrôler)

La structure globale du projet est la suivante,

fff@ubuntu:~/Desktop/cmake_1mian_define$ tree
.
├── bin
├── build
├── CMakeLists.txt
└── main.c

Supposons que nous ayons un main.c dont le contenu est le suivant,

#include <stdio.h>

int main(void)
{
#ifdef WWW1
    printf("hello world1\n");
#endif    

#ifdef WWW2     
    printf("hello world2\n");
#endif

    return 0;
}

Vous pouvez contrôler les informations imprimées en définissant des macros. Le contenu de notre CMakeLists.txt est le suivant,

cmake_minimum_required(VERSION 3.5)

project(demo)

set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)

option(WWW1 "print one message" OFF)
option(WWW2 "print another message" OFF)

if (WWW1)
    add_definitions(-DWWW1)
endif()

if (WWW2)
    add_definitions(-DWWW2)
endif()

add_executable(main main.c)

Ici, le nom de l'option reste le même que le nom de la macro dans main.c, ce qui est plus intuitif, et vous pouvez également choisir un nom différent. En coopérant avec add_definitions() , vous pouvez contrôler l'impression d'un seul fichier bin.

cd dans le répertoire build pour exécuter cmake .. && make, puis dans le répertoire bin pour exécuter ./main, vous pouvez voir que l'impression est vide,
puis suivez les instructions ci-dessous pour exécuter, puis vérifiez l'effet d'impression,

  • cmake .. -DWWW1=ON -DWWW2=OFF && make
  • cmake .. -DWWW1=OFF -DWWW2=ON && make
  • cmake .. -DWWW1=ON -DWWW2=ON && make

Avis:

Voici un petit trou auquel il faut prêter attention : supposons qu'il y ait deux options appelées A et B, appelez d'abord cmake pour définir A, puis appelez cmake pour définir B la prochaine fois, si le fichier cache généré lors de la dernière exécution de cmake n'est pas supprimé, alors ceci Bien que A ne soit pas défini cette fois, la dernière valeur d'option de A sera utilisée par défaut.

Ainsi, si l'option change, supprimez le fichier cache généré lors de la dernière exécution de cmake ou spécifiez explicitement sa valeur pour toutes les options.

10. Résumé

Ce qui précède sont quelques notes d'étude pour que j'apprenne CMake . Grâce à des exemples simples, je peux rapidement démarrer avec CMake . J'ai également lu de nombreux blogs d'internautes pendant mes études. Il existe encore de nombreux points de connaissances sur CMake, et des détails spécifiques peuvent être recherchés en ligne. En bref, CMake peut nous éviter d'écrire des Makefiles complexes , et il est multiplateforme. C'est un outil très puissant qui mérite d'être appris.

S'il y a quelque chose qui ne va pas, j'espère que vous pourrez laisser un message pour me corriger, merci d'avoir lu !

Je suppose que tu aimes

Origine blog.csdn.net/FLM19990626/article/details/132408320
conseillé
Classement