Параметр уровня --output решения больше недействителен для команд, связанных со сборкой

В пакете SDK 7.0.200 было изменено , чтобы больше не принимать --output/-o этот параметр при использовании файла решения со следующими командами:

  • build
  • clean
  • pack
  • publish
  • store
  • test
  • vstest

Это связано с тем, что семантика OutputPath свойства, управляемого --output/-o параметром, не определена для решений. Проекты, встроенные таким образом, будут размещать свои выходные данные в том же каталоге, что является несогласованным и привело к ряду проблем, сообщаемых пользователем.

Это изменение было сокращено до уровня серьезности в пакете SDK 7.0.201 и pack было удалено из списка затронутых команд.

Представленные версии

Пакет SDK для .NET 7.0.200, сокращен до предупреждения только в пакете SDK 7.0.201.

Прежнее поведение

Ранее, если вы указали --output/-o при использовании файла решения, выходные данные для всех встроенных проектов будут помещены в указанный каталог в неопределенном и несогласованном порядке.

Новое поведение

dotnet Интерфейс командной строки будет ошибкой, если --output/-o параметр используется с файлом решения. Начиная с пакета SDK 7.0.201, вместо этого будет создано предупреждение, а в случае dotnet pack отсутствия предупреждения или ошибки.

Тип критического изменения

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

Причина изменения

Это изменение было сделано, так как семантика OutputPath свойства, управляемого --output/-o параметром, не определена для решений. Проекты, встроенные таким образом, будут размещать свои выходные данные в том же каталоге, что является несогласованным и привело к ряду проблем, сообщаемых пользователем.

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

Единый проект, единый targetFramework

Представьте себе решение, содержащее один проект, предназначенный для одного TargetFramework, net7.0. В этом случае предоставление --output параметра эквивалентно настройке OutputPath свойства в файле проекта. Во время сборки (или других команд, но давайте обустроим обсуждение, чтобы создать сейчас), все выходные данные проекта будут помещены в указанный каталог.

Один проект, несколько TargetFrameworks

Теперь представьте решение, содержащее один проект с несколькими TargetFrameworksи net6.0 net7.0. Из-за нескольких целевых объектов проект будет создаваться дважды, один раз для каждого TargetFramework. Для каждой из этих "внутренних" сборок OutputPath будет задано одно и то же значение, поэтому выходные данные для каждой из внутренних сборок будут помещены в один каталог. Это означает, что последняя сборка перезаписывает выходные данные другой сборки, а в параллельной системе, такой как MSBuild, работает по умолчанию, "last" является неопределенным.

Библиотека = консоль =>> test, single TargetFramework

Теперь представьте, что решение, содержащее проект библиотеки, консольный проект, ссылающийся на проект библиотеки, и тестовый проект, ссылающийся на консольный проект. Все эти проекты предназначены для одного TargetFramework. net7.0 В этом случае проект библиотеки будет создан сначала, а затем будет создан консольный проект. Тестовый проект будет создан последним и будет ссылаться на проект консоли. Для каждого созданного проекта выходные данные каждой сборки будут скопированы в каталог, указанный в OutputPathфайле, и поэтому окончательный каталог будет содержать ресурсы из всех трех проектов. Это работает для тестирования, но для публикации может привести к отправке тестовых ресурсов в рабочую среду.

Библиотека = консоль =>> test, несколько TargetFrameworks

Теперь возьмите ту же цепочку проектов и добавьте к ним сборку net6.0 TargetFramework в дополнение к сборке net7.0 . Та же проблема, что и однопроектная многоцелая сборка, возникает — несогласованное копирование ресурсов, относящихся к TFM, в указанный каталог.

Несколько приложений

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

Если несколько приложений зависят от разных версий файла, то даже если сборка завершается успешно, какая версия файла копируется в выходной путь, может быть недетерминированной. Это может произойти, когда проекты зависят (возможно, транзитивно) от разных версий пакета NuGet. В рамках одного проекта NuGet помогает убедиться, что его зависимости (включая транзитивные зависимости через пакеты NuGet и/или ссылки на проекты) унифицированы с той же версией. Так как объединение выполняется в контексте одного проекта и его зависимых проектов, это означает, что можно разрешить различные версии пакета при создании двух отдельных проектов верхнего уровня. Если проект, зависящий от более поздней версии, копирует зависимость последней, то часто приложения будут работать успешно. Однако если последняя версия копируется ниже, приложение, скомпилированное в более поздней версии, не сможет загрузить сборку во время выполнения. Так как скопированная версия может быть недетерминированной, это может привести к спорадическим, ненадежным сборкам, где очень трудно диагностировать проблему.

Другие примеры

Дополнительные примеры того, как эта базовая ошибка представлена на практике, см. в обсуждении dotnet/sdk#15607.

Общая рекомендация — выполнить действие, которое вы ранее выполнили без/ --output-o параметра, а затем переместить выходные данные в нужное расположение после завершения команды. Также можно выполнить действие в определенном проекте и по-прежнему применить --output/-o этот параметр, так как он имеет более четко определенную семантику.

Если вы хотите точно сохранить существующее поведение, можно использовать --property флаг для задания свойства MSBuild требуемому каталогу. Свойство, используемое для использования, зависит от команды:

Команда Свойство Пример
build OutputPath dotnet build --property:OutputPath=DESIRED_PATH
clean OutputPath dotnet clean --property:OutputPath=DESIRED_PATH
pack PackageOutputPath dotnet pack --property:PackageOutputPath=DESIRED_PATH
publish PublishDir dotnet publish --property:PublishDir=DESIRED_PATH
store OutputPath dotnet store --property:OutputPath=DESIRED_PATH
test TestResultsDirectory dotnet test --property:OutputPath=DESIRED_PATH

ПРИМЕЧАНИЕ . Для наилучших результатов DESIRED_PATH должен быть абсолютным путем. Относительные пути будут "привязаны" (т. е. сделаны абсолютными) способами, которые могут не ожидать, и могут не работать одинаково со всеми командами.