GNU Make - как обрабатывать пути в объектных файлах
В настоящее время я пишу больший make-файл, который будет обрабатывать рекурсивную структуру исходных файлов и помещать их в одну рекурсивную структуру в целевом каталоге. По сути, вы можете использовать этот make-файл:
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, я не могу выровнять структуру. И подкаталоги являются динамическими, а не предопределенными.
Я искал других, имеющих такую же проблему, но у них либо есть плоские ОБЪЕКТЫ, либо рекурсивная модель, которая в моем случае не очень подходит из-за взаимосвязей между каталогами в соответствии с зависимостями.
Сводка / сообщение об ошибке:
Он не заменяет / в ОБЪЕКТАХ на src/. Таким образом, сообщение об ошибке "Keine Regel vorhanden, um das Target" out/abc.o ", benötigt von" all ", zu erstellen. Schluss." что является типичной ошибкой "Нет правила для цели...".
Полный Makefile можно увидеть здесь: Полный Makefile
Всякий раз, когда я оставляю правую сторону двоеточия с%.html на левой стороне, это работает, но мне нужно иметь исходный файл в качестве зависимости, чтобы получить работающую инкрементную сборку (надеюсь, без создания файлов зависимостей).
С уважением,
Даниил
2 ответа
С ответом Михаэля Грюневальда и сайтом MadScientist я решил пойти по пути VPATH. Но поэтому мне пришлось сначала переключиться на выходной каталог и удалить префиксы out/ OBJECTS (с рекурсивным вызовом make-файла). Приведенный выше короткий пример будет изменен следующим образом:
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-файле.
Извините за обстоятельства и еще раз спасибо. Для тех, кто читает это из-за схожей проблемы: дважды проверьте косые черты!
Решение использовать расширение GNU make не является хорошим способом. Я бы рекомендовал не использовать какую-либо особенность GNU Make. Прежде всего, это не портативно. Во-вторых, синтаксис ужасен. Используйте стандартные инструменты и технологии, когда-либо изобретенные. Ваше решение - Shell. Вы можете заключить ваш 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. Вы можете параметризовать его и сделать его очень мощным и умным. Не нужно использовать скудное и грязное расширение.