Когда я создаю свои проекты с целью MyConfig
, я хочу, чтобы код был оптимизирован, и мне не нужны файлы .pdb
.
Для этого я создал такой файл Directory.Build.props
в корне моего проекта.
<Project>
<PropertyGroup>
<Configurations>Debug;Release;MyConfig</Configurations>
</PropertyGroup>
<PropertyGroup Condition = "'$(Configuration)|$(Platform)' == 'MyConfig|AnyCPU'">
<DebugType>none</DebugType>
<Optimize>true</Optimize>
<DefineConstants>TRACE</DefineConstants>
</PropertyGroup>
</Project>
Теперь, если я запущу эту команду, я получу ожидаемый результат:
dotnet build .\BuildPoc.sln -c MyConfig
Однако при непосредственном построении проекта:
dotnet build .\src\MyProject\MyProject.csproj -c MyConfig
Затем создаются файлы .pdb
.
Я не понимаю, почему такая разница?
Следует ли dotnet build
не уважать Directory.Build.props
несмотря ни на что?
Я создал здесь образец репозитория с простым проектом, демонстрирующим такое поведение: https://github.com/mortenbock/BuildPoc
Обновлено:
Кроме того, я только что обнаружил, что если я запущу эти две команды:
dotnet build .\BuildPoc.sln -c MyConfig
dotnet publish .\src\MyProject\MyProject.csproj -c MyConfig --no-build
Затем я получаю эту ошибку: кажется, dotnet publish
предполагает, что должен быть файл .pdb
?
C:\Program Files\dotnet\sdk\8.0.300\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.Publish.targets(351,5): error MSB3030:
Could not copy the file "obj\MyConfig\net8.0\MyProject.pdb" because it was not found. [D:\Projects\BuildPoc\sr
c\MyProject\MyProject.csproj]
Проблемы со сборкой и публикацией решаются путем передачи явного аргумента платформы через -p:Platform=AnyCPU
.
dotnet build .\src\MyProject\MyProject.csproj -c MyConfig -p:Platform=AnyCPU
dotnet publish .\src\MyProject\MyProject.csproj -c MyConfig --no-build -p:Platform=AnyCPU
Либо удалите флажок $(Platform)
из условия, поскольку во всех ваших командных строках есть -c MyConfig
.
<PropertyGroup Condition = "'$(Configuration)' == 'MyConfig'">
Официального объяснения пока не нашел.
Другой альтернативой является использование файла Directory.Build.targets
, который импортируется позже.
Судя по вашему комментарию, порядок импорта и оценок имеет значение.
Вы можете переименовать этот Directory.Build.props
файл в Directory.Build.targets
.
.
При этом ваша первоначальная попытка создания проекта увенчается успехом.
dotnet build .\src\MyProject\MyProject.csproj -c MyConfig
Чтобы опубликовать проект, вам необходимо собрать и опубликовать его за один раз, поэтому удалите --no-build
(или воспользуйтесь предыдущим/вышеуказанным предложением публикации).
dotnet publish .\src\MyProject\MyProject.csproj -c MyConfig
Я следовал тем же шагам, о которых вы упомянули, даже --verbosity detailed
не сделал меня намного мудрее.
Directory.Build.props
импортируется очень рано и до «общей» поддержки проекта. Если нет явной необходимости, избегайте использования Directory.Build.props
и отдавайте предпочтение Directory.Build.targets
. (Имена произвольные. Оба файла являются «полными» файлами MSBuild без ограничений, т. е. свойства не обязательно должны быть в .props
.)
Предположение в заголовке «Directory.Build.props учитывается только при создании файла .sln» неверно и не является тем, что происходит.
Directory.Build.props
импортируется очень рано и до «общей» поддержки проекта. Свойства $(Configuration)
и $(Platform)
определяются в «общей» поддержке проекта после содержимого Directory.Build.props
.
Определение Configuration
и/или Platform
в командной строке меняет это. Свойства в командной строке будут определены как глобальные свойства до импорта Directory.Build.props
.
Используя файл решения, MSBuild сначала «переводит» решение в «метапроект». Метапроект строит каждый проект в решении, передавая Configuration
и Platform
из решения.
Значение по умолчанию для Configuration
— Debug
.
Во всех проектах в решении BuildPoc.sln в качестве Platform
указано «Любой ЦП». Поскольку используется только один Platform
, он будет использоваться по умолчанию.
(Метапроект sln сопоставит «Любой ЦП» в решении с «Любым ЦП» для проектов.)
Почему dotnet build .\BuildPoc.sln -c MyConfig
работает? Потому что sln предоставляет проекту значения Configuration
и Platform
.
Почему dotnet build .\src\MyProject\MyProject.csproj -c MyConfig
не работает? Потому что в проекте общие свойства, включая Configuration
и Platform
, определяются после импорта Directory.Build.props
. С переключателем -c
. Значение $(Configuration)|$(Platform)
равно MyConfig|
, когда PropertyGroup
Condition
оценивается и свойства DebugType
, Optimize
и DefineConstants
не изменяются. (Это также является причиной ошибки MSB3030 при запуске publish
для проекта.)
Вы можете подтвердить это, добавив к Directory.Build.props
следующее:
<PropertyGroup>
<TraceConfiguration Condition = "'$(Configuration)' == ''">Configuration has no value.</TraceConfiguration>
<TraceConfiguration Condition = "'$(Configuration)' != ''">Configuration has the value '$(Configuration)'.</TraceConfiguration>
<TracePlatform Condition = "'$(Platform)' == ''">Platform has no value.</TracePlatform>
<TracePlatform Condition = "'$(Platform)' != ''">Platform has the value '$(Platform)'.</TracePlatform>
</PropertyGroup>
<Target Name = "ShowPropsTrace" BeforeTargets = "BeforeBuild">
<Message Text = "*** $(TraceConfiguration)"/>
<Message Text = "*** $(TracePlatform)"/>
</Target>
Как правило, избегайте использования Directory.Build.props
и отдавайте предпочтение Directory.Build.targets
. Реальная необходимость в очень раннем импорте Directory.Build.props
возникает редко и необычно.
Имена Directory.Build.props
и Directory.Build.targets
произвольны. Оба файла являются «полными» файлами MSBuild без ограничений, т. е. свойства не обязательно должны быть в формате .props.
См. раздел «Как MSBuild создает проекты» и обратите внимание на этапы оценки и выполнения.
Простое исправление решения и проекта — переименовать файл Directory.Build.props
в Directory.Build.targets
.
Поскольку свойства компилятора связаны только с Configuration
, было бы неплохо протестировать только Configuration
.
Я выбрал вариант изменения своих условий. Хотя это очень странно. Я попробовал вывести
$(Platform)
во время сборки, и в обоих случаях это былоAnyCPU
, но, может быть, дело в том, в какой момент сборки устанавливается это значение? Возможно, иногда он не устанавливается до тех пор, пока не будут оценены условия.