Microsoft MVP성태의 닷넷 이야기
글쓴 사람
정성태 (seongtaejeong at gmail.com)
홈페이지
첨부 파일
 

.NET SDK 10 - 단일 소스 코드 파일을 빌드/실행하는 기능을 "dotnet" 명령어에 추가

실행까지는 아니었지만, 과거에도 단일 소스 코드 파일을 컴파일하는 것이 가능했습니다. 일례로, .NET Framework 시절에는 고정된 위치에 프레임워크가 설치됐고, 그 구성 요소에는 C# 컴파일러(csc.exe)도 함께 있었습니다. (msbuild.exe가 프로젝트 단위의 빌드를 담당했다면,) csc.exe는 소스 코드 파일을 컴파일하는 역할을 했는데요, 당연히 소스 코드 파일 1개도 빌드가 가능했습니다.

이후 .NET Core가 등장하면서 초기에 잠깐 csc.exe로 제공되다가 .NET 2.2.2 SDK부터는 csc.exe가 누락되고 아예 csc.dll로 제공되기 시작했습니다. 따라서 단일 소스 코드 파일을 컴파일하려면 dotnet.exe + csc.dll의 조합으로 컴파일해야 했는데요, 관련해서는 다음의 글에 자세하게 설명했으니 참고하시고.

.NET Core/5+ 환경에서 (프로젝트가 아닌) C# 코드 파일을 입력으로 컴파일하는 방법 - 두 번째 이야기
; https://www.sysnet.pe.kr/2/0/13105

어찌 보면, 사실상 .NET 9 환경까지는 단일 소스 코드 파일의 빌드를 공식적으로 지원한다고 보기에는 다소 무리가 있었는데요, 이런 애매함이 .NET 10부터 사라지게 되었습니다. 게다가 방법도 간단해졌는데요, 기존의 dotnet 실행 파일에 그 기능을 통합시켰기 때문입니다.

간단하게 실습을 해볼까요? ^^ 어떤 식으로든 단일 C# 코드 파일을 하나 만든 후, 다음과 같이 "dotnet build"로 전달만 하면,

c:\temp> type test.cs
Console.WriteLine("Hello world");

c:\temp> dotnet build test.cs

컴파일이 됩니다. 문제가 하나 있다면, 저렇게 빌드한 결과물의 위치가 매우 복잡하다는 점입니다.

%USERPROFILE%\AppData\Local\Temp\dotnet\runfile\test-6dee3fbcf5d3d00ed309fd6226803f671db092c17093e603ca20d6880b18d12c\bin\debug\test.dll

// 위의 경로는 빌드 시 -v 옵션을 주면 쉽게 확인할 수 있습니다.
c:\temp> dotnet build -v d test.cs
Restore complete (0.4s)
    All projects are up-to-date for restore.
    info NETSDK1057: You are using a preview version of .NET. See: https://aka.ms/dotnet-support-policy
  test succeeded (0.2s) → C:\Users\testusr\AppData\Local\Temp\dotnet\runfile\test-6dee3fbcf5d3d00ed309fd6226803f671db092c17093e603ca20d6880b18d12c\bin\debug\test.dll

Build succeeded in 1.4s

그래서 보통은 output 디렉터리를 지정해서 빌드하게 될 텐데요,

c:\temp> dotnet build test.cs -o .

c:\temp> dotnet test.dll
Hello world

여기서 더 재미있는 점은, 단일 소스 코드 파일에 대한 빌드뿐만 아니라 실행까지도 dotnet 명령어가 지원한다는 점입니다. 그래서 위의 명령어처럼 2개로 나뉠 필요 없이 곧바로 "dotnet run"으로 실행할 수 있습니다.

c:\temp> dotnet run test.cs
Hello world

이게 뭘 의미하냐면, 컴파일 언어에 속한 C#을 마치 스크립트 언어처럼 다룰 수 있게 되었다는 점입니다. ^^ 심지어 *NIX 환경에서는 이에 대한 특징이 더욱더 잘 드러나는데요, 왜냐하면 소스 코드 파일에 shebang 지시자를 담을 수 있기 때문입니다.

$ cat test.cs
#!/usr/bin/dotnet run

Console.WriteLine("Hello world");

이 상태에서 저 텍스트 파일에 실행 권한만 있다면, 단독으로 실행하는 것도 가능합니다.

$ chmode +x test.cs
$ ./test.cs
Hello world

오호~~~ 나름 괜찮은 기능이 추가된 것 같죠? 이로써 그동안 C#을 스크립트 언어처럼 사용하기 위한 부가 프로젝트들이 더 이상 필요 없게 되었습니다. ^^




그나저나, 기본적인 내용은 저렇게 컴파일과 실행이 가능하다는 건데요, 이게 또 들어가 보면 곁가지들이 좀 나옵니다. 왜냐하면, 그동안 프로젝트 파일(csproj)을 통해 관리를 했던 부분들이 날아갔기 때문에 그 빈자리가 아쉬울 수밖에 없고, 그래서 이에 대한 보완으로 5개 정도의 지시자가 추가됐습니다. (향후, 더 나올 수도 있습니다.)

  • #! (shebang)
  • #:sdk (SDK 설정)
  • #:property (속성 설정)
  • #:package (nuget 패키지 참조)
  • #:project (외부 프로젝트 참조)

첫 번째 shebang 지시자는 이미 위에서 설명했으니 넘어가고, 두 번째 지시자부터 하나씩 알아보겠습니다.


#:sdk 지시자

예를 들어, Console 응용 프로그램과 ASP.NET Core 웹 응용 프로그램의 경우 SDK 유형부터가 다릅니다.

<Project Sdk="Microsoft.NET.Sdk">
    <!-- ...[생략]... -->
</Project>

<Project Sdk="Microsoft.NET.Sdk.Web">
    <!-- ...[생략]... -->
</Project>

따라서, 단일 파일의 경우 저 SDK 유형을 지정할 방법이 필요했고, 그 용도로 "#:sdk" 지시자가 도입된 것입니다. 이를 응용하면 ASP.NET Core 웹 응용 프로그램도 단일 소스 코드 파일로 작성할 수 있습니다.

$ cat test.cs
#!/usr/bin/dotnet run
#:sdk Microsoft.NET.Sdk.Web

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapGet("/", () => "Hello World!");

app.Run();

$ dotnet run test.cs
info: Microsoft.Hosting.Lifetime[14]
      Now listening on: http://localhost:5000
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Production
info: Microsoft.Hosting.Lifetime[0]
      Content root path: /home/testusr


#:property 지시자

sdk 유형 외에 프로젝트 파일에서 거의 반드시 등장하는 것이 바로 속성(property) 설정인데요,

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

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net8.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

</Project>

이것을 소스 코드 파일에 지정이 가능하도록 다음의 유형으로 "#:property" 지시자를 추가할 수 있습니다.

#:property [속성]=[값]

이에 대한 예제로, WinRT API를 사용하는 단일 소스 코드 파일을 이렇게 작성할 수 있습니다.

#:sdk Microsoft.NET.Sdk.WindowsDesktop
#:property TargetFramework=net10.0-windows10.0.17763.0

using Windows.Devices.Enumeration;

// 이 코드는 WinRT를 사용하므로 *NIX 환경에선 동작하지 않습니다.

using Windows.Devices.Enumeration;

// https://www.sysnet.pe.kr/2/0/11284
await ListDevices();

static async Task ListDevices()
{
    var devices = await DeviceInformation.FindAllAsync(DeviceClass.VideoCapture);

    foreach (var item in devices)
    {
        Console.WriteLine($"{item.Id}: {item.Name}");
    }
}


#:package 지시자

그다음 프로젝트 파일의 역할 중 가장 중요한 것으로는 패키지 참조가 있는데요, 이에 대응해서는 "#:package" 지시자를 제공합니다.

#:package [패키지_이름]@[버전]

nuget에서 제공하는 패키지를 참조할 수 있게 해주는데, 아래의 예제는 Newtonsoft.Json 13.0.3 버전을 참조하는 단일 소스 코드 파일을 보여줍니다.

$ cat test.cs
#:package Newtonsoft.Json@13.0.3

using Newtonsoft.Json;

Product product = new Product();

product.Name = "Apple";
product.Price = 3.99M;

string output = JsonConvert.SerializeObject(product);
Console.WriteLine(output);

class Product
{
    public string Name { get; set; }
    public decimal Price { get; set; }
}

$ dotnet run test.cs
{"Name":"Apple","Price":3.99}


#:project 지시자

마지막으로, nuget 패키지뿐만 아니라 로컬의 프로젝트 참조도 가능하게 해주는 "#:project" 지시자가 있습니다. 예를 들어, 파일/디렉터리 구조가 다음과 같을 때,

c:\temp> tree /F
Folder PATH listing
Volume serial number is 2E94-0194
C:.
│   test.cs
│
└───ClassLibrary1
        Class1.cs
        ClassLibrary1.csproj

test.cs 파일에서 ClassLibrary1.csproj의 경로를 project 지시자로 참조해 실행할 수 있습니다.

c:\temp> type test.cs
#:project .\ClassLibrary1\ClassLibrary1.csproj

ClassLibrary1.Class1.HelloWorld();

c:\temp> type .\ClassLibrary1\Class1.cs
namespace ClassLibrary1;

public class Class1
{
    public static void HelloWorld()
    {
        System.Console.WriteLine("Hello world");
    }
}

c:\temp> dotnet run test.cs
Hello world




정리하면, "dotnet build", "dotnet run" 명령어의 인자로 단일 C# 소스 코드 파일을 지정할 수 있게 되었고, 이로 인해 5개의 지시자("#:", "#:sdk", "#:property", "#:package", "#:project")를 추가해 프로젝트 파일의 기능을 일부 대체했습니다.

그런데 혹시나, 프로젝트 파일의 특정 기능이 필요한 상황이 있을까요? 그런 경우의 대안으로 Directory.Build.props 파일 역시 유효하므로 현재는 아쉬운 대로 이것을 활용하시면 됩니다.

(참고로 글을 쓰면서 느낀 건데, 이제 블로그에서의 웬만한 예제는 단일 파일 기준으로 작성해도 될 것 같습니다. ^^)




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]







[최초 등록일: ]
[최종 수정일: 8/19/2025]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 




... [166]  167  168  169  170  171  172  173  174  175  176  177  178  179  180  ...
NoWriterDateCnt.TitleFile(s)
976정성태1/11/201157138오류 유형: 111. IIS - 500.19 오류 (0x8007000d)
975정성태1/10/201130732.NET Framework: 202. CLR JIT 컴파일러가 생성한 기계어 코드 확인하는 방법 [3]파일 다운로드1
974정성태1/8/201129966.NET Framework: 201. 윈폼 TreeView - Bold 폰트 설정 후 텍스트가 잘리는 문제 [1]파일 다운로드1
973정성태1/7/201129077.NET Framework: 200. IIS Metabase와 ServerManager 개체 활용파일 다운로드1
972정성태1/7/201127194개발 환경 구성: 95. SQL Server 2008 R2 이하 버전 정보 확인
971정성태1/5/201136848.NET Framework: 199. .NET 코드 - Named Pipe 닷넷 서버와 VC++ 클라이언트 제작 [2]파일 다운로드1
970정성태1/4/201137264.NET Framework: 198. 윈도우 응용 프로그램에 Facebook 로그인 연동 [1]파일 다운로드1
969정성태12/31/201043362VC++: 45. Winsock 2 Layered Service Provider - Visual Studio 2010용 프로젝트 [1]파일 다운로드1
968정성태12/30/201029594개발 환경 구성: 94. 개발자가 선택할 수 있는 윈도우에서의 네트워크 프로그래밍 기술 [2]
967정성태12/27/201031497.NET Framework: 197. .NET 코드 - 단일 Process 실행파일 다운로드1
966정성태12/26/201028964.NET Framework: 196. .NET 코드 - 창 흔드는 효과파일 다운로드1
965정성태12/25/201030849개발 환경 구성: 93. MSBuild를 이용한 닷넷 응용프로그램의 다중 어셈블리 출력 빌드파일 다운로드1
964정성태12/21/2010146652개발 환경 구성: 92. 윈도우 서버 환경에서, 최대 생성 가능한 소켓(socket) 연결 수는 얼마일까? [14]
963정성태12/13/201031114개발 환경 구성: 91. MSBuild를 이용한 닷넷 응용프로그램의 플랫폼(x86/x64)별 빌드 [2]파일 다운로드1
962정성태12/10/201025963오류 유형: 110. GAC 등록 - Failure adding assembly to the cache: Invalid file or assembly name.
961정성태12/10/2010103454개발 환경 구성: 90. 닷넷에서 접근해보는 PostgreSQL DB [5]
960정성태12/8/201048538.NET Framework: 195. .NET에서 코어(Core) 관련 CPU 정보 알아내는 방법파일 다운로드1
959정성태12/8/201034789.NET Framework: 194. Facebook 연동 - API Error Description: Invalid OAuth 2.0 Access Token
958정성태12/7/201032233개발 환경 구성: 89. 배치(batch) 파일에서 또 다른 배치 파일을 동기 방식으로 실행 및 반환값 얻기 [2]
957정성태12/6/201034823디버깅 기술: 31. Windbg - Visual Studio 디버그 상태에서 종료해 버리는 응용 프로그램 [3]
953정성태11/28/201039896.NET Framework: 193. 페이스북(Facebook) 계정으로 로그인하는 C# 웹 사이트 제작 [5]
952정성태11/25/201028640.NET Framework: 192. GC의 부하는 상대적인 것! [4]
950정성태11/18/201080785.NET Framework: 191. ClickOnce - 관리자 권한 상승하는 방법 [17]파일 다운로드2
954정성태11/29/201051824    답변글 .NET Framework: 191.1. [답변] 클릭원스 - 요청한 작업을 수행하려면 권한 상승이 필요합니다. (Exception from HRESULT: 0x800702E4) [2]
949정성태11/16/201030301오류 유형: 109. System.ServiceModel.Security.SecurityNegotiationException
948정성태11/16/201039851.NET Framework: 190. 트위터 계정으로 로그인하는 C# 웹 사이트 제작 [7]파일 다운로드1
... [166]  167  168  169  170  171  172  173  174  175  176  177  178  179  180  ...