Introdução ao Makefile

Prefácio

Este artigo é uma nota de estudo e todo o conteúdo vem da Internet.

A compilação no Android usa basicamente a sintaxe Makefile. Precisamos ter um conhecimento básico da sintaxe de compilação. O comando Make básico e a sintaxe do Makefile são apresentados abaixo.

texto

1. Introdução aos conceitos básicos de métodos de compilação

Antes de apresentar, vamos entender brevemente algumas ferramentas de compilação

1,1 gcc

gcc é a GUN Compiler Collection (conjunto de compiladores GUN), que pode ser simplesmente considerada um compilador. O gcc pode compilar muitas linguagens de programação, incluindo C, C++, Objective-C, Fortran, Java, etc.

Quando nosso programa possui apenas um arquivo fonte, podemos usar o comando gcc para compilá-lo. Porém, se nosso programa contém muitos arquivos fonte e usamos o comando gcc para compilá-los um por um, descobriremos que é fácil ficar confuso e a carga de trabalho é pesada. Em resposta a essa necessidade, surgiu a ferramenta make.

1.2 fazer

A ferramenta make pode ser considerada uma ferramenta inteligente de processamento em lote. A ferramenta make em si não tem a função de compilar e vincular. Em vez disso, ela compila e vincula em lote, chamando os comandos especificados no arquivo makefile.

1.3 makefile

Os comandos e regras de compilação são definidos no makefile, e a ferramenta make compila e vincula com base nos comandos do makefile.

Em um projeto, existem muitos arquivos fonte, que são armazenados em vários diretórios de acordo com tipo, função e módulo. Eles precisam ser compilados de acordo com uma determinada ordem e regras. Nesse caso, é necessário o makefile.

O makefile define uma série de regras para especificar quais arquivos precisam ser compilados primeiro, quais arquivos precisam ser recompilados, como vincular e outras operações.

Makefile é uma "compilação automatizada", informando ao comando make como compilar e vincular.

makefile é o script de configuração da ferramenta make. Por padrão, o comando make irá procurar o arquivo no diretório atual (procurando por arquivos chamados "GUNmakefile", "makefile" e "Makefile" em ordem).

Makefiles podem ser concluídos manualmente em alguns projetos simples, mas quando o projeto é muito grande, escrever o makefile à mão também é muito problemático, e quando a plataforma é alterada, o makefile precisa ser modificado novamente. Neste momento, a ferramenta cmake aparece.

1,4 cm

cmake é uma poderosa ferramenta de configuração automatizada, de código aberto e multiplataforma, que constrói um sistema de compilação lendo as regras no arquivo de script CMakeLists.txt.

cmake usa CMakeLists.txt como arquivo de script para construir regras de compilação por padrão, assim como make usa arquivos makefile por padrão.

1,5 nmake

nmake é um comando incluído no Microsoft Visual Studio e requer a instalação do VS. Na verdade, pode-se dizer que é equivalente ao make do Linux.

2. Formato de arquivo Makefile

O arquivo Makefile registra as regras de construção do projeto.

O arquivo Makefile conterá: regras de exibição, regras implícitas, definições de variáveis, conhecimento do arquivo e comentários.

2.1 Visão geral

O arquivo Makefile consiste em uma série de regras. O formato de cada regra é o seguinte:

<target> : <prerequisites>
[tab]	<commands>

解释
<目标> : <前置条件>
tab 键起首 <命令>
--------------------------------------------------------------------------------------------------------------------------------
或者 

<target> : <prerequisites> ; <commonds>

解释
<目标> : <前置条件> ; <命令>

"Destino" é obrigatório e não pode ser omitido; "pré-condição" e "comando" são opcionais, mas pelo menos um deles deve existir.

Se os pré-requisitos e os pontos comuns estiverem na mesma linha, eles precisam ser separados por ";". Se os pré-requisitos e os commonds não estiverem na mesma linha, os commonds precisarão começar com a tecla tab.

Cada regra comanda duas coisas: quais são os pré-requisitos para construir o alvo e como construí-lo. Os componentes deste formato são explicados abaixo.

2.2 alvo alvo

target é o arquivo de destino, que pode ser um ObjectFile, um arquivo executável ou uma nota; se houver vários arquivos, eles podem ser separados por espaços; curingas podem ser usados.

Uma meta constitui uma regra. O alvo é normalmente um nome de ficheiro,indicando o objecto que o comando make pretende construir.O ​​alvo pode ser um nome de ficheiro ou vários nomes de ficheiros,separados por espaços. Além do nome do arquivo, o destino também pode ser o nome de uma operação, chamada de "alvo falso".

clean:
	rm *.o

A regra makefile acima define um comando clean. Não é um nome de arquivo, mas o nome de uma operação, que é um "pseudo alvo" e é usada para excluir arquivos .o.

make clean

No entanto, se houver um arquivo chamado clean no diretório atual. Então este alvo não será executado, pois a ferramenta make descobre que o arquivo limpo já existe, e pensa que não há necessidade de reconstruir, e as regras acima não serão executadas.

Para evitar esta situação, você pode declarar explicitamente limpo como um "pseudo alvo", escrito da seguinte forma:

.PHONY: clean
clean:
	rm *.o temp

Após declarar clean como um "pseudo alvo", make não verificará se existe um arquivo chamado clean, mas executará o comando correspondente sempre que for executado. Existem muitos nomes de destino de conteúdo, como .PHONY. Você pode consultar este link [Alvo especial (produção GNU)]

alvos integrados do makefile significado
.FALSO Pseudo alvo. Suas regras serão executadas incondicionalmente.
.SUFIXOS Verifique a lista de sufixos de regras de sufixos
.PADRÃO Quando nenhum destino é especificado, as regras desta configuração são usadas
.PRECIOSO Este destino do item de configuração não excluirá o alvo se ele for eliminado ou interrompido durante a execução
.INTERMEDIÁRIO O alvo deste item de configuração é considerado um arquivo intermediário
.NÃO INTERMEDIÁRIO As condições prévias para o destino deste item de configuração nunca são consideradas arquivos intermediários
.SECUNDÁRIO Os objetos deste item de configuração são tratados como arquivos intermediários, sabendo que nunca são excluídos automaticamente. .SECONDART pode ser utilizado para evitar reconstrução redundante em determinadas situações anormais.
.SECONDEXPANSION Se mencionado como alvo em qualquer lugar de um makefile, todas as listas de pré-condições definidas após sua ocorrência serão expandidas novamente após todos os makefiles terem sido lidos.
.DELETE_ON_ERROR Se o destino deste item de configuração sair com um status diferente de zero, o destino da regra será excluído.
.IGNORAR O objetivo deste item de configuração é ignorar erros que ocorrem ao executar receitas para estes arquivos específicos.
.LOW_RESOLUTION_TIME O alvo deste item de configuração.Se estes ficheiros foram criados por comandos com carimbos temporais de baixa resolução,a receita do alvo será ignorada.
.SILENCIOSO O objetivo deste item de configuração é não imprimir as receitas utilizadas para recriar esses arquivos específicos antes de serem executados.
.EXPORT_ALL_VARIABLES O objectivo deste item de configuração é exportar todas as variáveis ​​para o processo filho por defeito.Esta é uma alternativa à utilização sem argumentos.
.NOTPARALLEL Alvos deste item de configuração, todos os alvos nesta chamada serão executados em série, mesmo que as opções sejam fornecidas
.ONESHELL O alvo deste item de configuração, ao construir o alvo, todas as linhas da receita serão fornecidas para uma única invocação do shell, mas ao invés de chamar cada linha individualmente
.POSIX O objetivo deste item de configuração é analisar o makefile e executá-lo em modo compatível com POSIX

Se nenhum destino for especificado quando o comando make for executado, o primeiro destino do arquivo Makefile será executado por padrão.

2.3 Pré-requisitos Pré-requisitos

pré-requisitos são arquivos de dependência, arquivos ou outros destinos necessários para gerar esse destino.

Uma pré-condição geralmente é um conjunto de nomes de arquivos separados por espaços. "Pré-condição" especifica o critério para saber se o "destino" deve ser reconstruído, desde que um "arquivo de pré-requisito" não exista ou tenha sido atualizado (o carimbo de data/hora da última modificação do arquivo de pré-requisito é mais recente que o carimbo de data/hora do destino), A “meta” precisa ser reestruturada.

result.txt : source.txt
	cp souce.txt result.txt

No código acima, a pré-condição para construir result.txt é source.txt. Se source.txt já existir no diretório atual, make result.txt poderá ser executado normalmente, caso contrário, você deverá escrever outra regra para gerar source.txt.

source.txt:
	echo "this is the source" > source.txt

No código acima, não há pré-condições após source.txt, o que significa que não tem nada a ver com outros arquivos.Enquanto este arquivo ainda não existir, ele será gerado toda vez que make source.txt for chamado.

make result.txt
make result.txt

Execute o comando acima duas vezes consecutivas para criar result.txt. Na primeira execução, source.txt será criado primeiro e depois result.txt será criado. Durante a segunda execução, make descobre que source.txt não foi alterado (o carimbo de data/hora não é posterior a result.txt), portanto, não executará nenhuma operação e result.txt não será regenerado.

Se você precisar gerar vários arquivos, o seguinte método de escrita é frequentemente usado

source : file1 file2 file3

No código acima, source é um pseudo destino, com apenas três arquivos de prefixo e nenhum comando correspondente.

make source

Depois de executar make source, três arquivos fil1, file2 e file3 serão gerados de uma só vez, o que é muito mais conveniente do que o método de escrita a seguir.

make file1
make file2
make file3

2.4 comando comando

commond é o comando que make precisa ser executado.

Os comandos indicam como atualizar o arquivo de destino e consistem em uma ou mais linhas de comandos shell. É uma instrução específica para construir um “target”, e o resultado de sua operação geralmente é gerar um arquivo alvo.

Deve haver uma tecla TAB antes de cada linha de comando. Se desejar usar outras chaves, você pode usar a variável interna .RECIPEPREFIX instrução.

.RECIPEPREFIX = >
all:
> echo Hello, World

O código acima usa .RECIPEPREFIX para especificar que o sinal de maior que (>) substitui a tecla tab, de modo que o início de cada linha de comando se torna o sinal de maior que em vez da tecla tab. Deve-se observar que cada linha de comando é executada em um shell separado e não há relacionamento de herança entre esses shells.

var-lost:
	export foo=bar
	echo "foo=[$$foo]"

Após o código acima ser executado usando make var-lost, o valor de foo não pode ser obtido porque as duas linhas de comandos são executadas em processos diferentes. Uma solução é escrever os dois comandos em uma linha, separados por ponto e vírgula.

var-kept:
	export foo=bar; echo "foo=[$$foo]"

Outra solução é escapar do caractere de nova linha com uma barra invertida.

var-kept:
	export foo=bar; \
	echo "foo=[$$foo]"

O último método é adicionar o comando .ONESHELL:.

.ONESHELL:
var-kept:
	export foo=bar;
	echo "foo=[$$foo]"

3. Sintaxe do arquivo Makefile

3.1 Notas

Os comentários são representados por # na sintaxe do Makefile.

# 这是注释
result.txt : source.txt
	# 这是注释
	cp source.txt result.txt # 这是注释

3.2 eco ecoando

Em circunstâncias normais, make imprimirá cada comando antes de executá-lo. Isso é chamado de eco.

Ao adicionar o símbolo @ antes da primeira linha de comandos, você pode desligar o eco para que o comando não seja impresso.

.ONESHELL:
var-kept:
	# 这是注释
	export foo="foood"
	echo "foo=[$$foo]"
	export foo2=$$foo"dd"
	echo "foo2=[$$foo2]"

Resultados de saída

make var-kept

# 这是注释
export foo="foood"
echo "foo=[$$foo]"
export foo2=$$foo"dd"
echo "foo2=[$$foo2]"

foo=[foood]
foo2=[foooddd]

Os resultados de saída geram todos os comandos, até mesmo os arquivos de comentários.

Como desligar o eco

.ONESHELL:
var-kept:
	@# 这是注释
	export foo="foood"
	echo "foo=[$$foo]"
	export foo2=$$foo"dd"
	echo "foo2=[$$foo2]"

Resultados de saída

make var-kept

foo=[foood]
foo2=[foooddd]

3.3 Curingas

O curinga é usado para especificar um conjunto de nomes de arquivos que atendem às condições. Os caracteres curinga do Makefile são consistentes com o Bash, incluindo principalmente asterisco (*), ponto de interrogação (?) e […]. Por exemplo, **.o representa todos os arquivos com o sufixo o.

clean:
	rm -rf *.o

3.4 Correspondência de padrões

O comando Make permite a correspondência de nomes de arquivos semelhantes às operações regulares. O principal caractere de correspondência usado é %. Por exemplo, supondo que haja dois arquivos de código-fonte f1.c e f2.c no diretório atual, eles precisam ser compilados em objetos correspondentes.documento.

%.o:%.c

É equivalente à seguinte escrita

f1.o:f1.c
f2.o:f2.c

Usando o caractere correspondente %, um grande número de arquivos do mesmo tipo pode ser construído usando apenas uma regra.

3.5 Variáveis ​​e configuradores

Makefile permite variáveis ​​personalizadas usando o sinal de igual.

txt = Hello World
test:
	@echo $(txt)

No código acima, a variável txt é igual a Hello World. Ao chamar, a variável precisa ser colocada em $().

Ao chamar uma variável Shell, você precisa adicionar um cifrão antes do cifrão. Isso ocorre porque o comando Make escapará do cifrão.

test:
	@echo $$HOME

Às vezes, o valor de uma variável pode apontar para outra variável.

v1 = $(v2)

No código acima, o valor da variável v1 é outra variável v2. Neste momento, surge uma questão: se o valor de v1 é expandido em tempo de definição (expansão estática) ou em tempo de execução (expansão dinâmica). Se o valor de v2 for dinâmico, os resultados dos dois métodos de escalonamento poderão diferir significativamente.

Para resolver problemas semelhantes, Makefile fornece um total de quatro operadores de atribuição (=, :=, ?=, +=)

# 在执行时扩展,允许递归扩展
VARIABLE = value

# 在定义时扩展
VARIABLE := value

#只有在该变量为空时才设置值
VARIABLE ?= value

#将值追加到变量的尾端
VARIABLE += value

3.6 Variáveis ​​Implícitas

O comando Make fornece uma série de variáveis ​​incorporadas, por exemplo, ( C C ) aponta para o compilador usado atualmente, (CC) aponta para o compilador usado atualmente, < /span>(CC) aponta para o compilador usado atualmente, (MAKE) aponta para a ferramenta MAKE usada atualmente. Isto é principalmente para compatibilidade entre plataformas.

output:
	$(CC) -o output input.c

3.7 Variáveis ​​Automáticas

O comando Make fornece algumas variáveis ​​automáticas cujos valores estão relacionados à regra atual. Existem principalmente os seguintes

3.7.1$@

" @ " refere-se ao destino atual, que é o destino atualmente criado pelo comando Make. Por exemplo, o "@" de make foo refere-se ao alvo atual, que é o alvo atualmente construído pelo comando Make. Por exemplo, o "@" de make foo@”Estudar tomae mego, trabalho éMak eInstruções sobre a construção atual. a>@" Taxa de emprego foo."alvooo

3.7.2 $<

" < " refere-se à primeira pré-condição. Por exemplo, se a regra for t : p 1 p 2 , então " <" refere-se à primeira pré-condição. Por exemplo, se a regra for t: p1 p2 , então " <" refere-se à primeira pré-condição. Por exemplo, a regra ét:p1p2,nanao<” Taxa de emprego p1.

3,7,3$?

" ?" refere-se a todas as pré-condições que são mais recentes que o destino, separadas por espaços. Por exemplo, a regra é t : p 1 p 2 , onde o carimbo de data/hora de p 2 é mais recente que t , então "?" refere-se a todas as pré-condições que são mais recentes que o destino, separadas por espaços. Por exemplo, a regra é t : p1 p2, onde o carimbo de data/hora de p2 é mais recente que t, então " ?" refere-se a todas as pré-condições que são mais recentes que o destino, separadas por espaços. Por exemplo, a regra ét:p1p2, dentro?” Taxa de emprego p2. novo 、Nanatconversão de tempo2p

3.7.4$^

" " refere-se a todas as pré-condições, separadas por espaços. Por exemplo, t : p 1 p 2 , então " ^" refere-se a todas as pré-condições, separadas por espaços. Por exemplo, t : p1 p2 , então " " refere-se a todas as pré-condições, separadas por espaços. Por exemplot:p1p2,nanao^” Taxa de emprego p1 p2.

3,7,5$*

∗ " refere-se ao caractere correspondente *" refere-se à parte correspondente ao caractere correspondente %, por exemplo, % corresponde a f1 em f1.txt, " "arranjo digital*” exibição de posição f1.

3.7.6 $(@D) e $(@F)

$(@D) e $(@F) apontam para o nome do diretório e o nome do arquivo de @ respectivamente. Por exemplo, @ nomes de diretórios e nomes de arquivos. Por exemplo, O nome do diretório e o nome do arquivo de @. Por exemplo, @ é src/input.c, então o valor de ( @ D ) é s r c , o valor de (@D) é src, (@D)の值为(@F) の值为 input.c. src

3.7.7 $(<D) e $(<F)

$(<D) e $(<F) apontam para o nome do diretório e o nome do arquivo de $< respectivamente.

dest/%.txt: src/%.txt
	@[-d dest] || mkdir dest
	cp $< $@

O código acima copia o txt do diretório src para o diretório dest. Primeiro, ele determina se o diretório dest existe. Se não existir, crie um novo e, em seguida, " < " refere-se ao arquivo de prefixo (s r c / <" refere-se ao arquivo de prefixo (src/%.txt), " <"Caixa de sentença com prefixo de dedo(src / @” O item de índice (dest/%.txt).

3.8 Julgamento e looping

julgamento

# 下面判断当前编译器是否是 gcc,然后指定不同的库文件
ifeq ($(CC),gcc)
	libs=$(libs_for_gcc)
else
	libs=$(normal_libs)
endif

ciclo

# 下面循环遍历 LIST 中的数据,然后输出
LIST = one two three
all:
	for i in $(LIST): do \
		echo $$i; \
	done

# 等同于
all:
	for i in one two three: do \
		echo $i; \
	done

# 运行结果
one
two
three

3.9 Funções

Makefile também pode usar funções, o formato é o seguinte

$(function arguments)
# 或者
${function arguments}

Makefile fornece muitas funções integradas que podem ser chamadas. Aqui estão alguns exemplos de funções integradas comumente usadas.

3.9.1 funções de shell

função shell é usada para executar comandos shell

srcfiles := $(shell echo src/{00..99}.txt)
3.9.2 função curinga

A função curinga é usada para substituir caracteres curinga Bash no Makefile.

srcfiles := $(wildcard src/*.txt)
3.9.3 subfunção

A função subst é usada para substituição de texto, o formato é o seguinte

$(subst from, to ,text)

O exemplo a seguir substitui a string "feet on the street" por "fEEt on the strEEt".

$(subst ee,EE,feet on the street)

Aqui está um exemplo um pouco mais complexo

comma:=,
empty:=
# space 变量用两个空变量作为表示符,当中是一个空格
space:=$(empty) $(empty)
foo:= a b c
bar:= $(subst $(space),$(comma),$(foo))
# bar is now 'a,b,c'.
3.9.4 função patsubst

A função patsubst é usada para substituição de correspondência de padrões. O formato é o seguinte

$(patsubst parrern,replacement,text)

O exemplo a seguir substitui o nome do arquivo "x.c.c bar.c" por "x.c.o bar.o".

$(patsubst %.c,%.o,x.c.c,bar.c)
3.9.5 Substituir nome do sufixo

O método de escrita para substituir a função do nome do sufixo é: nome da variável + dois pontos + regra de substituição do nome do sufixo. Na verdade, é uma forma abreviada da função patsubst.

min:$(OUTPUT:.js=.min.js)

O significado do código acima é substituir todos os nomes de sufixos .js na variável OUTPUT por .min.js

4. Exemplo de Makefile

4.1 Execute múltiplos objetivos

.PHONY: cleanall cleanobj cleandiff

cleanall : cleanobj cleandiff
	rm program

cleanobj :
	rm *.o

cleandiff :
	rm *.diff

O código acima pode chamar diferentes destinos para excluir arquivos com sufixos diferentes ou pode chamar um destino (cleanall) para excluir todos os arquivos de um tipo especificado.

4.2 Compilar projeto de linguagem C

edit : main.o kbd.o command.o display.o
	cc -o edit main.o kbd.o command.o display.o

main.o : main.c defs.h
	cc -c main.c

kbd.o : kbd.c defs.h command.h
	cc -c command.c

display.o : display.c defs.h
	cc -c display.c

clean :
	rm edit main.o kbd.o command.o display.o

.PHONY: edit clean

おすすめ

転載: blog.csdn.net/Yang_Mao_Shan/article/details/131696714