Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

I was hoping to see in the readme how this is different than what they offer in core today? You can build self-contained exes (and they're getting better with each release). Is this the same only different or an improvement on that?


It is different.

.NET Core will create a self-contained executable which can have AOT compilation (or not), but which will include the byte code so that it can be JIT-optimized at runtime.

This is about creating a binary that is small and uses some of the upcoming experimental stuff like Crossgen 2 and NativeAOT. Some of the Crossgen 2 stuff will land with .NET 6 this fall.

As the project says, it's about bringing together two components that are being actively worked on in the .NET ecosystem to create a compiler and runtime for small binaries.

For most people, you'll want the normal .NET self-contained Ready2Run binaries. They're compatible with everything and rock-solid. But sometimes you want to play around with something - like creating C# programs that are going to be tiny.

Microsoft and others in the .NET ecosystem are improving C#/.NET at a rapid pace and it's great. bflat is, as it notes, using what is being created in that ecosystem. I mean, bflat literally labels itself "Initial proof-of-concept release" at this point. The guy writing it is on the .NET Runtime team at Microsoft and is really interested in these types of things. I think we can all imagine ourselves creating a project that does things a bit differently to figure out what is possible, figure out possible future directions we could take our work, etc.

So, it is different from what is available in .NET today. It's written by one of the people on the .NET Runtime team who is interested in this stuff. Some of the concepts might show up in .NET 7/8/9. Heck, Crossgen 2 should be showing up in .NET 6.

It's a cool proof of concept of slimming down C# binaries and even the readme shows how things like stack trace information takes up space.


Those self-contained exes need a .NET runtime to be just-in-time (JIT) compiled to code your CPU can actually run. This JIT compilation happens as your app runs, so your startup performance suffers as a result. On the other hand, bflat compiles your project ahead of time into native code your CPU understands.

Also, to build that exe you have to use the .NET SDK which pulls in lots of tooling: MSBuild, NuGet, etc... It looks like bflat ditches all of that.


You can actually add `-p:PublishReadyToRun=true` to your `dotnet publish` command and it will do AOT compilation for you. It blows up your executable a bit, but it does pretty much give you warmed up code at the get go.


That's only partial compilation and not the full AOT available with something like CoreRT.


It's been a few years, but I worked on a dotnet core C# project once. Prod was Linux and dev usually OSX. I remember running a dotnet build to generate some kind of artifact (dll maybe) that still needed the SDK to run. Is there some other way to do it that made a self contained executable?


Yes, .NET Core can now create self-contained executables. Microsoft and others have been enhancing this since it was introduced in .NET Core 2.1.

I've been enjoying the way that .NET has been evolving in pragmatic ways. The initial implementation basically created a self-extracting zip that would include the runtime. That had its drawbacks, but it was a way for them to get self-contained deployable out the door with minimal hassle. Sure, it meant taking up a bit more space, but it worked and solved what most people cared about: having a single file that they could run without needing to install things in the OS.

Likewise, they came up with ReadyToRun. Basically, they'd AOT-compile stuff for fast startup times, but include the byte code so that things could be JIT-compiled during runtime. This meant that the AOT-compiler didn't need to be perfect and that they didn't need to worry too much about things like the performance of reflection code. That code would end up JIT-compiled in long-running programs. Again, a pragmatic approach that does have some drawbacks (like large deployable artifacts), but they got it out the door and have been improving it as time goes forward.

A more pure approach might be to wait until one can produce a really top-notch AOT compiler, wait until one can replace certain reflection-heavy code, wait until one can optimize libraries, wait until one can do lots of testing to make sure you don't have regressions, etc. But that requires a lot of time while what a lot of people might want isn't a pure solution, but just something that allows them to speed up start times.

Likewise, zipping up the runtime with your code into a self-extracting and self-running file isn't the most pure approach, but it meant that you could get a single file to scp and just do `./myprogram` on.


The self extracting is gone for Linux in .NET 5 and gone for Windows in the upcoming .NET 6. If any copying still happens, it just within the memory space of the process.

If you include extra DLL or .so files, those still have to be extracted so that the operating system dynamic linker can load them.


Yep! It's one of the things that's nice about the .NET ecosystem. We didn't have to wait for self-contained executables and got them back in 2018 (even if it wasn't perfect, it worked well enough) and they refined it as time went along in a way that didn't require me to do things.

Microsoft could have waited until .NET 5/6 to offer self-contained executables "the right way", but they were able to create something that offered 90% of people what they wanted a few years earlier.


Yep. One of the things I've been doing lately with some internal utility apps is building a small Windows exe (for Workstations where almost always the dotnet runtime is already installed), and a larger but self-contained binary for linux.

    dotnet publish -r win-x64 -p:PublishSingleFile=true ---self-contained=false

    dotnet publish -r linux-x64 -p:PublishSingleFile=true -p:PublishTrimmed=true --self-contained=true
To give an example of this for a reasonably complex test tool I have on .NET core 3.1, the Windows exe is 3.7MB and the linux binary is 38MB. I'm guessing there's some room for optimization in the process though, as the linux binary is compressed (tgz) to 13.37MB.


The binary is that big on Linux because the debug symbols are embedded in the executable. You need to strip them.


In the interest of keeping the comment small, I omitted a couple things:

    -p:Configuration=Release -p:DebuggerSupport=false 
FWIW, I did also try the following, but found they had basically no impact on output size:

    -p:TrimMode=link
    -p:EnableUnsafeBinaryFormatterSerialization=false 
    -p:EnableUnsafeUTF7Encoding=false 
    -p:EventSourceSupport=false 
    -p:HttpActivityPropagationSupport=false 
(Tested on .NET Core 3.1.5)


Huh, the debug symbols are in separate .pdb files, aren't they?

38MB is a pretty typical size for a real-world, self-contained, assembly-trimmed package, and the size comes from the runtime itself, plus the core assemblies that weren't trimmed out.


Actually, in my tests with the AoT compiler I had to strip the binary to get a significantly smaller one despite there being a .pdb file. Your mileage may vary as the build flags can be a bit fiddly.


Yes, since I believe 2.1 you can make a self contained executable with sdk included using dotnet publish. You can read more about it here: https://docs.microsoft.com/en-us/dotnet/core/deploying/#publ...


The nice thing they also added was the ability to trim the self-contained app, so it doesn't include a lot of unnecessary assemblies.

https://docs.microsoft.com/en-us/dotnet/core/deploying/trim-...


self contained executables simply bundles the libraries, but still requires a JIT compilation to execute.

The description of bflat is what you are looking for, and it's the second section of the readme.

bflat implements a form of ahead-of-time compilation.

This is closer to .net native conceptually, but that was only a UWP abomination.

edit: replies have pointed out this is actually closer to ReadyToRun, a neat feature I was not aware of.


replied with this on another post, but you can add `-p:PublishReadyToRun=true` to your `dotnet publish` command to do AOT. it blows up your binary in size, but pretty much gives your warmed up code from the start.


it doesn't fully AOT your app and worse it doesn't produce a native static executable

it runs few tier for JIT, it still ship with IL and the JIT

don't advertise ReadyToRun as "hey we got AOT at home, says Microsoft salesman"

because all it does is makes me want to use Go instead, it feels and sounds bloaty


What about with ReadyToRun and single file?




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: