Makefile заменяет символьный список файлов - PullRequest
0 голосов
/ 23 января 2019

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

existing_files = $(wildcard dir1/dir2/*.txt)

# The next line shows where I would want to put the symbolic links
symlinks = $(wildcard new_dir1/new_dir2/*.txt)

make_some_links:
# Remove previous symlinks if they share name as existing_files
ifeq ($(notdir $(existing_files)), $(notdir $(symlinks)))
    $(info Removing previous symlinks)
    @rm $(symlinks)
endif
# Loop to link here

Помимо этого, пытается ли указанное выше условие сопоставить каждый элемент каждого списка, или оно выполнится успешно, если совпадает только один из элементов?

Я не могу понять, как выполнить цикл в Make,в том числе с $(foreach), поэтому я написал следующий цикл, чтобы показать, что я имею в виду в Python с такими же именами переменных.

for i in len($(existing_files)):
    @ln -s $(existing_files)[i] $(symlinks)[i]

Здесь первый элемент в $(list_files) связан с первымэлемент в $(symlinks).Любое понимание того, как написать этот цикл в Make, или, если есть прямой подход к этому, было бы очень полезно.Спасибо.

Ответы [ 2 ]

0 голосов
/ 23 января 2019

В большинстве случаев, когда вы начинаете создавать циклы оболочки в рецептах make, вы упускаете важные функции make.Естественно, «make» будет « loop » для целей, которые вы объявляете, для достижения целей, о которых вы просите.И make предлагает множество способов факторизации подобных правил.

Но в вашем случае, когда цели являются символическими ссылками, необходимо рассмотреть несколько вопросов:

  • Если вы объявите ссылки как обычные целии если некоторые уже существуют, но указывают на другие файлы, отличные от тех, которые вам нужны, make может считать их актуальными и пропустить их, вместо того, чтобы заменять их.Таким образом, вы должны найти способ заставить make заново создать все ссылки или, по крайней мере, те, которые не указывают на правильный файл.И времени последнего изменения для этого недостаточно.
  • Даже с опцией -f ln не заменит существующий каталог (или ссылку на каталог), вместо этого он создаст ссылку внутрикаталог.Поэтому вы должны сначала удалить любой каталог (или ссылку на каталог), который конфликтует с целевой ссылкой.
  • Команда ln должна использоваться с параметрами -sr для создания символических ссылок относительно местоположения ссылки.
  • Целевой каталог (new_dir1/new_dir2) должен существовать до того, как вы попытаетесь создать первую ссылку.

Если вас не волнует воссоздание уже правильных ссылок, вещипросты:

  • объявить фиктивную фиктивную цель (force) и сделать обязательным предварительное условие для всех ваших ссылок, чтобы заставить их создавать заново,
  • перед созданием ссылок удалитесуществующие ссылки, файлы или каталоги, конфликтующие с ними,
  • используют правильные параметры ln,
  • объявляют целевой каталог как обязательное условие только для заказа ссылоки добавьте правило, чтобы создать его, если оно отсутствует.

Следующее должно выполнить работу:

source_dir     := dir1/dir2
link_dir       := new_dir1/new_dir2
existing_files := $(wildcard $(source_dir)/*.txt)
symlinks       := $(patsubst $(source_dir)/%,$(link_dir)/%,$(existing_files))

.PHONY: all force
all: $(symlinks)

$(link_dir)/%: $(source_dir)/% force | $(link_dir)
    rm -rf $@
    ln -sr $< $@

force:;

$(link_dir):
    mkdir -p $@

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

0 голосов
/ 23 января 2019

Давайте рассмотрим это поэтапно.

Сначала создайте символическую ссылку и удалите существующую ссылку с таким именем, если она есть:

ln -fs filename linkname

Теперь, чтобы составить список существующих файлов:

existing_files = $(wildcard dir1/dir2/*.txt)

Пока все хорошо. Давайте предположим, что это дает нам dir1/dir2/red.txt dir1/dir2/green.txt.

# The next line shows where I would want to put the symbolic links
symlinks = $(wildcard new_dir1/new_dir2/*.txt)

Это даст вам список вещей, которые уже существуют в этом каталоге, что, вероятно, не то, что вы намеревались. Мы должны составить список ссылок, которые мы хотим из списка файлов, которые у нас есть:

filenames := $(notdir $(existing_files))
symlinks := $(addprefix new_dir1/new_dir2/, $(filenames))

Теперь для правила или правил для создания символических ссылок. Мы могли бы написать два явных правила:

new_dir1/new_dir2/red.txt: dir1/dir2/red.txt
    ln -fs dir1/dir2/red.txt new_dir1/new_dir2

new_dir1/new_dir2/green.txt: dir1/dir2/green.txt
    ln -fs dir1/dir2/green.txt new_dir1/new_dir2

но это ужасно избыточно, и к тому же мы заранее не знаем имен файлов. Сначала мы можем удалить часть избыточности, определив переменную и используя автоматическую переменную $<:

DEST_DIR := new_dir1/new_dir2

$(DEST_DIR)/red.txt: dir1/dir2/red.txt
    ln -fs $< $(DEST_DIR)

$(DEST_DIR)/green.txt: dir1/dir2/green.txt
    ln -fs $< $(DEST_DIR)

Теперь мы можем увидеть, как заменить эти правила на шаблонное правило :

$(DEST_DIR)/%.txt: dir1/dir2/%.txt
    ln -fs $< $(DEST_DIR)

Теперь все, что нам нужно, это главное правило, требующее ссылки:

.PHONY: make_some_links
make_some_links: $(symlinks)
...