Любой способ использовать переменные в качестве правил и предпосылок в GNU Make? - PullRequest
0 голосов
/ 24 июня 2019

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


ROOT_OBJS= \
    $(B)/main.o \
    $(B)/src1.o

ROOT_SRC= \
    $(SRC)/main.cpp \
    $(SRC)/src1.cpp


$(TARGET) : $(ROOT_OBJS)
    $(LD) $(LD_FLAGS) $^ -o $@


$(ROOT_OBJS) : $(ROOT_SRC)
    $(CXX) $(CFLAGS) $< -o $@

Это в основном работает, за исключением части $< во втором правиле, она всегда использует main.cpp. Есть ли какое-то решение для этого или я поступаю неправильно?

РЕДАКТИРОВАТЬ: для пояснения, это вывод, который я ожидаю:

g++ main.cpp -o main.o
g++ src1.cpp -o src1.o

Это вывод, который я получаю:

g++ main.cpp -o main.o
g++ main.cpp -o src1.o

Я знаю, что это потому, что $< берет первую зависимость, я думал, что make будет достаточно умен, чтобы понять это, потому что мне нужно поведение .o.

$^ это не то, что я ищу. Я хочу, чтобы gcc создавал отдельный объектный файл для каждого файла cpp.

1 Ответ

2 голосов
/ 24 июня 2019

$< всегда принимает предварительное условие first . Поскольку ваше правило расширяется до

$(B)/main.o $(B)/src1.o : $(SRC)/main.cpp $(SRC)/src1.cpp
    $(CXX) $(CFLAGS) $< -o $@

$(SRC)/main.cpp всегда является первой предпосылкой. Нет никакой магической связи между $(B)/main.o и $(SRC)/main.cpp, поскольку make .

Если вы хотите, чтобы ваши правила устанавливали это соединение, вы должны закодировать его в правилах. Есть несколько способов сделать это правильно. Самое простое - написать отдельные правила для каждой цели:

$(B)/main.o : $(SRC)/main.cpp
    $(CXX) $(CFLAGS) $< -o $@
$(B)/src1.o : $(SRC)/src1.cpp
    $(CXX) $(CFLAGS) $< -o $@

Вы также можете использовать шаблонное правило следующим образом:

$(B)/%.o : $(SRC)/%.cpp
    $(CXX) $(CFLAGS) $< -o $@

Здесь $< делает правильные вещи, потому что $(SRC)/%.cpp параметризован с шаблоном, поэтому он расширится до правильного исходного файла.

Самая большая пушка у вас , генерирующая отдельные правила:

STEMS := main src1

$(foreach stem,$(STEMS), \
    $(eval $(B)/$(stem).o: $(SRC)/$(stem).cpp ; $(CXX) $(CFLAGS) $< -o $@))

Здесь я перебираю все слова в $(STEMS) с помощью встроенного вызова функции $(foreach) и генерирую одно правило на итерацию с помощью вызова функции $(eval). Это синтаксис GNU Make, только , другие реализации make, вероятно, не имеют этих функций. Однако это самый общий и гибкий способ сказать make, что делать. Синтаксис вызова функции GNU Make завершен, поэтому вы можете выполнять любые вычисления, которые вам нужны, чтобы придумать правильные правила. Однако читаемость пострадает, поэтому используйте это с осторожностью.

...