Как написать команду 'cd' в make файле?

Например, у меня есть что-то вроде этого в моем make файле:

all:
     cd some_directory

Но когда я набрал make, я увидел только "cd some_directory", как в команде echo.

Ответ 1

Фактически выполняется команда, меняя каталог на 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, которая выполняется (если явно не подавлена), даже если она не имеет выхода, что вы видите.

Ответ 2

Начиная с GNU make 3.82, вы можете использовать .ONESHELL специальная цель для запуска всех строк рецептов в одном экземпляре оболочки:

  • Новая специальная цель: .ONESHELL дает команду вызвать один экземпляр оболочки и предоставить ей весь рецепт, независимо от того, сколько строки, которые он содержит. [...]

Пример:

.ONESHELL:
all:
    cd ~/some_dir
    pwd # this line is correctly run in ~/some_dir if cd succeeded

Ответ 3

Вот симпатичный трюк, чтобы разобраться с каталогами и сделать. Вместо использования многострочных строк или "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

Ответ 4

Что вы хотите, чтобы он сделал, когда он туда попал? Каждая команда выполняется в подоболочке, поэтому подголовник меняет каталог, но конечным результатом является то, что следующая команда все еще находится в текущем каталоге.

С GNU make вы можете сделать что-то вроде:

BIN=/bin
foo:
    $(shell cd $(BIN); ls)

Ответ 5

Вот так:

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

Удачи!