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

On topic: I agree that upstream-provided 3rd party binaries are not a good solution to this particular problem. That is the type of solution that works in a closed environment like a corporate CI system, but it should not be the default.

Off topic: I don't understand why the article repeatedly says the Rust compiler or procedural macros are already fast, even "plenty fast". Aren't they slower or about as slow as C++, which is notorious for being frustratingly slow, especially for local, non-distributed builds?

"Plenty fast" would mean fast enough for some simple use-case. e.g., "1G ethernet is plenty fast for a home network, but data centers can definitely benefit from faster links". i.e., fast enough you won't notice anything faster when doing your average user's daily activities, but certainly not fast enough for all users or activities.

The Rust compiler is then in no way "plenty fast". It has many benefits, and lots of hard work has gone into it, even optimizing it, but everyone would notice and benefit from it being any amount faster.



> Aren't they slower or about as slow as C++, which is notorious for being frustratingly slow, especially for local, non-distributed builds?

Yes. Significantly slower. The last rust crate I pulled [0] took as long to build as the unreal engine project I work on.

[0] https://github.com/getsentry/symbolicator/


Ehhhhhhhh. Are you talking full build or incremental? How long did it take?

Clean and rebuild of Unreal Engine on my 32-core Threadripper takes about 15 minutes. And incremental change to a CPP takes… varies but probably on the order of 30 seconds. Their live coding feature is super slick.

I just cloned, downloaded dependencies, and fully built Symbolicator in 3 minutes 15 seconds. A quick incremental change and build tool 45 seconds.

My impression is the Rust time was all spent linking. Some big company desperately needs to spend the time to port Mold linker to Windows. Supposedly Microsoft is working on a faster linker. But I think it’d be better to just port Mold.


My 32 core threadripper builds ue5 in 12 minutes on Windows. Single file changes on our game are usually under 10 seconds due to unity builds, and a good precompiled header.

My first clone on symbolicator took the same length of time on my windows machine. Even with your numbers, 4 minutes to build what is not a particularly large project is bonkers. I


Sounds like we’re on basically the same page.

My experience across a wide range of C++ projects and wide range of Rust projects is that they’re roughly comparable in terms of compilation speed. Rust macros can do bad things very quickly. Same as C++ templates.

Meanwhile I have some CUDA targets that take over 5 minutes to compile a single file.

I feel like if Rust got a super fast incremental linker it’d be in a pretty decent place.


Is using a 32-core CPU as a baseline for speed comparisons some kind of satire in this thread?


No, threadrippers[0] are commonly used by people working in large compiled codebases. They're expensive, sure, but not incomparable to a top of the range Macbook Pro.

[0] https://www.cpubenchmark.net/cpu.php?cpu=AMD+Ryzen+Threadrip...


> No, threadrippers[0] are commonly used by people working in large compiled codebases.

I don't think that's true at all, unless you're using a very personal definition of "common".

In the real world, teams use compiler cache systems like ccache and distributed compilers like distcc to share the load through cheap clusters of COTS hardware or even vCPUs. But even that isn't "common".

Once you add CICD pipelines, you recognize that your claim doesn't hold water.


I know, I have one and it cost the company about 3x as much as a 16" MacBook Pro. An expense that's very unaffordable for most companies, not to mention most developers.

(Even most MBPs are unaffordable for a large set of developers.)

I don't think it's as accessible to average C++ or Rust developers as you expect.


My 3970x workstation, all in, cost about £3200.

I've also got a 14" Macbook Pro (personal machine) that was a _little_ cheaper - it was £2700.

> An expense that's very unaffordable for most companies I think it's unaffordable for some companies, but not most. If your company is paying you $60k, they can afford $3500 once every 5 years on hardware.

> I don't think it's as accessible to average C++ or Rust developers as you expect.

I never said they were accessible, just that they are widespread (as is clear from the people in this thread who have the same hardware as I do).

FWIW, I was involved in choosing the hardware for our team. We initially went with Threadrippers for engineers, but we found that in practice, a 5950x (we now use 7950x's) is _slightly_ slower for full rebuilds but _much_ faster for incremental builds which we do most of.


It’s definitely not a baseline. It’s simply what I have infront of me.

Lenovo P620 is a somewhat common machine for large studios doing Unreal development. And it just so happens that, apparently, lots of people in this thread all work somewhere that provides one.

I don’t think the story changes much for more affordable hardware.


I kind of does, given that the C and C++ culture depends heavily on binary libs (hence the usual ABI drama), in more affordable hardware building everything from source, versus using binary libraries makes a huge difference, thus C++ builds end up being quite fast unless they abuse templates (without extern template on libs).


The project itself may not be large, but if it's pulling in 517 dependencies, that's a lot to compile.

Rust also does significantly more for you at compile time than C++ does, so I don't mind the compiler taking some not time to do it


> The project itself may not be large, but if it's pulling in 517 dependencies, that's a lot to compile.

Why do you need to build hundreds of dependencies if you're not touching them?


Why do you assume they're not touching them?


Only if not taking metaprogramming and constexpr into account.


FYI Unity builds are often slower than incremental builds with proper caching.


What can I use to cache with MSVC that isn't Incredibuild? (a per-core license model isn't suitable - we'd spend more on incredibuild licenses every year than we do on hardware)

Also, I've spent a _lot_ of time with Unreal and the build system. Unreal uses an "adaptive unity" that pulls changed files out of what's compiled every time. Our incremental single file builds are sub-10-seconds most of the time.


> What can I use to cache with MSVC that isn't Incredibuild?

Ccache works, but if you use the Visual Studio C++ compiler you need to configure your build to be cacheable.

https://github.com/ccache/ccache/wiki/MS-Visual-Studio


Lack of Precompiled Header support kills this for us immediately. (We also currently use the unsupported method of debug info generation which we could change). A local build cache is no better than UnrealBuildTool's detection though.


> Lack of Precompiled Header support kills this for us immediately.

Out of curiosity, why do you use precompiled headers? I mean,the standard usecase is to improve build times, and a compiler cache already does that and leads to greater gains. Are you using precompiled headers for some other usecase?


Improved build times is _the_ reason.

> and a compiler cache already does that and leads to greater gains

Can you back that claim up? I've not benchmarked it (and I'm not making a claim either way, you are), but a build cache isn't going to be faster than an incremental build with ninja (for example), and I can use precompiled headers for our common headers to further speed up my incrementals.

You did encourage me to go back and look at sccache though, who have fixed the issues I've reported with MSVC and I'm going to give it a try this week


Mold is ELF only. They'd have to rewrite it anyway. I don't see much point in a Windows port


It’s tentatively planned for 3.0. https://github.com/bluewhalesystems/sold/issues/8

The file formats are indeed totally different. But the operation of linking is the same at a high-level.


Huh, interesting


If they ever plan supporting UNIXes like Aix, mainframes or micros, ELF isn't there as well.


Additionally, in Windows, when Rust is compiling the Microsoft's linker allays launch the M$ telemetry vctip.exe, that stablish an internet connection [Here is an icon of someone in sad thought].

If anyone knows a method for to avoid such launch (besides connection blocking after launch by firewall ), share it please.


I was curious about a couple numbers. Looks like symbolicator has about 20k lines of rust code and 517 crates it depends on (directly and indirectly).


> On topic: I agree that 3rd party binaries are not a good solution to this particular problem. That is the type of solution that works in a closed environment like a corporate CI system, but it should not be the default.

Why?

I mean, OS distributions making available whole catalogs of prebuilt binaries is a time-tested solution solution that's in place for decades. What leads you to believe that this is suddenly undesirable?


I think there's a very obvious distinction between the kind of "3rd party" that is your chosen OS distribution and the kind of 3rd party that is "some person on github or crates.io", and I didn't feel the need to clarify this as I thought it was obvious.

I've clarified it to "upstream-provided 3rd party" in the original post.


It's a 3rd party package that rustc and cargo already internally depend on themselves. If you're okay getting those distributed to you as binaries, this package too may as well come with a precompiled binary.


Either way you're running their code, I don't understand the outrage here, frankly. People who look at the code they're running and the changes they're pulling in of course noticed this, but I seriously doubt even 1% of the rageposters are in that set of rust users.


I'm not outraged. I dislike it, and it would be a "con" when considering any use of the project.

Binaries are relatively inscrutable, and there are massive differences in ease of doing something nefarious or careless with OS binaries, and upstream checked in source code, and upstream checked in binaries.

That's just one or two reasons why I think this approach is not at all commonplace in open settings, and is generally limited to closed and controlled settings like corporate environments.

A more typical and reasonable approach would be having a dependency on such a binary that you get however you like: OS, build from upstream source, upstream binary, etc., and where the default is not the latter.

And now if you allow me to get a bit off-topic again: to me, having to "innovate" like this is a major sign that this project knows it is very slow, and knows it's unlikely to ever not be very slow.


> I think there's a very obvious distinction between the kind of "3rd party" that is your chosen OS distribution and the kind of 3rd party that is "some person on github or crates.io"

That tells you more about crates.io than consuming prebuilt binaries.

Some Linux distro ship both source code packages and prebuilt binaries. This has not been a problem for the past two decades. Why is it suddenly a problem with Rust's ecosystem?


crates.io is just a platform for people to make their Rust code distributable; it's not curated in any way really (other than removing obvious malware). An OS distribution is explicitly curated.


I never saw anyone complain that crates.io isn't curated. Why is this suddenly an issue when discussing shipping prebuilt binaries? If it's somehow ok to download the source code as-is, why is it a problem if crates.io builds it for you?

Some problems have solutions, but people need to seek for solutions instead of collecting problems.


I'm not complaining that it's not curated, specifically because it's exclusively a source code package directory. Auditing source code for safety is hard, doing so with a binary is much harder.


I wouldn't mind if rust had reproducible builds, and the binaries had to be built+signed by both the original author and crates.io. But how the article describes it seems sketchy


Because it demonstrates a failure of the Rust ecosystem.

Proc macros have effectively become fundamental to Rust. This is unfortunate, but, given that it is reality, they should get compiler support. Part of what is making them so slow is that they need to process a firehose of information through a drinking straw. Placing proc macros into the compiler would not only speed them up but also remove the 50+ crate dependency chain that gets pulled in.

Serde, while slow, has a more fundamental Rust problem. Serde demonstrates that Rust needs some more abstractions that it currently does not have. The "orphan rule" means that you, dear user, cannot take my crate and Serde and compose them without a large amount of copypasta boilerplate. A better composition story would speed up the compilation of Serde as it would have to do far less work.

Rust has fundamental problems to solve, and lately only seems capable of stopgaps instead of progress. This is unfortunate as it will wind up ceding the field to something like Carbon.


> Rust has fundamental problems to solve

The orphan rule isn't a problem that needs solving, it is itself a solution to a problem. There's nothing stopping Rust from removing the orphan rule right this minute and introducing bold new problems regarding trait implementation coherence.


> The orphan rule isn't a problem that needs solving, it is itself a solution to a problem.

It is both.

The Orphan Rule was indeed chosen as a solution because other choices were dramatically more difficult to implement.

However, the Orphan Rule also has tradeoffs that make certain things problematic.

Engineering is tradeoffs. There are only two types of programming languages: those you bitch about and those you don't use. YMMV. etc.


Edward Kmett has a great explanation[1] of the considerations around this space. It's not that alternatives to the orphan rule are hard to implement, it's that they lead to things being much harder to reason about for the programmer.

[1]: https://youtube.com/watch?v=hIZxTQP1ifo


proc macros are user written code, how can you "place them into the compiler"?

What does the orphan rule have to do with the compilation speed of serde? How does it reduce the work it needs to do?


You have to pulverize the macro into syntax atoms and then reassemble it piece by piece into an AST that the compiler needs. All the processing to do all of that should be a part of the compiler--not a smattering of 50 crates (syn being the most oppressive one) and a weak compiler API.

Serde has to enumerate the universe even for types that wind up not used. Those types then need to be discarded--which is problematic if it takes a non-trivial amount of time to enumerate or construct them (say: by using proc macros). Part of this is the specification that must be done because Rust can't do compile-time reflection/introspection part of which is blocked because of the way Rust resolves types--different versions of crates wind up with different types even if the structures are structurally identical because Rust can't do compile time reflection and relies on things like the Orphan rule.

I am not saying that any of these things are easy. They are in fact hard. However, without solving them, Rust compilation times will always be garbage.

I'm beginning to think that the folks who claimed that compiler speed is the single most important design criterion were right. It seems like you can't go back and retrofit "faster compiler time" afterward.


> You have to pulverize the macro into syntax atoms and then reassemble it piece by piece into an AST that the compiler needs. All the processing to do all of that should be a part of the compiler--not a smattering of 50 crates (syn being the most oppressive one) and a weak compiler API.

First of all it's not 50 crates, it's 3 main crates syn, quote and proc-macro2 and a few smaller helper crates which are used less often.

And the reason to not include them in the compiler is exactly the same reason why "crate X" is not included in std. Stuff in std must be maintained forever without breaking changes. Just recently syn was bumped to version 2 with breaking changes which would have not been possible if it was part of the compiler.

In any case, shipping precompiled proc macros WASM binaries will solve this problem.

> Serde has to enumerate the universe even for types that wind up not used. Those types then need to be discarded--which is problematic if it takes a non-trivial amount of time to enumerate or construct them (say: by using proc macros). Part of this is the specification that must be done because Rust can't do compile-time reflection/introspection...

Yes, it's a design tradeoff, in return Rust has no post-monomorphization errors outside of compile time function evaluation. I think it's worth it.

> I'm beginning to think that the folks who claimed that compiler speed is the single most important design criterion were right.

I don't agree. As long as the compile times are reasonable (and I consider Rust compile times to be more than reasonable) other aspects of the language are more important. Compile time is a tradeoff and should be balanced against other features carefully, it's not the end goal of a language.


> First of all it's not 50 crates, it's 3 main crates syn, quote and proc-macro2 and a few smaller helper crates which are used less often.

That may be technically true. However, every time I pull in something that uses proc macros it seems my dependency count goes flying through the roof and my compile times go right out the door.

Maybe people aren't using proc macros properly. That's certainly possible. But, that also speaks to the ecosystem, as well.


> seems my dependency count goes flying through the roof and my compile times go right out the door.

I have two dependencies (memchr, urlencoding) and one two dev dependencies (libmimic, criterion). I have 77 transitive dependencies, go figure. People like to outsource stuff to other libraries, when possible.


I strongly agree with all your criticisms and factual assertions, but I think all your predictions are likely to end up being wrong.


I hope you are correct about predictions because I really want to see the day that C++ gets a spike put through it because something better exists.

I really don't want to see something like Carbon take off. It's not really that much "better" than C++, and it will take up the oxygen from something that could be a genuine replacement.


Definitely, as C++ allows using binary libraries from the get go, instead of rebuilding the world after each checkout, or clean build on the CI/CD pipeline.

There are workarounds like sccache, but again additional tooling to take into account, across all target platforms.


I think there's a different kind of "plenty fast" that more closely aligns with "as fast as it can be." If you develop some code that runs at 90% of the theoretical throughput, I'd call that plenty fast, even if the theoretical wait time was 100s of seconds. The rust compiler does a lot of stuff that simpler languages don't do. I would accept that level of checking to take longer while still being considered "plenty fast". Making that argument would require some serious benchmarking of the rust compiler though.




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

Search: