web-dev-qa-db-fra.com

Cmake vs faire des exemples de codes?

Je me demandais s'il y avait un exemple de code pour Makefiles (make) et CMakeLists.txt (cmake) que les deux fassent la même chose (la seule différence est que l’un est écrit en make et l’autre en cmake).

J'ai essayé de rechercher 'cmake vs make', mais je n'ai jamais trouvé de comparaison de code. Il serait vraiment utile de comprendre les différences, même s'il ne s'agit que d'un cas simple.

107
jlo

Le Makefile suivant construit 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 tous deux également construits à partir de la source. De plus, prog utilise la bibliothèque libstuff.a dans stuff/lib et son en-tête dans stuff/include. Le Makefile par défaut construit 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 une CMakeLists.txtqui 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 compiler
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 les 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 telles que $ (CC) ..., $ (RANLIB) ... et ainsi de suite.

  • Tous les indicateurs 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/indépendantes du système.

  • Les indicateurs de débogage sont inclus en définissant la variable CMAKE_BUILD_TYPE sur "Debug" ou en la passant à CMake lors de l’appel du programme: cmake -DCMAKE_BUILD_TYPE:STRING=Debug.

  • CMake offre également l'inclusion, indépendamment de la plate-forme, de l'indicateur '-fPIC' (via la propriété POSITION_INDEPENDENT_CODE) et de nombreux autres. Néanmoins, des paramètres plus obscurs peuvent être implémentés manuellement dans CMake, ainsi que dans un Makefile (en utilisant COMPILE_FLAGS et propriétés similaires). Bien sûr, CMake commence vraiment à briller lorsque des bibliothèques tierces (telles que OpenGL) sont incluses de manière portable.

  • Le processus de construction comporte une étape si vous utilisez un Makefile, à savoir taper make sur la ligne de commande. Pour CMake, il y a deux étapes: Tout d’abord, vous devez configurer votre environnement de construction (soit en tapant cmake <source_dir> dans votre répertoire de construction ou en exécutant un client graphique). Cela crée un Makefile ou quelque chose d’équivalent, selon le système de construction de votre choix (par exemple make sous Unixes ou VC++ ou MinGW + Msys sous Windows). Le système de construction peut être passé à CMake en tant que paramètre; Cependant, CMake fait des choix par défaut raisonnables 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 construction sont disponibles sur https://github.com/rhoelzel/make_cmake .

111
Roberto

Prenez un logiciel qui utilise CMake comme système de construction (il y a beaucoup de projets opensource parmi lesquels choisir). Obtenez le code source et configurez-le en utilisant CMake. Lire les makefiles résultants et en profiter.

Une chose à garder à l'esprit que ces outils ne mappent pas un à un. La différence la plus évidente est que CMake analyse les dépendances entre différents fichiers (par exemple, les fichiers source et en-tête C), alors que make laisse cela aux auteurs du makefile.

Si cette question concerne un exemple Makefile, la sortie du CMakeList.txt fichier alors veuillez vérifier les sources de cmake-backend et générer un tel Makefile. Si ce n'est pas le cas, alors j'ajoute à la réponse de @Roberto j'essaie de simplifier les choses en cachant les détails.

Fonction CMake

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.

Ma plaine CMakeLists.txt ressemblera à ce qui suit,

cmake_minimum_required(VERSION 2.8)
project(example)
file(GLOB testapp_SOURCES *.cc)
add_executable(testapp ${testapp_SOURCES})

Notez que CMake cache how la construction peut être faite. Nous avons uniquement spécifié que what est l’entrée et la sortie.

Le CMakeLists.txt contient la liste des appels de fonction définis par cmake.

(Fonction CMake) Vs établir des règles

Dans Makefile le rules and recipes sont utilisés à la place de functions. En plus de la fonctionnalité semblable à function, rules and recipes fournir un chaînage. Mon minimaliste Makefile ressemblera à ce qui suit,

-include "executable.mk"
TARGETS=testapp.bin
all:${TARGETS}

Tandis que le executable.mk ressemblera à ce qui suit,

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)

En partant 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 eu cet extrait de ici et l'ai modifié. Notez que certaines règles implicites sont ajoutées à ce fichier, que vous pouvez trouver dans la documentation de makefile. Certaines variables implicites sont également pertinentes ici.

Notez que Makefile fournit le détail recipe montrant how que la construction peut être faite. Il est possible d'écrire executable.mk pour conserver les détails définis dans un fichier. De cette façon, le makefile peut être réduit comme je l’ai déjà montré.

Variables internes dans CMake et Make

Maintenant que nous sommes un peu avancés, dans CMake, nous pouvons définir un drapeau de compilateur comme celui-ci,

set(CMAKE_C_FLAGS "-Wall")

Veuillez en savoir plus sur les variables CMake par défaut dans CMakeCache.txt fichier. Le code CMake ci-dessus sera équivalent à Make code 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.

ajout de include et du chemin de bibliothèque dans CMake

Nous pouvons le faire dans cmake en utilisant des fonctions.

target_include_directories(testapp PRIVATE "myincludes")
list(APPEND testapp_LIBRARIES
    mytest mylibrarypath
)
target_link_libraries(testapp ${testapp_LIBRARIES})

Vs ajoutant include et chemin de la bibliothèque dans Make

Nous pouvons ajouter des bibliothèques include et en ajoutant des lignes comme suit:

INCLUDES += -Imyincludes
LIBS += -Lmylibrarypath -lmytest

Notez que les lignes ci-dessus peuvent être générées à partir d’outils de génération automatique ou de pkg-config. (bien que Makefile ne soit pas dépendant des outils de configuration automatique)

CMake configure/tweek

Normalement, il est possible de générer quelques config.h fichier comme auto-config outils en utilisant configure_file une fonction. Il est possible de faire plus de truc en écrivant des fonctions personnalisées. Et enfin, nous pouvons sélectionner une configuration comme celle-ci,

cmake --build . --config "Release"

Il est possible d’ajouter des options configurables à l’aide de la fonction option.

Makefile configure/Tweak

Si d’une manière ou d’une autre nous avons besoin de le compiler avec un indicateur de débogage, nous pouvons invoquer le make comme,

make CXXFLAGS=NDEBUG

Je pense que les variables internes, Makefile-rules et CMake-functions sont un bon début pour la comparaison, bonne chance pour creuser davantage.

4
shuva