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

> In .NET 6, in-memory single file apps have been enabled for Windows and macOS. In .NET 5, this deployment type was limited to Linux. You can now publish a single-file binary that is both deployed and launched as a single file, for all supported OSes. Single files apps no longer extract any core runtime assemblies to temporary directories.

This is a great! Now I can publish statically linked executables and run it everywhere. I don't have to tolerate Golang and its quirks just to have cross-compilation and static binaries, even though they will be larger in size.



Wait, wait… .Net can build “static linked” executables that doesn’t require that I install .Net to run? I had no idea, I guess it’s time to revisit .Net


That's exactly what it is. You can even cross-compile for all supported platforms.

    $ dotnet new console -n HelloWorld
    $ dotnet publish --project HelloWorld -r osx-arm64 --self-contained -o out -p:PublishTrimmed=true
    $ du -sh out
    10M


I haven't used .net. But how memory management happens when you are running a binary executable? Does it have a builtin CLR (Common Language Runtime[1])? Because CLR provides the tools for managing memory & security?

[1] https://en.wikipedia.org/wiki/Common_Language_Runtime


Yes, it embeds the CLR in to the application see the PR at https://github.com/dotnet/runtime/issues/43072


Wow... I didn't know. Since when can it do this?


I've been using this for at least a year or two. With their stripping, my binaries (which use very little other than system.* and math.*) are 12M in size on each OS. I tested with today's release of version six, the binaries are about 1M smaller each.


I believe it was introduced around .NET Core 5? or 3? so at least 1 year ago


Since .net core 3.0


After almost 18 years, Joel finally got his wish:

https://www.joelonsoftware.com/2004/01/28/please-sir-may-i-h...


This, combined with linker stripping below even assembly level for smaller static binaries.

.NET 7 will work on NativeAOT for instantaneous startup of especially smaller apps, but I think they’ve already optimized JIT warmups or something — I was pleasantly surprised when I just wrote a .NET 6 console app that read JSON from a server.


If it's like v5, you can. They're big (since they include .NET, though it looks like v6 will strip out more than v5). And they won't run on Windows 7 without an administrator installing a system component first.


For an internal tool that reformats our code base, I've used that to pack the `dotnet format` (although technically, not allowed case, since it's a tool, and need to be run from an "sdk" environment). It works for what we use it (whitespace formatting, but not for msbuild/analysis - which is clearly understood).

One thing though, is that native .dlls are still outside (DetoursServices.dll for example in BuildXL). But still pretty impressive what it can done. That, and the new embedded .pdb (for .NET only, e.g. not native).

I wish "publish" was used more by the place I work for (most of the folks would simply Release (F5) and store what's there in p4). I've only recently discovered about "publish" and that is after haven't worked with .NET for so long...


Yeah "publish" is magical, I specifically jumped from .net 4.8 to 5 just for this feature.


msbuild had publish since at least .net 3.5 (when I started to use the platform) it was just a little bit akward to use tough. and of course dotnet publish is 1000x better than msbuild with it's obscure syntax (which got way better in .net5 and 6 with -p: syntax, etc.)


-p:Property=Value (or /p: Property=Value) has existed in Ms build since the beginning. That's not a .NET 5 or 6 thing.


Also If I'm not mistaken most of the properties (if not all) can be set through the command-line (for good and bad :)), e.g. `set Property=Value && msbuild` or `Property=Value msbuild` (on unix systems)


I don't remember what changed, but I wasn't able to use it on my old .NET projects.


>> Single files apps no longer extract any core runtime assemblies to temporary directories

I might be ignorant here but if you're not specifically pointing out what version DLL's you want, aren't you in fact publishing a dynamically linked executable instead of a statically linked one?

Doesn't these single-file apps rely on the GAC?


There is no GAC.

> .NET Core and .NET 5 and later versions eliminate the concept of the global assembly cache (GAC)


Interesting. I haven't worked in .NET for several years now, but the GAC was always an absolute headache to deal with.


Thankfully they did not port this hell to Linux


Surely the binaries generated by the JIT still get cached somewhere?


you can set a ReadyToRun flag on publish which pre jits your dlls https://docs.microsoft.com/en-us/dotnet/core/deploying/ready...


The whole runtime gets included in the binary.


This actually makes sense in 2021 since we have the resources to allow things like this. 20 years ago this might have seemed insane.


Keep in mind that it's just one option. If you want, you can still deploy your app separately from the .Net runtime.

Also, to keep the size at least somewhat in check, unused parts of the base library are not included in the single-file mode.


Keeping in mind it's also a double edge sword. TLS deprecations alone will ensure your app will die after a few years if it doesn't run on an up-to-date CLR.


This sounds quite the argument for basing critical workflows only on software for which the user has both access and permission to modify the source code.


Timezone and DST fuckery is another, I assume?


30 years ago we used DOS and DLL Hell was a completely unknown concept. We did have to deal with himem.sys though.


On the contrary, 30 years ago we were using Windows 3.0, which is about when dll hell started being a real thing.

(DLL hell stopped being a problem a lot sooner than you probably think, too...)


>DLL hell stopped being a problem a lot sooner than you probably think, too

Does not match my experience at work unfortunately.


If you're seeing this on any version of Windows made in the last 22 years or so, it's because a software developer fucked up in a really creative way. My condolences.

Sometimes the issue is that people have tended to conflate "dll hell" and "dependency hell." That's an old pet peeve of mine and I realize it doesn't matter...


"Insert floppy disk 435 of 880 and press [Enter] when ready..."


Invalid media type

Abort, Retry, Fail?

FFFFFFFUUUUUUUUCCCCCCKKKKK!!!!!!


Does this mean you need one binary per OS so that the runtime matches, or do they do some magic so that one single binary can run on all Oses ?


You create a single binary which has the runtime and dependencies self contained within.

You of course have to choose your target platform for this as it makes .exes for Windows, ELFs for Linux, etc.

If you want you can still choose to distribute IL DLLs and users then use their already installed dotnet on their machine to run them.


> You of course have to choose your target platform for this (...)

https://github.com/jart/cosmopolitan

(but, yeah, you probably want one version per target, even if hacks are cool)


You create one binary per OS.


How much does this add to the binary's size?


Something like 60MB if the application is not trimmed. Closer to 10MB if the application can be trimmed.


In my case about 60MB


Kind of curious that Microsoft had a feature that was available in Linux but not Windows, no?


Yea, funny :D However, the problem was mostly deploying dotnet apps on servers which did not have dotnet installed. Windows has .NET installed anyway, so there the problem did not really exist


.NET (Core) 5 is not installed on Windows. Windows comes with .NET Framework 4.x.

I think the user interest was startup times of lambdas and containers. Therefore Linux was a priority.


Seem to recall this happening several time with Microsoft Office for Mac getting certain features before Office for Windows did.


What do you mean by golang quirks?


No passable debugger, weird typing system, verbose error handling, lack of exceptions, generics, syntactic sugar ...

I'm a novice at Golang, and I dislike much of the language, except that it's fast and can produce small binaries.


"verbose error handling, lack of exceptions"

Exactly why I prefer Go to Java and C#.


Understandable, but it's a matter of taste. For people who prefer a language with exception, it's good that there now exist a viable solution other than sticking to a language that might not fit their taste so well.

It seems to me that F# could get a bit more love from HN-style nerds. Obviously, it's more similar to C# than Golang, but specifically error handling can be done in much nicer way using the Result type.


But Go has no sum types either!


I can live with many things, but no generics in 2021? Over my dead body!


Sounds like you want nim.


Yeah, nim ticks all the boxes, but the ecosystem around it should grow a bit more until I can develop comfortably with it.

vlang[0] also seems like a nice golang "fork" that I'd be willing to spend time on.

[0]: https://github.com/vlang/v/blob/master/doc/docs.md


As a personal choice, would rather use Vlang than Nim. Like the potential and what I'm seeing from Vlang, though was hoping the cross-platform UI would be further along. As it is, they are developing quite quickly.


Not wanna bring down that project, but be wary of V, as in the past it has made plenty of impossible to live up to “features” and indeed, never delivered. But I haven’t followed it since then.


I'm aware of the controversy, and I've been following its development for some time now. It seems to be developed at a neck-breaking pace, but I'm still waiting for an official "go!" license before I start playing with it.

I hope they succeed because it has/promises a really attractive set of features.


I wish that I knew about this earlier. I'm a Linux user but I love C#. I suppose that VS Code is the canonical IDE for C# today?


No visual studio or rider, vscode support isn’t great from my experience.


Thanks. I love the Jetbrains IDEs.


For Linux you can use either VS Code or Rider.


Terrific, thank you.


Last time I tried it, single-file binaries were super slow on first load. It was one of the reasons we went back to .NET framework. Has this improved?


You should also be able to do this in Java with jlink.


yes but then you have to write your program in java


Yes, arguably a better decision than writing it in golang to begin with.


Go is better than Java any day of any week if startup time or memory footprint are of any concern to you at all.

Also Java is OO which is... terrible to say the least.


Java has had AOT compilation since around 2000, just not as free beer.

In 2021, the AOT free beer exists, as do JIT caches.

As for OO model, I rather be able to understand which interfaces a type implements by looking at it, instead of producing compiler errors, or have a type by accident supporting a single method interface with complete different semantics.


GraalVM is a thing (see: www.quarkus.io for an example) if fast startup and low memory usage are a requirement.

Not sure what the OO rant is about, it's awesome. It's not like golang isn't (poorly implemented) OO as well (minus explicit inheritance, which embedding is somewhat similar as well).


and now you have two problems


Three problems, since POM.XML is probably involved somehow.


I rather have a pom.xml than build.xml or gradle spaghetti.




Consider applying for YC's Winter 2026 batch! Applications are open till Nov 10

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

Search: