In case you missed: "dotnet compile --native" is basically like the Go compiler, it statically links all the DLLs and produces a single PXE/ELF executable.
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.
Because static linking has been out of vogue for so incredibly long in the C/C++ worlds, and above that, most languages either compile down to C, or are interpreted.
I mean broadly almost all unixes, Mac, and Windows. All the big platforms. In embedded systems and plan9, static linking never left. But for mainstream development for desktop and server systems? Static linking has been out for a while.
Huh. You learn something every day. But for the most part, everybody still links against libc dynamically. Solaris has actually stopped providing libc.a!
Which makes sense when you think of libc as "the library which provides the system call interface to the OS, and just happens to provide a C runtime library as well".
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.
This is true. It's funny because the api's have always existed in the Microsoft compliers but they would litterally throw not implemented errors when run. Mono actually implemented them.
Particularly on the topic of binaries. I've tried using gccgo (the Go backend for GCC, or "the stepchild Go compiler for sake of having a second compiler") for use on an embedded device.
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.
This is, in fact, really cool. Asking as someone who's relatively unfamiliar with .NET - what are the most significant differences between compile --native and ngen.exe?
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?
If I'm reading the article correctly, that's a 656KB "Hello World" binary. 671,644 bytes just to print a single string to standard output and exit? That is smaller than the whole .NET framework, but considering that a real native "Hello World" binary is <1KB, what's the other 655KB doing?
While your point is absolutely true, the rule of thumb in those case is that the growing curve in file size is not linear; while the very minimal executable already brings lots of things it doesn't need, adding functionalities make it grow slowly (since a lot is already there).
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).
If it's truly just a single binary, wouldn't that include the whole GC and runtime system? If so its probably the entire core runtime plus a few bytes to console.writeline a string.
# 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
If you truly wanted your app to just print out the one line then you could probably pick a different language.
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.
They also have an Azure SDK for Go which we are using at HashiCorp in Terraform and Packer - https://github.com/Azure/azure-sdk-for-go. I believe the Visual Studio Code editor supports Go as well.
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.