在 GNU Make 中使用变量作为规则和先决条件的任何方法?
Any way to use variables as rules and prerequisites in GNU Make?
我正在尝试设置我的 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 文件制作一个单独的目标文件。
$<
总是先满足 先决条件。由于您的规则扩展为
$(B)/main.o $(B)/src1.o : $(SRC)/main.cpp $(SRC)/src1.cpp
$(CXX) $(CFLAGS) $< -o $@
$(SRC)/main.cpp
始终是第一个先决条件。 就make
而言,$(B)/main.o
和$(SRC)/main.cpp
之间没有神奇的联系。
如果您希望您的规则建立这种联系,您必须将其编码到规则中。有几种方法可以做到这一点。最直接的方法是为每个目标编写单独的规则:
$(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 $@))
在这里,我使用 $(foreach)
内部函数调用循环遍历 $(STEMS)
中的所有单词,并使用 $(eval)
函数调用每次迭代生成一个规则。 这是 GNU Make 语法,仅,其他 make
实现可能没有这些功能。然而,这是告诉 make
做什么的最通用和灵活的方式。 GNU Make 的函数调用语法是图灵完备的,因此您可以执行任何需要的计算以得出正确的规则。但是,可读性会受到影响,因此请谨慎使用。
我正在尝试设置我的 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 文件制作一个单独的目标文件。
$<
总是先满足 先决条件。由于您的规则扩展为
$(B)/main.o $(B)/src1.o : $(SRC)/main.cpp $(SRC)/src1.cpp
$(CXX) $(CFLAGS) $< -o $@
$(SRC)/main.cpp
始终是第一个先决条件。 就make
而言,$(B)/main.o
和$(SRC)/main.cpp
之间没有神奇的联系。
如果您希望您的规则建立这种联系,您必须将其编码到规则中。有几种方法可以做到这一点。最直接的方法是为每个目标编写单独的规则:
$(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 $@))
在这里,我使用 $(foreach)
内部函数调用循环遍历 $(STEMS)
中的所有单词,并使用 $(eval)
函数调用每次迭代生成一个规则。 这是 GNU Make 语法,仅,其他 make
实现可能没有这些功能。然而,这是告诉 make
做什么的最通用和灵活的方式。 GNU Make 的函数调用语法是图灵完备的,因此您可以执行任何需要的计算以得出正确的规则。但是,可读性会受到影响,因此请谨慎使用。