GNU Make — как обрабатывать пути в объектных файлах

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

DESTINATION_DIR = out
SOURCE_DIR = src
OBJECTS = out/abc.o out/subdir/test.o out/subdir/subdir/xyz.o

.PHONY: all
all: $(OBJECTS)

$(DESTINATION_DIR)/%.o: $(SOURCE_DIR)/%.c
    @echo "$@ --- $<"

Как видите, я пытаюсь заменить $(DESTINATION_DIR) на $(SOURCE_DIR) в зависимости, но это не работает. Как я могу это решить? Я даже пытался использовать замещающий скрипт таким образом:

%.o: $(shell myreplacementscript.py "%.c" "$(DESTINATION_DIR)" "$(SOURCE_DIR)")
    @echo "$@ --- $<"

но знак процента будет передан моему скрипту без замены. Итак, как я могу сказать, что вывод динамически зависит от исходного файла? Мне нужно сохранить подкаталоги в переменной OBJECTS, я не могу сгладить структуру. И подкаталоги являются динамическими, а не предопределенными.

Я искал других, имеющих ту же проблему, но у них либо плоские ОБЪЕКТЫ, либо рекурсивный make, что в моем случае не очень подходит из-за взаимосвязей между каталогами в соответствии с зависимостями.

Сводка/сообщение об ошибке:

Он не заменяет out/ в ОБЪЕКТАХ на src/. Таким образом, сообщение об ошибке: «Keine Regel vorhanden, um das Target »out/abc.o«, benötigt von »all«, zu erstellen. Schluss». что является типичной ошибкой «Нет правила для создания цели ...».

Полный make-файл можно увидеть здесь: Полный Makefile

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

С уважением,

Даниэль


person DanielB    schedule 24.09.2014    source источник
comment
Какую версию Make вы используете? (Если вы не уверены, попробуйте make -v.)   -  person Beta    schedule 25.09.2014
comment
Если вы точно объясните, что на самом деле означает но это не работает (сообщения об ошибках? Неправильное поведение? Отсутствующее поведение?), помочь вам будет намного проще.   -  person MadScientist    schedule 25.09.2014
comment
@Бета: GNU Make 3.81   -  person DanielB    schedule 25.09.2014
comment
@MadScientist: он не заменяет out/in OBJECTS на src/. Итак, сообщение об ошибке: Keine Regel vorhanden, um das Target »out/abc.o«, benötigt von »all«, zu erstellen. Шлюсс. что является типичной ошибкой Нет правила для создания цели .... Это в основном потому, что он не заменяет out/ на src/ и не может найти исходный файл.   -  person DanielB    schedule 25.09.2014
comment
Хотя это и не ответ, статья как не использовать VPATH может быть вам интересна. Также обратите внимание, что BSD Make имеет IMHO гораздо лучшую встроенную поддержку для хранения объектов в каталоге, отличном от исходного кода.   -  person Michaël Le Barbier    schedule 25.09.2014
comment
Идиома $(DESTINATION_DIR)/%.o: $(SOURCE_DIR)/%.c идеальна, ничего лишнего, насколько мне известно. Я использую это все время.   -  person kebs    schedule 25.09.2014


Ответы (2)


Решение использовать расширение GNU make не является хорошим способом. Я бы рекомендовал не использовать какие-либо специальные функции GNU Make. Во-первых, он не портативный. Во-вторых, его синтаксис ужасен. Используйте стандартные инструменты и технологии, когда-либо изобретенные. Ваше решение - Шелл. Вы можете обернуть свой Makefile в сценарий оболочки и выполнять все вычисления и манипуляции со строками, используя общий язык оболочки. Возьмем следующий пример:

src_files="file1.c file2.c file3.c"

cat > Makefile <<EOF
-
-
YOUR MAKEFILE STATIC STUFF GOES HERE
-

all: $(OBJECTS)

EOF

for file in $src_files; do
  src="src/$file"
  obj=`echo $file | sed 's/\.c$/\.o/'`
  sources="$sources $src"
  objects="$objects out/$obj"

  cat >>Makefile <<EOF
$obj: $src
    YOUR CODE HERE
EOF
done

cat >>Makefile <<EOF
SOURCES = $sources
OBJECTS = $objects

EOF

Назовите свой скрипт «mkmf» и запустите ./mkmf. Он сгенерирует Makefile. Вы можете параметризовать его и сделать очень мощным и умным. Не нужно использовать скудное и грязное расширение gnu make.

person Oleksiy Chernyavskyy    schedule 30.09.2014
comment
Это может быть правдой, но портативность мне не нужна. И какое именно расширение вы имеете в виду? Наконец-то я заработал со стандартным шаблоном out/%.o: in/%.o. - person DanielB; 01.10.2014
comment
Все эти приятные вещи в строке '$(shell ..)' являются специфической функцией GNU. Это не работает в других реализациях make. - person Oleksiy Chernyavskyy; 01.10.2014
comment
Спасибо за информацию, но, как я уже сказал, я могу жить с этим. Я не сосредотачиваюсь на других реализациях make, кроме GNU make. - person DanielB; 02.10.2014

С ответом Майкла Грюневальда и веб-сайтом MadScientist я решил пойти по пути VPATH. Но поэтому мне пришлось сначала переключиться на выходной каталог и удалить префиксы out/ ОБЪЕКТОВ (с рекурсивным вызовом makefile). Приведенный выше короткий пример будет изменен следующим образом:

ROOTDIR = $(abspath ./)

DESTINATION_DIR = out
SOURCE_DIR = src

DESTINATION_DIRABS = $(abspath $(shell cd $(ROOTDIR); cd $(DESTINATION_DIR); pwd))
SOURCE_DIRABS = $(abspath $(shell cd $(ROOTDIR); cd $(SOURCE_DIR); pwd))

ifneq ($(abspath ./),$(DESTINATION_DIRABS))
# we are not in the destination directory, so we first need to change to it
OBJECTS     = 
else
# without out/ prefix!
OBJECTS     = abc.o subdir/test.o subdir/subdir/xyz.o
# set the VPATH for the source files
VPATH       = $(SOURCE_DIRABS)
endif

.PHONY: all
all: $(OBJECTS)
ifneq ($(abspath ./),$(DESTINATION_DIRABS))
    # call make inside the destination directory
    $(MAKE) -C $(DESTINATION_DIRABS) -f $(ROOTDIR)/Makefile ROOTDIR='$(ROOTDIR)'
endif

%.o: %.c
    @echo "$@ --- $<"

(не проверено в этом небольшом примере, но работает в моем большем Makefile)

Итак, наконец, теперь он работает, как и ожидалось. Большое спасибо за ваши комментарии, Майкл Грюневальд, MadScientist и Beta.

Обновление:

Наконец, я повторил подход $(DESTINATION_DIR)/%.o: $(SOURCE_DIR)/%.c, и ошибка заключалась просто в том, что $(DESTINATION_DIR) уже содержал косую черту в моем полном make-файле.

Извините за обстоятельства и еще раз спасибо. Для тех, кто читает это из-за похожей проблемы: проверьте косые черты дважды!

person DanielB    schedule 25.09.2014