dotnet / sdk

Core functionality needed to create .NET Core projects, that is shared between Visual Studio and CLI
https://dot.net/core
MIT License
2.71k stars 1.06k forks source link

Make it possible to invoke the compiler directly #8742

Open danmoseley opened 7 years ago

danmoseley commented 7 years ago

Not sure whether this belongs in the SDK repo instead.

In the desktop world, most people build with MSBuild on the command line or in VS. But for quick experimentation, learning c#, or custom scripts, one can invoke csc.exe directly. This has the advantage of being very fast, and not needing a project file. In that situation csc adds some default references so you simply run csc Program.cs. It is implicit that you are getting no help resolving references, so this is not a good way to make shipping software, unless you really want something custom and know what you're doing. When you are done experimenting, you should make a project file. This scenario has worked well since .NET Framework v1.

Can we support this scenario for .NET Core? This would be a supported shortcut for dotnet C:\Program Files\dotnet\sdk\...version..\Roslyn\csc that would also add some basic default references.

cc @ViktorHofer @stephentoub

dasMulli commented 7 years ago

Fyi there was a related question on StackOverflow: https://stackoverflow.com/questions/46065777/is-it-possible-to-compile-a-single-file-with-net-core

While using RunCsc.sh directly is possible, it would be nice to have a dotnet csc command that adds all the reference dlls. A problem here is that AFAIK .NET Core doesn’t include its own reference assemblies so there may be differences to a project build

mellinoe commented 7 years ago

If a command was exposed, I don't think it should automatically add any references, or do anything else "special" -- it should just be equivalent to using csc today where you need to provide such things.

ViktorHofer commented 7 years ago

I don't think that dotnet csc should automatically include required reference assemblies. The point of csc is that you define which assemblies you want to compile against.

dasMulli commented 7 years ago

csc.exe adds mscorlib.dll automatically AFAIK.. Would it make sense to add netstandard.dll on .NET Core?

As I pointed out on SO, the current behaviour is:

$ /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
livarcocc commented 7 years ago

This does not feel like a basic command like build, run, publish, test etc and we have been trying to keep the "native" CLI verbs to a minimum. So, I don't believe we would take building such a command in the CLI. We have been talking quite a bit about global commands and this seems like a good candidate for such a thing.

ViktorHofer commented 7 years ago

As you are closing the issue, do you note this request somewhere or can give a timeline for it?

dasMulli commented 7 years ago

There are currently two command wish lists that I know of: https://github.com/dotnet/cli/issues/4672 https://github.com/dotnet/cli/issues/6223

Probably adding to one wouldn't hurt

vhnatyk commented 4 years ago

yes it wouldn't hurt, it would not at all so - after two years still have to revive python for single file cross-platform scripting instead of beloved C# 🤦‍♂️

sebgod commented 4 years ago

if .NET 5 is considered a replacement for both .NET framework and core, shouldn't it also expose a proper csc (e.g. via something called dotnet-csc) that allows compiling .cs from the command line, in a portable fashion?

danmoseley commented 4 years ago

@jaredpar @MadsTorgersen since the discussion above I believe you have discussed making it easier to get started writing code by allowing global code without Main(). Would it similarly make it easier if I did not need a project file, as proposed here?

We currently don't seem to mention in docs like this that it doesn't work in Core: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/compiler-options/command-line-building-with-csc-exe

danmoseley commented 4 years ago

Reopening for discussion, feel free to close again.

jaredpar commented 4 years ago

My personal goal is to make it possible to use dotnet build and dotnet run for .cs files without needing an explicit project file. That is very different though than allowing direct invocation of the compiler in the form of say dotnet csc hello-world.cs.

The reason for using dotnet build / run vs dotnet csc for a single file application is because at a fundamental level building and running for .NET Framework and .NET Core are very different problem spaces. In .NET Framework there are the following advantages:

  1. While reference assemblies exist, there is really no meaningful difference in compiling against reference vs. implementation assemblies.
  2. Because of (1) above there is no need to every "find the reference assemblies". When you run csc example.cs on .NET Desktop we can find all of the default references by using the default csc.rsp file and resolving all of the assemblies in typeof(object).Assembly.Loctation
  3. There really isn't a deployment step to speak of which means you can easily csc /t:exe example.cs and then immediately just run example.exe.

That is why for .NET Framework using csc as the single tool for building is very approachable. For .NET Core though it's really not that generally useful for customers because they need to solve all of the above problems to successfully use csc.. The logic for those steps are inside dotnet build / run hence that is what I envision us leveraging for the single *.cs file scenarios.

That being said: I would like to make dotnet csc as usable on .NET Core as it is on .NET Framework for the act of compiling. If for nothing else than because it's how the Roslyn team does a lot of it's own work :wink:. But I don't think it will be a tool that a ton of customers end up finding that useful.

danmoseley commented 4 years ago

An implicit project file sounds like a great idea. Is that idea tracked anywhere?

jaredpar commented 4 years ago

Not in an official proposal yet. Still working on a draft of this. It's been discussed in a few forums though: email, twitter, discord, etc ...

danmoseley commented 4 years ago

cc @eerhardt since we were just talking about how this could be more approachable.

eerhardt commented 4 years ago

My personal goal is to make it possible to use dotnet build and dotnet run for .cs files without needing an explicit project file.

@jaredpar - for other languages that allow this, the source files allow for references to external code inside of the source file (both to other files and packages). How do you plan on tackling this problem? The scenario works great for "Hello World", but as soon as you need to use anything that isn't in Microsoft.NETCore.App, or to include some other class file, now you need a project file.

jaredpar commented 4 years ago

@eerhardt

By borrowing from existing directive style solutions 😄

#!r Newtonsoft.Json 
...

Directives are very easy to scan and easy to ignore by the compiler. This can be parsed out with some ReadLine calls and a simple string matching code. That can be done by the layer of the build that creates the implicit project file and it can translate them to <PackageReference> or file references.

km-hussain-in commented 3 years ago

Download https://github.com/km-hussain-in/CSharpCore/blob/master/cscc.zip and follow the instructions in readme.txt.

kinglionsz commented 3 years ago

Copy the cscc script from https://github.com/km-hussain-in/CSharpCore/blob/master/cscc.zip into dotnet installation directory and use cscc command. It compiles .cs file to exe which you can run with dotnet command

Good!

Tks so much👍👏

km-hussain-in commented 3 years ago

It works for me on Windows as well as Linux.

mirabilos commented 3 years ago

@km-hussain-in it doesn’t work on Debian; running with bash -x shows:

[…]
+ dotnet /usr/bin/sdk/5.0.201/Roslyn/bincore/csc.dll -nologo @/tmp/csc-5.0.4.rsp greeter.cs -t:library
Could not execute because the specified command or file was not found.
Possible reasons for this include:
  * You misspelled a built-in dotnet command.
  * You intended to execute a .NET program, but dotnet-/usr/bin/sdk/5.0.201/Roslyn/bincore/csc.dll does not exist.
  * You intended to run a global tool, but a dotnet-prefixed executable with this name could not be found on the PATH.

Though…

$ find /usr/ -name csc.dll
/usr/share/dotnet/sdk/5.0.201/Roslyn/bincore/csc.dll

… probably fixable.

evandrix commented 3 years ago

Download https://github.com/km-hussain-in/CSharpCore/blob/master/cscc.zip and follow the instructions in readme.txt.

is HTTP 404 ... someone re-up?

mirabilos commented 3 years ago

evandrix dixit:

is HTTP 404 ... someone re-up?

Not exactly the same, but I use this:

$ sh csc -nologo NinetyNineBottles.cs
$ sh dotnet-mkrtc NinetyNineBottles.exe
$ dotnet NinetyNineBottles.exe
99 bottles of beer on the wall, 99 bottles of beer.
Take one down and pass it around, 99 bottles of beer on the wall.

98 bottles of beer on the wall, 98 bottles of beer.
[…]

I had to split out the .runtimeconfig.json generation because I also use csc for .dll generation, which don’t need it.

Enjoy, //mirabilos -- FWIW, I'm quite impressed with mksh interactively. I thought it was much much more bare bones. But it turns out it beats the living hell out of ksh93 in that respect. I'd even consider it for my daily use if I hadn't wasted half my life on my zsh setup. :-) -- Frank Terbeck in #!/bin/mksh

!/bin/sh

DOTNET_CLI_TELEMETRY_OPTOUT=1 export DOTNET_CLI_TELEMETRY_OPTOUT

sdkver=$(LC_ALL=C dotnet --version) fwkver=$(LC_ALL=C dotnet --list-runtimes | \ LC_ALL=C sed --posix -n '/^Microsoft.NETCore.App ([^ ]) .$/{s//\1/p;q;}')

dotnet-sdk-5.0 installed via .deb package

dotnethome=/usr/share/dotnet dotnetlib=$dotnethome/shared/Microsoft.NETCore.App/$fwkver dotnet_cscdll=$dotnethome/sdk/$sdkver/Roslyn/bincore/csc.dll dotnet_csclib='-r:netstandard.dll -r:Microsoft.CSharp.dll -r:System.dll' for x in "$dotnetlib"/System..dll; do dotnet_csclib="$dotnet_csclib -r:${x##/}" done

add if needed

dotnet_csclib="$dotnet_csclib -r:Microsoft.Win32.Primitives.dll"

exec dotnet "$dotnet_cscdll" "-lib:$dotnetlib" $dotnet_csclib "$@"

!/bin/sh

DOTNET_CLI_TELEMETRY_OPTOUT=1 export DOTNET_CLI_TELEMETRY_OPTOUT

sdkver=$(LC_ALL=C dotnet --version) fwkver=$(LC_ALL=C dotnet --list-runtimes | \ LC_ALL=C sed --posix -n '/^Microsoft.NETCore.App ([^ ]) .$/{s//\1/p;q;}')

exename=$1 case $exename in (.exe|.EXE) ;; (*) echo >&2 "E: $exename is not a .exe file" exit 1 ;; esac

jsonname=${exename%.*}.runtimeconfig.json printf '%s"%s"%s\n' \ '{"runtimeOptions":{"framework":{"name":"Microsoft.NETCore.App","version":' \ "$fwkver" '}}}' >"$jsonname"

joshcangit commented 2 years ago

Thanks to @mirabilos, I made a script to use as csc. Even so, I'm definitely looking forward to using dotnet csc.

km-hussain-in commented 1 year ago

reuploaded dotnet-csc https://github.com/km-hussain-in/CourseSamples/blob/main/CSharp/cscc.zip?raw=true