buninu-linux 0.8.56 → 0.10.56

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/LICENSES/MIT-ZilchOS-bootstrap-from-tcc.txt +21 -0
  2. package/NOTICE.md +34 -0
  3. package/README.md +3 -0
  4. package/initramfs/bin/tar +34 -46
  5. package/initramfs/buninu/apps/bunmsh/CHANGELOG.md +103 -0
  6. package/initramfs/buninu/apps/bunmsh/PORTING.md +133 -15
  7. package/initramfs/buninu/apps/bunmsh/help/awk.md +38 -0
  8. package/initramfs/buninu/apps/bunmsh/help/break.md +21 -0
  9. package/initramfs/buninu/apps/bunmsh/help/chmod.md +8 -2
  10. package/initramfs/buninu/apps/bunmsh/help/cmp.md +29 -0
  11. package/initramfs/buninu/apps/bunmsh/help/continue.md +22 -0
  12. package/initramfs/buninu/apps/bunmsh/help/cp.md +4 -0
  13. package/initramfs/buninu/apps/bunmsh/help/diff.md +30 -0
  14. package/initramfs/buninu/apps/bunmsh/help/egrep.md +26 -0
  15. package/initramfs/buninu/apps/bunmsh/help/export.md +2 -2
  16. package/initramfs/buninu/apps/bunmsh/help/expr.md +30 -0
  17. package/initramfs/buninu/apps/bunmsh/help/fgrep.md +25 -0
  18. package/initramfs/buninu/apps/bunmsh/help/grep.md +4 -0
  19. package/initramfs/buninu/apps/bunmsh/help/ls.md +4 -2
  20. package/initramfs/buninu/apps/bunmsh/help/mkdir.md +1 -1
  21. package/initramfs/buninu/apps/bunmsh/help/print.md +3 -0
  22. package/initramfs/buninu/apps/bunmsh/help/return.md +23 -0
  23. package/initramfs/buninu/apps/bunmsh/help/sed.md +8 -3
  24. package/initramfs/buninu/apps/bunmsh/help/set.md +12 -3
  25. package/initramfs/buninu/apps/bunmsh/help/tr.md +4 -0
  26. package/initramfs/buninu/apps/bunmsh/help/trap.md +22 -0
  27. package/initramfs/buninu/apps/bunmsh/help/uniq.md +27 -0
  28. package/initramfs/buninu/apps/bunmsh/package.json +1 -1
  29. package/initramfs/buninu/apps/bunmsh/src/awk.js +203 -0
  30. package/initramfs/buninu/apps/bunmsh/src/diff.js +222 -0
  31. package/initramfs/buninu/apps/bunmsh/src/fancy-ls.js +15 -4
  32. package/initramfs/buninu/apps/bunmsh/src/main.js +21 -5
  33. package/initramfs/buninu/apps/bunmsh/src/sed.js +159 -0
  34. package/initramfs/buninu/apps/bunmsh/src/shell.js +1283 -540
  35. package/initramfs/buninu/apps/bunmsh/test/awk-reference.test.js +35 -0
  36. package/initramfs/buninu/apps/bunmsh/test/awk.test.js +62 -0
  37. package/initramfs/buninu/apps/bunmsh/test/posix-bootstrap.test.js +595 -0
  38. package/initramfs/buninu/apps/bunmsh/test/utility-reference-cases.mjs +98 -0
  39. package/initramfs/buninu/apps/bunmsh/test/utility-reference.test.js +23 -0
  40. package/initramfs/buninu/apps/jsgotty/client-kitty.mjs +61 -0
  41. package/initramfs/buninu/apps/jsgotty/client.mjs +16 -0
  42. package/initramfs/buninu/apps/jsgotty/package-lock.json +2 -2
  43. package/initramfs/buninu/apps/jsgotty/package.json +1 -1
  44. package/initramfs/buninu/apps/jsgotty/tests/client-kitty.test.mjs +43 -0
  45. package/initramfs/etc/resolv.conf +2 -1
  46. package/initramfs/usr/lib/bootstrap/1.prepare-rootfs.js +106 -0
  47. package/initramfs/usr/lib/bootstrap/10.build-m4.js +40 -0
  48. package/initramfs/usr/lib/bootstrap/11.build-flex.js +50 -0
  49. package/initramfs/usr/lib/bootstrap/12.build-gcc.js +261 -0
  50. package/initramfs/usr/lib/bootstrap/2.enter-rootfs.js +49 -0
  51. package/initramfs/usr/lib/bootstrap/3.gen-musl-dev.js +141 -0
  52. package/initramfs/usr/lib/bootstrap/4.build-tcc.js +61 -0
  53. package/initramfs/usr/lib/bootstrap/5.build-make.js +58 -0
  54. package/initramfs/usr/lib/bootstrap/6.build-binutils.js +77 -0
  55. package/initramfs/usr/lib/bootstrap/7.build-gmp.js +68 -0
  56. package/initramfs/usr/lib/bootstrap/8.build-mpfr.js +59 -0
  57. package/initramfs/usr/lib/bootstrap/9.build-mpc.js +55 -0
  58. package/initramfs/usr/lib/bootstrap/LICENSE +21 -0
  59. package/initramfs/usr/lib/bootstrap/LICENSES/MIT-ZilchOS-bootstrap-from-tcc.txt +21 -0
  60. package/initramfs/usr/lib/bootstrap/NOTICE.md +65 -0
  61. package/initramfs/usr/lib/bootstrap/README.md +204 -0
  62. package/initramfs/usr/lib/bootstrap/downloads.md +49 -0
  63. package/initramfs/usr/lib/bootstrap/lib/build.js +155 -0
  64. package/initramfs/usr/lib/bootstrap/lib/common.js +134 -0
  65. package/initramfs/usr/lib/bootstrap/lib/compile-object.c +14 -0
  66. package/initramfs/usr/lib/bootstrap/lib/musl-headers.js +59 -0
  67. package/initramfs/usr/lib/bootstrap/lib/seed.js +148 -0
  68. package/initramfs/usr/lib/bootstrap/lib/startup-check.c +14 -0
  69. package/initramfs/usr/lib/bootstrap/lib/tcc-build.js +53 -0
  70. package/initramfs/usr/lib/bootstrap/sources/musl-1.2.6.tar.gz +0 -0
  71. package/initramfs/usr/lib/bootstrap/sources/tinycc-05f0faf-upstream.tar.gz +0 -0
  72. package/initramfs/usr/lib/bootstrap/sources/tinycc-local-bootstrap-files.tar.gz +0 -0
  73. package/initramfs/usr/share/doc/buninu-linux/tar.md +11 -0
  74. package/package.json +1 -1
  75. package/scripts/fetch.js +2 -0
  76. package/test/bootstrap.test.js +65 -0
  77. package/test/tar-strip.test.js +36 -0
@@ -0,0 +1,261 @@
1
+ #!/usr/bin/env bun
2
+ import {
3
+ chmodSync, copyFileSync, cpSync, existsSync, mkdirSync, mkdtempSync,
4
+ readFileSync, readdirSync, renameSync, rmSync, statSync, writeFileSync,
5
+ } from "node:fs";
6
+ import {
7
+ bootstrap, cli, sha256,
8
+ } from "./lib/common.js";
9
+ import {
10
+ buildRoot, command, configure,
11
+ makeIn, patch, deps, ready,
12
+ resultRoot, source, sourceRoot, stage, useLog,
13
+ toolchain, tools,
14
+ } from "./lib/build.js";
15
+
16
+ const gccCommit = "9d2b63d100ae7c99ee8b128fb41086fd85c8f57d";
17
+ // GCC clears MAKEOVERRIDES. Preserve its normal explicit submake flags
18
+ // and append our header-install selection to that forwarding list.
19
+ const headerInstallFlags =
20
+ "FLAGS_TO_PASS=$(BASE_FLAGS_TO_PASS) $(EXTRA_HOST_FLAGS) " +
21
+ "INSTALL_HEADERS_DIR=install-include-dir";
22
+
23
+ async function main(args) {
24
+ const { arch, triple } = stage(
25
+ 12, "gcc", args
26
+ );
27
+ // GCC's ARM vendor 4.7 branch has
28
+ // both the ARM64 and x64 backends.
29
+ // Pin the full commit, not a branch.
30
+ const src = await source(
31
+ "gcc@4.7-9d2b63d",
32
+ "gcc-" + gccCommit
33
+ );
34
+ const build = buildRoot + "/gcc-4.7";
35
+ prepareGcc(src, arch);
36
+ // Install native assembler/linker
37
+ // before building target libgcc.
38
+ installBinutils();
39
+ await configure(src, build, [
40
+ "--build=" + triple,
41
+ "--host=" + triple,
42
+ "--target=" + triple,
43
+ "--prefix=" + resultRoot,
44
+ "--enable-languages=c",
45
+ "--disable-build-with-cxx",
46
+ "--disable-bootstrap",
47
+ "--disable-libquadmath",
48
+ "--disable-decimal-float",
49
+ "--disable-fixed-point",
50
+ "--disable-lto",
51
+ "--disable-libgomp",
52
+ "--disable-multilib",
53
+ "--disable-multiarch",
54
+ "--disable-libmudflap",
55
+ "--disable-libssp",
56
+ "--disable-libitm", "--disable-nls",
57
+ "--disable-werror",
58
+ "--with-gmp=" + deps,
59
+ "--with-mpfr=" + deps,
60
+ "--with-mpc=" + deps,
61
+ "--with-build-time-tools=" +
62
+ toolchain + "/bin",
63
+ "--with-as=" +
64
+ resultRoot + "/bin/as",
65
+ "--with-ld=" +
66
+ resultRoot + "/bin/ld",
67
+ "--with-native-system-header-dir=" +
68
+ "/usr/include",
69
+ ]);
70
+
71
+ // Explicit make assignments avoid
72
+ // cached missing-tool commands.
73
+ await makeIn(build, [
74
+ "M4=" + tools + "/m4",
75
+ "FLEX=" + tools + "/flex", "all",
76
+ ]);
77
+ // Install compiler, headers, CRT
78
+ // support and libgcc into result.
79
+ // Create include directories via
80
+ // Make; copy headers with JS below.
81
+ // No tar pipe or cp -p -r needed.
82
+ await makeIn(build, [
83
+ headerInstallFlags, "install-gcc",
84
+ ]);
85
+ await makeIn(build, [
86
+ "install-target-libgcc",
87
+ ]);
88
+ // libgcc installs unwind.h too.
89
+ // Copy headers last to remove links
90
+ // back into the source tree.
91
+ installCompilerHeaders(
92
+ src, build, triple
93
+ );
94
+ // Test with all intermediate trees
95
+ // hidden, then restore them.
96
+ await verifyGcc(arch, triple);
97
+ ready(
98
+ 12, "GCC 4.7 C compiler + libgcc"
99
+ );
100
+ console.log(
101
+ "Compiler: " +
102
+ resultRoot + "/bin/gcc"
103
+ );
104
+ console.log(
105
+ "Stop: GCC 4.7 milestone reached."
106
+ );
107
+ }
108
+
109
+ function prepareGcc(src, arch) {
110
+ const header = "bootstrap-musl.h";
111
+ const text = `/* Local ordinary Linux-musl bootstrap target settings. */
112
+ #undef GNU_USER_DYNAMIC_LINKER
113
+ #define GNU_USER_DYNAMIC_LINKER "/lib/ld-musl-${arch}.so.1"
114
+ #undef GNU_USER_DYNAMIC_LINKER64
115
+ #define GNU_USER_DYNAMIC_LINKER64 "/lib/ld-musl-${arch}.so.1"
116
+ #undef OPTION_GLIBC
117
+ #define OPTION_GLIBC 0
118
+ #undef TARGET_C99_FUNCTIONS
119
+ #define TARGET_C99_FUNCTIONS 1
120
+ #undef TARGET_HAS_SINCOS
121
+ #define TARGET_HAS_SINCOS 1
122
+ #undef INT_FAST16_TYPE
123
+ #define INT_FAST16_TYPE "int"
124
+ #undef INT_FAST32_TYPE
125
+ #define INT_FAST32_TYPE "int"
126
+ #undef UINT_FAST16_TYPE
127
+ #define UINT_FAST16_TYPE "unsigned int"
128
+ #undef UINT_FAST32_TYPE
129
+ #define UINT_FAST32_TYPE "unsigned int"
130
+ `;
131
+ writeFileSync(src + "/gcc/config/" + header, text);
132
+ const path = src + "/gcc/config.gcc";
133
+ const config = readFileSync(path, "utf8");
134
+ const marker = "# Buninu native musl bootstrap";
135
+ if (!config.includes(marker)) writeFileSync(path, config + `\n${marker}\ncase $target in\n aarch64-*-linux-musl*|x86_64-*-linux-musl*) tm_file="$tm_file ${header}" ;;\nesac\n`);
136
+ patch(src + "/libiberty/regex.c", "# ifdef REGEX_MALLOC\n", "/* TinyCC: use the existing heap allocation path. */\n# if defined __TINYC__ && !defined REGEX_MALLOC\n# define REGEX_MALLOC 1\n# endif\n# ifdef REGEX_MALLOC\n");
137
+ patch(src + "/libiberty/argv.c", '#include "libiberty.h"', '#include <stdlib.h>\n#include "libiberty.h"');
138
+ }
139
+
140
+ function verificationSource(arch) {
141
+ return `#include <stdint.h>
142
+ #include <stdio.h>
143
+ #include <unwind.h>
144
+ #ifdef __gnu_linux__
145
+ #error musl must not claim glibc
146
+ #endif
147
+ #if !defined(__linux__) || !defined(${arch === "aarch64" ? "__aarch64__" : "__x86_64__"})
148
+ #error unexpected target
149
+ #endif
150
+ typedef char fast16[__builtin_types_compatible_p(__INT_FAST16_TYPE__,int_fast16_t)?1:-1];
151
+ typedef char fast32[__builtin_types_compatible_p(__UINT_FAST32_TYPE__,uint_fast32_t)?1:-1];
152
+ static volatile unsigned __int128 large=((unsigned __int128)1<<100)+123,divisor=7;
153
+ int main(void){unsigned __int128 a=large,b=divisor,q=a/b,r=a%b;
154
+ if(q*b+r!=a||r>=b)return 1;
155
+ puts("GCC 4.7 C and libgcc runtime verified");return 0;}
156
+ `;
157
+ }
158
+
159
+ function installCompilerHeaders(src, build, triple) {
160
+ const version = readFileSync(src + "/gcc/BASE-VER", "utf8").trim();
161
+ if (!/^4\.7\.\d+$/.test(version)) throw new Error(`Unexpected GCC version: ${version}`);
162
+ const destination = `${resultRoot}/lib/gcc/${triple}/${version}`;
163
+ for (const name of ["include", "include-fixed"]) {
164
+ const source = `${build}/gcc/${name}`;
165
+ if (!statSync(source).isDirectory()) throw new Error(`Missing GCC headers: ${source}`);
166
+ const target = `${destination}/${name}`;
167
+ // Replace only the generated private header directory. Dereference
168
+ // unwind.h and other source/build links so result survives their removal.
169
+ rmSync(target, { recursive: true, force: true });
170
+ cpSync(source, target, { recursive: true, dereference: true, preserveTimestamps: true });
171
+ }
172
+ }
173
+
174
+ function installBinutils() {
175
+ mkdirSync(resultRoot + "/bin", { recursive: true });
176
+ rmSync(resultRoot + "/verified.json", { force: true });
177
+ for (const name of ["as", "ld", "ar", "ranlib", "nm", "objcopy", "objdump", "readelf", "strip", "size", "strings", "addr2line", "c++filt"]) {
178
+ // Copy bytes, not symlinks into the intermediate toolchain tree.
179
+ const target = resultRoot + "/bin/" + name;
180
+ copyFileSync(toolchain + "/bin/" + name, target);
181
+ chmodSync(target, 0o755);
182
+ }
183
+ const notices = resultRoot + "/share/licenses/bootstrap";
184
+ mkdirSync(notices, { recursive: true });
185
+ copyFileSync(bootstrap + "/NOTICE.md", notices + "/NOTICE.md");
186
+ copyFileSync(bootstrap + "/LICENSE", notices + "/LICENSE");
187
+ cpSync(bootstrap + "/LICENSES", notices + "/LICENSES", { recursive: true });
188
+ // Keep notices with the installed binaries, including static dependencies.
189
+ for (const directory of ["gcc-" + gccCommit, "binutils-2.39", "gmp-4.3.2", "mpfr-2.4.2", "mpc-0.8.1"]) {
190
+ const target = resultRoot + "/share/licenses/" + directory;
191
+ mkdirSync(target, { recursive: true });
192
+ for (const name of readdirSync(sourceRoot + "/" + directory)) {
193
+ if (/^(COPYING|COPYRIGHT|LICENSE)/.test(name) && statSync(sourceRoot + "/" + directory + "/" + name).isFile()) {
194
+ copyFileSync(sourceRoot + "/" + directory + "/" + name, target + "/" + name);
195
+ }
196
+ }
197
+ }
198
+ }
199
+
200
+ async function verifyGcc(arch, triple) {
201
+ const gcc = resultRoot + "/bin/gcc";
202
+ const work = mkdtempSync("/tmp/bootstrap-result-check-");
203
+ const hidden = [];
204
+ // No compiler search-path overrides: exercise the installed defaults.
205
+ const env = {
206
+ PATH: resultRoot + "/bin:/bin:/usr/bin",
207
+ SHELL: "/bin/sh", CONFIG_SHELL: "/bin/sh", CC: gcc,
208
+ LD_LIBRARY_PATH: resultRoot + "/lib:" + resultRoot + "/lib64",
209
+ };
210
+ useLog(resultRoot + "/verification.log");
211
+ try {
212
+ for (const path of [sourceRoot, deps, toolchain, buildRoot]) {
213
+ const backup = path + ".verification-hidden";
214
+ if (existsSync(backup)) throw new Error(`Restore interrupted verification directory first: ${backup} -> ${path}`);
215
+ renameSync(path, backup);
216
+ hidden.push([path, backup]);
217
+ }
218
+ const version = (await command([gcc, "-dumpversion"], work, env, true)).trim();
219
+ if (!/^4\.7\./.test(version)) throw new Error(`Unexpected GCC version: ${version}`);
220
+ for (const name of ["libgcc.a", "libgcc_s.so.1", "crtbegin.o", "crtend.o", "crtbeginS.o", "crtendS.o"]) {
221
+ const path = (await command([gcc, "-print-file-name=" + name], work, env, true)).trim();
222
+ if (!path.startsWith(resultRoot + "/") || !existsSync(path)) throw new Error(`Missing installed support file: ${name}: ${path}`);
223
+ if (name === "libgcc_s.so.1") env.LD_LIBRARY_PATH = path.slice(0, path.lastIndexOf("/")) + ":" + env.LD_LIBRARY_PATH;
224
+ }
225
+ writeFileSync(work + "/verify.c", verificationSource(arch));
226
+ for (const optimization of ["-O0", "-O2"]) {
227
+ await command([gcc, optimization, "verify.c", "-o", "verify-gcc"], work, env);
228
+ const headers = await command([resultRoot + "/bin/readelf", "-l", "verify-gcc"], work, env, true);
229
+ if (!headers.includes(`/lib/ld-musl-${arch}.so.1`)) throw new Error("Wrong musl interpreter");
230
+ await command([work + "/verify-gcc"], work, env);
231
+ }
232
+ // Exercise installed crtbeginS/crtendS and shared libgcc, too.
233
+ writeFileSync(work + "/shared.c", "__int128 divide(__int128 a,__int128 b){return a/b;}\n");
234
+ writeFileSync(work + "/shared-main.c", "extern __int128 divide(__int128,__int128);int main(void){return divide(((__int128)1<<100)+1,7)!=(((__int128)1<<100)+1)/7;}\n");
235
+ await command([gcc, "-shared", "-fPIC", "-shared-libgcc", "shared.c", "-o", "libverify.so"], work, env);
236
+ await command([gcc, "shared-main.c", "-L.", "-lverify", "-Wl,-rpath,$ORIGIN", "-o", "verify-shared"], work, env);
237
+ await command([work + "/verify-shared"], work, env);
238
+ const files = [];
239
+ function inventory(directory, prefix = "") {
240
+ for (const entry of readdirSync(directory, { withFileTypes: true })) {
241
+ const path = prefix + entry.name;
242
+ if (entry.isDirectory()) inventory(directory + "/" + entry.name, path + "/");
243
+ else if (statSync(directory + "/" + entry.name).isFile() && !["verified.json", "verification.log"].includes(path)) {
244
+ const bytes = readFileSync(directory + "/" + entry.name);
245
+ files.push({ path, bytes: bytes.length, sha256: sha256(bytes) });
246
+ }
247
+ }
248
+ }
249
+ inventory(resultRoot);
250
+ writeFileSync(resultRoot + "/verified.json", JSON.stringify({
251
+ version, arch, triple, compiler: gcc, independentOf: hidden.map(([path]) => path),
252
+ requires: ["/usr/include", "/usr/lib", "/lib"], files,
253
+ }, null, 2) + "\n");
254
+ } finally {
255
+ // Restore in reverse order even when a compiler check fails.
256
+ for (const [path, backup] of hidden.reverse()) renameSync(backup, path);
257
+ rmSync(work, { recursive: true, force: true });
258
+ }
259
+ }
260
+
261
+ if (import.meta.main) await cli(main);
@@ -0,0 +1,49 @@
1
+ #!/usr/bin/env bun
2
+ import {
3
+ cli, isBuninuLinux, options, quote,
4
+ } from "./lib/common.js";
5
+
6
+ const archAlias = /^(x|x64|x86_64|x86-64|a|arm64|aarch64)$/;
7
+
8
+ export function printEntry(rootfs = "/path/to/your/rootfs") {
9
+ console.log("\nEnter the rootfs:");
10
+ console.log(isBuninuLinux()
11
+ ? ` chroot ${quote(rootfs)} /bin/sh`
12
+ : ` bun x bunproot -koe -r ${quote(rootfs)}`);
13
+ console.log("Then run inside it:");
14
+ console.log(" cd /bootstrap");
15
+ console.log(" bun 3.gen-musl-dev.js");
16
+ console.log(" bun 4.build-tcc.js");
17
+ }
18
+
19
+ async function main(args) {
20
+ // Print instructions only. No
21
+ // rootfs or marker file is read.
22
+ if (!args.length) {
23
+ printEntry();
24
+ return;
25
+ }
26
+ if (args.includes("--help") ||
27
+ args.includes("-h")) {
28
+ console.log(
29
+ "Usage: bun 2.enter-rootfs.js " +
30
+ "[ARCH] [ROOTFS]"
31
+ );
32
+ console.log(
33
+ "No ROOTFS: print commands " +
34
+ "using /path/to/your/rootfs."
35
+ );
36
+ return;
37
+ }
38
+ // Keep stage 1's argument aliases,
39
+ // but never infer roota or rootx.
40
+ const archOnly = args.length === 1
41
+ && archAlias.test(args[0]);
42
+ const selected = options(archOnly
43
+ ? [...args, "/path/to/your/rootfs"]
44
+ : args);
45
+ if (!selected) return;
46
+ printEntry(selected.rootfs);
47
+ }
48
+
49
+ if (import.meta.main) await cli(main);
@@ -0,0 +1,141 @@
1
+ #!/usr/bin/env bun
2
+ import { cc } from "bun:ffi";
3
+ import {
4
+ mkdtempSync, readFileSync, renameSync,
5
+ rmSync, writeFileSync,
6
+ } from "node:fs";
7
+ import { join } from "node:path";
8
+ import {
9
+ assertAbsent, bootstrap, cli,
10
+ requireRootfs, validateElf,
11
+ } from "./lib/common.js";
12
+ import {
13
+ generateHeaders,
14
+ } from "./lib/musl-headers.js";
15
+
16
+ async function main(args) {
17
+ // Run inside the prepared rootfs.
18
+ // This generates public headers
19
+ // and ordinary dynamic-link CRT.
20
+ // It does not build libc or rcrt1.
21
+ if (args.length) throw new Error(
22
+ "Usage: bun 3.gen-musl-dev.js"
23
+ );
24
+ const { arch } = requireRootfs();
25
+ const names = [
26
+ "crt1.o", "crti.o", "crtn.o",
27
+ ];
28
+ assertAbsent("/usr/include");
29
+ for (const name of names) {
30
+ assertAbsent(`/usr/lib/${name}`);
31
+ }
32
+
33
+ // Follow musl's Makefile rules in
34
+ // JS: public headers, arch bits,
35
+ // alltypes.h and syscall.h.
36
+ console.log(
37
+ "① Generating musl headers"
38
+ );
39
+ generateHeaders(
40
+ arch,
41
+ "/bootstrap/src/musl",
42
+ "/usr/include"
43
+ );
44
+ // chroot mounts /tmp separately;
45
+ // stage objects on the same FS as
46
+ // /usr/lib for the final rename.
47
+ const work = mkdtempSync(
48
+ "/usr/lib/.musl-crt-"
49
+ );
50
+ let compiler;
51
+ try {
52
+ // ARM64 TCC does not handle adrp.
53
+ // Ordinary crt1's _start_c uses
54
+ // x0, not x1 (_DYNAMIC). Omit just
55
+ // that unused argument in a
56
+ // temporary header override.
57
+ // Keep musl sources untouched.
58
+ if (arch === "aarch64") {
59
+ prepareArm64Startup(work);
60
+ }
61
+
62
+ // Bun.cc builds libtcc.c in memory
63
+ // without standalone cc or CRT.
64
+ // TCC_OUTPUT_OBJ emits the three
65
+ // relocatable startup objects.
66
+ console.log(
67
+ "② Building CRT with Bun.cc"
68
+ );
69
+ compiler = cc({
70
+ source: join(
71
+ bootstrap,
72
+ "lib/compile-object.c"
73
+ ),
74
+ library: ["gcc_s"],
75
+ flags: ["-L/usr/lib", "-L/lib"],
76
+ include: [
77
+ "/bootstrap/src/tinycc",
78
+ "/bootstrap/src/tinycc/include",
79
+ "/usr/include",
80
+ ],
81
+ symbols: {
82
+ compile_object: {
83
+ args: [
84
+ "cstring", "cstring",
85
+ "cstring",
86
+ ],
87
+ returns: "int",
88
+ },
89
+ },
90
+ });
91
+ compileCrt(
92
+ compiler, arch, work, names
93
+ );
94
+ for (const name of names) {
95
+ renameSync(
96
+ join(work, name),
97
+ `/usr/lib/${name}`
98
+ );
99
+ }
100
+ console.log(
101
+ "Ready: musl headers and CRT."
102
+ );
103
+ console.log(
104
+ "Next: bun " +
105
+ "/bootstrap/" +
106
+ "4.build-tcc.js"
107
+ );
108
+ } finally {
109
+ compiler?.close();
110
+ rmSync(work, {
111
+ recursive: true, force: true,
112
+ });
113
+ }
114
+ }
115
+
116
+ function prepareArm64Startup(work) {
117
+ const original = readFileSync("/bootstrap/src/musl/arch/aarch64/crt_arch.h", "utf8");
118
+ const lines = original.split("\n");
119
+ const removed = lines.filter(line => line.includes("_DYNAMIC"));
120
+ if (removed.length !== 4 || !removed.some(line => line.includes("adrp x1"))) {
121
+ throw new Error("Unexpected musl ARM64 startup code; refusing compatibility edit");
122
+ }
123
+ writeFileSync(join(work, "crt_arch.h"), lines.filter(line => !line.includes("_DYNAMIC")).join("\n"));
124
+ }
125
+
126
+ function compileCrt(compiler, arch, work, names) {
127
+ const z = text => Buffer.from(text + "\0");
128
+ const flags = `-nostdinc -DCRT -D_XOPEN_SOURCE=700 -I${work} -I/bootstrap/src/musl/arch/${arch} -I/bootstrap/src/musl/arch/generic -I/bootstrap/src/musl/src/include -I/bootstrap/src/musl/src/internal -I/usr/include -I/bootstrap/src/tinycc/include`;
129
+ for (const name of names) {
130
+ const source = name === "crt1.o" ? "/bootstrap/src/musl/crt/crt1.c" : `/bootstrap/src/musl/crt/${arch}/${name.slice(0, -2)}.s`;
131
+ const output = join(work, name);
132
+ console.log(`${source} -> /usr/lib/${name}`);
133
+ const result = compiler.symbols.compile_object(z(source), z(output), z(flags));
134
+ if (result) throw new Error(`${name}: TinyCC returned ${result}`);
135
+ const bytes = readFileSync(output);
136
+ validateElf(name, bytes, arch);
137
+ if (bytes.readUInt16LE(16) !== 1) throw new Error(`${name} is not a relocatable ELF object`);
138
+ }
139
+ }
140
+
141
+ if (import.meta.main) await cli(main);
@@ -0,0 +1,61 @@
1
+ #!/usr/bin/env bun
2
+ import { readFileSync } from "node:fs";
3
+ import { join } from "node:path";
4
+ import {
5
+ bootstrap, cli, requireRootfs, run,
6
+ validateElf,
7
+ } from "./lib/common.js";
8
+ import {
9
+ buildTcc,
10
+ } from "./lib/tcc-build.js";
11
+
12
+ async function main(args) {
13
+ // Stage 3 must have generated
14
+ // headers and the three CRT files.
15
+ if (args.length) throw new Error(
16
+ "Usage: bun 4.build-tcc.js"
17
+ );
18
+ const { arch } = requireRootfs();
19
+ for (const name of [
20
+ "crt1.o", "crti.o", "crtn.o",
21
+ ]) {
22
+ validateElf(
23
+ name,
24
+ readFileSync(`/usr/lib/${name}`),
25
+ arch
26
+ );
27
+ }
28
+
29
+ // Bun.cc -> standalone stage1 ->
30
+ // stage2, then compare bytes.
31
+ // Build x64 runtime helpers when
32
+ // needed and test /bin/cc.
33
+ await buildTcc();
34
+
35
+ // Exercise the generated CRT:
36
+ // argv, env, constructors,
37
+ // destructors and exit status.
38
+ await verifyStartup();
39
+ console.log(
40
+ "Ready: cc source.c -o program"
41
+ );
42
+ console.log(
43
+ "Next: bun /bootstrap/" +
44
+ "5.build-make.js"
45
+ );
46
+ }
47
+
48
+ async function verifyStartup() {
49
+ const output = "/bootstrap/build/tinycc/startup-check";
50
+ await run(["/bin/cc", join(bootstrap, "lib/startup-check.c"), "-o", output]);
51
+ const child = Bun.spawn([output, "hello", "two words"], {
52
+ env: { PATH: "/bin:/usr/bin", CRT_TEST: "seed-free" }, stdout: "pipe", stderr: "inherit",
53
+ });
54
+ const stdout = await new Response(child.stdout).text();
55
+ if (await child.exited !== 42 || stdout !== "argc/argv, environment, constructor OK\ndestructor OK\n") {
56
+ throw new Error(`CRT startup check failed: ${stdout}`);
57
+ }
58
+ console.log(stdout + "exit status 42: OK");
59
+ }
60
+
61
+ if (import.meta.main) await cli(main);
@@ -0,0 +1,58 @@
1
+ #!/usr/bin/env bun
2
+ import {
3
+ chmodSync, copyFileSync,
4
+ } from "node:fs";
5
+ import { cli } from "./lib/common.js";
6
+ import {
7
+ buildRoot, command, configure,
8
+ installAdapters, makeIn, patch,
9
+ ready, shell, source, stage, tools,
10
+ } from "./lib/build.js";
11
+
12
+ async function main(args) {
13
+ const { triple } = stage(
14
+ 5, "make", args
15
+ );
16
+ installAdapters();
17
+ const src = await source(
18
+ "make@4.4.1", "make-4.4.1"
19
+ );
20
+ const build = buildRoot + "/make";
21
+ prepareMake(src);
22
+ await configure(src, build, [
23
+ "--build=" + triple,
24
+ "--prefix=/bootstrap/toolchain",
25
+ "--disable-dependency-tracking",
26
+ "--without-guile", "--disable-nls",
27
+ ]);
28
+
29
+ // GNU Make provides its own
30
+ // no-make shell bootstrap builder.
31
+ await command(
32
+ [shell, src + "/build.sh"],
33
+ build
34
+ );
35
+ copyFileSync(
36
+ build + "/make", tools + "/make"
37
+ );
38
+ chmodSync(tools + "/make", 0o755);
39
+ await makeIn(build, ["clean"]);
40
+ await makeIn(build);
41
+ copyFileSync(
42
+ build + "/make", tools + "/make"
43
+ );
44
+ await command(
45
+ [tools + "/make", "--version"]
46
+ );
47
+ ready(5, "GNU Make self-rebuild");
48
+ }
49
+
50
+ function prepareMake(src) {
51
+ patch(src + "/build.sh", ' LIBOBJS="${LIBOBJS:+$LIBOBJS }lib/$lo"',
52
+ ' lo=${lo#\'${LIBOBJDIR}\'}\n LIBOBJS="${LIBOBJS:+$LIBOBJS }lib/$lo"');
53
+ patch(src + "/src/mkcustom.h", "char *alloca ();", "void *alloca ();");
54
+ patch(src + "/lib/glob.c", "extern char *alloca ();", "extern void *alloca ();");
55
+ patch(src + "/lib/alloca.c", "memory_full ();", "abort ();");
56
+ }
57
+
58
+ if (import.meta.main) await cli(main);
@@ -0,0 +1,77 @@
1
+ #!/usr/bin/env bun
2
+ import {
3
+ existsSync, readdirSync,
4
+ readFileSync, statSync,
5
+ copyFileSync, writeFileSync,
6
+ } from "node:fs";
7
+ import { cli } from "./lib/common.js";
8
+ import {
9
+ buildRoot, command, configure,
10
+ makeIn, ready, source, stage,
11
+ toolchain, tools,
12
+ } from "./lib/build.js";
13
+
14
+ async function main(args) {
15
+ const { arch, triple } = stage(
16
+ 6, "binutils", args
17
+ );
18
+ const src = await source(
19
+ "binutils@2.39", "binutils-2.39"
20
+ );
21
+ const build = buildRoot + "/binutils";
22
+ const env = {
23
+ CFLAGS: "-O2 -D__LITTLE_ENDIAN__=1",
24
+ };
25
+ await configure(src, build, [
26
+ "--build=" + triple,
27
+ "--host=" + triple,
28
+ "--target=" + triple,
29
+ "--prefix=" + toolchain,
30
+ "--disable-nls", "--disable-werror",
31
+ "--disable-gprofng",
32
+ "--disable-gold", "--disable-gdb",
33
+ "--disable-sim", "--disable-libctf",
34
+ "--disable-shared",
35
+ "--disable-multilib",
36
+ "--disable-dependency-tracking",
37
+ "--without-debuginfod",
38
+ "--without-zstd",
39
+ ], env);
40
+ await makeIn(build, ["all"], env);
41
+ restoreManpages(src, build);
42
+ await makeIn(build, ["install"], env);
43
+ await runtime(arch);
44
+ await command([
45
+ toolchain + "/bin/as", "--version",
46
+ ]);
47
+ await command([
48
+ toolchain + "/bin/ld", "--version",
49
+ ]);
50
+ ready(6, "Binutils and TCC runtime");
51
+ }
52
+
53
+ function restoreManpages(src, build) {
54
+ for (const dir of ["gas/doc", "binutils/doc", "ld", "gprof"]) {
55
+ for (const name of readdirSync(src + "/" + dir).filter(n => n.endsWith(".1"))) {
56
+ const target = `${build}/${dir}/${name}`;
57
+ if (existsSync(target) && statSync(target).size === 0) copyFileSync(`${src}/${dir}/${name}`, target);
58
+ }
59
+ }
60
+ }
61
+
62
+ async function runtime(arch) {
63
+ const cwd = buildRoot + "/tcc-runtime";
64
+ if (arch === "aarch64") {
65
+ await command([tools + "/cc", "-c", "/bootstrap/src/tinycc/lib/lib-arm64.c", "-o", "lib-arm64.o"], cwd);
66
+ await command([toolchain + "/bin/ar", "rcs", toolchain + "/lib/tcc/libbootstrap-tcc-arm64.a", "lib-arm64.o"], cwd);
67
+ }
68
+ const code = `static volatile long double a=1.5L,b=2.0L;
69
+ int main(void){long double x=a,y=b;return x*y!=3.0L||x/y!=0.75L||x+y!=3.5L||x-y!=-0.5L||!(x<y)||(double)(x*y)!=3.0;}`;
70
+ // command() creates the working directory before compilation.
71
+ await command([toolchain + "/bin/ar", "--version"], cwd);
72
+ writeFileSync(cwd + "/quad.c", code);
73
+ await command([tools + "/cc", "quad.c", "-o", "quad"], cwd);
74
+ await command([cwd + "/quad"], cwd);
75
+ }
76
+
77
+ if (import.meta.main) await cli(main);