What does HackerNews think of min-sized-rust?

🦀 How to minimize Rust binary size 📦

Language: Rust

#3 in Rust
That must be without stripping. Also there are ways to reduce binary size. See e.g. [min-sized-rust](https://github.com/johnthagen/min-sized-rust). I've gotten stripped binaries of small cli utils less than 400KiB without doing anything special, less than 150 KiB by customizing profile settings and compressing with upx, and less than 30 KiB by replacing the std with the libc as the link shows. Haven't tried with fltk though...
You can check out a number of strategies for reducing rust binary size here: https://github.com/johnthagen/min-sized-rust

I don't think he mentions it, and I doubt it's relevant in your Hello World example, but if you have a lot of generic code, it's useful to extract the non-generic parts into a separate non-generic function. For example:

  fn foo>(s: T) -> String {
      bar(s.as_ref())
  }
  
  fn bar(s: &str) -> String {
      // A whole bunch of other stuff
      s.to_string()
  }
On their github repo:

> Simple "hello world" at about 65kb, comparable to React

I assume that is minified and compressed. That's quite bloat. I wonder if they try https://github.com/johnthagen/min-sized-rust ?

Also I feel like the BytecodeAlliance too much focus on their cloud runtime use case while seamless wasm + dom interop is where its adoption will skyrocking. I would rather write Rust/Go/Roc/any-sane-typing instead of TS.

AssemblyScript produces the smallest binary and then Zig. Rust produces bloat binary by default but can be small by https://github.com/johnthagen/min-sized-rust for hello word type of app. I have no idea if the gc proposal could make those langs produce smaller binary size. That said, .wasm is generally smaller on wire and faster-to-execute on host.

    > Rust makes enormous binaries
Rust binaries are optimized to be fast (by default, fast != small), this [0] explains pretty well why, and min-sized also has many optimizations [1].

    > and compiles slow
You can have a very slow compiler with all the optimizations and safety checks, or a fast one which doesn't. This however doesn't mean there is no room for improvement.

One thing that can definitely improved on is how cargo manages dependencies, I am tired of each of my project's /target directory using >2GB of disk space, there at least should be some kind of opt-in global cache.

I am also worried about dependencies going in the same direction as the JS ecosystem, many of my projects only have 3-5 top level dependencies, but I end up downloading hundreds. A few are only compile-time, but this makes auditing very difficult and does make compile times a lot longer.

[0]: https://lifthrasiir.github.io/rustlog/why-is-a-rust-executab... [1]: https://github.com/johnthagen/min-sized-rust

Yes, it has a bit of the same problem Node does with NPM.

There are ways to minimize the final resulting binary though, such as link time optimization, stripping symbols, building in release mode, and more. The following does a good job going over the options:

https://github.com/johnthagen/min-sized-rust

A dynamically typed Lisp has virtually nothing in common with Rust. A cached heap can benefit literally any language which is why it's an optimization found in some programs written in C or C++ as well.

Also, Rust binaries have been of comparable size in the past. Check out this question where someone asks why Hello World is 3mb even in release mode:

https://stackoverflow.com/questions/29008127/why-are-rust-ex...

This 3mb doesn't have any cached heap, doesn't have any garbage collector, doesn't have support for high quality exceptions and doesn't have much in the way of a cross platform abstraction, whereas the Clojure-as-native binary has all of those and more.

There's a giant pile of things you can do here to try and reduce Rust's binary size:

https://github.com/johnthagen/min-sized-rust

... but as you can see, it's a lot of work.

Rust gets great press and HN is flooded with "let's do it in Rust" type comments. But I think sometimes we need a reality check. Rust is an extremely different language to most others, even C. The combination of the borrow checker+everything async is not obviously better than everything else, not even in the low level domains even though Rust is deservedly picking up loyal users there. The moment you care about development speed i.e. for the sort of apps Clojure was designed for, you're going to be better off with a GC and a strong runtime that abstracts the platform well.

6MB is quite large. Makes me question if you were even building in release mode.

You may want to see https://github.com/johnthagen/min-sized-rust

It's not difficult to get binaries down into the 50KB range. And for embedded applications, less than 10KB is totally possible.

> It's a 55 MB executable. You could fit at least one hundred full blow almost self contained (CLI) text-editors with the feature-set of Lapce in that size…

Sure, why not, I've got time to waste on endless bikeshedding... :D

IMO 55MB isn't "gigantic"--a 450MB binary could rightly be called "gigantic": https://github.com/lapce/lapce/issues/24#issuecomment-100122... (But, ya know, ya don't get this here debugging info for free.)

FWIW the Linux binary I downloaded can be immediately shrunk from 57413256 bytes to 44604432 bytes (~43MB) by running `strip` on it.

I imagine further size reductions can be found by following the, by now, "standard", list of steps at https://github.com/johnthagen/min-sized-rust but for a pre-pre-alpha personal project I imagine doing so is not a high priority.

Also FWIW comparing a "self contained (CLI)" to a self-contained GUI editor seems pretty apples to oranges as comparisons go...

I will accept though a 3x multiplier on the "bloated" `emacs25-nox` (~15MB) and a 50x on the svelte `vim.tiny` (~11MB) I found installed locally. (Apparently `emacs25-x` on another machine weighs in at ~17MB so I guess that's the eventual target. :D )

My primary interest in Lapce is for editing Rust code with LSP/Rust-Analyzer support (the latter being where there's actually issues with regard to constrained development environments), I recently almost got there with the KDE Kate editor but a Rust built editor with WASM/WASI as a target for plugins seems more attractive to me going forward.

I'm not sure what flags wasm-pack uses, but you can try using opt-level=s for smaller codegen. Also lto can help.

You can take a look at cargo-bloat. It's sometimes surprising what code takes up all the space.

There are some general tips here: https://github.com/johnthagen/min-sized-rust

Is alpine really going for “small” though?

I’m not saying they’re not small and haven’t done a fantastic job, but my impression is that this is due to being mostly minimal in the default install;

The reason I say this (and I could be wrong) is because the use of musl for the libc means each binary kinda needs to include it’s own libc statically.

This must make the binaries huge!

Also, you can easily make small rust binaries, it’s Golang (of the two) that produces very large binaries.

If you just follow the first two bits of advice from: https://github.com/johnthagen/min-sized-rust you’ll reduce your binary sizes to near C++ levels.

> Rust can't count on OSes having Rust's standard library built-in, so Rust executables bundle bits of the Rust's standard library (300KB or more). Fortunately, it's a one-time overhead.

No, it's not, especially if you have multiple binaries. There are hacks, like using a multi-call single binary, (forget about file-based privilege separation), or using an unmaintained fork of cargo to build a rust toolchain capable of dynamic linking libstd. See: https://users.rust-lang.org/t/link-the-rust-standard-library... and https://github.com/johnthagen/min-sized-rust

I'd be interested in any up-to-date trick to do better than this.

It's possible to make very small Rust binaries: https://github.com/johnthagen/min-sized-rust 8kB for that Rust example, compared to 16kB for my optimized C hello world compiled with GCC. (Not that I think it makes a difference to anything.)

Furthermore, how are Rust memory allocations and layout "fairly opaque"?

Significantly bigger than the C version.

Rust: 73M source: https://packages.debian.org/experimental/rust-coreutils

C: 17M https://packages.debian.org/unstable/coreutils

Note that no size optimization that been done and there is a lot ways to do it in Rust https://github.com/johnthagen/min-sized-rust

In term of performance, well, it depends on the binary. For example for cp, most of the time is spending copying the files. For the factor command, some work happened to make it faster https://github.com/uutils/coreutils/commits/master/src/uu/fa... (getting closer).

Using Rust also opens some great capabilities like parallelism. But this makes sense only for complex commands. For example, doing a parallel "df" isn't super interesting (I tried it was too expensive just to start threads to do it).

Anyway, performances should be a focus but only after correctness is implemented.

It seems like this blog post is not very well thought out. At least the Rust version was compiled in debug mode, binaries were not stripped, the size-optimizing compiler profile was not used and neither was LTO. This repository contains information on how to achieve small Rust binaries: https://github.com/johnthagen/min-sized-rust
It's a bit unfair to use a default hello world program as an argument for why binaries are too large to use in an embedded context, because rust binaries can be made very small with tuning[1][2][3].

[1] https://www.codeslow.com/2019/12/tiny-windows-executable-in-...

[2] https://github.com/johnthagen/min-sized-rust

[3] https://rust-embedded.github.io/book/unsorted/speed-vs-size....

It may be worthwhile to point out that the example is built in debug mode, and also Rust is including the whole standard library in the output. Re-configuring some low hanging fruit [1] reduces the binary size on my test machine to 27K. This is still not small, granted.

[1] https://github.com/johnthagen/min-sized-rust

> total size of the binary

Have you researched this space already[1]? By default Rust doesn't optimize for the resulting binary size, but there are lots of things that can be done to bring size down where you'd expect.

> number of dependencies used

When this comes up it becomes as much a technical discussion as a philosophical one :)

> and compilation time.

No arguments there. There are some things that can be done in your project to avoid spending too much time (simplify bounds to minimize recalculation in the type system, avoid proc macros, leverage cfg conditional compilation), but they are work arounds.

[1]: https://github.com/johnthagen/min-sized-rust

Rust is statically linked by default, not sure how D works. Rust still includes some debug features that can give you a stack trace. Size will also depend on the compile options, if LTO was enabled, how much generics were used, how much string printing was used (print is a macro in Rust that generates code at the callsite), etc. Most, if not all, of these can be resolved.

See https://github.com/johnthagen/min-sized-rust for aiming for small binary size.

This article shows a 93% size reduction, 2.7m -> 200kb, with some relatively simple modifications https://www.collabora.com/news-and-blog/blog/2020/04/28/redu....

Here is someone using Rust for a 3kb demoscene program https://www.codeslow.com/2019/12/tiny-windows-executable-in-....

The following is a very good resource, going from safe/practical ways to reduce the size (like `strip`) to more advanced and unpractical builds (up to 8KiB hello world, removing... a lot).

https://github.com/johnthagen/min-sized-rust

No way are you fitting a normal operating system on there.

You can certainly compile rust to fit on there without any trouble though, you just have to try... the same way you have to try to compile any language in that sort of environment really. You can get to about 30kb while still keeping the standard library [1], you can get something with a fully featured web server in a few hundred kb [2].

[1] https://github.com/johnthagen/min-sized-rust

[2] https://jamesmunns.com/blog/tinyrocket/

True, fitting a game and a boot loader into 512 bytes is very impressive. You can build pretty tiny rust binaries if you don’t link the std library though. Check this out for some tricks: https://github.com/johnthagen/min-sized-rust

That blog post explains the vga buffer quite nicely so you should also be able to use the same information when writing assembler.

Have you tried making them small? Rust doesn't optimize programs for size by default, there's a lot of easy ways to shrink binaries (like stripping symbols).

https://github.com/johnthagen/min-sized-rust

Maybe rust core/std/alloc should built with many smaller crates that are cached better and have fewer dependencies?

Also: https://github.com/johnthagen/min-sized-rust

When Rust switched to the system allocator by default, that slimmed down the minimum size quite a bit. In addition to that, where size matters, there are some articles about how to slim it down even more, here's an example: https://github.com/johnthagen/min-sized-rust