Параметр уровня --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 должен быть абсолютным путем. Относительные пути будут "привязаны" (т. е. сделаны абсолютными) способами, которые могут не ожидать, и могут не работать одинаково со всеми командами.