85 lines
3.8 KiB
TypeScript
85 lines
3.8 KiB
TypeScript
/**
|
|
* Generates `${codegenDir}/build_options.rs` — Rust constants derived from
|
|
* `Config`, `include!()`'d by `bun_core::build_options`.
|
|
*
|
|
* Replaces the `option_env!("BUN_*")` handshake (a dozen env vars exported
|
|
* by `rust.ts`, read back in `bun_core`). `Config` is now the single source
|
|
* of truth: literal `pub const`s land on disk, so a bare `cargo check` /
|
|
* rust-analyzer sees the real version/sha/paths instead of placeholder
|
|
* defaults, and the env-var name list isn't maintained in two places.
|
|
*
|
|
* `bun_core/build.rs` emits `rerun-if-changed` on the file; `writeIfChanged`
|
|
* keeps the mtime stable so a reconfigure with the same sha doesn't
|
|
* recompile `bun_core` and its dependents.
|
|
*
|
|
* Target-dependent constants (`ENABLE_TINYCC`, `ENABLE_ASAN`, `ENABLE_LOGS`)
|
|
* stay as `cfg!()` expressions inside the generated file rather than literals
|
|
* so a `cargo check --target <other-triple>` against the same generated file
|
|
* still evaluates them per-target.
|
|
*
|
|
* Written at configure time alongside `depVersionsHeader.ts` /
|
|
* `cargo-config.ts` — it's a constant manifest, not a build edge.
|
|
*/
|
|
|
|
import { mkdirSync } from "node:fs";
|
|
import { resolve } from "node:path";
|
|
import type { Config } from "./config.ts";
|
|
import { writeIfChanged } from "./fs.ts";
|
|
|
|
/** Rust string literal for `s`. JSON escaping is a strict subset of Rust's. */
|
|
const rstr = (s: string): string => JSON.stringify(s);
|
|
/**
|
|
* Rust `&[u8]` literal for `s`. Goes via a UTF-8 string literal +
|
|
* `.as_bytes()` rather than `b"..."` so non-ASCII paths (e.g. a Windows
|
|
* checkout under `C:\Users\Müller\`) survive — Rust byte-string literals are
|
|
* ASCII-only and `JSON.stringify` would pass the `ü` through verbatim.
|
|
*/
|
|
const rbstr = (s: string): string => `${JSON.stringify(s)}.as_bytes()`;
|
|
|
|
export function generateBuildOptionsRs(cfg: Config): string {
|
|
const outPath = resolve(cfg.codegenDir, "build_options.rs");
|
|
const [major, minor, patch] = cfg.version.split(".");
|
|
|
|
const lines: string[] = [
|
|
"// Generated by scripts/build/buildOptionsRs.ts from `Config` at configure",
|
|
"// time. Do not edit. Regenerate with `bun bd`.",
|
|
"",
|
|
`pub const SHA: &str = ${rstr(cfg.revision)};`,
|
|
`pub const REPORTED_NODEJS_VERSION: &str = ${rstr(cfg.nodejsVersion)};`,
|
|
`pub const RELEASE_SAFE: bool = ${cfg.assertions};`,
|
|
`pub const IS_CANARY: bool = ${cfg.canary};`,
|
|
`pub const CANARY_REVISION: &str = ${rstr(cfg.canaryRevision)};`,
|
|
`pub const ENABLE_FUZZILLI: bool = ${cfg.fuzzilli};`,
|
|
`pub const FALLBACK_HTML_VERSION: &str = "0000000000000000";`,
|
|
"pub const VERSION: crate::Version = crate::Version {",
|
|
` major: ${Number(major)},`,
|
|
` minor: ${Number(minor)},`,
|
|
` patch: ${Number(patch)},`,
|
|
"};",
|
|
`pub const BASE_PATH: &[u8] = ${rbstr(cfg.cwd)};`,
|
|
`pub const CODEGEN_PATH: &[u8] = ${rbstr(cfg.codegenDir)};`,
|
|
"",
|
|
"// Target/profile-derived — kept as `cfg!()` so cross-target",
|
|
"// `cargo check` evaluates per-triple. Values agree with `Config`:",
|
|
"// rust.ts sets `--cfg=bun_debug` ⇔ `cfg.debug`, `--cfg=bun_asan` ⇔",
|
|
"// `cfg.asan`, and `cfg.tinycc`'s default (config.ts) is the negation",
|
|
"// of this predicate.",
|
|
"pub const ENABLE_LOGS: bool = cfg!(bun_debug);",
|
|
"pub const ENABLE_ASAN: bool = cfg!(bun_asan);",
|
|
"pub const ENABLE_TINYCC: bool = !cfg!(any(",
|
|
` target_os = "android",`,
|
|
` target_os = "freebsd",`,
|
|
"));",
|
|
"",
|
|
];
|
|
|
|
// Generated file self-opts-out of the workspace's denied unused lints. It is
|
|
// `include!`d, where inner attributes are rejected, so tag each item.
|
|
const allow = "#[allow(dead_code, unreachable_pub, unused)]";
|
|
const withAllow = lines.flatMap(l => (l.startsWith("pub const ") ? [allow, l] : [l]));
|
|
|
|
mkdirSync(cfg.codegenDir, { recursive: true });
|
|
writeIfChanged(outPath, withAllow.join("\n"));
|
|
return outPath;
|
|
}
|