J'utilise GNU make pour compiler mon code C++ et je voudrais comprendre comment rendre mes compilations personnalisables.
J'ai lu à différents endroits que CFLAGS
, CCFLAGS
et CXXFLAGS
étaient utilisés à cette fin. Alors, comment devrais-je les utiliser? Si j'ai des arguments de ligne de commande supplémentaires pour le compilateur, devrais-je les ajouter à CFLAGS
ou les ajouter au début? Y a-t-il une pratique commune?
Pourquoi les trois variables différentes? Je suppose que le compilateur C devrait avoir CFLAGS
et CCFLAGS
, tandis que le compilateur C++ devrait avoir CFLAGS
et CXXFLAGS
- l’ai-je bien compris?
L'utilisateur humain est-il censé définir ces variables? Est-ce que des outils automatiques (automake
, autoconf
, etc.) les définissent? Le système Linux que je suis supposé utiliser ne définit aucune de ces variables - est-ce typique?
Actuellement, mon Makefile ressemble à ceci et je trouve ça un peu sale:
ifdef code_coverage
GCOV_FLAG := -fprofile-arcs -ftest-coverage
else
GCOV_FLAG :=
endif
WFLAGS := -Wall
INC_FLAGS := -Istuff -Imore_stuff -Ietc
CCFLAGSINT := -O3 $(WFLAGS) $(INC_FLAGS) $(CCFLAGS)
... (somewhere in the makefile, the command-line for compilation looks like this)
$(CC) $(CCFLAGSINT) -c $< -o $@
... (somewhere in the makefile, the command-line for linking looks like this)
$(CC) $(GCOV_FLAG) $(CCFLAGSINT) $(OBJLIST) $(LDFLAGS) -o $@
Je suis à peu près sûr qu'il n'y a pas de bugs ici; Le Makefile fonctionne très bien. Mais y a-t-il quelque chose qui va à l'encontre des conventions (comme CCFLAGSINT
- devrais-je simplement écraser CCFLAGS
à la place? Ou bien CXXFLAGS
? FUD!)
Désolé pour tant de questions; vous n'allez évidemment pas y répondre tous, mais j'espère que les réponses m'aideront à comprendre l'idée générale qui se cache derrière ces paramètres.
Comme vous l'avez remarqué, il s'agit de Makefile {macros ou variables}, et non d'options du compilateur. Ils mettent en œuvre un ensemble de conventions. (Macros est un ancien nom pour eux, encore utilisé par certains. GNU make doc les appelle variables).
La seule raison pour laquelle les noms sont importants, ce sont les règles de création par défaut, visibles via make -p
, qui en utilise certains.
Si vous écrivez toutes vos propres règles, vous devez choisir tous vos propres noms de macro.
Dans une marque Vanilla gnu, il n’existe pas de CCFLAGS. Il y a CFLAGS
, CPPFLAGS
et CXXFLAGS
. CFLAGS
pour le compilateur C, CXXFLAGS
pour C++ et CPPFLAGS
pour les deux.
Pourquoi CPPFLAGS
est-il dans les deux? Conventionnellement, c'est la maison des drapeaux de préprocesseur (-D
, -U
) et c et c ++ les utilisent. Maintenant, l'hypothèse que tout le monde veut le même environnement de définition pour c et c ++ est peut-être discutable, mais traditionnelle.
P.S. Comme indiqué par James Moore , certains projets utilisent CPPFLAGS pour les indicateurs du compilateur C++, et non pour le préprocesseur C. Le Android NDK, par exemple).
Selon le GNU make
Manuel:
CFLAGS: Drapeaux supplémentaires à donner au compilateur C.
CXXFLAGS: indicateurs supplémentaires à donner au compilateur C++.
CPPFLAGS: indicateurs supplémentaires à donner au préprocesseur C et aux programmes qui l’utilisent (les compilateurs C et Fortran).
src: https://www.gnu.org/software/make/manual/make.html#index-CFLAGS
note: PP signifie PreProcessor (et non Plus Plus), c.-à-d.
CPP: programme pour exécuter le préprocesseur C, avec les résultats obtenus en sortie standard; défaut '$ (CC) -E'.
Ces variables sont utilisées par les règles implicites de make
Compiler les programmes C
n.o est créé automatiquement à partir de n.c avec une recette de la forme
"$ (CC) $ (CPPFLAGS) $ (CFLAGS) -c".Compiler des programmes C++
n.o est créé automatiquement à partir de n.cc, n.cpp ou n.C avec une recette de la forme
‘$ (CXX) $ (CPPFLAGS) $ (CXXFLAGS) -c '.
Nous vous encourageons à utiliser le suffixe ".cc" pour les fichiers source C++ au lieu de ".C".
src: https://www.gnu.org/software/make/manual/make.html#Catalogue-of-Rules
Et juste pour faire ce que Mizux a dit à titre d'exemple minimal:
main_c.c
#include <stdio.h>
int main(void) {
puts("hello");
}
main_cpp.cpp
#include <iostream>
int main(void) {
std::cout << "hello" << std::endl;
}
Ensuite, sans aucun Makefile
:
make CFLAGS='-g -O3' CXXFLAGS='-ggdb3 -O0' CPPFLAGS='-DX=1 -DY=2' main_c main_cpp
fonctionne:
cc -g -O3 -DX=1 -DY=2 main_c.c -o main_c
g++ -ggdb3 -O0 -DX=1 -DY=2 main_cpp.cpp -o main_cpp
Nous comprenons donc que:
make
avait des règles implicites pour faire main_c
et main_cpp
de main_c.c
et main_cpp.cpp
.c
compilation.cpp
compilationCes variables ne sont utilisées automatiquement que dans les règles implicites de make: si la compilation avait utilisé nos propres règles explicites, nous devrions les utiliser explicitement comme suit:
main_c: main_c.c
$(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $<
main_cpp: main_c.c
$(CXX) $(CXXFLAGS) $(CPPFLAGS) -o $@ $<
pour obtenir un effet similaire aux règles implicites.
Nous pourrions aussi nommer ces variables comme bon nous semble: mais comme Make les traite déjà de manière magique dans les règles implicites, celles-ci font de bons choix de noms.
Testé sous Ubuntu 16.04, GNU Make 4.1.