Megosztás a következőn keresztül:


A build testreszabása mappa szerint

Az MSBuild által importálandó bizonyos fájlokat hozzáadhat az alapértelmezett tulajdonságbeállítások felülbírálásához és egyéni célok hozzáadásához. Ezeknek a testreszabásoknak a hatóköre a mappa szintjén szabályozható a fájlok elhelyezésének helye szerint.

Ez a cikk az alábbi forgatókönyvekre vonatkozó testreszabásokat ismerteti:

  • Több projekt buildbeállításainak testreszabása egy megoldásban
  • Számos megoldás buildbeállításainak testreszabása egy közös fájlkönyvtárban
  • A mappák összetett struktúrájában lévő almappák esetében eltérő buildbeállítások testreszabása
  • Felülbírálja az alapértelmezett beállításokat, az alapértelmezett buildmappákat és az SDK által beállított egyéb viselkedéseket, például Microsoft.Net.Sdk
  • Tetszőleges számú projektre vagy megoldásra vonatkozó buildcélok hozzáadása vagy testreszabása

Ha C++ projektekkel dolgozik, a C++ buildek testreszabása című cikkben ismertetett módszereket is használhatja.

Directory.Build.props és Directory.Build.targets

Minden projekthez hozzáadhat egy új tulajdonságot, ha egyetlen, Directory.Build.props nevű fájlban definiálja, a forrást tartalmazó gyökérmappában.

Az MSBuild futtatásakor a Microsoft.Common.props megkeresi a címtárstruktúrában a Directory.Build.props fájlt. Ha talál egyet, importálja a fájlt, és beolvassa a benne definiált tulajdonságokat. Directory.Build.props egy felhasználó által definiált fájl, amely testre szabja a címtárban lévő projekteket.

Hasonlóképpen, Microsoft.Common.targetsDirectory.Build.targetskeres.

Directory.Build.props importálása az importált fájlok sorozatának korai szakaszában történik, ami akkor lehet fontos, ha be kell állítania egy importálás által használt tulajdonságot, különösen azokat, amelyeket implicit módon importál a Sdk attribútum használatával, például amikor a .NET SDK-t használja a legtöbb .NET-projektfájlban.

Jegyzet

A Linux-alapú fájlrendszerek megkülönböztetik a kis- és nagybetűket. Győződjön meg arról, hogy a Directory.Build.props fájlnév pontosan egyezik, különben nem lesz észlelhető a build folyamat során.

** További információkért tekintse meg ezt a GitHub-hibajegyet: .

Directory.Build.props példa

Íme például egy Directory.Build.props fájl, amely beállítja a kimeneti könyvtárat a Visual Studio-megoldás összes projektjének. Az egyes projektek kimenete a saját projektnév alatt van elhelyezve. Ebben a példában a Directory.Build.props fájl egy megoldásmappában található, amely alatt számos projekt található almappákban. A $(MSBuildProjectName) tulajdonság az egyes projektek nevét adja meg. Mivel a Directory.Build.props fájl importálása az egyes projektekbe a saját buildelése során történik, a rendszer a megoldás minden egyes projektjének megfelelő értékre értékeli ki.

  1. Törölje a megoldást a régi kimeneti fájlok eltávolításához.

    msbuild /t:Clean SolutionName.sln

  2. Hozzon létre egy új fájlt a Directory.Build.propsnevű adattár gyökerében.

  3. Adja hozzá a következő XML-t a fájlhoz.

    <Project>
       <PropertyGroup>
          <OutDir>C:\output\$(MSBuildProjectName)</OutDir>
       </PropertyGroup>
    </Project>
    

    Jegyzet

    A $(OutDir) tulajdonság abszolút elérési út a kimenethez, és használata megkerüli a .NET-projektekben általában használt konfigurációhoz, célkerethez vagy futtatókörnyezethez tartozó almappák létrehozását. Használja inkább a BaseOutputPath tulajdonságot, ha azt szeretné, hogy a szokásos almappák egyéni kimeneti útvonalon legyenek létrehozva.

  4. Futtassa az MSBuild parancsot. A projekt meglévő importálásai, a Microsoft.Common.props és a Microsoft.Common.targets, megtalálják és importálják a Directory.Build.props fájlt, azután az új kimeneti mappát használják az adott mappában lévő összes projekthez.

Keresési hatókör

Ha egy Directory.Build.props fájlt keres, az MSBuild felfelé halad a címtárszerkezeten a projekt helyétől $(MSBuildProjectFullPath), és leáll, miután megtalálta a Directory.Build.props fájlt. Ha például a $(MSBuildProjectFullPath)c:\users\username\code\test\case1volt, az MSBuild ott kezdi a keresést, majd felfelé keres a könyvtárstruktúrában, amíg el nem helyez egy Directory.Build.props fájlt, ahogyan az a következő könyvtárszerkezetben is látható.

c:\users\username\code\test\case1
c:\users\username\code\test
c:\users\username\code
c:\users\username
c:\users
c:\

A megoldásfájl helyének nincs jelentősége a Directory.Build.propsszempontjából.

Rendelés importálása

A Directory.Build.props korán, már a Microsoft.Common.propselején kerül importálásra, így a később definiált tulajdonságok nem érhetők el. Ezért ne hivatkozz olyan tulajdonságokra, amelyek még nincsenek definiálva (és üresnek lesznek értékelve).

A Directory.Build.props megadott tulajdonságok felülírhatók a projektfájl más részeiben vagy az importált fájlokban, ezért a Directory.Build.props beállításaira kell gondolnia a projektek alapértelmezett beállításainak megadásaként.

Directory.Build.targets a Microsoft.Common.targets-ból importálódik, miután a .targets fájlokat importálták a NuGet-csomagokból. Így felülbírálhatja a legtöbb buildlogikában definiált tulajdonságokat és célokat, vagy beállíthatja az összes projekt tulajdonságait, függetlenül attól, hogy az egyes projektek mit állítottak be.

Ha meg kell adnia egy tulajdonságot, vagy meg kell határoznia egy célértéket egy olyan projekthez, amely felülírja a korábbi beállításokat, a végső importálás után helyezze el ezt a logikát a projektfájlban. Ahhoz, hogy ezt egy SDK-stílusú projektben elvégezhesse, először az SDK-stílusú attribútumot kell lecserélnie az egyenértékű importálásra. Lásd a(z) : MSBuild projekt SDK-k használata.

Jegyzet

Az MSBuild motor a kiértékelés alatt beolvassa az importált fájlokat még a projekt építésének megkezdése előtt (beleértve a PreBuildEvent-t is), így ezeket a fájlokat a PreBuildEvent vagy a buildfolyamat más része nem módosíthatja. A módosítások csak a MSBuild.exe következő meghívásakor, vagy a következő Visual Studio épüléskor lépnek érvénybe. Emellett, ha a build folyamat több projekt buildet tartalmaz (például többcélú felépítés vagy függő projektek esetében), akkor az importált fájlokat, köztük a Directory.build.props, az egyes projektbuildek értékelése során tölti be a rendszer.

Használati eset: többszintű egyesítés

Tegyük fel, hogy rendelkezik ezzel a standard megoldásstruktúrával:

\
  MySolution.sln
  Directory.Build.props     (1)
  \src
    Directory.Build.props   (2-src)
    \Project1
    \Project2
  \test
    Directory.Build.props   (2-test)
    \Project1Tests
    \Project2Tests

Kívánatos lehet, hogy az összes projekt közös tulajdonságokkal rendelkezzen (1), projektek (2 src)közös tulajdonságaival, valamint a teszt projektek (2-teszt)közös tulajdonságaival.

Ahhoz, hogy az MSBuild megfelelően egyesítse a "belső" fájlokat (2 src és 2-teszt) a "külső" fájllal (1), figyelembe kell vennie, hogy miután az MSBuild megtalálta a Directory.Build.props fájlt, az leállítja a további vizsgálatot. A vizsgálat folytatásához és a külső fájlba való egyesítéshez helyezze a kódot mindkét belső fájlba:

<Import Project="$([MSBuild]::GetPathOfFileAbove('Directory.Build.props', '$(MSBuildThisFileDirectory)../'))" />

Az MSBuild általános megközelítésének összefoglalása a következő:

  • Az MSBuild minden adott projekt esetében megkeresi az első Directory.Build.props felfelé a megoldásstruktúrában, egyesíti az alapértelmezett értékekkel, és leállítja a további kereséseket.
  • Ha több szintet szeretne megtalálni és egyesíteni, akkor <Import...> (korábban látható) válassza külön a "külső" fájlt a "belső" fájltól.
  • Ha a "külső" fájl maga sem importál valamit felette, akkor a vizsgálat ott leáll.

Az egyszerűség kedvéért: az első Directory.Build.props, amely nem importál semmit, ott van, ahol az MSBuild megáll.

Az importálási folyamat pontosabb szabályozásához használja a tulajdonságokat $(DirectoryBuildPropsPath), $(ImportDirectoryBuildProps), $(DirectoryBuildTargetsPath)és $(ImportDirectoryBuildTargets). A $(DirectoryBuildPropsPath) tulajdonság határozza meg a használni kívánt Directory.Build.props fájl elérési útját; Hasonlóképpen, $(DirectoryBuildTargetsPath) a Directory.Build.targets fájl elérési útját adja meg.

A logikai tulajdonságok $(ImportDirectoryBuildProps) és $(ImportDirectoryBuildTargets) alapértelmezés szerint true-re vannak beállítva, így az MSBuild rendszerint megkeresi ezeket a fájlokat, de átállíthatja őket false-ra, hogy megakadályozza az MSBuild-et abban, hogy importálja őket.

Példa

Ez a példa az előre feldolgozott kimenet használatát mutatja be annak meghatározásához, hogy hol kell beállítani egy tulajdonságot.

Egy beállítani kívánt tulajdonság használatának elemzéséhez futtassa az MSBuild parancsot a /preprocess vagy /pp argumentummal. A kimeneti szöveg az összes importálás eredménye, beleértve az olyan rendszerimportálásokat is, mint a Microsoft.Common.props, amelyek implicit módon vannak importálva, valamint a saját importálásai. Ezzel a kimenettel láthatja, hogy a tulajdonságot a használt értékhez képest hol kell beállítani.

Tegyük fel például, hogy egy egyszerű .NET Core- vagy .NET 5-ös vagy újabb konzolalkalmazás-projekttel rendelkezik, és testre szeretné szabni a köztes kimeneti mappát, általában obj. Az elérési utat megadó tulajdonság a(z) BaseIntermediateOutput. Ha ezt egy PropertyGroup elembe próbálja helyezni a projektfájlban, a már beállított különböző tulajdonságokkal (például TargetFramework) együtt, a projekt létrehozásakor felfedezheti, hogy a tulajdonság nem lép érvénybe. Ha az MSBuild parancsot a /pp beállítással futtatja, és a kimenetben BaseIntermediateOutputPathkeres, láthatja, hogy miért. Ebben az esetben a BaseIntermediateOutput-t beolvasottként használják a Microsoft.Common.props-ben.

A Microsoft.Common.props fájlban van egy megjegyzés, amely szerint a BaseIntermediateOutput tulajdonságot itt kell beállítani, mielőtt egy másik tulajdonság, MSBuildProjectExtensionsPath, használná. Azt is láthatja, hogy ha a BaseIntermediateOutputPath először be van állítva, megjelenik egy már meglévő érték ellenőrzése, és ha nincs meghatározva, akkor objértékre lesz állítva.

<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">obj\</BaseIntermediateOutputPath>

Az elhelyezés tehát azt jelzi, hogy a tulajdonság beállításához valahol korábban be kell azt megadni. Mielőtt az előre feldolgozott kimenetben lévő kódhoz érne, láthatja, hogy a Directory.Build.props importálva van, így beállíthatja a BaseIntermediateOutputPath-et, és elég korán lesz beállítva ahhoz, hogy elérje a kívánt hatást.

Az alábbi rövidített előre feldolgozott kimenet azt mutatja, hogy mi történik, amikor a BaseIntermediateOutput beállítást beillesztik a Directory.Build.props-be. A szabványos importálások tetején található megjegyzések közé tartozik a fájlnév és általában néhány hasznos információ a fájl importálásának okáról.

<?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>
  ...