Skip to main content

Crate rucc_sysroot

Crate rucc_sysroot 

Source
Expand description

Where a target’s headers and link inputs live, which directories are searched for them, and in what order they reach the linker.

Design: spec/cross-compile/08-sysroots.md, and section 8.5 for the rule this crate exists to enforce.

§The claim this crate is responsible for

spec/cross-compile/02-the-goal.md claim 5 is byte identical output from different hosts for the same target. It holds only because the search path rules make the libc header directory a function of the target rather than of the machine, and that function is here.

So every answer in this crate is derived from a TargetTuple and from paths the caller supplies. Nothing reads an environment variable, nothing looks at std::env::consts, and nothing touches the filesystem. A host directory can only enter through Options::host_include, which include_paths uses exactly once and only when the target is the host, and that is checkable by reading one function.

§What is in here

Sysroot is the directory layout for one target: where its headers go, where its link inputs go, and where the record of what they are goes. Its root is a function of a cache directory and the tuple, which is what makes the tuple a cache key.

Kernel is the other half of a Linux target’s headers. linux/ and asm/ are the system call interface rather than the C library, 31 of glibc’s installed headers and 3 of musl’s include one of them, and they are the same files for every target that shares an architecture. So they sit in the cache rather than in a sysroot and a Linux target searches four directories.

bundled_glibc_minor is the version half of the same tree. One tree serves every glibc release, with the differences inside the files as #if __GLIBC_MINOR__ >= n, so the release is what the target supplies and the compiler defines the macro. It answers None for every libc that has no such macro and an error for a release newer than the tree, which is the one direction that cannot be approximated.

include_paths is section 8.5 as an ordered list, with each entry saying which of the four steps put it there. LinkLine is the start files, the libraries and the end files, in the order a linker needs them, for either libc.

argv is spec/cross-compile/11-linking.md section 11.3: the whole linker command line as a function of the target, the sysroot and what the user asked for. It is the same division as the one above, one level up. LinkLine is what has to be linked, which is a fact about the target, and argv is how that is spelled for a linker, which is a fact about the linker. Section 11.3 asks for a golden file per target and tests/link-lines is it, one file per target, regenerated by cargo xtask link-lines and checked in CI.

Manifest is what a produced sysroot carries: every input with where it came from, its hash and its licence. Two sysroots for the same target built on two hosts have the same manifest, and comparing manifests is how that gets checked without comparing several thousand files. Manifest::digest is the same comparison in one line, which is what the cache layout of spec/cross-compile/13-distribution.md section 13.2 wanted a hash in a directory’s name for.

sha256 is how that digest is computed, and it is public because the digest is not the only thing that needs it. An artifact a downloader just wrote is checked against the hash pinned in the release before anything is unpacked, and the files that come out of it are checked against the manifest inside it, which is section 13.8’s division of a fetch into the transport and the part that decides whether the result is correct.

artifact is what a release pins: one sysroot artifact per target, by URL and by hash. It is here rather than beside the fetch that uses it because the generator of the file below cannot depend on the driver, and because a pin is a fact about a sysroot.

distribution is that table and Wall and the target table written out as one file, which is what spec/cross-compile/13-distribution.md section 13.5 asks to ship beside the binary: for every target, whether the sysroot for it is in the archive, is a download this release pins, is behind a licence wall, or is ours to ship and not published yet.

Wall is section 13.4’s two licence walls as data. Apple’s SDK and Microsoft’s are the two things in section 8.2’s table that are not ours to ship, so for those targets there is no bundled tree, no artifact a release can pin, and a message that names the licence and the lawful ways to get one instead of a message about a tree that has not been built yet.

§What is not in here

Nothing fetches. Downloading musl, verifying it and unpacking it is spec/cross-compile/13-distribution.md, and the network policy it needs is that document’s section 13.8: the bytes are moved by a downloader the machine already has, and the hash check, the manifest and the rename into place are ours. None of those three is in this crate either. What this crate settles is where the result goes and how it is searched, which is the part that has to be decided before anything is worth downloading.

use rucc_sysroot::{Sysroot, LinkLine, LinkMode, argv};
use rucc_tuple::TargetTuple;
use std::path::Path;

let target: TargetTuple = "aarch64-linux-musl".parse().unwrap();
let sysroot = Sysroot::in_cache(Path::new("/cache"), target);

// The cache key is the canonical spelling, so two hosts asking for the same target ask for
// the same directory.
assert_eq!(sysroot.cache_key(), "aarch64-linux-musl");
assert_eq!(sysroot.root(), Path::new("/cache/sysroots/aarch64-linux-musl"));

// A static link needs three start files, and `crtn.o` goes after the libraries rather than
// with the other two.
let line = LinkLine::musl(&sysroot, LinkMode::Static);
assert_eq!(line.start.last().unwrap().file_name().unwrap(), "crti.o");
assert_eq!(line.end.first().unwrap().file_name().unwrap(), "crtn.o");

// And the whole linker command line, which names nothing on this machine.
let options = argv::Invocation { mode: LinkMode::Static, ..Default::default() };
let line = argv::argv(target, &sysroot, &options).unwrap();
assert!(line.contains(&"-static".to_owned()));
assert!(line.contains(&"-m".to_owned()) && line.contains(&"aarch64linux".to_owned()));

Re-exports§

pub use argv::Invocation;
pub use argv::Item;
pub use argv::Unsupported;
pub use artifact::PINNED;
pub use artifact::Pinned;
pub use artifact::pinned_for;
pub use artifact::pinned_targets;
pub use distribution::Arrival;
pub use layout::BUNDLED_GLIBC;
pub use layout::GlibcSkew;
pub use layout::Kernel;
pub use layout::Sysroot;
pub use layout::bundled_glibc_minor;
pub use link::Libc;
pub use link::LinkLine;
pub use link::LinkMode;
pub use link::libc;
pub use manifest::Input;
pub use manifest::Licence;
pub use manifest::Manifest;
pub use manifest::ManifestError;
pub use manifest::Provenance;
pub use search::Entry;
pub use search::Options;
pub use search::Origin;
pub use search::include_paths;
pub use wall::Wall;

Modules§

argv
The linker command line, as a function of the target and the sysroot and nothing else.
artifact
What this release pins: one sysroot artifact per target, by URL and by hash.
distribution
What a release brings onto a machine, per target, as one file an auditor can read.
layout
The directory layout of one target’s sysroot, and the cache key that names it.
link
The start files, the libraries and the loader for one target’s link.
manifest
What a produced sysroot carries: every input, where it came from, its hash and its licence.
search
The header search path, as section 8.5 states it.
sha256
sha256, as published in FIPS 180-4.
wall
The two targets whose system headers are somebody else’s to license.

Structs§

TargetTuple
Everything about a target that changes the bytes the compiler emits.