【问题标题】:Correct way to handle linking in Makefiles?在 Makefile 中处理链接的正确方法?
【发布时间】:2012-03-17 12:06:15
【问题描述】:

我目前正在从事一个项目,其中有大约 20 个 c 源文件和大约 8 个二进制目标。我们发现 Makefile 维护相当困难且容易出错。主要问题是记录哪些二进制文件依赖于哪些目标文件,因为自动头文件依赖解析看起来相当简单(但我们还没有实现它)。

这是我们的 makefile 当前设置方式的示例。两个程序 foo 和 bar。 Foo 需要使用从 timestamp.c 导出的函数,而 bar 需要使用从 pretty_print.c 导出的函数,而后者又使用时间戳函数来生成带时间戳的字符串。

foo bar:
     $(CC) -o $@ $^ $(CFLAGS) $(LIBS)

foo: foo.o timestamp.o
foo.o: timestamp.h   

bar: bar.o pretty_print.o timestamp.o
bar.o: pretty_print.h 

pretty_print.o: pretty_print.h timestamp.h

timestamp.o: timestamp.h

有没有更好的方法来做到这一点(除了自动生成 foo.o 和 bar.o 行)?我觉得好像必须有一种更好的方法,而不是在不包含 timestamp.h 的情况下编写该条取决于 timestamp.o。这实际上是大多数错误的根源。直到链接器找不到符号“create_timestamp”,我们才意识到 pretty_print 依赖于时间戳中的函数。也许这就是它的工作方式?

【问题讨论】:

  • 一个小提示:在目标文件的规则中(例如timestamp.o: 行),您不仅应该将头文件包含在源文件中,还应该包含源文件。所以timestamp.o 的规则如下所示:timestamp.o: timestamp.c timestamp.h
  • 如果您不使用自动跟踪此内容的 IDE 或其他工具(如 automake),那么您很不走运,并且在找到新的依赖项时必须手动编辑正确的 makefile。

标签: c linux dependencies makefile


【解决方案1】:

已经存在像这样在 makefile 中自动生成所需行的脚本。

参见“makedepend”或“mkdepend”——人们通常在实践中这样做。它们随大多数 Unix 版本一起提供,这很常见。

【讨论】:

  • makedepend 将推断 header 依赖项(例如bar.o: pretty_print.h),但不是 linking 依赖项(例如 bar: timestamp.o),这就是 OP 的含义要求。
【解决方案2】:

链接仍然是构建过程中相对传统的部分。添加另一个源文件是一项不常见且相对重量级的任务(创建新的源文件和头文件,添加到源代码管理,添加版权样板)任务,因此自动化添加一个对象的相对琐碎的子任务并没有太大压力文件到几个链接配方。

所以实际上我会用更直接的方式来写这个:

FOO_OBJS = foo.o timestamp.o
foo: $(FOO_OBJS)
    $(CC) $(LDFLAGS) -o $@ $(FOO_OBJS) $(LIBS)

BAR_OBJS = bar.o pretty_print.o timestamp.o
bar: $(BAR_OBJS)
    $(CC) $(LDFLAGS) -o $@ $(BAR_OBJS) $(LIBS)

如果您真的不想担心哪些二进制目标需要哪些杂项目标文件,您可以将目标文件分为与每个二进制目标(@​​987654322@、bar.o 等)对应的规范文件和其他杂项,并将后者放入杂项链接器库中:

foo: foo.o libmisc.a
    $(CC) $(LDFLAGS) -o $@ foo.o libmisc.a $(LIBS)

bar: bar.o libmisc.a
    $(CC) $(LDFLAGS) -o $@ bar.o libmisc.a $(LIBS)

MISC_OBJS = pretty_print.o timestamp.o
libmisc.a: $(MISC_OBJS)
    -rm -f $@
    $(AR) rc $@ $(MISC_OBJS)
    -$(RANLIB) $@

然后链接每个二进制目标(@​​987654325@、bar)只会拉入它需要的各种目标文件。

【讨论】:

  • 谢谢,有道理。一个可以放置所有东西的杂项库似乎是一种简单的方法。创建共享库而不是 .a 文件有意义吗?
  • @Chris - .a 文件是共享库。这些对象一起归档到 libmisc.a 中,然后链接器只提取链接期间需要的文件。
  • @Alex:不,.a 文件是一个 静态 库。 Chris 询问是否部署一个 .so 库,而像往常一样,答案是“它取决于”。如果有很多二进制目标经常同时运行,每个目标都使用很多杂项目标文件,那么总内存使用量会有所减少。如果二进制文件使用杂项对象的小的不相交子集(不太可能),那么它就不值得了。除非所有二进制文件都打包并安装在一起,否则我不会梦想有一个共享库,因为您会无缘无故地购买版本控制问题。否则,也许。
【解决方案3】:

我自己从未尝试过,但要列出链接依赖项,您可以使用 nm 和一些简单的文本后处理。

【讨论】:

    猜你喜欢
    • 2018-01-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-30
    • 2023-03-05
    • 1970-01-01
    • 2023-01-17
    相关资源
    最近更新 更多