2012-05-07 2 views
3

Я получил следующую структуру каталогов:комплекс схему замещения в Makefile предпосылки

./ 
|- obj/ 
|--- debug/ 
|--- release/ 
|- bin/ 
|--- debug/ 
|--- release/ 
|- src/ 
|--- main.c 
|--- libb/ 
|----- foo.c 
|- include/ 
|--- libb/ 
|----- foo.h 

Кроме того, я вручную указать зависимости отдельных объектов в моем Makefile в следующем формате (пример):

main_DEPS = libb/foo 

Теперь я хочу, чтобы иметь возможность вводить make bin/debug/main, и это создает необходимые зависимости и целевой файл:

  • obj/debug/libb/foo.o
  • obj/debug/main.o
  • bin/debug/main

Как я могу это сделать? Моего текущий подход крайне запутанный и неполный:

  • Следующие создают объектные файлы. Однако он не создает никаких необходимых подпапок (libb), если они еще не существуют. Он также не отслеживает любые измененные файлы заголовков. Возможно, можно было настроить Makefile tutorial trick to generate prerequisites automatically?

    CFLAGS+=-I include 
    
    obj/*/%.o: src/%.cpp 
        $(CC) $(CFLAGS) $< -c -o [email protected] 
    
  • Следующие попыток разрешить зависимости бинарной и построил его из всех необходимых объектных файлов. Но я не знаю, как получить эти объектные файлы из переменной *_DEPS.

    .SECONDEXPANSION: 
    
    bin/debug/%: obj/debug/%.o $(patsubst %,obj/debug/%.o,$($(patsubst bin/debug/%,%,[email protected])_DEPS)) 
        $(LD) $(LDFLAGS) $< $(patsubst %,obj/debug/%.o,$($(patsubst bin/debug/%,%,[email protected])_DEPS)) -o [email protected] 
    
    bin/release/%: obj/release/%.o $(patsubst %,obj/release/%.o,$($(patsubst bin/release/%,%,[email protected])_DEPS)) 
        $(CXX) $(LDFLAGS) $< $(patsubst %,obj/release/%.o,$($(patsubst bin/release/%,%,[email protected])_DEPS)) -o [email protected] 
    

    К сожалению, это не не создает зависимостей автоматически: он просто жалуется на «объект/отладки/libb/foo.o: Нет такого файла или каталога» - но она работает достаточно странно, если бы я построил этот файл вручную с помощью mkdir obj/debug/libb; make obj/debug/libb/foo.o.

    Он также безнадежно усложняется и использует бесплатное дублирование кода (от которого я не могу избавиться, не сделав его еще более сложным).

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

ответ

2

Update в ответ на chat message

@sehe Это делает его немного легче, да ... но дублирование все еще существует, и проблема не построения зависимостей, а

Я нашел многословный, но эффективный (не сложный) способ заставить его работать с вызовами подкачки (в одном файле Makefile).

У нас есть «внешний макияж», который содержит только одно правило и определение зависимостей

A_DEPS=dep1 dep2 
C_DEPS=dep2 

########################## 
# "outer" Make 
bin/%/A bin/%/B bin/%/C: 
    $(MAKE) BUILD="$*" TARGET=$(@F) DEPS="$($(@F)_DEPS)" GENRULE 

В сущности, мы переводим «выводили» информацию в явное переменные на суб-вызов, чтобы сделать. Остальная часть Makefile содержит определение нашего 'общего целевого правила', GENRULE:

########################## 
# "inner" Make 

%/*.o: 
    mkdir -p "$(@D)" && touch "[email protected]" 

GENRULE: obj/$(BUILD)/$(TARGET).o $(DEPS:%=obj/$(BUILD)/%.o) 
    echo gcc -o "bin/$(BUILD)/$(TARGET)" $^ 
    mkdir -p "bin/$(BUILD)" && touch "bin/$(BUILD)/$(TARGET)" 
.PHONY: GENRULE 

Снова тестовый прогон:

$ for target in bin/{debug,release}/{A,B,C}; do make -Bs "$target"; done 

gcc -o bin/debug/A obj/debug/A.o obj/debug/dep1.o obj/debug/dep2.o 
gcc -o bin/debug/B obj/debug/B.o 
gcc -o bin/debug/C obj/debug/C.o obj/debug/dep2.o 
gcc -o bin/release/A obj/release/A.o obj/release/dep1.o obj/release/dep2.o 
gcc -o bin/release/B obj/release/B.o 
gcc -o bin/release/C obj/release/C.o obj/release/dep2.o 

Объектов все были созданы:

$ find bin obj 

bin 
bin/debug 
bin/debug/A 
bin/debug/B 
bin/debug/C 
bin/release 
bin/release/A 
bin/release/B 
bin/release/C 
obj 
obj/debug 
obj/debug/A.o 
obj/debug/B.o 
obj/debug/C.o 
obj/debug/dep1.o 
obj/debug/dep2.o 
obj/release 
obj/release/A.o 
obj/release/B.o 
obj/release/C.o 
obj/release/dep1.o 
obj/release/dep2.o 

Для простых переменных (без зависимостей) здесь ' s простой пример с использованием автоматических переменных $ @ и $ (@ F) :

EXTRA="--standardopts" 
A_FLAGS="--a-opts" 
B_FLAGS="--b-opts" 

.SECONDEXPANSION: 

debug/% release/%: EXTRA+=$($(@F)_FLAGS) 

%/A %/B %/C: 
    echo building [email protected] with $(EXTRA) 
Смежные вопросы