带有生成的C ++源文件的Makefile

时间:2018-12-03 23:17:32

标签: makefile gnu-make

我正在使用一种工具,该工具可以生成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.cppbar.cpp,因此SRCS在该时间被编译。

这对我来说似乎很奇怪,因为根据“如何重新制作Makefile”中的GNU Make manual

  

在检查完所有makefile之后,如果实际上已进行了任何更改,make将以干净的开始,并重新读取所有makefile。

因此,在我的第一个main.cpp调用中,GNU Make进程bar.cpp之后,发现它已经过时并进行了构建,我希望它会从头开始 em>并从头开始分析Makefile,包括bar.cpp,并依次使include bar.mk包含makebar.mk

我的期望不对吗?还是我的Makefile(添加)有问题?我在Linux上使用GNU Make 4.1。

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.mkgen/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

但这可能太奇怪了,并且会完全破坏可维护性。首选其他两个选项之一,它们更易于理解。