Например, у меня есть что-то вроде этого в моем make файле:
all:
cd some_directory
Но когда я набрал make
, я увидел только "cd some_directory", как в команде echo
.
Например, у меня есть что-то вроде этого в моем make файле:
all:
cd some_directory
Но когда я набрал make
, я увидел только "cd some_directory", как в команде echo
.
Фактически выполняется команда, меняя каталог на some_directory
, однако это выполняется в оболочке подпроцесса и не влияет ни на make, ни на оболочку, из которой вы работаете.
Если вы хотите выполнить больше задач в some_directory
, вам нужно добавить полуточку и добавить другие команды. Обратите внимание: вы не можете использовать символы новой строки, поскольку они интерпретируются make как конец правила, поэтому любые новые строки, которые вы используете для ясности, должны быть экранированы обратным слэшем.
Например:
all:
cd some_dir; echo "I'm in some_dir"; \
gcc -Wall -o myTest myTest.c
Обратите внимание также, что точка с запятой необходима между каждой командой, даже если вы добавляете обратную косую черту и новую строку. Это связано с тем, что вся строка анализируется как одна строка оболочки. Как отмечено в комментариях, вы должны использовать '& &' для объединения команд, что означает, что они выполняются только в том случае, если предыдущая команда была успешной.
all:
cd some_dir && echo "I'm in some_dir" && \
gcc -Wall -o myTest myTest.c
Это особенно важно при выполнении деструктивной работы, такой как очистка, поскольку иначе вы уничтожаете неправильный материал, если cd
не работает по какой-либо причине.
Обычное использование, однако, заключается в вызове make в подкаталоге, который вы, возможно, захотите изучить. Там есть опция командной строки, поэтому вам не нужно вызывать cd
самостоятельно, поэтому ваше правило будет выглядеть следующим образом:
all:
$(MAKE) -C some_dir all
который изменится на some_dir
и выполнит Makefile
там с целевым "все". В качестве наилучшей практики используйте $(MAKE)
вместо прямого вызова make
, так как позаботится о вызове правильного экземпляра make (если вы, например, используете специальную версию make для вашей среды сборки), а также при работе с некоторыми коммутаторами, например, -t
.
Для записи всегда выполняйте команду echo, которая выполняется (если явно не подавлена), даже если она не имеет выхода, что вы видите.
Начиная с GNU make 3.82
, вы можете использовать .ONESHELL
специальная цель для запуска всех строк рецептов в одном экземпляре оболочки:
- Новая специальная цель:
.ONESHELL
дает команду вызвать один экземпляр оболочки и предоставить ей весь рецепт, независимо от того, сколько строки, которые он содержит. [...]
Пример:
.ONESHELL:
all:
cd ~/some_dir
pwd # this line is correctly run in ~/some_dir if cd succeeded
Вот симпатичный трюк, чтобы разобраться с каталогами и сделать. Вместо использования многострочных строк или "cd;" для каждой команды определите простую функцию chdir следующим образом:
CHDIR_SHELL := $(SHELL)
define chdir
$(eval _D=$(firstword $(1) $(@D)))
$(info $(MAKE): cd $(_D)) $(eval SHELL = cd $(_D); $(CHDIR_SHELL))
endef
Тогда все, что вам нужно сделать, это вызвать его в своем правиле так:
all:
$(call chdir,some_dir)
echo "I'm now always in some_dir"
gcc -Wall -o myTest myTest.c
Вы даже можете сделать следующее:
some_dir/myTest:
$(call chdir)
echo "I'm now always in some_dir"
gcc -Wall -o myTest myTest.c
Что вы хотите, чтобы он сделал, когда он туда попал? Каждая команда выполняется в подоболочке, поэтому подголовник меняет каталог, но конечным результатом является то, что следующая команда все еще находится в текущем каталоге.
С GNU make вы можете сделать что-то вроде:
BIN=/bin
foo:
$(shell cd $(BIN); ls)
Вот так:
target:
$(shell cd ....); \
# ... commands execution in this directory
# ... no need to go back (using "cd -" or so)
# ... next target will be automatically in prev dir
Удачи!