[HN Gopher] Fast Rust Builds
___________________________________________________________________
Fast Rust Builds
Author : agluszak
Score : 177 points
Date : 2021-09-05 15:36 UTC (7 hours ago)
(HTM) web link (matklad.github.io)
(TXT) w3m dump (matklad.github.io)
| nextaccountic wrote:
| > If you do need generic interface for better type-safety and
| ergonomics, make sure that the interface layer is thin, and that
| it immediately delegates to a non-generic implementation. The
| classical example to internalize here are various functions from
| str::fs module which operate on paths: pub fn
| read<P: AsRef<Path>>(path: P) -> io::Result<Vec<u8>> {
| fn inner(path: &Path) -> io::Result<Vec<u8>> { let
| mut file = File::open(path)?; let mut bytes =
| Vec::new(); file.read_to_end(&mut bytes)?;
| Ok(bytes) } inner(path.as_ref()) }
|
| --
|
| Nobody seems to care, but there's a crate that does this for you
| https://github.com/llogiq/momo
|
| But the Rust compiler should be doing this automatically :(
| epage wrote:
| There is interest in making this automatic, its just not been
| the highest priority for people.
| mrec wrote:
| https://github.com/rust-lang/rust/issues/77960 I think.
| zozbot234 wrote:
| > But the Rust compiler should be doing this automatically
|
| This will become a lot easier once the actual full const-
| generics implementation lands. Because then even your "non-
| generic" implementations will be enabled to depend on compile-
| time-defined features of the instantiated type (such as size,
| alignment, value bounds etc.) without any sort of duplicate
| code generation. Of course, these in turn should delegate to
| truly non-generic code when feasible to minimize bloat.
| jstx1 wrote:
| As a side note, looking at this block of code, the syntax is
| just so ugly and overcrowded. I don't get how a relatively new
| language ended up looking so messy so fast; it's like no one
| cared about readability.
| scottlamb wrote:
| Partly personal preference in both what is readable and in
| how much you optimize caller convenience vs simple callee
| code. I think it's fine to just expect the caller to do the
| conversion. In fact, it's often automatic. (Eg if you have a
| PathBuf, then just sticking a & in front of it is sufficient
| to supply &Path via Deref<Target = Path>.) So I'd write this
| function as follows: fn read(path: &Path)
| -> io::Result<Vec<u8>> { let mut file =
| File::open(path)?; let mut bytes = Vec::new();
| file.read_to_end(&mut bytes)?; Ok(bytes)
| }
|
| which I find readable. Comparing to another language...I
| haven't written Go in a while, but I think the rough
| equivalent would be: func Read(path *Path)
| ([]byte, error) { file, err := os.Open(path)
| if err != nil { return nil, err }
| slice, err := io.ReadAll(file) if err != nil {
| return nil, err } return slice, nil
| }
|
| (Maybe in this case you'd just return the io.ReadAll rather
| than doing an if, but I'm trying to use similar constructs.
| The ? is something you can use all throughout the function,
| not just at the end, so I tried to match that pattern.)
|
| [edited: I said there wasn't a io.ReadToEnd extracted from
| io.ReadFile in Go, but jatone pointed out it's called
| io.ReadAll.]
| jatone wrote:
| bytes, err := ioutil.ReadAll("path.txt")
|
| is the golang equivalent.
| [deleted]
| steveklabnik wrote:
| To be clear you can write let bytes =
| std::fs::read("path.txt")?;
|
| If you're trying to actually do this in real code. The
| example is how you'd write this function yourself, but if
| you're just trying to Get It Done, it's significantly
| easier than the example.
| oxnrtr wrote:
| fun read(path: &Path): io.Result[Vec[UInt8] { var
| file = File.open(path).orReturnErr() var bytes =
| Vec.new() file.readToEnd(&mut
| bytes).orReturnErr() Ok(bytes) }
|
| would be good enough for me, tbh.
| yakubin wrote:
| _> File.open(path).orReturnErr()_
|
| Method syntax is reserved for functions. There are no
| method syntax macros. Since a return in a function
| terminates execution of this function, and not its
| caller, your example would not work.
| capableweb wrote:
| I don't know Rust but converting that code snippet of Go
| code you wrote to (non-idiomatic [wouldn't use upper-case
| characters, namespaces used doesn't actually exists])
| Clojure: (defn Read [path]
| (io/ReadToEnd (os/Open path)))
|
| Now that's what I call readable!
| scottlamb wrote:
| You can chain calls in Rust. If read_to_end were written
| to allocate and return a fresh Vec, you could do this:
| File::open(path)?.read_to_end()
|
| but instead read_to_end is written to take a presupplied
| Vec so the caller has the option to reduce allocations.
| brundolf wrote:
| Clojure is also a much higher-level language than Rust
| (and arguably Go too)
| tanaypingalkar wrote:
| I think rust syntax is more readable and self explains.
| Having syntax more minimal, more use of symbols, spaces and
| tab make them beautiful but they are really hard to get if it
| is written by someone else. I personally noticed it's more
| easy understand other rust project than other langs project.
| mamcx wrote:
| The syntax is ugly and can become overcrowded, but is in the
| HIGH side of readable.
|
| Compare: def read(path):
|
| What is path? Unknow. What it read? Unknow. What it return?
| Unknow pub fn read<P: AsRef<Path>>(path: P)
| -> io::Result<Vec<u8>> {
|
| What is path? Anything that can become path on the file
| system.
|
| What it read? Anything that can be pointed with that PATH
|
| What it return? Vec of bytes or a IO::Error
|
| PLUS: This code is compiled tot he exact types that call it,
| Path not allocate, the result can be cloned, the errors are
| defined in IO, ....
|
| --
|
| Rust is very readable: Almost any line tell you what is
| happening and what expect.
|
| Where it get messy is when it hide that crucial info. But is
| not many times it happens.
| nextaccountic wrote:
| The worst decision regarding Rust syntax was following C++
| syntax. Due to this, we write, in type syntax
|
| Things<Like<This, That>, That> -- as in C++
|
| Instead of a more legible (and very familiar to Rust authors)
|
| Things (Like This That) That -- as in Haskell
|
| Inherited from C++, we had also :: for namespacing (while a
| dot . could be perfectly be used for that), and tons of other
| stuff like <> for scoping generics.
|
| Without some of that we could have: pub fn
| read<P: AsRef Path>(path: P) -> io.Result (Vec u8) {
| fn inner(path: &Path) -> io.Result (Vec u8) { let
| mut file = File.open(path)?; let mut bytes =
| Vec.new(); file.read_to_end(&mut bytes)?;
| Ok(bytes) } inner(path.as_ref())
| }
|
| Perhaps it looks a little better? It looks for me, at least.
|
| For doing better than that we could drop C-like syntax
| perhaps?
|
| The trouble is that languages have a weirdness budget -
| there's a finite amount of novel stuff a language can have
| until it becomes too weird for mainstream programmers. So
| language designers have to pick their weird features
| carefully. Spending it all in novel syntax is unwise.
|
| I think that at the time the Rust pull was safety for low
| level code and, as Rust was targeted to replace some C++
| components, following C++ syntax was seen as a good idea.
| the_mitsuhiko wrote:
| What's the worst decision for you is my favorite feature of
| the language syntax for me. I find it easy to read and very
| easy to navigate in the text editor because types are
| enclosed by balanced operators that editors can easily
| highlight and jump between.
| axelf4 wrote:
| Surely mixing usage of space and parentheses for function
| application is a bad idea?
| nextaccountic wrote:
| But I'm not talking about function application - I'm
| talking about type application.
|
| The syntax of type application and function application
| is already different in rust: F<A, B> vs f(a, b).
|
| Type application even has default and named parameters!
| F<X = A, Y = B> and F<A> if B has a default.
|
| I just think this particular type-level syntax is very
| noisy, specially because types in Rust tend to be very
| nested.
| xpressvideoz wrote:
| > Rust was targeted to replace some C++ components,
| following C++ syntax was seen as a good idea.
|
| And that was a good decision. If it were too far from the
| C++ syntax, I would not have learned it, because as a
| mostly C++ guy at the time, some similarities with C++
| helped me keep interest in Rust. Also, I was unable to
| parse Haskell's "type parameters as function applications"
| syntax, which was purely confusing. The Rust syntax is an
| abomination, that's true, but it is a necessary evil.
| Zababa wrote:
| I like how the namespace and the function chaining have
| different characters. I think it makes it easier to read.
| darksaints wrote:
| Function application and type annotation both using parens
| is pretty jarring for a lot of people. I much preferred the
| proposal that would have used [] like typescript or scala.
| brundolf wrote:
| Dot syntax is used when accessing a function/property on a
| _value_ , :: is used when accessing a function/property on
| a _module or type_. I think it 's great having this visual
| distinction, especially given that you can call the same
| function in either style: let x =
| Foo::new(); x.bar(); Foo::bar(x);
| Jare wrote:
| I thought the distinction was meaningful until I worked
| in a language that used dot pervasively, and saw that it
| was totally fine.
| oconnor663 wrote:
| By comparison, near-source-compatibility with C is arguably
| the "worst" design decision that C++ made, a constant
| source of complexity and frustration, and yet the #1 reason
| behind C++'s early growth and continued success. There are
| a lot of different factors at play here.
| OJFord wrote:
| To take a guess at what you don't like, it can be
| equivalently spaced out a bit more like:
| pub fn read<P>(path: P) -> io::Result<Vec<u8>> where
| P: AsRef<Path>, {
|
| And of course if you were using a lot of u8 vec results, you
| might create a shorter alias for that.
| pcwalton wrote:
| Come on, it is definitely not the case that nobody cared
| about readability. My sleepless nights after arguments about
| syntax in 2011 and 2012 very much say otherwise.
| steveklabnik wrote:
| Or the endless arguments about await, or that time I cried
| because the discussion over what we call integers was so
| contentious. We all cared quite a bit about syntax. Heck
| that's partially why almost none of it is novel!
| matklad wrote:
| I don't think that when people say "Rust has ugly syntax"
| they mean that Rust has ugly syntax. It seems that what
| they are complaining about is actually Rust semantics,
| which needs extra syntax to express it.
|
| Blog post idea: express this snippet (with references,
| aliasing control, generics and all) in pseudo C++, Java,
| Python, etc. Then express "reading a file in gc language
| with exceptions" in pseudo Rust.
| capableweb wrote:
| It is what usually happens when you design by committee
| instead of everyone having a common understanding and working
| towards the same goal under a single person/entity.
|
| Not saying it's good or bad, just how Rust ended up where it
| is.
| pcwalton wrote:
| What Rust committee?
| capableweb wrote:
| "Design by committee" -
| https://en.wikipedia.org/wiki/Design_by_committee
|
| I disagree it's a pejorative term as Wikipedia puts it
| though. Design by committee is in many cases necessary or
| even wanted (standard bodies).
| [deleted]
| Zababa wrote:
| I find the syntax very readable. What's your problem with it?
| kbenson wrote:
| I imagine it's that there's a fairly high ratio if function
| signatures to other lines of code, and function signatures
| are particularly gnarly in rust compared to many other
| languages, at least when lifetimes are involved.
| Zababa wrote:
| I agree that I find lifetimes a bit hard to read, but
| outside of that I usually find Rust's syntax really clear
| for an algol-like. For example, they use the ML-style
| type declaration variable: type, which I find more
| readable than the C-like type variable. There's a
| different syntax for namespace and function chaining,
| which I also like.
| infogulch wrote:
| I wonder if this is a side-effect of rust function
| signatures being very _precise_ , as in the function is
| very clear about the allowable type and ownership of its
| parameters and return values, where most languages can't
| even express things at that level of precision so
| people's eyes glaze over when reading it.
| kbenson wrote:
| I imagine so. A function signature is rust encodes more
| information than a lot of other languages. From my (very)
| limited experience, without lifetimes they look fairly
| similar to C++, and then adding lifetimes just makes them
| busier and more complex, but that's because you're
| encoding additional information.
| jakobnissen wrote:
| Compare to Julia # Your big function has
| specific types function my_function(x::UInt,
| y::UInt) [ ... ] end #
| Wrapper function to minimize monomorph. cost
| my_function(x::Integer, y::Integer) = my_function(UInt(x),
| UInt(y))
| nextaccountic wrote:
| Rust need a lot of extra stuff in function signatures to
| do its magic. Julia couldn't possibly do what Rust does
| because it doesn't have enough information
| jakobnissen wrote:
| No. They didn't have to have a pub keyword, which takes
| space. They didn't have to have the ugly syntax to make
| functions generic: Julia's functions are generic without
| using those brackets. Rust didn't have to have explicitly
| needed return types, or having to have those fully
| specified.
| dthul wrote:
| Fully specified function signatures are a conscious
| decision because it allows you to type check and borrow
| check a piece of code without needing to analyze the
| bodies of other functions. I also love it as a human
| because there is no guesswork involved.
| nextaccountic wrote:
| Rust generics can be written in a more compact way,
| fn f(x: impl Test) { ... }
|
| Is basically the same as fn f<T:
| Test>(x: T) { ... }
|
| Having to annotate the return value of functions is
| partly to make sure don't break semver accidentally, but
| it also constrains type inference to a local search
| rather than global search, avoiding spooky action at
| distance (when modifying a function changes the signature
| of another function). It seems that semver hazards are
| more important in languages with static types.
|
| That pub? It's punching waaay above its weight! Having
| things private by default protects against semver hazards
| too, but it's also the major tool that enable writing
| safe code that uses unsafe { .. } blocks underneath.
| That's because a single unsafe block typically taints the
| whole module it's contained (such that even safe code
| needs a safety review). Being able to write safe
| abstractions of unsafe code is the pull of Rust so people
| need to get it right.
|
| For example, setting the field len of a Vec to a value
| larger than what's initialized in its buffer will cause
| UB when accessing that memory; if this field weren't
| private, making a safe Vec would be impossible (likewise,
| a function that could set the len to any value must be
| private, etc).
|
| So pub can only be used for things that are safe to
| export, and people should be careful with that.
|
| Here's my least favorite syntax from there: that damn
| Ok(..). Ok-wrapping sucks. There were proposals to remove
| it, but they were rejected. There's a library that
| removes it [0], and people should use it. It also makes
| the Result<..> return type implicit in the function
| signature too.
|
| [0] https://boats.gitlab.io/blog/post/failure-to-
| fehler/#but-abo...
| Zababa wrote:
| So how do you make the difference between public and
| private code without a pub keyword? And for the "explicit
| return types", I think it makes the code more readable.
| You seem to think that what is your personal preference
| (something that looks like Julia) is best practice. It's
| not, it's just a preference.
| jakobnissen wrote:
| Both Julia and Python has a concept of public and private
| code, neither have a pub keyword.
|
| I don't believe Julia or Python is "best practice" over
| Rust. I even empathize with the opinion that explicitness
| may be preferential sometimes. But you _must_ be able to
| see how Rust's syntax overload obfuscates the core
| business logic, right?
| Zababa wrote:
| The difference between pub in Rust and _/__ in Python
| isn't that big. It's like Go that uses a capital letter
| to say what code is public. There's also a difference in
| philosophy between public by default and private by
| default. All in all, it's a small detail and doesn't
| affect things.
|
| Sure, business logic is more readable in something like
| OCaml than in Rust. On the other hand, Rust isn't really
| worse than something like Java, and I like having more
| information than what you have in Python. I'll also add
| that Rust is often chosen for speed and reliability, and
| that part of that syntax is here to guarantee that. It's
| not directly business logic in the traditional sense, but
| it's something you expect from your code.
|
| All in all, Rust is still not at the level of the
| "platonic ideal for syntaxes", especially not for most of
| the code I write (business logic for web apps, which
| wouldn't need Rust's speed). Still, in the realms of
| programming languages that are used, it's one of the
| best.
| Ar-Curunir wrote:
| Those are all trade-offs. Ditching fully-specified
| function signatures makes type inference more difficult
| and results in poorer type inference errors
| Zababa wrote:
| Your comparaison isn't only about syntax, it's also about
| the presence or absence of static types.
| jakobnissen wrote:
| Those two are related, clearly. It's not that Rust has
| added words that literally do nothing. Instead, the
| designers of Rust packed all kinds of things into the
| syntax that other languages decided would cause too much
| noise. * The output type must be
| explicitly named instead of inferred * The let
| keyword for creation of variables instead of merely
| assignment * The mut keyword to distinguish between
| mutable/immutable variables * The pub keyword,
| instead of another mechanism * Semicolons needed
| after every expression
|
| And more. Again, for every one of them, you can argue
| that it's _good_ for it to be there, because it serves a
| function. But you end up with a language with a hugely
| bloated syntax where the business logic is sort of
| swamped in these accessory keywords.
| Zababa wrote:
| I don't agree that the syntax is "hugely bloated". The
| return type is part of the business logic. mut and pub
| are here to make some things explicit, so again I don't
| mind them. Rust is one of those languages that wants to
| make more things explicit because the people using it
| need those things to be explicit.
| tialaramex wrote:
| > The output type must be explicitly named instead of
| inferred
|
| That isn't syntax. It's a decision about analysis.
|
| > The pub keyword, instead of another mechanism
|
| The "other mechanisms" discussed are in fact not
| providing this feature, but pretending you needn't care,
| and I'd argue Rust shows that in fact you should care and
| pretending otherwise is a problem.
|
| > Semicolons needed after every expression
|
| On the contrary, semicolons are at the end of Rust's
| _statements_. If what you 've got is an _expression_ you
| don 't need a semicolon. For example here's how log is
| defined on an f64 (a double precision floating point
| number) pub fn log(self, base: f64) ->
| f64 { self.ln() / base.ln() }
|
| Notice there's no semicolon there because that function
| is an expression, we want the _value_ of this division as
| the result of the function.
| scrubs wrote:
| Agree.
| fmakunbound wrote:
| Regular jack-off here. It's hard enough coding in Rust as-is.
| In addition to that, I don't think I could take into
| consideration a coding style just to bring the build times
| down.
| thinkafterbef wrote:
| Awesome work!
|
| If you want to cut the CI run time even further. I'd recommend
| BuildJet for Github Action. We give you managed high-performance
| CI runners, which cuts both your CI time and price in half.
|
| We plug right into Github Actions, so it's just one line change
| in your yaml file.
|
| https://buildjet.com/for-github-actions
| smoldesu wrote:
| I'm not an expert on the language, but I see Rust's build times
| as fairly justified. Rust's focus is on execution speed and
| correctness, which means that the compiler needs to be
| _extremely_ pedantic with CPU targets to know how to optimize
| your release. Once you have a target outlined, it has to acquire
| and build the latest versions of your dependencies with the
| highest level of optimization possible for your specific
| architecture... that 's just a lot of computing, period. Caching
| is a half-solution to this as the author suggests, but frankly
| there isn't much juice left to squeeze out of the Rust fruit.
|
| Now, there are still ways to make the compiler choke: the mention
| of instantiations towards the end is a great example. But in my
| (non-professional) experience, the build times are pretty
| tolerable for what it's providing.
| Kenji wrote:
| People who complain that Rust build times are too slow are
| python and webshit cucks who have no clue about what it means
| to compile a million lines project for a particular
| architecture. They never compiled C++ projects and they have no
| clue that C++ compile times are comparable to if not slower
| than Rust compile times. Long story short: People who complain
| about Rust build times are clueless morons.
| ReactiveJelly wrote:
| The critics are right that the build times are slow even in
| debug mode, and that it's one of the most frustrating things
| about the language even for experienced users.
|
| There are some alternate codegen backends that aim to fix this
| by compiling less-optimized debug builds more quickly.
| sodality2 wrote:
| Ooh, got a link to any of those alternate backends?
| pjmlp wrote:
| For example Cranelift and using lld as linker.
|
| Also read the Bevy documentation about improving build
| times.
| rhn_mk1 wrote:
| What is the reason to downvote this?
| lostdog wrote:
| I didn't downvote it, but it feels like the parent comment is
| making excuses for rust build times being slow. As someone
| who's worked with C++, slow build times are a leech to
| productivity, and I expect new languages to have a better
| solution than "whatever."
| eminence32 wrote:
| > the build times are pretty tolerable for what it's providing.
|
| I think this is probably right, and I think just about everyone
| "tolerates" the build times (that is, I see very few people
| stop developing in rust because of the build times).
|
| But when, for example, I run `rustup update` to get a new
| nightly compiler and have to re-compile everything, it's
| annoying to have to wait 20 minutes. I'll tolerate it, and if a
| magic wand could make it instantaneous I would love that. But
| it's still annoying.
| tanaypingalkar wrote:
| I have a low spec machine but i still patiently wait for 200
| crates to download.Because it is cached. But the most
| annoying thing is that when I am using any frameworks like
| gui and game. The second compilation also takes a minute to
| start the app. I have ended up with them. :(
| dhosek wrote:
| I'm old enough that I can remember having to wait 45 minutes for
| a compile to finish and _not be able to do anything else with the
| computer_. The worst cases of this were the slow processes which
| required occasional manual intervention. Or, the situation where
| if there was an error during compilation, only the first error
| was reliably meaningful and everything after that might or might
| not be an accurate reflection of the state of the source code.
|
| It's worth noting that there's a sort of uncanny valley in the
| amount of time something takes: when it's short, it's not too big
| a deal to wait for it. When it's fairly long (and predictably
| so), it's easy enough to context switch (I used to read a lot
| waiting for compiles to finish). It's the stuff in the 5-10
| minute range that kills you.
|
| What depresses me, is that while I can now do something else in a
| different window while a process runs, the issues with errors and
| requiring interaction still persist.
| justinsaccount wrote:
| I tried again to use rust for something the other day. Just
| wanted to fetch some things via http. Nothing fancy, didn't even
| really care about the response body, just the timings.
|
| Consensus seemed to be that reqwest is the way to do this using
| rust, since the stdlib does not include an http client.
|
| Adding the dependency on reqwest tried to pull in over 100
| dependencies and after building for a while, it failed somewhere
| along the way because my rust version was too old. Now, maybe
| some of these were optional dependencies, but they all got pulled
| in automatically.
|
| so, when TFA says
|
| > Another obvious advice is to use fewer, smaller dependencies.
|
| I just went back to go, which can do the crazy obscure task of
| making an http request without requiring 100 external
| dependencies.
| SquishyPanda23 wrote:
| > Just wanted to fetch some things via http. Nothing fancy,
| didn't even really care about the response body, just the
| timings.
|
| why not bash and curl?
| justinsaccount wrote:
| Because I wanted to do other things with the timing data.
| tinco wrote:
| Why would you do it in Rust if you can do it in Go? Was
| there some realtime constraint in making the web request?
| justinsaccount wrote:
| I was prototyping something that could monitor a few api
| endpoints in parallel, collect timing stats using sqlite,
| then output a static status page, statistics and graphs.
|
| Kind of like what smokeping does, just wanted to see what
| a from-scratch implementation that did just what I needed
| might look like.
|
| Ended up being about 400 lines. Only dependencies were
| go-sqlite and go-chart.
| sodality2 wrote:
| `ureq::get("url").call().unwrap().to_string().unwrap()` with a
| stopwatch should get you where you want. Add ureq as a
| dependency, of course, but I found ureq to be better than
| reqwest with about half the dependencies.
|
| Or... `rustup update`...
| PragmaticPulp wrote:
| Those dependencies aren't recompiled every time you change
| something. They will only impact your initial build or a clean
| build on a CI/CD system.
|
| Raw dependency counts can be shocking for those coming from
| other languages where pulling in a dependency is an uncommon
| operation, but it's not a bad thing. I'd rather have my HTTP
| client library re-use popular, tested packages for things like
| decoding JSON, handling TLS, working with IP addresses, and
| other common tasks. I don't think it would be better to have
| every package roll their own versions of all of those common
| pieces.
|
| You can browse the dependencies of reqwest here:
| https://crates.io/crates/reqwest/0.11.4/dependencies
|
| Notably, several of the big dependencies are maintained by the
| same person who maintains reqwest. It's a common practice with
| Rust crates to split a project into reusable parts. Reqwest
| uses hyper (http client), http, http-body, mime, url, and
| several other crates that are owned by the person who owns the
| reqwest crate.
|
| If we instead mashed all of those dependencies together into a
| single crate it would appease the people who don't like seeing
| high dependency numbers, but it wouldn't really make the
| product any better. It would make it harder to re-use the
| individual pieces, though.
|
| > I just went back to go, which can do the crazy obscure task
| of making an http request without requiring 100 external
| dependencies.
|
| Go is famous for including HTTP utilities in the standard
| library. If I was building a simple app that made HTTP requests
| and little more, I'd probably pick Go as well. Or Python.
|
| Or you could have searched for a minimal HTTP request crate (
| https://github.com/algesten/ureq ) designed to be small instead
| of using the most full-featured crate.
|
| Or you could have searched for Rust libcurl bindings (
| https://github.com/alexcrichton/curl-rust ) to use an old
| standby.
|
| If your goal is to reach for something quick and easy with
| batteries included and minimal external dependencies, Rust is
| not a good choice. Doesn't mean Rust is "bad", but it's not the
| right tool for every simple job. You also can't just pick the
| most popular crate and assume it's exactly what you want.
| smoldesu wrote:
| > It's a common practice with Rust crates to split a project
| into reusable parts.
|
| Precisely this. Rust is not the same as Go or Java or Python:
| it's still a fairly low-level language. Standard practice is
| to build lower-level components (like http parsing and url
| crates) that are abstracted over by more 'friendly' crates
| (like reqwest). It's jarring, and certainly different from a
| lot of other languages, but it's a testament to the
| language's flexibility in my eyes.
| [deleted]
| ReactiveJelly wrote:
| Yeah Go just has those as internal dependencies in the stdlib.
|
| That _is_ the tradeoff - Rust builds up from nothing and makes
| it friction-less to add a new dependency. Go starts at a higher
| level and the friction for adding new stuff is high. And some
| of the high-level stuff, like the GC, can't be removed.
| lumost wrote:
| Rusts ability to squeeze into small footprints is a huge part
| of the appeal. I don't think that that excuses the
| exceptional difficulty of writing a web server or client in
| rust relative to other languages.
|
| How often are folks writing applications that _don't_ need to
| connect to the web these days?
| kibwen wrote:
| _> How often are folks writing applications that don't need
| to connect to the web these days? _
|
| For Go, perhaps rarely. For Rust, not needing to touch the
| web is extremely common.
|
| Let's also keep in mind that Rust's stdlib does include IP,
| TCP, and UDP.
| msbarnett wrote:
| > How often are folks writing applications that don't need
| to connect to the web these days?
|
| In Go? Rarely, I would expect. In Rust, I'd assume
| connecting to the web is the exception rather than the
| norm. Most Rust projects tend to be lower-level
| infrastructure & systems programming.
|
| This probably explains, and in turn is explained by, their
| different choices re: http in stdlib. They have much
| different aims and target use-case.
| at_compile_time wrote:
| I just tested this. It took me 43 second to build a new
| project with reqwest as a dependency. The second build took
| 0.55 seconds. If that's exceptional difficulty, I'm
| underpaid.
|
| Maybe the lesson here is to update Rust if you haven't used
| it in a while?
| wongarsu wrote:
| I didn't find writing a simple web server or client in Rust
| any harder or simpler than in e.g. Python. What is this
| exceptional difficulty we are talking about?
| Ar-Curunir wrote:
| It depends on your niche; as a person writing cryptography
| libraries in Rust, I have never needed to make a HTTP
| request.
| mseepgood wrote:
| > and the friction for adding new stuff is high
|
| Not really, it's just a 'go get'.
| mamcx wrote:
| I just wanna say why is this in Rust:
|
| Rust is a _system language_.
|
| For example, one shock is that you can't print! or dbg!
| anything (without adding Debug/Display to each type).
|
| The reasons?
|
| Where it will print in a Airpod? yeah: Rust is made to work in
| places where NOT exist a place to print to. Or where NOT exist
| a filesystem, or HTTP because not exist TCP because not exist a
| network card.
|
| So, in Rust all start in the deepest of the deepest bottom.
|
| ---
|
| I have a good metric to select frameworks/libraries:
|
| - If is too complex, NO except if is the only game on town
|
| - If have crazy deps setup (ejem: OpenSSL, bastard mess of
| dep!) NOOOOO. (except if is the only game on town)
|
| - If is too big, damm be good and solid (ej: PostgreSQL)
|
| Whatever the lang, this have served me well, and when I have
| been lazy (I get a deps to OpenSSL and waste 1 week fixing CI
| builds with it then remember this and cut that mess) the pain
| quickly fix it.
|
| So, next time you get a trouble like this (in Rust or whatever)
| ask what alternatives you can use instead!
| xcambar wrote:
| Funny thing is, Rust and JS are both given that comment.
|
| Seeing how they are different languages, there's not a single
| language feature that explains this dependency gluttony.
|
| I'd like to open up the option that it is a necessary side-
| effect of large ecosystems: more devs using the language, more
| packages published, more quality in small packages. And then,
| when building a large-ish package, it only makes sense to use
| existing packages rather than reinventing the wheel.
|
| And so, driven by nothing but good will and best practices,
| since you have a lot of prebuilt "assets" at your disposal
| ,your project ends up with 100s of deps and everybody
| complains.
| codefined wrote:
| Rust and JS both have a very small standard library. This is
| what unites them in a 'dependency hell' of having to handle
| thousands of packages for most projects.
|
| Other languages that don't face this, e.g. Python, have very
| large standard libraries which already include a dizzying
| array of features. E.g. take a look at some of the things you
| get with standard Python[0].
|
| - sqlite3 (DB-API 2.0 interface for SQLite databases)
|
| - bz2 (Support for bzip2 compression)
|
| - sunau (Read and write Sun AU files)
|
| - netrc (netrc file processing)
|
| - curses (terminal handling for character-cell displays)
|
| - mailbox (manipulate mailboxes in various formats)
|
| [0] https://docs.python.org/3/library/
| mrec wrote:
| There's a downside to Python's batteries-included approach
| though:
|
| https://leancrew.com/all-this/2012/04/where-modules-go-to-
| di...
|
| HN discussion: https://news.ycombinator.com/item?id=3913182
|
| The obvious compromise would be to let libraries bake as
| third-party projects for a good long while until there's a
| fair amount of consensus that they're the Right Thing To
| Do, _then_ pull them into the standard library. Java 's
| Joda-Time would be one example.
| smoldesu wrote:
| Oracle doesn't own Rust though, there's no real push to
| onboard these features besides the general curb-cutting
| efforts for newcomers. For the most part, 'integral'
| crates like serde and tokio have been community-managed
| without issue so far, so it doesn't make much sense to
| pull one open-source developers passion project from them
| and pass it to another.
| _tom_ wrote:
| I don't think this is a characteristic of languages or a
| large ecosystems. It's a side effect of dependency managers
| making it seem like zero cost to include another library.
| Including one dependency can end up pulling in an entire
| ecosystem of connected dependencies, when the perhaps one
| function in the original dependency.
|
| One recent build I did, a small library included a dependency
| to build its documentation. This was a full-fledged
| documentation project, which pulled in hundreds more
| dependencies.
|
| It would be interesting to see a display of "cost" in
| projects indicating how much additional dead weight each
| individual dependency pulls in. This might lead to slight
| better decisions on dependencies to choose.
| mrec wrote:
| > _It would be interesting to see a display of "cost" in
| projects_
|
| cargo-bloat is kind of along these lines, although it only
| measures the absolute size of each dependency (as opposed
| to "dead weight") and has some platform limitations.
|
| https://crates.io/crates/cargo-bloat/
| jollybean wrote:
| " it is a necessary side-effect of large ecosystems"
|
| It depends a lot.
|
| Java has a huge ecosystem, but almost all of the core
| functionality is provided for you.
|
| Like everything there's a 90/10 rule in that 90% of the
| 'things we need' really amount to only 10% of the total
| packages out there, so it actually makes sense that the
| people backing the platform provide for it.
|
| Language, compiler, debugger, documentation, tutorials,
| standard libraries etc. - it's all part of the platform.
|
| Looking at it that way, it becomes a little more obvious why
| even some cool languages don't quite breakthrough.
| xcambar wrote:
| Java is a good example.
|
| As another commenter pointed out, it may relate more to the
| size of the standard library than to the size of the
| ecosystem. Which your comment seems to emphasize as well.
| ReactiveJelly wrote:
| > when building a large-ish package, it only makes sense to
| use existing packages rather than reinventing the wheel.
|
| Yes, for instance one of `reqwest`'s dependencies is
| `base64`. We can argue both that re-inventing base64 in every
| big library is pointless, and also that a language doesn't
| need base64 in its stdlib because C and C++ don't have it.
|
| There's no right way to cut this cake - Many a language has
| included something in the standard library, and then
| struggled to fix a broken interface once everything depended
| on it. (Like JS picking UTF-16 for strings) Many a language
| has also failed to include something in the stdlib and caused
| every application to suffer and re-invent it. (Like C++ not
| really saying anything about Unicode strings, which means Qt
| and everyone else has their own little take on it.)
|
| And the suffering is only bigger if you make dependencies
| artificially hard to add.
|
| Rust's approach is more flexible, at the cost of building the
| universe from scratch every time you make a new workspace.
| Personally I don't mind it. At least it's not like the
| problems I've heard from Haskell land. Moving from futures to
| async in Rust was fairly smooth.
| tptacek wrote:
| Rust should include Base64 in the standard library, and
| languages should continue to standardize on UTF-8.
|
| Doesn't seem hard to work out.
| kibwen wrote:
| The process for proposing new modules for Rust's stdlib
| is pretty streamlined. Small API additions can be
| proposed directly via PR to rust-lang/rust, whereas large
| API additions can be brought up for discussion in rust-
| lang/rfcs. If anybody thinks that base64 deserves to be
| in Rust's stdlib, I encourage them to propose it (to my
| knowledge nobody ever has).
| burntsushi wrote:
| You're nitpicking one example. Putting base64 into std
| makes the higher level comment go from complaining about
| 100 dependencies to complaining about 99 dependencies.
|
| So maybe it's harder to work out than you think.
| tptacek wrote:
| I don't have an opinion about the broader dependency
| problem in Rust. The comment to which I responded was
| hosting an internal debate about Base64 and UTF-8. I
| think that debate is easy to resolve: use UTF-8, put
| Base64 in the stdlib. Do you disagree?
| burntsushi wrote:
| The comment you responded to was using base64 as an
| _example_. That 's why your comment is a nitpick in this
| conversation.
|
| And yeah, I doubt I would support including base64 in std
| unless there were a compelling reason to do so. I can't
| think of one.
|
| And yes, use UTF-8. Not contesting that.
| tptacek wrote:
| I guess I'd just say that the aggregation of these "keep
| base64 out of std" decisions are why every Rust thingy I
| put together ends up with a zillion dependencies. There
| might be an upside to that (I have not detected it), but
| there's an obvious downside.
|
| Rust gets a bunch of stuff right that other languages
| missed. I don't think this one of them. I think Go's
| strategy of having a pretty-ok version of most of the
| table-stakes things developers do is probably the right
| one, just like I think sum types and option/result are
| better than error types and `nil`.
|
| I share your irritation at people who drop into the
| middle of discussions like these to nitpick random
| language war arguments, but this is a thread that is
| actually about Rust dependency hell, and the comment I
| responded to, I think, sort of diagnoses why Rust has
| that "problem" (if you think it's a problem --- I do, but
| whatever).
|
| For whatever this is worth, by the way, languages that
| have Base64 in std appear to include Ruby, Javascript,
| Python, Clojure, Java, Scala, Go, Elixir, Nim, and Swift.
| OCaml, C++ and Haskell do not.
| pixel_fcker wrote:
| What's the "obvious" downside?
| tptacek wrote:
| Having to find, download, review, and build a bunch of
| extra dependencies (and surveil all the dependencies you
| _do_ explicitly want to make sure they 're not pulling in
| fucky code to do table-stakes things that the stdlib
| could just stdize.)
|
| Again: these are _downsides_ , but not _dispositions_. On
| balance there could be good reasons to have a terse,
| svelte, balletic std. I 'm just saying, there's clearly a
| downside to the decision.
| awsthro00945 wrote:
| >and also that a language doesn't need base64 in its stdlib
| because C and C++ don't have it
|
| I don't follow this logic. If we just wanted to do
| everything the way C/C++ does it, we'd be using C/C++, and
| Rust wouldn't exist.
| pjmlp wrote:
| True, although my only complain with C++ is the
| subculture that to this day pushes for C types and unsafe
| by default.
|
| For anything else I don't have any major complaint.
| secondcoming wrote:
| who is pushing for 'unsafe by default'?
| pjmlp wrote:
| Anyone that uses char * instead of std::array for
| example.
| yakubin wrote:
| _std::array_ will instantiate function templates for all
| used array sizes, lengthen compilation time, and be hard
| to use across separately-compiled code without putting
| code into headers. It has its uses, but more often I 'd
| prefer _T[N]_ with bounds-checking, and, in another
| world, a builtin variably-sized, non-resizable array
| type; basically a sort of _absl::FixedArray_ [1], but
| with the semantics of _operator[]_ and _at()_ reversed,
| so that bounds-checking is the default. Sadly, nothing
| like that is included in the standard, so won 't be a
| lingua-franca.
|
| [1]: <https://github.com/abseil/abseil-
| cpp/blob/master/absl/contai...>
| tialaramex wrote:
| The C++ Standards Committee itself.
|
| Take expected (which missed C++ 20 but may land in C++
| 23). The idea here is like Rust's Result type+, but C++
| lacks a sum type so it's instead presented a bit like a
| smart pointer. You check it for errors and then just
| dereference expected to get your answer if there weren't
| any errors. Simple. If you can't be bothered to do error-
| checking, no worries, dereferencing expected when it's an
| error throws an exception, and your usual C++ exception
| handling applies.
|
| But no, the committee says this doesn't look dangerous
| enough to us, so they _required_ it to be rewritten to
| say dereferencing expected when it 's an error is
| Undefined Behaviour instead of throwing an exception.
|
| Imagine deliberately adding more Undefined Behaviour to a
| programming language (technically in this case the
| language's standard library) in response to work to
| compete with safer languages. It's an act of self-
| sabotage without question.
|
| + Unlike exceptions, in Result your error is just more
| data, to examine, process, store and use now or later or
| not at all at your option. An exception changes control
| flow in the program when the error occurs, which may not
| be what you need at all. This is crucial to some designs.
| pjmlp wrote:
| Yeah, the "there should not exist any language underneath
| besides Assembly" motto pushed to extreme, is what might
| eventually sink all efforts to make C++ safer alternative
| than plain old C.
| tialaramex wrote:
| I don't see this part though. "Leave no room for a lower
| level language" doesn't require you to go around defining
| every mistake as Undefined Behaviour, that's crazy. A
| different part of the committee managed to see in 2021
| that if your format can be statically detected as bogus
| (e.g. you tell the formatter you're giving it a string,
| then hand over a floating point type variable) then the
| compiler should be obliged to emit a diagnostic and give
| up compiling the program, not hand you a program that it
| knows can't work and enjoy your humiliation when it fails
| in production. _That 's_ the sort of safety improvement
| you'd want to see.
|
| As I understand it the runtime performance-at-all-costs
| school, which includes people from Google, don't want the
| C++ language to be deliberately _unsafe_ they just don 't
| prioritize safety over performance. This group won't
| allow C++ to have runtime bounds checking for the array
| subscript operator or its overloaded equivalents and _I_
| think they 're wrong about that, but it's not making the
| problem _worse_. Stuff like ranges, views and iterators
| (even though C++ iterators are incredibly ugly) mean in
| idiomatic C++ today you 're rarely reaching for this
| particular gun that's supplied loaded and pointing
| directly at your feet. In contrast what was done to
| expected just seems like self-sabotage. If it's too
| _slow_ then don 't use it. Or rather, as these same
| people would be the first to point out, _measure_ to
| check your intuition that it 's too slow and only then if
| it really is don't use it.
| pjmlp wrote:
| That is exactly what I mean, the leave no language
| underneath agenda is being pushed by the performance at
| all costs crowd.
|
| In all these years I have left RTTI enabled, used
| exceptions, tried to keep bounds checking enabled in STL
| types, and it was never an issue in production.
| hardwaregeek wrote:
| Yeah in the debate about dependencies, people often frame
| it as more dependencies == bad and less dependencies ==
| good. Except more/less dependencies is actually more or
| less _explicit_ dependencies. Fact of the matter is that
| you need a crazy amount of dependencies to write most
| modern software. You need ways to handle Unicode, to
| connect to databases, to write async code, to handle dates,
| etc.
|
| The question is whether that code is going to come from a
| monolithic Swiss Army Knife of a library (aka a standard
| library), a bunch of packages, or some code that everybody
| copies into their codebase. In which case the packages
| option doesn't seem so bad. At least they're explicitly
| versioned, tracked for vulnerabilities and can be updated
| at a granular level.
| mirekrusin wrote:
| True in js/ts world this is a problem. Since couple of years
| I've been experimenting with more radical fat trimming on
| dependencies. It works very well on backend code. I belive
| shallow or no dependencies is the way to go.
|
| What seems to be missing is standard library as constellation
| of well designed modules/packages. I decided to just do it
| for myself (and anybody who finds it interesting). I don't
| think it's going to fly high but if somebody is interested
| the link is here [0]. I'm adding modules every few days.
|
| The aim is to have something worthwile to show around the
| time node v16 goes lts. I have some experience taking care of
| high stake business critical systems. This is fun side
| project as a hobby atm. Modules being dropped there are
| reflection of problems I'm facing during my day-to-day work.
|
| You'll see there some non conventional code. Large parts are
| inspired by functional programming, ocalm and simplicitly in
| general. Personally I find it exciting how well this kind of
| approach fits into production projects.
|
| The nice thing about this approach is that you can have niche
| leaf packages/modules as part of standard library
| (constellation) - if you don't want to use it, it doesn't
| matter, it wont incur any cost. For example order book module
| or exchange matching engine - those can simply live there, be
| useful to people who care and have zero impact to people who
| don't care at all. I find it to be an interesting difference
| from builtin, shipped library.
|
| Large package ecosystem is a sign of popularity. With time
| libraries should converge onto shared approaches.
| Interestingly practice shows wide spread of duplication. I
| think more effort from big players with wide reach could
| reduce it. Ie. not me doing stuff but Microsoft or others
| picking up the ball.
|
| [0] https://github.com/preludejs
| [deleted]
| batterylow wrote:
| Try ureq instead, like in this article:
| https://datacrayon.com/posts/programming/rust-notebooks/type...
| duped wrote:
| You could just use Curl bindings like you would in C or C++,
| which is a better comparison than Go.
| serverholic wrote:
| So you gave up because your rust version was too old?
|
| Dude it's like one command to update.
| GrayShade wrote:
| Not if you're using the Debian version.
|
| They could at least package rustup, I have no idea why they
| don't.
| pornel wrote:
| Debian's Rust is useless, sorry.
|
| Rust went for "evergreen" approach like Chrome. It focuses
| on making small gradual changes, and quick and painless
| upgrades. This allows everyone to only target one version:
| the current stable one. Debian's philosophy is the polar
| opposite, so Debian's Rust version is already obsolete even
| on the day of a new Debian release.
| carlmr wrote:
| >[Build time] also is a non-linear factor. Just waiting for the
| compiler is the smaller problem. The big one is losing the state
| of the flow or (worse) mental context switch to do something else
| while the code is compiling. One minute of work for the compiler
| wastes more than one minute of work for the human.
|
| This is so true, and so hard to convey to a lot of people, even
| in engineering. They like to abstract humans as machines that can
| just context switch at a whim, which is just not true.
| pjmlp wrote:
| The irony of cargo not supporting binary libraries is that the
| usual solution ends up reducing the number of dependencies, and
| being forced to rewrite ourselves the solution in another way.
| kibwen wrote:
| If you want to set up something like this for your own use,
| look into sccache. Integrating this more broadly into cargo
| would be generally pretty useless without a stable Rust ABI.
| pjmlp wrote:
| Yeah that is a possible solution, but still not quite what
| vcpkg, conan and distribution repositories offer, or having
| COM/Windows Runtime libraries.
|
| I look forward when cargo offers that as an option, doesn't
| mean everyone has to offer their libraries that way, just
| having the possibility on crates.io would be nice.
|
| I am also very thankful for what has been achieved thus far,
| so don't take this as thankless complaint rather as I would
| like Rust one day to be.
| jgavris wrote:
| I'm surprised nobody has mentioned trying out using Google's
| Bazel build system with the Rust rules. Bazel provides relatively
| straightforward 'remote caching' of build artifacts via Google
| Cloud Storage or S3.
|
| https://github.com/bazelbuild/rules_rust
| gravypod wrote:
| Another few benefits with Bazel is that your build is mostly
| hermetic and reproducible. I've never had to run `bazel clean`
| and the output sha of your builds will always be the same (good
| for signing and security). You can also use remote build
| execution (RBE) to run your builds in parallel. This makes for
| a massive performance boost when you're compiling a lot of
| libraries (packages, source files, etc).
|
| It also models your source code in your build system (exposing
| libraries, binaries, etc).
|
| I'd love to see a performance comparison with `rules_rust`.
| jgavris wrote:
| Of course, making the right abstractions and library / module
| / crate boundaries is still very much important to
| incremental build performance. For 'very large' Rust
| projects, setting up remote build execution can be hard, but
| a few of the original Bazel folks at Google are trying to
| make that easier for folks with EngFlow
| https://www.engflow.com/
| gravypod wrote:
| This space is pretty healthy right now! For an updated list
| of people in this space you can also check out:
| https://bazel.build/remote-execution-services.html
| finnb wrote:
| Engflow has some very smart people.
|
| There are also a number of other open source alternatives
| such as Buildbarn (https://github.com/buildbarn) and
| Buildfarm (https://github.com/bazelbuild/bazel-buildfarm)
| which you can host yourself.
|
| Personally, I've found Buildbarn great to throw up in
| Kubernetes and build massive projects with.
| eminence32 wrote:
| > Another obvious advice is to use fewer, smaller dependencies.
|
| As a library author, I sometimes wonder if I should be
| introducing more feature flags into my crate to let people only
| use the bits that they want, in order to help compile times. The
| whole thing doesn't take very long to compile (~20 seconds), but
| maybe the added complexity of juggling feature flags might be
| worth it.
| stormbrew wrote:
| As someone who works on a large rust codebase with a lot of
| moving parts, I'd ask you to really think hard about how your
| use of features might affect people down the line in
| undesireable ways if you go down this path.
|
| In particular, please for the love of god don't put the whole
| kitchen sink into the default feature. I'd even argue don't
| ever have a default feature at all. In practice, once a
| codebase gets above a specific size, it becomes completely
| impossible to exclude any features in a crate's default list
| because `default-features=false` only applies locally.
| Something 5 levels deep will bring those features in whether I
| like it or not just by not specifying anything.
|
| Also, please don't do things like how slog uses a feature flag
| to control minimum log levels, or k8s-openapi uses it for
| version selection. These kinds of usages create extremely
| frustrating problems.
|
| Honestly, features -- and especially the way default features
| work -- are the worst thing about cargo to me. I think they
| should be a lot more restricted than they currently are. If I
| had my way you'd only be able to use `#[cfg(feature = X)]` at
| module level to include or exclude code, never to select actual
| behaviour.
|
| To me they're filling a hole that crates themselves should be
| filling. Certain language features aren't really rich enough to
| make really effective 'additive' crates though, unfortunately.
| matklad wrote:
| > In practice, once a codebase gets above a specific size, it
| becomes completely impossible to exclude any features in a
| crate's default list because `default-features=false` only
| applies locally
|
| Curious, what that specific size approximately is? For rust-
| analyzer, getting all the deps to use features correctly is
| rather annoying, but isn't particularly time-consuming.
| dochtman wrote:
| I only use feature flags for features that require an
| additional dependency, or for features that really require a
| whole lot of extra code.
| mplanchard wrote:
| Fwiw unless the flags really represent independent bits of
| functionality, I find many features more of a pain to deal with
| than dependency compile times, given that even in our big
| workspace, a combination of incremental builds and sccache
| makes compile times mostly a non issue.
| eminence32 wrote:
| Yeah, the position you articulated is my main concern. Do you
| think it makes any differences if the features are enabled-
| by-default? If so, the "default" experience isn't any
| different than it is today, but discerning consumers can
| disable things if they need it. But also, an "everything-by-
| default" approach doesn't seem that helpful to the global
| ecosystem.
| jeroenhd wrote:
| I'm just one voice (and I'm probably not someone who uses your
| specific library), but this does sound like a good idea. I'd
| appreciate it (though I understand that this takes effort and
| maintenance, so I understand if you don't want to!)
|
| Your 20 second library is not too bad when it's used on its
| own, but add 5 or 6 libraries that all "only" take a few
| seconds and you're waiting a solid five minutes compiling other
| people's code and their dependencies.
|
| Even simple Rust programs quickly end up compiling several
| versions of several libraries because of the dependency tree,
| some of which can include large libraries like Tokio and Serde.
| I love libraries that make use of feature flags, they massively
| cut down on my compile time.
|
| This isn't really any library developers' fault, it's a problem
| with the entire ecosystem. Cargo is not dissimilar from NPM
| where you can quickly end up with an exploded dependency chain
| of hundreds of megabytes in supporting code before you even
| realize.
| edflsafoiewq wrote:
| Doesn't this basically require buy-in across the entire crate
| tree? Eg even if I disable all the default features I don't
| need, all it takes is a single crate anywhere in the dep tree
| that uses the same crate with the default features to turn them
| on again?
| nicoburns wrote:
| You think 20 seconds isn't a long compile time!?
| [deleted]
| axiosgunnar wrote:
| I don't see the problem. Since it's an external crate, it
| will compile exactly once after adding it to Cargo.toml, and
| will be cached forever.
| finnb wrote:
| Cached locally, sure. The point of bazel with remote
| execution and remote caching is that it's then available in
| the cloud for everyone to access.
| unanswered wrote:
| I'm convinced that most of the people complaining about
| build times are using docker for some incomprehensible
| reason and are blowing away the dependency cache with every
| build.
| rowanG077 wrote:
| This. It's annoying to compile from scratch. But I almost
| never have to do that. So I don't really have a problem
| with compile times.
| kzrdude wrote:
| forever, or until rust version update (might be often for
| nightly builds), or until build flag change or cargo clean,
| whichever happens first. It's also only a per-project
| target directory (not across all projects you compile).
| kibwen wrote:
| Even for people on nightly builds of the compiler, I
| would be quite surprised if nearly anyone actually
| bothered to upgrade their compiler every night. Most
| people on nightly are just going to be there for the use
| of a specific unstable feature.
| alkonaut wrote:
| It all depends on how many times you do it! 20 seconds for an
| edit-compile loop is huge. 20 seconds for a CI build is not
| as bad, but still bad (if you have dozens more).
|
| 20 seconds once per machine per dependency version (i.e.
| there is no rebuild of the dependency until you change
| compiler flags or update the library) is OK.
| jeroenhd wrote:
| This depends on what the library does, of course. From a
| quick Google I believe the parent has made several packages,
| like a front-end to help with XML trees or a full wrapper
| around procfs. Libraries that complex (especially with their
| dependencies) can take significant time to compile, it's just
| a consequence of their complexity.
|
| Some smaller libraries I've seen that just do some annoying-
| to-test but simple string manipulations have had similar
| compile times, mostly because they include specific versions
| of advanced logging or error reporting libraries for no
| obvious reason.
| eminence32 wrote:
| Yup, that's me :)
|
| For example in the `procfs` crate, there's a dependency on
| `flate2` just in case a /boot/config.gz file exists (in
| order to see what options the kernel was built with). But
| if a consumer never needs to inspect the kernel options,
| this dependency (and related code) is just dead-weight.
|
| The nice thing about rust is that this code will be removed
| from the final executable if it's unused, but maybe it's
| time to start thinking more carefully about compile times.
___________________________________________________________________
(page generated 2021-09-05 23:01 UTC)