CFLAGS против CPPFLAGS

104

Я понимаю, что CFLAGS (или CXXFLAGS для C ++) предназначены для компилятора, тогда как CPPFLAGS используется препроцессором.

Но я до сих пор не понимаю разницы.

Мне нужно указать путь включения для файла заголовка, который включается с помощью #include - поскольку #include - это директива препроцессора, препроцессор (CPPFLAGS) - единственное, что меня волнует?

При каких обстоятельствах мне нужно предоставить компилятору дополнительный путь включения?

В общем, если препроцессор находит и включает необходимые файлы заголовков, зачем ему когда-либо сообщать о дополнительных подключаемых каталогах? Какая вообще польза от CFLAGS?

(В моем случае я действительно обнаружил, что ОБА из них позволяют мне компилировать мою программу, что добавляет путаницы ... Я могу использовать CFLAGS ИЛИ CPPFLAGS для достижения моей цели (по крайней мере, в контексте autoconf). Что дает?)

EBM
источник
2
возможный дубликат stackoverflow.com/questions/495598/…
Майкл Мрозек

Ответы:

156

Неявное правило make для компиляции программы на C:

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

где $()синтаксис расширяет переменные. Поскольку оба CPPFLAGSи CFLAGSиспользуются в вызове компилятора, который вы используете для определения путей включения, это дело личного вкуса. Например, если foo.cэто файл в текущем каталоге

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

оба будут вызывать ваш компилятор точно так же, а именно

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

Разница между ними проявляется, когда у вас есть несколько языков, которым нужен один и тот же путь включения, например, если вы bar.cppпопробуете

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

тогда сборники будут

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

поскольку неявное правило C ++ также использует CPPFLAGSпеременную.

Эта разница дает хорошее руководство , для которого нужно использовать - если вы хотите, чтобы флаг будет использоваться для всех языков положить его в CPPFLAGS, если это для конкретного языка положить его в CFLAGS, и CXXFLAGSт.д. Примерами последнего типа включают в себя стандартные соответствия или предупреждающие флаги - вы бы не хотели переходить -std=c99на свой компилятор C ++!

Затем вы можете получить что-то подобное в своем make-файле

CPPFLAGS=-I/usr/include
CFLAGS=-std=c99
CXXFLAGS=-Weffc++
Скотт Уэльс
источник
1
Обратите внимание, что вы не можете запускать автономное cppиспользование CPPFLAGSи ожидать какого-либо разумного результата, поскольку -std=c99влияет на то, какие символы определены (особенно вместо макросов тестирования функций). Вместо этого вам нужно $(CC) $(CPPFLAGS) $(CFLAGS) -E.
Jed
10

CPPFLAGSМакрос является один использовать для указания #includeкаталогов.

Оба CPPFLAGSи CFLAGSработают в вашем случае, потому что makeправило (1) объединяет предварительную обработку и компиляцию в одной команде (поэтому в команде используются оба макроса).

Вам не нужно указывать .в качестве включаемого каталога, если вы используете форму #include "...". Вам также не нужно указывать стандартный каталог include компилятора. Вам необходимо указать все остальные подключаемые каталоги.

Стив Эммерсон
источник
Это имеет больше смысла, но я все еще не понимаю, что делает CFLAGS. Если, как вы, кажется, подразумеваете, компиляция в более сложных проектах выполняется на отдельном этапе от предварительной обработки, будет ли предварительная обработка успешной, но компиляция завершится ошибкой, если CFLAGS не добавит те же пути, которые CPPFLAGS добавил для препроцессора? Думаю, я не понимаю, что компилятор делает с путями включения, если препроцессор уже обработал директивы #include?
EBM
4
@EB Если вы компилируете предварительно обработанные файлы, тогда пути включения не нужны - необходимые заголовки уже были добавлены в предварительно обработанный источник (посмотрите на вывод, когда вы запускаете gcc -Eфайл - нет #includes). Большинство современных компиляторов объединяют этапы предварительной обработки и компиляции, поэтому вам не нужно об этом беспокоиться.
Скотт Уэльс,
0

Чтобы добавить к тем, кто упомянул неявные правила, лучше всего посмотреть, что make определил неявно и для вашего env, используя:

make -p

Например:

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

который расширяет

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

Это также распечатает # environmentданные. Здесь вы найдете путь включения GCC среди другой полезной информации.

C_INCLUDE_PATH=/usr/include

В make, когда дело доходит до поиска, путей много, свет один ... или что-то в этом роде.

  1. C_INCLUDE_PATH общесистемный, установите его в оболочке *.rc .
  2. $(CPPFLAGS) это путь включения препроцессора.
  3. Если вам нужно добавить общий путь поиска для make, используйте:
VPATH = my_dir_to_search

... или даже более конкретно

vpath %.c src
vpath %.h include

make использует VPATH как общий путь поиска, поэтому используйте его с осторожностью. Если файл существует более чем в одном месте, указанном в VPATH, make возьмет первое вхождение в списке.

67 Гц
источник