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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
//! The directory layout of one target's sysroot, and the cache key that names it.
//!
//! Design: `spec/cross-compile/08-sysroots.md` sections 8.2 and 8.3.
//!
//! # Why the directories are split the way they are
//!
//! Section 8.3 is about a multiplication. Headers are naively `arch x os x libc x libc-version`
//! trees, which for glibc alone is eight architectures times six versions and several hundred
//! megabytes, and `spec/cross-compile/13-distribution.md` has a size budget that number destroys.
//!
//! The fix is two splits that turn the product into a sum. The per version differences go inside
//! the files as `#if __GLIBC_MINOR__ >= n`, so one tree serves every version. The per architecture
//! differences stay in directories, because they are whole files rather than lines, but only for
//! the small part of a libc that has any: `bits/` and a handful of others. Everything else is one
//! copy.
//!
//! That is why a sysroot here has two include directories rather than one. [`Sysroot::arch_include`]
//! holds the files that differ by architecture and is searched first, and
//! [`Sysroot::generic_include`] holds the copy that every architecture shares.
//!
//! A Linux target searches four directories and not two, because the kernel's headers are a second
//! pair with the same split and a different owner. They are [`Kernel`], their root is the cache
//! rather than a sysroot, and the order is the libc's two and then the kernel's two, which is the
//! order `zig cc -E -v` prints for a glibc target. `linux/` and `asm/` are nine megabytes of files
//! that are the same for every target, so one tree is shared and only `asm/` is copied per
//! architecture.
//!
//! # Why the root is a function of the tuple
//!
//! `spec/cross-compile/02-the-goal.md` claim 5 asks for byte identical output from different hosts.
//! A sysroot that lands in a directory named after the host, or after the day it was built, or
//! after a hash of an absolute path, breaks that before anything is compiled. So the root is the
//! cache directory the caller chose plus the canonical spelling of the tuple, and nothing else.
//!
//! The canonical spelling is the key rather than a hash of it because it is already unique, it is
//! already a legal directory name, and a cache a person can read is a cache a person can debug. It
//! carries the whole ten field model, so `x86_64-linux-gnu` and `x86_64-linux-gnu.2.28` are
//! different directories, which is the point of `env_version` being in the tuple at all.
//!
//! It is not the hash of the contents either, which is what
//! `spec/cross-compile/13-distribution.md` section 13.2 asked for until tamnd/rucc#1021 settled it.
//! A name cannot carry one: this function is what the producer calls to find out where to write
//! files it has not written yet, so there are no contents to hash when the question is asked. The
//! hash lives in the record instead, which is [`crate::Manifest::digest`], and the one thing the
//! name has to be is the same on two hosts.
use fmt;
use ;
use ;
/// One target's sysroot: where its headers are, where its link inputs are, and where the record
/// of what they are is.
///
/// Constructed rather than discovered. Nothing here checks that any of these directories exists,
/// because the caller that is about to produce a sysroot needs the same answer as the caller that
/// is about to read one, and a constructor that failed for an absent directory would give the
/// first one nothing to create.
/// The kernel's own headers, which are not the libc's and are shared by every target that can read
/// them.
///
/// `linux/` and `asm/` are the system call interface rather than the C library, and a sysroot
/// without them does not compile 31 of glibc's installed headers or 3 of musl's, `sys/quota.h` and
/// `net/ethernet.h` among them. So they are part of what section 8.2 calls a sysroot even though no
/// libc produced them.
///
/// # Why they are not under [`Sysroot`]
///
/// One tree serves every libc and every architecture except `asm/`, which is per architecture and
/// small. Copying the shared part into each tuple's sysroot would be nine megabytes times the
/// number of Linux rows in the table, for files that are identical in every copy. So the root is
/// the cache directory rather than a sysroot, and a sysroot that was produced with it records the
/// version in its manifest, which is [`crate::Manifest::kernel`] and the `kernel` line of the
/// format. The tree carries its own record as well, headed `rucc kernel headers manifest 1`, because
/// one tree serves every target and a sysroot manifest names one. Nothing checks the two against
/// each other: a sysroot can be produced beside one tree and read beside another, and the manifest
/// makes that visible rather than preventing it.
///
/// # Why the version is not in the path
///
/// The driver has to be able to compute this path before it reads anything, and a version in the
/// path would mean asking the cache what it has before being able to ask where it is. It is the
/// same decision [`Sysroot::in_cache`] makes about the libc version, where the tuple carries the
/// version only because `env_version` is part of the target's identity, and the same gap: a cache
/// populated by one release and read by the next gets whatever is there.
///
/// That gap does not close by putting a hash in a path, which is what
/// `spec/cross-compile/13-distribution.md` section 13.2 used to say and what tamnd/rucc#1021
/// settled: a path has to be known before anything has been read. What closes it is comparing a
/// record against one somebody published, and the record says which release it was, here as the
/// tree's own `manifest` and in a sysroot as [`crate::Manifest::kernel`].
/// What `make headers_install ARCH=` takes, which is a third naming of the machine.
///
/// `arm64` rather than `aarch64` and `s390` rather than `s390x`, because those are the directories
/// under `arch/` in the kernel's source tree, and the 31-bit s390 port leaving did not rename the
/// one that stayed. One directory serves both widths of x86, of riscv and of powerpc, the same way
/// glibc's family does and for the same reason: the uapi headers branch on the compiler's macros.
///
/// [`None`] for an architecture the kernel does not have, which is wasm.
const
/// Whether we can produce a sysroot for this target without the user fetching anything.
///
/// Section 8.2's table has seven rows and two of them are legal walls rather than engineering.
/// The macOS SDK is restricted by the Xcode licence to Apple-branded hardware and the Windows SDK
/// is not redistributable, so for those two the answer is a path the user supplies under their own
/// licence, and `spec/cross-compile/13-distribution.md` owns the mechanism.
///
/// This returns false for those two and true for everything else, including freestanding, which
/// needs nine compiler headers and no link inputs at all.
/// The glibc our bundled header tree is derived from.
///
/// A fact about the tree and not a choice. `sysroots/manifest` in `tamnd/rucc-cross` pins the glibc
/// source by version and hash, the tree is produced from that source, and this is that version. It
/// moves when the pin moves and the two are checked against each other by the producer.
pub const BUNDLED_GLIBC: Version = new;
/// The `__GLIBC_MINOR__` a target gets when it is compiled against the bundled glibc tree.
///
/// Design: `spec/cross-compile/08-sysroots.md` section 8.3.
///
/// One tree serves every glibc release, with the differences written inside the files as
/// `#if __GLIBC_MINOR__ >= n`, so the release is the part of it the target supplies. That is Zig's
/// patch to the same tree and the same macro, which is where the spelling comes from: `features.h`
/// keeps `__GLIBC__` at 2 and leaves the minor to the compiler, and `__GLIBC_PREREQ` reads both.
///
/// [`None`] for anything that is not glibc, because there is no such macro on musl or mingw and
/// defining one would have every probe for it answer yes on a libc that does not have it.
///
/// The version is the one the tuple asked for, which is the point of `env_version` being in the
/// tuple, and [`BUNDLED_GLIBC`] when it asked for nothing. Asking for an older release is how a
/// program is kept off symbols and declarations the target's libc does not have, and it is honest
/// only as far as the text goes: the declarations are guarded by the macro and the structure
/// layouts in the same files are one release's. Issue #926's last box is where that is finished and
/// it is the same direction as the compat symbol gap of #920, too permissive rather than wrong
/// about what it does say.
///
/// # Errors
///
/// A release newer than the tree, which is the one direction that cannot be approximated. Every
/// `__GLIBC_PREREQ` in the program would answer yes and the declarations behind them would not be
/// there, so the failure would be a missing declaration at best and a missing symbol at link time
/// at worst. Both versions are in the error, because the two things a person can do about it are
/// pin a release the tree has and name a sysroot that has the one they asked for, and neither is a
/// choice they can make without being told which release the tree is.
/// A glibc release the bundled tree cannot serve, and the release the tree is.
///
/// A type rather than a pair, because the two versions read the same way round in the message as
/// they do here and a caller that swapped them would produce a diagnostic exactly as wrong as it is
/// convincing.