是否可以使用.net核心Roslyn编译器编译单个C#代码文件?

时间:2017-09-06 02:13:20

标签: c# compilation .net-core roslyn csc

在旧的.net中,我们以前能够运行csc编译器来编译单个cs文件或多个文件。使用.net核心,我们dotnet build坚持拥有一个合适的项目文件。是否有一个独立的命令行编译器,它可以在没有项目的情况下编译源代码文件(并在同一命令行中列出引用的依赖项)?

在Linux上,当我安装了旧的csc和新的.net核心时,我得到了这些时间:

[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核心注意7秒,使用相同Program.cs的旧csc注意几百毫秒。

我希望能够使用.net核心快速编译,因为我曾经能够使用csc。

5 个答案:

答案 0 :(得分:14)

是的,可以使用.NET Core中的csc或vbc编译器编译单个文件。

要直接调用Roslyn编译器,必须使用命令行驱动程序 csc。{exe | dll} ,因为与旧csc.exe相比,Roslyn不会隐式引用mscorlib.dll,所以必须使用传递对所需依赖项的引用,即System.RuntimeSystem.Private.CoreLib库以及任何其他必需的引用。以下清单显示了如何编译以下HelloWorld程序。

using System;

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

在安装了Ubuntu 16.04和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上,在Ubuntu 16.04上传递System.Runtime.dllSystem.Console.dll就足够了,另外需要传递System.Private.CoreLib.dll 。不同的SDK版本将具有位于不同位置的Roslyn和命令行驱动程序 - 版本之间的SDK布局更改 - 以及最新的2.2.2 SDK附带csc.dllvbc.dll而不是csc.exe和{{ 1}}。因此,在使用此方法之前,有必要检查SDK布局。

详细说明

Roslyn编译器的设计方式与以前使用的vbc.execsc.exe编译器的设计方式略有不同。首先,Roslyn是用C#和VB编写的,是一个托管的.NET应用程序。在Windows上,它主要用作在服务器进程vbc.exe(。dll)中运行的公共服务。但是,Roslyn附带托管命令行驱动程序VBCSCompiler.execsc.exe(最新的dotnet SDK版本附带vbc.execsc.dll),可用于直接从命令编译源文件线。无论如何,这正是dotnet中的构建系统通过命令行调用Roslyn的原因。运行简单的vbc.dll命令将打印使用信息,这将指导直接从命令行使用编译器(参见上一个清单)。

旧的本机编译器和Roslyn之间的主要区别在于后者是托管应用程序,这是启动时间。 Roslyn甚至在被编译为R2R本机程序集(dotnet csc.exe -help)后,需要首先加载整个dotnet框架,初始化它,然后加载Roslyn程序集并开始编译过程。然而,它总是比运行本机编译器慢一点,从上面的时间可以看出并没有那么慢。

Ready To Run repo中添加了一篇新的文档文章,描述了Advanced scenario - Build and run application code with csc/vbc and CoreRun。任何感兴趣的人都可以将它作为指导如何在.NET Core的低级别工作。

corefx

答案 1 :(得分:4)

可以使用

直接调用编译器
$ /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

答案 2 :(得分:0)

简而言之,没有预定义的项目就不支持它。

但是@ Andrew的评论显示,如果您准备在命令行选项中列出包括隐式系统依赖项在内的每个依赖项,那么它仍然可行。

来自generate the powerset

  

目前,我们还没有计划在此使用csc.exe   方式。该指南是暂时使用dotnet CLI工具   存在。即使在这里做了一些修改,它也会在   该框架提供统一和/或简化的参考   编译器的程序集。编译器永远不会有更多   比现在复杂的类型或装配分辨率(按设计)。

另见error CS0518: Predefined type 'System.Object' is not defined or imported #12393

答案 3 :(得分:0)

接受的答案是使用System.Private.CoreLib.dll,它是运行时程序集,不建议使用。来自C# compiler developer's comments

  

不尝试将运行时程序集用作编译引用   支持并经常中断运行时的结构   组装

相反,应使用参考程序集。在dotnet build期间从NuGet提取参考程序集,并且在运行具有更高详细程度(csc)的dotnet CLI时,可以看到完整的dotnet build --verbosity normal调用。有人可能会从System.Runtime.dll NuGet包中看到对程序集的引用,例如System.Console.dllmicrosoft.netcore.app

但是,对于简单的单文件hello world编译,可以引用netstandard.dll。对于{.1}下存在的.NET Core 2.2。

<installation-directory>/sdk/2.2.203/ref/netstandard.dll

请注意,为了使用DOTNETDIR=$(dirname $(which dotnet)) alias csc='dotnet $DOTNETDIR/sdk/2.2.203/Roslyn/bincore/csc.dll /r:$DOTNETDIR/sdk/2.2.203/ref/netstandard.dll' csc /t:exe HelloWorld.cs 运行生成的可执行文件,必须创建一个对应的dotnet HelloWorld.exe,其中包含目标.NET Core运行时版本:

HelloWorld.runtimeconfig.json

答案 4 :(得分:0)

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