CFLAGS vs CPPFLAGS

104

Je comprends que CFLAGS (ou CXXFLAGS pour C ++) sont pour le compilateur, alors que CPPFLAGS est utilisé par le préprocesseur.

Mais je ne comprends toujours pas la différence.

J'ai besoin de spécifier un chemin d'inclusion pour un fichier d'en-tête qui est inclus avec #include - parce que #include est une directive de préprocesseur, le préprocesseur (CPPFLAGS) est-il la seule chose qui me préoccupe?

Dans quelles circonstances dois-je donner au compilateur un chemin d'inclusion supplémentaire?

En général, si le préprocesseur trouve et inclut les fichiers d'en-tête nécessaires, pourquoi a-t-il jamais besoin d'être informé des répertoires d'inclusion supplémentaires? Quelle est l'utilité du CFLAGS?

(Dans mon cas, j'ai en fait trouvé que LES DEUX d'entre eux me permettent de compiler mon programme, ce qui ajoute à la confusion ... Je peux utiliser CFLAGS OU CPPFLAGS pour atteindre mon objectif (en contexte autoconf au moins).

EBM
la source
2
duplicata possible de stackoverflow.com/questions/495598/…
Michael Mrozek

Réponses:

154

La règle de fabrication implicite pour la compilation d'un programme C est

%.o:%.c
    $(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $<

où la $()syntaxe étend les variables. Comme les deux CPPFLAGSet CFLAGSsont utilisés dans l'appel du compilateur, que vous utilisez pour définir les chemins d'inclusion est une question de goût personnel. Par exemple, si foo.cest un fichier dans le répertoire courant

make foo.o CPPFLAGS="-I/usr/include"
make foo.o CFLAGS="-I/usr/include"

appellera tous les deux votre compilateur exactement de la même manière, à savoir

gcc -I/usr/include -c -o foo.o foo.c

La différence entre les deux entre en jeu lorsque vous avez plusieurs langues qui ont besoin du même chemin d'inclusion, par exemple si vous avez bar.cppessayé

make bar.o CPPFLAGS="-I/usr/include"
make bar.o CFLAGS="-I/usr/include"

alors les compilations seront

g++ -I/usr/include -c -o bar.o bar.cpp
g++ -c -o bar.o bar.cpp

car la règle implicite C ++ utilise également la CPPFLAGSvariable.

Cette différence vous donne un bon guide à utiliser - si vous voulez que l'indicateur soit utilisé pour toutes les langues, insérez-le CPPFLAGS, s'il s'agit d'une langue spécifique, insérez-le CFLAGS, CXXFLAGSetc. - vous ne voudriez pas passer -std=c99à votre compilateur C ++!

Vous pourriez alors vous retrouver avec quelque chose comme ça dans votre makefile

CPPFLAGS=-I/usr/include
CFLAGS=-std=c99
CXXFLAGS=-Weffc++
Scott Wales
la source
1
Notez que vous ne pouvez pas exécuter de manière autonome en cpputilisant CPPFLAGSet vous attendre à un résultat raisonnable car cela -std=c99affecte les symboles définis (en particulier au lieu des macros de test de fonctionnalités). Au lieu de cela, vous avez besoin $(CC) $(CPPFLAGS) $(CFLAGS) -E.
Jed
10

La CPPFLAGSmacro est celle à utiliser pour spécifier les #includerépertoires.

Les deux CPPFLAGSet le CFLAGStravail dans votre cas parce que le make(1) La règle combine à la fois pré - traitement et la compilation dans une commande (afin que les deux macros sont utilisées dans la commande).

Vous n'avez pas besoin de spécifier .comme répertoire d'inclusion si vous utilisez le formulaire #include "...". Vous n'avez pas non plus besoin de spécifier le répertoire d'inclusion du compilateur standard. Vous devez spécifier tous les autres répertoires d'inclusion.

Steve Emmerson
la source
Cela a plus de sens, mais je ne vois toujours pas ce que fait CFLAGS. Si, comme vous semblez l'impliquer, la compilation dans des projets plus complexes est effectuée dans une étape distincte du prétraitement, le prétraitement réussira-t-il mais la compilation échouera si CFLAGS n'ajoute pas les mêmes chemins que CPPFLAGS a ajoutés pour le préprocesseur? Je suppose que je ne comprends pas ce que le compilateur fait avec les chemins d'inclusion si le préprocesseur a déjà traité les directives #include?
EBM
4
@EB Si vous compilez des fichiers prétraités, les chemins d'inclusion sont inutiles - les en-têtes requis ont déjà été ajoutés à la source prétraitée (jetez un œil à la sortie lorsque vous exécutez gcc -Esur un fichier - il n'y a pas de #includes). La plupart des compilateurs modernes combinent les étapes de prétraitement et de compilation, vous n'avez donc pas à vous en soucier.
Scott Wales
0

Pour ajouter à ceux qui ont mentionné les règles implicites, il est préférable de voir ce que make a défini implicitement et pour votre env en utilisant:

make -p

Par exemple:

%.o: %.c
    $(COMPILE.c) $(OUTPUT_OPTION) $<

qui se dilate

COMPILE.c = $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c

Cela imprimera également les # environmentdonnées. Ici, vous trouverez le chemin d'inclusion de GCC parmi d'autres informations utiles.

C_INCLUDE_PATH=/usr/include

En make, quand il s'agit de chercher, les chemins sont nombreux, la lumière est une ... ou quelque chose à cet effet.

  1. C_INCLUDE_PATHest à l'échelle du système, placez-le dans votre shell *.rc.
  2. $(CPPFLAGS) est pour le préprocesseur include path.
  3. Si vous devez ajouter un chemin de recherche général pour make, utilisez:
VPATH = my_dir_to_search

... ou encore plus spécifique

vpath %.c src
vpath %.h include

make utilise VPATH comme chemin de recherche général, utilisez donc avec prudence. Si un fichier existe à plusieurs emplacements répertoriés dans VPATH, make prendra la première occurrence de la liste.

67 Hz
la source