Visual Studio перестраивает неизмененные проекты

Итак, как гласит заголовок, у меня есть решение VS2010 с ~50 проектами в нем прямо сейчас. Если я внесу изменения в проект "верхнего уровня", на который ничего не ссылается, VS все равно перестроит все 50 проектов. Я использую Visual Studio 2010 Ultimate без каких-либо дополнений. Я использую ILMerge для объединения всех проектов в один файл.

Я проверил это, проверив временные метки dll нижнего уровня и убедился, что они действительно перестроены, хотя их код не был затронут.

Я прочитал все отзывы и комментарии для:

Visual Studio 2008 продолжает перестраивать

Визуальная студия продолжает строить все

Странный глюк сборки VS2010 происходит в моем решении

Причины для проектов C# для перестройки в Visual Studio

Но большинство из них просто предлагают предложения по разгрузке проектов, чтобы ускорить время сборки, но ничего конкретного для исправления. Я пытаюсь выяснить, почему VS считает, что эти зависимые проекты нужно перестраивать, когда они этого не делают, и исправлять это.

Я включил "Инструменты> Параметры> Проекты и решения> Построить и запустить> Создавать только запускаемые проекты и зависимости при запуске", но безрезультатно.

Кроме того, если я просто перестрою проект "среднего уровня", который имеет только 8 (in) прямых зависимостей, он все равно создает все 8 проектов, даже если ILMerge не вызывается и ни один из зависимых проектов не был изменен.

Спасибо всем за любые идеи, которые вы можете предоставить.

добавленной

Чтобы проверить некоторые предложения, я создал новый проект WinForms с нуля. Затем я создал два новых проекта в этом решении. Я скопировал весь код и ресурсы (не файл проекта) из моих двух проектов "самого низкого уровня" в два совершенно новых проекта (я сделал это, поместив файлы и папки из Проводника в проект в Visual Studio).

Самый низкий проект, назовем его B, не ссылался ни на какой другой проект. Следующий проект, A, ссылается только на B. Поэтому, как только я добавлю в проекты необходимые ссылки.NET и внешние сборки, решение будет построено.

Затем у меня была новая ссылка на проект WinForm A, и я сделал полную сборку. Итак, цепочка ссылок:

WinForm -> A -> B

Затем я изменил только WinForm и сделал стандартную сборку (F6). Как и прежде, Visual Studio перестроил все три проекта.

После некоторого систематического удаления исходных файлов в проекте B я обнаружил, что если я удалю Resources.Designer.cs а также Resources.resx (и закомментировал код, который использовал .Properties.Resources объект этих ресурсов), то модификация WinForm больше не будет перестраивать все решение и будет перестраивать только WinForm.

Добавление Resources.resx а также Resources.Designer.cs вернуться к проекту B (но оставив закомментированный код, закомментированный так, чтобы ресурсы не использовались ничем), вновь представило бы полное поведение сборки.

Чтобы проверить, не повреждены ли мои файлы ресурсов, я снова удалил их, а затем создал новый (через "Свойства проекта" -> "Ресурсы") и повторно добавил тот же ресурс, что и раньше, который представлял собой один файл Excel. При такой настройке полная перестройка все равно будет происходить.

Затем я удалил один ресурс, но оставил файл ресурса в проекте B. Даже если ресурсы не добавлены, но файл ресурсов все еще находится в проекте, произойдет полное (ненужное) восстановление.

Похоже, что добавление файла ресурсов в проект (.NET 3.5) приведет к тому, что Visual Studio 2010 всегда будет перестраивать этот проект. Это ошибка или предполагаемое / ожидаемое поведение?

Спасибо всем еще раз!

18 ответов

Решение

Хотя я не думаю, что это исправление, это обходной путь, который сработал для моей ситуации...

Первоначально у меня было около 5 проектов из 50, которые содержали Resources раздел. Эти проекты всегда будут перестраиваться, и поэтому все, от чего они зависят, также будет перестраиваться. Одним из этих 5 проектов была библиотека "базового" уровня, на которую ссылались 48 других проектов, таким образом, 96% моего проекта будут перестраиваться каждый раз, даже если в этом нет необходимости.

Мой обходной путь - использовать внедрение зависимостей, интерфейсы и выделенный проект "Ресурсы". Вместо того, чтобы эти 5 проектов ссылались на свои собственные Resources объект, я создал интерфейс в каждом проекте, который будет поставлять нужные ресурсы. Затем классы, которым требовались эти ресурсы, потребовали бы передачи интерфейса во время их создания в конструкторе (внедрение конструктора).

Затем я создал отдельный проект "Ресурсы", в котором был настоящий раздел "Ресурсы", как обычно. Этот проект содержал только сами ресурсы и класс для каждого интерфейса, который был необходим для предоставления этих ресурсов через интерфейс. Этот проект будет ссылаться на любой другой проект, имеющий зависимость от ресурсов, и реализовывать интерфейс, который необходим проекту.

Наконец, в моем проекте "Верхний уровень", на который ничего не ссылалось (и где фактически был создан exe-файл и живет мой корень композиции), я ссылался на проект "Ресурсы", подключил DI, и мы поехали.

Это означает, что только два проекта ("Ресурсы" и "Верхний уровень") будут перестраиваться каждый раз, и если я сделаю частичную сборку (Shift-F6), они вообще не будут перестроены.

Опять же, это не очень хорошая работа, но каждый раз, когда создается 48 проектов, сборка занимает около 3 минут, поэтому я терял от 30 до 90 минут в день из-за ненужных перестроений. Рефакторинг занял некоторое время, но я думаю, что это были хорошие инвестиции.

Вот упрощенная схема. Обратите внимание, что зависимости от Main.exe в Proj1 а также Proj2 не показаны, чтобы уменьшить беспорядок.

Схема решения

С этим дизайном я могу сделать сборку Proj1 или же Proj2 без запуска полной перестройки, так как они не имеют никаких зависимостей от Resources раздел. Только Main знает о Resources реализация.

Откройте "Инструменты" - "Параметры", выберите "Проекты и решения" - "Построить и запустить" в дереве, а затем установите "Детализация вывода сборки проекта MSBuild" на "Диагностика". Это выведет причину построения проекта, т.е.

Проект 'ReferencedProject' не обновлен. Элемент проекта "c:\some.xml" имеет атрибут "Копировать в выходной каталог", установленный на "Всегда копировать".

Проект "MyProject" не обновлен. Входной файл "c:\ReferencedProject.dll" изменяется после выходного файла "c:\MyProject.pdb".

В этом случае исправление заключается в копировании файла some.xml, только если он более новый.

События до и после сборки также могут запускать сборку.

Это происходит, когда у проекта есть файл, который на самом деле не существует.
Проект не может определить, был ли файл изменен (потому что его там нет), поэтому он перестраивается.

Просто посмотрите на все файлы в проекте и найдите тот, у которого нет расширяемой стрелки рядом с ним.

У меня была такая же проблема в VS 2015.

Что сделал трюк для меня это:

  1. Один проект ссылался на саму копию в каком-то другом бине проекта (магия, да). Подобные вещи могут быть найдены при переключении на вывод диагностической сборки (в опциях сборки), а затем при попытке построить проекты один за другим из верхней части иерархии проектов - если вы видите проект, который перестраивается, даже если ничего не было изменено, посмотрите, что он Рекомендации.
  2. Я изменил все файлы "всегда копировать" во всех проектах на "копировать, если новее". В основном, во всех.csproj файлах заменить <CopyToOutputDirectory>Always</CopyToOutputDirectory> в <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
  3. Затем я отключил туннелирование NTFS, как описано в этой статье, с помощью этого сценария powershell:

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

После этого мне нужно было перестроить, и, похоже, сейчас работает.

В моем случае виновником была установка "Копировать локально" для dll, на которую ссылаются, равной true, и "Копировать в выходной каталог", задавая для файла значение Копировать всегда.

Для проектов.Net Core все вышеперечисленные решения не работают. Я нашел решение. Если вы используете Visual Studio 2019:

  1. Создайте решение дважды
  2. Включить Tools -> Options -> Projects and Solutions -> SDK-Style Projects -> Logging Level -> Verbose
  3. Очистить окно вывода
  4. Создайте свой стартовый проект
  5. Осмотрите окно вывода. Вся строка, начинающаяся с FastUpToDate
  6. Вы найдете некоторые элементы проекта, которые делают ваш проект устаревшим.
  7. Исправьте эти проблемы и повторите попытку, начиная с шага 1. Если ваши исправления верны, вы добьетесь Build: 0 succeeded, 0 failed, {n} up-to-date, 0 skipped в последней строке вывода сборки.

Команда MSBuild собирает документацию о расследовании проблем с инкрементностью сборки здесь: https://github.com/Microsoft/MSBuild/wiki/Rebuilding%20when%20nothing%20changed

У меня была такая же проблема, и она оказалась связана с парой проектов, которые имели локальную ссылку на копию в dll в своем собственном каталоге вывода.

Ключом к обнаружению этого было наличие диагностического вывода, установленного для вывода сборки, а также знание того, что искать в журнале. Поиск: "не в курсе" был ключом.

Другая проблема, которая часто возникает, - когда у какого-либо элемента в вашем решении есть модифицированная печать, которая находится в будущем. Это может произойти, если вы установите часы вперед, а затем установите правильное время. У меня такое было при установке Linux.

В этом случае вы можете рекурсивно коснуться всех файлов, используя git bash (да, в Windows):

find . -exec touch {} \;

Наконец-то я нашел еще одного преступника, которого мне было трудно найти, увеличив степень детализации журнала сборки.

В некоторых случаях MSBuild ищет vc120.pdb в выходной папке, и если этот файл не существует, он перестроит весь проект. Это происходит, даже если вы отключили генерацию символов отладки.

Обходной путь здесь состоит в том, чтобы включить символы отладки и позволить этому файлу генерироваться, затем отключить настройку снова, не удаляя файл PDB.

Судя по вашим наблюдениям, у вас есть проекты, выражающие зависимости от других проектов таким образом, что это не очевидно. Потерянные зависимости могут оставаться в файлах проекта, не будучи видимыми в пользовательском интерфейсе. Вы просматривали неправильно работающий файл проекта после его открытия в текстовом редакторе? Проверены зависимости построения решения?

Если вы не можете ничего найти, попробуйте воссоздать один из ваших проектов с нуля, чтобы увидеть, есть ли в новом проекте такая же проблема. Если чистый проект собирается правильно, вы будете знать, что у вас есть нежелательные зависимости, выраженные где-то. Насколько я знаю, они должны быть в файле (ах) проекта или файла решения, если у вас нет make-файлов или других необычных шагов сборки.

Вот ответ от VS2010 всегда перестраивает решение?

Эта проблема решается путем изменения файлов проекта, очистки решения, удаления всех папок бина вручную, перезапуска Visual Studio и восстановления всего.

В моем случае (смешанное C#, C++/CLI и нативное решение C++) некоторые проекты C++ были перекомпонованы, даже если ничего не изменилось. Я потратил целую вечность, пытаясь понять, что происходит. В итоге из опции "Командная строка" я понял, что путь вывода PDB (опция /Fd) не может обработать настройку папки $(IntDir). Я удалил это - пустое значение будет делать по умолчанию правильно - и моя проблема ушла.

У меня были такие же проблемы с тобой. Я обнаружил, что это произошло из некоторых удаленных файлов. Когда я удалил файлы из своего проекта, проблемы исчезли. С уважением.

У меня возникла проблема с перестройкой проектов Visual Studio при обновлении с Visual Studio 2015 до 2017 года, и я добавляю этот ответ для тех, кто может столкнуться с подобными проблемами, поскольку, похоже, он нигде не документирован.

В моем случае проблема заключалась в том, что все проекты в решении имели один и тот же промежуточный выходной путь (obj). Файл GeneratedInternalTypeHelper.cs генерируется всеми проектами, содержащими XAML. Вплоть до Visual Studio 2015 процесс сборки, по-видимому, не проверял дату файла для этого файла и, следовательно, никаких проблем с ним не возникало. В VS2017 проверяется дата файла этого файла, и поскольку более поздний проект в процессе сборки перезапишет его (с тем же содержимым), более ранний проект будет перестроен, повторно запустив более позднюю сборку, до бесконечности.

Решением в этом случае является обеспечение того, чтобы все проекты имели разные промежуточные выходные каталоги, что устранит проблему.

Как заметили другие, вероятная причина в том, что 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
}

Для этой категории проблем сборки установка подробного вывода MSBuild на "диагностику" действительно является необходимым первым шагом. В большинстве случаев заявленной причины повторных сборок будет достаточно для принятия мер, НО иногда MSBuild ошибочно заявляет, что некоторые файлы изменены и их необходимо скопировать.

В этом случае вам нужно либо отключить туннелирование NTFS, либо скопировать выходную папку в другое место. Вот это в нескольких словах.

Файлы, которые не существуют, являются проблемой и, очевидно, файлы также не производят вывод. Это может случиться, если у вас есть файл ресурсов в статической библиотеке. (С++)

Другие вопросы по тегам