#makefile #gnu-make
Вопрос:
Я на Mac использую GNU Make для управления своими dot-файлами. В файле Makefile есть каталог с моими файлами конфигурации emacs и соответствующим целевым объектом:
all: _emacs .PHONY: all list $(MAKECMDGOALS) .... EMACS_SOURCE_DIR := $(abspath ./emacs) EMACS_TARGET_DIR := $(abspath $(HOME)/.emacs.d) EMACS_CONFIG_FILES := $(wildcard $(EMACS_SOURCE_DIR)/*.el) _emacs: | $(EMACS_TARGET_DIR) @echo $(call message,"Setting up config files for emacs") $(foreach file, $(EMACS_CONFIG_FILES), ln -sf $(file) $(addsuffix /, $(EMACS_TARGET_DIR))) $(EMACS_TARGET_DIR): @echo "Creating directory $(EMACS_TARGET_DIR)" @mkdir -p $@
Когда я запускаю make _emacs
его, он создает несколько дополнительных ссылок:
.emacs.d -gt; /Users/xxx/.emacs.d/ -sf -gt; -sf early-init.el -gt; /Users/xxx/Projects/bootstrap/emacs/early-init.el init-org.el -gt; /Users/xxx/Projects/bootstrap/emacs/init-org.el init-pkgs.el -gt; /Users/xxx/Projects/bootstrap/emacs/init-pkgs.el init.el -gt; /Users/xxx/Projects/bootstrap/emacs/init.el ln -gt; ln
Я изо всех сил пытаюсь понять, что именно происходит и как избежать создания первых двух и последних мягких ссылок.
Ответ №1:
В общем, это плохая идея-пытаться создать сложную команду оболочки, используя функции make внутри рецепта. Вы должны просто использовать конструкции оболочки: например, используйте цикл оболочки for
, а не foreach
цикл создания.
Давайте посмотрим, что делает ваш рецепт:
_emacs: | $(EMACS_TARGET_DIR) $(foreach file, $(EMACS_CONFIG_FILES), ln -sf $(file) $(addsuffix /, $(EMACS_TARGET_DIR)))
Заставьте функции манипулировать текстом. Они ничего не знают о командах, синтаксисе оболочки и т. Д. Прежде чем make вызовет оболочку, она сначала развернет сценарий. К чему это приведет? Этот:
ln -sf .../emacs/early-init.el /Users/xxx/.emacs.d/ ln -sf .../emacs/init-org.el /Users/xxx/.emacs.d/ ln -sf ...
Может быть, теперь вы видите проблему.
Если вы хотите сделать это с помощью make foreach
, вам нужно добавить разделитель оболочки, чтобы оболочка знала, где заканчивается одна команда и начинается следующая; что-то вроде:
$(foreach file, $(EMACS_CONFIG_FILES), ln -sf $(file) $(addsuffix /, $(EMACS_TARGET_DIR)) ; )
(обратите внимание ;
в конце). Теперь, когда make расширяется, это будет выглядеть так:
ln -sf .../emacs/early-init.el /Users/xxx/.emacs.d/ ; ln -sf .../emacs/init-org.el /Users/xxx/.emacs.d/ ; ln -sf ...
На вашем месте я бы вместо этого использовал контур оболочки. Просто это гораздо проще понять:
for file in $(EMACS_CONFIG_FILES); do ln -sf $file $(addsuffix /, $(EMACS_TARGET_DIR)) ; done
Но для того, что вы хотите сделать, вам вообще не нужен цикл; вы можете связать несколько файлов в один каталог с помощью одной команды:
ln -sf $(EMACS_CONFIG_FILES) $(EMACS_TARGET_DIR)
(Я не уверен, для чего addsuffix
это было нужно, или почему вы не могли просто написать это как $(EMACS_TARGET_DIR)/
без addsuffix
)
Комментарии:
1. Я использовал эту
addsuffix
штуковину, например, для переименования целевых ссылокzshrc -gt; .zshrc
. Вы правы, в данном случае это ничего не значит. Спасибо за вашу помощь!