1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
//! 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()));
//! ```
// Every public item here is read by somebody bringing up a target, and an undocumented one is a
// question they have to answer by reading the body.
pub use ;
pub use ;
pub use Arrival;
pub use ;
pub use ;
pub use ;
pub use ;
pub use Wall;
pub use TargetTuple;