-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfeatures.h
More file actions
249 lines (237 loc) · 12.5 KB
/
Copy pathfeatures.h
File metadata and controls
249 lines (237 loc) · 12.5 KB
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
/* How a second name for a definition is made, where the object format has no
* weak one.
*
* musl gives almost every public name to a definition that is named something
* else: `fstat' is a weak alias of `__fstat', `malloc' of the allocator's own
* entry. There are 289 such aliases. Weakness does two different jobs among
* them, and the difference is what this header is about.
*
* It lets a program supply its own `malloc' and have the library's yield.
*
* It lets one of musl's own sources supply a placeholder that another source
* replaces --- 46 names are provided that way, and every one of the
* placeholders is an alias of a local, empty definition whose name begins
* with "dummy".
*
* The measurement, made with both toolchains this package is built by:
*
* int base(void) { return 7; }
* extern __typeof(base) w __attribute__((__weak__, __alias__("base")));
* extern __typeof(base) s __attribute__((__alias__("base")));
*
* On an ELF target both `w' and `s' are defined. On this object format `s' is
* defined and `w' is not: it becomes a record named `.weak.w.base' that neither
* GNU ld nor lld ever resolves, so a program referring to `w' fails to link
* naming it, and a weak *reference* to it evaluates to a null pointer. The same
* holds for a weak definition that is not an alias, and for data as well as
* functions. This object format, as both linkers implement it, has no weak
* symbol that is a definition.
*
* So a second name is made strongly, and the placeholders --- which would then
* collide with the sources that replace them --- are not made at all. Which is
* which is decided by the name of the target, because musl's placeholders are
* recognisable by it and by nothing else.
*
* A third object format reaches the same conclusion by a different route. There
* the compiler refuses the construct outright --- "aliases are not supported on
* darwin" --- so neither form above can be written. What that format does have
* is the assembler's own way of giving an address a second name, and the same
* measurement establishes it:
*
* int base(void) { return 7; }
* __asm__(".globl _w\n\t.set _w, _base");
*
* produces `w' as a definition at `base's address. That is a strong name, so the
* placeholder list below applies there too, and the underscore is written out
* because that format prefixes every C name with one.
*
* Two consequences follow, and both are boundaries rather than defects.
*
* A program cannot replace a function of this library by defining one of the
* same name. It is told so by the linker, which is the loudest report
* available and is preferable to the alternative: the library's definition
* winning silently while the program believes its own is in use.
*
* A placeholder that nothing replaces is now absent rather than empty. Those
* are supplied by port/src/okm_pe_defaults.c, which lists them, and the list
* was obtained by removing the placeholders and reading what the linker then
* reported.
*/
#ifndef OKM_FEATURES_H
#define OKM_FEATURES_H
#include_next <features.h>
/* ⚠️ THE INTERNAL HEADERS ARE MUSL'S, AND A CONSUMER IS NOT MUSL.
*
* musl's build reaches its own declarations through src/include, whose headers
* add the hidden entries the public ones do not have. This package publishes
* the path it is built from --- one set of directories rather than two, which
* is the decision mcpp.toml records --- so a consumer reaches src/include too,
* and finds <features.h> defining `weak', `hidden' and `weak_alias' as macros
* that mean something only to musl's own sources.
*
* ⓘ THIS WAS THE SECOND-BEST REMEDY, AND THE FIRST ONE HAS ARRIVED.
*
* The note used to read: "The first would be for a package to distinguish the
* directories it is built from from the directories it publishes. Measured
* 2026-08-22: mcpp cannot express it --- publicUsage takes privateBuild's
* include directories entire." It was left here so that the better fix would
* not be lost, and it was not: mcpp 2026.8.27.1 added
* `[build] private_include_dirs`, and this package's manifest now uses it.
*
* ⚠️ SO WHY IS THE BLOCK BELOW STILL HERE? Because the two answer different
* questions and only one of them is about visibility.
*
* private_include_dirs --- WHO SEES the internal overlay. A consumer no
* longer has these directories on its command line
* at all, so the macros cannot reach it.
* OKM_MUSL_INTERNAL --- WHO IS COMPILING. A C source that IS built with
* these directories on its line and is NOT musl's
* --- compiler-rt, when a board builds it here ---
* still needs the macros inert.
*
* The second case is measured and is recorded further down: `int_util.c:49:
* use of undeclared identifier __weak__'. Removing either axis brings back a
* defect that has already been paid for once.
*
* ⚠️ The rejected alternative is also kept: moving the two directories into
* per-glob flags places them AFTER include_dirs on the command line, and musl's
* own build then finds the public <features.h> before the internal one and
* fails with `unknown type name hidden'. That is why `private_include_dirs` is
* a SUBSET of `include_dirs` rather than a second list --- the order is the
* thing that cannot be given up.
*
* ⭐⭐ THE DISCRIMINATOR WAS WRONG ONCE, AND THE WRONG ONE HELD FOR A DAY.
*
* It used to be `#ifdef __cplusplus', with this reasoning written beside it:
* musl's own sources are C and are never compiled as anything else, so a
* translation unit that is C++ is with certainty not one of them.
*
* Both halves are true. The conclusion drawn from them was not, because it was
* used backwards: a C++ unit is certainly not musl's, but a C unit is not
* certainly musl's. Measured 2026-08-23, when a freestanding target needed
* compiler-rt's soft-float routines built --- C, not musl, and the first file
* compiled stopped at
*
* int_util.c:49: use of undeclared identifier `__weak__'
* features.h:6: expanded from macro `weak'
*
* ⇒ The property that matters is not the LANGUAGE of the unit. It is whether
* this package is the one compiling it, and that is a thing this package can
* simply say: mcpp.toml defines OKM_MUSL_INTERNAL for its own build, and
* `defines' does not propagate to a consumer --- publicUsage carries include
* directories and flags, and this is neither. Verified by building both sides.
*
* A consumer therefore gets the block below in EITHER language, and musl's own
* sources get the machinery at the end of the file. */
#ifndef OKM_MUSL_INTERNAL
/* The rule, rather than a remedy per collision. Everything src/include adds for
* musl's own build is inert here, and what it must not do is collide with the
* consumer. Four names, found one at a time by three consumers rather than by
* reading:
*
* restrict C++ ONLY --- in C it is a keyword and needs nothing. There
* `f(int *restrict, int *restrict)' is read as two parameters
* both named `restrict'. Given the spelling every compiler
* accepts in both languages.
*
* hidden ⭐ IN C++, GIVEN C LINKAGE rather than emptied. Every
* declaration the internal overlay adds begins with it --- that
* is what it is for --- so one spelling gives all of them the
* linkage they were written with. The overlay's headers carry no
* `extern "C"' of their own because musl never compiles them as
* C++, and a consumer that emptied `hidden' instead would parse
* the declarations and then fail to link against musl's
* definitions: measured, with `undefined symbol:
* ___errno_location()' beside `did you mean: extern "C"
* ___errno_location'. In C there is no linkage to restore, so it
* is emptied.
*
* weak an attribute musl spells as a bare word. Emptied. ⚠️ This is
* the one that bit compiler-rt: it writes
* `__attribute__((weak))' of its own, which became
* `__attribute__((__attribute__((__weak__))))'.
*
* weak_alias REMOVED rather than emptied. It is used in musl's .c files and
* in no header, so nothing here needs it --- and leaving it
* defined breaks any consumer that writes
* `__attribute__((weak_alias(...)))' of its own. LLVM's
* libunwind does, in fifteen places, and reported
* `use of undeclared identifier __weak__'. */
# ifdef __cplusplus
# if !defined(restrict)
# define restrict __restrict
# endif
# undef hidden
# define hidden extern "C"
# else
# undef hidden
# define hidden
# endif
# undef weak
# define weak
# undef weak_alias
#endif /* !OKM_MUSL_INTERNAL */
/* Only for musl's own sources: it redefines weak_alias, and the block above
* removed that name deliberately for everyone else. */
#if (defined(_WIN32) || defined(__APPLE__)) && defined(OKM_MUSL_INTERNAL)
/* Whether a name is one the preprocessor has been told about. The idiom is the
* usual one: a name that has been told about expands to a marker that shifts
* the argument list, and one that has not expands to itself and does not. */
#define OKM_SECOND(a, b, ...) b
#define OKM_CHECK(...) OKM_SECOND(__VA_ARGS__, 0, )
#define OKM_MARK(x) x, 1,
#define OKM_IS_PLACEHOLDER(target) OKM_CHECK(OKM_PLACEHOLDER_##target)
/* Every name musl gives a placeholder alias to. The list is the set of local,
* empty definitions musl aliases from, and it is closed: `grep' over the
* vendored sources produces exactly these seven. */
#define OKM_PLACEHOLDER_dummy OKM_MARK(~)
#define OKM_PLACEHOLDER_dummy_0 OKM_MARK(~)
#define OKM_PLACEHOLDER_dummy1 OKM_MARK(~)
#define OKM_PLACEHOLDER_dummy_file OKM_MARK(~)
#define OKM_PLACEHOLDER_dummy_gettextdomain OKM_MARK(~)
#define OKM_PLACEHOLDER_dummy_lockptr OKM_MARK(~)
#define OKM_PLACEHOLDER_dummy_tsd OKM_MARK(~)
/* Three placeholders musl gives an ordinary name rather than a dummy one. Each
* is a simple implementation that a fuller one replaces: the bump allocator
* that the real allocator replaces, the plain system call that the cancellable
* one replaces, and the conservative answer that the allocator's own replaces. */
#define OKM_PLACEHOLDER___simple_malloc OKM_MARK(~)
#define OKM_PLACEHOLDER_sccp OKM_MARK(~)
#define OKM_PLACEHOLDER_allzerop OKM_MARK(~)
/* 0: the second name is made. 1: it is not, and the source that supplies the
* real definition makes it instead.
*
* The two formats differ only in how a second name is written. One accepts the
* compiler's construct without its weakness; the other refuses the construct
* and accepts the assembler's directive, where the name carries the leading
* underscore that format gives every C name. */
#if defined(__APPLE__)
/* The directive names the definition, and the pointer keeps it.
*
* A directive in module-level assembly is opaque to the compiler, so a
* definition that nothing else in the translation unit refers to is deleted
* before the assembler ever sees the name --- and musl has six such: a static
* function that exists only to be given a second name. What the compiler then
* emits is a second name for nothing, which the linker reports as an undefined
* symbol with the alias as its only reference.
*
* The pointer is a reference the compiler does understand. It is `used' so that
* it is emitted rather than folded away, and taking the address of the
* definition is what obliges the compiler to keep it.
*
* The other object format needs none of this: there the second name is made
* with the compiler's own construct, which is itself a use. */
# define OKM_ALIAS_0(old, new) \
__asm__(".globl _" #new "\n\t.set _" #new ", _" #old); \
static __typeof(old)* const OKM_KEEP_##new \
__attribute__((__used__)) = &old
#else
# define OKM_ALIAS_0(old, new) extern __typeof(old) new __attribute__((__alias__(#old)))
#endif
#define OKM_ALIAS_1(old, new) extern __typeof(old) new
#define OKM_ALIAS_PICK2(x) OKM_ALIAS_##x
#define OKM_ALIAS_PICK(x) OKM_ALIAS_PICK2(x)
#undef weak_alias
#define weak_alias(old, new) OKM_ALIAS_PICK(OKM_IS_PLACEHOLDER(old))(old, new)
#endif /* _WIN32 || __APPLE__ */
#endif