Delen via


Having common intermediate directory causes all project targets to be deleted

While debugging one of my customers’ scenarios, we came across an interesting issue were if we ‘rebuild’ the application we get a warning for a missing file, and for the same application when we ‘build’ everything works fine.

All this occurs only in VS2010 and not in the earlier versions of Visual Studio. To understand what went wrong, like anybody would do, the first approach was to use procmon and compare the file creation/deletion activity.

For the purpose of explaining this scenario, I created a sample application, App.exe that depends on a dll, lib.dll . I did make changes to project settings such that both the projects have a common intermediate directory. (Btw, this works fine in VS2005,VS2008 )

Rebuilding the sample I created in VS2010 IDE, I did see that it throws a linker error 2>LINK: fatal error LNK1104: cannot open file '.\abc\Projects\App\Debug\lib.lib'

Again, Building the application, both projects were built successfully and all worked absolutely fine.

Snip from the procmon log when Rebuilding(failing) the application;

 

This is how the intermediate Directory for both the projects looks;

 

So the reason for the failure was because of the deleted file. While we have the above snip, it was not obvious in the beginning and took some time for us to come to this point.

The mystery of MSBuild deleting the file in VS2010 but not in earlier versions of Visual Studio was identified to be a design change in VS2010. More specifically, with VS2010, the Intermediate directory cannot be same for all the referenced projects in the solution. 

If accidentally, the intermediate directory is same, we will notice a warning/error about missing files depending on the respective project.

The snips I pasted above are only to show the failure and what you can look for when we have such a scenario. The takeaway for us was the “by design” change in VS2010 in which we cannot have same folder for the intermediate directory for projects in the solution. This issue might be prominent when porting from an earlier version of VS to VS2010.

Now, you know what to do if you happen to face such a situation while developing an application !!!

 

^Ganesh Shankaran

  Technical Lead | Microsoft Developer Support | Visual C++, C#, CLR

Comments

  • Anonymous
    July 14, 2014
    Same problem/feature in VS2012.  If the intermediate directories are the same for multiple projects within a  solution, dependent target outputs (located in directories different than the immediate directories) will be deleted.

  • Anonymous
    July 19, 2014
    Yes. This is by design, and will continue to be so for the foreseeable future.  In general, it's considered a mistake to share an intermediate folder with another project.

  • Anonymous
    July 25, 2014
    "In general, it's considered a mistake to share an intermediate folder with another project." Then how about some kind of warning when this happens? It looks like the Cleaning action looks at the log files in the intermediate directory and cleans whatever was written by the last project that finished building into it. So when project A is finished and project B starts its rebuild, the outputs of A are removed. How about making the log files in the intermediate directory more project-specific (like "myprojectname.cl.write.log") so that the files don't conflict?

  • Anonymous
    October 29, 2014
    We developed a major project that mixed many (100+) projects in a common directory.  The advantage is, we didn't need lots of project updates to add LIBs (DLLs) sub-directories to lots of projects.  This change is an major change to the way C++ has operated since the introduction of Windows NT.  Don't know why MS changed this unless they had dumbed down their developers but taking away features like this only leads to (me) and others looking for alternative C++ compliers.  Consistency, right or wrong, is important when upgrading to newer versions.  I guess, lots of C++ developers will live with older versions until Microsoft realizes stuff like this IS very important.

  • Anonymous
    October 29, 2014
    The OBjs are for a project are listed in the project files.  In the past, the older versions (like C++ 2008) would know what OBJs and other files were part of a project and remove only those part of it.  Again, I guess this was "too difficult of a task" for the current C++ complier developers.  PLEASE bring back the group from C++ 2008 and older versions who realized this was not a hard thing to do (Interesting that the MSDN comments are just..... "That's the way things will be in the future..."  sounds too much like a politician trying to sell me a bridge....).

  • Anonymous
    October 29, 2014
    This is not the result of any "dumbing down" or removal of a feature because it was "too difficult" for our developers.  In fact, quite a few of the current Visual C++ development team has been around for many years, and they have made good improvements to the product.  I would never choose to go back to VC++ 2008, because there are so many good features introduced in later versions.  It is a poor design to mix the intermediate files of multiple projects, and I'm sorry that you believe otherwise.  I agree with "Just Sayin'" that it would be good to emit some warning if this is detected.  My earlier reply was not political spin; it was my way of saying that we believe this is how it should be.  If there is a substantial number of people who disagree, as you do, I would be interested in seeing some more intelligent debate on the topic.

  • Anonymous
    November 19, 2014
    Any suggestion regarding what to do for dlls.  I have one project creating a dll which is used by another project.  In order for the second project's executable to run find the first project's dll, they use the same output directory.  However upon building the second project, the dll from the fist project gets "cleaned"

  • Anonymous
    November 19, 2014
    There's a difference between a shared "Output" directory and a shared "Intermediate" directory.  Sharing Output directory is GOOD, sharing Intermediate directory is BAD.

  • Anonymous
    December 25, 2015
    Scott, The rationale for why a shared "intermediate" folder is a bad "design" is not provided. One reason I can think of is that source files in different projects might have the same names.  In my case, I've made sure that they don't.  However, I still don't need to have a "shared" intermediate folder, but there is a very good reason to have Intermediate files not mixed in with source files:  That way, we can tell how many MBs our source files add up to, and they can be quickly copied, searched, etc. So, we tried to change the Intermediate folder to:  DevIntermediate$(Platform)$(ProjectName)$(Configuration) This should work, correct?  If not, why even provide the ability to change the intermediate folder?  Have you or anyone ever tested this feature? So, with Visual C++ 2015, it looks to me like making this change, even though Intermediates are NOT in a shared folder, will result in lost of functionality, specifically, debugging no longer works.   I could be wrong about exactly what is causing it.  I've been going back in source control history to figure it out, but this is what it looks like to me.

  • Anonymous
    December 26, 2015
    Scott, To clarify my previous comment.  It was changing the Precompiled Header Output File from .Debug$(TargetName).pch to $(IntDir)$(TargetName).pch, while the Intermediate folder is set to DevIntermediate$(Platform)$(ProjectName)$(Configuration). This configuration causes breakpoints to not be hit in the associated project.  How can I achieve the goal of having all Intermediate files be outside the source folder area?

  • Anonymous
    December 26, 2015
    Also, in order to break it, I had to change the Program Database File Name from $(IntDir)vc$(PlatformToolsetVersion).pdb to $(IntDir)$(ProjectName).pdb

  • Anonymous
    December 26, 2015
    Also, in order to break it, I think I had to change the Program Database File Name from $(IntDir)vc$(PlatformToolsetVersion).pdb to $(IntDir)$(ProjectName).pdb