Как реализовать файл Makefile, который запоминает последнюю цель сборки?


Допустим, у вас есть Makefile с двумя псевдо-целями, 'all' и 'debug'. Цель "debug" предназначена для построения того же проекта, что и "all", за исключением некоторых различных параметров компиляции (например,- ggdb). Поскольку целевые объекты используют разные переключатели компиляции, Вам, очевидно, нужно перестроить весь проект, если вы переключаетесь между ними. Но GNUmake не естественно признать это.

Так что если вы наберете make all, то получите

Building ...
...

Тогда, если вы наберете make debug, Вы get

make: Nothing to be done for `debug'.

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

3 6

3 ответа:

Поместите продукты сборки в разные деревья каталогов (сохраняя при этом одну копию исходного кода, конечно). Таким образом, вы всегда просто короткая компиляция из последней сборки, будь то debug или release (или даже другие). И никакой возможности запутаться тоже.

EDIT

Набросок вышесказанного.

src := 1.c 2.c 3.c
bare-objs := ${src:%.c=%.o}
release-objs := ${bare-objs:%=Release/%}
debug-objs := ${bare-objs:%=Debug/%}

Release/prog: ${release-objs}
Debug/prog: ${debug-objs}

${release-objs}: Release/%.o: %.c # You gotta lurve static pattern rules
    gcc -c $< -o $@

${debug-objs}: Debug/%.o: %.c
    gcc -c $< -o $@

Release/prog Debug/prog:
    gcc $^ -o $@

.PHONY: all
all: Release/prog ; echo $@ Success

.PHONY: debug
debug: Debug/prog ; echo $@ Success

(Отказ от ответственности: не тестировался, даже не пробегал через make.)

Вот так. Это даже -j безопасно, так что вы можете сделать make -j5 all debug. Есть много очевидных котельных плит просто кричала, чтобы прибрались.

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

%-marker:
        @rm -f $(OBJECTS) *-marker
        @touch $@

debug: GCCFLAGS += -ggdb

debug: SOMEOTHERFLAG = WHATEVER

all debug: % : %-marker
        @echo making $@
        @$(MAKE) -S GCCFLAGS='$(GCCFLAGS)' SOMEOTHERFLAG='$(SOMEOTHERFLAG)' main

Есть и другие варианты этой идеи; у вас может быть небольшой файл, содержащий настройки флага, который будет создан файлом makefile и include. Это было бы умно, но не намного чище, чем это.

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