buninu-linux 0.9.56 → 0.11.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 (50) hide show
  1. package/LICENSES/MIT-ZilchOS-bootstrap-from-tcc.txt +21 -0
  2. package/NOTICE.md +48 -2
  3. package/README.md +81 -12
  4. package/initramfs/bin/buninu-land +26 -0
  5. package/initramfs/bin/chroot +68 -47
  6. package/initramfs/buninu/CHANGELOG.md +22 -0
  7. package/initramfs/buninu/apps/jsgotty/package-lock.json +2 -2
  8. package/initramfs/buninu/apps/jsgotty/package.json +1 -1
  9. package/initramfs/buninu/apps/jsgotty/static/js/gotty.js +1 -0
  10. package/initramfs/buninu/package.json +1 -1
  11. package/initramfs/lib/bunterm/geometry.js +15 -0
  12. package/initramfs/lib/bunterm/pointer-report.js +10 -0
  13. package/initramfs/lib/bunterm/terminal.js +5 -4
  14. package/initramfs/lib/chroot-options.js +69 -0
  15. package/initramfs/usr/lib/bootstrap/1.prepare-rootfs.js +106 -0
  16. package/initramfs/usr/lib/bootstrap/10.build-m4.js +40 -0
  17. package/initramfs/usr/lib/bootstrap/11.build-flex.js +50 -0
  18. package/initramfs/usr/lib/bootstrap/12.build-gcc.js +261 -0
  19. package/initramfs/usr/lib/bootstrap/2.enter-rootfs.js +49 -0
  20. package/initramfs/usr/lib/bootstrap/3.gen-musl-dev.js +141 -0
  21. package/initramfs/usr/lib/bootstrap/4.build-tcc.js +61 -0
  22. package/initramfs/usr/lib/bootstrap/5.build-make.js +58 -0
  23. package/initramfs/usr/lib/bootstrap/6.build-binutils.js +77 -0
  24. package/initramfs/usr/lib/bootstrap/7.build-gmp.js +68 -0
  25. package/initramfs/usr/lib/bootstrap/8.build-mpfr.js +59 -0
  26. package/initramfs/usr/lib/bootstrap/9.build-mpc.js +55 -0
  27. package/initramfs/usr/lib/bootstrap/LICENSE +21 -0
  28. package/initramfs/usr/lib/bootstrap/LICENSES/MIT-ZilchOS-bootstrap-from-tcc.txt +21 -0
  29. package/initramfs/usr/lib/bootstrap/NOTICE.md +65 -0
  30. package/initramfs/usr/lib/bootstrap/README.md +204 -0
  31. package/initramfs/usr/lib/bootstrap/downloads.md +49 -0
  32. package/initramfs/usr/lib/bootstrap/lib/build.js +155 -0
  33. package/initramfs/usr/lib/bootstrap/lib/common.js +134 -0
  34. package/initramfs/usr/lib/bootstrap/lib/compile-object.c +14 -0
  35. package/initramfs/usr/lib/bootstrap/lib/musl-headers.js +59 -0
  36. package/initramfs/usr/lib/bootstrap/lib/seed.js +148 -0
  37. package/initramfs/usr/lib/bootstrap/lib/startup-check.c +14 -0
  38. package/initramfs/usr/lib/bootstrap/lib/tcc-build.js +53 -0
  39. package/initramfs/usr/lib/bootstrap/sources/musl-1.2.6.tar.gz +0 -0
  40. package/initramfs/usr/lib/bootstrap/sources/tinycc-05f0faf-upstream.tar.gz +0 -0
  41. package/initramfs/usr/lib/bootstrap/sources/tinycc-local-bootstrap-files.tar.gz +0 -0
  42. package/initramfs/usr/share/doc/buninu-linux/bunterm.md +4 -1
  43. package/initramfs/usr/share/doc/buninu-linux/chroot.md +37 -3
  44. package/package.json +1 -1
  45. package/scripts/npm-packages.md +8 -3
  46. package/test/bootstrap.test.js +65 -0
  47. package/test/bunterm-pixelmouse.test.js +27 -0
  48. package/test/chroot-bind.test.js +70 -0
  49. package/test/fetch-npm.test.js +2 -2
  50. package/test/stage-npm.test.js +42 -1
@@ -0,0 +1,69 @@
1
+ import { realpathSync, statSync, lstatSync, readlinkSync } from 'node:fs';
2
+ import { posix, resolve } from 'node:path';
3
+
4
+ export function parseChrootArguments(argv, env = process.env) {
5
+ const options = { mount: true, keep: false, verbose: false, binds: [] };
6
+ let positional = [];
7
+ for (let i = 0; i < argv.length; i++) {
8
+ const arg = argv[i];
9
+ if (arg === '--') { positional = argv.slice(i + 1); break; }
10
+ if (arg === '-h' || arg === '--help') return { options, positional, help: true };
11
+ if (arg === '-n' || arg === '--no-mount') options.mount = false;
12
+ else if (arg === '-k' || arg === '--keep-mounts') options.keep = true;
13
+ else if (arg === '-v' || arg === '--verbose') options.verbose = true;
14
+ else if (arg === '-b' || arg === '--bind') {
15
+ if (++i >= argv.length || !argv[i] || argv[i].startsWith('-')) throw Error(`${arg} requires HOST[:GUEST]`);
16
+ options.binds.push(argv[i]);
17
+ } else if (arg.startsWith('--bind=')) {
18
+ if (!arg.slice(7)) throw Error('--bind requires HOST[:GUEST]');
19
+ options.binds.push(arg.slice(7));
20
+ } else if (arg === '--shared-tmp') {
21
+ if (!env.TMPDIR) throw Error('--shared-tmp requires TMPDIR to be set');
22
+ options.binds.push(`${env.TMPDIR}:/tmp`);
23
+ } else if (arg.startsWith('-') && arg.length > 1) throw Error(`unknown option ${arg}`);
24
+ else { positional = argv.slice(i); break; }
25
+ }
26
+ return { options, positional, help: false };
27
+ }
28
+
29
+ export function resolveBindings(specs, cwd = process.cwd()) {
30
+ const bindings = new Map();
31
+ for (const spec of specs) {
32
+ const colon = spec.indexOf(':');
33
+ const host = colon < 0 ? spec : spec.slice(0, colon);
34
+ const guest = colon < 0 ? resolve(cwd, host) : spec.slice(colon + 1);
35
+ if (!host || !guest || host.includes('\0') || guest.includes('\0')) throw Error(`invalid bind: ${spec}`);
36
+ if (!posix.isAbsolute(guest)) throw Error(`bind guest path must be absolute: ${guest}`);
37
+ const inside = posix.normalize(guest);
38
+ if (inside === '/') throw Error('bind destination must not replace the chroot root');
39
+ const source = realpathSync(resolve(cwd, host));
40
+ bindings.set(inside, { inside, source, file: !statSync(source).isDirectory() });
41
+ }
42
+ // Parents must be mounted before children. For a repeated destination, the
43
+ // last argument wins, including --shared-tmp versus an explicit /tmp bind.
44
+ return [...bindings.values()].sort((a, b) => a.inside.split('/').length - b.inside.split('/').length);
45
+ }
46
+
47
+ // Resolve guest symlinks as chroot would: absolute links start at NEWROOT,
48
+ // never at the host's /. Missing suffixes are created by the mount caller.
49
+ export function resolveGuestPath(root, inside) {
50
+ const todo = inside.split('/'), parts = [];
51
+ let links = 0;
52
+ while (todo.length) {
53
+ const part = todo.shift();
54
+ if (!part || part === '.') continue;
55
+ if (part === '..') { parts.pop(); continue; }
56
+ const candidate = `${root}/${[...parts, part].join('/')}`;
57
+ let entry;
58
+ try { entry = lstatSync(candidate); }
59
+ catch (error) { if (error.code !== 'ENOENT') throw error; }
60
+ if (entry?.isSymbolicLink()) {
61
+ if (++links > 40) throw Error(`too many symlinks in bind destination: ${inside}`);
62
+ const target = readlinkSync(candidate);
63
+ if (target.startsWith('/')) parts.length = 0;
64
+ todo.unshift(...target.split('/'));
65
+ } else parts.push(part);
66
+ }
67
+ if (!parts.length) throw Error('bind destination resolves to the chroot root');
68
+ return '/' + parts.join('/');
69
+ }
@@ -0,0 +1,106 @@
1
+ #!/usr/bin/env bun
2
+ import { mkdtempSync, rmSync, statSync } from "node:fs";
3
+ import { tmpdir } from "node:os";
4
+ import { dirname, join } from "node:path";
5
+ import {
6
+ assertAbsent, cli, isBuninuLinux,
7
+ normalizeArch, options,
8
+ } from "./lib/common.js";
9
+ import {
10
+ installSources, localSeed,
11
+ releaseSeed, sourceArchives,
12
+ validateSeed, writeSeed,
13
+ } from "./lib/seed.js";
14
+ import { printEntry } from "./2.enter-rootfs.js";
15
+
16
+ async function main(args) {
17
+ // Optional arguments: ARCH ROOTFS.
18
+ // ARCH defaults to this Bun's CPU.
19
+ // ROOTFS defaults to roota / rootx
20
+ // in the current working directory.
21
+ const selected = options(args);
22
+ if (!selected) return;
23
+ const { arch, rootfs } = selected;
24
+ assertAbsent(rootfs);
25
+ const parent = statSync(
26
+ dirname(rootfs)
27
+ );
28
+ if (!parent.isDirectory()) {
29
+ throw new Error(
30
+ "ROOTFS parent must exist"
31
+ );
32
+ }
33
+
34
+ // Bundled musl 1.2.6 + TinyCC +
35
+ // overlay; verify before any writes.
36
+ // No musl-dev APK is required.
37
+ const archives = sourceArchives();
38
+ const work = mkdtempSync(
39
+ join(tmpdir(), "buninu-bootstrap-")
40
+ );
41
+ try {
42
+ // Local mode reads /etc/os-release
43
+ // ID=buninu-linux, then copies:
44
+ // /bin/bun, /lib/ld-musl-*.so.1,
45
+ // libgcc_s.so.1, libstdc++.so.6,
46
+ // resolv.conf, tar, unzip, env,
47
+ // their JS helpers and bunmsh.
48
+ // Resolve links to copy real data.
49
+ const local = isBuninuLinux()
50
+ && arch === normalizeArch(
51
+ process.arch
52
+ );
53
+ console.log(
54
+ "① Preparing runtime and tools " +
55
+ (local ? "from this Buninu Linux"
56
+ : "from buninu-linux@0.9.56")
57
+ );
58
+
59
+ // Otherwise fetch npm 0.9.56:
60
+ // native/<arch>/lib -> rootfs libs
61
+ // initramfs tools -> same paths.
62
+ // Fetch musl Bun 1.4.2 ZIP for
63
+ // the selected arch -> /bin/bun.
64
+ // URLs + SHA-256: downloads.md,
65
+ // parsed as YAML, like the repo's
66
+ // scripts/npm-packages.md.
67
+ const files = local
68
+ ? localSeed(arch)
69
+ : await releaseSeed(arch, work);
70
+ if (local) console.log(
71
+ "② Reusing system musl-bun"
72
+ );
73
+ validateSeed(files, arch);
74
+ writeSeed(
75
+ rootfs, arch, files,
76
+ local ? "local" : "npm@0.9.56"
77
+ );
78
+
79
+ // Extract musl and TinyCC into
80
+ // /bootstrap/src. The overlay
81
+ // adds build recipes and /bin/cc.
82
+ // Stage 3 already needs TinyCC
83
+ // source to generate CRT objects.
84
+ // Copy stages 1–12 and helpers to
85
+ // /bootstrap in rootfs.
86
+ console.log(
87
+ "③ Extracting musl, TinyCC " +
88
+ "and bootstrap overlay sources"
89
+ );
90
+ await installSources(
91
+ rootfs, archives
92
+ );
93
+ console.log(
94
+ `Prepared ${arch}: ${rootfs}`
95
+ );
96
+ printEntry(rootfs);
97
+ } finally {
98
+ // Preserve a partially written
99
+ // rootfs for inspection on error.
100
+ rmSync(work, {
101
+ recursive: true, force: true,
102
+ });
103
+ }
104
+ }
105
+
106
+ if (import.meta.main) await cli(main);
@@ -0,0 +1,40 @@
1
+ #!/usr/bin/env bun
2
+ import { writeFileSync } from "node:fs";
3
+ import { cli } from "./lib/common.js";
4
+ import {
5
+ buildRoot, command, configure,
6
+ makeIn, ready, source, stage, tools,
7
+ } from "./lib/build.js";
8
+
9
+ async function main(args) {
10
+ const { triple } = stage(
11
+ 10, "m4", args
12
+ );
13
+ const src = await source(
14
+ "m4@1.4.18", "m4-1.4.18"
15
+ );
16
+ const build = buildRoot + "/m4";
17
+ await configure(src, build, [
18
+ "--build=" + triple,
19
+ "--host=" + triple,
20
+ "--prefix=/bootstrap/toolchain",
21
+ "--disable-dependency-tracking",
22
+ ]);
23
+ await makeIn(build);
24
+ await makeIn(build, ["install"]);
25
+ writeFileSync(
26
+ build + "/verify.m4",
27
+ "define(`square',`eval($1*$1)')" +
28
+ "square(12)\n"
29
+ );
30
+ const output = await command(
31
+ [tools + "/m4", "verify.m4"],
32
+ build, {}, true
33
+ );
34
+ if (output.trim() !== "144") {
35
+ throw new Error("m4 check failed");
36
+ }
37
+ ready(10, "GNU m4 expansion");
38
+ }
39
+
40
+ if (import.meta.main) await cli(main);
@@ -0,0 +1,50 @@
1
+ #!/usr/bin/env bun
2
+ import { writeFileSync } from "node:fs";
3
+ import { cli } from "./lib/common.js";
4
+ import {
5
+ buildRoot, command, configure,
6
+ makeIn, ready, source, stage, tools,
7
+ } from "./lib/build.js";
8
+
9
+ async function main(args) {
10
+ const { triple } = stage(
11
+ 11, "flex", args
12
+ );
13
+ const src = await source(
14
+ "flex@2.6.4", "flex-2.6.4"
15
+ );
16
+ const build = buildRoot + "/flex";
17
+ const env = { M4: tools + "/m4" };
18
+ await configure(src, build, [
19
+ "--build=" + triple,
20
+ "--host=" + triple,
21
+ "--prefix=/bootstrap/toolchain",
22
+ "--disable-nls",
23
+ "--disable-dependency-tracking",
24
+ "--disable-shared",
25
+ ], env);
26
+ await makeIn(
27
+ build, ["-C", "src"], env
28
+ );
29
+ await makeIn(
30
+ build, ["-C", "src", "install"],
31
+ env
32
+ );
33
+ await verifyLexer(build, env);
34
+ ready(11, "Flex generated lexer");
35
+ }
36
+
37
+ async function verifyLexer(build, env) {
38
+ writeFileSync(build + "/verify.l", `%option noyywrap
39
+ %%
40
+ [0-9]+ return 7;
41
+ . return 1;
42
+ %%
43
+ int main(void){yy_scan_string("123");return yylex()!=7;}
44
+ `);
45
+ await command([tools + "/flex", "-o", "verify.c", "verify.l"], build, env);
46
+ await command([tools + "/cc", "verify.c", "-o", "verify-flex"], build, env);
47
+ await command([build + "/verify-flex"], build, env);
48
+ }
49
+
50
+ if (import.meta.main) await cli(main);
@@ -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);