diff --git a/build.zig b/build.zig index ef338c67..5c3b265c 100644 --- a/build.zig +++ b/build.zig @@ -36,7 +36,7 @@ pub fn build(b: *std.Build) void { // ************************************************ CODEGEN IR LIB_MODEL***************************************** // $ zig build lib-gen -Dmodel="myModel" ... - lib_codegen(b, zantBuild); + const codegen_run_step = lib_codegen(b, zantBuild); // ************************************************ LIB_MODEL EXECUTABLE **************************************** // $ zig build lib-exe -Dmodel="myModel" ... @@ -50,6 +50,10 @@ pub fn build(b: *std.Build) void { // $ zig build lib -Dmodel="myModel" [ -Dtarget=... -Dcpu=... -Doptimize=[ReleaseSmall, ReleaseFast]] const static_lib: *std.Build.Step.Compile = lib_creation(b, zantBuild) catch unreachable; + // *********************************************** REWRITE SECTIONS WHEN NEEDED (ELF + XIP) ******************** + // $ zig build lib -Dmodel="myModel" -Dxip=true ... + rewrite_sections(b, zantBuild, codegen_run_step, static_lib); + // ************************************************ ONEOP CODEGEN ************************************************ // $ zig build op-codegen-gen [ -Dop="OpName" ] op_codegen_gen(b, zantBuild); @@ -108,12 +112,12 @@ inline fn unit_test_creation(b: *std.Build, zantBuild: ZantBuild) void { test_step.dependOn(&run_unit_tests.step); } -inline fn lib_codegen(b: *std.Build, zantBuild: ZantBuild) void { +inline fn lib_codegen(b: *std.Build, zantBuild: ZantBuild) *std.Build.Step { const IR_codeGen_exe = b.addExecutable(.{ .name = "codegen", .root_module = b.createModule(.{ .root_source_file = b.path("src/codegen/main.zig"), - .target = target, + .target = b.graph.host, .optimize = optimize, }), }); @@ -140,6 +144,8 @@ inline fn lib_codegen(b: *std.Build, zantBuild: ZantBuild) void { // Create a build step to run the application. const IR_codegen_step = b.step("lib-gen", "code generation"); IR_codegen_step.dependOn(&IR_codegen_cmd.step); + + return &IR_codegen_cmd.step; } inline fn lib_exe(b: *std.Build, zantBuild: ZantBuild) void { @@ -497,3 +503,47 @@ inline fn build_main(b: *std.Build, zantBuild: ZantBuild, static_lib: *std.Build const build_main_step = b.step("build-main", "Build the main executable for profiling"); build_main_step.dependOn(&install_main_exe_step.step); } + +inline fn addRewriteSectionsStep( + b: *std.Build, + generated_dir: []const u8, +) *std.Build.Step { + const file_path = std.fs.path.join( + b.allocator, + &.{ generated_dir, "static_parameters.zig" }, + ) catch @panic("path join failed"); + + // In 0.15.x, set target/optimize on the module, not on the exe. + const mod = b.createModule(.{ + .root_source_file = b.path("src/codegen/cg_v1/parameters/rewrite_sections.zig"), + .target = b.graph.host, // host tool + .optimize = optimize, // small helper + }); + + const tool = b.addExecutable(.{ + .name = "rewrite_sections", + .root_module = mod, + }); + + const run = b.addRunArtifact(tool); + run.addArg(file_path); + + return &run.step; +} + +inline fn rewrite_sections(b: *std.Build, zantBuild: ZantBuild, codegen_run_step: *std.Build.Step, static_lib: *std.Build.Step.Compile) void { + // If the target output is ELF (e.g., Cortex-M) and XIP is enabled, normalize + // Mach-O-style names in generated/static_parameters.zig before building the lib. + const is_elf = target.result.ofmt == .elf; + const xip_enabled = zantBuild.zantOptions.codegen_flags.xip_enabled; + if (is_elf and xip_enabled) { + // Step: build & run small host-side tool + const rw = addRewriteSectionsStep( + b, + zantBuild.zantOptions.codegen_flags.generated_path_option, + ); + // Order: codegen → rewrite → static lib + rw.dependOn(codegen_run_step); + static_lib.step.dependOn(rw); + } +} diff --git a/src/codegen/cg_v1/parameters/parameters.zig b/src/codegen/cg_v1/parameters/parameters.zig index 5e05af77..bc77e34b 100644 --- a/src/codegen/cg_v1/parameters/parameters.zig +++ b/src/codegen/cg_v1/parameters/parameters.zig @@ -25,11 +25,15 @@ pub const XIPConfig = struct { if (!self.enabled) { // For macOS (mach-o), section specifiers must be in "segment,section" format if (comptime @import("builtin").target.os.tag == .macos) { - return "__DATA"; + return "__TEXT,__const"; } else { return ".rodata"; } } + // For macOS (mach-o), section specifiers must be in "segment,section" format + if (comptime @import("builtin").target.os.tag == .macos) { + return "__DATA,__flash_weights"; + } // For other platforms, use the original format return self.section_name; } diff --git a/src/codegen/cg_v1/parameters/rewrite_sections.zig b/src/codegen/cg_v1/parameters/rewrite_sections.zig new file mode 100644 index 00000000..8fee8193 --- /dev/null +++ b/src/codegen/cg_v1/parameters/rewrite_sections.zig @@ -0,0 +1,57 @@ +const std = @import("std"); + +/// Helper that replaces text and frees the previous buffer +fn replaceAndFree( + alloc: std.mem.Allocator, + buf: []u8, + needle: []const u8, + repl: []const u8, +) ![]u8 { + const out = try std.mem.replaceOwned(u8, alloc, buf, needle, repl); + alloc.free(buf); + return out; +} + +pub fn main() !void { + // ------------------------------------------------------------------------- + // Allocator setup with leak check (works in Zig 0.15.x) + // ------------------------------------------------------------------------- + var gpa = std.heap.GeneralPurposeAllocator(.{}){}; + defer { + const check = gpa.deinit(); + if (check == .leak) + std.debug.panic("memory leak detected in rewrite_sections", .{}); + } + const alloc = gpa.allocator(); + + // ------------------------------------------------------------------------- + // Argument parsing + // ------------------------------------------------------------------------- + var it = try std.process.argsWithAllocator(alloc); + defer it.deinit(); + + _ = it.next(); // exe name + const path = it.next() orelse { + std.log.err("usage: rewrite_sections ", .{}); + return error.MissingPath; + }; + + // ------------------------------------------------------------------------- + // Read file into memory + // ------------------------------------------------------------------------- + var text = try std.fs.cwd().readFileAlloc(alloc, path, 10 * 1024 * 1024); + defer alloc.free(text); + + // ------------------------------------------------------------------------- + // Replace Mach-O section names with ELF ones + // ------------------------------------------------------------------------- + text = try replaceAndFree(alloc, text, "__DATA,__flash_weights", ".flash_weights"); + text = try replaceAndFree(alloc, text, "__TEXT,__const", ".rodata"); + + // ------------------------------------------------------------------------- + // Overwrite the original file with the fixed content + // ------------------------------------------------------------------------- + try std.fs.cwd().writeFile(.{ .sub_path = path, .data = text }); + + std.log.info("rewrite_sections: updated {s}", .{path}); +}