Tornar alvo com duas palavras

3

Estou usando um Makefile para compilar meu código Clean . Meus arquivos limpos possuem nomes de arquivos com o formato *.icl e são compilados para binários com o mesmo nome, mas sem .icl . Isso é feito com a regra:

$(EXE): % : %.icl | copy
    $(CLM) $(CLM_LIBS) $(CLM_INC) $(CLM_OPTS) $@ -o $@

Agora gostaria de adicionar uma regra que me permita executar um binário. Atualmente, estou sempre fazendo

make some_module && ./some_module

Eu gostaria de ter um destino que depende da regra acima e executa o módulo. No entanto, o nome do módulo já é um alvo para a compilação e eu gostaria de mantê-lo assim. O que eu gostaria é de um alvo com duas palavras que eu possa chamar com make run some_module , que então depende da regra acima e executa ./some_module depois.

É possível criar alvos com várias palavras?

Eu tentei criar uma regra (agora ainda sem dependência) com o seguinte:

run $(EXE):
    ./$@

A execução de make run some_module faz com que muitas receitas sejam "substituídas" e "ignoradas" e, finalmente, ./run não exista.

Makefile:24: warning: overriding recipe for target 'tut7_2_2'
Makefile:21: warning: ignoring old recipe for target 'tut7_2_2'
Makefile:24: warning: overriding recipe for target 'support_check'
Makefile:21: warning: ignoring old recipe for target 'support_check'
[...]
Makefile:24: warning: overriding recipe for target 'drawingframe'
Makefile:21: warning: ignoring old recipe for target 'drawingframe'
./run
/bin/bash: ./run: No such file or directory
Makefile:24: recipe for target 'run' failed
make: *** [run] Error 127
    
por Keelan 10.08.2015 / 10:32

2 respostas

2

Você pode inspecionar MAKECMDGOALS para detectar a presença de um objetivo ao criar outro objetivo. Faça com que a %: %.icl run detecte a presença da meta run ou faça com que a meta run inspecione quais executáveis são mencionados como destinos. Se você passar mais de um executável como um destino, o primeiro método fará com que cada um seja executado logo após ser construído, enquanto o segundo faz com que todas as execuções ocorram no final.

A desvantagem dessa abordagem é que ela não se adapta bem a outros recursos. Por exemplo, se você definir um destino com vários executáveis como dependências, o método com run target não funcionará.

EXE = foo bar experimental
released: foo bar
run: $(filter $(EXE), $(MAKECMDGOALS))
        set -e; for x in $^; do ./$x; done

Aqui make released run não executará nada.

O que eu normalmente faço neste caso é definir um destino de "execução" para cada executável. Isso mantém cada alvo expresso como uma única palavra, o que é uma grande vantagem. É simples e não quebra outros recursos.

$(EXE): %.run: %
        ./$(@:.run=)
all.run: $(EXE:=.run)

Em seguida, executo make {foo,bar}.run se quiser criar e testar foo e bar ou make all.run para criar e executar todos eles.

    
por 11.08.2015 / 09:26
3

Você pode usar $ (MAKECMDGOALS) para forçar run para ser executado por último entre outros alvos especificados na linha de comando. O exemplo a seguir usa C porque não sei Limpar.

EXE = a b c

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

all: $(EXE)

clean:
    rm -f $(EXE)

run: $(filter-out run, $(MAKECMDGOALS))
    @for i in $^; do ./$$i; done

.PHONY: all clean run

make run program pode parecer um pouco desajeitado porque sempre coloca a saída desnecessária program is up to date .

$ cat a.c
#include <stdio.h>
int main(int argc, char **argv) { printf("This is %s\n", argv[0]); return 0; }
$ cp a.c b.c
$ cp a.c c.c

$ make run a b
cc  -o a a.c
cc  -o b b.c
This is ./a
This is ./b
make: 'a' is up to date.
make: 'b' is up to date.

make program run não produz esse resultado e pode ser mais natural como o inglês.

$ make c run
cc  -o c c.c
This is ./c
    
por 10.08.2015 / 12:52

Tags