VS2010静态链接问题
我公司最近从VS2005升级到VS2010。我们有一个庞大的项目,其中使用了许多静态链接到 exe 中的模块。但是VS2010中的链接似乎存在一些问题。
为了解释我们的问题,我们构建了一个最小的示例项目,其组成如下图所示:
>是一个使用库 A 中的一个函数的应用程序。库 A 调用库 B 和库 C 各一个函数。这两个库调用库 D 提供的函数。
对于框架下的 Exe 1 和参考文献我们将一切设置为false,除了设置为 true 的链接库依赖项。添加的唯一参考是链接到库 A。对于每个库,所有设置都设置为 false。库 A 仅获取对 B 和 C 的引用,而这两个库仅获取对 D 的引用。 库 D 没有参考文献。
构建应用程序时,它可以正常工作。应用程序注意到库 A 正在使用库 B,库 C 正在使用库 D,因此它知道它也必须链接这些库。这些库链接到 exe 中没有任何问题。
现在我们在库 D 中更改一些内容。只是一点点不同,只有一个字母。现在我们尝试再次构建应用程序,它注意到更改并重新编译库 D,但是:它不再链接到它。结果是 库 B 和 C 中出现链接错误,因为它们使用库 D。我们必须首先运行重建,以便强制完成构建,然后然后所有内容都再次链接。
对于最小的示例和我们的主要项目都会发生这种情况。当然,我们可以添加每个库作为 exe 的附加依赖项,但如果它能像第一次构建项目时一样工作并在代码更改后继续工作,那就太好了。我们注意到,当将“使用库依赖项输入”设置为“true”时,它会再次起作用,但它不会链接 *.lib 文件,而是链接 *.obj 文件。当然不是我们想要的。
有没有人有过类似的经历或者有没有人解决这个问题?这是 VS2010 的错误行为吗?
TIA。
ps:所有库和可执行文件都是本机 C++。
编辑:(解决方法取自此站点)
在文件中%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 的依赖项。
这似乎更像是一种解决方法,而不是解决方案,也许有一种正确的方法来实现隐式链接。
my company has recently upgraded from VS2005 to VS2010. We have a huge project which uses a lot of modules which are being linked statically into the exe. But there seem to be some issues with linking in VS2010.
To explain our problem, we've built a minimal example project which is composed as shown on this graphic:
There is an application using one function from library A. Library A calls one function of each library B and library C. Those two libraries call a function provided by library D.
For Exe 1 under Framework and References we set everything to false except for Link Library Dependencies which is set to true. The only reference added is linking to library A. For each of the libraries all the settings are set to false. Library A gets references to only B and C, as well as those two getting references to D only. Library D has no references.
When building the application it works without problems. The application notices that library A is using library B and C which are using library D, so it knows it has to link those libraries, too. The libs are linked into the exe without problems.
Now we change something in, let's say, library D. Just a little difference, only one letter. Now we try to build the application again, it notices the change and re-compiles library D, but: It doesn't link to it anymore. The result are linking errors in library B and C, because they use library D. We have to run Rebuild first, in order to force the complete building and then everything is linked again.
This happens for both the minimal example as well as for our main project. Of course, we can add each of the libraries as additional dependency for the exe but it would be nice if it would work just like it does when building the project for the first time and continue to work after changes in the code. We noticed that when setting Use Library Dependency Inputs to true, that it works again, but then it doesn't link the *.lib files but the *.obj files which is not what we want of course.
Has anyone made similar experiences or has anyone a solution for this issue? Is this a buggy behavior of VS2010?
TIA.
p.s.: All libraries and executables are native C++.
Edit: (Workaround taken from this site)
In the file %ProgramsFile%\MSBuild\Microsoft.cpp\v4.0\Microsoft.CPPBuild.Targets
there is a line
<Target Name="GetResolvedLinkLibs" Returns="@(LibFullPath)" DependsOnTargets="$(CommonBuildOnlyTargets)">
If you change that line to
<Target Name="GetResolvedLinkLibs" Returns="@(LibFullPath)" DependsOnTargets="$(CommonBuildOnlyTargets);ResolvedLinkLib">
the linking works properly and all needed libs are linked to implicitly. The linker output not only shows lib_a.lib but also all other chained libs, lib_b, lib_c, lib_d without having them added manually as dependencies to the exe.
This seems to be more a workaround then a solution, maybe there is a proper way to achieve implicit linking.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
查看以下链接:
Visual Studio 2010 不会自动链接来自作为依赖项的项目的静态库,因为它应该是这样的
2010 年链接库依赖关系的行为 < /一>
<一href="https://connect.microsoft.com/VisualStudio/feedback/details/638534/unresolved-externals-when-build-a-vc-project-with-chained-static-lib-dependency#details" rel=" nofollow noreferrer">构建具有链式静态库依赖项的 VC++ 项目时未解析的外部
灵活的项目到项目参考文献
Have a look at following links:
Visual Studio 2010 not autolinking static libraries from projects that are dependencies as it should be supposed to
Behavior of Link Library Dependencies in 2010
Unresolved Externals When Build a VC++ Project with Chained Static Lib Dependencies
Flexible Project-to-Project References
我只知道我遇到过类似的情况,因为错误地使用了同名但具有不同架构的库。可以说,我有一个适用于 x86 的 Dll(我们称之为 mydll.dll),并将其导入到我的项目中,它将可以工作。如果我对 x64 dll(同名 mydll.dll)执行相同的操作,它将起作用。
但如果我想包含这两个库,则不允许仅将其重命名为 mydllx86.dll / mydllx64.dll。 我现在可以将这两个库都包含到 Visual Studio 中。 但是当编译它或重新启动 Visual Studio 时,这两个库之一将无法再访问。
在这种情况下,我也许了解一下库架构和使用的命名空间/Api 名称会有所帮助。
问候
I only know that I had such similar situations because of wrong using of Libraries with same name but with different architecture. lets say, I have an Dll (lets call it mydll.dll) for x86 and will import it into my project it will work. If I will do the same with x64 dll (same name mydll.dll) it will work.
But if I want to include both libraries it is not allowed to only rename it into mydllx86.dll / mydllx64.dll. I CAN include now both libraries into Visual Studio. But when compiling it or restarting visual studio, one of both libraries will be unaccessable anymore.
In this case I perhaps it helps to have a look into library architecture and used namespaces / Api names.
Regards
如果您正在修改框架和引用,那么您会在该对话框中迷失方向,这些设置仅适用于托管代码。术语“引用”仅适用于 .NET 程序集。链接器不支持在 .lib 中存储已编译的托管代码。我将假设您实际上正在更改链接器设置。如果您对库 D 进行更改,那么您还必须更改其头文件。这本身就足以重建 B 和 C,因为它们的一个或多个源代码文件应该#include 该标头。
链接库依赖项所做的唯一事情是自动使 .lib 成为依赖项,与链接器 + 输入、附加依赖项设置相同。然而,这需要您显式设置项目依赖项。右键单击 B 项目,单击“项目依赖项”并勾选 D。对 C 重复此操作。对 A 重复此操作并勾选 B 和 C。对 EXE 重复此操作并勾选 A。
这很少是您想要的,它使 D 库嵌入到 B 中和 C 库。 B 和 C 嵌入到 A 中。EXE 现在仅依赖于 A。它可以工作,但它使 .lib 文件变得不必要的强大。 如果您没有正确设置项目依赖项,您就会遇到您所描述的问题,D 的重建不会导致 B 和 C 重新链接。
您应该做的不是在 .lib 之间设置依赖关系,它们没有任何依赖关系。每个库都可以在其他 .lib 不存在的情况下构建。 .lib 只是一包 .obj 文件。所需要做的就是使所有 4 个 .lib 项目成为 EXE 项目的依赖项。这可确保它们在链接器尝试链接 EXE 之前构建。
You are pretty lost in that dialog if you are tinkering with Framework and References, those are settings that only apply to managed code. The term "reference" only applies to .NET assemblies. The linker doesn't support storing compiled managed code in a .lib. I'll work from the assumption that you actually are changing linker settings. If you make a change in library D then you also have to change its header file. Which in itself will be enough to get B and C rebuilt since one or more of their source code files should #include that header.
The only thing that Link Library Dependencies does is automatically make a .lib a dependency, same thing as Linker + Input, Additional Dependency setting. That however requires you to explicitly set the project dependencies. Right-click the B project, click Project Dependencies and tick D. Repeat for C. Repeat for A and tick B and C. Repeat for EXE and tick A.
This is rarely what you want, it makes the D library embedded into the B and C libraries. And B and C get embedded in A. The EXE now only has a dependency on A. It works, but it makes the .lib files unnecessarily beefy. And you have the problem you describe if you don't set the project dependencies properly, a rebuild of D doesn't cause it B and C to be relinked.
What you should do is not set dependencies between the .libs, they don't have any. Each can be built without the other .libs being present. A .lib is nothing but a bag of .obj files. All that's required is that you make all 4 .lib projects dependencies of the EXE project. That makes sure that they are built before the linker tries to link the EXE.
在迁移到 Visual Studio 2015(以及 VS2017)后,我们再次开始看到此问题。该问题似乎仅存在于以下配置中:
解决方案中还有其他几个项目使用 A 和 B。当项目 B 或 C 中的某些内容发生更改时,其中许多项目都会发出 LNK4099 警告。
在我们的例子中,解决方案是使用以下内容:
代码生成>输出文件>程序数据库文件名:$(TargetDir)$(TargetName).pdb
Librarian >一般>输出文件:$(TargetDir)$(TargetName)$(TargetExt)
$(TargetDir) 使用绝对路径与默认的 $(OutDir) > 在我们的例子中这是相对的。似乎正确的路径因多层间接而丢失。
一件有趣的事情是,如果将编译线程数切换为 1,它似乎不会发生(也许 Visual Studio 中存在某种竞争条件?)。
We starting seeing this issue again after moving to Visual Studio 2015 (and also in VS2017). The problem only seems to exist in the following configuration:
There are several other projects in the solution that use A and B. When something in project B or C changes, many of these projects give LNK4099 warnings.
In our case, the solution is to use the following:
Code Generation > Output Files > Program Database File Name: $(TargetDir)$(TargetName).pdb
Librarian > General > Output File: $(TargetDir)$(TargetName)$(TargetExt)
$(TargetDir) uses an absolute path versus the default $(OutDir) which in our case was relative. It seems that the correct path gets lost with multiple levels of indirection.
One interesting thing is if you switch the number of compile threads to 1, it doesn't appear to happen (maybe some kind of race condition within Visual Studio?).