Re: [PATCH 1/2] cargo.eclass: for EAPI 9, ban cargo_src_install

Eli Schwartz <[email protected]> Sun, 31 May 2026 23:19:08 -0400
Newsgroups gmane.linux.gentoo.devel
Message-ID <[email protected]>
On 5/30/26 7:37 AM, moltonel 3x Combo wrote:
> On Fri, 29 May 2026 at 23:51, Eli Schwartz <[email protected]> wrote:
>> Notice how no features of a build system are present in cargo.
> 
> Not going to engage into a motivated no-true-scotsman argument.


Well, as I said,

"""
I didn't say "barely". Anyways, compare the features of an actual build
system -- like autotools, cmake, meson, scons, waf, or literally
anything else, to cargo. Notice how no features of a build system are
present in cargo.
"""

Comparing the definition of what the previous representatives of the
term mean, to what is being proposed as a new member of the family of
the term "build systems", I suppose it must surely be relevant to ask
what a "true" build system is or does.

No true scotsman, or, appeal to purity: an informal fallacy where one
modifies a prior claim in response to a counter-example by asserting the
counterexample is excluded by definition. Rather than admitting errors
or providing evidence to disprove the counterexample, the original claim
is changed by using a non-substantive modifier such as "true", "pure",
"genuine", "authentic", "real", or other similar terms.



By what definition of no true scotsman is my argument qualifying? I have
a list of criteria for what a build system can accomplish. I don't feel
like spending all my time debating it with you, so I invited you to go
ahead and read the user manual for some of them, and then compare them
to cargo. My *assertion* is that cargo lacks these preexisting features,
and therefore doesn't qualify. I'm not retroactively adding new
qualifications, I simply didn't happen to provide a bulleted list of my
initial qualifications.

I haven't said cargo cannot qualify because it does something wrong, or
unfaithful, and therefore "no matter what it gets right we won't count
it". Like the original concept namer, I am not saying "no true scotsman
would put sugar on his porridge, that's heretical", I am saying "in
order to claim to be a true scotsman it would be beneficial to claim
some qualifications that scottish people have, whereas you're not a
scotsman in the first place -- you were never born or lived there --
therefore you cannot be a true or false one".

You are welcome to your opinion but I am the upstream maintainer of a
build system, and a passionate hater of multiple other build systems,
and I don't claim the things I hate are "not true build systems", I just
think they are impure and inferior products people shouldn't use. And
I'll happily own up to that, and to the fact that it's a personal
opinion. Nobody should ever use scons or waf.

I claim that cargo isn't a build system because I don't think it is one
in the first place -- not because I don't think it's a good one.


>> Clearly, rust (users?) think so. Although that's not actually true.
>> Compiling different feature gates for your test program compared to what
>> you install is not actually how normal, sane testing works.
> 
> IMHO cargo does the right thing here. So call me insane, but I assure you I've
> seen that particular insanity in a lot of projects, it's not a Rust
> exclusive. There
> are good technical reasons to not want your test executable to be the same as
> your release one.


See, I also think that your test executables shouldn't be your end
product either.

I had originally thought that I'd successfully made that point via the
following parts of my email -- that you omitted in your reply:


"""
In other languages and other build systems, the build and install of
production software is part of the same build configuration and artifact
directory that also produces unittest executables. This works in other
languages because other languages are capable of shared libraries,
whereas rust is only capable of repr(C) -- crABI seems to be roundly
ignored, who knows if we will ever get it.

But maybe I could even accept instrumented executables if they had the
same runtime documented behavior, but apparently that is too high a bar
for rust, which fails this. So, I stand by my criticism.
"""


And there you have it! Libraries are good -- libraries provide a
distributable thing you can push to production, which is NOT your test
program. Your test program is designed to test the behavior of your
library -- therefore putting behavior in libraries linked to executables
allows you to divorce the concerns of runtime behavior from test
behavior. You test what you distribute, but what you distribute isn't
the test instrumentation itself.

You have a *programmatic guarantee* that the thing you are testing is
the actual honest to goodness bytes you put into production. There is no
mechanism by which it is possible for the test results to be
"inapplicable because the production code turned out to be compiled with
different optimization levels resulting in a bug", let alone
"inapplicable because the production code turned out to have different
build features enabled resulting in an Interaction™ occurring". This is
what peace of mind looks like.

Of course end to end testing is important as well. But those too, assume
that the test run is testing the production deliverables, not a
test-only executable that is also executed by the end-to-end tester tool
(and I will admit here that I don't know enough about rust's support for
end to end testing to know if that is a real issue, but I can definitely
say I don't have high hopes).


>> It ***matters*** to me, that src_compile, src_test, and src_install
>> ***all*** rebuild the software from scratch, and "don't respect
>> incremental builds or caching intermediate outputs".
>>
>> In the context of an ebuild, I should not have to build the software
>> twice, I shouldn't be ***executing a compiler*** during src_install (at
>> all -- this should be an automatic QA infraction), and I shouldn't have
>> to do it three times if FEATURES=test is active.
> 
> Leaving src_test aside (as explained above, and no amount of ebuild tweaking
> will change such a language fundamental).


But it should not be a language fundamental that building test
instrumented binaries causes a recompilation of crates that aren't under
test.

And I also don't see why it makes sense for it to be a language
fundamental to cause building instrumented binaries to wipe out the
non-instrumented binaries. In fact, I assert that it isn't a language
fundamental. It may be a cargo fundamental, but that's not a language
fundamental.

As I observed earlier with regard to "things that are actually a build
system":

"the build and install of production software is part of the same build
configuration and artifact directory that also produces unittest
executables"

But cargo is stateless and doesn't produce a build configuration at all,
let alone the ability to build a collection of shared sources, some of
which are linked into a production executable with one main() and also
into a test executable with a different main(). So it's a moot point.


> I agree that there shouldn't be any recompilation between src_compile
> and src_install,
> and that something is wrong with the ebuild otherwise. But I don't
> think avoiding
> `cargo install` in favor of doexec is the right fix, `cargo install`
> is perfectly able to reuse
> the artifacts from a `cargo build`.
> 
> I have never seen the rebuilds you are talking about. Can you point at
> a particular ebuild
> or bug number ? It'd help understand the problem and get a proper fix


And yet, I've seen it and assert it happens, and I don't really care
what you have to say about it. Other devs have seen it happen too. I
don't believe you can fix it, nor propose to fix it, because it is
fundamentally tied to cargo's failure to be a build system.

The biggest problem isn't even the fact that it happens, it is the fact
that it *can* happen and therefore even if there was a way to avoid it,
if the way to avoid it isn't guaranteed to work then the existence of
cargo_src_install constitutes a "tempting footgun" to get it wrong, and
should be removed.

There is nothing wrong with any ebuild, there is something wrong with
cargo and I see no reason to cater to it.


>> This is not about ccache comparisons, so if you somehow got that idea
>> then I do not know where you got it from, but please put it back again.
> 
> I think I got confused when you talked about incremental builds, which
> to me is about fast
> recompile after changing a line of code, and not something an ebuild
> should care about.
> Also, in my experience cargo should be good at reusing intermediate
> artifacts between ebuild
> phases, adding to the confusion.


If nothing has changed, nothing should need to be redone, of course. But
if something has changed, and you hash outputs anyway, and don't have a
concept of persistent state ("build configuration", as the build systems
might call it), and target directories can potentially grow unbounded,
then it seems a bit poor to me that changing back to your original code
doesn't rebuild incrementally what has already been built. And poor
design, if there's no way to test software without destroying all
progress on building the untested stuff.

In dev-util/ruff, I coped with this by having src_test simply run in a
different target dir.


>> ... so I am correct that it isn't doing something useful, then?
> 
> ???? Have fun reimplementing what cargo does in a different build system.


It is *genuinely* funny you say this, since outside of Gentoo I am
literally a maintainer of the Meson Build System and we are literally
reimplementing what cargo does in Meson, using only rustc and not
calling into cargo. (Although we do parse Cargo.toml, and reimplement
that too!)

QEMU, Mesa, gnome, gstreamer are all stakeholders in this by the way.
There is major interest in using the rust programming language and
utilizing crates from crates.io but not using the cargo program.

Did I mention that Meson's support for unittests allows producing two
executables (one an instrumented test binary, one a regular production
binary), at the same time? With different executable names, built at the
same time into the same ${BUILD_DIR}, and which link to the same
dependency crates, so you aren't doing anything twice other than
compiling the files containing the unittests (which are of course also
the files which contain production code, so no working around that if
you are using #[cfg(test)] but that's a project local decision
ultimately, and you aren't forced to use it if you'd rather use other
testing frameworks).

I'm okay with the idea that disliking cargo means committing to the bit
and reimplementing most of cargo from scratch in another program. We are
committing to the bit and reimplementing most of cargo from scratch in
another program.


> Again, if src_install recompiles stuff from src_compile, it's a bug.
> But it's not something
> inherently caused by `cargo install`. If something in the cargo eclass
> is buggy, let's
> fix it. But it would be a pity to lose the convenience of cargo_src_install.


It is *one line* to run doexe / dobin, what is this great insurmountable
inconvenience.

I don't understand the heavy resistance to simply doing what loads of
other packages need to do -- manually install files via one or two lines
in src_install() if the project doesn't have a reliable build system to
do it for you -- just because cargo.eclass used to provide a footgun and
it is being "taken away".

The base state for all ebuilds is that anything with a ./configure
script and a Makefile can/has fully automatic handling and is expected
to be reliable modulo overriding src_configure to pass suitable options.

Anything else is an unexpected gift not guaranteed by the package
manager specification, available as repository/eclass policy and also
expected to be reliable, which is manifestly not the case if you have to
provide any src_install at all. And lots of cargo.eclass packages
already need a src_install, in fact I'd go so far as to say the natural
state of cargo-using packages today looks like this:


src_install() {
    cargo_src_install
    dodir /usr/sbin
    mv "${ED}"/usr/{,s}bin/yaskkserv2 || die
    rm "${ED}"/usr/bin/test_wrapper || die
}

???

or

src_install() {
    cargo_src_install

    dobashcomp completions/bash/${PN}
    dozshcomp completions/zsh/_${PN}
    doman man/${PN}.1

    dodoc examples/*

    systemd_dounit ${PN}.service
    newinitd "${FILESDIR}"/${PN}.initd ${PN}
    newconfd "${FILESDIR}"/${PN}.confd ${PN}

    udev_dorules 90-${PN}-backlight.rules

    insinto /usr/share/${P}
    doins -r themes
    insinto /etc/xdg/autostart
    doins xdg/${PN}.desktop
}


Or perhaps someone can explain the tempting footgun that "having
cargo_src_install" has produced in nushell:

src_install() {
        cargo_src_install
        if use plugins ; then
                # Clear features to compile plugins
                local myfeatures=()
                cargo_src_configure

                cargo_src_install --path crates/nu_plugin_custom_values
                cargo_src_install --path crates/nu_plugin_example
                cargo_src_install --path crates/nu_plugin_formats
                cargo_src_install --path crates/nu_plugin_gstat
                cargo_src_install --path crates/nu_plugin_inc
                cargo_src_install --path crates/nu_plugin_polars
                cargo_src_install --path crates/nu_plugin_query
                cargo_src_install --path crates/nu_plugin_stress_internals
        fi
        local DOCS=( README.md )
        einstalldocs
}

(which I note apparently cannot just handle all plugins in one go, even
outside of the fact that evidently "compile in src_install" is being
taken to excess. Seriously -- what is this package doing???)

Somehow replacing the line "cargo_src_install" with, for the 90% cases,
just "dobin $(cargo_target_dir)/${PN}" is such an insurmountable
maintenance burden? There was practically no convenience in the first
place, and at least now you know you're expected to tastefully think
about what files to install.

I assert that cargo software has no sense of consistency from package to
package and we cannot pretend there is a turnkey process suitable for an
eclass src_install. We are doing a disservice to users to pretend there
is one.


>> Clearly it is doing something else, given it *recompiles* in src_install
>> because it thinks that the binary built in src_compile is out of date.
> 
> Again, can you reference a specific ebuild with the issue ?
> 
>> Did you read my email?
> 
> I read the whole thread, but you only clearly stated the issue of
> rebuild between
> src_compile and src_install in your last email. I only read that one thread,
> apologies if I missed previous discussions.


I commented twice in that email, that it felt like you didn't actually
read the email you were replying to. Maybe grumpy of me -- but I'm not
referencing any secret emails that occurred elsewhere.


-- 
Eli Schwartz
OpenPGP_signature.asc (application/pgp-signature, 236 B)
-----BEGIN PGP SIGNATURE-----

wnsEABYIACMWIQTnFNnmK0TPZHnXm3qEp9ErcA0vVwUCahz6LQUDAAAAAAAKCRCEp9ErcA0vV6lV
AQDO7mcSZcuuKpPko6jTZdVJ2RVkLaycjoehSWVLj+i0dQEAtb26VV4e6PChi+z2mMmscHLITL70
KP/vh29sFg3rWgE=
=ZH47
-----END PGP SIGNATURE-----