CFLAGS vs CPPFLAGS

103

Ich verstehe, dass CFLAGS (oder CXXFLAGS für C ++) für den Compiler sind, während CPPFLAGS vom Präprozessor verwendet wird.

Aber ich verstehe den Unterschied immer noch nicht.

Ich muss einen Include-Pfad für eine Header-Datei angeben, die in #include enthalten ist. Ist #include eine Präprozessor-Direktive? Ist der Präprozessor (CPPFLAGS) das einzige, was mich interessiert?

Unter welchen Umständen muss ich dem Compiler einen zusätzlichen Include-Pfad geben?

Wenn der Präprozessor benötigte Header-Dateien findet und einschließt, warum muss er dann im Allgemeinen über zusätzliche Include-Verzeichnisse informiert werden? Was nützt CFLAGS überhaupt?

(In meinem Fall habe ich tatsächlich festgestellt, dass BEIDE davon es mir ermöglichen, mein Programm zu kompilieren, was die Verwirrung noch verstärkt ... Ich kann CFLAGS ODER CPPFLAGS verwenden, um mein Ziel zu erreichen (zumindest im Autoconf-Kontext). Was gibt es?)

EBM
quelle
2
Mögliches Duplikat von stackoverflow.com/questions/495598/…
Michael Mrozek

Antworten:

153

Die implizite make-Regel zum Kompilieren eines C-Programms lautet

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

Dabei $()erweitert die Syntax die Variablen. Da beide CPPFLAGSund CFLAGSim Compiler-Aufruf verwendet werden, den Sie zum Definieren von Include-Pfaden verwenden, ist dies eine Frage des persönlichen Geschmacks. Zum Beispiel, wenn foo.csich eine Datei im aktuellen Verzeichnis befindet

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

beide rufen Ihren Compiler genauso auf, nämlich

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

Der Unterschied zwischen den beiden kommt ins Spiel, wenn Sie mehrere Sprachen haben, die denselben Include-Pfad benötigen, beispielsweise wenn Sie es bar.cppdann versucht haben

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

dann werden die Zusammenstellungen sein

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

als implizite C ++ - Regel wird auch die CPPFLAGSVariable verwendet.

Dieser Unterschied bietet Ihnen eine gute Anleitung für die Verwendung - wenn Sie möchten, dass das Flag für alle Sprachen verwendet wird, setzen Sie es ein CPPFLAGS, wenn es für eine bestimmte Sprache verwendet CFLAGSwird CXXFLAGSusw. Beispiele für den letzteren Typ sind Standard-Konformitäts- oder Warnflags - Sie möchten nicht -std=c99an Ihren C ++ - Compiler übergeben!

Sie könnten dann so etwas in Ihrem Makefile haben

CPPFLAGS=-I/usr/include
CFLAGS=-std=c99
CXXFLAGS=-Weffc++
Scott Wales
quelle
1
Beachten Sie, dass Sie nicht ausführen können Stand-alone cppmit CPPFLAGSjedem vernünftigen Ergebnis und erwarten , weil -std=c99beeinflusst , welche Symbole (insbesondere anstelle von Feature - Test - Makros) definiert sind. Stattdessen brauchen Sie $(CC) $(CPPFLAGS) $(CFLAGS) -E.
Jed
10

Das CPPFLAGSMakro ist dasjenige, mit dem #includeVerzeichnisse angegeben werden.

Beides CPPFLAGSund CFLAGSfunktionieren in Ihrem Fall, da die make(1) -Regel sowohl die Vorverarbeitung als auch das Kompilieren in einem Befehl kombiniert (daher werden beide Makros im Befehl verwendet).

Sie müssen kein .Include-Verzeichnis angeben, wenn Sie das Formular verwenden #include "...". Sie müssen auch nicht das Standard-Compiler-Include-Verzeichnis angeben. Sie müssen alle anderen Include-Verzeichnisse angeben.

Steve Emmerson
quelle
Das macht mehr Sinn, aber ich sehe immer noch nicht, was CFLAGS dann macht. Wenn, wie Sie zu implizieren scheinen, die Kompilierung in komplexeren Projekten in einem von der Vorverarbeitung getrennten Schritt erfolgt, ist die Vorverarbeitung erfolgreich, die Kompilierung schlägt jedoch fehl, wenn CFLAGS nicht dieselben Pfade hinzufügt, die CPPFLAGS für den Präprozessor hinzugefügt hat? Ich glaube, ich verstehe nicht, was der Compiler mit Include-Pfaden macht, wenn der Präprozessor die # include-Direktiven bereits verarbeitet hat.
EBM
4
@EB Wenn Sie vorverarbeitete Dateien kompilieren, sind Include-Pfade nicht erforderlich - die erforderlichen Header wurden bereits zur vorverarbeiteten Quelle hinzugefügt (Sehen Sie sich die Ausgabe an, wenn Sie gcc -Eeine Datei ausführen - es gibt keine #includes). Die meisten modernen Compiler kombinieren die Vorverarbeitungs- und Kompilierungsschritte, sodass Sie sich darüber keine Gedanken machen müssen.
Scott Wales
0

Um denjenigen hinzuzufügen, die die impliziten Regeln erwähnt haben, ist es am besten zu sehen, welche Marke implizit und für Ihre Umgebung definiert hat, indem Sie Folgendes verwenden:

make -p

Zum Beispiel:

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

was sich ausdehnt

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

Dadurch werden auch # environmentDaten gedruckt . Hier finden Sie unter anderem den Include-Pfad des GCC.

C_INCLUDE_PATH=/usr/include

Wenn es um die Suche geht, gibt es viele Wege, das Licht ist einer ... oder etwas in diesem Sinne.

  1. C_INCLUDE_PATHist systemweit, setzen Sie es in Ihre Shell *.rc.
  2. $(CPPFLAGS) ist für den Präprozessor-Include-Pfad.
  3. Wenn Sie einen allgemeinen Suchpfad für make hinzufügen müssen, verwenden Sie:
VPATH = my_dir_to_search

... oder noch genauer

vpath %.c src
vpath %.h include

make verwendet VPATH als allgemeinen Suchpfad. Gehen Sie daher vorsichtig vor. Wenn eine Datei an mehr als einem in VPATH aufgelisteten Speicherort vorhanden ist, wird make zum ersten Mal in der Liste aufgeführt.

67 Hz
quelle