Aracılığıyla paylaş


Derlemeyi klasöre göre özelleştirme

Varsayılan özellik ayarlarını geçersiz kılmak ve özel hedefler eklemek için MSBuild tarafından içeri aktarılacak bazı dosyaları ekleyebilirsiniz. Bu özelleştirmelerin kapsamı, bu dosyaların yerleştirildiği klasör düzeyinde denetlenebilir.

Bu makale, aşağıdaki senaryolar için geçerli olan özelleştirmeleri kapsar:

  • Çözümdeki birçok proje için derleme ayarlarını özelleştirme
  • Ortak bir dosya dizini altında birçok çözüm için derleme ayarlarını özelleştirme
  • Klasörlerin karmaşık yapısındaki alt klasörler için farklı olabilecek derleme ayarlarını özelleştirme
  • Varsayılan ayarları, varsayılan derleme klasörlerini ve Microsoft.Net.Sdk gibi bir SDK tarafından ayarlanan diğer davranışları geçersiz kılma
  • Herhangi bir sayıda proje veya çözüm için geçerli olan derleme hedeflerini ekleme veya özelleştirme

C++ projeleriyle çalışıyorsanız, C++ derlemelerini özelleştirmebölümünde açıklanan yöntemleri de kullanabilirsiniz.

Directory.Build.props ve Directory.Build.targets

Kaynağınızı içeren kök klasörde Directory.Build.props adlı tek bir dosyada tanımlayarak her projeye yeni bir özellik ekleyebilirsiniz.

MSBuild çalıştırıldığında Microsoft.Common.props dizin yapınızda Directory.Build.props dosyasını arar. Bulursa, dosyayı içeri aktarır ve içinde tanımlanan özellikleri okur. Directory.Build.props, dizin altındaki projelere özelleştirmeler sağlayan kullanıcı tanımlı bir dosyadır.

Benzer şekilde, Microsoft.Common.targetsDirectory.Build.targets'ı arar.

Directory.Build.props, içeri aktarılan dosyalar dizisinin erken aşamalarında içeri aktarılır; özellikle de çoğu .NET proje dosyasında .NET SDK'sını kullanırken olduğu gibi, Sdk özniteliği kullanılarak örtük olarak içeri aktarılanlar gibi içeri aktarmalar tarafından kullanılan bir özellik ayarlamanız gerekiyorsa önemli olabilir.

Note

Linux tabanlı dosya sistemleri büyük/küçük harfe duyarlıdır. Directory.Build.props dosya adının büyük/küçük harf uyumunun tam olarak sağlandığından emin olun, yoksa derleme işlemi sırasında algılanmayacaktır.

Daha fazla bilgi için bu GitHub sorununu konusuna bakın.

Directory.Build.props örneği

Örneğin, visual studio çözümündeki tüm projeler için çıkış dizinini ayarlayan bir Directory.Build.props dosyası aşağıda verilmiştir. Her projenin çıktısı kendi proje adı altına yerleştirilir. Bu örnekte, Directory.Build.props dosyası, alt klasörlerde birçok proje bulunan bir çözüm klasöründedir. $(MSBuildProjectName) özelliği her projenin adını verir. Directory.Build.props dosyası kendi derlemesi sırasında her projeye aktarıldığından, çözümdeki her proje için doğru değere değerlendirilir.

  1. Eski çıkış dosyalarını kaldırmak için çözümü temizleyin.

    msbuild /t:Clean SolutionName.sln

  2. Deponuzun kökünde Directory.Build.propsadlı yeni bir dosya oluşturun.

  3. Dosyaya aşağıdaki XML'yi ekleyin.

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

    Not

    $(OutDir) özelliği çıkışın mutlak yoludur ve bunu kullanmak normalde .NET projelerinde kullanılan yapılandırma, hedef çerçeve veya çalışma zamanı için alt klasörlerin oluşturulmasını atlar. Her zamanki alt klasörlerin özel bir çıkış yolu altında oluşturulmasını istiyorsanız bunun yerine BaseOutputPath özelliğini kullanmayı deneyin.

  4. MSBuild'i çalıştırın. Projenizde hali hazırda bulunan Microsoft.Common.props ve Microsoft.Common.targets dosyalarının içeri aktarımı, Directory.Build.props dosyasını bulup içeri aktarır; ve bu durumda yeni çıktı klasörü, bu klasör altındaki tüm projeler için kullanılmaktadır.

Arama kapsamı

Directory.Build.props dosyasını ararken, MSBuild, $(MSBuildProjectFullPath)proje konumunuzdan itibaren dizin yapısını yukarı doğru tarar ve bir Directory.Build.props dosyası bulduğunda durur. Örneğin, $(MSBuildProjectFullPath) c:\users\username\code\test\case1 , MSBuild hemen orada aramaya başlar ve aşağıdaki dizin yapısında gösterildiği gibi bir Directory.Build.props dosyası bulana kadar dizin yapısını yukarı doğru tarar.

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

Çözüm dosyasının konumu, Directory.Build.props ile ilgisizdir.

İthalat siparişi

Directory.Build.props Microsoft.Common.props içindeerken içeri aktarılır ve daha sonra tanımlanan özellikler ona kullanılamaz duruma gelir. Bu nedenle, henüz tanımlanmamış (ve boş olarak değerlendirilecek) özelliklere başvurmaktan kaçının.

Directory.Build.props ayarlanan özellikler proje dosyasının başka bir yerinde veya içeri aktarılan dosyalarda geçersiz kılınabilir, bu nedenle Directory.Build.props içindeki ayarları projeleriniz için varsayılanları belirtmek olarak düşünmelisiniz.

Directory.Build.targets, NuGet paketlerinden .targets dosyalar içeri aktarıldıktan sonra, Microsoft.Common.targets'tan içeri aktarılır. Bu nedenle, derleme mantığının çoğunda tanımlanan özellikleri ve hedefleri geçersiz kılabilir veya tek tek projelerin ayarladığından bağımsız olarak tüm projeleriniz için özellikleri ayarlayabilir.

Önceki ayarları geçersiz kılan tek bir proje için bir özellik ayarlamanız veya hedef tanımlamanız gerektiğinde, bu mantığı son içeri aktarma işleminden sonra proje dosyasına yerleştirin. Bunu SDK stili bir projede yapmak için, önce SDK stili özniteliğini eşdeğer içeri aktarmalarla değiştirmeniz gerekir. bkz. MSBuild proje SDK'larınıkullanma.

Not

MSBuild altyapısı, bir proje için derleme yürütmeye başlamadan önce (herhangi bir PreBuildEventdahil) değerlendirme sırasında içeri aktarılan tüm dosyaları okur, bu nedenle bu dosyaların PreBuildEvent veya derleme işleminin başka bir bölümü tarafından değiştirilmesi beklenmez. Bir sonraki MSBuild.exe çağrılana kadar veya sonraki Visual Studio derlemesi yapılana kadar herhangi bir değişiklik geçerli olmaz. Ayrıca, derleme işleminiz birçok proje derlemesi içeriyorsa (çok hedefli veya bağımlı projeler oluştururken olduğu gibi), her bir proje derlemesi için değerlendirme gerçekleştiğinde Directory.build.propsdahil olmak üzere içeri aktarılan dosyalar okunur.

Kullanım örneği: çok seviyeli birleştirme

Bu standart çözüm yapısına sahip olduğunuzu varsayalım:

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

(1)tüm projeler için ortak özellikler, src projeleri (2-src)için ortak özellikler ve test projeleri (2-test)için ortak özelliklere sahip olmak istenebilir.

MSBuild'in "inner" dosyalarını (2-src ve 2-test) "dış" dosyayla (1) doğru bir şekilde birleştirmesini sağlamak için, MSBuild bir Directory.Build.props dosyası bulduğunda daha fazla taramayı durdurduğunu hesaba katmalısınız. Taramaya devam etmek ve dış dosyayla birleştirmek için bu kodu her iki iç dosyaya da yerleştirin:

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

MSBuild'in genel yaklaşımının özeti aşağıdaki gibidir:

  • Herhangi bir proje için MSBuild, çözüm yapısında yukarı doğru ilk Directory.Build.props öğesini bulur, varsayılan değerlerle birleştirir ve daha fazlasını taramayı durdurur.
  • Birden fazla seviyenin bulunup birleştirilmesini istiyorsanız, "iç" dosyadan "dış" dosyayı <Import...> (daha önce gösterildi) olarak birleştirin.
  • "Eğer 'dış' dosya kendisi de üstünde bir şey içe aktarmıyorsa, tarama orada durur."

Veya daha basit bir ifadeyle: Hiçbir şeyi içeri aktarmayan ilk Directory.Build.props MSBuild'in durduğu yerdir.

İçeri aktarma işlemini daha açık bir şekilde denetlemek için $(DirectoryBuildPropsPath), $(ImportDirectoryBuildProps), $(DirectoryBuildTargetsPath)ve $(ImportDirectoryBuildTargets)özelliklerini kullanın. özelliği $(DirectoryBuildPropsPath) kullanılacak Directory.Build.props dosyasının yolunu belirtir; benzer şekilde, $(DirectoryBuildTargetsPath)Directory.Build.targets dosyasının yolunu belirtir.

$(ImportDirectoryBuildProps) ve $(ImportDirectoryBuildTargets) Boole özellikleri varsayılan olarak true olarak ayarlanır, bu nedenle MSBuild normalde bu dosyaları arar, ancak MSBuild'in bunları içeri aktarmasını önlemek için bunları false olarak ayarlayabilirsiniz.

Örnek

Bu örnekte, bir özelliğin ayarlanacağı yeri belirlemek için önceden işlenmiş çıkışın kullanımı gösterilmektedir.

Ayarlamak istediğiniz belirli bir özelliğin kullanımını analiz etmeye yardımcı olmak için MSBuild'i /preprocess veya /pp bağımsız değişkeniyle çalıştırabilirsiniz. Çıkış metni, örtük olarak içeri aktarılan Microsoft.Common.props ve kendi içeri aktarmalarınızdan herhangi biri gibi sistem içeri aktarmaları da dahil olmak üzere tüm içeri aktarmaların sonucudur. Bu çıkışla, özelliğinizin değerinin kullanıldığı yere göre ayarlanması gereken yeri görebilirsiniz.

Örneğin, basit bir .NET Core veya .NET 5 veya üzeri Konsol Uygulaması projeniz olduğunu ve ara çıkış klasörünü özelleştirmek istediğinizi varsayalım( normalde obj). Bu yolu belirten özelliktir BaseIntermediateOutput. Bunu proje dosyanızdaki bir PropertyGroup öğesine ve TargetFrameworkgibi önceden ayarlanmış olan diğer özelliklerle birlikte yerleştirmeyi denerseniz, projeyi oluşturduğunuzda özelliğin etkili olmadığını keşfedersiniz. MSBuild'i /pp seçeneğiyle çalıştırır ve çıktıda BaseIntermediateOutputPatharaması yaparsanız nedenini görebilirsiniz. Bu durumda, BaseIntermediateOutputMicrosoft.Common.propsiçinde okunur ve kullanılır.

Microsoft.Common.props'da, MSBuildProjectExtensionsPathbaşka bir özellik tarafından kullanılmadan önce BaseIntermediateOutput özelliğinin burada ayarlanması gerektiğini belirten bir açıklama vardır. ayrıca, BaseIntermediateOutputPath ilk ayarlandığında önceden var olan bir değerin denetlendiğini ve tanımlanmamışsa değerinin objolarak ayarlandığını da görebilirsiniz.

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

Bu nedenle, bu konum size bu özelliğin daha erken bir yerde belirtilmesi gerektiğini söyler. Önceden işlenmiş çıktıdaki bu koddan hemen önce, Directory.Build.props'ın içeri aktarıldığını görebilirsiniz, böylece BaseIntermediateOutputPath'i orada ayarlayabilirsiniz ve istenen etkiyi sağlamak için yeterince erken ayarlanmış olur.

Aşağıdaki kısaltılmış önceden işlenmiş çıktı, BaseIntermediateOutput ayarını Directory.Build.propsiçine koymanın sonucunu gösterir. Standart içeri aktarmaların en üstündeki açıklamalar dosya adını ve genellikle bu dosyanın neden içeri aktarıldığını gösteren bazı yararlı bilgileri içerir.

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