Skip to main content

rucc_sysroot/
lib.rs

1//! Where a target's headers and link inputs live, which directories are searched for them, and in
2//! what order they reach the linker.
3//!
4//! Design: `spec/cross-compile/08-sysroots.md`, and section 8.5 for the rule this crate exists to
5//! enforce.
6//!
7//! # The claim this crate is responsible for
8//!
9//! `spec/cross-compile/02-the-goal.md` claim 5 is byte identical output from different hosts for
10//! the same target. It holds only because the search path rules make the libc header directory a
11//! function of the target rather than of the machine, and that function is here.
12//!
13//! So every answer in this crate is derived from a [`TargetTuple`] and from paths the caller
14//! supplies. Nothing reads an environment variable, nothing looks at `std::env::consts`, and
15//! nothing touches the filesystem. A host directory can only enter through
16//! [`Options::host_include`], which [`include_paths`] uses exactly once and only when the target
17//! is the host, and that is checkable by reading one function.
18//!
19//! # What is in here
20//!
21//! [`Sysroot`] is the directory layout for one target: where its headers go, where its link inputs
22//! go, and where the record of what they are goes. Its root is a function of a cache directory and
23//! the tuple, which is what makes the tuple a cache key.
24//!
25//! [`Kernel`] is the other half of a Linux target's headers. `linux/` and `asm/` are the system
26//! call interface rather than the C library, 31 of glibc's installed headers and 3 of musl's
27//! include one of them, and they are the same files for every target that shares an architecture.
28//! So they sit in the cache rather than in a sysroot and a Linux target searches four directories.
29//!
30//! [`bundled_glibc_minor`] is the version half of the same tree. One tree serves every glibc
31//! release, with the differences inside the files as `#if __GLIBC_MINOR__ >= n`, so the release is
32//! what the target supplies and the compiler defines the macro. It answers [`None`] for every libc
33//! that has no such macro and an error for a release newer than the tree, which is the one direction
34//! that cannot be approximated.
35//!
36//! [`include_paths`] is section 8.5 as an ordered list, with each entry saying which of the four
37//! steps put it there. [`LinkLine`] is the start files, the libraries and the end files, in the
38//! order a linker needs them, for either libc.
39//!
40//! [`argv`] is `spec/cross-compile/11-linking.md` section 11.3: the whole linker command line as a
41//! function of the target, the sysroot and what the user asked for. It is the same division as the
42//! one above, one level up. [`LinkLine`] is what has to be linked, which is a fact about the target,
43//! and [`argv`] is how that is spelled for a linker, which is a fact about the linker. Section 11.3
44//! asks for a golden file per target and `tests/link-lines` is it, one file per target, regenerated
45//! by `cargo xtask link-lines` and checked in CI.
46//!
47//! [`Manifest`] is what a produced sysroot carries: every input with where it came from, its hash
48//! and its licence. Two sysroots for the same target built on two hosts have the same manifest, and
49//! comparing manifests is how that gets checked without comparing several thousand files.
50//! [`Manifest::digest`] is the same comparison in one line, which is what the cache layout of
51//! `spec/cross-compile/13-distribution.md` section 13.2 wanted a hash in a directory's name for.
52//!
53//! [`sha256`] is how that digest is computed, and it is public because the digest is not the only
54//! thing that needs it. An artifact a downloader just wrote is checked against the hash pinned in
55//! the release before anything is unpacked, and the files that come out of it are checked against
56//! the manifest inside it, which is section 13.8's division of a fetch into the transport and the
57//! part that decides whether the result is correct.
58//!
59//! [`artifact`] is what a release pins: one sysroot artifact per target, by URL and by hash. It is
60//! here rather than beside the fetch that uses it because the generator of the file below cannot
61//! depend on the driver, and because a pin is a fact about a sysroot.
62//!
63//! [`distribution`] is that table and [`Wall`] and the target table written out as one file, which is
64//! what `spec/cross-compile/13-distribution.md` section 13.5 asks to ship beside the binary: for
65//! every target, whether the sysroot for it is in the archive, is a download this release pins, is
66//! behind a licence wall, or is ours to ship and not published yet.
67//!
68//! [`Wall`] is section 13.4's two licence walls as data. Apple's SDK and Microsoft's are the two
69//! things in section 8.2's table that are not ours to ship, so for those targets there is no bundled
70//! tree, no artifact a release can pin, and a message that names the licence and the lawful ways to
71//! get one instead of a message about a tree that has not been built yet.
72//!
73//! [`msvc`] is the one lawful download either wall has behind it. Microsoft publishes an installer
74//! manifest naming every file the Visual Studio installer would fetch, and a licence that lets a
75//! person who accepts it fetch them, which is what section 13.4 says we copy. That module reads the
76//! two documents and says which of the nineteen thousand packages in them a compiler needs, which
77//! for the three architectures we target is fourteen files: the CRT headers, one CRT library
78//! package per architecture, and ten of the Windows SDK's header and library installers. It
79//! fetches nothing, the same as everything else in here.
80//!
81//! # What is not in here
82//!
83//! Nothing fetches. Downloading musl, verifying it and unpacking it is
84//! `spec/cross-compile/13-distribution.md`, and the network policy it needs is that document's
85//! section 13.8: the bytes are moved by a downloader the machine already has, and the hash check,
86//! the manifest and the rename into place are ours. None of those three is in this crate either.
87//! What this crate settles is where the result goes and how it is searched, which is the part that
88//! has to be decided before anything is worth downloading.
89//!
90//! ```
91//! use rucc_sysroot::{Sysroot, LinkLine, LinkMode, argv};
92//! use rucc_tuple::TargetTuple;
93//! use std::path::Path;
94//!
95//! let target: TargetTuple = "aarch64-linux-musl".parse().unwrap();
96//! let sysroot = Sysroot::in_cache(Path::new("/cache"), target);
97//!
98//! // The cache key is the canonical spelling, so two hosts asking for the same target ask for
99//! // the same directory.
100//! assert_eq!(sysroot.cache_key(), "aarch64-linux-musl");
101//! assert_eq!(sysroot.root(), Path::new("/cache/sysroots/aarch64-linux-musl"));
102//!
103//! // A static link needs three start files, and `crtn.o` goes after the libraries rather than
104//! // with the other two.
105//! // Our own runtime is a path the caller hands in, because it is the compiler's output for the
106//! // target rather than anything a sysroot holds, and `None` leaves it off the line.
107//! let line = LinkLine::musl(&sysroot, LinkMode::Static, None);
108//! assert_eq!(line.start.last().unwrap().file_name().unwrap(), "crti.o");
109//! assert_eq!(line.end.first().unwrap().file_name().unwrap(), "crtn.o");
110//!
111//! // And the whole linker command line, which names nothing on this machine.
112//! let options = argv::Invocation { mode: LinkMode::Static, ..Default::default() };
113//! let line = argv::argv(target, &sysroot, &options).unwrap();
114//! assert!(line.contains(&"-static".to_owned()));
115//! assert!(line.contains(&"-m".to_owned()) && line.contains(&"aarch64linux".to_owned()));
116//! ```
117
118#![doc(html_root_url = "https://docs.rs/rucc-sysroot/0.10.76")]
119// Every public item here is read by somebody bringing up a target, and an undocumented one is a
120// question they have to answer by reading the body.
121#![deny(missing_docs)]
122
123pub mod argv;
124pub mod artifact;
125pub mod distribution;
126mod json;
127pub mod layout;
128pub mod link;
129pub mod manifest;
130pub mod msvc;
131pub mod search;
132pub mod sha256;
133pub mod wall;
134
135pub use argv::{Invocation, Item, Unsupported};
136pub use artifact::{PINNED, Pinned, pinned_for, pinned_targets};
137pub use distribution::Arrival;
138pub use layout::{BUNDLED_GLIBC, GlibcSkew, Kernel, Sysroot, bundled_glibc_minor};
139pub use link::{Libc, LinkLine, LinkMode, libc};
140pub use manifest::{Input, Licence, Manifest, ManifestError, Provenance};
141pub use msvc::{Channel, Chip, MsvcError, Payload, Selection, Wanted};
142pub use search::{Entry, Options, Origin, include_paths};
143pub use wall::Wall;
144
145#[doc(inline)]
146pub use rucc_tuple::TargetTuple;