Perfecting Rust Packaging


Ok, cool, thanks for all the info @cuviper! I think for now we can hold off on more details for a later thread (and focus on rustc/cargo themselves here), but it’s really helpful to learn about this space!

Specifically on the topic of Servo I believe they’ve got a handful of external libraries (e.g. skia, harfbuzz, png, etc), but they’d probably know more than I!


This has been the rule for most other module ecosystems in the Linux distros (Python, CPAN, Eclipse modules to name just a few; Fedora even repackages node.js packages despite the strong preference for bundled dependency installation in npm). They do want to reflect both build dependencies and binary dependencies in the respective source/binary packages, avoid downloading in builds, and discourage library bundling.

I think the main reason for that is maintainability on the distribution level. If a library crate X is found to have a critical bug, they don’t have practical ways to comb through the entire package universe searching for Cargo build manifests listing that library as a dependency, let alone projects that don’t even use Cargo. All they have is their package database, so the bundling of crates should be reflected as build dependencies in the packages.

Subteam reports 2015-09-21

components/servo/Cargo.lock currently lists 181 packages, 118 of which are from and 34 from other git repositories. This leaves 31 crates in the same repository.



I didn’t read the whole thread, sorry (had no time, going to do so), so may be I’ll repeat someones thoughts. Some points from the Gentoo point of view:

  • System wide LLVM: it worked for us, but now we’ve switched to shipping shared LLVM libraries only, so we need support for linking with shared libs from Rust upstream /see rust-lang/rust#27937/.

  • Installation of multiple rusts. It works for us without multirust, the only thing we need is the ability to install rust libs/binaries to custom dirs. There is one bug in the rust installer that we temporary fix with patch.

  • Cargo binary package support: we really need versioned cargo binary releases similar to those versioned rust binary releases (I failed to find any versioned ones for cargo).

  • Cargo/rust infrastructure support in general: the main problem is how to make cargo use system libraries during production build (it fetches everything and uses fetched versions). This + not very clean linking model (or may be I just do not understand it well enough) makes shipping cargo based packages in gentoo at the moment near impossible. The ideal solution would be if there existed some ‘production’ mode for cargo when it is used just as a nice build system and uses only packages already installed in the system. If no necessary package is found it should just fail.

  • -Werror switched on during Rust build, ideally it would be good to have a possibility to switch it off (I’m just sedding mk scripts at the moment)

  • Additional libraries suffix. At the moment I’m sedding with sed -i -e "s/CFG_FILENAME_EXTRA=.*/CFG_FILENAME_EXTRA=${postfix}/" mk/, it would be good to have some switch in the build system to do this (it is necessary for the possibility of relible side by side istallation of libs).

  • Signing of rust release tarballs, so their authentity can be checked.

  • Rust bootstrapping: at this point of stability we can switch to bootstrapping by the previously installed compiler I think. There is a switch in the build system that can be used for it (local rustc). But we need guarantees from upstream that compiler will be self compilable by, say, N previous versions.

So far that’s all from my side. I’m going to read the thread and may be I’ll have more points.


-Werror switched on during Rust build, ideally it would be good to have a possibility to switch it off (I’m just sedding mk scripts at the moment)

I agree, but if -Werror is causing any problem for you, I think we are interested in bug reports.

Signing of rust release tarballs, so their authentity can be checked.

I think we already do this, i.e. Perhaps we should document this better? What would be needed?



Huh. I’m sad to say I’ve looked at this patch for a while and still don’t see what the bug is. Can you explain in more detail what the patch is working around? Is there a filed issue? (I know that --libdir has always been in some state of broken)

This is a common theme!

cc @alexcrichton

Ah, interesting point. I’ve opened an issue:

Ah, yes, that makes sense. Although we (try to) tie that extra bit to the version number. Perhaps we’re just not capturing enough metadata to differentiate the versions of Rust you are installing together?

In fact, the code looks wrong. It’s hashing an undefined variable…

Would hashing the version number as intended be enough to distinguish your sxs installs?

Edit: After investigation, this does actually hash the version number correctly before CFG_RELEASE is defined. I don’t understand why offhand.


Thank you, my fault, I haven’t seen it. May be adding a link to the signature to the download page would be a good idea. The same for sha256 file.


The problem with these lines is that they lead to failure in case if libdir which was used during compilation starts with lib/ (our case). Also changing libdir during installation is broken anyway, so makes no sense, as it gets hardcoded in the compiler during build by catching env variable.

It could work for some environments, but not for Gentoo. We have two Rust packages: binary and source. Now

  1. you install binary with already defined suffixes (these hashes)

  2. you want to install source package (e.g. for testing or whatever else reason, or may be you were bootstrapping using binary package). If suffixes are the same version hashes as in 1, your installation will not work properly. That’s why we are changing suffixes to the custom ones for source packages this way that we have guaranty that only one package with such suffix can be installed in the system (we have one suffix per slot which corresponds to release upstream channel).


I have created an issue with detailed explanation and steps to reproduce:


OK. Ugh. The way I want this to work is that setting --libdir during configure doesn’t mess at all with the installer’s layout (so this case wouldn’t trip incorrectly with custom-named lib- prefix files), and passing --libdir to the installer puts it in the right place (this is how --mandir works). The obvious problem here is that the relative path to libdir is hard-coded into rustc. Making this work may be more trouble than it’s worth so I left a comment on the bug about a simpler stop-gap.

Hm, I still think this scenario should work if the release channel were hashed, since a default source build is on the ‘dev’ channel, not ‘stable’. Would hashing the channel help? If not, we could add a configure option to mix in more extras. Feel free to submit a PR in this area if it would help you.

On the issue of side-by-side installs, neither @alexcrichton or I are clear on what actually happens when two copies of std, from two different toolchains, are installed to the same location. We believe this should be workable, but don’t know any reason why it would work reliably with the current crate resolver.


My next steps here are to summarize what we’ve learned into a plan to resolve the upstream problems in Q4, as well as some guidelines for packagers. Stay tuned.


@gus @jauhien @cuviper @alexcrichton et al.

I’m thinking about the requirements for teaching Cargo to allow the local system to override dependencies, and specifically wondering how a packager might extract the library artifacts from a Cargo build in order to put them at the desired location locally (presumably somewhere under /usr/lib). Are you able today to get the precise information out of Cargo to identify which files to copy somewhere? Does Cargo need to do more to make it clear which of its outputs are the packagable artifacts?


Another question: if we modify Cargo so that it can use locally-available rlibs, as packaged by the distro, then the distro is going to accumulate a bunch of rlibs in /usr/lib. Because of the way rustc works now those will all be invalidated when rustc is upgraded - rustc will not be able to use them at all, and will likely just pretend they don’t exist because they ‘belong’ to another compiler. The obvious way I see to fix this is to make all Rust crate packages depend on a specific version of the compiler. I know that sucks, but is it doable?

Edit: oh, @gus I see that in your previous thread, you said that rust packages would include the source in Debian, not just the rlibs, and I also recall this was a subject of the anti-vendoring thread in Fedora. I would not expect distro packages of crates to include the source, but instead the rlibs, just globally invalidated in some way when the compiler version changes. Is this difficult to do?

If Debian packages simply dropped the source code onto the system with the expectation that Cargo rebuilds it every time its needed then there will be lots of extra builds.

Does Debian really want to package the source code, and not the rlibs? If it packages the source code where would it put it on the local system for Cargo to reuse? Either way is going to require cargo and/or rustc changes.

Any other distro maintainers have opinions about - given Rust’s compilation model and ABI limitations - whether their packages of Cargo crates will simply install the source code, or the rlibs?


@gus Your use case for distributing packaged cargo apps I think works like this:

  • User says ‘apt-get install rust-application’
  • apt installs the source of all deps somewhere locally (where?)
  • apt installs rust-application, and in the process of doing so compiles it and all its deps locally. Cargo automatically knows to use the local source, not the source.

So the distro package manager, which is usually distributing binaries and not building locally, is actually distributing source code and building locally. Is this right? Is this really what you want to have? Can we skip straight to distributing rlibs and not do this?


The ABI issues are exactly what makes shipping source-based libraries seem like a lesser evil. As I mentioned, this appears to be what golang packagers are doing in Fedora already.

Yes, you could make a Rust crate package (with rlibs) depend on a specific rustc version. Then you effectively still have to rebuild them all to get a rustc update out into the distro, so I’m not sure it’s really any help. Even then, is there any guarantee that an rlib from rustc-x.y-1 (original release) is compatible with rustc-x.y-2 (perhaps a recompile with some security patches)?

No, that’s Gentoo – I think these would be statically-built binaries. They would have a build-time requirement on the crate-dev package, with its crate source, but the final product would stand alone.


No, the opposite is guaranteed :slight_smile: They will be forcibly incompatible.


Right, so if any tweak to rustc breaks all rlibs, there’s really no use in shipping rlibs at all.


Hm, ok. So under this scheme the binary packages for Rust libraries would basically be useless right? IOW, the builders when building ‘rust-application’ will use the ‘rust-dependency-dev’ package, but there is no practical use for the ‘rust-dependency’ package from the perspective of users of ‘rust-application’; installing ‘rust-application’ will not install ‘rust-dependency’.

Will there still then be binary (rlib) packages for ‘rust-dependency’ and what role do they play?


Right. The user could still install the crate-dev package for their own local use, if they like. But it wouldn’t be needed for rust-application. This also simplifies rustc upgrades a little, as only the leaf packages with static binaries have to be rebuilt. (If you even want to rebuild them at all – if there’s no security aspect, you may not need to.)

I think these shouldn’t be packaged at all until there is some ABI stability. Maybe that will come to dylib first – my intuition says that may be easier – then we’d stop static-linking application binaries and use dylibs instead. Or if some library crate exports stable C-FFI, that could be packaged too.


@cuviper I’ve reread @gus’s previous proposal and it reads like library packages themselves install Rust source locally, not the -dev packages. @gus can you clarify?