【发布时间】:2026-01-16 01:05:02
【问题描述】:
我正在使用一个生成 C++ 源文件的工具,我需要将这些文件包含在我的 C++ 项目编译中。
为了特别简化,我的一个非生成源文件main.cpp如下:
extern void bar();
int main(int, char**)
{
bar();
return 0;
}
下面是我的Makefile。整体结构是我们项目中已经存在的,我只是添加了生成所需源文件bar.cpp和makefilebar.mk的部分,这将bar.cpp添加到SRCS变量中,所以它(我希望)被包含在编译中:
SRCS := $(CURDIR)/main.cpp
#################### Adding everything between here... #####
BAR_MK := bar.mk
ifeq (,$(findstring clean,$(MAKECMDGOALS)))
include $(BAR_MK)
endif
#################### ...and here ###########################
OBJ_DIR := $(CURDIR)/obj
OBJS := $(patsubst %.cpp,%.o,$(subst $(CURDIR),$(OBJ_DIR),$(SRCS)))
a.out: $(OBJS)
@echo OBJS == $(OBJS)
@echo SRCS == $(SRCS)
$(CXX) $(OBJS)
#################### Adding everything between here... #####
GEN_DIR := $(CURDIR)/gen
# "Generate" my source file(s), add them to SRCS via an external makefile
$(BAR_MK): $(GEN_DIR)/bar.cpp
$(GEN_DIR)/bar.cpp:
mkdir -p $(dir $@)
echo "void bar () {}" > $@
echo SRCS += $@ > $(BAR_MK)
#################### ...and here ###########################
$(OBJ_DIR)/%.o: %.cpp
mkdir -p $(dir $@)
$(CXX) -c -o $@ $<
clean:
rm -rf $(OBJ_DIR)
rm -f a.out
rm -rf $(GEN_DIR)
rm -f $(BAR_MK)
问题是,由于“未定义对bar() 的引用”,我第一次运行make 时编译失败,但随后立即运行make 成功。这是因为在make 第一次运行时,当它评估a.out: 规则时,它看到SRCS 只包含main.cpp,因此bar.cpp 不会被编译。然后在第二次(和后续)运行中,SRCS 包含 main.cpp 和 bar.cpp,因此 bar.cpp 在那个时候被编译。
这对我来说似乎很奇怪,因为根据“如何重制 Makefile”中的 GNU Make manual:
检查完所有 makefile 后,如果确实有任何更改,make 从一个干净的状态开始并重新读取所有 makefile。
因此,在 GNU Make 在我的第一次 make 调用中处理 include bar.mk 后,发现它已过时并构建它,我希望它会重新开始从头开始进行解析Makefile 从一开始就包含bar.mk,而SRCS 又包含main.cpp 和bar.cpp。
我的期望错了吗?或者我的(添加到)Makefile 有什么问题吗?我在 Linux 上使用 GNU Make 4.1。
【问题讨论】: