Make не следует символическим c ссылкам для поиска файлов - PullRequest
0 голосов
/ 07 мая 2020

Когда я извлекаю файлы из tar-шара для создания списка файлов, make не следует символическим c ссылкам и продолжает извлекать один и тот же tar-шар для каждого файла, указанного в списке. Например, я создал 2 tar-шара со следующими командами в linux:

design1 - это каталог, который содержит ссылку на другой каталог с c файлами дизайна

% mkdir design1
% mkdir c_files
% cd c_files/
% touch a.c b.c c.c d.c e.c f.c
% cd ../design1/
% ln -s ../c_files/ .
% cd ..
% gtar zcvf design1.tgz design1/

design2 is то же, что и design1, за исключением того, что c_files - это каталог, а не ссылка

% mkdir design2
% 
% cp -rp c_files design2
% gtar zcvf design2.tgz design2/

Теперь есть 2 заархивированных tar-файла: design1.tgz и design2.tgz, а каталоги design1 и design2 удалены

% \rm -rf design1 design2

Вот мой Makefile: ---------------- Begin Makefile -------------------

DESIGN_EXTRACT_DIR := .
DESIGN_TOP1 := c_proj1
FILE_LIST1 := $(strip $(DESIGN_TOP1)).f


DESIGN_TAR_FILE1 := design1.tgz
DESIGN_RELEASE_DIR1 := $(DESIGN_EXTRACT_DIR)/design1

DESIGN_FILES1 =\
$(DESIGN_RELEASE_DIR1)/c_files/a.c   \
$(DESIGN_RELEASE_DIR1)/c_files/b.c   \
$(DESIGN_RELEASE_DIR1)/c_files/c.c   \
$(DESIGN_RELEASE_DIR1)/c_files/d.c   \
$(DESIGN_RELEASE_DIR1)/c_files/e.c   \
$(DESIGN_RELEASE_DIR1)/c_files/f.c   \


IP_EXTRACT1: $(DESIGN_FILES1) 

$(DESIGN_FILES1): $(DESIGN_TAR_FILE1)   
    gtar zxvfmhC $(DESIGN_TAR_FILE1) $(DESIGN_EXTRACT_DIR) 

$(FILE_LIST1): $(DESIGN_FILES1) 
    @( rm -f $(FILE_LIST1) )
    @( touch $(FILE_LIST1) )
    @$(foreach file, $(DESIGN_FILES1), `echo $(file) >> $(FILE_LIST1)`)


FL1:    $(FILE_LIST1)

DESIGN_TOP2 := c_proj2
FILE_LIST2 := $(strip $(DESIGN_TOP2)).f


DESIGN_TAR_FILE2 := design2.tgz
DESIGN_RELEASE_DIR2 := $(DESIGN_EXTRACT_DIR)/design2

DESIGN_FILES2 =\
$(DESIGN_RELEASE_DIR2)/c_files/a.c   \
$(DESIGN_RELEASE_DIR2)/c_files/b.c   \
$(DESIGN_RELEASE_DIR2)/c_files/c.c   \
$(DESIGN_RELEASE_DIR2)/c_files/d.c   \
$(DESIGN_RELEASE_DIR2)/c_files/e.c   \
$(DESIGN_RELEASE_DIR2)/c_files/f.c   \


IP_EXTRACT2: $(DESIGN_FILES2) 

$(DESIGN_FILES2): $(DESIGN_TAR_FILE2)   
    gtar zxvfmhC $(DESIGN_TAR_FILE2) $(DESIGN_EXTRACT_DIR) 

$(FILE_LIST2): $(DESIGN_FILES2) 
    @( rm -f $(FILE_LIST2) )
    @( touch $(FILE_LIST2) )
    @$(foreach file, $(DESIGN_FILES2), `echo $(file) >> $(FILE_LIST2)`)


FL2:    $(FILE_LIST2)

clean: 
    @( rm -rf $(FILE_LIST1)* $(FILE_LIST2)* )

---------------- Конец файла Makefile ----------------------

Теперь, когда Я запускаю make, чтобы создать список файлов. Я использую команды make FL1 и make FL2. В случае FL1 делайте итерации gtar столько раз, сколько у меня файлов, но не делайте этого с FL2. Единственная разница здесь в том, что FL1 работает со ссылкой c_files в design1, тогда как FL2 перебирает c_files как каталог. Вот что я вижу:

% make FL1
gtar zxvfmhC design1.tgz . 
design1/
design1/c_files
gtar zxvfmhC design1.tgz . 
design1/
design1/c_files
gtar zxvfmhC design1.tgz . 
design1/
design1/c_files
gtar zxvfmhC design1.tgz . 
design1/
design1/c_files
gtar zxvfmhC design1.tgz . 
design1/
design1/c_files
gtar zxvfmhC design1.tgz . 
design1/
design1/c_files


%make FL2
%

Проблема 1: FL1 создает c_proj1.f, а FL2 создает c_proj2.f, но FL2 не повторяется, как FL1, и я не уверен, как предотвратить эту итерацию, особенно если у меня может быть большой tar мяч с сотнями файлов.

Проблема 2: Когда DESIGN_FILES1 является длинным списком из-за количества файлов, я получаю следующую ошибку, потому что переменная слишком длинная: make: execvp: / bin / sh: Список аргументов слишком длинный

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

Спасибо

Ниль

Ответы [ 2 ]

0 голосов
/ 08 мая 2020

Я последовал вашему совету и изменил зависимость, и это решило проблему tar. Функция файла в make разрешает длину переменной, но из-за этого у меня есть 2 нежелательных эффекта. Я добавил сюда еще одну вещь, и я не могу объяснить поведение:

On linux:

  % mkdir -p design3/c_files
  % cd design3/c_files
  % touch x.c y.c z.c
  % cd ../..
  % ls ./design3/c_files/*.c >  design3/c_proj3.f

Вот что я сделал с Makefile:

DIR_LIST := design3

IP_EXTRACT1: $(DESIGN_TAR_FILE1)   
    gtar zxvfmC $(DESIGN_TAR_FILE1) $(DESIGN_EXTRACT_DIR) 

$(DESIGN_FILES1): 
    $(MAKE) IP_EXTRACT1

$(FILE_LIST1):  $(DESIGN_FILES1) 
    $(file > $(FILE_LIST1))
    @$(if $(strip $(DIR_LIST)), cat $(foreach dir, $(DIR_LIST), $(wildcard $(dir)/*.f)) >> $(FILE_LIST1))
    @$(foreach file,$(DESIGN_FILES1),$(file >>$(FILE_LIST1),$(file)))

Это решает проблему tar, но теперь я добавил DIR_LIST и хочу добавить список файлов в каждом каталоге в список файлов. Он поступает правильно, но имеет несколько нежелательных эффектов:

1) Я ожидаю, что содержимое design3 / c_proj3.f будет вверху, но оно появится в конце.

%make FL1
%more c_proj1.f
./design1/c_files/a.c
./design1/c_files/b.c
./design1/c_files/c.c
./design1/c_files/d.c
./design1/c_files/e.c
./design1/c_files/f.c
./design3/c_files/x.c
./design3/c_files/y.c
./design3/c_files/z.c

Я ожидал, что x, y, z вверху, так как есть зависимость от порядка, но внизу. Кроме того, если я сделаю FL1 - dry -run после удаления c_proj1.f, файлы с a по f попадают в него, но не x, y, z, потому что это из команды оболочки cat. Я бы предпочел, чтобы файлы не создавались. Есть ли способ решить эту проблему? Это частичное решение, поэтому я не уверен, нужно ли go вернуться к вопросу.

0 голосов
/ 07 мая 2020

Для меня это работает одинаково (повторяется один раз) независимо от того, есть символическая ссылка или нет. Но из содержимого кажется, что вас интересует только создание списка файлов, поэтому существование файла на самом деле не требуется. Если вы опустите зависимость, вы можете сгенерировать список файлов, даже не извлекая файлы.

Для фактического списка файлов запишите слишком большую ошибку командной строки из-за того, что сгенерированная команда представляет собой одну строку с несколькими вызовами подоболочки , что может быть слишком длинным для командной строки:

$ make FL1 --trace
...
Makefile:24: update target 'c_proj1.f' due to: design1/c_files/a.c design1/c_files/b.c design1/c_files/c.c design1/c_files/d.c design1/c_files/e.c design1/c_files/f.c
( rm -f c_proj1.f )
( touch c_proj1.f )
`echo ./design1/c_files/a.c >> c_proj1.f`  `echo ./design1/c_files/b.c >> c_proj1.f`  `echo ./design1/c_files/c.c >> c_proj1.f`  `echo ./design1/c_files/d.c >> c_proj1.f`  `echo ./design1/c_files/e.c >> c_proj1.f`  `echo ./design1/c_files/f.c >> c_proj1.f`

Эта часть может быть решена с помощью функции $(file) (если вы используете GNU make 4.1 +):

.PHONY: $(FILE_LIST1)
$(FILE_LIST1):
        $(file >$@)
        $(foreach file,$(DESIGN_FILES1),$(file >>$@,$(file)))

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

# Note double empty lines below
define newline


endef

.PHONY: $(FILE_LIST2)
$(FILE_LIST2):
        rm -f $@
        $(foreach file,$(DESIGN_FILES2),echo $(file) >> $@$(newline))

Результат теперь генерируется в отдельных вызовах оболочки, что должно избегать ограничения длины команды:

$ make FL2
rm -f c_proj2.f
echo ./design2/c_files/a.c >> c_proj2.f
echo ./design2/c_files/b.c >> c_proj2.f
echo ./design2/c_files/c.c >> c_proj2.f
echo ./design2/c_files/d.c >> c_proj2.f
echo ./design2/c_files/e.c >> c_proj2.f
echo ./design2/c_files/f.c >> c_proj2.f

РЕДАКТИРОВАТЬ:

Мне удалось воспроизвести вашу многократную итерацию извлечения. Ваш файл tgz на самом деле не содержит файлов, которые вы утверждаете для извлечения, поэтому файлы отсутствуют при попытке извлечения первого файла, а извлечение продолжается для следующего файла (который также отсутствует). Об этом также свидетельствует вывод tar, в котором говорится:

design1/
design1/c_files

вместо:

design1/
design1/c_files
design1/c_files/a.c
design1/c_files/b.c
design1/c_files/c.c
design1/c_files/d.c
design1/c_files/e.c
design1/c_files/f.c

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

EDIT2:

Когда фактические файлы не включены в файл tgz, но доступны по символической ссылке, есть вероятность, что они старше, чем сам файл tgz. В такой ситуации make проверяет временную метку файла через символическую ссылку и обнаруживает, что ее необходимо переделать, но файл фактически не переделывается (поскольку он не включен в tgz). Эта проверка выполняется для каждого отдельного файла, поэтому для каждого файла извлекается архив:

$ make FL1 -d
...
     Finished prerequisites of target file 'design1/c_files/a.c'.
     Prerequisite 'design1.tgz' is newer than target 'design1/c_files/a.c'.
    Must remake target 'design1/c_files/a.c'.
tar zxvfmhC design1.tgz .
Putting child 0x7fffe11ae730 (design1/c_files/a.c) PID 6286 on the chain.
Live child 0x7fffe11ae730 (design1/c_files/a.c) PID 6286
design1/
design1/c_files
Reaping winning child 0x7fffe11ae730 PID 6286
Removing child 0x7fffe11ae730 PID 6286 from chain.
    Successfully remade target file 'design1/c_files/a.c'.
    Considering target file 'design1/c_files/b.c'.
      Pruning file 'design1.tgz'.
     Finished prerequisites of target file 'design1/c_files/b.c'.
     Prerequisite 'design1.tgz' is newer than target 'design1/c_files/b.c'.
    Must remake target 'design1/c_files/b.c'.
tar zxvfmhC design1.tgz .
...

В общем, извлечение архива таким способом в любом случае ненадежно (образ работает параллельно с -j), поэтому было бы лучше использовать целевое правило группы , чтобы явно указать, что это правило генерирует все файлы одновременно:

$(DESIGN_FILES1) &: $(DESIGN_TAR_FILE1)
        tar zxvfmhC $(DESIGN_TAR_FILE1) $(DESIGN_EXTRACT_DIR)

Однако это новая функция, представленная в GNU make 4.3, поэтому, чтобы он работал с предыдущими версиями, мы могли бы использовать фальшивую цель, которая используется только для синхронизации, например:

$(DESIGN_FILES1): extract-$(DESIGN_TAR_FILE1)

.PHONY: extract-$(DESIGN_TAR_FILE1)
extract-$(DESIGN_TAR_FILE1):
        tar zxvfmhC $(DESIGN_TAR_FILE1) $(DESIGN_EXTRACT_DIR)

Вывод:

$ make FL1
tar zxvfmhC design1.tgz .
design1/
design1/c_files

Обратите внимание, что архив теперь извлекается только один раз.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...