Visual Studio 重建未修改的项目

Posted

技术标签:

【中文标题】Visual Studio 重建未修改的项目【英文标题】:Visual Studio Rebuilds unmodified projects 【发布时间】:2013-02-01 17:28:46 【问题描述】:

所以,正如标题所示,我现在有一个 VS2010 解决方案,其中包含大约 50 个项目。如果我对没有任何引用的“***”项目进行更改,那么 VS 仍然会重建所有 50 个项目。我正在运行没有任何附加组件的 Visual Studio 2010 Ultimate。我正在使用 ILMerge 将所有项目合并到一个文件中。

我已经通过检查较低级别 dll 的时间戳来验证这一点,并看到它们确实被重建了,即使它们的代码没有被触及。

我已阅读以下所有回复和 cmets:

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

但他们中的大多数只是提供有关卸载项目以加快构建时间的建议,但没有具体的修复方法。我试图弄清楚为什么 VS 认为这些依赖项目需要重建,而他们不这样做并修复它。

我已打开“工具 > 选项 > 项目和解决方案 > 构建和运行 > 仅构建启动项目和运行时的依赖项”,但没有任何效果。

另外,如果我只是重建一个只有 8 个(内)直接依赖项的“中级”项目,那么即使没有调用 ILMerge 并且没有修改任何依赖项目,它仍然会构建所有 8 个项目。

感谢大家提供的任何见解。

已添加

为了测试一些建议,我从头开始创建了一个新的 WinForms 项目。然后,我在该解决方案中创建了两个新项目。我将两个“最低级别”项目中的所有代码和资源(不是项目文件)复制到两个全新的项目中(我通过将文件和文件夹从资源管理器拖放到 Visual Studio 中的项目中)。

最低的项目,我们称之为B,没有引用任何其他项目。下一个项目 A 仅引用了 B。因此,一旦我将所需的 .NET 和外部程序集引用添加到项目中,就会构建解决方案。

然后我获得了我的新 WinForm 项目参考 A 并进行了完整构建。所以参考链是:

WinForm -> A -> B

然后我修改了 WinForm 并进行了标准构建 (F6)。和以前一样,Visual Studio 重建了所有三个项目。

在项目B中对源文件进行了一些系统性删除后,我发现如果我删除了我的Resources.Designer.csResources.resx(并注释掉了使用.Properties.Resources对象的代码这些资源)然后修改 WinForm 将不再重建整个解决方案,只会重建 WinForm

Resources.resxResources.Designer.cs 添加回项目B(但将引用的代码注释掉,这样就不会使用资源)将重新引入完整的构建行为。

为了查看我的资源文件是否已损坏,我再次删除了它们,然后创建了一个新文件(通过项目属性 -> 资源)并重新添加了与以前相同的资源,即单个 Excel 文件。使用此设置,仍会进行完全重建。

然后我删除了单个资源,但将资源文件留在了项目 B 中。即使没有添加资源,但资源文件仍在项目中,也会发生完整的(不需要的)重建。

似乎只要将资源文件添加到 (.NET 3.5) 项目中,就会导致 Visual Studio 2010 始终重新构建该项目。这是错误还是预期/预期的行为?

再次感谢大家!

【问题讨论】:

你可以试试直接用msbuild构建它,看看它是否仍然发生 我的理解是 VS 调用 msbuild(并且项目基本上是一个 msbuild 脚本***.com/questions/1497344/…)所以我不确定这会改变什么。我怀疑我最终会重新创建相同的构建脚本,然后从命令行运行它。是否有某种方式可以直接运行 msbuild 会有所不同?或者也许有什么方法可以找出为什么 msbuild 认为项目需要重建? 您是在建造还是在重建? 正常构建 (F6),有时仅项目构建 (Shift-F6)。两者都表现出相同的行为,尽管“仅项目构建”的重建项目的范围仅限于当前项目的直接和间接依赖项。 @MattKlein 是的,我感觉 VS 确实在内部运行 msbuild,但也许它调用它的方式可能有所不同,您可以通过执行“msbuild”从命令行 msbuild sln 文件mysol.sln" 【参考方案1】:

打开工具 - 选项,选择项目和解决方案 - 在树中构建和运行,然后将“MSBuild 项目构建输出详细程度”设置为诊断。 这将输出构建项目的原因,即

项目“ReferencedProject”不是最新的。项目项目 'c:\some.xml' 的 'Copy to Output Directory' 属性设置为 'Copy 总是'。

项目“MyProject”不是最新的。输入文件 'c:\ReferencedProject.dll' 在输出文件后被修改 'c:\MyProject.pdb'。

在这种情况下,解决方法是仅在更新时复制 some.xml。

构建前和构建后事件也可以触发构建。

【讨论】:

我相信这是最好的答案,因为它让您真正了解导致构建重复的原因,而不仅仅是猜测或试验。 很高兴知道!我在徘徊为什么项目重建也会重建所有引用的项目。诊断日志解释说:'目标“CleanReferencedProjects:(TargetId:8)”':) 谢谢,这正是我所需要的。就我而言,事实证明,常量构建是由设置为“始终复制”的 .ico 文件触发的。 我也有同样的问题,但是我将日志设置为详细,但它仍然没有输出一行告诉我为什么它认为它已经过时了。有没有其他方法可以发现这一点? 你成就了我的一天。就我而言,解决方案资源管理器中仍引用了一些已删除的文件(尽管未使用)。查找“不是最新的”很重要,因为日志很大。【参考方案2】:

虽然我不认为这是一个修复方法,但它是一种适用于我的情况的解决方法...

我最初在 50 个项目中约有 5 个项目包含 Resources 部分。这些项目总是会被重建,因此他们所依赖的任何东西也会被重建。这 5 个项目之一是其他 48 个项目引用的“基础”级库,因此我的项目的 96% 每次都会重新构建,即使它不需要它。

我的解决方法是使用依赖注入、接口和专用的“资源”项目。我没有让这 5 个项目引用它们自己的 Resources 对象,而是在每个项目中创建了一个接口来提供所需的资源。然后,需要这些资源的类将需要在构造函数中创建它们的过程中传入该接口(构造函数注入)。

然后,我创建了一个单独的“资源”项目,该项目具有正常的资源部分。该项目仅包含资源本身,以及通过接口提供这些资源所需的每个接口的类。该项目将引用具有资源依赖关系的所有其他项目并实现该项目所需的接口。

最后,在我没有任何引用的“***”项目中(以及实际构建 exe 和我的组合根目录的位置),我引用了“资源”项目,连接了 DI,然后我们就走了。

这意味着每次只会重建两个项目(“资源”和“***”),如果我进行部分构建(Shift-F6),那么它们根本不会被重建。

同样,这不是一个很好的解决方案,但是每次构建需要大约 3 分钟才能构建 48 个项目,因此我每天会因不必要的重建而浪费 30 到 90 分钟。重构花了一些时间,但我认为这是一项不错的投资。

这是一个简化的图表。请注意,从 Main.exeProj1Proj2 的依赖关系未显示以减少混乱。

通过这种设计,我可以构建 Proj1Proj2 而不会触发完全重建,因为它们对 Resources 部分没有任何依赖关系。只有Main 知道Resources 的实现。

【讨论】:

【参考方案3】:

当项目的文件实际上并不存在时,就会发生这种情况。 该项目无法确定文件是否已更改(因为它不存在),因此它会重新构建。

只需查看项目中的所有文件,然后搜索附近没有可展开箭头的文件。

【讨论】:

这也是我的问题,但是在我的情况下,它旁边有一个可扩展的箭头,因为该文件最近已被删除。因此,您可能需要更仔细地查找导致重新链接的已删除文件。 如果我有 7 亿个文件怎么办? 您可以创建一个小脚本/程序来遍历项目文件或 .filter 文件并检查引用的文件是否存在。【参考方案4】:

我在 VS 2015 中遇到了同样的问题。

对我来说诀窍是:

    一个项目在其他项目箱中引用自己的副本(很神奇,是的)。当切换到诊断构建输出(在构建选项中)然后尝试从项目层次结构的顶部一个一个地构建项目时,可以找到这种东西 - 如果您看到即使没有任何更改也可以重建的项目然后看到它参考文献。 我已将所有项目中的所有“始终复制”文件更改为“如果更新则复制”。基本上,在所有 .csproj 文件中,将 <CopyToOutputDirectory>Always</CopyToOutputDirectory> 替换为 &lt;CopyToOutputDirectory&gt;PreserveNewest&lt;/CopyToOutputDirectory&gt; 然后我已禁用 NTFS 隧道,如this 文章中所述,使用此 powershell 脚本:

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

在那之后我需要重建,现在它似乎工作了。

【讨论】:

有没有一种快速的方法来做到这一点(例如,我可以搜索一些特定的文本)?我在 VS 2015 中遇到了同样的问题,并且我有一个相当大的解决方案文件(包括一些我不允许修改的项目,因为它们不“属于”我)。【参考方案5】:

在我的情况下,罪魁祸首是将引用的 dll 的“复制本地”设置设置为 true,而“复制到输出目录”将文件设置为始终复制。

【讨论】:

【参考方案6】:

对于 .Net Core 项目,上述所有解决方案均无效。 我找到了解决方案。如果您使用的是 Visual Studio 2019:

    两次构建解决方案 开启Tools -> Options -> Projects and Solutions -> SDK-Style Projects -> Logging Level -> Verbose 清除输出窗口 构建您的启动项目 检查输出窗口。所有以FastUpToDate开头的字符串 您会发现一些项目项导致您的项目不是最新的。 修复这些问题,然后从第 1 步开始重试。如果您的修复正确,您将在构建输出的最后一个字符串中实现 Build: 0 succeeded, 0 failed, n up-to-date, 0 skipped

【讨论】:

制作简单的脚本现在打印丢失的文件(C++ 项目)***.com/questions/24063194/…【参考方案7】:

MSBuild 团队正在这里收集有关调查构建增量问题的文档: https://github.com/Microsoft/MSBuild/wiki/Rebuilding%20when%20nothing%20changed

【讨论】:

非常有用的链接。在那里也看到了您提到的工具,这方面的工作非常好!我可能会尝试调试我们的一个解决方案。【参考方案8】:

通过增加构建日志的详细程度,我终于找到了另一个我很难找到的罪魁祸首。

在某些情况下,MSBuild 会在输出文件夹中查找 vc120.pdb,如果此文件不存在,它将重新构建整个项目。 即使您禁用了调试符号生成,也会发生这种情况

这里的解决方法是启用调试符号并让该文件生成,然后再次禁用该设置而不删除 PDB 文件。

【讨论】:

如何在使用源代码控制的团队中扩展此选项?您会将 PDB 文件签入到源代码中吗(这听起来很糟糕)?否则,每当有人更新项目时,他们都需要执行此手动步骤。 @julealgon:没有线索:/【参考方案9】:

我遇到了同样的问题,结果证明这与几个项目有关,这些项目在他们自己的输出目录中具有对 dll 的复制本地引用。

找到这一点的关键是为构建输出设置诊断输出,同时还要知道要在日志中查找什么。搜索:“不是最新的”是关键。

【讨论】:

【参考方案10】:

这是VS2010 always rebuilds solution?的回答

通过更改项目文件,清理解决方案来解决此问题, 手动删除所有 bin 文件夹,重新启动 Visual Studio 并 重建一切。

【讨论】:

我不确定“更改项目文件”是什么意思,但我对其余部分进行了尝试,但没有任何效果。看起来它可能与资源文件有关(请参阅问题的附加信息)【参考方案11】:

根据您的观察,听起来您的项目以一种不明显的方式表达了对其他项目的依赖关系。孤立的依赖项可能会保留在项目文件中,而不会在 UI 中显示。您是否在文本编辑器中打开了一个行为不端的项目文件?检查解决方案构建依赖项?

如果您无法发现任何问题,请尝试从头开始重新创建您的一个项目,以查看新项目是否存在相同的问题。如果干净的项目正确构建,您将知道您在某处表达了不需要的依赖项。据我所知,这些必须在项目文件或解决方案文件中,除非您有 makefile 或其他不寻常的构建步骤。

【讨论】:

经过一些广泛的研究,看起来Resources.resx 可能是导致此行为的原因。我在问题中添加了信息来描述我的实验。 从您的新信息中不清楚您将 .resx 文件添加到了哪个项目。无论如何,在测试时要小心,在测试之间手动删除所有构建创建的文件夹,以确保早期的剩余文件不会影响以后的测试。 结果很好奇,但不幸的是,除了我会继续将问题缩小到最低限度之外,我没有任何新东西要添加(只有两个项目而不是三个,只有新的未修改向导创建具有重现问题所需的最少更改的项目等)然后查看其他人是否可以使用相同的项目文件重现问题。如果可以,请通过 Microsoft Connect 提交错误报告。 我很抱歉没有包括我正在调整的项目。我更新了声明以表明我正在修改最低 (B) 项目的资源文件。我将继续探索这一点,因为我每天可能会浪费 1 小时等待不必要的重建。【参考方案12】:

我和你有同样的问题。 我发现它来自一些已删除的文件。 当我从项目中删除文件时,问题就消失了。 问候。

【讨论】:

【参考方案13】:

对于此类构建问题,将 MSBuild 输出详细程度设置为“诊断”确实是必要的第一步。大多数情况下,重新构建的所述原因足以采取行动,但有时 MSBuild 会错误地声称某些文件已修改并需要复制。

如果是这种情况,您需要禁用 NTFS 隧道或将输出文件夹复制到新位置。 Here it is in more words.

【讨论】:

【参考方案14】:

另一个经常发生的问题是,当您的解决方案中的某些项目具有未来的修改标记时。如果您将时钟提前,然后将时钟设置为正确的时间,就会发生这种情况。我在安装 Linux 时发生了这种情况。

在这种情况下,您可以使用 git bash 递归地触摸所有文件(是的,在 Windows 中):

find . -exec touch  \;

【讨论】:

【参考方案15】:

从 Visual Studio 2015 升级到 2017 时,我遇到了 Visual Studio 重建项目的问题,我添加了这个答案是为了让那些可能遇到类似问题的人受益,因为它似乎没有在任何地方记录。

就我而言,问题在于解决方案中的所有项目都具有相同的中间输出路径 (obj)。文件 GeneratedInternalTypeHelper.cs 由包含 XAML 的所有项目生成。直到 Visual Studio 2015,构建过程显然没有检查此文件的文件日期,因此没有出现问题。使用 VS2017 会检查此文件的文件日期,因为构建过程中的后续项目将覆盖它(具有相同的内容),较早的项目将重新构建,重新触发后续构建,无限。

这种情况下的解决办法是保证所有项目都有不同的中间输出目录,这样问题就迎刃而解了。

【讨论】:

【参考方案16】:

在我的情况下(混合 C#、C++/CLI 和本机 C++ 解决方案),一些 C++ 项目正在重新链接,即使没有任何改变。我花了很长时间试图弄清楚发生了什么。最后,我从“命令行”选项中发现,PDB 输出路径(选项 /Fd)无法处理文件夹设置 $(IntDir)。我删除了它 - 一个空值将正确执行默认值 - 我的问题消失了。

【讨论】:

【参考方案17】:

正如其他人所注意到的,一个可能的原因是 CopyToOutputDirectory 设置为 Always。这可以通过应用下面的 powershell 脚本在所有项目文件中同时修复:

$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

【讨论】:

以上是关于Visual Studio 重建未修改的项目的主要内容,如果未能解决你的问题,请参考以下文章

Visual Studio项目总是重建,但未更新pdb

适用于 Android 的 Visual Studio 模拟器 - 项目未部署

将未包含的头文件添加到 Visual Studio 项目中的最新检查

Visual Studio 2013 SerialPort未接收所有数据

Visual Studio 2015 探查器未显示我的代码中的任何内容

Visual Studio Code 如何将新项目发布到GIT服务器