Visual Studio Rebuilds unmodified projects

做~自己de王妃 提交于 2019-12-17 15:26:51

问题


So, as the title reads, I have a VS2010 solution with ~50 projects in it right now. If I make a change to a "top level" project that nothing references then VS still rebuilds all 50 projects. I'm running Visual Studio 2010 Ultimate without any add-ons. I am using ILMerge to consolidate all of the projects into a single file.

I have verified this by checking the time stamps of the lower level dlls and see that they are indeed rebuilt even though their code wasn't touched.

I've read all responses and comments for:

Visual Studio 2008 keeps rebuilding

Visual studio keeps building everything

Strange VS2010 build glitch occurs in my solution

Reasons for C# projects to rebuild in Visual Studio

But most of them just offer suggestions on unloading projects to speed up build times but nothing concrete as to a fix. I'm trying to figure out why VS thinks these dependent projects need to be rebuilt when they don't and fix it.

I've turned on 'Tools > Options > Projects and Solutions > Build and Run > Only build startup projects and dependencies on run' but with no effect.

Also, if I just rebuild a "mid-level" project that only has 8 (in)direct dependencies then it still builds all 8 projects even though ILMerge isn't invoked and none of the dependent projects have been modified.

Thank you everyone for any insight you may be able to provide.

Added

To test some of the suggestions I created a new WinForms project from scratch. I then created two new projects inside that solution. I copied all of the code and resources (not project file) from my two 'lowest level' projects into the two brand new projects (I did this by dropping the files and folders from Explorer onto the project in Visual Studio).

The lowest project, let's call it B, did not reference any other project. The next project, A, referenced B only. So once I added the required .NET and external assembly references to the projects then the solution would build.

I then had my new WinForm project reference A and did a full build. So the ref chain is:

WinForm -> A -> B

I then modified WinForm only and did a standard build (F6). As before, Visual Studio rebuilt all three projects.

After some systematic eleminiation of source files in project B I found that if I removed my Resources.Designer.cs and Resources.resx (and commented out the code that made use of the .Properties.Resources object of those resources) then a modification of WinForm would no longer rebuild the entire solution and would only rebuild WinForm.

Adding the Resources.resx and Resources.Designer.cs back to project B (but leaving the referenced code commented out so that nothing was making use of the resources) would re-introduce the full build behavior.

To see if perhaps my resource files were corrupted, I deleted them again and then created a new one (via Project Properties -> Resources) and re-added the same resource as before, which was a single Excel file. With this setup the full rebuild would still occur.

I then removed the single resource, but left the resource file in project B. Even with no resources added, but the resource file still in the project, the full (unneeded) rebuild would occur.

It appears that just having a resource file added to a (.NET 3.5) project will cause Visual Studio 2010 to always rebuild that project. Is this a bug or intended/expected behavior?

Thanks all again!


回答1:


Open Tools - Options, select Projects and Solutions - Build and Run in tree, then set "MSBuild project build output verbosity" to Diagnostic. This will output the reason for building a project, i.e.

Project 'ReferencedProject' is not up to date. Project item 'c:\some.xml' has 'Copy to Output Directory' attribute set to 'Copy always'.

or

Project 'MyProject' is not up to date. Input file 'c:\ReferencedProject.dll' is modified after output file 'c:\MyProject.pdb'.

In this case the fix is to copy some.xml only if newer.

Pre and post build events can trigger build as well.




回答2:


While I don't think this is a fix, it is a workaround that has worked for my situation...

I originally had about 5 projects out of 50 that contained a Resources section. These projects would always be rebuilt and thus anything that they depended on would also be rebuilt. One of those 5 projects was a "base" level library that 48 of the other projects referenced, thus 96% of my project would be rebuilt every time even if it didn't need it.

My workaround was to use dependency injection, interfaces, and a dedicated "Resources" project. Instead of having those 5 projects reference their own Resources object, I created an interface in each project that would supply the desired resources. Then, the classes that needed those resources would require that interface be passed in during their creation in the constructor (constructor injection).

I then created a separate "Resources" project that had an actual Resources section like normal. This project only contained the resources themselves, and a class for each interface that was needed to provide those resources via an interface. This project would reference every other project that had a resource dependency and implement the interface that the project needed.

Finally, in my "Top Level" project which nothing referenced (and where the exe was actually built and my composition root lives) I referenced the "Resources" project, wired up the DI, and away we went.

This means that only two projects (the "Resources" and the "Top Level") will be rebuilt every time, and if I do a partial build (Shift-F6) then they won't get rebuilt at all.

Again, not a great work around, but with 48 projects being built every time a build would take about 3 minutes, so I was losing 30 to 90 minutes a day with needless rebuilds. It took awhile to refactor, but I think it was a good investment.

Here is a simplified diagram. Note that the dependencies from Main.exe to Proj1 and Proj2 are not shown in order to reduce clutter.

With this design, I can do a build of Proj1 or Proj2 without triggering a full rebuild, since they don't have any dependencies on a Resources section. Only Main knows about the Resources implementation.




回答3:


This happens when a project has a file that doesn't really exist.
The project can't determine if the file was changed (because it's not there) so it rebuilds.

Simply look at all the files in the project, and search for the one that doesn't have an expandable arrow near it.




回答4:


I had the same issue in VS 2015.

What did the trick for me is:

  1. One project was referencing itself copy in some other project bin (magic, yes). This kind of stuff could be found when switching to diagnostic build output (in build options) and then trying to build projects one by one from the top of projects hierarchy - if you see the project that rebuilds even if nothing has been changed then see it's references.
  2. I've changed all "copy always" files in all projects to "copy if newer". Basically, in all .csproj files replace <CopyToOutputDirectory>Always</CopyToOutputDirectory> to <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
  3. Then I've disabled NTFS tunneling as described in this article with this powershell script:

New-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem" -Name "MaximumTunnelEntries" -Value 0 -PropertyType "DWord"

After that I needed on rebuild and it seems working for now.




回答5:


In my case the culprit was "Copy Local" setting of a referenced dll set to true and "Copy to Output Directory" setting a file set to Copy always.




回答6:


The MSBuild team is collecting documentation about investigating build incrementality issues here: https://github.com/Microsoft/MSBuild/wiki/Rebuilding%20when%20nothing%20changed




回答7:


I've finally found one more culprit that I had hard time finding by increasing the build log verbosity.

In some cases, MSBuild looks for vc120.pdb in the output folder, and if this file doesn't exist, it will rebuild the entire project. This occurs even if you have disabled debug symbol generation.

The workaround here is to enable debug symbols and let this file get generated, then disable the setting again without deleting the PDB file.




回答8:


I had this same problem and it turned out to be related to a couple of project that had a copy local reference to a dll in their own output directory.

The key to finding this was having diagnostic output set for the build output, but also knowing what to look for in the log. Searching for: 'not up to date' was the key.




回答9:


Here is an answer from VS2010 always rebuilds solution?

This issue is solved by changing the project files, cleaning solution, deleting all bin folders by hand, restarting Visual studio and rebuilding everything.




回答10:


Based on your observations, it sounds like you have projects expressing dependencies to other projects in a way that isn't obvious. It is possible for orphaned dependencies to remain in project files without being apparent in the UI. Have you looked through a misbehaving project file after opening it in a text editor? Checked solution build dependencies?

If you're not able to spot anything, try recreating one of your projects from scratch to see if the new project exhibits the same problem. If the clean project builds correctly, you'll know that you have unwanted dependencies expressed somewhere. As far as I know, these would have to be in the project file(s) or the solution file, unless you have makefiles or other unusual build steps.




回答11:


I had the same issues with you. I found that it came from some deleted files. When I had removed the files from my project, the issues was gone. Regards.




回答12:


For this category of build problems setting MSBuild output verbosity to 'diagnostic' is indeed a necessary first step. Most of the time the stated reason for the re-builds would be enough to act upon, BUT occasionally MSBuild would erroneously claim that some files are modified and need to be copied.

If that is the case, you'd need to either disable NTFS tunneling or duplicate your output folder to a new location. Here it is in more words.




回答13:


Another problem that frequently happens is when some item in your solution has a modified stamp that is in the future. This can happen if you set your clock forward, and then set your clock to the correct time. I had this happen while installing Linux.

In this case you can recursively touch all the files using git bash (yes, in Windows):

find . -exec touch {} \;



回答14:


I had the problem of Visual Studio rebuilding projects when upgrading from Visual Studio 2015 to 2017 and I add this answer for the benefit of those who might experience similar problems, as it does not seem to be documented anywhere.

In my case, the problem was that all projects in the solution had the same intermediate Output path (obj). The file GeneratedInternalTypeHelper.cs gets generated by all projects containing XAML. Up to Visual Studio 2015, the build process apparently did not check for the file date of this file and thus no problem with it occurred. With VS2017 the file date of this file is checked and because a later project in the build process will overwrite it (with the same content), the earlier project will re-build, re-triggering the later build, ad infinitum.

The solution in this case is to ensure that all projects have differing intermediate output directories, which will make the problem go away.




回答15:


In my case (mixed C#, C++/CLI and native C++ solution) , some C++ projects were being re-linked even if nothing had changed. I spent ages trying to work out what was happening. In the end I worked out from the "Command Line" option that the PDB output path (option /Fd) could not handle the folder setting $(IntDir). I removed that - an empty value will do the default correctly - and my issue went away.




回答16:


As others have noticed, a likely reason is that CopyToOutputDirectory is set to Always. This can be fixed simultaneously in all project files by applying the powershell script below:

$folder = "C:\My\Solution\Folder"
$csvFiles = Get-ChildItem $folder *.csproj -rec
foreach ($file in $csvFiles)
{
    (Get-Content $file.PSPath -Encoding UTF8 -Raw) |
    Foreach-Object { $_ -replace "<CopyToOutputDirectory>Always</CopyToOutputDirectory>", "<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>" } |
    Set-Content $file.PSPath -Encoding UTF8 -NoNewline
}


来源:https://stackoverflow.com/questions/14916729/visual-studio-rebuilds-unmodified-projects

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!