Gcc G++/LD失败:can';当库为'时找不到库;实际上不需要

Gcc G++/LD失败:can';当库为'时找不到库;实际上不需要,gcc,linker,makefile,Gcc,Linker,Makefile,我有一个程序foo我正试图编译和链接,我遇到了一个鸡和蛋的难题 出于下面我将解释的原因,在给定的目录中,我被迫添加到我们构建的几个库的链接(让我们称它们为libA和libB),而不管我的目标是什么。我知道我的程序实际上只需要libA;因此,在构建了所有lib并构建了这个二进制文件之后,我用ldd-u-rfoo进行了验证,以表明libB是一个未使用的直接依赖项 由于未使用,我更改了makefile和标志,使得libB被-Wl--as needed和-Wl--no-as needed封装。我重新生成

我有一个程序
foo
我正试图编译和链接,我遇到了一个鸡和蛋的难题

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

由于未使用,我更改了makefile和标志,使得
libB
-Wl--as needed
-Wl--no-as needed
封装。我重新生成,再次使用
ldd
,这次它不会显示任何未使用的dep。到目前为止还不错

现在有趣的是:由于它没有被使用,我希望如果
libB
没有被找到/可用/构建,那么只要
libA
可用,我仍然能够编译并链接
foo
。(示例:如果我进行了一次新的签出,并且在尝试编译此特定测试之前只构建了
libA
)。但是
ld
错误与
/usr/bin/ld:无法找到-lB

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

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

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

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


我当然可以创建另一个
generictest.mk
类文件用于一些测试,并根据实际的库需求将使用每个文件的文件分组,但如果我不必这么做,只要我说“你不需要所有的文件,你需要每一个文件,但只有在你实际使用它的情况下才需要”.

链接器无法知道不需要该库。即使链接了所有“普通”库,仍然有很多未解析的符号:C运行时库的符号(
printf
,等等)。链接器不知道这些将从何而来

就我个人而言,如果链接器没有抱怨,我会感到惊讶,即使每个符号都已经解决了。毕竟,这里可能有一些奇特的东西在起作用:弱绑定,等等。这可能意味着在链接行后面找到的符号比在前面找到的符号更受欢迎(我不是100%确定这是可能的,但我不会感到惊讶)

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


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

生成文件设计错误,或者是根据现在过时的假设设计的。重新设计它,这样您就不会试图链接到既不存在也不是测试程序所必需的库。另一个选项是确保构建了
libB
——它成为
makefile
(generictest.mk)中目标的显式依赖项。当然,无论如何,它应该是;如果程序与之链接,则程序(或链接命令行)依赖于现有的库。@JonathanLeffler我知道它的设计严重错误。我只是没有能力改变它。我再次同意你所说的一切;但这对我没有帮助。我可以让它依赖于libB,但我不想在不需要libB的时候浪费构建libB的时间。它们不存在只是因为我没有建造它们;在“真实”构建中,它们通常都会存在;如果你不听智慧之言,你将不得不继续在破败建筑的泥潭中溃烂。或者等待天才的智慧出现