Programação de Sistemas Make reconstrução de aplicações Programação de Sistemas Make : 1/17 Objectivos Nos projectos de desenvolvimento de software são frequentes as ligações de derivação entre produtos. Exemplo: na fase de codificação existe dependência hierárquica entre programas fonte e executáveis. Ligação de derivação entre produtos implica ordenação temporal entre as datas de criação dos produtos (ex: os programas devem ser compilados depois de editados e a edição de ligações ( link ) deve ser feita em data posterior à compilação. Programação de Sistemas Make : 2/17
Formato makefile O make gera um programa coerente, executando apenas os comandos necessários sobre os ficheiros alterados. Os ficheiros envolvidos e as regras de construção são indicados no ficheiro makefile (ou Makefile). (nome-fich-alvo)+ : (nome-fich-dependentes)* \n ( \t comando-unix \n )* linha-terminação A primeira regra de construção deve gerar o ficheiro final (programa). Linha de terminação do comando iniciada por quaisquer caracteres diferentes de \t e # (usualmente uma linha em branco). Comentários iniciados # até ao fim da linha. Comando, ou lista dos ficheiros dependentes, continua na linha seguinte se na última coluna for colocado \. Programação de Sistemas Make : 3/17 Reconstrução das dependências (1) Comando make reconstrói, em profundidade ( depthfirst ) o ficheiro alvo. 1. A pesquisa da coerência temporal feita da esquerda para a direita, na lista de ficheiros dependentes. Se a lista for vazia (ex: usual na regra clean ), o make assume que a dependência é incoerente. 2. Se um ficheiro dependente for gerado a partir de outro (ex: fich.o gerado a partir de fich.c) a pesquisa da coerência temporal é suspensa e a reconstrução prossegue descendo na árvore de dependências. Se algum ficheiro dependente tiver data posterior ao ficheiro alvo, a ferramenta executa os comandos indicados nas linhas seguintes até à linha de terminação. Programação de Sistemas Make : 4/17
Reconstrução das dependências (2) Por omissão, o alvo reconstruído é o primeiro indicado na lista de regras. Se for necessário reconstruir outro alvo, ele deve ser indicado na linha de comando. Exemplo: # outros alvos clean: rm prg *.o # limpeza de ficheiros inúteis desencadeada por comando make clean Programação de Sistemas Make : 5/17 Reconstrução das dependências (3) Seja o seguinte ficheiro makefile prg: aux.o main.o gcc -o prg aux.o main.o prg aux.o: aux.c defs.h gcc -c aux.c aux.o main.o main.o: main.c gcc -c main.c clean: rm prg *.o aux.c defs.h main.c Árvore de dependências Programação de Sistemas Make : 6/17
Reconstrução das dependências (4) Consideremos as seguintes datas de última modificação: main.c@10:00, main.o@10:40 aux.c@10:20, aux.o@10:25 defs.h@14:00 prg@10:45 e o Make ser executado às 18:00 1. Verificação da dependência temporal entre prg e aux.o é suspensa. A. defs.h é posterior a aux.o: aux.c é compilado e aux.o passa a ter como data de última modificação as 18:00 Programação de Sistemas Make : 7/17 Reconstrução das dependências (5) 2. Verificação da dependência temporal entre prg e main.o é suspensa. A. main.c é anterior a main.o: logo, não há alterações. 3. Retomada a verificação da dependência temporal entre prg e aux.o, que agora não é satisfeita: logo, a edição de ligações é executada. Programação de Sistemas Make : 8/17
Macros (1) [Def] Uma macro é uma directiva de substituição. Existem dois tipos de macros, estáticos e dinâmicos. 1. Estáticas: macros válidas em todo o ficheiro makefile Exemplo: Declaração: Uso: ID=texto $(ID) CC=gcc # para alterar compilador, basta modificar macro CFLAGS=-Wall -ansi - pedantic main.o: main.c $(CC) $(CFLAGS) -c main.c Programação de Sistemas Make : 9/17 Macros (2) A definição de uma macro dentro do ficheiro makefile perde prioridade sobre a linha de comando. Exemplo: CC=gcc CFLAGS=-Wall -ansi - pedantic asterix.ist.utl.pt> make CC=lcc # o compilador usado passa a ser olcc, não ogcc Programação de Sistemas Make : 10/17
Macros (3) 2. Dinâmicas: adaptados em cada regra, usando a extensão do ficheiro para indicar o tipo. $@ id do ficheiro alvo $? Dependências com data posterior à do alvo $< id do ficheiro dependente $* id do ficheiro alvo, retirando extensão $% membro de uma biblioteca Exemplo de regra implícita:.c.o: $(CC) $(CFLAGS) -c $< Nota: regras implícitas pré-definidas podem ser listadas usando a opção make -p Programação de Sistemas Make : 11/17 Macros (4) prg: aux.o main.o $(CC) -o prg aux.o main.o aux.o: aux.c defs.h # todas as dependências de aux.o indicadas, porque a regra # implícita apenas aceita ligações um-para-um. # A reconstrução segue regra implícita. # reconstrução de main.c usa regra implícita clean: rm prg *.o Programação de Sistemas Make : 12/17
Macros (5) Ao ser lançado, o make começa por ler um ficheiro de regras implícitas pré-definidas (ex: regras.c.o) Se o makefile incluir regras implícita com novo sufixo, indicar pela regra.suffixes Exemplo:.SUFFIXES:.pdf.tex.pdf: latex $< dvipdf $*.dvi $@ # latex gera ficheiro.dvi all: Lab2.pdf Lab3.pdf Lab4.pdf \ Lab5.pdf Lab6.pdf Programação de Sistemas Make : 13/17 Localização de ficheiros (1) Comando vpath %.ext DIR identifica directoria onde residem ficheiros de extensãoext vpath %.c src/ vpath %.o obj/ vpath %.h include/.c.o: $(CC) $(CFLAGS) -c -I include/ -o obj/$@ $< target: f1.o $(CC) -o obj/f1.o Nota: necessário indicar directorias na linha de comando f1.o: f1.c defs.h Conteúdo da variáveis de ambiente do Shell (PATH, HOME, ) pode ser acedido dentro do Make, quer nas dependências, quer nas linhas de comando, na forma $(ID). Programação de Sistemas Make : 14/17
Localização de ficheiros (2) Explicação detalhada da regra implícita.c.o: $(CC) $(CFLAGS) -c -I include/ -o obj/$@ $< Se necessitar um ficheiro de extensão.o, e se esse ficheiro não existir no directório, procura no directório o ficheiro fonte de extensão.c. Se esse ficheiro existir, a reconstrução é feita com $(CC): comando a executar, indicado na macro CC (normalmente tem-se CC=gcc) $(CFLAGS): bandeiras do compilador. Por exemplo se se tiver CFLAGS= não inclui directivas de compilação -c: apenas gera o ficheiro objecto (não evoca a edição de ligações) -I include/: deve procurar todos os ficheiros #define de utlizador (indicados entre aspas, como #define "defs.h") no directório include/ -o obj/$@: o identificador do ficheiro resultado da compilação é dado pelo ficheiro alvo (determinado na linha das dependências) e inserido no directório obj/ $<: ficheiro a compilar Programação de Sistemas Make : 15/17 Opções (1) -C dir altera directório corrente (em alternativa, --directory=dir) -f fich redirecciona makefile (em alternativa,--file=fich) -I dir altera directório de pesquisa dos cabeçalhos (em alternativa,--include-dir=dir) -s modo silencioso (em alternativa,--silent) Programação de Sistemas Make : 16/17
Opções (2) Exemplo: gerador de programa para sistemas operativos distintos echo: echo make (DOS LINUX) DOS: make -C src -f Makefile.dos LINUX: make -C src -f Makefile.lnx Programação de Sistemas Make : 17/17