Hacker News new | ask | show | jobs
by coder543 1793 days ago
Yes, the Zig (and Go) developers have clearly put a lot of effort into ensuring the size of their toolchain remains reasonable. I fully believe the Rust developers could achieve similar results as well, if they really wanted.

Until then, the lack of a great cross compilation experience out of the box is just a limitation of the Rust toolchain. It's an acceptable limitation in many situations, but I don't buy your repeated arguments on this HN discussion that it is unclear that this is desirable to fix. Clearly many people in this discussion alone disagree with your position, and my own anecdotal discussions with other developers in real life aligns with this discussion. YMMV, obviously.

1 comments

> Yes, the Zig (and Go) developers have clearly put a lot of effort into ensuring the size of their toolchain remains reasonable. I fully believe the Rust developers could achieve similar results as well, if they really wanted.

I strongly disagree. These are different languages. Rust leans heavily on generics and monomorphization. It implements most language operations, like ptr::offset, in the language itself, increasing the size of library metadata. It supports tools like the sanitizers. It has a rich serializable MIR format so that generics can be embedded at a higher level than just machine code and a lower level than source.

It is absolutely not true that nobody "really wants" smaller binaries. Rust already did a fair bit of experimentation with running crate metadata through gzip, etc. years ago (turns out there are some thorny tradeoffs around compilation time vs. on-disk storage when you go that route). I can't speak to Zig, knowing less about it, but with Go there were conscious language design decisions that favor binary size over runtime performance (e.g. hash table lookups all going through a single function instead of being specialized). This is fine! But it's contrary to the idea that Rust could achieve smaller binary sizes if we "really" wanted to.

> Until then, the lack of a great cross compilation experience out of the box is just a limitation of the Rust toolchain.

Rust has a great cross-compilation experience. It's as simple as:

    $ rustup target add arm-linux-androideabi
    $ cargo build --target=arm-linux-androideabi
That's it. One more command than Zig or Go, to install the toolchain you need, and then you're off to the races.
The difference is really not just one command. I suggest you go out and actually try Zig cross compilation or at least read more about it. Andrew Kelley has written a lot about it. The work impressed me so much that it was one of the things that provoked me to become a financial supporter of Zig. (Even though I haven't written a line of Zig yet.)

Cross compilation in Rust is better than C or C++. But it's still a big pain.

I really think you are underestimating what the Zig folks are doing. Please investigate more deeply.

In particular: "Zig does not ship with any pre-compiled libraries; instead it ships with source code, and builds what it needs on-the-fly."

Do you think that Rust would be a better language if everything had to be compiled from source?
Obviously I don't. And that's totally consistent with learning from Zig about how to improve the cross compilation story for Rust. (Trivially: compile some things from source, but not other things.)

I'm honestly pretty disappointed at your participation in this thread. It seems like you're going out of your way to assume the worst possible interpretation of what folks are saying.

The Ultimate++ environment for C++ does the same thing with C++, and it seems to work just fine even for them.
If you use the build-std nightly feature you can compile the entire standard library, even for a custom JSON target file, and it goes pretty quick. With a bit of attention that feature would be just fine at filling in the gaps in rustup’s prebuilt targets.

But Zig’s approach isn’t actually about making everyone compile more things from scratch. It doesn’t compile libc from scratch any time you select a new target. Reading the article you can see the extreme lengths it goes to to avoid this.

The main thing that’s missing from Rust is target-specific libc.so/etc, and an appropriate linker for every target. If you try cross compiling anything, you will soon run into this problem; your system will not have the correct target libc or an appropriate linker. You can generally only change one part of the triple before the experience starts falling apart. I can cross compile for iOS/tvOS/etc on my Mac; that’s about it.

Zig manages to solve this for all its targets by pre-processing simplifications of the various libcs, which are then bundled into the Zig binary (as 3 very small files). It generates a useless but linkable .so file from the preprocessed files for any target on the fly. It gets you the correct libc headers. Then it uses LLD instead of making you hunt around on Ubuntu forum posts finding and downloading the correct GNU linker for your specific architecture. So you don’t link to a real libc, but you don’t have to compile one either. (Until you want to execute a binary with QEMU, but usually non-simulated target machines have a libc.so already.)

(Aside: Golang solves this by not depending on libc at all, by reimplementing most of it including the syscalls in Go, and I believe by using its own multi-target linker. Many pros and many cons, but an approach Google is happy to sponsor.)

If you’re saying this approach would be infeasible for Rust std/core, then yes obviously. It’s statically linked, you can’t get away with a fake .so file.

But that was never really the issue. Rustc can build std’s rlib files for any target effortlessly. And yet cross compiling is still a pretty poor experience. The state of the art for Rust developers at the moment is rust-embedded/cross, which solves the same libc+linker problem that Zig does, naively, by literally using Docker and per-target Ubuntu images to download prebuilt GCC and libc packages from Apt. Basically we can do way better than that, because Zig showed us how.

See this Dockerfile for what I mean: https://github.com/rust-embedded/cross/blob/master/docker/Do...

> That's it. One more command than Zig or Go, to install the toolchain you need, and then you're off to the races.

Except it's not the same. Zig also cross-compiles C code beautifully, and lots of Rust code depends on C libraries. That "one additional command" does not solve cross compilation to an equivalent degree as Zig.

Go code tends to avoid C because of the heavy penalty that CGo imposes, so the cross compiliation experience is usually good there, but for different reasons than Zig.