
The Rust compiler isn't slow; we are - pcr910303
https://blog.kodewerx.org/2020/06/the-rust-compiler-isnt-slow-we-are.html
======
imtringued
I seriously hope the Rust community won't get used to these slow compile times
the way the C++ community got used to it. C++ has some really big flaws that
can cause compilation time to become unbearable but for some reason boost
really loves to abuse these flawed features. Boost is almost as bad as npm.
You include a single header and then you end up including thousands of other
boost headers. When I looked at the include hierarchy of a single cpp file 99%
of the includes were from boost and maybe 30 includes were actually from the
C++ project itself. I'm sure you could cut down 80% of the compilation time
simply by removing boost and replacing it with different libraries.

I even found a reddit submission that shows how absurd boost is:
[https://www.reddit.com/r/cpp_questions/comments/2hzobl/reduc...](https://www.reddit.com/r/cpp_questions/comments/2hzobl/reducing_compile_time_should_i_drop_boost/)

~~~
fluffything
In my experience, Rust compiles orders of magnitude faster than similar C++
code for initial compiles. For incremental compiles, Rust is infinitely
faster. C++, even if you use Modules, needs to re-compile, re-instantiate, re-
check all the templates all the time. I speculate that this alone is what
probably is responsible for the largest difference in compile-times.

Comparing Rust with C here is hard. As others have mentioned, with C, you
typically only use libraries that are installed in your system. Rust does not
have a global system cache for libraries, and I don't think there is any
package manager installing pre-compiled Rust libraries, so at least for the
initial compiles, Rust needs to do much more work than C, for Rust
dependencies at least. If your Rust project only depends on C libraries, then
there is no work to be done of course.

For incremental compiles with C, it is hit or miss. If your C project is
properly "modularized" (split into a lot of small enough TUs), then when you
change a TU, C only needs to recompile that one TU. In our benchmarks, Rust is
faster for that situation, and speculating, this is because the Rust compiler
only recompiles the parts of a TU that actually changed.

In practice, however, Rust is much slower than C, because people do not write
small Rust TUs, but absurdly huge ones, at least, by C standards. A Rust TU
(crate) usually is mapped 1:1 to a C library, which often contains dozens or
hundreds of TUs. Just the cost of testing what changed in a Rust crate is
often larger than the cost of blindly recompiling the C TU that has a newer
timestamp.

If people would split Rust code like they do with C, then this wouldn't
happen. But Rust people are too optimistic in that one day the compiler will
be able to somehow auto-magically split a crate into multiple TUs as good or
even better than what people do for C manually. And do that determination +
the incremental compile faster than what takes a C compiler to blindly
recompile a tiny amount of code.

~~~
jfkebwjsbx
> Rust compiles orders of magnitude faster than similar C++ code for initial
> compiles

Please avoid misleading statements like "orders of magnitude faster". If that
were true, even super-complex projects would compile in a few seconds, given
it would be at least 100x faster than compiling C++.

> For incremental compiles, Rust is infinitely faster.

Please avoid obvious exaggerations...

Incremental compiles of C++ take as low as modular is the code. Same for Rust.
If you make huge TUs, you get huge incremental compile times.

> C++, even if you use Modules

Modules are not even used yet by any big project nor properly supported yet,
and they are not expected to speed up compilation much anyway.

> Comparing Rust with C here is hard.

It isn't hard: C can be compiled _way_ faster than either C++ or Rust because
the code and type system is much simpler.

> As others have mentioned, with C, you typically only use libraries that are
> installed in your system

C code can be anything. C++ libraries are also included with the system.

> Rust does not have a global system cache for libraries

It does have a cache per user/project/etc., which is basically the same and
without it the speed would be atrocious.

~~~
Kaze404
This type of comment is the worst. What did you add to the conversation
besides a bunch of useless "well ackshually"? If you want to respond to a
comment, respond to it in full, not only conveniently out of context
sentences.

~~~
mlthoughts2018
The comment makes good points that need to be considered and helps mitigate
the unrealistic exaggerations of the parent comment.

This does not fit the “well akshually” trope at all.

------
berkes
The article does a good job explaining why a certain project might have a long
compile time: dependencies.

But it fails to address how this compares to go or clang of gcc. It mentions
those (they take 1/5th the time to compile a similar project), then goes off
to explain how it was possible to shave over 75% off the compile time of Rust
project, but not if that same trick would shave 75% off a similar go- or c
project.

In other words: very good to show us, how, by choosing the correct
dependencies compile time decreases. But that does not prove that the Rust
compiler isn't slow.

~~~
eqvinox
> but not if that same trick would shave 75% off a similar go- or c project.

The question does apply to Go, but not C — because the way to reduce compile
time for C projects is to just not compile libraries & modules when you don't
need to. That's the return from having a stable ABI.

(C++ might be the most interesting in this regard because there's both things
- linked / ABI'd libraries as well as header-only "libraries")

[edit: "has" as in "is actually actively used" \- of course you can create
C-ABI libraries with Go and Rust too, but it's a rather rare practice]

~~~
jatone
uh what, go does exactly what you applaud C for, but better.

go is extremely aggressive about not recompiling dependencies.

you only pay a long compilation phase the first time you build something.
after that its partial compilations all the way.

~~~
eqvinox
> you only pay a long compilation phase the first time you build something

I'm referring to the fact that there is no "first time build" using a library
in C, since C libraries are installed as binaries.

------
jiripospisil
I have been tinkering with Rust lately and compile times have been an issue
since almost the beginning. After searching around for a bit, I discovered
that a significant amount of time is spent in the linker, not in the _actual_
compiler.

By switching from the default GNU gold linker to LLVM LLD, I have managed to
shave off a few seconds on every build. There's an open issue [0] about
switching to LLD. It still has some compatibility issues but it works fine on
my machine and albeit tiny project.

I would be curious to see how compile times improve for other people just by
linking with LLD. You of course need to install LLD first and then you can
tell the chain to use it:

    
    
      time RUSTFLAGS="-C link-arg=-fuse-ld=lld" cargo build
    

[0] [https://github.com/rust-lang/rust/issues/39915](https://github.com/rust-
lang/rust/issues/39915)

~~~
est31
Most of the stuff your linker has to churn through is actually debug info. If
you turn it off, you'll speed up linking whether it's with LLD, gold, or
ld.bfd. Do this in Cargo.toml:

    
    
        [profile.dev]
        debug = false

~~~
jiripospisil
Thanks, I will test it out when I get home.

~~~
jfkebwjsbx
Note that disabling debug info means way, way harder debugging!

~~~
est31
As the sibling comment says, you can always turn it back on when you want to
do debugging. Personally, I mainly do printf debugging so I don't miss it
much. Also there is the option of only turning it off for dependencies like:

    
    
        [profile.dev.package."*"]
        debug = false
    

I haven't tested how big the impact of that is, but it should be pretty large
for projects with a larger number of dependencies.

Edit: I've tested it now on cargo-udeps [1], which has a large crate graph but
only little code of its own and there is only a small difference between
turning off debuginfo for all crates vs only for dependencies, but a sizeable
improvement over compiling in debuginfo of dependencies.

[1]:
[https://gist.github.com/est31/1bb6e7d6f4be2a23701b8c7c1c678b...](https://gist.github.com/est31/1bb6e7d6f4be2a23701b8c7c1c678b6e#file-
comparison-md)

------
unnouinceput
Quote: "There is plenty of evidence that suggests rustc is slow relative to
compilers for other languages; Go can compile applications with similar
complexity in 1/5 the time, and clang or gcc can do the same for applications
written in C"

Wait until the author tries Delphi. Then will realize compile times for Go or
C are slower then a snail

~~~
brutt
Try V[0] . See [https://fast.vlang.io/](https://fast.vlang.io/) .

[0]: [https://vlang.io/](https://vlang.io/) .

~~~
unnouinceput
I have a project for a client. Nothing much, just your ordinary database
driven application, customized for his needs. I use some external libraries
from DevExpress (for showing data), from ReportBuilder (german one) to show
different reports, etc etc. All in all, since I have sources for all as well,
it's around 1 million lines of code. The application itself is just a measly
10k lines of code written by me in past month. So, when I do a "build all" in
Delphi, it will go and compile all external libraries and it shows me the
lines of code they compiled. Mind you, real lines of code, not empty lines,
and it does not include interface/types declarations, just actual code lines -
you know, the ones where you can actually put a breakpoint if you want to also
debug it. Since my style is to have for each project its own virtual machine,
this compiling runs inside the virtual machine, and the files that said
virtual machine consist of are sitting on a HDD with 5000 rpm (old cheap style
HDD, not an SDD mind you). Takes 45 seconds to do that "build all". Do you
have an equivalent V project size to tell me your compile time? For a real
application?

~~~
brutt
V at pre-alpha stage. The only real application in V is V itself. See link
above for compilation speed of V in V.

~~~
unnouinceput
So another programming language the type "dozens for a dime", that somebody in
the middle of their tenure at Uni, out of boring thought "you know what this
world is lacking? another programming language".

And after it was done you're like "hey look, V can slingshot a stone up to the
hill real fast, hence it can be really fast and really cheap to reach the moon
too". Tell you what, when you "reach the moon" using V, same as what Delphi
does it, and it's going to be faster then come and talk to me, ok?

------
g_airborne
You could say that Rusts great dependency management is both a blessing and a
problem at the same time. C programmers, often motivated by resource
constraints, are much less likely to use third party dependencies - not just
to save resources but also because it is just much harder to do it and to do
it well. They end up just rewriting the parts they need themselves. Because
those parts are likely a small subset of a full-featured library, binary size
and compile times are smaller at the expense of actual time spent writing
code.

~~~
indogooner
Also add the time maintaining that code.

~~~
sheeshkebab
Do we also need to add the time tracking down issues and dealing with all the
licensing and churn issues in mostly unstable third party rust dependencies?

~~~
coldpie
I'm about to ship my first Rust project for a client that actually cares about
licensing stuff. It's trivial to add a new line to Cargo.toml, but can you
legally redistribute it? What MIT-style copyright lines do I need to ship in
our License file? Well, let's list the project dependencies and find out how
many packages I need to go examine:

    
    
        $ ~/.cargo/bin/cargo-tree tree --no-indent | cut -f1 -d' ' | sort | uniq | wc -l
        61
    

Oi. I'm not sure this language dependency management thing is such a good
idea.

~~~
steveklabnik
You might like [https://github.com/embarkstudios/cargo-
about](https://github.com/embarkstudios/cargo-about)

~~~
coldpie
That looks fantastic, thank you.

------
flohofwoe
I had the same experience going from C++ back to C. I was surprised how fast
my C code compiled, and how small the resulting executables were, even though
I already tried to avoid the worst offenders in my C++ code.

The problem isn't that C compilers are "fast" or C++ compilers are "slow". C++
compilers are very fast, but typical C++ projects just throw way too much work
at the compiler (by having too much implementation code in headers, while C
headers are typically only declarations).

The underlying problem is that C++ makes it easy (and even encourages through
bad practices in the stdlib) to add complexity and hide it under "fancy"
interfaces, which indirectly leads to code that's slow to compile and results
in a bloated compiler output.

It's possible to create C++ projects which compile just as fast, and result in
just as small binary code as C projects (basically "embedded C++", but this
means giving up most high-level features that C++ added on top of C (such as
most of the C++ stdlib).

In short: C makes it hard to add accidental complexity under the hood, while
C++ makes it easy. Add a cargo-style dependency manager to the mix, and the
"accidental complexity" problem grows exponentially.

~~~
JoeAltmaier
Agreed. Especially the stdlib part. In embedded environments I start by
removing that. Pretty much cures the bloat issues.

------
acqq
The way I read it, the conclusion is that Rust compiler _is_ indeed slow when
there are dependencies, even as "simple" as argument parsing?

Now I would like to read why is that, and is it only about the "rebuild time"
or also about "make time", once the dependency is built and hasn't been
changed. If it's about the rebuild time, I agree that it's not important. If
it's a penalty for every use of dependency, then for my tastes it does reduce
the number of iterations one can do during the fixed development time.

~~~
vbrandl
Clap (the argument parser in discussion) does a little more: parsing to
correct types, colorful output, generation of shell completions and man pages,
fuzzy matching (did you mean X?) and so on.

That aside, I don't know why clap in particular was the problem.

~~~
astrobe_
Oh, I see. I was wondering how an argument parsing library could be as big as
a bytecode interpreter like Lua.

------
hermanradtke
I consider clap is a different type of dependency from lalrpop and regex. Clap
is part of the application interface and most likely does not change that
often. Lalrpop and regex are part of the domain logic and probably change
fairly often.

Today, we can separate a Rust application into "app" and "lib". Most of the
change would happen inside lib and app would only need to be compiled for
infrequent changes and releases. This allows one to use all the fancy features
of clap and mostly ignore the compile time cost.

It is annoying to separate a Rust application into "app" and "lib" though, so
most people do not do it. They instead opt to replace clap with gumdrop. I
think both approaches are valid.

------
fernmyth
Every time you make a compiler faster, I add extra dependencies to all of your
projects. I am Wirth’s Demon - the enforcer of Wirth’s Law!

------
zokier
To make fair comparison, you could translate C code very literally to Rust
code, not using any "advanced" features or different libs (meaning no_std).
Then you could see apples to apples how it'd compare to clang. Probably slower
still, but at least you'd know that the slowness wouldn't be due complex
generics or macros or something.

------
stephc_int13
There is an experiment that anyone interested in compiler speed and the joy of
fast iteration programming should do : trying a real fast C compiler: TCC
(from Fabrice Bellard)

On my computer, most of the time the compilation is finished before I have
time to release the return key...

And the generated code, while not highly optimized, is largely fast enough to
test/iterate.

------
mamcx
Yes.

But "we" also include the c/c++/rust developers here.

This is a puzzle that is hard to crack.

WHY "system language" developers near always produce the MOST slow languages
on earth (C, C++, Rust, ....).

And given time, CONTINUE to keep everything wrong with them?

C/C++/rust are among the slowest languages in actual use today. Is kinda
ironic them claim to build "fast" stuff and the tool, itself, is slow like
hell.

Is even more sad considering that Pascal mop the floor with everything,
decades ago, and still do.

> I believe there is more to it than that. I believe it's more of a human
> problem than an algorithmic one.

Totally. Somehow, the C/C++ mindset can't build fast languages, not matter how
many decades of wasted compile times are behind us.

Is uber funny that you read how certain dude spend A LOT of effort optimizing
his code to get a few nanoseconds here and there for the project is building,
but somehow, the same love is not give for our core tools.

Is funny that that guy is also me. I waste DAYS trying to cut the build times
of my pipeline. DAYS.

Rust is the ONLY lang in this 20 years that make me do busy work of that kind.
BTW, I have used more than other +12

\--

Before get angry, remember that Pascal, ADA, Go, exist. And them are orders of
magnitude faster than C/C++/Rust. This is not a problem of "but c/rust do that
stuff and must be slow", no... is because them, BY DESIGN, are suboptimal
tools.

\--

Then why you use rust? Because, in contrast with C/C++, at least give a lot of
extra benefits that are not present elsewhere (with the exception of ADA).

We can love AND hate something, at the same time. Funny humans.

~~~
mmm_grayons
The systems languages you reference have to do memory management by design.
It's very difficult to write a scalable, maintainable, performant operating
system or high-performance application in Pasca, ADA, or Golang. While they
are all decent, I'm referring to "low-level" as in device drivers or "high-
performance" as in game engines. Aside from some toy microcontrollers running
go or some userland fuchsia stuff, there's a reason serious stuff still uses
those languages. They're slow because they intentionally trade compile time
for run-time performance. If I write in such a language, I've got a pretty
good idea of how it will run; I don't have to worry about "Oh no, what's the
GC gonna do now."

~~~
mamcx
Pascal, ADA not have GC.

And C/C++/Rust not have GC... and still ARE slow to compile.

------
jmull
> ...this is a dissent to a common criticism that the compiler is slow. In
> this discussion, I will argue that these claims are misleading at best.

I think the author failed here.

The article shows the rust compiler is slow but you might be able to mitigate
the issue by switching to lighter-weight dependencies or removing dependencies
and instead write the parts you need yourself.

These actions are expensive in time spent, involve tradeoffs, and are
available only in some cases, so don't generally address the issue of compile
times. That is, these are potential mitigations for slow compile times.

------
bartwe
Compare this to .net and expect to reduce it by another order of magnitude

------
7532yahoogmail
I was talking to my wife about why something around the house was slow to get
done. Well, Rust wasn't having that. For a full 30-mins I was on full defense
trying to figure out how Rust got into the house. It's everywhere. And it
likes to talk! I'm gonna have to get to know it better, because it seems I
have no choice. Ok, satire out of the way, let's get to the real points.

The article was a let down at the end. Yes, less code and less dependencies
equals quicker builds. No kidding. It does not deal with Rust itself, however.

But at commercial scale this is a real concern. We're a big C++ shop ... but
for reasons that cannot be blamed solely on C++ itself, I quit C++ for the
last 18 months for GO weary of the 4-day long build times, the huge executable
sizes, and fighting the C++ compiler. The only thing worse than a C++ compiler
in a bad mood is Oracle's PL-SQL parser (dumb and silent) or when your wife is
mad at you.

Problems committed by programmers:

\- builds do not use PCH so C++ builds are indeed slow

\- very old legacy libraries have circular dependencies and sorting that out
is annoying

\- certain important, hard to avoid legacy calls hit into a library chain of
dependencies that quickly lead to very large executable sizes

\- linking depends on .a files because having tasks link .so files is
unreliable in production. Too many tasks, too many libraries, too many
versions, too many deployments just too much lead to dependency mismatches
leading to cores ... We still link archive libraries not shared but over the
last years build teams have taken making the archive files so compiling is
usually limited to app code plus whatever self-owned library code was
modified. (Not talking language or OS libraries here; that's disciplined.
Talking app libraries & tasks for which there are 10000s).

Thus on the whole we can blame the organization not C++ for not being as good
as it should at commercial level, very large scale software management.
Getting rid of legacy code or refactoring it is another weakness: for the
above reasons the effort is often big, and there's always so much new work to
do making management of resources tough.

We can blame C++ for other things however:

\- the language is far too complicated

\- the language involves some duplication of effort between headers and source
files

\- C++ inherits C's problems with #defines, macros, and other nasty things
that break builds at scale with bad things in global scope. Just having a pre-
processor is bad. C++ maybe should have been link compatible with C but it
dragged in the whole edifice. Other OOP languages were smarter.

\- C++ errors arising out of templates or certain other STL areas produce
messages which are 2K+ each. It takes time to see what the hell when wrong.
C++ often confuses you with the details. I hope GO generics does NOT do that.

\- Making code allocator aware and capable i.e. to make things behave properly
for performance, memory testing when everything should use a non-default
allocator, debugging, and so on is real effort. Memory errors are not that
easy to track down in C++ for something that _appears_ to care about safety.

\- C++ language complexity drifts into design complexity immediately. If
you're <5yrs in C++ you can't really attack a serious project without having
Meyer's C++ books side by side.

\- A lot of what makes a C++ class or method "good" i.e. narrow contract,
assertion checking, unit testing comes, if it comes at all, from the
organization's engineering culture not from C++ itself. In other languages
it's more baked into the language.

Of course GO avoids many of these problems by design to say nothing of quick
build times. But GO built on 20 years of industrial experience while others
created it along the way.

Other OOP languages may be better, but sorry the die has been cast. Ditching
C/C++ for something better will still likely need a back door to C because
there's too much of it to drop it entirely. Those working close to the kernel
will need a C backdoor as well.

