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.
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
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
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.
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:
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)
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?).