VS2010静态链接问题

时间:2011-06-22 09:14:21

标签: c++ visual-studio visual-studio-2010 linker static-linking

我公司最近从VS2005升级到VS2010。我们有一个庞大的项目,它使用了许多模块,这些模块被静态链接到exe中。但是VS2010中的链接似乎存在一些问题。

为了解释我们的问题,我们构建了一个最小的示例项目,其组成如下图所示:

minimal library example

有一个应用程序使用库A中的一个函数。库A调用每个库B和库C的一个函数。这两个库调用库D提供的函数。

对于框架和参考下的 Exe 1 ,我们将所有内容设置为 false ,但链接库依赖项除外设为true。添加的唯一参考是链接到库A 。对于每个库,所有设置都设置为false。图书馆A只能引用 B C ,以及仅获得 D 的引用。 图书馆D 没有参考资料。

构建应用程序时,它可以正常工作。应用程序注意到库A正在使用库B和C,它们正在使用库D,所以它知道它也必须链接这些库。 libs没有问题地链接到exe。

现在我们改变一些东西,比方说,库D 。只是一点点差异,只有一个字母。现在我们再次尝试构建应用程序,它注意到更改并重新编译库D ,但是:它不再链接到它。结果是链接库B C 中的错误,因为它们使用库D 。我们必须首先运行 Rebuild ,以强制完成整个建筑,然后所有内容都会再次链接。

对于最小示例以及我们的主项目都会发生这种情况。当然,我们可以添加每个库作为exe的附加依赖项,但如果它可以像第一次构建项目时那样工作并且在代码更改后继续工作将会很好。我们注意到,当将使用库依赖项输入设置为 true 时,它再次起作用,但它不会链接* .lib文件,而是链接* .obj文件当然不是我们想要的。

有没有人提出类似的经验或有任何人解决这个问题?这是VS2010的错误行为吗?

TIA。

p.s。:所有库和可执行文件都是本机C ++。


修改(从this site获取的解决方法)

在文件%ProgramsFile%\MSBuild\Microsoft.cpp\v4.0\Microsoft.CPPBuild.Targets中有一行

<Target Name="GetResolvedLinkLibs" Returns="@(LibFullPath)" DependsOnTargets="$(CommonBuildOnlyTargets)">

如果您将该行更改为

<Target Name="GetResolvedLinkLibs" Returns="@(LibFullPath)" DependsOnTargets="$(CommonBuildOnlyTargets);ResolvedLinkLib">

链接正常工作,所有需要的库都隐式链接。链接器输出不仅显示lib_a.lib,还显示所有其他链接库lib_b,lib_c,lib_d,而不是手动添加它们作为exe的依赖项。

这似乎是一种解决方法,然后是解决方案,也许有一种实现隐式链接的正确方法。

4 个答案:

答案 0 :(得分:2)

答案 1 :(得分:0)

我只知道我有类似的情况,因为错误地使用了同名不同架构的库。让我们说,我有一个Dll(让我们称之为mydll.dll)为x86,并将其导入我的项目,它将工作。如果我将使用x64 dll(同名mydll.dll),它将工作。 但是,如果我想要包含这两个库,则不允许仅将其重命名为mydllx86.dll / mydllx64.dll。 我现在可以将两个库都包含在Visual Studio中但是在编译或重新启动visual studio时,其中一个库将不再可用

在这种情况下,我查看库体系结构并使用名称空间/ Api名称可能会有所帮助。

此致

答案 2 :(得分:0)

如果您正在修改框架和参考,那么您很难在该对话框中丢失,这些设置仅适用于托管代码。术语“引用”仅适用于.NET程序集。链接器不支持将编译的托管代码存储在.lib中。我将假设您实际上正在更改链接器设置。如果在库D中进行更改,则还必须更改其头文件。由于其中一个或多个源代码文件应该#include该标题,因此本身就足以让B和C重建。

链接库依赖关系所做的唯一事情是自动使.lib成为依赖项,与链接器+输入,附加依赖项设置相同。但是,这需要您显式设置项目依赖项。右键单击B项目,单击Project Dependencies并勾选D. Repeat for C.重复A并勾选B和C.重复EXE并勾选A.

这很少是你想要的,它使D库嵌入到B和C库中。并且B和C嵌入在A中.EXE现在只依赖于A.它可以工作,但它使.lib文件不必要地变得强大。 如果没有正确设置项目依赖关系,则会遇到您描述的问题,D的重建不会导致B和C重新链接。

你应该做的是没有设置.libs之间的依赖关系,它们没有任何依赖关系。每个都可以在没有其他.lib存在的情况下构建。 .lib只不过是一包.obj文件。所需要的只是您创建EXE项目的所有4个.lib项目依赖项。这确保它们是在链接器尝试链接EXE之前构建的。

答案 3 :(得分:0)

我们在迁移到Visual Studio 2015(以及VS2017)后再次开始看到此问题。该问题似乎只存在于以下配置中:

Project (EXE)
  --> Static Library A (Reference)
    --> Static Library B (Specified in Linker->Additional Dependencies)
      --> Static Library C (Not in solution, specified in Linker->Additional Dependencies)

解决方案中还有其他一些使用A和B的项目。当项目B或C中的某些项目发生变化时,许多项目都会发出LNK4099警告。 在我们的例子中,解决方案是使用以下内容:

代码生成&gt;输出文件&gt;程序数据库文件名: $(TargetDir)$(TargetName).pdb

图书馆员&gt;一般&gt;输出文件: $(TargetDir)$(TargetName)$(TargetExt)

$(TargetDir)使用绝对路径与默认 $(OutDir),在我们的例子中是相对的。似乎正确的路径会因多个间接层而丢失。

一个有趣的事情是,如果将编译线程的数量切换为1,它似乎不会发生(可能是Visual Studio中的某种竞争条件?)。

相关问题