패키지 병합

패키지 병합 (Package Bundling)

패키지 병합은 클래스 라이브러리에서 외부 패키지에 대한 의존성을 관리하는 방법 중 하나입니다. 클래스 라이브러리는 애플리케이션 내에서 특정 기능을 제공하기 위해 여러 외부 패키지를 사용하는 경우가 많습니다. 이러한 외부 패키지가 외부 애플리케이션에 노출되지 않고 라이브러리 내부에서만 사용되도록 하는 것이 패키지 병합의 목적입니다. 이를 통해 클래스 라이브러리를 더 모듈화하고, 외부 종속성과의 충돌을 방지할 수 있습니다.

패키지 병합의 필요성

패키지 병합은 라이브러리가 참조하는 외부 패키지와 애플리케이션의 충돌을 방지하는 데 유용합니다. 예를 들어, 클래스 라이브러리가 특정 버전의 외부 패키지를 사용하지만 이를 참조하는 애플리케이션이 동일한 패키지의 다른 버전을 필요로 하는 경우가 발생할 수 있습니다. 이때 패키지 병합을 통해 클래스 라이브러리의 종속성을 외부 애플리케이션에 노출하지 않음으로써 버전 충돌을 예방할 수 있습니다. 또한, 패키지 병합을 통해 외부 애플리케이션이 클래스 라이브러리의 내부 동작에 의존하지 않도록 하여 라이브러리의 독립성을 보장할 수 있습니다. 이는 라이브러리를 사용하는 애플리케이션이 외부 패키지와 상관없이 라이브러리의 기능을 사용할 수 있도록 해줍니다.

패키지 병합의 구현 방법

패키지 병합을 구현하는 한 가지 일반적인 방법은 .NETPrivateAssets 속성을 사용하는 것입니다. 이 속성은 클래스 라이브러리에서 사용되는 패키지가 외부 애플리케이션으로 노출되지 않도록 설정할 수 있게 해줍니다. 이를 통해 클래스 라이브러리 내부에서만 특정 패키지를 사용하도록 제한할 수 있습니다. 예를 들어, 클래스 라이브러리에서 Serilog 패키지를 사용하는 경우, 다음과 같이 PrivateAssets 속성을 설정할 수 있습니다

<PackageReference Include="Serilog" Version="4.0.1">
  <PrivateAssets>all</PrivateAssets>
</PackageReference>

이 설정은 다음과 같은 의미를 가집니다:

  • PrivateAssets=all: 클래스 라이브러리에서 사용하는 Serilog 패키지는 외부 애플리케이션에 노출되지 않습니다. 이로 인해 외부 애플리케이션이 Serilog에 대한 종속성을 가지지 않으며, 빌드 시 해당 DLL 파일도 외부 애플리케이션으로 복사되지 않습니다. PrivateAssetsall을 지정하면 컴파일, 빌드, 실행, 콘텐츠 파일 및 종속성과 관련된 자산들이 외부 애플리케이션에 전달되지 않도록 할 수 있습니다.

추가적인 병합 도구 사용

패키지 병합은 단일 파일 배포와는 다르며, 단일 파일 배포 방식처럼 물리적으로 모든 DLL 파일을 하나의 DLL로 병합하는 것이 아닙니다. 예를 들어, 다른 여러 dll을 참조하는 dll 을 만들 때, 패키지 병합을 실행한다고 하여 참조한 dll 들이 새로 생성되는 dll 에 포함되는 것은 아닙니다. 이를 위해서는 ILMerge 또는 Costura.Fody 등의 . 이 도구들은 DLL 파일을 단일 실행 파일로 병합하거나 종속성을 포함하는 방법을 제공합니다.

ILMerge

ILMerge는 여러 .NET 어셈블리(DLL 파일)를 하나의 단일 어셈블리로 병합하는 도구입니다. 이를 통해 여러 종속성 DLL을 하나의 DLL로 통합할 수 있으며, 배포 시 단일 파일만 배포되도록 할 수 있습니다. 이 도구는 주로 .NET Framework 프로젝트에서 사용됩니다.

Costura.Fody

Costura.Fody는 Fody의 플러그인 중 하나로, 여러 종속성 DLL을 실행 파일(EXE 또는 DLL)에 내장하는 방식으로 병합을 수행합니다. 이 도구는 종속성 파일을 물리적으로 하나로 병합하는 대신, 종속성 DLL을 리소스 형태로 포함하고, 런타임에 메모리에서 로드하는 방식으로 동작합니다. Costura.Fody는 .NET Core, .NET 5+, 그리고 .NET Framework 프로젝트에서 모두 사용할 수 있으며, DLL 프로젝트에서도 쉽게 사용할 수 있습니다. 이 도구를 사용하면 추가적인 종속성 파일 없이도 애플리케이션을 배포할 수 있습니다.

패키지 병합의 장점

패키지 병합을 통해 얻을 수 있는 주요 장점은 다음과 같습니다:

  • 독립성 보장: 클래스 라이브러리가 특정 외부 패키지에 의존하더라도 이를 외부 애플리케이션에 노출하지 않기 때문에 라이브러리의 독립성을 유지할 수 있습니다.
  • 충돌 방지: 외부 애플리케이션이 동일한 패키지의 다른 버전을 사용할 때 발생할 수 있는 버전 충돌을 방지할 수 있습니다.
  • 유지보수 용이성: 패키지 병합을 통해 라이브러리의 내부 구조와 외부 애플리케이션 간의 의존성을 분리함으로써 유지보수가 더 쉬워집니다.

패키지 병합의 한계

패키지 병합은 라이브러리 내부에서만 패키지를 사용하도록 하지만, 모든 경우에 적합한 해결책은 아닐 수 있습니다. 예를 들어, 외부 애플리케이션이 라이브러리에서 사용된 특정 패키지의 기능에 직접 접근해야 하는 경우, 패키지 병합은 제한적일 수 있습니다. 이때는 패키지를 외부로 노출시키고 버전 호환성을 유지하는 것이 더 적합할 수 있습니다. 또한, 일부 프로젝트에서는 복잡한 트랜지티브 종속성 구조로 인해 PrivateAssets 속성이 완벽하게 격리되지 않거나 예상치 못한 충돌이 발생할 수 있습니다. 또한, 모든 패키지가 PrivateAssets 속성을 완벽히 지원하지 않기 때문에 프로젝트 요구사항에 맞게 이 설정이 적절한지 신중하게 고려해야 합니다.

추가 정보

IncludeAssets 속성

반대로 패키지의 특정 기능만 외부로 노출하고 싶을 때는 IncludeAssets 속성을 사용할 수 있습니다. 이 속성은 외부 애플리케이션에서 패키지의 일부 기능만 사용할 수 있도록 제어합니다. 예를 들어, 특정 패키지의 일부 기능만 노출하고 싶은 경우 IncludeAssets를 다음과 같이 설정할 수 있습니다:

<PackageReference Include="Serilog" Version="4.0.1">
    <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

이 설정은 특정 자산(예: 실행 파일, 빌드 파일, 네이티브 코드)을 외부 애플리케이션으로 노출하게 합니다. 이를 통해 외부 애플리케이션이 패키지의 필요한 부분만 사용할 수 있게 제어할 수 있습니다.