Microsoft MVP성태의 닷넷 이야기
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
 
(연관된 글이 1개 있습니다.)

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

예전에 이에 대해 한 번 설명했는데요,

.NET Core 환경에서 (프로젝트가 아닌) C# 코드 파일을 입력으로 컴파일하는 방법
; https://www.sysnet.pe.kr/2/0/12034

이후 .NET Core 2.2.2 SDK부터 배포되는 Roslyn 컴파일러에는 실행 파일 유형의 csc.exe가 누락되고 csc.dll로만 배포가 돼 위의 내용을 실습할 수 없습니다.

물론, csc.dll은 기존 csc.exe의 DLL 버전이므로 다음과 같은 식으로 직접 실행하는 것도 가능합니다.

// .NET 6 SDK가 설치된 경우 (버전 6.0.302)

c:\temp> dotnet "C:\Program Files\dotnet\sdk\6.0.302\Roslyn\bincore\csc.dll"
Microsoft (R) Visual C# Compiler version 4.2.0-4.22220.5 (432d17a8)
Copyright (C) Microsoft Corporation. All rights reserved.

warning CS2008: No source files specified.
error CS1562: Outputs without source must have the /out option specified

테스트를 위해 예제 C# 파일을 하나 만들고,

// c:\temp\test.cs 파일로 저장되었다고 가정

using System;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World");
        }
    }
}

빌드해 볼까요? ^^

c:\temp> dotnet "C:\Program Files\dotnet\sdk\6.0.302\Roslyn\bincore\csc.dll" test.cs
Microsoft (R) Visual C# Compiler version 4.2.0-4.22220.5 (432d17a8)
Copyright (C) Microsoft Corporation. All rights reserved.

test.cs(1,7): error CS0246: The type or namespace name 'System' could not be found (are you missing a using directive or an assembly reference?)
test.cs(5,11): error CS0518: Predefined type 'System.Object' is not defined or imported
test.cs(7,26): error CS0518: Predefined type 'System.String' is not defined or imported
test.cs(7,16): error CS0518: Predefined type 'System.Void' is not defined or imported

아쉽게도, 가장 기본적인 System.Object 타입을 정의한 어셈블리조차도 참조를 해주지 않으므로 직접 명령행에 해당 DLL을 함께 전달해야 합니다.

// 옵션 추가
// -r:"C:\Program Files\dotnet\shared\Microsoft.NETCore.App\6.0.7\System.Private.CoreLib.dll"

c:\temp> dotnet "C:\Program Files\dotnet\sdk\6.0.302\Roslyn\bincore\csc.dll" test.cs -r:"C:\Program Files\dotnet\shared\Microsoft.NETCore.App\6.0.7\System.Private.CoreLib.dll"
Microsoft (R) Visual C# Compiler version 4.2.0-4.22220.5 (432d17a8)
Copyright (C) Microsoft Corporation. All rights reserved.

test.cs(10,13): error CS0234: The type or namespace name 'Console' does not exist in the namespace 'System' (are you missing an assembly reference?)

음... Console 타입 역시 System.Console.dll로 분리돼 있으므로 이렇게 한 번 더 참조 추가를 해야 합니다.

// 옵션 추가
// -r:"C:\Program Files\dotnet\shared\Microsoft.NETCore.App\6.0.7\System.Console.dll"

c:\temp> dotnet "C:\Program Files\dotnet\sdk\6.0.302\Roslyn\bincore\csc.dll" test.cs -r:"C:\Program Files\dotnet\shared\Microsoft.NETCore.App\6.0.7\System.Private.CoreLib.dll" -r:"C:\Program Files\dotnet\shared\Microsoft.NETCore.App\6.0.7\System.Console.dll"
Microsoft (R) Visual C# Compiler version 4.2.0-4.22220.5 (432d17a8)
Copyright (C) Microsoft Corporation. All rights reserved.

test.cs(10,28): error CS0012: The type 'Object' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Runtime, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'.
test.cs(10,13): error CS0012: The type 'Decimal' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Runtime, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'.

하지만 ^^; 그래도 오류가 나는군요. 근데 오류 메시지가 잘 이해가 안 됩니다. System.Object의 실제 구현은 System.Private.CoreLib.dll에 있는 것이 맞고, System.Runtime의 경우에는 TypeForwardedTo를 이용해 System.Private.CoreLib.dll의 구현체를 가리키는 형태입니다.

따라서 원칙대로라면 System.Private.CoreLib.dll을 직접 참조하면 사실상 System.Runtime.dll의 참조는 필요하지 않습니다. (혹시 이에 대한 규칙을 아시는 분은 덧글 부탁드립니다. ^^)

암튼, 오류 메시지가 그러하니... 참조 추가를 하면 이제 컴파일이 잘 됩니다. ^^

// 옵션 추가
// -r:"C:\Program Files\dotnet\shared\Microsoft.NETCore.App\6.0.7\System.Runtime.dll"

c:\temp> dotnet "C:\Program Files\dotnet\sdk\6.0.302\Roslyn\bincore\csc.dll" test.cs -r:"C:\Program Files\dotnet\shared\Microsoft.NETCore.App\6.0.7\System.Private.CoreLib.dll" -r:"C:\Program Files\dotnet\shared\Microsoft.NETCore.App\6.0.7\System.Console.dll" -r:"C:\Program Files\dotnet\shared\Microsoft.NETCore.App\6.0.7\System.Runtime.dll"
Microsoft (R) Visual C# Compiler version 4.2.0-4.22220.5 (432d17a8)
Copyright (C) Microsoft Corporation. All rights reserved.




자... 이렇게 해서 test.exe가 생성되었고, 이를 실행해 보면,

c:\temp> test.exe

Unhandled Exception: System.IO.FileNotFoundException: Could not load file or assembly 'System.Private.CoreLib, Version=6.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e' or one of its dependencies. The system cannot find the file specified.

System.Private.CoreLib.dll이 같은 디렉터리에 없어 오류가 발생합니다. 그래서 해당 DLL을 복사해 둔 후 실행하면,

c:\temp> test.exe

Unhandled Exception: System.TypeLoadException: Could not load type 'System.Object' from assembly 'System.Private.CoreLib, Version=6.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e' because the parent does not exist.

이번엔 파일이 아닌, Type을 로드할 수 없다는 오류 메시지가 나옵니다. 딱히 더 해볼 것이 없군요. ^^;

그럼, dotnet 실행 파일을 경유해 실행해 볼까요?

c:\temp> dotnet test.exe
A fatal error was encountered. The library 'hostpolicy.dll' required to execute the application was not found in 'c:\temp\'.
Failed to run as a self-contained app.
  - The application was run as a self-contained app because 'c:\temp\test.runtimeconfig.json' was not found.
  - If this should be a framework-dependent app, add the 'c:\temp\test.runtimeconfig.json' file and specify the appropriate framework.

test.runtimeconfig.json 파일이 없다고 하는데, 이것만 다음의 내용으로 test.exe와 동일한 폴더에 "test.runtimeconfig.json" 파일명으로 넣어주면,

{
  "runtimeOptions": {
    "tfm": "netcoreapp6.0",
    "framework": {
      "name": "Microsoft.NETCore.App",
      "version": "6.0.0"
    }
  }
}

이제서야 정상적으로 프로그램이 실행됩니다.

c:\temp> dir /b
test.cs
test.exe
test.runtimeconfig.json

c:\temp> dotnet test.exe
Hello World




재미있는 건, csc.dll이 생성한 EXE 파일의 "Runtime" 대상이 ".NET Framework 4"라는 점입니다. 즉, 위에서 dotnet을 경유해 실행했을 때 ".NET Framework 4" 바이너리였어도 정상적으로 실행했던 것입니다.

바이너리의 Runtime 대상을 바꾸려면 C# 소스 코드 파일에서 TargetFrameworkAttribute 특성을 이용해 선택할 수 있습니다. 예를 들어 우리가 만든 예제의 경우 다음과 같이 추가하면 됩니다.

using System;
using System.Runtime.Versioning;

[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            // 문자열 출력
            System.Console.WriteLine("Hello World");
        }
    }
}




참고로, 아래는 csc.dll의 /help 출력 결과입니다.

c:\temp> dotnet "C:\Program Files\dotnet\sdk\6.0.302\Roslyn\bincore\csc.dll" /help
Microsoft (R) Visual C# Compiler version 4.2.0-4.22220.5 (432d17a8)
Copyright (C) Microsoft Corporation. All rights reserved.


                             Visual C# Compiler Options

                       - OUTPUT FILES -
-out:<file>                   Specify output file name (default: base name of file with main class or first file)
-target:exe                   Build a console executable (default) (Short form: -t:exe)
-target:winexe                Build a Windows executable (Short form: -t:winexe)
-target:library               Build a library (Short form: -t:library)
-target:module                Build a module that can be added to another assembly (Short form: -t:module)
-target:appcontainerexe       Build an Appcontainer executable (Short form: -t:appcontainerexe)
-target:winmdobj              Build a Windows Runtime intermediate file that is consumed by WinMDExp (Short form: -t:winmdobj)
-doc:<file>                   XML Documentation file to generate
-refout:<file>                Reference assembly output to generate
-platform:<string>            Limit which platforms this code can run on: x86, Itanium, x64, arm, arm64, anycpu32bitpreferred, or anycpu. The default is anycpu.

                       - INPUT FILES -
-recurse:<wildcard>           Include all files in the current directory and subdirectories according to the wildcard specifications
-reference:<alias>=<file>     Reference metadata from the specified assembly file using the given alias (Short form: -r)
-reference:<file list>        Reference metadata from the specified assembly files (Short form: -r)
-addmodule:<file list>        Link the specified modules into this assembly 
-link:<file list>             Embed metadata from the specified interop assembly files (Short form: -l)
-analyzer:<file list>         Run the analyzers from this assembly (Short form: -a)
-additionalfile:<file list>   Additional files that don't directly affect code generation but may be used by analyzers for producing errors or warnings.
-embed                        Embed all source files in the PDB.
-embed:<file list>            Embed specific files in the PDB.

                       - RESOURCES -
-win32res:<file>              Specify a Win32 resource file (.res)
-win32icon:<file>             Use this icon for the output
-win32manifest:<file>         Specify a Win32 manifest file (.xml)
-nowin32manifest              Do not include the default Win32 manifest
-resource:<resinfo>           Embed the specified resource (Short form: -res)
-linkresource:<resinfo>       Link the specified resource to this assembly (Short form: -linkres) Where the resinfo format is <file>[,<string name>[,public|private]]

                       - CODE GENERATION -
-debug[+|-]                   Emit debugging information
-debug:{full|pdbonly|portable|embedded}
                              Specify debugging type ('full' is default, 'portable' is a cross-platform format, 'embedded' is a cross-platform format embedded into the target .dll or .exe)
-optimize[+|-]                Enable optimizations (Short form: -o)
-deterministic                Produce a deterministic assembly (including module version GUID and timestamp)
-refonly                      Produce a reference assembly in place of the main output
-instrument:TestCoverage      Produce an assembly instrumented to collect coverage information
-sourcelink:<file>            Source link info to embed into PDB.

                       - ERRORS AND WARNINGS -
-warnaserror[+|-]             Report all warnings as errors
-warnaserror[+|-]:<warn list> Report specific warnings as errors (use "nullable" for all nullability warnings)
-warn:<n>                     Set warning level (0 or higher) (Short form: -w)
-nowarn:<warn list>           Disable specific warning messages (use "nullable" for all nullability warnings)
-ruleset:<file>               Specify a ruleset file that disables specific diagnostics.
-errorlog:<file>[,version=<sarif_version>]
                              Specify a file to log all compiler and analyzer diagnostics.
                              sarif_version:{1|2|2.1} Default is 1. 2 and 2.1 both mean SARIF version 2.1.0.
-reportanalyzer               Report additional analyzer information, such as execution time.
-skipanalyzers[+|-]           Skip execution of diagnostic analyzers.

                       - LANGUAGE -
-checked[+|-]                 Generate overflow checks
-unsafe[+|-]                  Allow 'unsafe' code
-define:<symbol list>         Define conditional compilation symbol(s) (Short form: -d)
-langversion:?                Display the allowed values for language version
-langversion:<string>         Specify language version such as
                              `latest` (latest version, including minor versions),
                              `default` (same as `latest`),
                              `latestmajor` (latest version, excluding minor versions),
                              `preview` (latest version, including features in unsupported preview),
                              or specific versions like `6` or `7.1`
-nullable[+|-]                Specify nullable context option enable|disable.
-nullable:{enable|disable|warnings|annotations}
                              Specify nullable context option enable|disable|warnings|annotations.

                       - SECURITY -
-delaysign[+|-]               Delay-sign the assembly using only the public portion of the strong name key
-publicsign[+|-]              Public-sign the assembly using only the public portion of the strong name key
-keyfile:<file>               Specify a strong name key file
-keycontainer:<string>        Specify a strong name key container
-highentropyva[+|-]           Enable high-entropy ASLR

                       - MISCELLANEOUS -
@<file>                       Read response file for more options
-help                         Display this usage message (Short form: -?)
-nologo                       Suppress compiler copyright message
-noconfig                     Do not auto include CSC.RSP file
-parallel[+|-]                Concurrent build.
-version                      Display the compiler version number and exit.

                       - ADVANCED -
-baseaddress:<address>        Base address for the library to be built
-checksumalgorithm:<alg>      Specify algorithm for calculating source file checksum stored in PDB. Supported values are: SHA1 or SHA256 (default).
-codepage:<n>                 Specify the codepage to use when opening source files
-utf8output                   Output compiler messages in UTF-8 encoding
-main:<type>                  Specify the type that contains the entry point (ignore all other possible entry points) (Short form: -m)
-fullpaths                    Compiler generates fully qualified paths
-filealign:<n>                Specify the alignment used for output file sections
-pathmap:<K1>=<V1>,<K2>=<V2>,...
                              Specify a mapping for source path names output by the compiler.
-pdb:<file>                   Specify debug information file name (default: output file name with .pdb extension)
-errorendlocation             Output line and column of the end location of each error
-preferreduilang              Specify the preferred output language name.
-nosdkpath                    Disable searching the default SDK path for standard library assemblies.
-nostdlib[+|-]                Do not reference standard library (mscorlib.dll)
-subsystemversion:<string>    Specify subsystem version of this assembly
-lib:<file list>              Specify additional directories to search in for references
-errorreport:<string>         Specify how to handle internal compiler errors: prompt, send, queue, or none. The default is queue.
-appconfig:<file>             Specify an application configuration file containing assembly binding settings
-moduleassemblyname:<string>  Name of the assembly which this module will be a part of
-modulename:<string>          Specify the name of the source module
-generatedfilesout:<dir>      Place files generated during compilation in the specified directory.




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

[연관 글]






[최초 등록일: ]
[최종 수정일: 7/23/2022]

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

비밀번호

댓글 작성자
 



2022-07-24 10시51분
비주얼 스튜디오에 포함된 Roslyn의 경우 (csc.dll이 아닌) csc.exe로 제공합니다. 예를 들어, 2022 버전을 설치하면 다음의 경로에서 찾을 수 있습니다.

[Community]
C:\Program Files\Microsoft Visual Studio\2022\Community\MSBuild\Current\Bin\Roslyn\csc.exe

[Enterprise]
C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Current\Bin\Roslyn\csc.exe

또는 예전에 설명한 nuget의 Microsoft.Net.Compilers도 여전히 csc.exe를 함께 배포합니다.

C# 6.0 이상의 소스 코드를 Visual Studio 설치 없이 명령행에서 컴파일하는 방법
; https://www.sysnet.pe.kr/2/0/11266
정성태

... 106  107  108  109  110  111  [112]  113  114  115  116  117  118  119  120  ...
NoWriterDateCnt.TitleFile(s)
11125정성태1/7/201724397개발 환경 구성: 310. IIS - appcmd.exe를 이용해 특정 페이지에 클라이언트 측 인증서를 제출하도록 설정하는 방법
11124정성태1/4/201727831개발 환경 구성: 309. 3년짜리 유효 기간을 제공하는 StartSSL [2]
11123정성태1/3/201723335.NET Framework: 629. .NET Core의 dotnet.exe CLI 명령어 확장 방법 [1]
11122정성태1/3/201722804.NET Framework: 628. TransactionScope에 사용자 정의 트랜잭션을 참여시키는 방법 [2]파일 다운로드1
11121정성태1/1/201720698개발 환경 구성: 308. "ASP.NET Core Web Application (.NET Core)"와 "ASP.NET Core Web Application (.NET Framework)" 차이점
11120정성태12/25/201626565개발 환경 구성: 307. ASP.NET Core Web Application을 IIS에서 호스팅하는 방법
11119정성태12/23/201649228개발 환경 구성: 306. Visual Studio Code에서 Python 개발 환경 구성 [2]
11118정성태12/22/201635994오류 유형: 374. Python 64비트 설치 시 0x80070659 오류 발생 [3]
11117정성태12/21/201622315웹: 35. nopCommerce 예제 사이트 구성 방법
11116정성태12/21/201624261디버깅 기술: 84. NopCommerce의 Autofac 부하(CPU, Memory) [2]
11115정성태12/21/201627236Windows: 133. 윈도우 서버 2016에서 플래시가 동작하지 않는 경우 [2]
11114정성태12/19/201637245Windows: 132. 역슬래시(backslash) 문자가 왜 통화 표기 문자(한글인 경우 "\")로 보일까요? [2]
11113정성태12/6/201621127오류 유형: 373. ICOMAdminCatalog::GetCollection에서 CO_E_ISOLEVELMISMATCH(0x8004E02F) 오류 발생파일 다운로드1
11112정성태11/23/201626307오류 유형: 372. MySQL 서비스가 올라오지 않는 경우 - Error 1067
11111정성태11/23/201634785.NET Framework: 627. C++로 만든 DLL을 C#에서 사용하기 [2]
11110정성태11/17/201621462.NET Framework: 626. Commit 메모리가 낮은 상황에서도 메모리 부족(Out-of-memory) 예외 발생 [2]
11109정성태11/17/201621447.NET Framework: 625. ASP.NET에서 System.Web.HttpApplication 인스턴스는 다중으로 생성됩니다.
11108정성태11/13/201621261.NET Framework: 624. WPF - Line 요소를 Canvas에 위치시켰을 때 흐림(blur) 현상파일 다운로드1
11107정성태11/9/201625155오류 유형: 371. Post cache substitution is not compatible with modules in the IIS integrated pipeline that modify the response buffers.파일 다운로드1
11106정성태11/8/201625323.NET Framework: 623. C# - PeerFinder를 이용한 Wi-Fi Direct 데이터 통신 예제 [2]파일 다운로드1
11105정성태11/8/201619720.NET Framework: 622. PeerFinder Wi-Fi Direct 통신 시 Read/Write/Dispose 문제
11104정성태11/8/201619203개발 환경 구성: 305. PeerFinder로 Wi-Fi Direct 연결 시 방화벽 문제
11103정성태11/8/201619149오류 유형: 370. PeerFinder.ConnectAsync의 결과 값인 Task.Result를 호출할 때 System.AggregateException 예외 발생
11102정성태11/8/201619255오류 유형: 369. PeerFinder.FindAllPeersAsync 호출 시 System.UnauthorizedAccessException 예외 발생
11101정성태11/8/201622024.NET Framework: 621. 닷넷 프로파일러의 오류 코드 - 0x80131363
11100정성태11/7/201628823개발 환경 구성: 304. Wi-Fi Direct 지원 여부 확인 방법 [1]
... 106  107  108  109  110  111  [112]  113  114  115  116  117  118  119  120  ...