CFLAGS vs CPPFLAGS

103

Eu entendo que CFLAGS (ou CXXFLAGS para C ++) são para o compilador, enquanto CPPFLAGS é usado pelo pré-processador.

Mas ainda não entendo a diferença.

Preciso especificar um caminho de inclusão para um arquivo de cabeçalho que está incluído com #include - porque #include é uma diretiva de pré-processador, o pré-processador (CPPFLAGS) é a única coisa que me interessa?

Sob quais circunstâncias eu preciso fornecer ao compilador um caminho de inclusão extra?

Em geral, se o pré-processador encontra e inclui os arquivos de cabeçalho necessários, por que ele precisa ser informado sobre os diretórios de inclusão extras? Para que serve CFLAGS afinal?

(No meu caso, na verdade descobri que AMBOS permitem compilar meu programa, o que aumenta a confusão ... Posso usar CFLAGS OU CPPFLAGS para atingir meu objetivo (no contexto do autoconf pelo menos). O que dá?)

EBM
fonte
2
possível duplicata de stackoverflow.com/questions/495598/…
Michael Mrozek

Respostas:

153

A regra implícita do make para compilar um programa C é

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

onde a $()sintaxe expande as variáveis. Como CPPFLAGSe CFLAGSsão usados ​​na chamada do compilador, o que você usa para definir caminhos de inclusão é uma questão de gosto pessoal. Por exemplo, se foo.cé um arquivo no diretório atual

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

ambos chamarão seu compilador exatamente da mesma maneira, a saber

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

A diferença entre os dois entra em jogo quando você tem vários idiomas que precisam do mesmo caminho de inclusão, por exemplo, se você tiver bar.cpp, tente

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

então as compilações serão

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

já que a regra implícita do C ++ também usa a CPPFLAGSvariável.

Essa diferença dá-lhe um guia bom para qual usar - se quiser que o pavilhão a ser utilizado para todos os idiomas colocá-lo em CPPFLAGS, se é para um idioma específico colocá-lo em CFLAGS, CXXFLAGSetc. Exemplos do último tipo incluem o cumprimento das normas ou bandeiras de aviso - você não gostaria de passar -std=c99para o seu compilador C ++!

Você pode então acabar com algo assim no seu makefile

CPPFLAGS=-I/usr/include
CFLAGS=-std=c99
CXXFLAGS=-Weffc++
Scott Wales
fonte
1
Observe que você não pode executar autônomo cppusando CPPFLAGSe esperar qualquer resultado razoável porque -std=c99afeta quais símbolos são definidos (especialmente em vez de macros de teste de recurso). Em vez disso, você precisa $(CC) $(CPPFLAGS) $(CFLAGS) -E.
Jed
10

A CPPFLAGSmacro é usada para especificar #includediretórios.

Ambos CPPFLAGSe CFLAGStrabalho no seu caso porque o make(1) regra combina pré-processamento e compilação em um comando (para que ambos os macros são utilizados no comando).

Você não precisa especificar .como um diretório de inclusão se usar o formulário #include "...". Você também não precisa especificar o diretório de inclusão do compilador padrão. Você precisa especificar todos os outros diretórios de inclusão.

Steve Emmerson
fonte
Isso faz mais sentido, mas ainda não vejo o que CFLAGS faz, então. Se, como você parece sugerir, a compilação em projetos mais complexos é feita em uma etapa separada do pré-processamento, o pré-processamento será bem-sucedido, mas a compilação falhará se CFLAGS não adicionar os mesmos caminhos que CPPFLAGS adicionou para o pré-processador? Acho que não entendo o que o compilador faz com caminhos de inclusão se o pré-processador já processou as diretivas #include.
EBM
4
@EB Se você estiver compilando arquivos pré-processados, então incluir caminhos são desnecessários - os cabeçalhos necessários já foram adicionados à fonte pré-processada (dê uma olhada na saída quando você executa gcc -Eem um arquivo - não há #includes). A maioria dos compiladores modernos combina as etapas de pré-processamento e compilação, então você não precisa se preocupar com isso.
Scott Wales
0

Para adicionar àqueles que mencionaram as regras implícitas, é melhor ver o que o make definiu implicitamente e para o seu ambiente usando:

make -p

Por exemplo:

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

que expande

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

Isso também imprimirá # environmentdados. Aqui, você encontrará o caminho de inclusão do GCC, entre outras informações úteis.

C_INCLUDE_PATH=/usr/include

No make, quando se trata de pesquisar, os caminhos são muitos, a luz é uma ... ou algo nesse sentido.

  1. C_INCLUDE_PATHé todo o sistema, defini-lo em seus da Shell *.rc.
  2. $(CPPFLAGS) é para o caminho de inclusão do pré-processador.
  3. Se você precisar adicionar um caminho de pesquisa geral para make, use:
VPATH = my_dir_to_search

... ou ainda mais específico

vpath %.c src
vpath %.h include

make usa VPATH como um caminho de busca geral, então use com cautela. Se um arquivo existir em mais de um local listado no VPATH, o make tomará a primeira ocorrência na lista.

67hz
fonte