P5.6 (macOS): default_pipeline drives bundling; fix issue 0125 (array-format blowup)
build.sx now `#import`s the sx bundler and `default_pipeline` delegates to its
`bundle_main` when a bundle was requested (emit + link, then wrap the binary into
the `.app`/`.apk`); otherwise it just emit+links via the shared `emit_and_link`
core. The Zig `--bundle`/`post_link_module` dispatch shim is removed — the CLI
bundle flags only feed `BuildConfig`, and `default_pipeline` branches on
`bundle_path()`. Validated end-to-end on macOS: `sx build --bundle App.app
--bundle-id … foo.sx` on a plain program AND auto-bundle from `set_bundle_path`
both produce a valid signed `.app` (correct `Contents/MacOS/` layout, Info.plist,
passes `codesign`, binary runs). Also fixed a pre-existing host-build bug:
target_triple was left empty for host builds → `is_macos()` false → wrong flat
layout; main.zig now exposes the host triple when `--target` is absent.
bundle_main no longer re-calls `build_options()` (the handle is already its `opts`
param).
Fix issue 0125 (root cause): the type-match dispatcher unboxed each interned array
tag to the concrete array type — a whole-array load — and passed it to
`array_to_string` by value, which LLVM scalarized into one SelectionDAG node per
element (~12s / segfault at [65536]u8). The bundler's `format("…{}…")` instantiates
`any_to_string`, so importing it into the prelude surfaced 0125 for any large-array
program. Fix (route 1): `any_to_string`'s `case array:` arm calls `slice_to_string`,
and `lowerRuntimeDispatchCall` detects an ARRAY tag bound to a SLICE param and builds
a `{ptr,len}` slice VIEW of the payload pointer (`unbox_any → [*]elem` is an
int-to-ptr with NO load, paired with the array length) instead of loading the array.
Output is byte-identical (`[a, b, c]`). Pinned as
examples/0056-basic-large-array-format-no-blowup.sx; 0055 drops 12s → 0.2s.
37 `.ir` snapshots regenerated (build.sx now pulls in the bundler's types + the
array-format lowering changed); verified `.ir`-only, zero behavior-stream diffs.
705/0 both gates.
This commit is contained in:
@@ -3,6 +3,11 @@
|
||||
// tail imports cli.sx which imports this file) is handled by the resolver.
|
||||
#import "modules/std.sx";
|
||||
#import "modules/compiler.sx";
|
||||
// The sx-side `.app`/`.apk` bundler. `default_pipeline` delegates to its
|
||||
// `bundle_main` when a bundle was requested. The bundler is `abi(.compiler)`
|
||||
// (comptime-only, never emitted into the binary), and the build↔bundle import
|
||||
// cycle resolves like the std↔build one.
|
||||
#import "modules/platform/bundle.sx";
|
||||
|
||||
OperatingSystem :: enum { macos; linux; windows; wasm; ios; android; unknown; }
|
||||
Architecture :: enum { aarch64; x86_64; wasm32; wasm64; unknown; }
|
||||
@@ -112,18 +117,34 @@ on_build :: (cb: (opt: BuildOptions) -> bool abi(.compiler)) abi(.compiler);
|
||||
|
||||
// ── The default build script ────────────────────────────────────────────────
|
||||
//
|
||||
// `default_pipeline` is the stdlib build driver: the compiler invokes it after
|
||||
// codegen (everything is sx-driven — there is no auto-emit/auto-link). It emits
|
||||
// the sx object, gathers the C companion objects, and links them into the output
|
||||
// with the build's libraries / frameworks / flags / target. A user overrides the
|
||||
// whole pipeline with their own `#run on_build(custom);` in main.sx (last-wins).
|
||||
// The compiler FORCE-LOWERS this well-known name and auto-invokes it after
|
||||
// codegen when no `#run on_build(custom);` override was registered (no library
|
||||
// `#run` needed). A user override takes over entirely.
|
||||
default_pipeline :: (opt: BuildOptions) -> bool abi(.compiler) {
|
||||
// `emit_and_link` is the build CORE: emit the sx object, gather the C companion
|
||||
// objects, and link them into the output with the build's libraries / frameworks /
|
||||
// flags / target. Shared by `default_pipeline` AND `platform.bundle.bundle_main`
|
||||
// (which wraps it with the per-target `.app` / `.apk` bundling) so a bundler
|
||||
// override doesn't re-implement emit+link.
|
||||
emit_and_link :: (opt: BuildOptions) -> bool abi(.compiler) {
|
||||
obj := emit_object();
|
||||
objs := c_object_paths();
|
||||
objs.append(obj);
|
||||
link(objs, build_output(), link_libraries(), build_frameworks(), build_flags(), build_target());
|
||||
return true;
|
||||
}
|
||||
|
||||
// `default_pipeline` is the stdlib build driver: the compiler invokes it after
|
||||
// codegen (everything is sx-driven — there is no auto-emit/auto-link). It emits +
|
||||
// links the program via `emit_and_link`. A user overrides the whole pipeline with
|
||||
// their own `#run on_build(custom);` in main.sx (last-wins) — e.g. bundling is
|
||||
// `#import "modules/platform/bundle.sx"; #run on_build(bundle_main);`, where
|
||||
// `bundle_main` runs `emit_and_link` then wraps the binary into a `.app` / `.apk`.
|
||||
// The compiler FORCE-LOWERS this well-known name and auto-invokes it after codegen
|
||||
// when no `on_build` override was registered (no library `#run` needed).
|
||||
//
|
||||
// When a bundle was requested (`--bundle`/`--apk` or `set_bundle_path`), delegate
|
||||
// to the per-target bundler (`bundle_main` runs the emit+link core then wraps the
|
||||
// `.app`/`.apk`); otherwise just emit + link.
|
||||
default_pipeline :: (opt: BuildOptions) -> bool abi(.compiler) {
|
||||
if opt.bundle_path().len > 0 {
|
||||
return bundle_main(opt);
|
||||
}
|
||||
return emit_and_link(opt);
|
||||
}
|
||||
|
||||
@@ -29,14 +29,18 @@
|
||||
// `abi(.compiler)` so the backend doesn't lower it and its `build_options()`
|
||||
// compiler-API call is permitted (it would otherwise be rejected as a
|
||||
// comptime-only function called at runtime).
|
||||
bundle_main :: (opt: BuildOptions) -> bool abi(.compiler) {
|
||||
opts := build_options();
|
||||
bundle_main :: (opts: BuildOptions) -> bool abi(.compiler) {
|
||||
// Run the standard build core first (emit the object + link the binary) — an
|
||||
// `on_build` override REPLACES default_pipeline, so the bundler owns the whole
|
||||
// pipeline: emit + link, then wrap the linked binary into the `.app` / `.apk`.
|
||||
if !emit_and_link(opts) { return false; }
|
||||
|
||||
binary := opts.binary_path();
|
||||
bundle := opts.bundle_path();
|
||||
bid := opts.bundle_id();
|
||||
|
||||
if bundle.len == 0 {
|
||||
// No bundle requested — nothing to do. Build succeeded.
|
||||
// No bundle requested — emit+link already done. Build succeeded.
|
||||
return true;
|
||||
}
|
||||
if bid.len == 0 {
|
||||
|
||||
@@ -336,7 +336,13 @@ any_to_string :: (val: Any) -> string {
|
||||
case enum: result = enum_to_string(cast(type) val);
|
||||
case error_set: { tagid : u32 = xx val; result = error_tag_name(tagid); }
|
||||
case vector: result = vector_to_string(cast(type) val);
|
||||
case array: result = array_to_string(cast(type) val);
|
||||
// Arrays format via `slice_to_string` over a SLICE VIEW of the payload
|
||||
// (the Any payload for an array IS a pointer to its storage). The dispatcher
|
||||
// (lowerRuntimeDispatchCall) builds the `{ptr,len}` view without ever
|
||||
// loading the whole array as a value — avoiding the O(N) SelectionDAG
|
||||
// scalarization that crippled `[65536]u8` (issue 0125). Output is identical
|
||||
// to the old `array_to_string` (`[a, b, c]`).
|
||||
case array: result = slice_to_string(cast(type) val);
|
||||
case slice: result = slice_to_string(cast(type) val);
|
||||
case pointer: result = pointer_to_string(cast(type) val);
|
||||
case optional: result = optional_to_string(cast(type) val);
|
||||
|
||||
Reference in New Issue
Block a user