Why is my Rust build so slow?
fasterthanli.me
fasterthanli.me
It means the complexity of the problem space is not solved by the language, and the responsibility of solving it is being passed on to the users.
You might react to this by saying that slow build times are not a big deal. That's a mistake -- iteration is key to productivity and other languages do it better.
Rust has always been marketed as a "systems programming language". C++ is Rust's closes competitor in this domain space and it suffers from terribly slow compiling as well. I would say that due to headers, massive portability baggage and a lack of a standard build system, compiling C++ is even worse. And that is a language that has been around for 30+ years.
I agree that build times are important (i.e. PR build takes us 30 minutes which is insane), but sometimes you don't really have a choice. When you do have a choice, then by all means reap the benefits of fast compilation that languages such as Go or C can offer.
That can mean avoiding templates, or (if you’re willing to do the work) using explicit instantiations in one source file only.
Use the PImpl pattern so that users of a class don’t need to know the declarations of its private members.
And whenever reasonable, design your method signatures so that objects are passed by pointer/reference — this means you can work with forward declarations instead of always having to include the full class declaration.
Do all of that only where reasonable. Small headers usually don’t matter much, and avoiding dependencies on headers that users are likely to include anyway (like <string>) doesn’t win anything either.
I use Qt, boost, lots of templates.
- clang as a compiler
- mold as a linker
- PCH (easy with cmake)
- plugin architecture for the software ; plugins are dynamic libraries when developing (everything is linked statically for releases which take of course much longer to build with lto, etc.)
- building on Linux (it's seriously slower on Windows, when using the exact same compiler on the exact same SSD)
A recent example, linkerd proxy compiled in a few minutes, while it took me hours to compile envoy proxy.
Then there are the stories in how ridiculously long it takes to build Chrome or the V8 engine. I’m really not sold that real world c(++) projects are fast to build.
Of course, such approaches lead to slower hot rebuilds. There's trade-offs worthy of a book. But the point is that C++ is only massively parallel by adding a lot of extra work.
This problem could be overcome by reducing the complexity of header files, but that's generally difficult if template-types are used. In general, the solution is to write code that's closer to C than C++ in the header files. In particular using opaque pointers to hide data.
We're actually seeing a very similiar problem in the linked article. The chief problem is monomorphization (~templates) and the solution is to use boxing (~data hiding via opaque pointers).
Also, compiling C++ is _not_ worse than compiling rust projects but again the other way around.
Although compilation times are a hog in both of these languages, it is well known that this is actually one of the biggest rust pain points.
In general, long compilation times are mostly attributed by the complexity of things (algorithms) that compilers are trying to do for you in order to produce machine code and not because there's a lack of standardized build system (a bad idea) nor because of existence of headers.
In particular, biggest "offender" in C++ compilation model is almost always due to the usage of template metaprogramming whereas in rust I'd envision it's the compile time guarantees that must be offered through mechanisms such as borrow checker and alike.
Anecdotally, the slow builds I've experienced in Rust were case sof overzealous Serialize implementation (aka, people adding Serialize to everything, just in case) or deps on large external projects (often in C++).
Coming from C++, where you either have someone who knows how to debug build times, I think the comparison with rust is unfair. cargo-timings is pretty nice and gives you a hint on what to look for.
This article actually shows debugging build times is not that hard. I did that for a personal project (which compiled part of OpenCV) and I'm certainly no ninja. I remember attempting similar tasks in C++ and getting completely lost.
OTOH debugging C++ build times is no more than recompiling your code with -ftime-trace and inspecting it with ninjatracing, which btw is a great tool.
However, getting the data as you see is not the real challenge here but in how to use this data to optimize your build pipeline while keeping the functionality and not introducing more technical burden. That is very difficult and for many projects questionable if the benefits will outweigh the total cost invested in it.
In general, long compilation times are mostly attributed by
the complexity of things (algorithms) that compilers are
trying to do for you in order to produce machine code and
not because there's a lack of standardized build system (a
bad idea) nor because of existence of headers.
that is not true - most of the project i worked for suffered from header parsing a lot - sometimes more then 50%, in 100k-1MioK lines of code projects
many C++ developer tend to think that the code generation is the time consuming part but that is less true - you will see if you start benchmarking the compilation with todays tools available in Clang and VS2019+Running the build with -ftime-trace almost always has shown in my experiments that the bottlenecks are either in exploding number of template instatiations or more often than not in linking time.
Years ago the GNAT Ada compiler authors intentionally avoided implementing precompiled headers. They instead focused on very fast lexical analysis (using a small handwritten lexer optimized for lower case letters because that was the usual case). By careful optimization of a small part of the compiler they made the recompilation of headers faster than loading a precompiled header!! More info: https://dwheeler.com/essays/make-it-simple-dewar.html
Maybe the Rust team needs to add timers to their test suite. This kind of big regression in compilation time should have been caught by the test suite.
I assure you it's not an afterthought. We track performance changes every week, going as far as reverting highly desired features to avoid regressions. The only reason we accept (small) regressions is for correctness fixes. This regression was only partly exercised by our perf test suite. That's how we grow it: see bad behaviour in the wild, add to the suite.
The source of rust compilation slowness usually boil down to excercising a part of the language that has O(n²) behaviour, like match arm evaluation, trait bound evaluation, or huge expansion due to monomorphization or macro expansion, and the resulting huge linking times from that, or the bottleneck that proc-macros introduce (they get compiled before they can get executed, only relevant on fresh compiles).
The regression was (partly) fixed by adding caching: https://github.com/rust-lang/rust/pull/90423/files and if I recall correctly was introduced by a feature change that fixed a bunch of incorrectly rejected deeply nested trait bounds.
Most time tends to be spent in LLVM. That will also go down over time as the quality of emitted LLVM IR improves due to optimizations in rustc itself.
- sccache is pretty much essential
- beefiness: GitLab’s default runners for example are way too underpowered and made our builds take like 30 minutes (as opposed to 5 on a beefy machine in CircleCI). We’re working on switching to self-hosted runners for GL
- replacing diesel with sqlx saved us a fair bit of time
- caching the cargo home can help. It wasn’t a massive gain relative to sccache, though. Similar story with caching the target directory
- lld linking was another relatively small win, but a win nonetheless
- splitting things up into smaller libraries and binaries (all in one workspace) helped us a fair bit, since building/testing some targets can now totally skip some libraries, but I imagine YMMV
Can you please clarify this point? Caching how?
In my experience, this has been the other way around. C++ gives you many tools to optimise compilation and when one one takes advantage of them (precompiled headers/shared libs/no boost, etc), the edit-compile-test cycle is fairly fast.
Rust is consistently slow to compile and not much idea of how to go about optimising compile speed.
Both languages are snails compared to Go, of-course.
This won't necessarily always be so, there's e.g. a new compiler backend called cranelift in the works, that makes compilations 30%ish faster, and in return the code isn't as optimized - which is good for a faster inner cycle.
https://pingcap.com/blog/rust-compilation-model-calamity#rus...
Only once that was worked around did they article really start having to pay attention to the code generation and linking stages, and the issues there seem to mostly be about lack of parallelism caused by the "crates" model combined with link time optimizations and incremental compiles being off by default. You don't need to make a fundamentally faster code generator that makes worse output to deal with this: the performance losses you get from parallel, incremental, and separate compilation techniques are so minimal that only the most serious C++ projects go out of their way to combine translation units and activate LTO.
fast execution, safe execution, fast compilation — choose 2.
This is a false(ish) dilema.
The problem of Rust is that is made with a C++ mindset. Is VERY hard to make compiler fast if it follow what C/C++ do (Go is the only evidence against!).
Is a death by thousands cut. The syntax is the FIRST and big one. How you chose it will impact all the pipeline. Then the rest...
But the things that make Rust safe are not that much slower. Macros, Generics, all that syntax, all that lang complexity (ie: Not just the semantics but the way is surfaced) have a bigger impact.
Some of it is the language not being designed with ease of compilation in mind, unlike let’s say, to pick an extreme example, Go. Some of it is the tooling and default settings, especially around incremental compilation, linkers etc. People are working on this, but it takes time.
But unfortunately, a lot of the problem is with the ecosystem, as hinted at in the article. There seems to be no limit to the amount of code bloat and compile time complexity that people are willing to accept to win some microbenchmarks. This includes some very popular crates with lots of dependents, like Tokio.
In the C++ world, the popular “boost” library has a similar problem, and I know shops that avoid it, or large parts of it, simply because the compile times would be unbearable. I really hope that parts of the Rust community start to make similar decisions.
But isn't this the right trade off for something like Tokio which is at the base of applications which expect to be fast? Or else those applications wouldn't bother with async runtimes and what-have-you. There's also the fact that during the dev cycle, you'll compile tokio & friends once and be done with it. And for CI pipelines, there's caching.
I'm however not a professional developer, so I'm curious if I'm missing something.
“tribal knowledge required to bypass it, so early in the the life of a programming language, is a really bad sign.”
and within a few replies we ended at (paraphrasing):
“Granted compilation time is incremental, libraries are only compiled once, debug mode is much faster, but it’s really going to be an issue with a huge project on absurdly obsolete hardware.”
As the author of a project that relies on 50+ projects with some massive dependencies (wgpu, Tokio, rayon), yes it can take a good long while to compile from scratch, but it’s not “hours”, and after first compile that’s all paid for going forward.
Honestly this all seems like grasping at one of Rust’s perceived weak points, but really there are so many better criticisms, I don’t know why compile time gets so much attention.
And long compile times kill the battery on the go, and cargo check hardly helps when writing GUI code.
The point I am making is Rust only for those with enough income to buy hardware powerful enough to have a usable workflow or for anyone regardless of what hardware they can afford?
As for coding on the go, classical desktops are a dying breed.
(Except for tokio-macros which takes a long time because it depends on syn and quote. Consider disabling it if you don't need it.)
Hopefully it's not the latter but then I wonder where the slowness comes from.
I wish that the proc_macro API from the compiler would do that instead.
To me the extra compile time makes sense when rust is showing me many unsafe coding issues that languages seem to ignore even with their strict warnings enabled.
… and I don’t get all of the complaining about rust. I’ve written code in a lot of languages and rust has its quirks too, as they all do, but I really like it!
This is a major pain. I wish it get more attention (and hopefully: How about a SINGLE way to do macros? Like zig?).
Serde is another killer on compiling speed.
error: could not compile `the_project`.
And nothing else. No hint of what the problem is.It then took me a long time to try to comment out code here and there to find out what was causing the error.
When I finally found out the problem, I took the time to fill a bug report. I don't know if anyone looked at it. https://github.com/rust-lang/rust/issues/73026
I wouldn't call that lack of output representative of the experience of using rustc though, if I'm allowed to let my pride on my work flare up a bit.
Saying in it inherited them, just proves you probably didn't use either.
While compilation times are longer than say Go, they definitely never felt too long, compared to say Java.
But your comment around errors takes the cake. Like maybe, if you use some combination of macros expansion and traits it could get confused.
But Rust errors are on par with Elm. They show the line, they show what went wrong and how to fix. This is a far cry from C++, where using even a bit of templates, results in unintelligible mess.
Woah... now I am the one who have to ask: what the hell are you on about??
I work on Rust and Java projects, if you exclude running tests, Java compiles very very fast compared to pretty much any language... Rust is a lot slower to compile even on the much smaller projects I've worked on... in this post, a very small project (I think it's like 16,000 LoC, it's mentioned in the beginning) was taking over a minute even on hot builds... To get a build to take this long in Java you would need to have several million LoC! Even if you don't use something like Gradle to cache compilation units and just compile everything from scratch with javac.
In my experience C# compiles faster, but I still agree with you on all points.
But I've got to say I'm super jealous of the level of introspection the rust compiler allows here. I'd definitely be willing to change a few C# coding patterns in code bases I maintain to benefit build times, but as is, that's a really painful trial and error process. And sometimes you get lucky finding the root cause, but if you don't... well, it's not a great experience.
Things that have like 420+ dependencies (spring boot + some other requirements). I timed the maven clean compile. And it takes around 2min.
> I don't love how the dependency graph looks
After adding this complexity to the project, yes, some of the crates are building in ~3s, if they are the only ones that needed to be rebuilt.
Meanwhile, in a Java project there is none of this artificial crate splitting. Sure, Java projects have other nonsense, but they don't force you to split up projects into tiny pieces to get decent compile times.
As to "How to fix it" however if you have lifetime confusion the error reported by the borrow checker probably isn't going to suggest refactoring your code with a design that makes sense even though that's likely the correct solution. It would be cute if the Rust compiler said "I think you want a Boxed collection of strings here to use the algorithm you're attempting, change how this is represented in all the related structs too, here's how:" but that's unrealistic and, more importantly, no other language is doing a better job here.
While Rust makes the errors themselves look easy, the right suggestion is context sensitive anyway. In my AoC solutions, unwrap() was the correct answer anywhere the problem is "I have an Option or a Result and I wish that I didn't". Because it's AoC if I'm wrong to be so cavalier I will eat a panic immediately, and I don't plan to maintain this stuff. In a real project I probably want to explicitly handle None and Error in some places, and pass on Errors in other places, even when I don't I should write an expect() in case I'm maintaining this years from now.
More likely in lifetime confusion scenarios the equivalent C++ compiles but just has mysterious crashes or bugs and the equivalent Java has runtime Null reference errors, Concurrency errors, a truly enormous memory leak, data races, other mysterious mutation bugs, or all of the above. I'll take a compile time error from the borrow checker thanks.
I think we could provide such messages in some cases. :)
For example, if you have an impl Trait return type and have multiple returned values of different types, we suggest using Box<dyn Trait> when valid. It's just a lot of work to get those in place. You're effectively implementing a language that does those things automatically, plus all the work to print out the actual diagnostic.
Complicated error messages are clearly no a common occurrence unless you rely heavily on meta-programming tricks, and that is not common in Rust, unlike C++.
So I really don’t know what you are talking about in your comment. What’s hard about this?
Do you mean 1.57?
As soon as I saw the final binary taking an ungodly amount of time I knew what it was going to be, because I hit it myself, in 1.57, using warp.
Though there are also a few separate older regressions (at least one in 1.56, though I gather somewhat less critical / troublesome).
> the knowledge required to bypass it is to just switch to the preview of the next release
Switching to the previous tends to be more reliable and a better idea, really.
Besides, for iteration people are probably in debug, not release mode, which the article mentions is initially 19s vs 2m+. As far as I can see the main conclusion seems to be that there was a compiler regression causing the issues, which is fixed in nightly.
I don't think many users would need to go through these steps to diagnose the problem beyond "wait for a newer compiler release".
In general I don't think being slightly slower in a systems language in cases where you've explicitly asked for full optimisations is that much of a problem when there are simple ways to mitigate the feedback loop (e.g. debug compilations). Would I like these things to be faster? Sure. But with the size of the rust projects I use, it's not noticeable slower than the large established C++ projects I have to deal with (that aren't tuned for compilation speed).
Edit: I realized you might have meant that debug compiles still take a long time. In that case, obviously this won't help.
I'd argue that when it comes to doing work, I only want to deep-dive into my code. Not third party libraries that "vow" to have been tested + performant, let alone the language/build tools themselves.
I suspect this only applies to an extremely small portion of real world code and projects (direct hand optimised asm, perhaps something like forth?)
As far as I am aware the only "guarantees" (interpreting "vow" to mean this) with rust are that edition-bound code will continue to compile correctly, modulo bugs which may be introduced/need fixing.
Of course, it feels like rust could do better, the reputation it has hasn't come from nowhere, but, personally, it's a far cry from e.g. the projects I work on, where we are mandated (by inter-company politics) to use a custom SCons atrocity on C++ that takes two minutes to run a no-op build.
What languages do it best?
JavaScript is a dystopia of stacked bundlers. Python dependencies and deployment is a toxic superfund wasteland.
You’re not wrong that it’s a problem. But as far as I can tell build+deployment is an unsolved problem for non-hobby projects in most, if not all, languages.
Almost Pascal levels of fast.
Super excited about 5.00 and multicore!
I get what you're saying but it applies to people who already work full time with OCaml. For guys like myself who want to periodically dip their toes and make a slow and steady progress... it makes us feel we're not welcome. (Obviously we're not owed a made bed but I'm hopeful that you get my point and you wouldn't interpret it as entitlement.)
A potential improvement: a very opinionated guide to esy, perhaps? I'd love to author such a guide one day (and would be delighted if somebody beats me to it).
Perhaps you would be best off finding a fully set-up Docker image with a working installation of OCaml/opam, and connecting VSCode to that to act as your dev environment. That's how some educators are teaching it nowadays.
After that's done I'll also document the entire thing. At that point that might make a good candidate for a blog post to enrich the OCaml ecosystem, too.
Only after that point can I play casually with it, that's true. There's always an initial ramp-up price that has to be paid and in my case that price was higher than I wanted. I'm still willing to go through it all because I absolutely love what OCaml is in every way that I've been exposed to so far (with the exception of build tooling as already said).
While I am going through this I can indeed make use of Docker images and see what they do that I failed to do before. Could be very illuminating.
That said, I don't think that the level of slowness we're talking about here is actually an intrinsic property of Rust. Specifically, I think there are a handful of strategies that would really improve things:
- For teams, dead-simple out-of-the-box sccache integration, and officially supported Terraform (etc.) projects for setting it up in your corporate cloud environment. Then your "cold" builds for a project you've never touched before could be a lot quicker.
- A set of inbuilt use-case-driven named profiles for Cargo beyond just "debug" and "release", which you could set as the default for your "debug" or "release" builds. I'm thinking things like "prioritise-runtime-performance-and-incremental-build-time" (maybe with a better name) that sets the right kinds of flags to make that work, given that all those things are achievable if you tweak flags manually.
- Using a faster linker by default, e.g. Mold. Although I don't know whether there are portability or other issues here. Maybe it could just be used where possible?
- Binary repositories. I think people are too quick to dismiss these on the grounds that different features enabled on a crate makes it produce a very different output. You could cache the three most common configurations or something.
TL;DR: I think just not a lot of time has gone into tackling this at a high level, because there have been other priorities, and there are whole lot of directions that could be explored that might make a big difference.
mold supports precisely one platform: x86_64 Linux. It also doesn't support linker scripts beyond what is necessary to link libc, and given the creator honestly suggested the suckless practice of editing and recompiling the source code as a possible replacement for them I have my doubts that it'll have a satisfactory replacement for, say, the things I'm currently doing. (Admittedly those things are in ARMv4T rather than x86_64, but still.)
If you have to use a linker script for kennel development or embedded programming, mold doesn't work for you, though.
For reasons that are not entirely elaborated in the article, the author is using release builds for local development.
I hit the same issue and worked around it the same way (boxing). My build times also went from 1-2 minutes down to a couple seconds.
Generally speaking, most of my Rust work has been reasonably fast on modern hardware. Waiting 3-5 seconds for incremental builds isn't a big deal. I've only seen the excessive compile times with cold starts or in weird edge cases like the Warp issue.
Also this is a really long article with a lot of cool tricks and interesting information. Like the author's binary crate, they might consider splitting this article apart. Or at least adding a TOC!
Still, in the end the biggest performance gain seems to have been found faaar away from LTO in this case.
ToC sounds like a good idea though
The issue with this is that the output might be parsed by downstream tools that assume a special format. They might break by a change in the output.
timings doesn't seem especially hard to stabilize; I'll take a look at it.
Third party tools might rely on the output. This is okay for things read by humans (say the error messages) but fails for things that tools are parsing, like data needed for code coverage tools. Stabilization of instrument-coverage, as proposed, is a bad idea in my opinion. I'm sad that the concerns have not been addressed: https://github.com/rust-lang/rust/pull/90132#issuecomment-94...
It depends on whether what you're stabilizing is an output format or a set of functionality. I think it's reasonable to do the latter.
(If you'd like to talk about that further, I would suggest Zulip.)
As another poster down-thread said, human output can change at any time and this shouldn't be viewed as a stability problem. And if the machine output is still in the air then maybe it pays off to branch it out in a separate flag?
Spring is one of most if not THE ubiquitous piece of Java software. All Java shop I worked for, had Spring
Comparing Spring+Java to Rust+Warp is imo fair game.
The dependency problem is a whole different issue. Hard to tackle, but it's one that must be solved.
Avoid these things and Java is extremely fast to compile
PS: Also if you are using Maven - leverage Maven Daemon.
PPS: Languages like Go are extremely fast to compile not just because the language is simpler but also because the standard library is so good and deep that deps are not needed.
Having to depend on so many third party libs is a much bigger issue for long term maintainability and security. Also the time choosing the libs is not neglectible. At work we currently developing a mid size project (CLI and HTTP API) with Go and the standard lib is simply amazing.
I want the stdlib to be as lean as possible.
Also, as you just read, crates are compilation modules, hence generally this means more crates, lead to faster compile times.
Microsoft has to ship binary libraries with build scripts to work around it,
https://github.com/microsoft/windows-rs/tree/master/.windows
Or I could put it differently and say that authors making blogposts complaining about full rebuild cycle taking staggering 2 minutes live in a pink bubble.
Everyday reality in somewhat complex industry-placed product is 10x that if you're lucky. More often than not it's few hours before you're able to build the whole thing.
2m to build a release and a few seconds to build incremental seems fine to me. Most of the time when I'm coding I just want the compiler to tell me if the syntax is wrong, and it is pretty snappy with rust.
Let's say you had a build that took 7 hours but if you took all the steps the author did, you would be able to build it in 30 minutes locally for debugging. Would that be interesting? That's about the amount of relative improvement the author saw.
Size of input varies, finding solutions to unnecessarily long compiles in rust are useful across many of them.
That's my assumption anyway because that's about what I went through, minus the blog post: had a project I was working on, at one point I noticed the clean builds were getting really long, we're talking >10mn. Initially I figured it might be Serde (as that project is really serde-heavy) and the compile time had crept up on me unnoticed, so I moved all the serialized and deserialized types in a sub-crate in case that did anything... and it did not.
Then I busted out the -Ztimings getting about the same result Lime did (ungodly amount of time spent producing the binary for no clear reason), tried fiddling with some compile-time options (went nowhere near as deep there, I looked at -Z self-profile fairly quickly IIRC), finally found the evaluate_obligation stuff. From there I didn't bust out the profiler to see what was what, instead through I don't quite remember which chain got me to issue 91598 (https://github.com/rust-lang/rust/issues/91598).
Added a follow to the issue and various PRs proposed for it, and locked the project to 1.56.
Individual files won't be faster but it's been a wonder for whole project compilations
My 2 main gripes with Bazel was that it was a pain having to rewrite the build system for all of my dependencies and that it's claim of being reproducible is weak in the sense that there are not even warnings when you use resources from the base system (eg. compilers can include files from the base system which may not be the same / exist on another) (this is a problem since I wanted to use a header from the dependency I built with Bazel and not something already on my system)
This does disable multiplex workers,.which can make it more memory intensive. Working on that.
I don't know exactly what I tried since this was maybe a year and a half ago. I tried asking on their slack, but I think I was told that it was not possible. I don't have the project around anymore to try out your suggestion.
Or even better, a massive Rust monorepo orchestrated with Bazel build?
Android uses Soong for Rust,
https://source.android.com/setup/build/rust/building-rust-mo...
While Fucshia uses GN with Rust,
https://fuchsia.dev/fuchsia-src/development/build/concepts/b...
I also like programming in Rust without a linter.
It really makes me think about what it is I'm doing. I do not have the luxury of typing something down, compiling it, and running it after every change to see: "does it work now?"
To be fair, that's only in my personal projects. I understand this is a major issue in the "ship it quickly -- everything else be damned" environment of commercial programming, where one must rely on all these aides to get something reasonably done in a reasonable amount of time.
It was a major headache when I first learned the language, because the syntax is so rigid and exacting; but it did force me to really understand the language, instead of just being able to throw shit at the wall and consult technical docs everytime I wanted to do something.
Now, I can still do the same, but that's after spending years using a particular language or ecosystem.
I wouldn't want to go back to writing code on paper without docs, but it definitely made you think differently when it came to both writing code and learning. Kind of like how when you had a question about something before the internet, you had to stew with it until you could answer it yourself, or until you met someone who could answer your question, or you did your own research. Now, I can take out my phone and answer most questions within 20 seconds.
This is different from C++ where each individual source file can be compiled in parallel, so it's something I had to re-learn.
OTOH there might be a benefit too as more code becomes re-usable in independent crates.
That's... not the same thing at all.
Rust lets you have multiple crate in a single workspace, which allows parallelising the build (because crates are the concurrency unit of building rust).
That's got nothing whatsoever to do with pulling random crates, which is a separate issue.
* Python TYPE_CHECKING https://adamj.eu/tech/2021/05/13/python-type-hints-how-to-fi...
* C/C++ header files
But regardless, there is too much Rust code in existence to change this now.
The problem in the JS ecosystem is not the number of dependencies, but the number of entities you have to trust. There is no real difference between having one big crate in a repo managed by one entity or fifteen small crates in a repo managed by one entity.
https://blog.llvm.org/2019/09/closing-gap-cross-language-lto...
Heh
Impossible to tell without knowing more. Steps to reproduce the issue would help. Just consider how TFA went through many different things to investigate.
> Does it really need to waste so much of my time to change a single byte in the output binary?
Does it actually only change a single byte in the binary? Changing a single value can cascade much further than that.
It was a rhetorical question based off my experience with rust. I was running into this issue with building a site using warp along with some other dependencies. Those projects have been deleted off my system. I am not interested in chasing down performance issues with the compiler. Remaking the site using C++ did not have me run into slow compile times. I just want to be able to quickly iterate on stuff I work on.
>Does it actually only change a single byte in the binary?
It would be possible. I could do it myself using binary ninja / ghidra. I just want to be able to iterate quickly and try out multiple different values. I understand it's not that simple of a problem, but I just want it to work else I'll gravitate to making projects in some other language.
Sounds like Go or C++, or maybe evne Zig, are good choices for you then
It is indeed very frustrating trying to play with these kind of "settings" values.
Just by having cargo support binary libraries would be an improvement for cold builds, but I understand it isn't a priority.
The Rust/WinRT folks have a big binary crate that they use to workaround Rust's compilation times, https://github.com/microsoft/windows-rs/tree/master/.windows
Very interesting that the author managed to hit a pathological case in rustc.
FWIW lots of people hit this one, because entire pretty-base libraries got impacted by the regression: it hit everything which makes significant use of deeply nested "decorator" types, like iterator, future, and stream combinators.
Lime hit it because Warp is a big, big user of large nested decorator types (its entire routing and response system is based on that), pretty much every user of Warp with more than a handful of routes in their project hit this issue.
Boxing disguises/splits the chain by taking a pointer to a trait object, which doesn't require the same depth of checks.
(This is especially important if the algorithm is superlinear, which is implied but not stated in the article.)
1. Type erasure — compiler works with a single abstract interface rather than big complex concrete types.
2. Replaces monomorphisation (a fancy word for big copy'n'paste of code for every type it's used with) with dynamic dispatch that has a single implementation for all users.
What? No. Nobody does that anymore."
Oh these Rustaceans or how they call themselves. Look at the gaming industry, if you're playing any AAA/AA game it's most likely C++, there's some market share on C# (where Unity is used), but still the whole gaming industry is C++, and it's bigger than movie/music industries combined.
So yes, people "do that", and it's not going to change anytime soon.
My solution to be able to work on a 5W Raspberry 4 is to use C (arrays for cache misses), compile with GCC to a .so and hot-deploy that into my engine.
That way I have a zero dependencies engine (only stb_ttf and kuba_zip) that compiles from scratch in 30 seconds and the game .so takes ~1 second.
I don't even have to use a build system or many cores to compile.
Simple and low power.
Downvotes without commenting, proves my point.