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. Вы можете параметризовать его и сделать его очень мощным и умным. Не нужно использовать скудное и грязное расширение.

Другие вопросы по тегам