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
//! The header search path, as section 8.5 states it.
//!
//! Design: `spec/cross-compile/08-sysroots.md` section 8.5.
//!
//! # The failure this prevents
//!
//! Host contamination. A cross build picks up a header from the machine it is running on, produces
//! something that works there, and does not work anywhere else. It is a quiet failure: the build
//! succeeds, the tests pass on the build machine, and the binary is wrong somewhere the person who
//! made it will not look.
//!
//! `spec/cross-compile/02-the-goal.md` claim 5 is the test that catches it, byte identical output
//! from two different hosts, and it catches it only because the rule below makes step 3 a function
//! of the target when the target is not the host. That is why [`Options::host_include`] exists as a
//! separate field rather than as a default: there is exactly one place a host directory can enter,
//! it is guarded by one condition, and both are in [`include_paths`] where they can be read.
//!
//! # The rule
//!
//! 1. `-I` in the order given.
//! 2. The compiler's own headers. Always present, on every target including freestanding, and never
//! taken from a sysroot, because `stddef.h` describes the compiler and not the C library.
//! 3. The target's libc headers, from `--sysroot` if given, otherwise from an Apple SDK this
//! machine has, otherwise from our bundled tree for that tuple, otherwise, and only when the
//! target is the host, from the host's directories. For a Linux target the bundled case is four
//! directories rather than two: the libc's per architecture tree, the libc's generic tree, the
//! kernel's `asm/` for the architecture, and the kernel's shared tree. That is the order
//! `zig cc -E -v` prints for a glibc target.
//! 4. Nothing else. No `/usr/local/include` in a cross build, ever.
//!
//! `-nostdinc` removes 3, `-nobuiltininc` removes 2, `--sysroot` replaces 3's root, and `-isysroot`
//! is the Darwin spelling of the same thing.
//!
//! # Why an SDK is a source of its own
//!
//! [`Options::sdk`] is the fourth of those sources and it is not one of the other three. It is not a
//! tree the user named, because on a mac it is found by asking `xcrun` and on Windows by asking the
//! Visual Studio installer, and nobody wrote either on the command line. It is not a bundled tree,
//! because `spec/cross-compile/13-distribution.md` section 13.4 says we may never ship one. And it is
//! not the host's own directories, because the SDK holds the headers of every architecture of its
//! platform rather than of this machine, so one installed SDK serves `x86_64-macos` on an arm64 mac
//! and one Windows Kit serves `aarch64-windows-msvc` on an x86_64 box, which is what the platform's
//! own tools do with them.
//!
//! The other half of the same rule is that a target behind one of those licence walls never takes
//! the bundled branch at all, whatever the caller passes, because [`crate::Wall`] is the statement
//! that no tree of ours can exist for it. A path under the cache for such a target would be a
//! directory nothing will ever put a file in, named in a `-v` listing as though a fetch were coming.
use ;
use TargetTuple;
use crate;
use crateWall;
/// Which of section 8.5's four steps put a directory in the list.
///
/// Carried rather than discarded because `-print-search-dirs` has to say it, because a user
/// debugging a wrong header needs to know which rule chose it, and because the test that no host
/// directory appears in a cross build is written against this rather than against path spelling.
/// One directory in the search path, and the reason it is there.
/// What the driver knows that the rule needs.
///
/// A struct rather than seven arguments, because six of the seven are empty in the common case and
/// a function with six defaulted parameters is a function somebody calls wrong.
/// The directories to search for an included file, in order.
///
/// `host` is what the compiler is running on, and it is an argument rather than something read from
/// the environment so that the rule can be tested for a host it is not running on. Passing [`None`]
/// says the host is unknown, which is treated as not being the target: an unknown host cannot be
/// proved to be the target, and guessing yes is the contamination this function is written against.