projtec:cmake
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
projtec:cmake [2017/01/25 18:32] – orel | projtec:cmake [2024/03/18 15:06] (current) – external edit 127.0.0.1 | ||
---|---|---|---|
Line 1: | Line 1: | ||
======CMake ====== | ======CMake ====== | ||
+ | |||
+ | * https:// | ||
+ | * https:// | ||
+ | * https:// | ||
==== Hello World ==== | ==== Hello World ==== | ||
Line 18: | Line 22: | ||
<code text CMakeLists.txt> | <code text CMakeLists.txt> | ||
cmake_minimum_required(VERSION 2.6) | cmake_minimum_required(VERSION 2.6) | ||
- | project(HelloWorld) | + | project(HelloWorld |
add_executable(hello hello.c) | add_executable(hello hello.c) | ||
</ | </ | ||
- | Pour générer un Makefile et compiler notre projet, il faut taper les commandes suivantes : | + | Pour générer un Makefile et compiler notre projet |
cmake . | cmake . | ||
- | make # ou make VERBOSE=ON | + | make clean ; make |
+ | | ||
+ | make help # pour voir la liste des cibles possibles | ||
+ | |||
+ | Pour compiler "en dehors des sources" | ||
+ | |||
+ | mkdir build | ||
+ | cd build | ||
+ | cmake .. | ||
+ | make | ||
+ | |||
+ | Un des avantages de cette méthode est quelle permet de ne pas mélanger les fichiers générés par CMake et Make avec les fichiers sources. Du coup, il suffit de supprimer le répertoire //build// pour tout nettoyer. | ||
==== Un peu plus compliqué ==== | ==== Un peu plus compliqué ==== | ||
Line 61: | Line 76: | ||
cmake_minimum_required (VERSION 2.6) | cmake_minimum_required (VERSION 2.6) | ||
project (HelloWorld C) | project (HelloWorld C) | ||
+ | |||
+ | set(CMAKE_BUILD_TYPE DEBUG) | ||
+ | set(CMAKE_VERBOSE_MAKEFILE ON) | ||
+ | set(CMAKE_C_COMPILER gcc) | ||
set(CMAKE_C_FLAGS " | set(CMAKE_C_FLAGS " | ||
set(CMAKE_INSTALL_PREFIX " | set(CMAKE_INSTALL_PREFIX " | ||
+ | |||
add_executable(hello hello.c pouet.c) | add_executable(hello hello.c pouet.c) | ||
target_link_libraries(hello m) | target_link_libraries(hello m) | ||
install(TARGETS hello RUNTIME DESTINATION bin) | install(TARGETS hello RUNTIME DESTINATION bin) | ||
</ | </ | ||
+ | |||
+ | Notons que CMake scanne automatiquement les dépendances (sans faire néanmoins de preprocessing). Il en résulte que la dépendance sur //pouet.h// est ajouté implicitement. | ||
Ensuite, on fait... | Ensuite, on fait... | ||
cmake . | cmake . | ||
- | make | + | make |
- | make install | + | make install |
+ | | ||
| | ||
==== Utilisation d'une bibliothèque interne ==== | ==== Utilisation d'une bibliothèque interne ==== | ||
- | Considérons maintenant le projet | + | Considérons maintenant le projet |
< | < | ||
Line 89: | Line 112: | ||
</ | </ | ||
- | (...) | + | Ce projet contient un éxecutable //hello// qui utilise la bibliothèque interne //mylib// définit par un second |
- | + | ||
- | <code C hello.c> | + | |
- | </code> | + | |
- | #include < | + | |
- | #include " | + | |
- | #include "mylib.h" | + | |
- | + | ||
- | int main() { | + | |
- | printf(" | + | |
- | pouet(); | + | |
- | mylib_foo(); | + | |
- | mylib_bar(); | + | |
- | return 0; | + | |
- | } | + | |
- | + | ||
- | </code> | + | |
- | + | ||
- | Voici donc le fichier | + | |
<code text CMakeLists.txt> | <code text CMakeLists.txt> | ||
Line 114: | Line 119: | ||
set(CMAKE_C_FLAGS " | set(CMAKE_C_FLAGS " | ||
set(CMAKE_INSTALL_PREFIX " | set(CMAKE_INSTALL_PREFIX " | ||
+ | include_directories(mylib) | ||
+ | # link_directories(mylib) | ||
add_executable(hello hello.c pouet.c) | add_executable(hello hello.c pouet.c) | ||
- | target_link_libraries(hello m) | + | target_link_libraries(hello m mylib) |
install(TARGETS hello RUNTIME DESTINATION bin) | install(TARGETS hello RUNTIME DESTINATION bin) | ||
+ | add_subdirectory(mylib) | ||
</ | </ | ||
- | Ensuite, on fait... | + | |
+ | <code text mylib/ | ||
+ | add_library(mylib mylib.c) | ||
+ | install(TARGETS mylib ARCHIVE DESTINATION lib) | ||
+ | install(FILES mylib.h DESTINATION include) | ||
+ | </ | ||
+ | |||
+ | Ensuite, on fait comme d' | ||
cmake . | cmake . | ||
Line 125: | Line 140: | ||
make install | make install | ||
+ | On trouve alors dans le répertoire //install// les fichiers suivants : | ||
- | ==== Biblio ==== | + | < |
+ | ├── bin | ||
+ | │ └── hello | ||
+ | ├── include | ||
+ | │ └── mylib.h | ||
+ | └── lib | ||
+ | └── libmylib.a | ||
+ | </ | ||
- | * https://cmake.org/documentation/ | + | ==== Tests Dynamiques ==== |
- | | + | |
- | * https://cmake.org/cmake/help/v3.3/manual/cmake-commands.7.html | + | On ajoute à notre projet un sous-répertoire |
+ | |||
+ | < | ||
+ | ├── CMakeLists.txt | ||
+ | ├── hello.c | ||
+ | ├── mylib | ||
+ | │ ├── CMakeLists.txt | ||
+ | │ ├── mylib.c | ||
+ | │ └── mylib.h | ||
+ | ├── pouet.c | ||
+ | ├── pouet.h | ||
+ | └── tests | ||
+ | ├── CMakeLists.txt | ||
+ | ├── test-mylib-bar.c | ||
+ | └── test-mylib-foo.c | ||
+ | </code> | ||
+ | |||
+ | Voici le fichier | ||
+ | |||
+ | <code text tests/ | ||
+ | include(CTest) | ||
+ | enable_testing() | ||
+ | |||
+ | add_executable(test-mylib-foo test-mylib-foo.c) | ||
+ | target_link_libraries(test-mylib-foo mylib) | ||
+ | |||
+ | add_executable(test-mylib-bar test-mylib-bar.c) | ||
+ | target_link_libraries(test-mylib-bar mylib) | ||
+ | |||
+ | add_test(test1 test-mylib-foo) | ||
+ | set_tests_properties(test1 PROPERTIES PASS_REGULAR_EXPRESSION " | ||
+ | add_test(test2 test-mylib-bar) | ||
+ | set_tests_properties(test2 PROPERTIES PASS_REGULAR_EXPRESSION " | ||
+ | |||
+ | </ | ||
+ | |||
+ | Pour lancer les tests : | ||
+ | | ||
+ | |||
+ | ==== Fuites Mémoire ==== | ||
+ | |||
+ | Pour aller un peu plus loin, on peut lancer des tests de varification de la mémoire (memcheck) | ||
+ | |||
+ | make ExperimentalMemCheck | ||
+ | |||
+ | Ces tests se base sur la variable MEMORYCHECK_COMMAND qui est par défault sur /sur/bin/ | ||
+ | |||
+ | Les logs sont disponibles dans : Testing/Temporary/MemoryChecker.*.log | ||
+ | |||
+ | Il est possible d' | ||
+ | |||
+ | find_program(MEMORYCHECK_COMMAND valgrind) | ||
+ | set(MEMORYCHECK_COMMAND_OPTIONS " | ||
+ | |||
+ | |||
+ | ==== Couverture de Code ==== | ||
+ | |||
+ | Pour aller encore plus loin... | ||
+ | |||
+ | <code text tests/CMakeLists.txt> | ||
+ | cmake_minimum_required(VERSION 3.0) | ||
+ | |||
+ | include(CTest) | ||
+ | enable_testing() | ||
+ | |||
+ | set(CMAKE_C_FLAGS " | ||
+ | |||
+ | add_executable(foo foo.c) | ||
+ | |||
+ | add_test(test1 ./foo 2) | ||
+ | add_test(test2 ./foo 5) | ||
+ | </ | ||
+ | |||
+ | | ||
+ | make ExperimentalTest # ou make test | ||
+ | make ExperimentalCoverage | ||
+ | more Testing/CoverageInfo/* | ||
+ | |||
+ | Il est plus élégant de n' | ||
+ | |||
+ | <code text tests/ | ||
+ | cmake_minimum_required(VERSION | ||
+ | |||
+ | include(CTest) | ||
+ | enable_testing() | ||
+ | |||
+ | set(CMAKE_C_FLAGS " | ||
+ | set(CMAKE_C_FLAGS_DEBUG " | ||
+ | |||
+ | add_executable(foo foo.c) | ||
+ | |||
+ | add_test(test1 ./foo 2) | ||
+ | add_test(test2 ./foo 5) | ||
+ | </ | ||
+ | |||
+ | |||
+ | Il faut alors compiler le code en mode DEBUG (et non pas en mode RELEASE) : | ||
+ | |||
+ | | ||
+ | make ExperimentalTest | ||
+ | make ExperimentalCoverage | ||
+ | more Testing/ | ||
projtec/cmake.1485369121.txt.gz · Last modified: 2024/03/18 15:05 (external edit)