Почему гну не может понять эту последовательность правил? - PullRequest
1 голос
/ 03 апреля 2019

У меня есть Makefile:

%: %.x
    cp $< $@

build/%: src/%
    cp $< $@

И структура каталогов, которая выглядит следующим образом:

Makefile
build/
src/
    hello.x

Почему make ведет себя следующим образом:

$ make build/hello
make: *** No rule to make target 'build/hello'.  Stop.

Почему он не видит, что

  1. он может перевести src/hello.x в src/hello, используя первое правило, и
  2. скопировать src/hello в build/hello используя второе правило?

1 Ответ

2 голосов
/ 03 апреля 2019

Согласно GNU make manual , то есть:

Если вы не помечаете правило соответствия чему-либо как терминальное, то оно не является терминальным.Нетерминальное правило сопоставления чего-либо не может применяться к имени файла, которое указывает конкретный тип данных.Имя файла указывает на конкретный тип данных, если ему соответствует какое-то неявное целевое правило без совпадений.

Ваше первое правило - это нетерминальное правило для поиска совпадений, поэтому оно не может применяться к цели src/hello, которая указывает на конкретный тип данных.В журнале отладки с make build/hello -d также показан процесс:

......
Considering target file `build/hello'.
 Looking for an implicit rule for `build/hello'.
 Trying pattern rule with stem `hello'.
 Trying implicit prerequisite `src/hello'.
 Trying pattern rule with stem `hello'.
 Trying implicit prerequisite `build/hello,v'.
 Trying pattern rule with stem `hello'.
 Trying implicit prerequisite `build/RCS/hello,v'.
 Trying pattern rule with stem `hello'.
 Trying implicit prerequisite `build/RCS/hello'.
 Trying pattern rule with stem `hello'.
 Trying implicit prerequisite `build/s.hello'.
 Trying pattern rule with stem `hello'.
 Trying implicit prerequisite `build/SCCS/s.hello'.
 Trying pattern rule with stem `hello'.
 Trying implicit prerequisite `src/hello'.
 Looking for a rule with intermediate file `src/hello'.
  Avoiding implicit rule recursion.
  Trying pattern rule with stem `hello'.
  Trying implicit prerequisite `src/hello,v'.
  Trying pattern rule with stem `hello'.
  Trying implicit prerequisite `src/RCS/hello,v'.
  Trying pattern rule with stem `hello'.
  Trying implicit prerequisite `src/RCS/hello'.
  Trying pattern rule with stem `hello'.
  Trying implicit prerequisite `src/s.hello'.
  Trying pattern rule with stem `hello'.
  Trying implicit prerequisite `src/SCCS/s.hello'.
 No implicit rule found for `build/hello'.
 Finished prerequisites of target file `build/hello'.
No need to remake target `build/hello'.
make: Nothing to be done for `build/hello'.

Ваше первое правило для правила match-any следует пометить как terminal, определив его двойным двоеточием.

Когда правило является терминальным, оно не применяется, если его предпосылки не существуют.Предпосылки, которые могут быть сделаны с другими неявными правилами, недостаточно хороши.Другими словами, дальнейшее связывание не допускается, кроме терминального правила.

Измените ваш make-файл на:

%:: %.x
        cp $< $@

build/%: src/%
        cp $< $@

Тест с make build/hello:

cp src/hello.x src/hello
cp src/hello build/hello
rm src/hello

В журнале отладки ниже показано, как это работает:

 ......
 Looking for a rule with intermediate file `src/hello'.
  Avoiding implicit rule recursion.
  Trying pattern rule with stem `hello'.
  Trying implicit prerequisite `src/hello.x'.
 Found an implicit rule for `build/hello'.
   Considering target file `src/hello.x'.
    Finished prerequisites of target file `src/hello.x'.
   No need to remake target `src/hello.x'.
 Considering target file `src/hello'.
  File `src/hello' does not exist.
   Pruning file `src/hello.x'.
  Finished prerequisites of target file `src/hello'.
 Must remake target `src/hello'.
cp src/hello.x src/hello
Putting child 0x08a51438 (src/hello) PID 30908 on the chain.
Live child 0x08a51438 (src/hello) PID 30908
Reaping winning child 0x08a51438 PID 30908
Removing child 0x08a51438 PID 30908 from chain.
 Successfully remade target file `src/hello'.
 Finished prerequisites of target file `build/hello'.
Must remake target `build/hello'.
cp src/hello build/hello
Putting child 0x08a51438 (build/hello) PID 30909 on the chain.
Live child 0x08a51438 (build/hello) PID 30909
Reaping winning child 0x08a51438 PID 30909
Removing child 0x08a51438 PID 30909 from chain.
Successfully remade target file `build/hello'.
Removing intermediate files...
rm src/hello
...