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

... 151  152  153  154  155  156  157  158  159  [160]  161  162  163  164  165  ...
NoWriterDateCnt.TitleFile(s)
1048정성태5/27/201132260개발 환경 구성: 123. Apache 소스를 윈도우 환경에서 빌드하기
1047정성태5/27/201126121.NET Framework: 217. Firebird ALinq Provider - 날짜 필드에 대한 낙관적 동시성 쿼리 오류
1046정성태5/26/201130790.NET Framework: 216. 라이선스까지도 뛰어넘는 .NET Profiler [5]
1045정성태5/24/201131878.NET Framework: 215. 닷넷 System.ComponentModel.LicenseManager를 이용한 라이선스 적용 [1]파일 다운로드1
1044정성태5/24/201132444오류 유형: 122. zlib 빌드 오류 - inflate.obj : error LNK2001: unresolved external symbol _inflate_fast
1043정성태5/24/201131419.NET Framework: 214. 무료 Linq Provider - DbLinq를 이용한 Firebird 접근파일 다운로드1
1042정성태5/23/201137740개발 환경 구성: 122. PHP 소스를 윈도우 환경에서 빌드하기
1041정성태5/22/201128634.NET Framework: 213. Linq To SQL - ALinq Provider를 이용하여 Firebird 사용파일 다운로드1
1040정성태5/21/201138962개발 환경 구성: 121. .NET 개발자가 처음 설치해 본 Apache + PHP [2]
1039정성태5/17/201131660.NET Framework: 212. Firebird 데이터베이스와 ADO.NET [2]파일 다운로드1
1038정성태5/16/201133632개발 환경 구성: 120. .NET 프로그래머에게도 유용한 Firebird 무료 데이터베이스 [2]
1037정성태5/11/201128470개발 환경 구성: 119. Visual Studio Professional 이하 버전에서도 TFS의 정적 코드 분석 정책 연동이 가능할까? [3]
1036정성태5/7/201194268오류 유형: 121. Access DB에 대한 32bit/64bit OLE DB Provider 관련 오류 [11]
1035정성태5/7/201129026오류 유형: 120. File cannot be opened. Ensure it is a valid Data Link file.
1034정성태5/2/201126061.NET Framework: 211. 파일 잠금 없이 .NET 어셈블리의 버전을 구하는 방법 [2]파일 다운로드1
1033정성태5/1/201131776웹: 19. IIS Express - appcmd.exe를 이용한 applicationHost.config 변경 [2]
1032정성태5/1/201128428웹: 18. IIS Express를 NT 서비스로 변경
1031정성태4/30/201129583웹: 17. IIS Express - "IIS Installed Versions Manager Interface"의 IIISExpressProcessUtility 구하는 방법 [1]파일 다운로드1
1030정성태4/30/201151850개발 환경 구성: 118. IIS Express - localhost 이외의 호스트 이름으로 접근하는 방법 [4]파일 다운로드1
1029정성태4/28/201140981개발 환경 구성: 117. XCopy에서 파일/디렉터리 확인 질문 없애기 [2]
1028정성태4/27/201138374오류 유형: 119. Visual Studio 2010 SP1 설치 후 Windows Phone 개발자 도구로 인한 재설치 문제 [3]
1027정성태4/25/201127552디버깅 기술: 40. 상황별 GetFunctionPointer 반환값 정리 - x86파일 다운로드1
1026정성태4/25/201145838디버깅 기술: 39. DebugDiag 1.1을 사용한 덤프 분석 [7]
1025정성태4/24/201127895개발 환경 구성: 116. IIS 7 관리자 - Active Directory Certification Authority로부터 SSL 사이트 인증서 받는 방법 [2]
1024정성태4/22/201129199오류 유형: 118. Windows 2008 서버에서 Event Viewer / PowerShell 실행 시 비정상 종료되는 문제 [1]
1023정성태4/20/201130087.NET Framework: 210. Windbg 환경에서 확인해 본 .NET 메서드 JIT 컴파일 전과 후 [1]
... 151  152  153  154  155  156  157  158  159  [160]  161  162  163  164  165  ...