[英]Is it possible to compile a single C# code file with the .NET Core Roslyn compiler?
在旧的 .NET 中,我们曾经能够运行csc
编译器来编译单个 .cs 文件或多个文件。
使用 .NET Core,我们有dotnet build
,它坚持拥有正确的项目文件。 是否有独立的命令行编译器允许在没有项目的情况下编译源代码文件(并在同一命令行上列出引用的依赖项)?
在 Linux 上,当我安装了旧的csc
和新的 .NET Core 时,我得到以下时间:
[root@li1742-80 test]# time dotnet build
Microsoft (R) Build Engine version 15.3.409.57025 for .NET Core
Copyright (C) Microsoft Corporation. All rights reserved.
test -> /root/test/bin/Debug/netcoreapp2.0/test.dll
Build succeeded.
0 Warning(s)
0 Error(s)
Time Elapsed 00:00:03.94
real 0m7.027s
user 0m5.714s
sys 0m0.838s
[root@li1742-80 test]# time csc Program.cs
Microsoft (R) Visual C# Compiler version 2.3.0.61801 (3722bb71)
Copyright (C) Microsoft Corporation. All rights reserved.
real 0m0.613s
user 0m0.522s
sys 0m0.071s
[root@li1742-80 test]#
请注意 .NET Core 的 7 秒与旧csc
数百毫秒对于同一文件Program.cs
。
我希望能够像以前使用csc
一样快速地使用 .NET Core 进行编译。
是的,可以在 .NET Core 中使用 csc 或 vbc 编译器编译单个文件。
要直接调用 Roslyn 编译器,必须使用命令行驱动程序csc.{exe|dll}并且由于 Roslyn 与旧的 csc.exe 相比不隐式引用 mscorlib.dll,因此有必要传递对所需的引用依赖项,即System.Runtime
和System.Private.CoreLib
库以及任何其他必需的引用。 以下清单显示了如何编译以下Hello, World! 程序。
using System;
namespace HelloWorld
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello, World!");
}
}
}
在安装了Ubuntu 16.04 (Xenial Xerus) 和 dotnet-sdk-2.0.0 的情况下使用 WSL:
time dotnet /usr/share/dotnet/sdk/2.0.0/Roslyn/csc.exe -r:/usr/share/dotnet/shared/Microsoft.NETCore.App/2.0.0/System.Private.CoreLib.dll -r:/usr/share/dotnet/shared/Microsoft.NETCore.App/2.0.0/System.Console.dll -r:/usr/share/dotnet/shared/Microsoft.NETCore.App/2.0.0/System.Runtime.dll HelloWorld.cs
Microsoft (R) Visual C# Compiler version 2.3.2.61921 (ad0efbb6)
Copyright (C) Microsoft Corporation. All rights reserved.
real 0m0.890s
user 0m0.641s
sys 0m0.250s
ls -li
total 4
4785074604720852 -rw-rw-rw- 1 developer developer 178 Dec 7 15:07 HelloWorld.cs
11821949022487213 -rw-rw-rw- 1 developer developer 4096 Dec 7 15:13 HelloWorld.exe
传递给编译器的所需依赖项在不同平台上是不同的,即在 Windows 上传递System.Runtime.dll
和System.Console.dll
就足够了,而在 Ubuntu 16.04 上则需要另外传递System.Private.CoreLib.dll
。 不同的 SDK 版本将具有位于不同位置的 Roslyn 和命令行驱动程序 - 版本之间的 SDK 布局会发生变化 - 最新的 2.2.2 SDK 附带csc.dll
和vbc.dll
而不是csc.exe
和vbc.exe
。 因此,在使用此方法之前,有必要检查您的 SDK 布局。
详细说明
Roslyn 编译器的设计方式与之前使用的csc.exe
和vbc.exe
编译器略有不同。 首先,Roslyn 是用 C# 和 VB.NET 编写的,是一个托管的 .NET 应用程序。 在 Windows 上,它主要用作在服务器进程VBCSCompiler.exe
(.dll) 中运行的公共服务。 但是,Roslyn 附带托管命令行驱动程序csc.exe
和vbc.exe
(最新的 .NET SDK 版本附带csc.dll
和vbc.dll
),可用于直接从命令行编译源文件。 无论如何,这正是 .NET 中的构建系统所做的,通过命令行调用 Roslyn。 运行一个简单的dotnet csc.exe -help
命令将打印使用信息,这些信息将指导直接从命令行使用编译器(请参阅最后一个清单)。
旧的本机编译器和 Roslyn 之间的主要区别在于后者是托管应用程序的事实是启动时间。 Roslyn,即使在被编译为 R2R 本机程序集( Ready To Run
)之后,也需要首先加载整个 .NET 框架,初始化它,然后加载 Roslyn 程序集并开始编译过程。 它总是比运行本地编译器慢一点,但是,从上面的时间可以看出,并没有那么慢。
在corefx
存储库中添加了一篇新的文档文章,描述了高级场景 - 使用 csc/vbc 和 CoreRun 构建和运行应用程序代码。 任何感兴趣的人都可以将其用作如何在 .NET Core 的底层工作的指南。
Microsoft (R) Visual C# Compiler version 2.3.2.61921 (ad0efbb6)
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, 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
/warn:<n> Set warning level (0-4) (Short form: /w)
/nowarn:<warn list> Disable specific warning messages
/ruleset:<file> Specify a ruleset file that disables specific
diagnostics.
/errorlog:<file> Specify a file to log all compiler and analyzer
diagnostics.
/reportanalyzer Report additional analyzer information, such as
execution time.
- LANGUAGE -
/checked[+|-] Generate overflow checks
/unsafe[+|-] Allow 'unsafe' code
/define:<symbol list> Define conditional compilation symbol(s) (Short
form: /d)
/langversion:<string> Specify language version mode: ISO-1, ISO-2, 3,
4, 5, 6, 7, 7.1, Default, or Latest
- 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 (default) or SHA256.
/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.
/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
接受的答案是指使用System.Private.CoreLib.dll
,这是一个运行时程序集,不推荐使用。 来自C# 编译器开发人员的评论:
不支持尝试使用运行时程序集作为编译引用,并且经常破坏运行时程序集的结构
相反,应该使用引用程序集。 在dotnet build
期间从 NuGet 获取参考程序集,并且在运行具有更高详细程度的dotnet
CLI ( dotnet build --verbosity normal
) 时可以看到完整的csc
调用。 人们可能会看到microsoft.netcore.app
NuGet 包中对System.Runtime.dll
和System.Console.dll
等程序集的引用。
但是,对于简单的单个文件Hello, World! 编译,可以引用netstandard.dll
,对于 .NET Core 2.2 存在于<installation-directory>/sdk/2.2.203/ref/netstandard.dll
。
请注意,为了使用dotnet HelloWorld.exe
运行生成的可执行文件,必须创建相应的HelloWorld.runtimeconfig.json
,其中包含目标 .NET Core 运行时版本。 我们将通过为控制台 (NETCoreApp) 应用程序创建一个通用运行时配置以及随附的别名csc_run
来简化它。
在您的~/.profile
添加以下内容:
#!/usr/bin/env sh
# IMPORTANT: make sure dotnet is present in PATH before the next lines
# prepare csc alias
DOTNETDIR=$(dirname $(dirname $(dotnet --info | grep "Base Path" | cut -d' ' -f 6)))
CSCPATH=$(find $DOTNETDIR -name csc.dll -print | sort | tail -n1)
NETSTANDARDPATH=$(find $DOTNETDIR -path *sdk/*/ref/netstandard.dll ! -path *NuGetFallback* -print | sort | tail -n1)
alias csc='dotnet $CSCPATH /r:$NETSTANDARDPATH '
# prepare csc_run alias
if [ ! -w "$DOTNETDIR" ]; then
mkdir -p $HOME/.dotnet
DOTNETDIR=$HOME/.dotnet
fi
DOTNETCSCRUNTIMECONFIG=$DOTNETDIR/csc-console-apps.runtimeconfig.json
alias csc_run='dotnet exec --runtimeconfig $DOTNETCSCRUNTIMECONFIG '
if [ ! -f $DOTNETCSCRUNTIMECONFIG ]; then
DOTNETRUNTIMEVERSION=$(dotnet --list-runtimes |
grep Microsoft\.NETCore\.App | tail -1 | cut -d' ' -f2)
cat << EOF > $DOTNETCSCRUNTIMECONFIG
{
"runtimeOptions": {
"framework": {
"name": "Microsoft.NETCore.App",
"version": "$DOTNETRUNTIMEVERSION"
}
}
}
EOF
fi
退出并启动 shell 以重新加载配置文件(或者如果您不想离开当前会话,则使用. ~/.profile
它)。
用法:
cat << EOF > ./Program.cs
class Program
{
static void Main() => System.Console.WriteLine("Hello World!");
}
EOF
csc -out:hwapp.exe Program.cs
csc_run hwapp.exe
# Hello World!
编译器可以直接调用
$ /usr/local/share/dotnet/sdk/2.0.0/Roslyn/RunCsc.sh
但是,如果没有支持的项目基础结构,此特定命令可能不会很有帮助,因为您需要手动传入所有 .NET Core 或 .NET Standard 参考程序集,这通常由 SDK 和 NuGet 处理。 你会得到这样的错误:
$ /usr/local/share/dotnet/sdk/2.0.0/Roslyn/RunCsc.sh Program.cs
Microsoft (R) Visual C# Compiler version 2.3.2.61921 (ad0efbb6)
Copyright (C) Microsoft Corporation. All rights reserved.
Program.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?)
Program.cs(5,11): error CS0518: Predefined type 'System.Object' is not defined or imported
Program.cs(7,26): error CS0518: Predefined type 'System.String' is not defined or imported
Program.cs(7,16): error CS0518: Predefined type 'System.Void' is not defined or imported
简而言之,如果没有预定义的项目,它就不受支持。
但是@Andrew 的评论表明,如果您准备好在命令行选项中列出每个依赖项(包括隐式系统依赖项),它仍然是可能的。
来自错误 CS0518:未定义或导入预定义类型“System.Object”#12393 :
目前,我们没有计划以这种方式轻松使用 csc.exe。 指南是暂时使用 dotnet CLI 工具。 即使在此处进行一些修改,也将在框架上为编译器提供统一和/或简化的参考程序集。 编译器永远不会有比现在更复杂的类型或程序集解析(按设计)。
另请参阅关闭的使直接调用编译器成为可能#7689 。
This is the scripts:
#!/bin/bash
#dotnethome=`dirname "$0"`
dotnethome=`dirname \`which dotnet\``
sdkver=$(dotnet --version)
fwkver=$(dotnet --list-runtimes | grep Microsoft.NETCore.App | awk '{printf("%s", $2)}')
dotnetlib=$dotnethome/shared/Microsoft.NETCore.App/$fwkver
if [ "$#" -lt 1 ]; then
dotnet $dotnethome/sdk/$sdkver/Roslyn/bincore/csc.dll -help
echo dotnethome=$dotnethome
echo sdkver=$sdkver
echo fwkver=$fwkver
echo dotnetlib=$dotnetlib
exit 1
fi
progfile=$1
prog="${progfile%.*}"
echo -r:$dotnetlib/netstandard.dll > /tmp/$prog.rsp
echo -r:$dotnetlib/System.dll >> /tmp/$prog.rsp
echo -r:$dotnetlib/Microsoft.CSharp.dll >> /tmp/$prog.rsp
for f in $dotnetlib/System.*.dll; do
echo -r:$f >> /tmp/$prog.rsp
done
dotnet $dotnethome/sdk/$sdkver/Roslyn/bincore/csc.dll -out:$prog.dll -nologo @/tmp/$prog.rsp $*
if [ $? -eq 0 ]; then
if test -f "$prog.dll"; then
if ! test -f "$prog.runtime.config"; then
echo "{
\"runtimeOptions\": {
\"framework\": {
\"name\": \"Microsoft.NETCore.App\",
\"version\": \"$fwkver\"
}
}
}" > "$prog.runtimeconfig.json"
fi
fi
fi
echo /tmp/$prog.rsp:
cat /tmp/$prog.rsp
rm /tmp/$prog.rsp
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.