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
정성태

... 76  77  78  79  80  81  82  83  [84]  85  86  87  88  89  90  ...
NoWriterDateCnt.TitleFile(s)
11836정성태3/5/201923226오류 유형: 525. Visual Studio 2019 Preview 4/RC - C# 8.0 Missing compiler required member 'System.Range..ctor' [1]
11835정성태3/5/201921748.NET Framework: 810. C# 8.0의 Index/Range 연산자를 .NET Framework에서 사용하는 방법 및 비동기 스트림의 컴파일 방법 [3]파일 다운로드1
11834정성태3/4/201920575개발 환경 구성: 432. Visual Studio 없이 최신 C# (8.0) 컴파일러를 사용하는 방법
11833정성태3/4/201921090개발 환경 구성: 431. Visual Studio 2019 - CMake를 이용한 공유/실행(so/out) 리눅스 프로젝트 설정파일 다운로드1
11832정성태3/4/201917016오류 유형: 524. Visual Studio CMake - rsync: connection unexpectedly closed
11831정성태3/4/201916839오류 유형: 523. Visual Studio 2019 - 새 창으로 뜬 윈도우를 닫을 때 비정상 종료
11830정성태2/26/201916537오류 유형: 522. 이벤트 로그 - Error opening event log file State. Log will not be processed. Return code from OpenEventLog is 87.
11829정성태2/26/201918288개발 환경 구성: 430. 마이크로소프트의 CoreCLR 프로파일러 예제 빌드 방법 - 리눅스 환경 [1]
11828정성태2/26/201926156개발 환경 구성: 429. Component Services 관리자의 RuntimeBroker 설정이 2개 있는 경우 [8]
11827정성태2/26/201919079오류 유형: 521. Visual Studio - Could not start the 'rsync' command on the remote host, please install it using your system package manager.
11826정성태2/26/201919256오류 유형: 520. 우분투에 .NET Core SDK 설치 시 패키지 의존성 오류
11825정성태2/25/201924479개발 환경 구성: 428. Visual Studio 2019 - CMake를 이용한 리눅스 빌드 환경 설정 [1]
11824정성태2/25/201918930오류 유형: 519. The SNMP Service encountered an error while accessing the registry key SYSTEM\CurrentControlSet\Services\SNMP\Parameters\TrapConfiguration. [1]
11823정성태2/21/201920617오류 유형: 518. IIS 관리 콘솔이 뜨지 않는 문제
11822정성태2/20/201918920오류 유형: 517. docker에 설치한 MongoDB 서버로 연결이 안 되는 경우
11821정성태2/20/201919683오류 유형: 516. Visual Studio 2019 - This extension uses deprecated APIs and is at risk of not functioning in a future VS update. [1]
11820정성태2/20/201922754오류 유형: 515. 윈도우 10 1809 업데이트 후 "User Profiles Service" 1534 경고 발생
11819정성태2/20/201922041Windows: 158. 컴퓨터와 사용자의 SID(security identifier) 확인 방법
11818정성태2/20/201920102VS.NET IDE: 131. Visual Studio 2019 Preview의 닷넷 프로젝트 빌드가 20초 이상 걸리는 경우 [2]
11817정성태2/17/201916450오류 유형: 514. WinDbg Preview 실행 오류 - Error : DbgX.dll : WindowsDebugger.WindowsDebuggerException: Could not load dbgeng.dll
11816정성태2/17/201919884Windows: 157. 윈도우 스토어 앱(Microsoft Store App)을 명령행에서 직접 실행하는 방법
11815정성태2/14/201918123오류 유형: 513. Visual Studio 2019 - VSIX 설치 시 "The extension cannot be installed to this product due to prerequisites that cannot be resolved." 오류 발생
11814정성태2/12/201916985오류 유형: 512. VM(가상 머신)의 NT 서비스들이 자동 시작되지 않는 문제
11813정성태2/12/201918318.NET Framework: 809. C# - ("Save File Dialog" 등의) 대화 창에 확장 속성을 보이는 방법
11812정성태2/11/201915625오류 유형: 511. Windows Server 2003 VM 부팅 후 로그인 시점에 0xC0000005 BSOD 발생
11811정성태2/11/201920832오류 유형: 510. 서버 운영체제에 NVIDIA GeForce Experience 실행 시 wlanapi.dll 누락 문제
... 76  77  78  79  80  81  82  83  [84]  85  86  87  88  89  90  ...