At present, cargo_src_compile calls "${CARGO} build …", and cargo_src_test calls "${CARGO} test …". This has the unfortunate consequence that compilation of unit tests is deferred until the src_test phase. If it would be acceptable for all cargo.eclass-inheriting ebuilds to have IUSE="test" RESTRICT="!test? ( test )", then cargo_src_compile could call "use test && ${CARGO} test --no-run …" to build the unit tests in the src_compile phase. At present, this is a workaround: src_compile() { cargo_src_compile use test && cargo_src_test --no-run }
Yeah, this has been a gripe of Eli for some time. It doesn't help that tests sometimes require rebuilds of crates with different features and I think sometimes may even affect the image. I think the suggested workaround / change is not unreasonable (perhaps with some eclass var to suppress it to avoid a useless USE=test in some cases) but let's see what others say.
(In reply to Sam James from comment #1) > It doesn't help that tests > sometimes require rebuilds of crates with different features and I think > sometimes may even affect the image. Indeed, sometimes building the unit tests requires rebuilding dependencies because of changed features, but as far as I have been able to discern, the rebuilt dependencies get unique build IDs, so their build artifacts do not overwrite the original (non-test) artifacts. I do not believe that building the unit tests with "${CARGO} test --no-run" affects the original build products, but I am quite inexperienced with Rust, so I may be wrong.
(In reply to Matt Whitlock from comment #2) (In the same boat as you. I meant to add a caveat that I wasn't sure if I was misremembering that latter part or not.)
(In reply to Matt Whitlock from comment #2) > (In reply to Sam James from comment #1) > > It doesn't help that tests > > sometimes require rebuilds of crates with different features and I think > > sometimes may even affect the image. > > Indeed, sometimes building the unit tests requires rebuilding dependencies > because of changed features, but as far as I have been able to discern, the > rebuilt dependencies get unique build IDs, so their build artifacts do not > overwrite the original (non-test) artifacts. I do not believe that building > the unit tests with "${CARGO} test --no-run" affects the original build > products, but I am quite inexperienced with Rust, so I may be wrong. I can confirm with extreme prejudice (because I'm very prejudiced against cargo and its insanities). I encountered this issue with dev-util/ruff originally. See for more explanation: https://gitweb.gentoo.org/repo/gentoo.git/commit/?id=f10d64828e9c33b2a1951c9a0e1fa84e4a736875 or github link as gitweb is currently down: https://github.com/gentoo/gentoo/commit/f10d64828e9c33b2a1951c9a0e1fa84e4a736875 If you run "cargo build && cargo test" the unique build IDs may theoretically help you inasmuch as intermediate artifacts are available for both the ordinary release binary and the test-instrumented binary. It unfortunately does not remotely mean that the "dobin" calls see the binary you intend to be installed. If you use cargo_src_install I believe it will go ahead and compile the binary a third time and that one will be a release binary again. Anecdotally, I believe it didn't tend to be any shorter than the original cargo_src_compile, though I have no idea why my anecdotal experiences weren't taking advantage of cached intermediate artifacts. I do know that the tests don't share any intermediate artifacts anyway, so using a separate target directory felt clean to me. cargo_src_install will recompile the executable during install anyway, technically. I have zero confidence that it reliably avoids recompiling. Certainly it depends how you pass additional arguments to cargo build, because "cargo install" recomputes all features and arguments and environment variables etc and then tries to bring the build artifacts up to date again using the new configuration. But hey, at least it will recompile the test executable with your release artifact flags. :)
(In reply to Eli Schwartz from comment #4) > If you run "cargo build && cargo test" the unique build IDs may > theoretically help you inasmuch as intermediate artifacts are available for > both the ordinary release binary and the test-instrumented binary. It > unfortunately does not remotely mean that the "dobin" calls see the binary > you intend to be installed. If you do both a 'cargo build --release' and a 'cargo test --release --no-run', then in the output directory you should find both the production binary and the test binary side by side, suffixed by unique build IDs. If you then run 'cargo test --release', Cargo should execute the test binary (without recompiling anything, although it will first check that it doesn't need to). If you do 'cargo install', Cargo should install the already-built production binary (without recompiling anything, although it will first check that it doesn't need to). "Doesn't need to" is a very brittle notion: you have to provide exactly the same Rust environment and flags, or Cargo will notice the change and will dutifully disregard the old build products and produce what you're now demanding instead. Assuming you do indeed request exactly the same build, then you should see Cargo spit out a list of all the dependencies, claiming each one is "Fresh". If you see "Dirty", then Cargo should tell you why it's dirty, such as due to changed Rust flags. > If you use cargo_src_install I believe it will go ahead and compile the > binary a third time and that one will be a release binary again. Well, "compile" in the sense that it will recheck all the dependencies. It should take less than 1 second unless something is incorrect. > Anecdotally, I believe it didn't tend to be any shorter than the original > cargo_src_compile, though I have no idea why my anecdotal experiences > weren't taking advantage of cached intermediate artifacts. Probably you didn't request *exactly* the same build product the second time. It's very fussy. > cargo_src_install will recompile the executable during install anyway, > technically. I have zero confidence that it reliably avoids recompiling. > Certainly it depends how you pass additional arguments to cargo build, > because "cargo install" recomputes all features and arguments and > environment variables etc and then tries to bring the build artifacts up to > date again using the new configuration. Quite right. I don't know of any way to tell Cargo, "Please install what you have already built, and if that's stale, then please error out and do not rebuild anything." My own anecdote, working with the Rust bits of net-p2p/core-lightning, is that I can alternately call 'cargo build --release' and 'cargo test --release --no-run', and everything is "Fresh" on the second and subsequent runs of each command; nothing gets rebuilt. When I then call 'cargo test --release', still nothing gets rebuilt, and the tests get run. If I then call 'cargo build --release' again, still everything is "Fresh" and nothing gets rebuilt. It all appears to work exactly as I would hope, but of course this is just one data point; maybe other projects misconfigure Cargo and break things.
(In reply to Sam James from comment #1) > Yeah, this has been a gripe of Eli for some time. It doesn't help that tests > sometimes require rebuilds of crates with different features and I think > sometimes may even affect the image. > > I think the suggested workaround / change is not unreasonable (perhaps with > some eclass var to suppress it to avoid a useless USE=test in some cases) > but let's see what others say. I should say: after discussing it with Eli, I'm not really sure if we want to do this or not. We don't do it for autotools (automake doesn't do it, anyway) and for Meson, I sent https://public-inbox.gentoo.org/gentoo-dev/6cef3ecbaa1909ebe9d848fa0d6ba3e9891ca7bd.1743917689.git.sam@gentoo.org/. If we want to generally try build tests in src_compile, that merits a discussion on the gentoo-dev ML and would involve changes elsewhere. Unless you can make a case for cargo being different, which I might be able to imagine given the above remarks.
If there is no prohibition against compiling and linking stuff in the src_test phase, then I'm perfectly happy to let test frameworks build whatever they need just-in-time to run their tests. I just thought that Gentoo policy requires all binaries (including unit tests) to be built in the src_compile phase and that src_test should merely execute them. Am I not wrong that nothing is supposed to be built in the src_install phase? It runs as root, not as portage, and heavyweight compilation as root doesn't give me warm fuzzies. I think the same logic does *NOT* implicitly apply to the src_test phase since it does *not* run as root. (In reply to Sam James from comment #6) > We don't do it for autotools (automake doesn't do it, anyway) Hmm, really? All the Autotools-based projects for which I've written test-enabled ebuilds had configure options to enable/disable building the tests, and the tests would then be built (or not) as a dependency of the default Make target, such that they were ready to be executed by the time that 'make check' would be run.
(In reply to Matt Whitlock from comment #7) > If there is no prohibition against compiling and linking stuff in the > src_test phase, then I'm perfectly happy to let test frameworks build > whatever they need just-in-time to run their tests. I just thought that > Gentoo policy requires all binaries (including unit tests) to be built in > the src_compile phase and that src_test should merely execute them. > > Am I not wrong that nothing is supposed to be built in the src_install > phase? It runs as root, not as portage, and heavyweight compilation as root > doesn't give me warm fuzzies. I think the same logic does *NOT* implicitly > apply to the src_test phase since it does *not* run as root. Indeed. Nothing should ever be compiled by src_install, but there's no rule against doing so in src_test. > (In reply to Sam James from comment #6) > > We don't do it for autotools (automake doesn't do it, anyway) > > Hmm, really? All the Autotools-based projects for which I've written > test-enabled ebuilds had configure options to enable/disable building the > tests, and the tests would then be built (or not) as a dependency of the > default Make target, such that they were ready to be executed by the time > that 'make check' would be run. If the test program is defined as an automated check, but not installed, it isn't guaranteed to be built when running `make all` (and not either by `make install`) but is always built as a prerequisite for `make check`. It's not strictly necessary to have a configure option to build tests, unless the tests themselves have third-party dependencies that need to be found during ./configure It is of course possible to annotate any target so that it gets built as part of `make all`, but automake doesn't force you into it. It will simply depend on how your targets are defined.
(In reply to Eli Schwartz from comment #8) > If the test program is defined as an automated check, but not installed, it > isn't guaranteed to be built when running `make all` (and not either by > `make install`) but is always built as a prerequisite for `make check`. > > It's not strictly necessary to have a configure option to build tests, > unless the tests themselves have third-party dependencies that need to be > found during ./configure Thank you. I'm sure that explains it. (In reply to Eli Schwartz from comment #8) > Indeed. Nothing should ever be compiled by src_install, but there's no rule > against doing so in src_test. Perfect. Then this bug is invalid in a good way. :)