타깃 프레임워크 개념에 대해 전반적 질문

.NET으로 일을 한 지 그래도 몇 해 지났는데도 타깃 프레임워크라는 개념 전반에 대해 이해가 부족한 것 같아 질문 드립니다. 사실 이걸로 그동안 검색도 많이 해 봤는데 엉뚱한 키워드로만 씨름한 건지 모르겠지만, 개운하게 알려주는 설명을 찾지 못 했던 것 같습니다. 정말 궁금한 게 많은데요, 차근차근 질문을 나열해 보겠습니다.

우선, MSBuild 빌드 스크립트(예: *.csproj)에서 <TargetFrameworks> 태그를 통해 해당 프로젝트가 지원하려는 모든 타깃 프레임워크를 나열할 수 있다는 정도로 이해해 왔는데, 최근 다시 하나의 궁금함이 생겼습니다. 그러면 저 목록을 늘릴 수록 해당 프로젝트에 참여하는 동료들은 각자의 개발환경에 설치해야 하는 SDK가 늘어나야 한다는 의미일까요?

예를 들어, 저는 최근 M1 맥을 구입했는데, .NET 6부터 M1을 에뮬레이션 없이 쓸 수 있어서 .NET 5나 그 이전 버전의 SDK가 설치되어 있지 않습니다. 이럴 때, <TargetFrameworks>net5.0;net6.0</TargetFrameworks>로 설정되어 있을 경우, 꼭 dotnet build -f net6.0으로 타깃 프레임워크를 하나로 특정해서 빌드해야 하는 걸까요?

.NET CLI의 -f/--framework 옵션 얘기를 하니 또 하나 궁금한 것이 있습니다. 이 옵션이 MSBuild에 TargetFrameworkMoniker 속성을 부여하는 것과 동등한 것일까요? 그러니까, dotnet build -f netstandard2.0msbuild /p:TargetFrameworkMoniker=netstandard2.0과 동등하다고 봐도 될까요?

또, 이렇게 하나의 타깃 프레임워크를 지정하는 빌드 옵션이 Visual Studio나 Rider 같은 IDE에서도 있을 법한데, 어떻게 할 수 있는 것인지 여전히 모르겠더라고요. 그래서 타깃 프레임워크를 지정해야 할 때는 그냥 빌드만 커맨드라인에서 불편하게 할 때도 있는데, Visual Studio 내에서 지정할 방법이 있을까요?

마지막으로, 이건 앞서의 모든 궁금함이 생기게 된 계기이기도 한데요, 하나의 솔루션을 여러 버전의 .NET SDK에서도 문제 없이 빌드할 수 있게 구성하는 게 가능할까요? 예를 들면, 개발 환경에 .NET 6 SDK만 깔려 있든, .NET Core 3.1 SDK만 깔려 있든, 혹은 심지어 Mono 6.12 SDK만 깔려 있든 빌드할 수 있게 하고 싶습니다. 사실 라이브러리 프로젝트는 여태까지는 <TargetFrameworks>netstandard2.0;netstandard2.1</TargetFrameworks>처럼 .NET Standard만 지정하는 걸로 그런 게 가능했는데, 테스트 프로젝트나 실행 가능한 프로그램 프로젝트는 netcoreapp3.1이나 net5.0, Mono 같은 경우 net47 같은 옛날 타깃 프레임워크를 지정해야 하는 것 같더라고요. (아니라면 알려주세요.)

많은 분들을 조언과 설명을 듣고 이번 기회에 타깃 프레임워크라는 개념 전반에 대해 충분히 숙지하고 싶습니다.

장환한 질문 읽어주셔서 감사합니다.

7개의 좋아요

멋진 질문입니다!

5개의 좋아요

(혹시 설명이 잘못된 부분이 있다면 피드백 부탁드립니다. :bowing_man: )

a. 닷넷 5와 닷넷 6 빌드 설정에 대하여

이 부분은 정확하게 테스트해본 것이 아니어서 경험이 있으신 분의 답변이 있으면 더 좋을 것 같습니다!

닷넷 런타임을 지정하는 부분을 보면, 닷넷 버전 외에도 CPU 아키텍처를 고르는 부분 ( .NET RID(런타임 식별자) 카탈로그 | Microsoft Docs 참조)이 있는데, 닷넷 6에서만 arm64 아키텍처를 지원하기 때문에 말씀하신 상황이 나타나는게 아닐까 싶습니다.

b. 타겟 프레임워크에 관하여

일단 닷넷 코어에서 .NET Framework를 선택할 수 있도록 한 옵션은 제가 보기에는 일종의 편의 기능 정도로 생각합니다. .NET Framework 측의 msbuild는 Visual C++ 툴체인에 결부되어있고, Windows에 종속되어있어서 닷넷 코어쪽의 msbuild 엔진과는 또 다른 부분이 있습니다.

.NET Framework SDK나 Windows SDK를 설치하지 않고 닷넷 코어의 빌드 시스템만으로 .NET Framework 애플리케이션을 빌드할 수 있는 부가 기능 정도로 생각할 수 있긴 하지만, .NET Framework 애플리케이션을 정말 빌드해야 하는 상황에서는 이런 방식보다는 정공법으로 .NET Framework SDK와 Windows SDK를 이용하는 방법을 더 많이 택하는 것 같습니다. (C++/CLI 앱까지 같이 빌드해야 하는 일도 제법 있기 때문이고요!)

시중의 IDE들은 이런 확장 기능을 UI에 담으려고 하기 보다 단순함을 지향하기 위하여 닷넷 코어 계열은 닷넷 코어만을, 닷넷 프레임워크는 Mono나 .NET Framework SDK를 직접 부르도록 맞추어진 것 같습니다.

5개의 좋아요

저는 아는 것만 답변을 드릴께요.

  1. <TargetFrameworks>의 타깃 프레임워크가 늘어날 수록 각자의 개발환경에서 설치해야 하는 SDK가 늘어나야 한다는 의미일까요?

예 맞습니다. <TargetFrameworks>의 타깃 프레임워크에 해당하는 SDK가 설치되어야 합니다.

해결 방법은 구성 관리자에서 솔루션 구성을 추가한 후 다음처럼 분기 하도록 하는 것입니다.

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

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <!--<ImplicitUsings>enable</ImplicitUsings>-->
    <Nullable>enable</Nullable>
    <LangVersion>10</LangVersion>
	<Configurations>Debug;Release;net6;net42</Configurations>
  </PropertyGroup>

  <PropertyGroup Condition="$(Configuration)=='net42'">
     <TargetFramework>net42</TargetFramework>
  </PropertyGroup>

  <PropertyGroup Condition="$(Configuration)=='net6'">
     <TargetFramework>net6.0</TargetFramework>
  </PropertyGroup>
</Project>

가령 .NET Framework 4.2가 설치되어 있지 않고 .NET 6이 설치된 환경이라면 net6 구성을 선택해서 컴파일 및 실행할 수 있게 됩니다.

image

동일한 방법으로 M1에서 .NET 5이나 그 이전 버전의 SDK를 설치하지 않고도 컴파일 및 실행되도록 csproj를 구성하실 수 있습니다.

  1. dotnet build -f netstandard2.0msbuild /p:TargetFrameworkMoniker=netstandard2.0 과 동등하다고 봐도 될까요?

정확한 것은 아니지만 TFM 적용 이후 그런 것으로 알고 있습니다.

  1. … Visual Studio 내에서 지정할 방법이 있을까요?

1번의 방법을 참고하시면 되겠습니다.

  1. <TargetFrameworks>netstandard2.0;netstandard2.1</TargetFrameworks> 처럼 .NET Standard만 지정하는 걸로 그런 게 가능했는데, 테스트 프로젝트나 실행 가능한 프로그램 프로젝트는 netcoreapp3.1 이나 net5.0 , Mono 같은 경우 net47 같은 옛날 타깃 프레임워크를 지정해야 하는 것 같더라고요.

확인해 본 결과 netstandard2.0의 경우 콘솔 프로그램의 경우 <OutputType>Exe</OutputType>을 추가하는 것으로 실행되었고 netstandard2.1의 경우 컴파일은 되었으나 실행 시 dll을 참조할 수 없어 오류가 발생했습니다. 아마 netstandard2.0도 동작하는 것 처럼 보이고 비정상 동작할 것으로 예상됩니다.

이것도 마찬가지로 구성관리자를 통해 여러개의 구성을 두어 정확히 타겟팅 하는 것으로 해결하실 수 있을 것 같습니다.

3개의 좋아요

혹시 솔루션 수준에서 MSBuild 속성을 지정할 수 있다면 TargetFrameworkMoniker를 각각 다르게 지정한 솔루션 파일을 Foo.net6.0.sln, Foo.net5.0.sln, Foo.net47.sln 같은 식으로 여러 개 둘 수도 있지 않을까 해서 찾아봤는데, 솔루션 파일 자체에는 Configuration 이외에는 MSBuild 속성을 지정하는 기능이 없는 것 같네요…

솔루션 안에 프로젝트가 꽤 많아서 부담스럽긴 하지만 Condition 속성을 나열하는 식으로 해결하는 게 현재로서는 가장 잘 동작하는 방식일 것 같네요. 답변 모두 고맙습니다.

혹시 좀더 좋은 아이디어가 있으신 분들은 댓글로 알려주세요!

2개의 좋아요