Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Вы можете добавить определенные файлы, импортируемые MSBuild, чтобы переопределить параметры свойств по умолчанию и добавить пользовательские целевые объекты. Область этих настроек можно контролировать на уровне папки, где размещаются эти файлы.
Краткий справочник
В следующей таблице перечислены специальные файлы MSBuild, распознаваемые для настройки на основе папок:
| Файл | Цель | Область действия | Импортировано компанией |
|---|---|---|---|
| Directory.Build.props | Установить свойства по умолчанию для проектов | Все проекты в папке и подпапках | Microsoft.Common.props (ранняя версия) |
| Directory.Build.targets | Добавление пользовательских целевых объектов и поздних свойств | Все проекты в папках и подпапках | Microsoft.Common.targets (поздняя версия) |
| Directory.Build.rsp | Установка аргументов командной строки по умолчанию | Только сборки CLI (msbuild.exe, dotnet build) |
Обработчик командной строки MSBuild |
| Directory.Solution.props | Установка свойств для сборок решения | Процессы сборки файлов решения | Процесс сборки решения |
| Directory.Solution.targets | Добавление целевых объектов для сборок решений | Построение файлов решения | Процесс сборки решения |
В этой статье рассматриваются Directory.Build.props и Directory.Build.targets. Для получения информации о других файлах см. файлы ответов MSBuild и настройка сборок решений.
Сценарии
В этой статье рассматриваются настройки, применимые к следующим сценариям:
- Настройка параметров сборки для многих проектов в решении
- Настройка параметров сборки для многих решений в общем каталоге файлов
- Настройка параметров сборки, которые могут отличаться для вложенных папок в сложной структуре папок
- Переопределите параметры по умолчанию, папки сборки по умолчанию и другие действия, заданные пакетом SDK, например
Microsoft.Net.Sdk - Добавление или настройка целевых объектов сборки, которые применяются к любому количеству проектов или решений
Если вы работаете с проектами C++, можно также использовать методы, описанные в статье Настройка сборок C++.
Directory.Build.props и Directory.Build.targets
Вы можете добавить новое свойство в каждый проект, определив его в одном файле с именем Directory.Build.props в корневой папке, содержащей источник.
При запуске MSBuild Microsoft.Common.props ищет в структуре каталогов файл Directory.Build.props. Если он находит его, он импортирует файл и считывает свойства, определенные в нем. Directory.Build.props — это определяемый пользователем файл, который предоставляет настройки для проектов в каталоге.
Аналогичным образом Microsoft.Common.targets ищет Directory.Build.targets.
Directory.Build.props импортируется рано в последовательности импортированных файлов, что может быть важно, если необходимо задать свойство, используемое импортом, особенно те, которые неявно импортируются с помощью атрибута Sdk, например при использовании пакета SDK для .NET в большинстве файлов проекта .NET.
Заметка
Файловые системы под управлением Linux чувствительны к регистру. Убедитесь, что регистру имени файла Directory.Build.props соответствует точно, иначе он не будет обнаружен при сборке.
Дополнительные сведения см. в этой проблеме GitHub.
Пример Directory.Build.props
Например, вот файл Directory.Build.props, который задает выходной каталог для всех проектов в решении Visual Studio. Выходные данные каждого проекта размещаются под его собственным названием. В этом примере файл Directory.Build.props находится в папке решения с большим количеством проектов в вложенных папках под ним. Свойство $(MSBuildProjectName) дает имя каждого проекта. Так как файл Directory.Build.props импортируется в каждый проект во время собственной сборки, он оценивается в правильное значение для каждого отдельного проекта в решении.
Очистите решение для удаления старых выходных файлов.
msbuild /t:Clean SolutionName.slnСоздайте файл в корне репозитория с именем Directory.Build.props.
Добавьте следующий XML-код в файл.
<Project> <PropertyGroup> <OutDir>C:\output\$(MSBuildProjectName)</OutDir> </PropertyGroup> </Project>Заметка
Свойство
$(OutDir)— это абсолютный путь к выходным данным, и его использование позволяет обойти создание вложенных папок для конфигурации, целевой платформы или среды выполнения, которые обычно применяются в проектах .NET. Попробуйте использовать свойствоBaseOutputPathвместо этого, если вы хотите создать обычные вложенные папки в пользовательском пути вывода.Запустите MSBuild. Существующие импорты Microsoft.Common.props и Microsoft.Common.targets находят и импортируют файл Directory.Build.props, и новая выходная папка используется для всех проектов в этой папке.
Пример Directory.Build.targets
Используйте Directory.Build.targets , если необходимо добавить пользовательские целевые объекты сборки или переопределить целевые объекты, которые выполняются во время процесса сборки. Так как он импортируется в конце последовательности сборки, он может получить доступ к свойствам, заданным пакетами проекта и NuGet.
В следующем примере добавляется пользовательский целевой объект, который выполняется после каждой сборки, чтобы регистрировать сведения о выходных данных сборки:
<Project>
<Target Name="LogBuildInfo" AfterTargets="Build">
<Message Importance="high" Text="Built $(MSBuildProjectName) -> $(TargetPath)" />
</Target>
</Project>
Еще одним общим способом является принудительное применение анализа кода во всех проектах:
<Project>
<PropertyGroup>
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
<Target Name="ValidateNamingConventions" BeforeTargets="CoreCompile">
<!-- Custom validation logic here -->
</Target>
</Project>
Область поиска
При поиске файла Directory.Build.props MSBuild проходит по структуре каталогов вверх от расположения вашего проекта $(MSBuildProjectFullPath)и останавливается после нахождения файла Directory.Build.props. Например, если ваш $(MSBuildProjectFullPath) был c:\users\username\code\test\case1, MSBuild начнет выполнять поиск в этой директории, а затем будет искать по структуре каталогов вверх, пока не будет найден файл Directory.Build.props, как показано в следующей структуре каталогов.
c:\users\username\code\test\case1
c:\users\username\code\test
c:\users\username\code
c:\users\username
c:\users
c:\
Расположение файла решения не имеет значения для Directory.Build.props.
Порядок импорта
Directory.Build.props импортируется в начале Microsoft.Common.props, а свойства, определенные позже, недоступны для него. Поэтому избегайте ссылки на свойства, которые еще не определены (и будут оцениваться как пустые).
Свойства, заданные в Directory.Build.props, можно переопределить в другом месте файла проекта или импортированных файлов, поэтому следует думать о параметрах в Directory.Build.props как указание значений по умолчанию для проектов.
Directory.Build.targets импортируется из Microsoft.Common.targets после импорта файлов .targets из пакетов NuGet. Таким образом, он может переопределить свойства и цели, определенные в большей части логики сборки, или задать свойства для всех проектов независимо от настроек отдельных проектов.
Если необходимо задать свойство или определить целевой объект для отдельного проекта, который переопределяет все предыдущие параметры, поместите эту логику в файл проекта после окончательного импорта. Чтобы сделать это в проекте в стиле SDK, сначала необходимо заменить атрибут этого стиля на эквивалентные импорты. См. Как использовать SDK для проектов MSBuild.
Заметка
Модуль MSBuild считывает все импортированные файлы во время оценки перед началом выполнения сборки для проекта (включая любые PreBuildEvent), поэтому эти файлы не должны быть изменены PreBuildEvent или любой другой частью процесса сборки. Любые изменения не вступают в силу до следующего вызова MSBuild.exe или следующей сборки Visual Studio. Кроме того, если процесс сборки содержит множество сборок проектов (например, при многоцелевой компиляции или сборке зависимых проектов), то импортированные файлы, включая Directory.build.props, считываются при оценке для каждой отдельной сборки проекта.
Вариант использования: слияние на нескольких уровнях
Предположим, что у вас есть стандартная структура решения:
\
MySolution.sln
Directory.Build.props (1)
\src
Directory.Build.props (2-src)
\Project1
\Project2
\test
Directory.Build.props (2-test)
\Project1Tests
\Project2Tests
Возможно, желательно иметь общие свойства для всех проектов (1), общие свойства для проектов src(2-src)и общие свойства для тестовых проектов (2-тестовые).
Чтобы MSBuild правильно объединить "внутренние" файлы (2-src и 2-test) с "внешним" файлом (1), необходимо учитывать, что после того, как MSBuild находит файл Directory.Build.props, он останавливает дальнейшее сканирование. Чтобы продолжить сканирование и слияние с внешним файлом, поместите этот код в оба внутренних файла:
<Import Project="$([MSBuild]::GetPathOfFileAbove('Directory.Build.props', '$(MSBuildThisFileDirectory)../'))" Condition="'' != $([MSBuild]::GetPathOfFileAbove('Directory.Build.props', '$(MSBuildThisFileDirectory)../'))" />
Сводка общего подхода MSBuild выглядит следующим образом:
- Для любого конкретного проекта MSBuild находит первый Directory.Build.props вверх в структуре решения, объединяет его со значениями по умолчанию и останавливает сканирование.
- Если вы хотите, чтобы несколько уровней было найдено и объединено, отделите «внешний» файл от «внутреннего» файла, как показано ранее в примере
<Import...>. - Если "внешний" файл сам не импортирует ничего из более высокого уровня, то сканирование останавливается там.
- Это делается только в том случае, если внешний файл фактически существует
Или проще: первый Directory.Build.props, который не импортирует ничего, и на котором останавливается MSBuild.
Чтобы управлять процессом импорта более явно, используйте свойства $(DirectoryBuildPropsPath), $(ImportDirectoryBuildProps), $(DirectoryBuildTargetsPath)и $(ImportDirectoryBuildTargets). Свойство $(DirectoryBuildPropsPath) указывает путь к используемому файлу Directory.Build.props; аналогичным образом $(DirectoryBuildTargetsPath) указывает путь к файлу Directory.Build.targets.
Логические свойства $(ImportDirectoryBuildProps) и $(ImportDirectoryBuildTargets) по умолчанию имеют значение true, поэтому MSBuild обычно выполняет поиск этих файлов, но их можно задать для false, чтобы предотвратить импорт MSBuild.
Пример: Использование предварительно обработанных данных для отладки размещения свойств
В этом примере показано, как использовать предварительно обработанные выходные данные, чтобы определить, где задать свойство.
Чтобы проанализировать использование определенного свойства, которое вы хотите задать, можно запустить MSBuild с помощью аргумента /preprocess или /pp. Выходной текст является результатом всех импортов, включая системные импорты, такие как Microsoft.Common.props, которые неявно импортированы и любой из ваших собственных импортов. В этих выходных данных вы увидите, где необходимо задать свойство относительно места использования его значения.
Например, предположим, что у вас есть простой проект консольного приложения .NET, и вы хотите настроить промежуточную выходную папку, как правило obj. Свойство, указывающее путь, — BaseIntermediateOutput. Если вы попытаетесь поместить его в элемент PropertyGroup в файл проекта вместе с различными другими свойствами, которые уже установлены там, например TargetFramework, то обнаружите при сборке проекта, что свойство не вступает в силу. Если вы запускаете MSBuild с параметром /pp и ищете выходные данные для BaseIntermediateOutputPath, вы можете увидеть, почему. В этом случае BaseIntermediateOutput считывается и используется в Microsoft.Common.props.
Существует комментарий в Microsoft.Common.props, который говорит, что свойство BaseIntermediateOutput должно быть задано здесь, прежде чем оно используется другим свойством, MSBuildProjectExtensionsPath. Вы также можете увидеть, что при первоначальной установке BaseIntermediateOutputPath есть проверка на наличие предварительно существующего значения, и если оно не определено, оно получает значение obj.
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">obj\</BaseIntermediateOutputPath>
Таким образом, это размещение указывает на то, что для задания этого свойства, оно должно быть задано где-то раньше этого. Непосредственно перед этим кодом в предварительно обработанных выходных данных можно увидеть, что Directory.Build.props импортируется, поэтому можно задать BaseIntermediateOutputPath там, и он будет установлен достаточно рано, чтобы иметь нужный эффект.
Ниже приведены сокращенные предварительно обработанные выходные данные, в результате чего параметр BaseIntermediateOutput помещается в Directory.Build.props. Комментарии в верхней части стандартных импортов включают имя файла и, как правило, некоторые полезные сведения о том, почему этот файл импортируется.
<?xml version="1.0" encoding="IBM437"?>
<!--
============================================================================================================================================
c:\source\repos\ConsoleApp9\ConsoleApp9\ConsoleApp9.csproj
============================================================================================================================================
-->
<Project DefaultTargets="Build">
<!--
============================================================================================================================================
<Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk">
This import was added implicitly because the Project element's Sdk attribute specified "Microsoft.NET.Sdk".
C:\Program Files\dotnet\sdk\7.0.200-preview.22628.1\Sdks\Microsoft.NET.Sdk\Sdk\Sdk.props
============================================================================================================================================
-->
<!--
***********************************************************************************************
Sdk.props
WARNING: DO NOT MODIFY this file unless you are knowledgeable about MSBuild and have
created a backup copy. Incorrect changes to this file will make it
impossible to load or build your projects from the command-line or the IDE.
Copyright (c) .NET Foundation. All rights reserved.
***********************************************************************************************
-->
<PropertyGroup xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!--
Indicate to other targets that Microsoft.NET.Sdk is being used.
This must be set here (as early as possible, before Microsoft.Common.props)
so that everything that follows can depend on it.
In particular, Directory.Build.props and nuget package props need to be able
to use this flag and they are imported by Microsoft.Common.props.
-->
<UsingMicrosoftNETSdk>true</UsingMicrosoftNETSdk>
<!--
Indicate whether the set of SDK defaults that makes SDK style project concise are being used.
For example: globbing, importing msbuild common targets.
Similar to the property above, it must be set here.
-->
<UsingNETSdkDefaults>true</UsingNETSdkDefaults>
</PropertyGroup>
<PropertyGroup Condition="'$(MSBuildProjectFullPath)' == '$(ProjectToOverrideProjectExtensionsPath)'" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<MSBuildProjectExtensionsPath>$(ProjectExtensionsPathForSpecifiedProject)</MSBuildProjectExtensionsPath>
</PropertyGroup>
<!--<Import Project="$(AlternateCommonProps)" Condition="'$(AlternateCommonProps)' != ''" />-->
<!--
============================================================================================================================================
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="'$(AlternateCommonProps)' == ''">
C:\Program Files\Microsoft Visual Studio\2022\Preview\MSBuild\Current\Microsoft.Common.props
============================================================================================================================================
-->
<!--
***********************************************************************************************
Microsoft.Common.props
WARNING: DO NOT MODIFY this file unless you are knowledgeable about MSBuild and have
created a backup copy. Incorrect changes to this file will make it
impossible to load or build your projects from the command-line or the IDE.
Copyright (C) Microsoft Corporation. All rights reserved.
***********************************************************************************************
-->
<PropertyGroup>
<ImportByWildcardBeforeMicrosoftCommonProps Condition="'$(ImportByWildcardBeforeMicrosoftCommonProps)' == ''">true</ImportByWildcardBeforeMicrosoftCommonProps>
<ImportByWildcardAfterMicrosoftCommonProps Condition="'$(ImportByWildcardAfterMicrosoftCommonProps)' == ''">true</ImportByWildcardAfterMicrosoftCommonProps>
<ImportUserLocationsByWildcardBeforeMicrosoftCommonProps Condition="'$(ImportUserLocationsByWildcardBeforeMicrosoftCommonProps)' == ''">true</ImportUserLocationsByWildcardBeforeMicrosoftCommonProps>
<ImportUserLocationsByWildcardAfterMicrosoftCommonProps Condition="'$(ImportUserLocationsByWildcardAfterMicrosoftCommonProps)' == ''">true</ImportUserLocationsByWildcardAfterMicrosoftCommonProps>
<ImportDirectoryBuildProps Condition="'$(ImportDirectoryBuildProps)' == ''">true</ImportDirectoryBuildProps>
</PropertyGroup>
<!--
Determine the path to the directory build props file if the user did not disable $(ImportDirectoryBuildProps) and
they did not already specify an absolute path to use via $(DirectoryBuildPropsPath)
-->
<PropertyGroup Condition="'$(ImportDirectoryBuildProps)' == 'true' and '$(DirectoryBuildPropsPath)' == ''">
<_DirectoryBuildPropsFile Condition="'$(_DirectoryBuildPropsFile)' == ''">Directory.Build.props</_DirectoryBuildPropsFile>
<_DirectoryBuildPropsBasePath Condition="'$(_DirectoryBuildPropsBasePath)' == ''">$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildProjectDirectory), '$(_DirectoryBuildPropsFile)'))</_DirectoryBuildPropsBasePath>
<DirectoryBuildPropsPath Condition="'$(_DirectoryBuildPropsBasePath)' != '' and '$(_DirectoryBuildPropsFile)' != ''">$([System.IO.Path]::Combine('$(_DirectoryBuildPropsBasePath)', '$(_DirectoryBuildPropsFile)'))</DirectoryBuildPropsPath>
</PropertyGroup>
<!--
============================================================================================================================================
<Import Project="$(DirectoryBuildPropsPath)" Condition="'$(ImportDirectoryBuildProps)' == 'true' and exists('$(DirectoryBuildPropsPath)')">
c:\source\repos\ConsoleApp9\Directory.Build.props
============================================================================================================================================
-->
<!-- Directory.build.props
-->
<PropertyGroup>
<BaseIntermediateOutputPath>myBaseIntermediateOutputPath</BaseIntermediateOutputPath>
</PropertyGroup>
<!--
============================================================================================================================================
</Import>
C:\Program Files\Microsoft Visual Studio\2022\Preview\MSBuild\Current\Microsoft.Common.props
============================================================================================================================================
-->
<!--
Prepare to import project extensions which usually come from packages. Package management systems will create a file at:
$(MSBuildProjectExtensionsPath)\$(MSBuildProjectFile).<SomethingUnique>.props
Each package management system should use a unique moniker to avoid collisions. It is a wild-card import so the package
management system can write out multiple files but the order of the import is alphabetic because MSBuild sorts the list.
-->
<PropertyGroup>
<!--
The declaration of $(BaseIntermediateOutputPath) had to be moved up from Microsoft.Common.CurrentVersion.targets
in order for the $(MSBuildProjectExtensionsPath) to use it as a default.
-->
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">obj\</BaseIntermediateOutputPath>
<BaseIntermediateOutputPath Condition="!HasTrailingSlash('$(BaseIntermediateOutputPath)')">$(BaseIntermediateOutputPath)\</BaseIntermediateOutputPath>
<_InitialBaseIntermediateOutputPath>$(BaseIntermediateOutputPath)</_InitialBaseIntermediateOutputPath>
<MSBuildProjectExtensionsPath Condition="'$(MSBuildProjectExtensionsPath)' == '' ">$(BaseIntermediateOutputPath)</MSBuildProjectExtensionsPath>
<!--
Import paths that are relative default to be relative to the importing file. However, since MSBuildExtensionsPath
defaults to BaseIntermediateOutputPath we expect it to be relative to the project directory. So if the path is relative
it needs to be made absolute based on the project directory.
-->
<MSBuildProjectExtensionsPath Condition="'$([System.IO.Path]::IsPathRooted($(MSBuildProjectExtensionsPath)))' == 'false'">$([System.IO.Path]::Combine('$(MSBuildProjectDirectory)', '$(MSBuildProjectExtensionsPath)'))</MSBuildProjectExtensionsPath>
<MSBuildProjectExtensionsPath Condition="!HasTrailingSlash('$(MSBuildProjectExtensionsPath)')">$(MSBuildProjectExtensionsPath)\</MSBuildProjectExtensionsPath>
<ImportProjectExtensionProps Condition="'$(ImportProjectExtensionProps)' == ''">true</ImportProjectExtensionProps>
<_InitialMSBuildProjectExtensionsPath Condition=" '$(ImportProjectExtensionProps)' == 'true' ">$(MSBuildProjectExtensionsPath)</_InitialMSBuildProjectExtensionsPath>
</PropertyGroup>
....
Устранение неполадок
В этом разделе рассматриваются распространенные проблемы при работе с Directory.Build.props и Directory.Build.targets.
Свойство не вступает в силу
Если свойство, заданное в Directory.Build.props , не работает:
Проверьте порядок импорта: свойство может быть перезаписано позже. Используйте
msbuild /pp:preprocessed.xml YourProject.csproj, чтобы просмотреть полный порядок импорта и положение вашего свойства относительно того, где оно используется.Проверьте расположение файла: MSBuild выполняет поиск вверх из каталога проекта. Убедитесь, что файл находится в вышестоящем каталоге вашего проекта.
Проверьте опечатки в имени файла: имя файла должно быть именно Directory.Build.props (не directory.build.props в файловых системах, учитывающих регистр).
Конфликты между несколькими файлами "Directory.Build"
Если у вас есть файлы Directory.Build.props на нескольких уровнях в иерархии папок и свойства не объединяются должным образом:
- Помните, что MSBuild перестает выполнять поиск после поиска первого файла.
- Используйте метод, показанный в
варианте использования: многоуровневое слияние , чтобы объединить файлы. - Используйте
$(DirectoryBuildPropsPath), чтобы явно указать, какой файл нужно импортировать.
Изменения, не отраженные в Visual Studio
Visual Studio кэширует сведения о проекте. После изменения Directory.Build.props или Directory.Build.targets:
- Сохраните все файлы.
- Закройте решение и откройте его снова или
- Щелкните правой кнопкой мыши решение и выберите "Перезагрузить проект".