-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmcpp.toml
More file actions
702 lines (670 loc) · 38.7 KB
/
Copy pathmcpp.toml
File metadata and controls
702 lines (670 loc) · 38.7 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
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
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
[package]
namespace = "mcpplibs"
name = "openkal-musl"
version = "0.19.1"
description = "musl 1.2.5 redirected onto openkal: one C library, ported once, above every implementation of the specification rather than above one kernel."
license = "Apache-2.0"
# The layer this package supplies. `mcpp:c-abi` is the C library — the triple's
# environment field — and `=musl` is the interface it answers to, which is the
# same answer it would give above a kernel rather than above openkal. What
# changes is not the C library a program sees but what that library is written
# on.
provides = ["mcpp:c-abi=musl"]
authors = ["mcpplibs"]
repo = "https://github.com/mcpplibs/openkal-musl"
# The environment this C library presents, on every target — musl states one
# data model per architecture and this package follows it rather than
# stating a second one for Windows. `presents = "posix"` defines `__unix__`
# and leaves `_WIN32` and `__MINGW32__` undefined, on every target including
# Windows: the machine code is still PE and Win64, and what changes is only
# what the source text sees. `data-model = "arch-default"` is musl's own
# answer for the architecture — LP64 on every 64-bit target this package
# builds for, Windows included, rather than the LLP64 this package used to
# state for it alone. `wchar = 32` is musl's `wchar_t`, unconditionally; the
# Windows environment used to present 16 instead, which is why four patches
# in musl/PATCHES.md existed and do not any more. `builtins = "iso"` states
# that the compiler must not assume a platform C library is present beneath
# this one — musl is the whole of what a program built on this package calls.
#
# This block is read and checked, not merely trusted: the engine compiles a
# probe translation unit with the final flags for the target and compares
# `sizeof(long)`, `__SIZEOF_WCHAR_T__` and whether `_WIN32` is defined against
# what is declared here, and refuses the build if they disagree.
[c-abi]
presents = "posix"
data-model = "arch-default"
wchar = 32
builtins = "iso"
# WHAT THIS C LIBRARY DOES NOT SUPPLY, AND IN WHAT SHAPE EACH ABSENCE REACHES A
# PROGRAM.
#
# The set of names a C library supplies is not enumerable here --- POSIX has
# about twelve hundred --- and enumerating it is the mistake openkal's own
# specification records withdrawing (SPEC 0.14 clause 3.3, on the name it gave
# to a set of interfaces and then took back). The exceptions are enumerable.
# README's "The following are absent" table has carried them in prose since
# this port began, and nothing executed that prose: it was contradicted once
# already, in the release before this one, where `SIG_IGN` was accepted for
# every signal and installed for none and a program that asked not to be ended
# by the interrupt keystroke was told it had succeeded and was ended by it.
#
# `form` is how the absence reaches the program, and it is the load-bearing
# field:
#
# link the definition is not in the archive; the program
# fails to link, naming the symbol. This is the shape
# openkal's capability model requires of an
# implementation (clause 6.1: a conforming
# implementation shall not provide an interface whose
# operations report a lack of support at run time).
# enosys the definition exists and reports that it cannot act.
# POSIX has a value for this and a caller can read it,
# which is what makes it a bounded answer rather than a
# silent one.
# accepted-no-effect the call succeeds and part of what it asked for is not
# done. This is the shape of the defect the previous
# release repaired, and it is named so that "how many of
# these are there" is a question with an answer.
#
# tools/check-absent.sh asserts every row against the built archive: a `link`
# name that IS defined, or an `enosys` name that is NOT, fails the build.
#
# THIS TABLE ASKS NOTHING OF AN OLDER ENGINE, AND ITS SPELLING IS WHY. mcpp
# ignores a top-level table it does not know and refuses an unknown MEMBER of
# a table it does know, so `[c-abi].absent` --- which reads better, and is
# where the first draft of this file put it --- made every mcpp below
# 2026.9.20.1 refuse THIS WHOLE MANIFEST on every target. Measured against the
# published 2026.9.18.3 archive on exactly this file. Everything the table
# does is diagnostic, so an engine that ignores it reports the same raw link
# error it reports today; an engine that refused it would have taken this
# package away entirely and forced the index floor up, costing every client
# below that floor the whole index for a note they merely would not receive.
#
# The consequence here: 0.17.0 needs no `min_mcpp` move and may be registered
# as soon as it is tagged. An older client builds it and gets the link error
# without the sentence that explains it, which is what it gets today.
[c-abi-absent]
# Readiness held by the environment. A set is a facility of one kernel rather
# than a capability; `poll` and `select` ask each descriptor in turn, which is
# what an interface without a set permits. These five are not compiled at all
# (see the withheld sources below), so the link names them.
epoll_create = { form = "link", note = "openkal has no readiness set; poll and select ask each descriptor in turn" }
epoll_create1 = { form = "link", note = "as epoll_create" }
epoll_ctl = { form = "link", note = "as epoll_create" }
epoll_wait = { form = "link", note = "as epoll_create" }
epoll_pwait = { form = "link", note = "as epoll_create" }
timerfd_create = { form = "link", note = "a descriptor that is created and never becomes ready is worse than one that cannot be created" }
timerfd_settime = { form = "link", note = "as timerfd_create" }
timerfd_gettime = { form = "link", note = "as timerfd_create" }
eventfd = { form = "link", note = "as timerfd_create" }
eventfd_read = { form = "link", note = "as timerfd_create" }
eventfd_write = { form = "link", note = "as timerfd_create" }
signalfd = { form = "link", note = "as timerfd_create" }
inotify_init = { form = "link", note = "as timerfd_create" }
inotify_init1 = { form = "link", note = "as timerfd_create" }
inotify_add_watch = { form = "link", note = "as timerfd_create" }
inotify_rm_watch = { form = "link", note = "as timerfd_create" }
# Reported to the caller, which can read the value and act on it.
mprotect = { form = "enosys", note = "openkal has no operation upon a mapping's protection; musl asks for a guard page and proceeds without one when told this" }
sigaction = { form = "enosys", note = "a disposition other than the one already in effect; openkal has no asynchronous delivery, and a handler that was accepted and could never run would be silently wrong" }
chmod = { form = "enosys", note = "a request whose read or write bits differ from what stat already reports; a capability-oriented environment has no principal for a permission to name" }
fchmodat = { form = "enosys", note = "as chmod" }
chown = { form = "enosys", note = "a capability-oriented environment has no principal for an owner to name" }
fchown = { form = "enosys", note = "as chown" }
lchown = { form = "enosys", note = "as chown" }
# The call succeeds and part of what it asked for is not done. Each of these
# is a place where refusing would be worse than the partial answer, and the
# README row beside it says why.
#
# TWO THINGS THIS TABLE CANNOT SAY TODAY, STATED RATHER THAN ROUNDED OFF.
#
# A FACILITY NARROWER THAN A NAME. "A mode given at creation" is about an
# ARGUMENT of `open` and `mkdir`, not about those calls: they do what they are
# for, and the mode is what is not applied. A row keyed on `open` would say the
# call is absent, which is false and worse than the absence of a row.
#
# AN ABSENCE THAT VARIES BY TARGET. `fork` is composed here from
# `openkal.space` (port/src/okm_fork.c), which the reference to it takes
# WEAKLY: a backend that provides the interface gets a working `fork`, and one
# that does not gets `-ENOSYS`. openkal-linux provides it; openkal-windows
# declines it, for the reason its own README gives --- constructing the copy
# out of `CreateProcessW` would be present, would look like the operation, and
# would not produce a copy of the caller. So `fork` is `enosys` on Windows and
# works on Linux, and every row here is unconditional. Writing it as `enosys`
# would be false on Linux; omitting it is silent on Windows, and silence is the
# lesser of the two. The row returns when the schema carries `targets`.
#
# Both stay in the README until then. A table that answered these two by
# rounding them off would be a table nobody could assert against, which is the
# state this one exists to leave.
tcsetattr = { form = "accepted-no-effect", note = "openkal names three positions of the terminal mode word; a request that alters output post-processing, the line speed, the control characters or VMIN/VTIME is accepted and that part has no effect" }
[dependencies]
openkal = "0.14.0"
# An ordinary consumer of openkal declares the specification and leaves the
# choice of implementation to whoever builds the program, which is what the
# specification recommends and what openkal's own example demonstrates.
#
# This package declares the implementation itself, and the reason is a property
# of this package rather than a property of openkal. A program built above this
# package carries no other runtime: this one supplies everything the program
# calls. The implementation must therefore be the whole of the program's
# environment, which is a thing only the party that knows there is no other
# runtime can state --- and that party is this package, not the program.
#
# The consequence for a program is that it names this package and nothing else.
[target.'cfg(os = "linux")'.dependencies]
openkal-linux = { version = "0.15.0", features = ["standalone"] }
[target.'cfg(os = "macos")'.dependencies]
# 0.12.0 is the first release of this implementation that declares which
# interfaces of the layer it provides, so it is the first under which mcpp can
# ANSWER a consumer's `[kernel-abi] requires-interfaces` on macOS. Below it the
# question had no answer at all --- not a refusal and not a confirmation, which
# is the shape of a check that silently does not run --- while the same
# consumer was answered on Linux and Windows, whose implementations have
# carried the array since openkal-linux 0.15.0 and openkal-windows 0.10.0.
openkal-macos = { version = "0.12.0", features = ["standalone"] }
# FIRST STEP TOWARD A BARE MACHINE, AND NOT THE WHOLE OF IT.
#
# An environment with no operating system reaches openkal through firmware. The
# architecture directory and the generated headers for it are now here --- they
# were not, and their absence was the blocker, not any property of libc++ or of
# this port. What is NOT here yet is the rest of the chain: a linker script, a
# runtime that receives control, and a C library configured for an environment
# with no process to exit from. So this declares the implementation and stops.
[target.'cfg(os = "none")'.dependencies]
openkal-opensbi = { version = "0.8.0", features = ["standalone"] }
# WHICH OPENKAL INTERFACES THE IMPLEMENTATION BENEATH IS EXPECTED TO PROVIDE.
#
# A machine with no operating system has no storage to open a file on, no second
# image to start, and no scheduler to give a context to. openkal's answer to
# each is that the interface is ABSENT — clause 6.2 forbids an implementation
# from providing one whose operations always fail — and the answer for this C
# library is that it must not be built calling them.
#
# IT IS BUILT CALLING THEM UNLESS TOLD OTHERWISE, AND THE WAY THAT SHOWS IS A
# LINK FAILURE IN A PROGRAM THAT NEVER OPENS A FILE. Measured 2026-08-23 on
# riscv64-none-elf: a program whose whole text was `import std;` and one line of
# output failed on fifteen names it can never reach, because `fclose` is on the
# exit path of anything that uses stdio and the descriptor table closes what it
# holds. port/src/okm.h records what these three change and why answering with
# an error is right for a C library and wrong for an openkal implementation.
#
# THE TARGET IS A PROXY FOR THE IMPLEMENTATION, AND AN IMPERFECT ONE. A board
# CAN carry a real filesystem. Each macro is `#ifndef`-guarded, so a project
# with one turns it back on from its own build without editing this file.
[target.'cfg(os = "none")'.build]
defines = ["OKM_HAS_FS=0", "OKM_HAS_PROCESS=0", "OKM_HAS_TASK=0"]
[target.'cfg(windows)'.dependencies]
openkal-windows = { version = "0.10.1", features = ["standalone"] }
# The feature macros musl's own build establishes.
#
# musl's <features.h> turns on the POSIX and BSD declarations when a program
# names no feature macro and is not compiled in strict ISO mode. A program
# built by this tool *is* compiled in strict ISO mode --- `-std=c11' rather than
# `-std=gnu11' --- so the macros are stated instead of inferred. They are
# declared as a feature rather than as build flags because a feature's defines
# are the one thing a package can contribute to the translation units of a
# program above it, and a program above a C library needs the same view of that
# library's headers that the library was built with.
#
# _BSD_SOURCE is deliberately absent, and the reason is worth recording because
# it looks like an omission: musl's own build does not define it either, and a
# build that does fails --- <strings.h> then declares `index', and one of musl's
# own sources has a static variable of that name. The macro musl's features.h
# would have inferred is therefore not the macro musl is built with.
[features]
default = ["posix"]
posix = { defines = ["_XOPEN_SOURCE=700"] }
[build]
c_standard = "c99"
# musl's own source selection rule, written as globs. The base set is one level
# under src/ plus the selected allocator; a directory named after an
# architecture holds overrides for that architecture, and this port takes none
# of them --- the four names for which musl ships no C are supplied by
# port/src/okm_setjmp.S, in one file that assembles for every object format.
#
# The nine exclusions are the whole of what this port replaces in musl, and
# each is replaced for a reason recorded beside it in musl/PATCHES.md. Five read
# the shape of one environment directly --- the auxiliary vector, the program's
# own ELF headers, the instruction that installs a thread pointer, the system
# call that creates a thread, and the duplication of the calling image. Two
# carry a machine word through a variable declared `long', which is the same
# width on every architecture musl supports and is not on every architecture
# this port builds for.
sources = [
"musl/src/*/*.c",
"musl/src/malloc/mallocng/*.c",
"!musl/src/env/__libc_start_main.c",
"!musl/src/env/__init_tls.c",
"!musl/src/thread/__set_thread_area.c",
"!musl/src/thread/clone.c",
# Replaced in port/src/okm_thread.c: musl leaves for a 256-byte shared stack
# before the calls that end a detached thread, and this port's path for those
# calls needs far more --- it overwrote the context table on macOS.
"!musl/src/thread/__unmapself.c",
"!musl/src/process/posix_spawn.c",
# AND ITS SIBLING, WHICH IS EXCLUDED BECAUSE THE ONE ABOVE IS.
# musl's posix_spawnp does not search a PATH: it stores `__execvpe' in the
# attributes and lets posix_spawn call it IN THE DUPLICATE. This port has no
# duplicate to run it in, so the field was read by nobody and a name without
# a separator was taken as a path --- reporting success for a program it had
# not started. port/src/okm_spawn.c performs the search instead.
"!musl/src/process/posix_spawnp.c",
"!musl/src/mman/mmap.c",
"!musl/src/internal/syscall_ret.c",
"!musl/src/unistd/getcwd.c",
# THE THIRD SOURCE OF ONE KIND, AND IT WAS UNREACHABLE UNTIL 0.11.0.
# musl's `fcntl' reads its variable argument as an `unsigned long', which holds
# a pointer on every system musl was written for and thirty-two bits on one
# this port builds for --- so a `struct flock *' arrived with its top half
# gone. Every command answered before 0.11.0 took an integer or took a pointer
# nothing followed, so the truncation faulted nothing; a real `F_SETLK' follows
# it, and it faulted on the first attempt. Replaced by port/src/okm_fcntl.c.
"!musl/src/fcntl/fcntl.c",
# Replaced by port/src/okm_phdr.c: musl answers this from the auxiliary
# vector, which the replaced __libc_start_main does not read.
"!musl/src/ldso/dl_iterate_phdr.c",
# THE ONE SOURCE WHOSE vDSO DEPENDENCY SURVIVES AN ARCHITECTURE HEADER THAT
# DOES NOT OPT IN.
#
# There is no vDSO above openkal — that is a facility one system supplies to
# the programs it starts, and nothing here is started by it. musl's own
# arrangement handles that correctly: `__vdsosym` is defined only under
# VDSO_USEFUL, this port's syscall_arch.h replaces the architecture's and
# therefore never defines it, and every user of `__vdsosym` is behind a
# VDSO_* guard that is likewise never defined. So `vdso.c` compiles to an
# empty object and nothing misses it.
#
# Except this one. `cache.c` guards its vDSO use on SYS_riscv_flush_icache
# — a SYSCALL NUMBER, which the generated bits/syscall.h does define — rather
# than on a VDSO_* macro. So on riscv64 it alone compiles a call to a
# definition that was compiled away, and the link reports
# `undefined hidden symbol: __vdsosym`.
#
# It was invisible until 2026-08-23, and not because it is new: on the
# other architectures the guard is false and the file is empty, and riscv64's
# first COMPLETE link is this one. A latent defect of the port, found by the
# target that has nothing to fall back on — which is the reason §8.2 makes
# bare metal the acceptance environment.
#
# What the file provides is `__riscv_flush_icache`, which a program above
# openkal reaches through openkal.exec instead.
"!musl/src/linux/cache.c",
# --- FACILITIES WITHHELD SO THAT THEIR ABSENCE IS A LINK ERROR -----------
#
# Below this line the exclusions answer a different question from the ones
# above. Those replace a source this port supplies itself. These withhold a
# source whose facility openkal does not have and is not going to have, so that
# a program requiring it is refused when it is BUILT rather than when it runs.
#
# Clause 6.2 states the principle: the absence of an operation is expressed by
# the absence of its definition. `mcpplibs/tinyhttps` --- a package in mcpp's
# own index --- built successfully against this port and failed at its
# twenty-seventh test, which is what a run-time refusal costs.
#
# THE LIST IS MUCH SHORTER THAN THE PRINCIPLE, AND THE REASON IS MEASURED
# RATHER THAN CONSERVATIVE.
#
# Withholding a family only works when nothing else in musl reaches it. Each
# candidate was checked for consumers outside its own directory:
#
# timerfd eventfd signalfd inotify epoll 0 consumers withheld
# select 1: network/res_msend.c
# network syslog.c, nscd_query.c, mq_notify.c -> getpwnam
# fork forkpty.c, wordexp.c, daemon.c,
# linux/clone.c -> pthread_create
#
# The fork closure terminates at the THREAD implementation and the network
# closure at the password functions. Withholding either takes an essential or
# an ordinary facility with it, so neither is withheld.
#
# THREE OF THOSE FOUR ROWS ARE NOW MOOT, AND FOR THE RIGHT REASON: the
# facilities arrived rather than the exclusions being relaxed. openkal 0.8
# added `net', `datagram', `timeout' and `space'; port/src/okm_net.c,
# okm_poll.c and okm_fork.c route them, so `select', the network family and
# `fork' are not facilities this port lacks and had to reason about keeping ---
# they work. `epoll' and the four descriptor-shaped notifications below stay
# withheld, because a readiness SET held by the environment is a facility of
# one kernel rather than a capability, and openkal has none to express.
#
# AND THE MECHANISM HAS A PRECONDITION THIS PACKAGE MEETS ON ONE TARGET OF
# FOUR. `-ffunction-sections` with `-Wl,--gc-sections` is what makes an
# unreferenced definition cost nothing, and only `cfg(os = "linux")` sets those
# ldflags. On the mingw target the objects are kept, so `daemon` and `wordexp`
# took the build down while the same list passed here:
#
# musl/src/legacy/daemon.c:18: undefined reference to `fork'
#
# SO WITHHOLDING THE NETWORK FAMILY IS NOT REFUSED, IT IS NOT YET POSSIBLE.
# It becomes possible once every target collects unreferenced sections ---
# `--gc-sections` for the ELF and PE linkers, `-dead_strip` for this system's
# --- and that is a change to the link line of three targets, testable on its
# own, rather than something to attach here.
#
# What remains withheld are the five whose closure is empty on every target.
# THEY GO TOGETHER WITH THEIR REASON: a descriptor that is created and never
# becomes ready is worse than one that cannot be created, because a program
# waiting on it waits for ever with nothing to report.
"!musl/src/linux/timerfd.c",
"!musl/src/linux/eventfd.c",
"!musl/src/linux/signalfd.c",
"!musl/src/linux/inotify.c",
"!musl/src/linux/epoll.c",
"port/src/*.c",
"port/src/*.S",
]
# The order is musl's own, and it is load-bearing twice. port/include holds the
# two headers that replace an architecture's copies, so it precedes the
# architecture's directory; and an architecture's bits precede the generic ones,
# six of which exist in both places.
#
# These directories reach a program above this package as well, which is how a
# program's <stdio.h> becomes musl's. That includes musl's own internal
# headers: this package is built from the same include path it publishes, and
# the alternative --- two paths --- is a second place where the set of headers
# is configured.
# THE ONE THING THIS PACKAGE KNOWS THAT A CONSUMER DOES NOT: THAT IT IS THIS
# PACKAGE DOING THE COMPILING.
#
# musl's internal header overlay defines `weak`, `hidden` and `weak_alias` as
# macros that mean something only to musl's own sources, and this package
# publishes the path it is built from — so every consumer sees them too. Which
# consumers break by it was found one at a time: a C++ one on `restrict`, then
# on linkage; a C one (compiler-rt) on `weak`, which it writes itself.
#
# The discriminator used to be the LANGUAGE of the translation unit, and that
# was wrong in one direction: a C++ unit is certainly not musl's, but a C unit
# is not certainly musl's. Authorship is the property, and it is expressible —
# `defines` is applied to this package's own sources and is not carried to a
# consumer, which publicUsage's include directories and flags are.
# port/include/features.h records the measurement and what it cost.
#
# A CONSUMER THAT WAS BUILT BEFORE THIS LINE EXISTED DOES NOT SEE IT UNTIL ITS
# BUILD DIRECTORY IS CLEARED. Measured 2026-08-23: adding a flag here changed
# nothing in an example that depends on this package by path — not after a
# rebuild, and not after touching the sources either. The generated build file
# still carried the previous list. Removing `target/` and `mcpp.lock` picked it
# up at once. So a change to a path dependency's MANIFEST does not invalidate
# the consumer's plan, and the way that shows is a change that appears to have
# had no effect. Reported; nothing here works around it.
defines = ["OKM_MUSL_INTERNAL=1"]
include_dirs = [
"port/include",
"musl/src/include",
"musl/src/internal",
"musl-generated/internal",
"musl/include",
]
# THE FIRST-BEST REMEDY, WHICH port/include/features.h SAID WAS NOT
# AVAILABLE AND NOW IS.
#
# That file records the measurement of 2026-08-22: "The first would be for a
# package to distinguish the directories it is BUILT FROM from the directories
# it PUBLISHES. Measured: mcpp cannot express it — publicUsage takes
# privateBuild's include directories entire."
#
# It can now. `private_include_dirs` names the entries OF `include_dirs` that
# stop at this package's boundary, so musl's internal overlay reaches musl's
# own sources and reaches no consumer.
#
# A SUBSET OF THE LIST ABOVE RATHER THAN A LIST OF ITS OWN, and that is the
# point: the ORDER is load-bearing. `port/include` must precede the
# architecture's directory, and the internal overlay must precede
# `musl/include` — moving these three to the end makes musl's own build find
# the public <features.h> first and fail with `unknown type name hidden`.
# The one ordered list stays the one ordered list.
#
# THIS DOES NOT REPLACE `OKM_MUSL_INTERNAL`. That answers a different
# question — "is this package the one compiling this unit" — and it is what
# keeps the macros inert for a C consumer that IS built with these directories
# on its line (compiler-rt, when a board builds it here). The two are the
# authorship axis and the visibility axis; removing either brings back a defect
# that has already been measured.
private_include_dirs = [
"musl/src/include",
"musl/src/internal",
"musl-generated/internal",
]
cflags = [
# musl is written to C99 and to nothing else. -nostdinc is not an
# optimisation: a C library that included the headers of another C library
# would be describing that library's types rather than its own.
"-ffreestanding",
"-nostdinc",
"-fno-stack-protector",
"-fno-strict-aliasing",
"-frounding-math",
"-w",
# A C library is a set of facilities a program chooses from, and every
# facility it did not choose would otherwise be linked into it: this package
# contributes objects rather than an archive, so a program that calls printf
# would also carry the complex-arithmetic routines. Placing each function and
# each object in a section of its own lets the linker discard what nothing
# reaches, which restores the property an archive would have given.
"-ffunction-sections",
"-fdata-sections",
]
# A program above this package carries no other runtime, and the link line is
# where that is stated.
#
# The C++ runtime is not embedded. This package is C, and the implementation
# beneath it is C++ only because the specification's declarations are modules;
# neither throws, neither uses run-time type information, and neither reaches a
# standard library. Left to itself the driver would attach one, and on a link
# that has removed the C library the attached runtime's own references to it
# would be resolved by this package --- which is the collision this arrangement
# exists to avoid.
cxx_runtime = "host-coupled"
# -nostdlib is the statement that the program carries one C library and that it
# is this one; without it the driver adds the host's, and the two define the
# same names. --no-dynamic-linker removes the interpreter the driver records
# even for a static link: a program that names a loader it does not use is a
# program the loader refuses to start, and clang records one where gcc does not.
# -lgcc supplies the routines a compiler emits calls to and no C library
# defines --- integer division on some architectures, and the complex
# arithmetic musl's own <complex.h> calls.
[target.'cfg(os = "linux")'.build]
ldflags = ["-nostdlib", "-static", "-Wl,--no-dynamic-linker",
"-Wl,--gc-sections"]
# `-lgcc` was here; it is now named by build.mcpp, and only when the compiler
# is the one whose runtime has that name. See that file.
# The link line on this system.
#
# -nostdlib is the statement that the program carries one C library and that it
# is this one. -lSystem follows it because two names this system's openkal
# implementation needs live there and nowhere else, and both were chosen for the
# property that no C library defines them.
#
# Naming that library alongside a C library of our own is safe here and would
# not be on the first system, and the difference is a property of the object
# format rather than of this port. This format binds every reference to the
# library that defined it: a call inside that library reaches that library's own
# definition, and a call in the program reaches the program's. So the two
# `malloc's coexist rather than collide, which is the recursion that made the
# first system's implementation reject its own C library.
#
# The entry point is named rather than found: this format records an entry in
# the image header rather than looking for a fixed symbol. -dead_strip is this
# linker's spelling of discarding what nothing reaches.
[target.'cfg(os = "macos")'.build]
# The port's own dl_iterate_phdr is for ELF and is excluded here, as musl's was:
# this format has no program headers.
sources = [
"!port/src/okm_phdr.c",
# One file this format needs that no other does — the loader here runs
# constructors before the entry point, so the library has to be able to come
# up from a constructor too. `port/src/*.c` is a package-wide glob, so the
# file lives in a subdirectory it does not match.
"port/src/mach/*.c",
]
#
# --ld-path names this system's own linker rather than the one the toolchain
# brings. The reason is one construct and fifteen uses of it. A second name for
# a definition is made here with the assembler's own directive; where the
# definition is in the same translation unit that produces an ordinary symbol,
# and where it is not --- fifteen names in musl, every one of them a function
# declared in a header and defined elsewhere --- it produces an indirect symbol,
# which is what that directive is for. The toolchain's linker refuses an
# indirect symbol, in as many words: "TODO: support aliasing to symbols of kind
# 1". This system's own linker is the one the format was designed alongside and
# resolves them.
#
# The flag's scope is narrower than it reads, and the difference matters for
# cross builds. Remeasured 2026-08-22 with the open-source toolchain: the same
# 1356 objects produce ZERO indirect symbols, for both architectures and for two
# compiler versions, and ld64.lld links them on Linux. The linker's limitation
# is still present --- the string is still in the binary --- but the compiler no
# longer produces the construct that reaches it. The fifteen symbols are a
# property of THIS SYSTEM'S OWN COMPILER, which is what the original measurement
# was made with, and not of this port or of the object format.
#
# So: this flag is for a NATIVE build on this system. A cross build does not
# reach the construct, does not need this system's linker, and therefore does
# not need any file this system supplies. musl/PATCHES.md records both
# measurements and the two names a program does still need.
# `--ld-path` IS GONE, AND THE COMMENT ABOVE ALREADY SAID WHY IT WOULD BE.
#
# It named this system's own linker, to work around a construct that the
# compiler this package was FIRST built with produced. The remeasurement above
# is the whole of the reason it can go: with the open-source toolchain, the same
# objects produce ZERO indirect symbols, and `ld64.lld` links them.
#
# AND IT HAD TO GO, because mcpp's conditions are on the TARGET and not on the
# host. `cfg(os = "macos")` is true when this library is BUILT ON macOS and also
# when it is BUILT FOR macOS from somewhere else — and the second case is a Linux
# machine, where `/usr/bin/ld` is GNU ld and cannot link a Mach-O:
#
# /usr/bin/ld: Error: unable to disambiguate: -dead_strip
# (did you mean --dead_strip ?)
#
# Without it the clang driver picks the linker its target needs, which is what a
# retargetable driver is for.
ldflags = ["-nostdlib", "-lSystem",
"-Wl,-e,_okm_start", "-Wl,-dead_strip"]
# The generated headers, per architecture and per data model.
#
# musl states its data model in three lines of bits/alltypes.h, and every
# architecture it supports states LP64 or ILP32. This package's own [c-abi]
# block above now states LP64 for Windows too — the same three lines this
# architecture states everywhere else — so `musl-generated/x86_64-windows`
# and `musl-generated/x86_64` carry the same three lines; they are kept as
# two directories because the row below still names its own target and
# because a target-specific generated header is the seam a future divergence
# would land in, not because the content differs today.
# musl-generated/README.md records the three lines and how they are
# produced.
[target.'cfg(all(arch = "x86_64", not(windows), not(os = "macos")))'.build]
include_dirs = ["musl-generated/x86_64", "musl/arch/x86_64", "musl/arch/generic"]
[target.'cfg(all(arch = "x86_64", windows))'.build]
include_dirs = ["musl-generated/x86_64-windows", "musl/arch/x86_64", "musl/arch/generic"]
# THREE ROWS FOR ONE ARCHITECTURE NOW, NOT TWO — found by
# `port/src/okm_type_identity.c`, which checks every one of these generated
# typedefs against the compiler's own statement of the same type, for the
# actual target being built, rather than waiting for a probe that happens to
# exercise the one that is wrong. Measured cross-compiling for
# `x86_64-apple-macos`: `int64_t`/`uint64_t` disagree with `__INT64_TYPE__`/
# `__UINT64_TYPE__` the same way `aarch64-macos` already knew about below;
# `wint_t` disagrees with `__WINT_TYPE__` (signed `int` there, `unsigned` in
# the generic answer); and `intmax_t`/`uintmax_t` disagree with
# `__INTMAX_TYPE__`/`__UINTMAX_TYPE__` in a way that is NOT fixed by the same
# `_Int64` override that fixes `int64_t` --- Apple's own `intmax_t` is `long`,
# `int64_t` is `long long`, and the two are different types at the same width
# on this target, so `musl-generated/x86_64-macos/bits/alltypes.h` states
# `intmax_t`/`uintmax_t` directly rather than deriving them from `_Int64` the
# way every other architecture here does. See `musl-generated/README.md`.
[target.'cfg(all(arch = "x86_64", os = "macos"))'.build]
include_dirs = ["musl-generated/x86_64-macos", "musl/arch/x86_64", "musl/arch/generic"]
# TWO ROWS FOR ONE ARCHITECTURE, AND MUTUALLY EXCLUSIVE — the same shape
# x86_64 already has for Windows, and for a narrower version of the same reason.
#
# musl states its data model in three lines of bits/alltypes.h. Windows needed a
# variant because it is LLP64 and every musl architecture is LP64. Apple is
# LP64 — a `long` holds a pointer — and still differs in one of the three:
# `int64_t` is spelled `long long` there and `long` on Linux.
#
# One spelling, and it is not cosmetic. Measured 2026-08-23 on a macOS cross:
#
# okm_syscall.c:439: incompatible pointer types passing 'uint64_t *'
# (aka 'unsigned long *') to parameter of type 'kal_u64 *'
# (aka 'unsigned long long *')
#
# `kal_u64` comes from the COMPILER (`__UINT64_TYPE__`), which is authoritative
# about the target's ABI; `uint64_t` came from these three lines, which carried
# Linux's answer. Same width, different type, and the two do not convert.
[target.'cfg(all(arch = "aarch64", not(os = "macos")))'.build]
include_dirs = ["musl-generated/aarch64", "musl/arch/aarch64", "musl/arch/generic"]
[target.'cfg(all(arch = "aarch64", os = "macos"))'.build]
include_dirs = ["musl-generated/aarch64-macos", "musl/arch/aarch64", "musl/arch/generic"]
[target.'cfg(arch = "riscv64")'.build]
include_dirs = ["musl-generated/riscv64", "musl/arch/riscv64", "musl/arch/generic"]
# The link line on this environment. There is no separate loader to name and no
# archive of compiler support routines to add: the entry point is this
# library's, and the implementation beneath it names the libraries its own
# interfaces live in.
[target.'cfg(windows)'.build]
# WHICH TARGET THIS IS, STATED BY THE MANIFEST RATHER THAN READ OFF THE
# COMPILER.
#
# `_WIN32` used to answer this for the four sites port/src and
# port/include/features.h ask it at (OKM_MUSL_INTERNAL is already required
# alongside it there, so the definition below reaches only this package's own
# build): argv's shape in okm_start.c, the object-format shims in
# okm_format.c, the `.exe` retry in okm_spawn.c, and the weak_alias fallback
# in features.h. `[c-abi] presents = "posix"` (mcpp.toml, above) now leaves
# `_WIN32` undefined on this target, correctly --- the C environment a
# program sees is POSIX, and Win32 was never one of the three things that
# macro used to be asked to mean here. What each of those four sites actually
# needs to know did not go away with it: this states it directly.
#
# THIS DOES NOT REACH A CONSUMER. `defines` under `[build]` is applied to
# this package's own sources and is not carried to a program built above it
# --- see the comment beside `OKM_MUSL_INTERNAL=1` for the general rule and
# the measurement behind it. A consumer that needs to know the target asks
# openkal's own `[target.'cfg(windows)']`, as every other consumer of this
# port already does; it does not read this macro, which is why it is not
# named `OKM_WINDOWS` or anything a program might reach for.
defines = ["OKM_TARGET_WINDOWS=1"]
# The port's own dl_iterate_phdr is for ELF and is excluded here, as musl's was:
# this format has no program headers.
sources = [
"!port/src/okm_phdr.c",
# AND ONE THIS FORMAT NEEDS THAT NO OTHER DOES.
#
# IN A SUBDIRECTORY, AND THAT IS THE POINT. `port/src/*.c` in the
# package-wide list is a glob, so a file placed beside its neighbours would be
# compiled for EVERY target — and `__main` is a name only this format's
# compiler emits a call to. `port/src/win/` is not matched by that glob, which
# states the restriction in the layout rather than relying on an exclusion
# that would have to win against an inclusion.
"port/src/win/*.c",
]
# `-lgcc` AND `-lgcc_eh` WERE HERE AND ARE NOT ANY MORE.
#
# They named GCC's runtime: the routines a compiler emits calls to and no C
# library defines, plus one more this format needs — the helper a thread-local
# variable is reached through, because on this format it cannot be reached
# directly from something loaded at run time.
#
# Both statements were true. What was false is that this port should name them:
#
# 1. THE macOS BLOCK ABOVE NAMES NEITHER, and it is the same C library on the
# same compiler. Builtins come from the graph there — `openkal-llvm-runtime`
# builds compiler-rt for the target — and the thread-local helper is
# `__emutls_get_address` from that same build. This block was the outlier.
#
# 2. AND IT ONLY EVER WORKED BY ACCIDENT. `libgcc.a` and `libgcc_eh.a` are
# mingw's, so a cross build resolved them out of `/usr/x86_64-w64-mingw32/lib`
# — present on a machine with mingw installed and nowhere else. Measured
# 2026-08-22 on a clean CI runner, alongside the four import libraries that
# failed for the same reason:
#
# lld: error: unable to find library -lgcc
# lld: error: unable to find library -lgcc_eh
#
# A GCC runtime on a link whose compiler is clang was the sign, and the
# missing file was the report.
#
# ⇒ Measured after removing them, with `openkal-llvm-runtime` in the graph
# (which now builds compiler-rt's builtins AND `emutls.c` for this format):
# `examples/same-source` links and the program runs, printing `unwound: true`.
ldflags = ["-nostdlib", "-static", "-Wl,--gc-sections", "-Wl,-e,okw_start"]