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.
Törölje a megoldást a régi kimeneti fájlok eltávolításához.
msbuild /t:Clean SolutionName.sln
Hozzon létre egy új fájlt a Directory.Build.propsnevű adattár gyökerében.
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 aBaseOutputPath
tulajdonságot, ha azt szeretné, hogy a szokásos almappák egyéni kimeneti útvonalon legyenek létrehozva.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 BaseIntermediateOutputPath
keres, 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>
...