Je me demandais s’il y avait un exemple de code pour Makefile
( make
) et CMakeLists.txt
( cmake
) qui font la même chose (la seule différence étant que l’un est écrit dans make
et l’autre dans cmake
).
J’ai essayé de chercher “cmake vs make”, mais je n’ai jamais trouvé de comparaison de code. Il serait très utile de comprendre les différences, même pour un cas simple.
Le Makefile suivant crée un exécutable nommé prog
partir des sources prog1.c, prog2.c, prog3.c and main.c
prog
est lié à libmystatlib.a
et libmydynlib.so
qui sont également construits à partir des sources. De plus, prog
utilise la bibliothèque libstuff.a
dans stuff/lib
et son en-tête dans stuff/include
. Le Makefile crée par défaut une cible de publication, mais offre également une cible de débogage:
#Makefile CC = gcc CPP = g++ RANLIB = ar rcs RELEASE = -c -O3 DEBUG = -c -g -D_DEBUG INCDIR = -I./stuff/include LIBDIR = -L./stuff/lib -L. LIBS = -lstuff -lmystatlib -lmydynlib CFLAGS = $(RELEASE) PROGOBJS = prog1.o prog2.o prog3.o prog: main.o $(PROGOBJS) mystatlib mydynlib $(CC) main.o $(PROGOBJS) $(LIBDIR) $(LIBS) -o prog debug: CFLAGS=$(DEBUG) debug: prog mystatlib: mystatlib.o $(RANLIB) libmystatlib.a mystatlib.o mydynlib: mydynlib.o $(CPP) -shared mydynlib.o -o libmydynlib.so %.o: %.c $(CC) $(CFLAGS) $(INCDIR) $< -o $@ %.o: %.cpp $(CPP) $(CFLAGS) $(INCDIR) -fPIC $< -o $@
Voici un CMakeLists.txt
qui fait (presque) exactement la même chose, avec quelques commentaires pour souligner les similitudes avec le Makefile:
#CMakeLists.txt cmake_minimum_required(VERSION 2.8) # stuff not directly project(example) # related to building include_directories(${CMAKE_SOURCE_DIR}/stuff/include) # -I flags for comstackr link_directories(${CMAKE_SOURCE_DIR}/stuff/lib) # -L flags for linker set(PROGSRC prog1.c prog2.c prog3.c) # define variable add_executable(prog main.c ${PROGSRC}) # define executable target prog, specify sources target_link_libraries(prog mystatlib mydynlib stuff) # -l flags for linking prog target add_library(mystatlib STATIC mystatlib.c) # define static library target mystatlib, specify sources add_library(mydynlib SHARED mydynlib.cpp) # define shared library target mydynlib, specify sources #extra flags for linking mydynlib set_target_properties(mydynlib PROPERTIES POSITION_INDEPENDENT_CODE TRUE) #alternatively: #set_target_properties(mydynlib PROPERTIES COMPILE_FLAGS "-fPIC")
Dans cet exemple simple, les différences les plus importantes sont les suivantes:
CMake reconnaît quels compilateurs utiliser pour quel type de source. En outre, il appelle la bonne séquence de commandes pour chaque type de cible. Par conséquent, il n'y a pas de spécification explicite de commandes comme $ (CC) ..., $ (RANLIB) ... et ainsi de suite.
Tous les drapeaux habituels du compilateur / éditeur de liens traitant de l'inclusion de fichiers d'en-tête, de bibliothèques, etc. sont remplacés par des commandes indépendantes de la plate-forme / du système de construction.
Les indicateurs de débogage sont inclus en définissant la variable CMAKE_BUILD_TYPE sur "Debug" ou en la transmettant à CMake lors de l'appel du programme: cmake -DCMAKE_BUILD_TYPE:STRING=Debug
.
CMake offre également l'inclusion indépendante de la plate-forme du drapeau '-fPIC' (via la propriété POSITION_INDEPENDENT_CODE) et bien d'autres. Néanmoins, des parameters plus obscurs peuvent être implémentés à la main dans CMake aussi bien que dans un Makefile (en utilisant COMPILE_FLAGS
et des propriétés similaires). Bien sûr, CMake commence vraiment à briller lorsque des bibliothèques tierces (comme OpenGL) sont incluses de manière portable.
Le processus de construction comporte une étape si vous utilisez un fichier Makefile, à savoir make
au niveau de la ligne de commande. Pour CMake, il y a deux étapes: Premièrement, vous devez configurer votre environnement de génération (en tapant cmake
dans votre répertoire de construction ou en exécutant un client d'interface graphique). Cela crée un Makefile ou quelque chose d'équivalent, selon le système de construction de votre choix (par exemple, sur Unix ou VC ++ ou MinGW + Msys sur Windows). Le système de génération peut être transmis à CMake en tant que paramètre; Toutefois, CMake fait des choix raisonnables par défaut en fonction de la configuration de votre système. Deuxièmement, vous effectuez la construction réelle dans le système de construction sélectionné.
Les sources et les instructions de compilation sont disponibles sur https://github.com/rhoelzel/make_cmake .
Prenez un logiciel qui utilise CMake comme système de compilation (vous pouvez choisir parmi de nombreux projets opensource). Obtenez le code source et configurez-le à l’aide de CMake. Lisez les fichiers makefiles obtenus et profitez-en.
Une chose à garder à l’esprit est que ces outils ne correspondent pas à un seul. La différence la plus évidente est que CMake parsing les dépendances entre différents fichiers (par exemple, en-tête C et fichiers source), alors que make laisse cela aux auteurs du fichier makefile.
Si cette question concerne un exemple de sortie Makefile
du fichier CMakeList.txt
, veuillez vérifier les sources cmake-backend et en générer un. Si ce n’est pas le cas, j’ajoute à la réponse de @Roberto que j’essaie de simplifier en cachant les détails.
Alors que Make
est un outil flexible pour les règles et les recettes, CMake
est une couche d’abstraction qui ajoute également la fonctionnalité de configuration.
Mon simple CMakeLists.txt
ressemblera à ceci,
cmake_minimum_required(VERSION 2.8) project(example) file(GLOB testapp_SOURCES *.cc) add_executable(testapp ${testapp_SOURCES})
Notez que CMake
cache la how
la construction peut être effectuée. Nous avons seulement spécifié what
sont les entrées et les sorties.
Le CMakeLists.txt
contient la liste des appels de fonctions définis par cmake
.
Dans Makefile
les rules and recipes
sont utilisées à la place des functions
. En plus de la function
, les rules and recipes
offrent un chaînage. Mon Makefile
minimaliste ressemblera à ceci,
-include "executable.mk" TARGETS=testapp.bin all:${TARGETS}
Alors que l’ executable.mk
ressemblera à ceci,
SOURCES=$(wildcard *.cpp) OBJECTS=$(SOURCES:.cpp=.o) DEPS=$(SOURCES:.cpp=.d) %.bin:$(OBJECTS) $(CC) $(CFLAGS) -o $@ $^ $(LFLAGS) $(LIBS) .PHONY: all clean clean: $(RM) $(OBJECTS) $(DEPS) $(TARGETS) -include $(DEPS)
À partir de zéro, je commencerai par un Makefile
comme celui-ci,
all: testapp.bin testapp.bin:sourcea.o sourcb.o $(CC) $(CFLAGS) -o $@ $^ $(LFLAGS) $(LIBS) .PHONY: all clean clean: $(RM) $(OBJECTS) testapp.bin
J’ai obtenu cet extrait et l’ai modifié. Notez que certaines règles implicites sont ajoutées à ce fichier, qui peuvent être trouvées dans la documentation de makefile. Certaines variables implicites sont également pertinentes ici.
Notez que Makefile
fournit la recipe
détaillée montrant how
la construction peut être effectuée. Il est possible d’écrire executable.mk
pour conserver les détails définis dans un fichier. De cette façon, le fichier makefile peut être réduit comme je l’ai montré précédemment.
CMake
et Make
Maintenant que nous sums un peu avancés, dans CMake
nous pouvons définir un indicateur de compilation comme celui-ci,
set(CMAKE_C_FLAGS "-Wall")
Veuillez en savoir plus sur les variables par défaut de CMake
dans le fichier CMakeCache.txt
. Le code CMake
ci-dessus sera équivalent au code Make
ci-dessous,
CFLAGS = -Wall
Notez que CFLAGS
est une variable interne dans Make
, de la même manière, CMAKE_C_FLAGS
est une variable interne dans CMake
.
Nous pouvons le faire en utilisant cmake
fonctions.
target_include_directories(testapp PRIVATE "myincludes") list(APPEND testapp_LIBRARIES mytest mylibrarypath ) target_link_libraries(testapp ${testapp_LIBRARIES})
Nous pouvons append include et des bibliothèques en ajoutant des lignes comme ci-dessous,
INCLUDES += -Imyincludes LIBS += -Lmylibrarypath -lmytest
Notez que les lignes ci-dessus peuvent être générées à partir des outils de génération automatique ou de pkg-config. (mais Makefile ne dépend pas des outils de configuration automatique)
Normalement, il est possible de générer un fichier config.h
comme auto-config
outils d’ auto-config
en utilisant la fonction configure_file
. Il est possible de faire plus de fonctions personnalisées d’écriture de truc. Et enfin, nous pouvons sélectionner une configuration comme celle-ci,
cmake --build . --config "Release"
Il est possible d’append une option configurable à l’aide de la fonction d’ option
.
Si nous avons besoin de le comstackr avec un indicateur de débogage, nous pouvons appeler le make
like,
make CXXFLAGS=NDEBUG
Je pense que les variables internes, les Makefile-rules
et les CMake-functions
sont un bon début pour la comparaison, bonne chance avec plus de recherches.