다음을 통해 공유


Visual Studio 빌드 프로세스 확장

Visual Studio 빌드 프로세스는 프로젝트 파일로 가져온 일련의 MSBuild .targets 파일에 의해 정의됩니다. Visual Studio 프로젝트처럼 SDK를 사용하는 경우 이러한 가져오기는 암시적입니다. 이러한 가져온 파일 중 하나인 Microsoft.Common.targets를 확장하여 빌드 프로세스의 여러 지점에서 사용자 지정 작업을 실행할 수 있습니다. 이 문서에서는 Visual Studio 빌드 프로세스를 확장하는 데 사용할 수 있는 세 가지 방법을 설명합니다.

  • 사용자 지정 대상을 만들고 BeforeTargetsAfterTargets 특성을 사용하여 실행 시기를 지정합니다.

  • 공통 목표에서 DependsOn에 정의된 속성을 재정의합니다.

  • 공통 대상(Microsoft.Common.targets 또는 가져오는 파일)에 정의된 특정 미리 정의된 대상을 재정의합니다.

AfterTargets 및 BeforeTargets

사용자 지정 대상에서 특성을 사용하여 AfterTargetsBeforeTargets 실행할 시기를 지정할 수 있습니다.

다음 예제에서는 특성을 사용하여 AfterTargets 출력 파일에서 작업을 수행하는 사용자 지정 대상을 추가하는 방법을 보여줍니다. 이 경우 출력 파일을 CustomOutput 폴더에 복사합니다. 이 예제는 CustomClean 특성을 사용하고 사용자 지정 정리 작업이 BeforeTargets 대상 전에 실행되도록 지정함으로써 CoreClean 대상을 사용하여 사용자 지정 빌드 작업에서 생성된 파일을 정리하는 방법을 보여줍니다.

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
     <TargetFramework>netcoreapp3.1</TargetFramework>
     <_OutputCopyLocation>$(OutputPath)..\..\CustomOutput\</_OutputCopyLocation>
  </PropertyGroup>

  <Target Name="CustomAfterBuild" AfterTargets="Build">
    <ItemGroup>
      <_FilesToCopy Include="$(OutputPath)**\*"/>
    </ItemGroup>
    <Message Text="_FilesToCopy: @(_FilesToCopy)" Importance="high"/>

    <Message Text="DestFiles:
        @(_FilesToCopy->'$(_OutputCopyLocation)%(RecursiveDir)%(Filename)%(Extension)')"/>

    <Copy SourceFiles="@(_FilesToCopy)"
          DestinationFiles=
          "@(_FilesToCopy->'$(_OutputCopyLocation)%(RecursiveDir)%(Filename)%(Extension)')"/>
  </Target>

  <Target Name="CustomClean" BeforeTargets="CoreClean">
    <Message Text="Inside Custom Clean" Importance="high"/>
    <ItemGroup>
      <_CustomFilesToDelete Include="$(_OutputCopyLocation)**\*"/>
    </ItemGroup>
    <Delete Files='@(_CustomFilesToDelete)'/>
  </Target>
</Project>

경고

미리 정의된 대상은 SDK 가져오기를 통해 재정의되므로, 반드시 미리 정의된 대상과 다른 이름을 사용해야 합니다. 예를 들어, 여기에서 사용자 지정 빌드 대상은 CustomAfterBuild이고, AfterBuild이 아닙니다. 미리 정의된 대상 목록은 이 문서의 끝부분에 있는 표를 참조하세요.

DependsOn 속성 확장

빌드 프로세스를 확장하는 또 다른 방법은 속성(예DependsOn: )을 사용하여 BuildDependsOn 표준 대상 전에 실행해야 하는 대상을 지정하는 것입니다.

이 메서드는 다음 섹션에서 논의될 미리 정의된 대상을 재정의하는 것보다 더 선호됩니다. 미리 정의된 대상 재정의는 여전히 지원되는 이전 메서드이지만 MSBuild는 대상 정의를 순차적으로 평가하므로 프로젝트를 가져오는 다른 프로젝트가 이미 재정의된 대상을 재정의하지 못하도록 방지할 수 없습니다. 예를 들어 다른 모든 프로젝트를 가져온 후 프로젝트 파일에 정의된 마지막 AfterBuild 대상은 빌드 중에 사용되는 대상이 됩니다.

DependsOn 속성을 공통 대상 전반의 DependsOnTargets 특성에서 재정의하여 대상의 의도치 않은 재정의를 방지할 수 있습니다. 예를 들어 대상에는 Build .의 DependsOnTargets특성 값이 "$(BuildDependsOn)" 포함됩니다. 고려할 사항은 다음과 같습니다.

<Target Name="Build" DependsOnTargets="$(BuildDependsOn)"/>

이 XML 조각은 대상이 실행되기 전에 Build 속성에 BuildDependsOn 지정된 모든 대상이 먼저 실행되어야 임을 나타냅니다. 속성은 BuildDependsOn 다음과 같이 정의됩니다.

<PropertyGroup>
    <BuildDependsOn>
        $(BuildDependsOn);
        BeforeBuild;
        CoreBuild;
        AfterBuild
    </BuildDependsOn>
</PropertyGroup>

프로젝트 파일의 끝에 BuildDependsOn라는 속성을 선언하여 이 속성 값을 재정의할 수 있습니다. SDK 스타일 프로젝트에서는 명시적 가져오기를 사용해야 합니다. 마지막 가져오기 다음에 속성을 넣을 수 있도록 DependsOn 참조하세요. 새 속성에 이전 BuildDependsOn 속성을 포함하면 대상 목록의 시작과 끝에 새 대상을 추가할 수 있습니다. 다음은 그 예입니다.

<PropertyGroup>
    <BuildDependsOn>
        MyCustomTarget1;
        $(BuildDependsOn);
        MyCustomTarget2
    </BuildDependsOn>
</PropertyGroup>

<Target Name="MyCustomTarget1">
    <Message Text="Running MyCustomTarget1..."/>
</Target>
<Target Name="MyCustomTarget2">
    <Message Text="Running MyCustomTarget2..."/>
</Target>

프로젝트 파일을 가져오는 프로젝트는 사용자가 만든 사용자 지정을 덮어쓰지 않고도 이러한 속성을 추가로 확장할 수 있습니다.

DependsOn 속성을 재정의하려면

  1. 재정의하려는 공통 대상에서 미리 정의된 DependsOn 속성을 식별합니다. 일반적으로 재정의된 DependsOn 속성 목록은 다음 표를 참조하세요.

  2. 프로젝트 파일의 끝에 있는 속성 또는 속성의 다른 인스턴스를 정의합니다. 새 속성에 원래 속성(예 $(BuildDependsOn): )을 포함합니다.

  3. 속성 정의 전후에 사용자 지정 대상을 정의합니다.

  4. 프로젝트 파일을 빌드합니다.

일반적으로 재정의된 DependsOn 속성

속성 이름 추가된 대상은 이 시점 이전에 실행됩니다.
BuildDependsOn 기본 빌드 진입점입니다. 전체 빌드 프로세스 전후에 사용자 지정 대상을 삽입하려는 경우 이 속성을 재정의합니다.
RebuildDependsOn Rebuild
RunDependsOn 최종 빌드 출력의 실행(.EXE 경우)
CompileDependsOn 해당 컴파일(Compile 대상)입니다. 컴파일 단계 전후에 사용자 지정 프로세스를 삽입하려는 경우 이 속성을 재정의합니다.
CreateSatelliteAssembliesDependsOn 위성 어셈블리 만들기
CleanDependsOn Clean 대상(모든 중간 및 최종 빌드 출력 삭제)입니다. 사용자 지정 빌드 프로세스에서 출력을 정리하려는 경우 이 속성을 재정의합니다.
PostBuildEventDependsOn PostBuildEvent 대상
PublishBuildDependsOn 빌드 게시
ResolveAssemblyReferencesDependsOn ** ResolveAssemblyReferences 대상(지정된 종속성의 전이적 폐쇄를 찾기). ResolveAssemblyReference을(를) 참조하세요.

예: BuildDependsOn 및 CleanDependsOn

다음 예제는 BeforeTargetsAfterTargets 예제와 비슷하지만, 유사한 기능을 구현하는 방법을 보여줍니다. BuildDependsOn를 사용하여 빌드 후 출력 파일을 복사하는 고유한 작업 CustomAfterBuild를 추가하여 빌드를 확장하며, CustomClean를 사용하여 해당 CleanDependsOn 작업도 추가합니다.

이 예제에서는 SDK 스타일 프로젝트입니다. 이 문서의 앞부분에 있는 SDK 스타일 프로젝트에 대한 참고 사항에서 설명한 것처럼 Visual Studio에서 프로젝트 파일을 생성할 때 사용하는 특성 대신 Sdk 수동 가져오기 메서드를 사용해야 합니다.

<Project>
  <Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk"/>

  <PropertyGroup>
    <TargetFramework>netcoreapp3.1</TargetFramework>
  </PropertyGroup>

  <Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk"/>

  <PropertyGroup>
    <BuildDependsOn>
      $(BuildDependsOn);CustomAfterBuild
    </BuildDependsOn>

    <CleanDependsOn>
      $(CleanDependsOn);CustomClean
    </CleanDependsOn>

    <_OutputCopyLocation>$(OutputPath)..\..\CustomOutput\</_OutputCopyLocation>
  </PropertyGroup>

  <Target Name="CustomAfterBuild">
    <ItemGroup>
      <_FilesToCopy Include="$(OutputPath)**\*"/>
    </ItemGroup>
    <Message Importance="high" Text="_FilesToCopy: @(_FilesToCopy)"/>

    <Message Text="DestFiles:
      @(_FilesToCopy-&gt;'$(_OutputCopyLocation)%(RecursiveDir)%(Filename)%(Extension)')"/>

    <Copy SourceFiles="@(_FilesToCopy)"
          DestinationFiles="@(_FilesToCopy-&gt;'$(_OutputCopyLocation)%(RecursiveDir)%(Filename)%(Extension)')"/>
  </Target>

  <Target Name="CustomClean">
    <Message Importance="high" Text="Inside Custom Clean"/>
    <ItemGroup>
      <_CustomFilesToDelete Include="$(_OutputCopyLocation)**\*"/>
    </ItemGroup>
    <Delete Files="@(_CustomFilesToDelete)"/>
  </Target>
</Project>

요소의 순서가 중요합니다. BuildDependsOnCleanDependsOn 요소는 표준 SDK 대상 파일을 가져온 후에 나타나야 합니다.

미리 정의된 대상 덮어쓰기

공통 .targets 파일에는 빌드 프로세스의 일부 주요 대상 전후에 호출되는 미리 정의된 빈 대상 집합이 포함되어 있습니다. 예를 들어, MSBuild는 BeforeBuild 대상을 주 CoreBuild 대상 앞에 호출하고, AfterBuild 대상 뒤에 CoreBuild 대상을 호출합니다. 기본적으로 공통 대상의 빈 대상은 아무 작업도 수행하지 않지만 프로젝트 파일에서 원하는 대상을 정의하여 기본 동작을 재정의할 수 있습니다. 이 문서의 앞부분에서 설명한 메서드가 선호되지만 이 메서드를 사용하는 이전 코드가 발생할 수 있습니다.

프로젝트에서 SDK를 사용하는 경우(예 Microsoft.Net.Sdk: 명시적 가져오기 및 암시적 가져오기에서 설명한 대로) 암시적 가져오기에서 명시적 가져오기로 변경해야 합니다.

미리 정의된 대상을 덮어쓰려면

  1. 프로젝트에서 Sdk 특성을 사용하는 경우, 명시적으로 가져오기 구문으로 바꿉니다. 명시적 및 암시적 가져오기를 참조하세요.

  2. 재정의하려는 공통 대상에서 미리 정의된 대상을 식별합니다. 안전하게 재정의할 수 있는 대상의 전체 목록은 다음 표를 참조하세요.

  3. 프로젝트 파일의 끝 부분에서 명시적 SDK 가져오기 직후 및 </Project> 태그 바로 앞에 대상을 정의합니다. 다음은 그 예입니다.

    <Project>
        <Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" />
        ...
        <Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" />
        <Target Name="BeforeBuild">
            <!-- Insert tasks to run before build here -->
        </Target>
        <Target Name="AfterBuild">
            <!-- Insert tasks to run after build here -->
        </Target>
    </Project>
    

    최상위 Sdk 요소의 Project 특성이 제거되었습니다.

  4. 프로젝트 파일을 빌드합니다.

미리 정의된 대상 테이블

다음 표는 재정의할 수 있는 공통 대상의 모든 대상을 나타냅니다.

대상 이름 설명
BeforeCompile, AfterCompile 이러한 대상 중 하나에 삽입된 작업은 코어 컴파일이 완료되기 전이나 후에 실행됩니다. 대부분의 사용자 지정은 이러한 두 대상 중 하나에서 수행됩니다.
BeforeBuild, AfterBuild 이러한 대상 중 하나에 삽입된 작업은 빌드의 다른 모든 항목 앞이나 뒤에 실행됩니다. 메모:BeforeBuild 대부분의 프로젝트 파일 끝에 있는 주석에 대상과 AfterBuild 대상이 이미 정의되어 있으므로 빌드 전 이벤트와 빌드 후 이벤트를 프로젝트 파일에 쉽게 추가할 수 있습니다.
BeforeRebuild, AfterRebuild 이러한 대상 중 하나에 삽입된 작업은 핵심 다시 빌드 기능이 호출되기 전이나 후에 실행됩니다. Microsoft.Common.targets의 대상 실행 순서는 다음과 BeforeRebuildCleanBuildAfterRebuild같습니다.
BeforeClean, AfterClean 이러한 대상 중 하나에 삽입된 작업은 핵심 정리 기능이 호출되기 전이나 후에 실행됩니다.
BeforePublish, AfterPublish 이러한 대상 중 하나에 삽입된 작업은 핵심 게시 기능이 호출되기 전이나 후에 실행됩니다.
BeforeResolveReferences, AfterResolveReferences 이러한 대상 중 하나에 삽입된 작업은 어셈블리 참조가 해결되기 전이나 후에 실행됩니다.
BeforeResGen, AfterResGen 이러한 대상 중 하나에 삽입된 작업은 리소스가 생성되기 전이나 후에 실행됩니다.

빌드 시스템 및 .NET SDK에는 더 많은 대상이 있습니다. MSBuild 대상( SDK 및 기본 빌드 대상)을 참조하세요.

사용자 지정 대상에 대한 모범 사례

속성 DependsOnTargetsBeforeTargets 둘 다 대상이 다른 대상 앞에 실행되도록 지정할 수 있지만 서로 다른 시나리오에서 둘 다 필요합니다. 종속성 요구 사항이 지정되는 대상 방식이 다릅니다. 사용자 고유의 대상만 제어할 수 있으며 시스템 대상 또는 기타 가져온 대상을 안전하게 수정할 수 없으므로 선택한 메서드를 제약할 수 있습니다.

사용자 지정 대상을 작성할 때 다음 일반 지침에 따라 대상이 의도한 순서대로 실행되도록 합니다.

  1. DependsOnTargets 특성을 사용하여 대상이 실행되기 전에 수행해야 하는 대상을 지정합니다. 제어하는 대상 체인의 경우 각 대상은 체인 DependsOnTargets의 이전 멤버를 지정할 수 있습니다.

  2. 제어할 수 없는 대상을 먼저 실행해야 할 때 BeforeTargets를 사용하세요(예를 들어, 빌드 초기에 실행해야 하는 대상을 위한 BeforeTargets="PrepareForBuild"와 같이 사용).

  3. 귀하가 제어하지 않는 대상 중 필요한 출력의 사용 가능성을 보장하는 모든 대상에 AfterTargets를 사용합니다. 예를 들어 참조 목록을 수정할 항목을 지정 AfterTargets="ResolveReferences" 합니다.

  4. 이러한 항목을 조합하여 사용할 수 있습니다. 예: DependsOnTargets="GenerateAssemblyInfo" BeforeTargets="BeforeCompile".

명시적 및 암시적 가져오기

Visual Studio에서 생성된 프로젝트는 일반적으로 프로젝트 요소의 Sdk 특성을 사용합니다. 이러한 유형의 프로젝트를 SDK 스타일 프로젝트라고합니다. MSBuild 프로젝트 SDK 사용참조하세요. 예제는 다음과 같습니다.

<Project Sdk="Microsoft.Net.Sdk">

프로젝트에서 특성을 사용하는 Sdk 경우 두 개의 가져오기가 암시적으로 추가되고, 하나는 프로젝트 파일의 시작 부분에, 다른 하나는 끝에 추가됩니다.

암시적 가져오기는 다음과 같은 import 문을 요소 뒤 Project 의 프로젝트 파일의 첫 번째 줄로 사용하는 것과 같습니다.

<Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" />

및 다음 import 문을 프로젝트 파일의 마지막 줄로 지정합니다.

<Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" />

이 구문을 명시적 SDK 가져오기라고 합니다. 이 명시적 구문을 사용하는 경우 프로젝트 요소의 Sdk 특성을 생략해야 합니다.

암시적 SDK 가져오기는 다음과 같이 이전 프로젝트 파일에서 일반적인 구문인 특정 "공통" .props 또는 .targets 파일을 가져오는 것과 같습니다.

<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />

<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />

이러한 이전 참조는 이 섹션의 앞부분에 표시된 명시적 SDK 구문으로 바꿔야 합니다.

명시적 SDK 구문을 사용하면 첫 번째 가져오기 전이나 최종 SDK 가져오기 후에 고유한 코드를 추가할 수 있습니다. 즉, 가져온 파일에 적용되는 .props 첫 번째 가져오기 전에 속성을 설정하여 동작을 변경할 수 있으며, 최종 가져오기 후에 SDK .targets 파일 중 하나에 정의된 대상을 재정의할 수 있습니다. 이 메서드를 사용하여 BeforeBuild 또는 AfterBuild를 다음에 설명한 대로 재정의할 수 있습니다.

다음 단계

빌드를 사용자 지정하기 위해 MSBuild를 사용하여 수행할 수 있는 작업은 훨씬 더 많습니다. 을 참조하여을 사용자 지정합니다.