【问题标题】:I'm seeing occasional build failure due to auto generated files (automake). How do I create dependencies between autogenerated files?由于自动生成的文件(automake),我偶尔会看到构建失败。如何在自动生成的文件之间创建依赖关系?
【发布时间】:2020-08-16 03:19:53
【问题描述】:

我一直在尝试调试有时会导致 make 构建失败的 makefile.am。在这个文件中,源是自动生成的 .c 文件,头文件是自动生成的 .h 文件。

..._SOURCES = @buildDirectory@/x.c
              @buildDirectory@/y.c
              @buildDirectory@/z.c

..._HEADERS = @buildDirectory@/x.h
              @buildDirectory@/y.h
              @buildDirectory@/z.h

失败是这样的

<failedproto>.proto: "symbol1" is not defined.
<failedproto>.proto: "symbol2" is not defined.
<failedproto>.proto: "symbol3" is not defined.
...
<failedproto>.proto: warning: Import <failedproto>.proto but not used.
make: *** [<failedproto>.c] Error 1
make: *** Waiting for unfinished jobs....

所有这些符号都出现在相应的 .h 中。这让我认为 .c 是在 .h 之前生成的,而且它只是一场直线比赛。我已将 ..._SOURCES 和 _HEADERS 添加到 BUILT_SOURCES,但我仍然看到失败。所以我的下一个直觉是在 .h 上为 .c 创建一个依赖项。我该怎么做,因为它们都是自动生成的?此外,也欢迎任何替代解决方案。

希望我的格式没有混乱。

编辑更多细节:

这些文件由 protoc-c 编译器自动生成:https://github.com/protobuf-c/protobuf-c protoc-c 把这些 .proto 文件,生成 .pb-c.c 和 .pb-c.h 文件,让我觉得这两个毕竟没有依赖关系。还运行一些内部代码,生成其他 .proto 文件,我将它们称为 nameX.proto 和 nameY.proto,它们依次生成 nameX.pb-cc/nameX.pb-ch 和 nameY.pb-cc/nameY .pb-ch Makefile.am 的一个更准确的例子是这样的:

..._SOURCES = @buildDirectory@/name.pb-c.c
              @buildDirectory@/nameX.pb-c.c
              @buildDirectory@/nameY.pb-c.c

..._HEADERS = @buildDirectory@/name.pb-c.h
              @buildDirectory@/nameX.pb-c.h
              @buildDirectory@/nameY.pb-c.h

我一直在尝试跟踪这些依赖关系,我将尝试描述我得出的结论。 nameX.pb-c.c 包含其对应的头文件 nameX.pb-c.h。该标头包含 nameY.pb-c.h,让我认为 nameX.proto 在 nameY.proto 可以编译之前被编译成 nameX.pb-c.c/nameX.pb-c.h。由于 nameX.pb-c.h 和 nameY.pb-c.h 之间存在包含关系,因此构建失败,因为 nameX.pb-c.h 需要 nameY.pb-c.h。这让我想到了两条我从一开始就怀疑的规则。这些规则概括如下:

$(OUT_DIRECTORY)/%nameX.proto:$(SRC_DIRECTORY)/name.proto $(SRC_DIRECTORY)/nameY.proto
        command $(OUT_DIRECTORY) $(FLAGS) $<

$(OUT_DIRECTORY)/%nameX.proto:$(SRC_DIRECTORY)/name.proto 
        command $(OUT_DIRECTORY) $(FLAGS) $<

这可能是个问题吗?如果第二条规则确实需要第一条规则,是什么阻止它运行?

更糟糕的是,许多 .proto 文件都是中间文件(它们是在整个构建过程中生成然后丢弃的),所以我无法查看它们以了解它们的外观。

【问题讨论】:

  • 重要的是要理解,仅仅因为一个源文件(或头文件)包含另一个源文件或头文件,并不意味着它们是 make 的先决条件看法。 Make 只关心需要运行的命令、命令的输出和命令的输入。因此,对于 C 编译器,输出是 object 文件,输入是 all the source/headers,源不依赖于 headers,而是依赖于目标文件在源文件及其所有包含的头文件上。
  • 我不明白为什么您有两个具有相同目标模式的模式规则,以及在先决条件列表中未使用该模式的地方。这些规则中的每一个都说“如果你想构建一个与$(OUT_DIRECTORY)/%nameX.proto 匹配的目标,如果这些先决条件存在或可以构建,你就可以做到”。但是,如果您想构建两个都匹配该模式的目标,make 将运行该规则两次......这可能会生成相同的输出。为什么在这里使用模式规则?
  • “我不明白为什么你有两个具有相同目标模式的模式规则” - 这是一个很好的问题。这个 Makefile 不是我写的,我为修复它的间歇性构建失败而苦恼。这是我第一次深入制作,所以我对作者在这个文件中所做的任何选择都不是非常有信心。当我继承它时,它的形状很糟糕。至于为什么我们有模式规则,是因为Makefile中列出了更多的_SOURCE和_HEADERS。
  • 您显示的错误消息似乎不是来自 C 编译器。我猜它一定是由 protoc-c 发出的。在这种情况下,问题可能根本不在于 make 依赖项,而在于您对 protoc-c 的输入。
  • @JohnBollinger 我同意这是一个 protoc-c 错误。但是,传递给 protoc-c 的文件也是在这个 Makefile 中生成的。所以我想这是我追踪汽车发电菊花链在哪里发生故障的问题......

标签: makefile dependencies protocol-buffers autotools automake


【解决方案1】:

像这样在整个 makefile 中使用 @...@ 替换是非常不寻常的。通常,您会将替换分配给一个 make 变量,然后使用该变量代替(除了“更易于阅读”之外,这允许某人在他们想要的情况下在 make 命令行上覆盖此值):

BUILDDIR = @buildDirectory@

..._SOURCES = $(BUILDDIR)/x.c
          $(BUILDDIR)/y.c
          $(BUILDDIR)/z.c

..._HEADERS = $(BUILDDIR)/x.h
          $(BUILDDIR)/y.h
          $(BUILDDIR)/z.h

另外,在我看来,标准的 automake 变量可能已经涵盖了这个值;如果是这样,最好使用标准的而不是发明新的……但显然,如果不了解您的环境,就无法知道这一点。

无论如何,对于您的问题,我们需要了解有关此自动生成操作的更多信息。你的自动生成规则现在是什么样的?真的是.c文件的生成要等到.h文件生成后才能完成吗?这很不寻常。

如果您列出输出文件、输入文件和所需的命令,那么编写正确的规则就很简单了。

【讨论】:

  • 感谢您在这里表现出一些兴趣,我已经更新了问题的更多细节。
猜你喜欢
  • 2018-02-09
  • 1970-01-01
  • 2023-03-20
  • 1970-01-01
  • 2020-10-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多