【问题标题】:G++/LD fails: can't find library when library isn't actually neededG++/LD 失败:实际上不需要库时找不到库
【发布时间】:2014-01-30 16:34:04
【问题描述】:

我有一个程序foo 我正在尝试编译和链接,但我遇到了先有鸡还是先有蛋的困境。

出于我将在下面解释的原因,在给定目录中,我不得不添加指向我们构建的几个库的链接(我们称它们为 libAlibB),而不管我的目标是什么。我知道我的程序实际上只需要libA;所以在构建了所有库并构建了这个二进制文件之后,我用ldd -u -r foo 验证了libB 是一个未使用的直接依赖项。

由于未使用,我更改了 makefile 和标志,使 libB-Wl --as-needed-Wl --no-as-needed 包围。我进行了重建,再次使用ldd,这次它没有显示任何未使用的部门。到目前为止一切顺利。

现在有趣的部分:由于它未使用,我希望如果 libB 未找到/可用/构建,我应该仍然能够编译和链接 foo,只要 libA 可用。 (例如:如果我在尝试编译此特定测试之前进行了新的结帐并且只构建了libA)。但是ld/usr/bin/ld: cannot find -lB 出错

这表明ld 需要找到libB,即使它不需要它提供的任何符号?这似乎没有意义。如果已经满足所有符号依赖项,为什么还要查看这个其他库? (这可以解释 ld 的问题以及为什么这是不可能的)

有没有办法让我说“嘿,如果你找不到这个库,不要抱怨,我们不需要链接它?”

承诺的理由如下
由于我无法控制的各种原因,由于项目 makefile 层次结构,我必须与此目录中的许多其他测试共享 makeflags。所有这些测试都有一个两级生成文件,上面写着foo 是一个虚假目标,他的配方是make -f generictest.mk target=foo,而generictest.mk 只是说源文件是$(target).C,这个二进制文件需要使用每个我们构建的库,指定到我们的根目录的相对路径,然后包含根的通用 makefile。根目录通用 makefile 扩展了所有其他内容(标志、选项、编译器、通过 g++ 自动生成依赖项等),最重要的是,对于在 generictest.mk 中说“使用 libX”的每个语句,它会将 -lX 添加到旗帜(或者在我的情况下,根据需要包裹在旗帜中)

虽然我很清楚在 makefile 最佳实践方面有很多非常不理想和/或非常不正确的事情,但我没有权限/物理能力来更改它。与其他文件夹中使用的替代方法相比,其他文件夹为每个目标制作此 makefile 的单独具体副本,我非常喜欢它;因为这迫使我在想要修改我们的整个制作模式时编辑所有这些,并产生许多其他拼写错误和问题。

我当然可以创建另一个类似generictest.mk 的文件以用于某些测试,并根据实际库需要将使用每个测试的那些组合在一起,但如果我不必这样做,那将是一种整洁,只要我说“你不需要全部,你需要它们中的每一个,但前提是你实际使用它”。

【问题讨论】:

  • makefile 设计错误——或者是根据现在过时的假设设计的。重新设计它,这样您就不会尝试链接那些既不存在也不对所讨论的测试程序不必要的库。另一种选择是确保构建libB——它成为makefilegenerictest.mk)中目标的显式依赖。当然,无论如何,它应该是;如果程序与其链接,则程序(或链接命令行)取决于现有的库。
  • @JonathanLeffler 我知道它的设计严重错误。我只是没有能力改变它。我再次同意你所说的一切;但这对我没有帮助。我可以让它依赖于 libB,但我不想在不需要的时候浪费构建 libB 的时间。它们不存在只是因为我没有建造它们;在“真实”构建中,它们通常都会存在。
  • 好的;如果你不听智慧的话,你将不得不继续在破损建筑的泥沼中溃烂。或者等待一些天才想出一个解决方案。但是最好的办法是不要与编译器和链接器强加的系统作斗争;最好的办法是修复滥用编译器和链接器的工具(即generictest.mk 文件)中的缺陷。你的电话……玩得开心! (“我无法修复”在软件中并不适用;软件具有延展性——这就是它被称为 soft 的原因。如果是当权者在强加规则,请问他们如何解决你的困境。)
  • ?我不反对你。我正在尝试找到一种解决方法来解决我遇到的难题。我无法从头开始更改整个系统;这不在我的权限范围内。如果由我来决定,我会完全按照你的要求去做,而不必问这个荒谬的问题。
  • 软件只有在您的经理和旧版兼容性协议允许的情况下才具有可塑性。仅仅因为它可以改变并不意味着它值得他们花时间;在现实世界中,您经常会发现人们对这种改变的“风险”持怀疑态度,即使您和我都知道这是等待发生的世界末日:-p 欢呼,尽管我认为您重申了我的目前正在使用另一个文件。

标签: gcc linker makefile


【解决方案1】:

链接器无法知道不需要该库。即使在链接了所有“正常”库之后,仍然有很多未解析的符号:C 运行时库的符号(printf 等)。链接器不知道这些将来自哪里。

如果链接器没有抱怨,我个人会感到惊讶,即使每个符号都已被解析。毕竟这里可能有一些花哨的东西在起作用:弱绑定等,这可能意味着在链接行后面找到的符号将优先于之前找到的符号(我不是 100% 确定这是可能的,但我不会感到惊讶)。

至于您的情况,如果您知道不需要该库,您就不能在链接命令行上使用$(filter-out ...) 来摆脱它吗?您必须使用自己的配方为此编写自己的显式规则,而不是使用默认规则,但至少您可以使用所有相同的变量。

或者,也可以使用特定于目标的变量来玩一些技巧。为该目标声明一个特定于目标的变量,该变量将包含“坏库”的变量重置为不包含它的值(可能通过使用$(filter-out ...) 如上所述),它将仅覆盖该目标的该值。有一些微妙的陷阱,目标特定的变量会覆盖“更通用”的变量,但我认为它会起作用。

【讨论】:

  • 谢谢,我正在利用你的第一点,它变成了各种各样的停止问题。
猜你喜欢
  • 1970-01-01
  • 2016-01-18
  • 1970-01-01
  • 2014-12-13
  • 1970-01-01
  • 2012-08-19
  • 2014-12-27
  • 2015-11-14
  • 2023-03-27
相关资源
最近更新 更多