Exploring the new .NET “dotnet” CLI
hanselman.com
hanselman.com
This is the most exciting thing for me in the new dotnet CLI as a person writing Go full-time at Microsoft. Most developers will be able to take advantage of single-binary shipping, they'll just put that in a Docker container and happily run everywhere.
In the GNU/Linux world maybe, but that is just one planet in the C and C++ galaxy.
Making libc dynamic link only allows the OS developers to change the userland/kernel land interface as they see fit without breaking compatibility. The fact that this also ties you to a dynamically linked C runtime library is an artifact of the close ties between Unix and C.
Over in Windows land, there isn't a tight coupling between libc and the system call interface. libc is provided by your compiler (Visual C++ provides static and dynamic versions), while the system call interface is provided by ntdll.dll and friends, which are part of the OS and free to change in future OS versions.
https://blogs.oracle.com/rie/entry/static_linking_where_did_...
However, that is one implementation of one compiler in one specific OS.
So many languages did this for so long and then VMs got in vogue. Go not doing it was, for many people, a reminder it could be done.
But for a managed language runtime like the CLR to start supporting it is a big deal.
But I do agree it is a big deal, specially for getting more developers to adopt safer programming languages.
It turns out that gccgo stores critical information for the program execution as debug information, which strip will happily remove, leaving you with an undecipherable error on execution.
Maybe you mean developers of scripting languages?
In any case, C# always had this in Singularity OS.
Java always had this in comercial JVMs targeted to embedded market.
except for every other code formatter ever.
If I understand ngen correctly, it only compiles to native code at install time - meaning that the assembly and its IL code needs to be included. Is this correct, and are there other key differences that I've missed?
Not saying this is not an issue (although it isn't really in most fields, except for things like embedded), but that the 656 KB for "Hello World" is because of the "upfront cost" in binary size.
I have spent sometime developing in Delphi years back, and this was even more true with it (simple hello world GUI app was over a megabyte [create new project and compile], complex GUI app was barely above it).
Language runtime.
http://blogs.msdn.com/b/abhinaba/archive/2008/09/15/how-many...
# echo 'main = putStrLn "hi"' > hi.hs
# ghc --make -optl=-static -optl=-pthread hi.hs -o hi
[1 of 1] Compiling Main ( hi.hs, hi.o )
Linking hi ...
# file hi
hi: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, not stripped
# du -hs hi
10.6M hi
# strip hi
# du -hs hi
4.4M hi
This is against musl libc by the way.In this case you would only pick .net if you were making something complex enough to warrant the size cost in exchange for the perceived benefits.
I mean comparing it to a raw native binary isn't an apples to apples comparison. What might be better would be comparing it to another VM based language like java / ruby / python / node. Where the size of the app is the scripts + the installed runtime.
Your one line "console.log('hello world!')" node app may be less than 1k but with the size of the node binary added in it becomes more comparable.
The DOS-style CLI arguments used by Microsoft's other command line tools seem like such a stubborn throwback to a long-lost war. "/" won the battle for folder path separators (see: URLs) and "-" won the battle for argument delimiters.
The reasons were technical[1] instead of a stubborn resistance.
The hyphen "-" was allowed in DOS/Windows filenames. The "/" was not. Therefore, if you programmed your command utility to use "-" as command line switches to match UNIX convention, your app would be "broken" because it couldn't accept filenames that began with hyphens such as "-verify.txt"
If you then try to mitigate that with an "escape" switch such as double-hyphen "--" to turn off the hyphen processing, that means you can't operate on files that are named as "--". (Viruses and malware love creating files with legal filenames that utilities can't open.)
So then you layer another hack on top of that and create the mother of all escape sequences with something like "--switch_character=-" (and then cross your fingers that nobody has a file that's actually named "--switch_character=-".
(Arguably, you could make "myapp -- --" be unambiguous by imposing a rule that position is significant (the 1st "--" is parsed as a semantics switch, and the 2nd "--" is parsed as the oddly named file) but now you've given up the flexibility of specifying parameters in any order which many UNIX utilities do allow.)
Instead of all that complication, you just let "/" be the switch character and it's easier because "/" is already an illegal character for filenames. (When in Rome...[2])
[1]https://en.wikipedia.org/wiki/8.3_filename#Directory_table
[2]https://en.wiktionary.org/wiki/when_in_Rome,_do_as_the_Roman...
The actual reason that DOS uses "/" to mark options isn't technical, it's purely historic: that was the character that CP/M used.
I'd call the behaviour "dangerous by default." You need specific training to be aware of, and overcome the issue, without the training you're likely executing commands which can be taken advantage of (in particular recursive commands over files and directories you yourself don't control).
Yes, 40 years ago, the decision was arbitrary not technical.
myapp "-verify.txt"http://blogs.msdn.com/b/twistylittlepassagesallalike/archive...
That article also doesn't go into the difficulties of quotes in legacy DOS apps. Passing/ignoring quotes in DOS command lines was extremely difficult compared to the Win32 API. The CMD.EXE would eat the quote delimiters and your app wouldn't even see them. (It's been many years since I last tested this so a new OS like Windows 10 may have changed things.)
There was a system call which would tell the argument parser that you wanted a different switch character, and if you changed it to, say, "-", then "/" would work. Of course, not everything used the standard argument parser, so if you did change this you ended up in a world of pain because your tools would start behaving inconsistently, but it was theoretically possible.
I've seen references to this code existing as late as XP, but I don't do Windows any more, so can't comment on later versions.
That leads to some interesting answers on stackoverflow sometimes about cross compatibility, where the correct answer of "use whatever constant your language has for directory separator" gets down-voted in favor of "use forward slash everywhere".
Many applications assume \ and deal with paths directly, instead of using the Windows APIs for path manipulation.
This means the moment your application gives a / to another application, there is a high probability that it will break, regardless of what the Windows API supports.
Even cmd doesn't handle / properly.
You can take it as a side criticism of how things are turning sour on stackoverflow with "popular" being more valuable that "right", I guess.
Painful to say the least.
[1] https://github.com/tracker1/msysgit/blob/patch-1/bin/start-s...
[2] https://github.com/msysgit/msysgit/blob/master/cmd/start-ssh...
[3] http://stackoverflow.com/questions/34647591/passing-windows-...
[4] http://stackoverflow.com/questions/30195353/trouble-running-...
Deleted comment
He really did not.
Currently .NET Native (AOT) is used with WinStore apps - in fact every Win10 .NET application in the store and on your computer HAS to be .NET Native - but the plan is to make compiling a native DLL possible for all .NET Core applications.
So many write "go-style" as if it was something that was just invented by the Go team.
So is the knowledge in our industry.
There are some traps though; one I ran into for example is that you require dynamic linking in order to use libnss. I ended up producing a mostly-static binary that just depended on the platform's libc but brought its own libstdc++.
Similarly on Windows, statically linking third-party COM components is not a good idea.
There are plenty to choose from, but if you want a list:
PL/I, Algol, PL/M, Quick Basic, Turbo Basic, Quick Pascal, Turbo Pascal, C, C++, Ada, Eiffel, Haskell, Objective-C, OCaml, Delphi, Oberon, Oberon-2, Component Pascal, Mesa, Modula-2, Modula-2+, Modula-3,...
Jeez.
It is dynamic linking that is hard to implement, not the other way around.
The ones with compilers that also support dynamic linking, either via a switch or via explicit dynamic modules.
It would be nice to have something like JavaFX for .NET - resurrected Silverlight could be it.
As someone who does not follow the .NET landscape that closely can anyone explain why this is a big deal ? Java has been able to do 'javac Hello.java; java Hello' for as long as I can remember. If this was so important why are they getting around to it only now ?
This is more like maven or leiningen I guess - you can build and run, manage dependencies, create projects. That said, I'm not up to date in the Java landscape.
Also, since Java 8 you can package everything together with the reference JDK, no need for third party tools any longer. This will be improved with the Java 9 modularity and possible AOT compilation in Java 10.
This is intended to be a high-level tool that can be used as an alternative to IDEs.
I have a ton of old CLI apps I wrote in VB.Net 10 years or so ago and it would be interesting to port them. Mono's support for VB.Net last I tested was not good.
In fact, the package I used for the compiler binaries contains the csc + vbc compilers, so it's literally just shoveling some command line arguments down the pipe.
It's definitely on my to-do list. :)
Annoyingly it seems to work differently to how DNX builds. With my project [1] I have spent what felt like an age setting up a .NET Core supported project.json that builds with 'dnx build'; the result is horror slow compilation and maxed out CPU usage whenever I build in VS2015, even if nothing has changed - actually borderline unusable. I have rebuilt all of the csproj files and the sln that I originally deleted to make way for the project.json and xproj files. So I now have:
* project.json per folder
* <project name>.project.json per folder
* <project name>.csproj per folder
* <project name>.xproj per folder
* <project name>.sln per folder
The per xproj sln is tedious just so I can tick a box saying 'Produce output', like I'd ever not want to produce output. Total mess.So I thought I'd give this (dotnet CLI) a go. I can't run from the root because there's not a project.json there. If I go into the Core project then it compiles OK (on OSX with no issues), but builds in the <project>/bin folder like MSBuild. That means the other projects in the repo can't find their references like they can with the DNX artifact system. It seems to me that it should support the same DNX project.json/global.json dependency system.
Whilst I support the general direction MS is taking with DNX and 'dotnet'. The whole system is a buggy inconsistent mess and has recently lost me weeks of time trying to figure out the magic combination of settings that are needed to support cross-platform builds (actually most of the time has been spent waiting for builds, waiting for VS2015 to stop locking up, or giving VS2015 enough 'lock up time' before killing it from the Task Manager and starting again).
I'm also not sure MS has quite prepared itself for the public evolution of their tools and source. It has lead to a trail of misinformation throughout the web - and I for one have found the process incredibly difficult to follow. Trying to piece together what is going-on through github issues on the aspnet/dnx/fsprojects repos is tedious. I still don't really know if I'm doing it right and the 'official' help is light on details at best.
The dotnet-cli stuff is super new so a lot of the tooling is incompatible right now. As things start to settle out more in the next few weeks a plan to write a series of blog posts about how things work, general development approaches, and where you can expect to hit rough edges.
Thanks for the feedback, though! We're definitely a bit new to this style of development.
Also, I don't know how long ago you tried Mono + VB, but especially since MS started collaborating with Mono and offering upstream first-party support (~2 years), support for the IL has been almost production quality. (Now it is production quality - I'm running some of my customer ASP.NET applications which was built around the NHibernate rather than EF/MS SQL on full Linux infrastructure).
Satya is making a ton of bold moves that are basically antithetical compared to the Ballmer-era MS. Visual Studio Code (yet-another-electron-based-editor) and Community, along with the ridiculous amount of open stuff on Github has effectively eliminated the vendor-lock-in stronghold that Microsoft previously had. Residual Office renewals and upgrades on the MS SQL stack will only get them so far. They're going full Docker[1] support on the new Windows Server stack, as well as full .NET support off the Windows stack, which is interesting to say the least. I wonder if we'll start seeing them buying out companies that are traditionally aligned with more-open-sourcey.
A bold move they could make would be buying out Cognitect. Datomic could be a perfect fit for them. Integrate Visual Studio support (e.g. as good as IntelliJ/Cursive) and give CLJS first-party support (let Nolen take a lead spot on the TypeScript team) in VS and it could be a steal at even a few hundred million dollars. The talent (Hickey+Nolen) the developers who they bring over + the perception shift within the dev community + the Datomic itself is likely worth a half a billion to MS.
[1] http://www.hanselman.com/blog/BrainstormingDevelopmentWorkfl...
I doubt a bright person such as David Nolen would like to work with TypeScript as it is right now.
IMHO of course.
MS gets the Clojure (and maybe more importantly the CLJS userbase), Cognitect gets massive reach (CLJS is subsidized solely by the licensing of Datomic by strict revenue), MS' corporate customers get Datomic. Just going by the direction MS has been in lately ("embrace & extend") under the new anti-Ballmer role, floating an offer of 300-500 million would be beneficial to everyone involved. Let's say there are conservatively 100k Clj(s) users out there right now using Clojure + Sun's JVM. At 300 million that's 3k per active developer acquired right off the bat. You'll lose maybe 10% of the users who live-by-their-Macbook-and-die-by-their-iPhone. Even at 600 million, that's still a cheap price to pay.
Finally Microsoft will put something of that is useful for everybody.
I'm adding this to my list for potential 20% time project exploration.
Cross platform and cross language have their interesting aspects...
dotnet is a wrapper ( like git command ) for multiple executable, to replace msbuild as project file + build tool and add some new functionalities ( restore nuget packages, etc )
i think the real news is having a dumb project.json (nuget deps,source files,etc) and a xplat tool ( dotnet ) who read this project.json, and can restore packages, compile ( --native too ), publish, packages as another nuget package, etc.
All that xplat and multiple language. c# works, F# got merged last week, other coming next.
Some example commands:
- `dotnet new` scaffold a new project ( really simple atm )
- `dotnet restore` read dependencies from the project.json and download nuget packages
- `dotnet compile` call the csc compiler ( with a wrapper `dotnet-compile-csc` ) with source files, defines, references from project.json, etc
There is a good split of responsabilities, you can call dotnet-compile-csc if you want. dotnet cli bundle the roslyn compiler ( c#, vb ) and f# compiler, so ready to go
for example `dotnet compile`.
dotnet compile read project.json and call ( for c# ) the `dotnet-compile-csc` passing source list, defines, references, etc. dotnet-compile-csc doenst know about project.json, and call csc ( the c# compiler ). if --native, the `dotnet compile` then call a compiler from .net bytecode to native code
It's more like a replacement for msbuild, with a really good command line story, and a common project file ( project.json ) who can be used from visual studio or vs code, or others ide ( it's a json file, dumb )
And you'd have to be pretty belligerent of VS to use a cli to create a .Net project instead of clicking 'File > New > Project...'. Although the amount of crap they add in to a asp.net project these days is phenomenal. You spend 20 minutes deleting all the junk they've added.
It just seems to be a simplification. In all honesty the article doesn't actually say anything really about why we should use it.
[1] https://docs.nuget.org/consume/command-line-reference#restor...
Obviously you can do everything .Net related already - if you're sitting in VS on Windows.
https://github.com/dotnet/cli/tree/master/src/Microsoft.DotN...
https://github.com/dotnet/cli/tree/master/src/Microsoft.DotN...
c# is used to bootstrap all tools, so it's the first supported language and the default. Nightly, dev build have f# support, but it's a beta ( merged last week, but it's ok ).
f# dotnet cli (the wrapper for f# compiler) is a beta, but moving fast, not much todo. For example the f# support in dotnet new is in a pull request.
The F# compiler built for coreclr ( bundled with dotnet cli, so ready to go ) is working pretty much, some stuff missing ( portable pdb for example ),
f# coreclr is open source https://github.com/Microsoft/visualfsharp
You can have multiple project (same repo, different directories ) and reference one from another
you can have each project.json use a different compiler setting the compilerName property ( csc for c#, or fsc for f# ) .
A project can reference another project, so you can reference a F# project in a c# project, or the other way around.
like now in .net with msbuild or other tools
This looks pretty cool. I wish powershell were slightly easier to set up and use, and that there was a repo for extensions other than "google it and then download".
[1] https://technet.microsoft.com/en-us/library/dn807169.aspx [2] https://www.powershellgallery.com/
Powershell is certainly a cool shell, but it is a shell, and that makes it much less likely to be ported+packaged everywhere (Pash exists, but I don't know whether it exists as, say, an Ubuntu PPA.) Whereas, when you release a language, you kind of want its tooling to go wherever it goes.
.NET CLI is a set of cross platform command line tools for making .NET applications.
Scott is showing off command-line tools for creating and compiling C# projects.
Perhaps I'm just overly familiar with the unix small tools philosophy.
the dotnet is like git, so `dotnet compiler` just call `dotnet-compiler`
the first level tools ( dotnet-compile, dotnet-restore ) read the project json ( the only supported project file atm ) and pass argument to second level tools.
for example:
- dotnet compiler call dotnet-compile
- dotnet-compile read source files, references, defines from project.json and call dotnet-compile-csc with the source files as arguments.
- dotnet-compile-csc call csc
- if --native, another .net bytecode to native tools is called
and csc (csharp compiler) is bundled with the dotnet cli package.
Once you have fetched ruby I'd be much happier if it was all one command "ruby" for fetching packages, building, running etc. That doesn't mean it can't be several pieces of code running in the end, but from the end user perspective one top level util for one set of tasks makes sense.
Compare "git lfs foo baz" with "git-lfs foo baz". I think the first is a lot better, even if what happens is closer to the second.