Как написать команду " cd " в makefile?

например, у меня есть что-то вроде этого в моем makefile:

all:
     cd some_directory

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

6 ответов


он фактически выполняет команду, изменяя каталог на 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.

для записи, сделать всегда повторяет команду, которую он выполняет (если явно не подавлен), даже если у него нет выходных данных, что вы видите.


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

  • новая специальная цель:.ONESHELL поручает сделать для вызова один экземпляр оболочки и предоставить ему весь рецепт, независимо от того, сколько строк он содержит. [...]
.ONESHELL:
all:
    cd ~/some_dir
    pwd # Prints ~/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

удачи!


изменить dir

foo: 
    $(MAKE) -C mydir

multi:
    $(MAKE) -C / -C my-custom-dir   ## Equivalent to /my-custom-dir