我正在使用一种工具,该工具可以生成C ++源文件,而这些文件需要包含在C ++项目编译中。
为了极大简化,我的一个未生成的源文件topshelf
如下:
<behaviors>
<serviceBehaviors>
<behavior name="MetaDataBehvior">
<serviceMetadata />
</behavior>
<behavior>
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<netTcpBinding>
<binding name="NetTcpBinding" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" transactionFlow="false" hostNameComparisonMode="StrongWildcard" maxBufferPoolSize="524288" maxReceivedMessageSize="2147483647">
<readerQuotas maxDepth="32" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
<reliableSession ordered="true" inactivityTimeout="00:10:00" enabled="false" />
<security mode="Transport">
<!--Transport security is enabled Because all machinses on the same Domain (intranet) -->
<!-- http://www.karthikscorner.com/sharepoint/wcf-transport-security/ -->
<!--Transport security is enabled-->
<transport clientCredentialType="Windows"
protectionLevel="EncryptAndSign" />
</security>
</binding>
</netTcpBinding>
</bindings>
我的main.cpp
在下面。总体结构是我们项目中已经存在的结构,我只是添加了指出的部分以生成所需的源文件extern void bar();
int main(int, char**)
{
bar();
return 0;
}
和makefile Makefile
,从而将bar.cpp
添加到{ {1}}变量,以便(希望)它包含在编译中:
bar.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)
成功。这是因为在make
的第一次运行时,当它评估bar()
规则时,会发现make
仅包含make
,因此a.out:
不会不能编译。然后在第二次(及后续)运行中,SRCS
同时包含main.cpp
和bar.cpp
,因此SRCS
在该时间被编译。
这对我来说似乎很奇怪,因为根据“如何重新制作Makefile”中的GNU Make manual:
在检查完所有makefile之后,如果实际上已进行了任何更改,make将以干净的开始,并重新读取所有makefile。
因此,在我的第一个main.cpp
调用中,GNU Make进程bar.cpp
之后,发现它已经过时并进行了构建,我希望它会从头开始 em>并从头开始分析Makefile,包括bar.cpp
,并依次使include bar.mk
包含make
和bar.mk
。
我的期望不对吗?还是我的Makefile(添加)有问题?我在Linux上使用GNU Make 4.1。
答案 0 :(得分:1)
以bar.mk
为目标的规则没有配方。因此,make认为无法生成丢失的bar.mk
。但是它并不会立即失败,它会继续解析主Makefile,生成bar.cpp
...和bar.mk
,但是它无法提前知道这一点。结果是生成了bar.mk
但未包括在内...并且make不会失败。不确定是否应将其视为错误。我填写了一个也许是错误的报告。
无论如何,如果您明确告诉make如何构建bar.mk
,它应该可以工作:
$(BAR_MK): $(GEN_DIR)/bar.cpp
echo 'SRCS += $<' > $@
$(GEN_DIR)/bar.cpp:
mkdir -p $(dir $@)
echo "void bar () {}" > $@
编辑:添加更多评论/其他解决方案
请注意,$(BAR_MK)
规则仍然不完善:它声明的先决条件不是真实的。但是在删除它之前,我们必须修复其他问题:由于使用了$(CURDIR)
作为前缀,因此您的模式规则将与生成的源文件不匹配。让我们摆脱它:
SRCS := main.cpp
BAR_MK := bar.mk
ifeq (,$(findstring clean,$(MAKECMDGOALS)))
include $(BAR_MK)
endif
OBJ_DIR := obj
OBJS := $(patsubst %.cpp,$(OBJ_DIR)/%.o,$(SRCS))
a.out: $(OBJS)
@echo OBJS == $(OBJS)
@echo SRCS == $(SRCS)
$(CXX) $(OBJS)
GEN_DIR := gen
$(BAR_MK):
echo 'SRCS += $(GEN_DIR)/bar.cpp' > $@
$(GEN_DIR)/bar.cpp:
mkdir -p $(dir $@)
echo "void bar () {}" > $@
$(OBJ_DIR)/%.o: %.cpp
mkdir -p $(dir $@)
$(CXX) -c -o $@ $<
clean:
rm -rf $(OBJ_DIR) a.out $(GEN_DIR) $(BAR_MK)
最后,如果您确实想使用相同的规则生成bar.mk
和gen/bar.cpp
,则有一种可能性仍然会告诉make:a pattern rule with multiple targets:
模式规则可能有多个目标。与正常规则不同, 不能以相同的先决条件执行许多不同的规则,并且 食谱。如果模式规则有多个目标,请确保 规则的配方负责制定所有目标。食谱 仅执行一次即可创建所有目标。当寻找一个 匹配目标的模式规则,其他规则的目标模式 而不是与需要规则的目标相匹配的目标: 只需为文件提供配方和前提条件即可 目前有问题。但是,运行此文件的配方时, 其他目标被标记为自身已更新。
以下是与模式规则的通配符匹配的a
中的bar
:
PATTERN_TARGET := $(subst bar,b%r,$(BAR_MK) $(GEN_DIR)/bar.cpp)
$(PATTERN_TARGET):
mkdir -p $(GEN_DIR)
echo "void bar () {}" > $(GEN_DIR)/bar.cpp
echo 'SRCS += $(GEN_DIR)/bar.cpp' > bar.mk
但这可能太奇怪了,并且会完全破坏可维护性。首选其他两个选项之一,它们更易于理解。