From b59f86cd2fd821b98cf38f7f7a8bf6ab2a0a74af Mon Sep 17 00:00:00 2001 From: Kenneth Bogert Date: Wed, 21 Oct 2026 14:51:17 -0400 Subject: [PATCH 01/28] Simple api changes for 0.17 --- ConfigHeaderExt.zig | 3 +-- build.zig | 23 +++++++++++------------ 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/ConfigHeaderExt.zig b/ConfigHeaderExt.zig index 8862282..1973a2a 100644 --- a/ConfigHeaderExt.zig +++ b/ConfigHeaderExt.zig @@ -7,10 +7,9 @@ pub fn addFile(config_header: *ConfigHeader, config_results: std.Build.LazyPath) const apply = b.allocator.create(ApplyConfigStep) catch @panic("OOM"); apply.* = .{ .step = std.Build.Step.init(.{ - .id = .custom, + .tag = .config_header, .name = "add configuration from lazy path", .owner = b, - .makeFn = ApplyConfigStep.make, }), .config_header = config_header, .config_results = config_results, diff --git a/build.zig b/build.zig index 802b257..11364fd 100644 --- a/build.zig +++ b/build.zig @@ -177,7 +177,7 @@ pub fn build(b: *std.Build) !void { headers: []const std.Build.LazyPath, }; const add_modules_make = struct { - fn make(step: *std.Build.Step, options: std.Build.Step.MakeOptions) anyerror!void { + fn make(step: *std.Build.Step, options: std.Build.Step.StepOptions) anyerror!void { _ = options; const b2 = step.owner; const self: *AddModules = @fieldParentPtr("step", step); @@ -189,10 +189,9 @@ pub fn build(b: *std.Build) !void { const add_modules = b.allocator.create(AddModules) catch @panic("OOM"); add_modules.* = .{ .step = std.Build.Step.init(.{ - .id = .custom, + .tag = .run, .name = "add modules to run deepfreeze.py", .owner = b, - .makeFn = &add_modules_make, }), .version = version, .run_deepfreeze = run, @@ -394,8 +393,11 @@ fn addMakesetup( } fn addReplaceModuleArgs(b: *std.Build, replace: *std.Build.Step.Run, comptime Modules: type, modules: Modules) void { - inline for (std.meta.fields(Modules)) |field| { - const name = field.name; + comptime switch (@typeInfo(Modules)) { + .@"struct" => {}, + else => @compileError("Modules type must be a struct"), + }; + inline for (@typeInfo(Modules).@"struct".field_names) |name| { const value = @field(modules, name); var upcase_buf: [100]u8 = undefined; for (name, 0..) |c, i| { @@ -506,7 +508,7 @@ fn addPythonExe( module_compile_args_file: std.Build.LazyPath, }; const add_modules_make = struct { - fn make(step: *std.Build.Step, options: std.Build.Step.MakeOptions) anyerror!void { + fn make(step: *std.Build.Step, options: std.Build.Step.StepOptions) anyerror!void { _ = options; const io = step.owner.graph.io; const self: *AddModules = @fieldParentPtr("step", step); @@ -546,10 +548,9 @@ fn addPythonExe( const add_modules = b.allocator.create(AddModules) catch @panic("OOM"); add_modules.* = .{ .step = std.Build.Step.init(.{ - .id = .custom, + .tag = .update_source_files, .name = b.fmt("add module sources/includes to {s} exe", .{exe.name}), .owner = b, - .makeFn = &add_modules_make, }), .upstream = upstream, .exe = exe, @@ -862,10 +863,8 @@ fn addPyconfig( const run = b.addRunArtifact(configquery_exe); run.addArg("--zig-exe"); run.addArg(b.graph.zig_exe); - if (b.cache_root.path) |cache_root| { - run.addArg("--cache-dir"); - run.addArg(cache_root); - } + run.addArg("--cache-dir"); + run.addDirectoryArg(std.Build.LazyPath.cache_root); run.addArg("-target"); run.addArg(try target.query.zigTriple(b.allocator)); run.addArg("-mcpu"); From 4a9984bbca8e2bf72c3d25c1b6216a40265b90f2 Mon Sep 17 00:00:00 2001 From: Kenneth Bogert Date: Thu, 22 Oct 2026 18:08:44 -0400 Subject: [PATCH 02/28] Replace the replace program with configure phase file generation --- build.zig | 412 ++++++++++++++++++++++++++-------------------------- replace.zig | 27 +--- 2 files changed, 208 insertions(+), 231 deletions(-) diff --git a/build.zig b/build.zig index 11364fd..dbe17ad 100644 --- a/build.zig +++ b/build.zig @@ -43,27 +43,20 @@ const Stage2FrozenMods = struct { pub fn build(b: *std.Build) !void { const version: Version = b.option(Version, "version", "Python Version") orelse .latest; - const replace_exe = b.addExecutable(.{ - .name = "replace", - .root_module = b.createModule(.{ - .root_source_file = b.path("replace.zig"), - .target = b.graph.host, - }), - }); - const configquery_exe = b.addExecutable(.{ - .name = "configquery", - .root_module = b.createModule(.{ - .root_source_file = b.path("configquery.zig"), - .target = b.graph.host, - }), - }); - const makesetup_exe = b.addExecutable(.{ - .name = "makesetup", - .root_module = b.createModule(.{ - .root_source_file = b.path("makesetup.zig"), - .target = b.graph.host, - }), - }); + // const configquery_exe = b.addExecutable(.{ + // .name = "configquery", + // .root_module = b.createModule(.{ + // .root_source_file = b.path("configquery.zig"), + // .target = b.graph.host, + // }), + // }); + // const makesetup_exe = b.addExecutable(.{ + // .name = "makesetup", + // .root_module = b.createModule(.{ + // .root_source_file = b.path("makesetup.zig"), + // .target = b.graph.host, + // }), + // }); const upstream: *std.Build.Dependency = switch (version) { .@"3.11.13" => if (b.lazyDependency("upstream_3.11.13", .{})) |d| d else noUpstream(b), @@ -90,151 +83,146 @@ pub fn build(b: *std.Build) !void { })) |dep| dep.artifact("openssl") else null) else null, }; - const makesetup_host = addMakesetup(b, version, upstream, libs_host, .{ - .os_tag = b.graph.host.result.os.tag, - .replace_exe = replace_exe, - .makesetup_exe = makesetup_exe, - }); - const makesetup_target = addMakesetup(b, version, upstream, libs_target, .{ - .os_tag = target.result.os.tag, - .replace_exe = replace_exe, - .makesetup_exe = makesetup_exe, - }); - const pyconfig_host = try addPyconfig(b, version, upstream, b.graph.host, .{ .zlib = null, .openssl = null }, configquery_exe); - - const freeze_module_exe = addPythonExe(b, upstream, b.graph.host, .Debug, .{ - .name = "freeze_module", - .makesetup_out = makesetup_host, - .pyconfig = pyconfig_host, - .stage = .freeze_module, - }); - - const stage2_frozen_mods: Stage2FrozenMods = .{ - .getpath_h = blk: { - const freeze = b.addRunArtifact(freeze_module_exe); - freeze.addArg("getpath"); - freeze.addFileArg(upstream.path("Modules/getpath.py")); - break :blk freeze.addOutputFileArg("Python/frozen_modules/getpath.h"); - }, - .importlib_bootstrap_h = blk: { - const freeze = b.addRunArtifact(freeze_module_exe); - freeze.addArg("importlib._bootstrap"); - freeze.addFileArg(upstream.path("Lib/importlib/_bootstrap.py")); - break :blk freeze.addOutputFileArg("Python/frozen_modules/importlib._bootstrap.h"); - }, - .importlib_bootstrap_external_h = blk: { - const freeze = b.addRunArtifact(freeze_module_exe); - freeze.addArg("importlib._bootstrap_external"); - freeze.addFileArg(upstream.path("Lib/importlib/_bootstrap_external.py")); - break :blk freeze.addOutputFileArg("Python/frozen_modules/importlib._bootstrap_external.h"); - }, - .zipimport_h = blk: { - const freeze = b.addRunArtifact(freeze_module_exe); - freeze.addArg("zipimport"); - freeze.addFileArg(upstream.path("Lib/zipimport.py")); - break :blk freeze.addOutputFileArg("Python/frozen_modules/zipimport.h"); - }, - }; - - const frozen_headers, const deepfreeze_c = blk_deepfreeze_c: { - const bootstrap_python_exe = addPythonExe(b, upstream, b.graph.host, .Debug, .{ - .name = "bootstrap_python", - .makesetup_out = makesetup_host, - .pyconfig = pyconfig_host, - .stage = .{ .bootstrap = stage2_frozen_mods }, - }); - const bootstrap_packaged = packagePython(b, version, upstream, bootstrap_python_exe); - - const frozen_headers = b.allocator.alloc(std.Build.LazyPath, frozen_modules.len) catch @panic("OOM"); - // don't free - - const freeze_step = b.step("freeze", ""); - for (frozen_modules, frozenModuleNames(version), frozen_headers) |mod_path, mod_name, *header| { - const freeze = std.Build.Step.Run.create(b, b.fmt("run _freeze_module.py for '{s}'", .{mod_path})); - freeze.addFileArg(bootstrap_packaged.exe); - freeze.addFileArg(upstream.path("Programs/_freeze_module.py")); - freeze.addArg(mod_name); - freeze.addFileArg(upstream.path(mod_path)); - header.* = freeze.addOutputFileArg(b.fmt("frozen_modules/{s}.h", .{mod_name})); - freeze_step.dependOn(&freeze.step); - } - - const run = std.Build.Step.Run.create(b, "run deepfreeze.py"); - run.addFileArg(bootstrap_packaged.exe); - run.addFileArg(upstream.path(switch (version) { - .@"3.11.13" => "Tools/scripts/deepfreeze.py", - else => "Tools/build/deepfreeze.py", - })); - run.addArg("-o"); - const deepfreeze_c = run.addOutputFileArg("deepfreeze.c"); - { - // Need to create a custom step because std.Build.Step.Run doesn't - // have addSuffixedOutputArg. - const AddModules = struct { - step: std.Build.Step, - version: Version, - run_deepfreeze: *std.Build.Step.Run, - headers: []const std.Build.LazyPath, - }; - const add_modules_make = struct { - fn make(step: *std.Build.Step, options: std.Build.Step.StepOptions) anyerror!void { - _ = options; - const b2 = step.owner; - const self: *AddModules = @fieldParentPtr("step", step); - for (frozenModuleNames(self.version), self.headers) |mod_name, header| { - self.run_deepfreeze.addArg(b2.fmt("{s}:{s}", .{ header.getPath(b2), mod_name })); - } - } - }.make; - const add_modules = b.allocator.create(AddModules) catch @panic("OOM"); - add_modules.* = .{ - .step = std.Build.Step.init(.{ - .tag = .run, - .name = "add modules to run deepfreeze.py", - .owner = b, - }), - .version = version, - .run_deepfreeze = run, - .headers = frozen_headers, - }; - add_modules.step.dependOn(freeze_step); - run.step.dependOn(&add_modules.step); - } - - b.step("deepfreeze", "").dependOn(&run.step); - break :blk_deepfreeze_c .{ frozen_headers, deepfreeze_c }; - }; - - const final_exe = addPythonExe(b, upstream, target, optimize, .{ - .name = "python", - .makesetup_out = makesetup_target, - .pyconfig = try addPyconfig(b, version, upstream, target, libs_target, configquery_exe), - .stage = .{ - .final = .{ - .stage2 = stage2_frozen_mods, - .frozen_headers = frozen_headers, - .deepfreeze_c = deepfreeze_c, - }, - }, - }); - const final_packaged = packagePython(b, version, upstream, final_exe); - const install_final = b.addInstallDirectory(.{ - .source_dir = final_packaged.root, - .install_dir = .prefix, - .install_subdir = "", - }); - b.getInstallStep().dependOn(&install_final.step); - - const ci_step = b.step("ci", "The build/test step to run on the CI"); - ci_step.dependOn(b.getInstallStep()); - try ci(b, version, ssl_enabled, upstream, ci_step, .{ - .replace_exe = replace_exe, - .makesetup_exe = makesetup_exe, - .configquery_exe = configquery_exe, - .stage2_frozen_mods = stage2_frozen_mods, - .frozen_headers = frozen_headers, - .deepfreeze_c = deepfreeze_c, - }); + const makesetup_host = addMakesetup(b, version, upstream, libs_host, b.graph.host.result.os.tag); + const makesetup_target = addMakesetup(b, version, upstream, libs_target, target.result.os.tag); + + _ = makesetup_host; + _ = makesetup_target; + // const pyconfig_host = try addPyconfig(b, version, upstream, b.graph.host, .{ .zlib = null, .openssl = null }, configquery_exe); + + // const freeze_module_exe = addPythonExe(b, upstream, b.graph.host, .Debug, .{ + // .name = "freeze_module", + // .makesetup_out = makesetup_host, + // .pyconfig = pyconfig_host, + // .stage = .freeze_module, + // }); + + // const stage2_frozen_mods: Stage2FrozenMods = .{ + // .getpath_h = blk: { + // const freeze = b.addRunArtifact(freeze_module_exe); + // freeze.addArg("getpath"); + // freeze.addFileArg(upstream.path("Modules/getpath.py")); + // break :blk freeze.addOutputFileArg("Python/frozen_modules/getpath.h"); + // }, + // .importlib_bootstrap_h = blk: { + // const freeze = b.addRunArtifact(freeze_module_exe); + // freeze.addArg("importlib._bootstrap"); + // freeze.addFileArg(upstream.path("Lib/importlib/_bootstrap.py")); + // break :blk freeze.addOutputFileArg("Python/frozen_modules/importlib._bootstrap.h"); + // }, + // .importlib_bootstrap_external_h = blk: { + // const freeze = b.addRunArtifact(freeze_module_exe); + // freeze.addArg("importlib._bootstrap_external"); + // freeze.addFileArg(upstream.path("Lib/importlib/_bootstrap_external.py")); + // break :blk freeze.addOutputFileArg("Python/frozen_modules/importlib._bootstrap_external.h"); + // }, + // .zipimport_h = blk: { + // const freeze = b.addRunArtifact(freeze_module_exe); + // freeze.addArg("zipimport"); + // freeze.addFileArg(upstream.path("Lib/zipimport.py")); + // break :blk freeze.addOutputFileArg("Python/frozen_modules/zipimport.h"); + // }, + // }; + + // const frozen_headers, const deepfreeze_c = blk_deepfreeze_c: { + // const bootstrap_python_exe = addPythonExe(b, upstream, b.graph.host, .Debug, .{ + // .name = "bootstrap_python", + // .makesetup_out = makesetup_host, + // .pyconfig = pyconfig_host, + // .stage = .{ .bootstrap = stage2_frozen_mods }, + // }); + // const bootstrap_packaged = packagePython(b, version, upstream, bootstrap_python_exe); + + // const frozen_headers = b.allocator.alloc(std.Build.LazyPath, frozen_modules.len) catch @panic("OOM"); + // // don't free + + // const freeze_step = b.step("freeze", ""); + // for (frozen_modules, frozenModuleNames(version), frozen_headers) |mod_path, mod_name, *header| { + // const freeze = std.Build.Step.Run.create(b, b.fmt("run _freeze_module.py for '{s}'", .{mod_path})); + // freeze.addFileArg(bootstrap_packaged.exe); + // freeze.addFileArg(upstream.path("Programs/_freeze_module.py")); + // freeze.addArg(mod_name); + // freeze.addFileArg(upstream.path(mod_path)); + // header.* = freeze.addOutputFileArg(b.fmt("frozen_modules/{s}.h", .{mod_name})); + // freeze_step.dependOn(&freeze.step); + // } + + // const run = std.Build.Step.Run.create(b, "run deepfreeze.py"); + // run.addFileArg(bootstrap_packaged.exe); + // run.addFileArg(upstream.path(switch (version) { + // .@"3.11.13" => "Tools/scripts/deepfreeze.py", + // else => "Tools/build/deepfreeze.py", + // })); + // run.addArg("-o"); + // const deepfreeze_c = run.addOutputFileArg("deepfreeze.c"); + // { + // // Need to create a custom step because std.Build.Step.Run doesn't + // // have addSuffixedOutputArg. + // const AddModules = struct { + // step: std.Build.Step, + // version: Version, + // run_deepfreeze: *std.Build.Step.Run, + // headers: []const std.Build.LazyPath, + // }; + // const add_modules_make = struct { + // fn make(step: *std.Build.Step, options: std.Build.Step.StepOptions) anyerror!void { + // _ = options; + // const b2 = step.owner; + // const self: *AddModules = @fieldParentPtr("step", step); + // for (frozenModuleNames(self.version), self.headers) |mod_name, header| { + // self.run_deepfreeze.addArg(b2.fmt("{s}:{s}", .{ header.getPath(b2), mod_name })); + // } + // } + // }.make; + // const add_modules = b.allocator.create(AddModules) catch @panic("OOM"); + // add_modules.* = .{ + // .step = std.Build.Step.init(.{ + // .tag = .run, + // .name = "add modules to run deepfreeze.py", + // .owner = b, + // }), + // .version = version, + // .run_deepfreeze = run, + // .headers = frozen_headers, + // }; + // add_modules.step.dependOn(freeze_step); + // run.step.dependOn(&add_modules.step); + // } + + // b.step("deepfreeze", "").dependOn(&run.step); + // break :blk_deepfreeze_c .{ frozen_headers, deepfreeze_c }; + // }; + + // const final_exe = addPythonExe(b, upstream, target, optimize, .{ + // .name = "python", + // .makesetup_out = makesetup_target, + // .pyconfig = try addPyconfig(b, version, upstream, target, libs_target, configquery_exe), + // .stage = .{ + // .final = .{ + // .stage2 = stage2_frozen_mods, + // .frozen_headers = frozen_headers, + // .deepfreeze_c = deepfreeze_c, + // }, + // }, + // }); + // const final_packaged = packagePython(b, version, upstream, final_exe); + // const install_final = b.addInstallDirectory(.{ + // .source_dir = final_packaged.root, + // .install_dir = .prefix, + // .install_subdir = "", + // }); + // b.getInstallStep().dependOn(&install_final.step); + + // const ci_step = b.step("ci", "The build/test step to run on the CI"); + // ci_step.dependOn(b.getInstallStep()); + // try ci(b, version, ssl_enabled, upstream, ci_step, .{ + // .replace_exe = replace_exe, + // .makesetup_exe = makesetup_exe, + // .configquery_exe = configquery_exe, + // .stage2_frozen_mods = stage2_frozen_mods, + // .frozen_headers = frozen_headers, + // .deepfreeze_c = deepfreeze_c, + // }); } fn noUpstream(b: *std.Build) *std.Build.Dependency { @@ -248,13 +236,9 @@ fn addMakesetup( version: Version, upstream: *std.Build.Dependency, libs: Libs, - args: struct { - os_tag: std.Target.Os.Tag, - replace_exe: *std.Build.Step.Compile, - makesetup_exe: *std.Build.Step.Compile, - }, + os_tag: std.Target.Os.Tag, ) std.Build.LazyPath { - const is_posix = (args.os_tag != .windows); + const is_posix = (os_tag != .windows); const stdlib_modules_common = .{ ._ssl = (libs.openssl != null), @@ -275,7 +259,7 @@ fn addMakesetup( ._pickle = true, ._queue = true, ._random = true, - ._socket = (args.os_tag != .windows), + ._socket = (os_tag != .windows), ._statistics = true, ._struct = true, ._zoneinfo = true, @@ -302,9 +286,9 @@ fn addMakesetup( .fcntl = is_posix, ._posixshmem = is_posix, .grp = is_posix, - .ossaudiodev = (args.os_tag == .linux), - .resource = (args.os_tag == .linux), - .spwd = (args.os_tag == .linux), + .ossaudiodev = (os_tag == .linux), + .resource = (os_tag == .linux), + .spwd = (os_tag == .linux), .syslog = is_posix, .termios = is_posix, @@ -355,44 +339,49 @@ fn addMakesetup( ._xxinterpchannels = false, }; - const setup_bootstrap = blk: { - const replace = b.addRunArtifact(args.replace_exe); - replace.addFileArg(upstream.path("Modules/Setup.bootstrap.in")); - const out = replace.addOutputFileArg("Setup.bootstrap"); + const pwd_enabled = is_posix; + const value_str = if (pwd_enabled) "" else "#"; - const pwd_enabled = is_posix; - const value_str = if (pwd_enabled) "" else "#"; - replace.addArg(b.fmt("MODULE_PWD_TRUE={s}", .{value_str})); - break :blk out; - }; + const dep_root_path = upstream.builder.root.root_dir.path orelse "."; + const bootstrap_in_path = b.pathJoin(&.{ dep_root_path, "Modules/Setup.bootstrap.in" }); + const bootstrap_out_path = b.pathJoin(&.{ dep_root_path, "Modules/Setup.bootstrap" }); - const setup_stdlib = blk_stdlib: { - const replace = b.addRunArtifact(args.replace_exe); - replace.addFileArg(upstream.path("Modules/Setup.stdlib.in")); - const out = replace.addOutputFileArg("Setup.stdlib"); - replace.addArg("MODULE_{NAME}_TRUE=MODULE_{NAME}_TRUE"); - replace.addArg("MODULE_BUILDTYPE=static"); - addReplaceModuleArgs(b, replace, @TypeOf(stdlib_modules_common), stdlib_modules_common); - switch (version) { - .@"3.11.13" => addReplaceModuleArgs(b, replace, @TypeOf(@"stdlib_modules_3.11.13"), @"stdlib_modules_3.11.13"), - .@"3.12.11" => { - replace.addArg("MODULE__CTYPES_MALLOC_CLOSURE="); - addReplaceModuleArgs(b, replace, @TypeOf(@"stdlib_modules_3.12.11"), @"stdlib_modules_3.12.11"); - }, - } - break :blk_stdlib out; - }; + replace.replace(b, bootstrap_in_path, bootstrap_out_path, &.{ + b.fmt("MODULE_PWD_TRUE={s}", .{value_str}), + }); + b.dependOnFileContents(upstream.path("Modules/Setup.bootstrap")); + + var replacements: std.ArrayList([]const u8) = .empty; + defer replacements.deinit(b.allocator); - const generate = b.addRunArtifact(args.makesetup_exe); - generate.addDirectoryArg(upstream.path(".")); - const makesetup_out = generate.addOutputDirectoryArg("gen"); - generate.addFileArg(setup_bootstrap); - generate.addFileArg(setup_stdlib); - generate.addFileArg(upstream.path("Modules/Setup")); - return makesetup_out; + replacements.append(b.allocator, "MODULE_{NAME}_TRUE=MODULE_{NAME}_TRUE") catch @panic("OOM"); + replacements.append(b.allocator, "MODULE_BUILDTYPE=static") catch @panic("OOM"); + addReplacements(&replacements, b, @TypeOf(stdlib_modules_common), stdlib_modules_common); + switch (version) { + .@"3.11.13" => addReplacements(&replacements, b, @TypeOf(@"stdlib_modules_3.11.13"), @"stdlib_modules_3.11.13"), + .@"3.12.11" => { + replacements.append(b.allocator, "MODULE__CTYPES_MALLOC_CLOSURE=") catch @panic("OOM"); + addReplacements(&replacements, b, @TypeOf(@"stdlib_modules_3.12.11"), @"stdlib_modules_3.12.11"); + }, + } + + const stdlib_in_path = b.pathJoin(&.{ dep_root_path, "Modules/Setup.stdlib.in" }); + const stdlib_out_path = b.pathJoin(&.{ dep_root_path, "Modules/Setup.stdlib" }); + replace.replace(b, stdlib_in_path, stdlib_out_path, replacements.items); + b.dependOnFileContents(upstream.path("Modules/Setup.stdlib")); + + // const generate = b.addRunArtifact(args.makesetup_exe); + // generate.addDirectoryArg(upstream.path(".")); + // const makesetup_out = generate.addOutputDirectoryArg("gen"); + // generate.addFileArg(setup_bootstrap); + // generate.addFileArg(setup_stdlib); + // generate.addFileArg(upstream.path("Modules/Setup")); + // return makesetup_out; + + return b.path("."); } -fn addReplaceModuleArgs(b: *std.Build, replace: *std.Build.Step.Run, comptime Modules: type, modules: Modules) void { +fn addReplacements(list: *std.ArrayList([]const u8), b: *std.Build, comptime Modules: type, modules: Modules) void { comptime switch (@typeInfo(Modules)) { .@"struct" => {}, else => @compileError("Modules type must be a struct"), @@ -404,7 +393,7 @@ fn addReplaceModuleArgs(b: *std.Build, replace: *std.Build.Step.Run, comptime Mo upcase_buf[i] = std.ascii.toUpper(c); } const value_str = if (value) "" else "#"; - replace.addArg(b.fmt("MODULE_{s}_TRUE={s}", .{ upcase_buf[0..name.len], value_str })); + list.append(b.allocator, b.fmt("MODULE_{s}_TRUE={s}", .{ upcase_buf[0..name.len], value_str })) catch @panic("OOM"); } } @@ -545,6 +534,8 @@ fn addPythonExe( }); } }.make; + + _ = add_modules_make; const add_modules = b.allocator.create(AddModules) catch @panic("OOM"); add_modules.* = .{ .step = std.Build.Step.init(.{ @@ -1222,3 +1213,4 @@ fn concat(allocator: std.mem.Allocator, lists: []const []const []const u8) []con const std = @import("std"); const ConfigHeaderExt = @import("ConfigHeaderExt.zig"); +const replace = @import("replace.zig"); diff --git a/replace.zig b/replace.zig index adb4c51..a1d073a 100644 --- a/replace.zig +++ b/replace.zig @@ -1,22 +1,9 @@ const std = @import("std"); const Io = std.Io; -pub fn main(init: std.process.Init) !void { - const arena = init.arena.allocator(); - const all_args = try init.minimal.args.toSlice(arena); - const io = init.io; - - if (all_args.len <= 1) { - var stderr = std.Io.File.stderr().writer(io, &.{}); - try stderr.interface.writeAll("usage: replace IN_FILE OUT_FILE NAME=VALUE...\n"); - std.process.exit(0xff); - } - const args = all_args[1..]; - if (args.len < 2) errExit("expected at least 2 cmdline args but got {}", .{args.len}); - - const in_path = args[0]; - const out_path = args[1]; - const replacements = args[2..]; +pub fn replace(b: *std.Build, in_path: []const u8, out_path: []const u8, replacements: []const []const u8) void { + const arena = b.allocator; + const io = b.graph.io; var map: std.StringHashMapUnmanaged(MapNode) = .{}; for (replacements) |r| { @@ -24,20 +11,18 @@ pub fn main(init: std.process.Init) !void { "expected NAME=VALUE cmdline arg but got '{s}'", .{r}, ); - try map.put(arena, r[0..eq_index], .{ .count = 0, .value = r[eq_index + 1 ..] }); + map.put(arena, r[0..eq_index], .{ .count = 0, .value = r[eq_index + 1 ..] }) catch @panic("OOM"); } const in = std.Io.Dir.cwd().readFileAlloc(io, in_path, arena, .unlimited) catch |e| std.debug.panic("open '{s}' failed with {t}", .{ in_path, e }); - var out_file = try std.Io.Dir.cwd().createFile(io, out_path, .{}); + var out_file = std.Io.Dir.cwd().createFile(io, out_path, .{}) catch @panic("Cannot create outfile"); defer out_file.close(io); var out_file_buf: [4096]u8 = undefined; var file_writer = out_file.writer(io, &out_file_buf); - writeFile(in_path, in, &map, &file_writer.interface) catch |err| switch (err) { - error.WriteFailed => return file_writer.err orelse error.Unexpected, - }; + writeFile(in_path, in, &map, &file_writer.interface) catch |err| std.debug.panic("write to '{s}' failed with {t}", .{ out_path, err }); var unused_count: usize = 0; var it = map.iterator(); From 1d19a637d743952672beb4372a1591434975bec8 Mon Sep 17 00:00:00 2001 From: Kenneth Bogert Date: Thu, 22 Oct 2026 21:57:24 -0400 Subject: [PATCH 03/28] Successfully generate config.c --- build.zig | 50 +++++++++++++++++---------- makesetup.zig | 95 ++++++++++++++++----------------------------------- replace.zig | 28 +++++++-------- 3 files changed, 76 insertions(+), 97 deletions(-) diff --git a/build.zig b/build.zig index dbe17ad..a718abf 100644 --- a/build.zig +++ b/build.zig @@ -63,6 +63,8 @@ pub fn build(b: *std.Build) !void { .@"3.12.11" => if (b.lazyDependency("upstream_3.12.11", .{})) |d| d else noUpstream(b), }; + if (b.graph.unlazy_deps.count() > 0) return; + const target = b.standardTargetOptions(.{}); const optimize = b.standardOptimizeOption(.{}); @@ -344,12 +346,13 @@ fn addMakesetup( const dep_root_path = upstream.builder.root.root_dir.path orelse "."; const bootstrap_in_path = b.pathJoin(&.{ dep_root_path, "Modules/Setup.bootstrap.in" }); - const bootstrap_out_path = b.pathJoin(&.{ dep_root_path, "Modules/Setup.bootstrap" }); + b.dependOnFileContents(upstream.path("Modules/Setup.bootstrap.in")); - replace.replace(b, bootstrap_in_path, bootstrap_out_path, &.{ + // First replace call + const setup_bootstrap = replace.replace(b, bootstrap_in_path, &.{ b.fmt("MODULE_PWD_TRUE={s}", .{value_str}), }); - b.dependOnFileContents(upstream.path("Modules/Setup.bootstrap")); + defer b.allocator.free(setup_bootstrap); var replacements: std.ArrayList([]const u8) = .empty; defer replacements.deinit(b.allocator); @@ -365,20 +368,30 @@ fn addMakesetup( }, } + // Second replace call const stdlib_in_path = b.pathJoin(&.{ dep_root_path, "Modules/Setup.stdlib.in" }); - const stdlib_out_path = b.pathJoin(&.{ dep_root_path, "Modules/Setup.stdlib" }); - replace.replace(b, stdlib_in_path, stdlib_out_path, replacements.items); - b.dependOnFileContents(upstream.path("Modules/Setup.stdlib")); - - // const generate = b.addRunArtifact(args.makesetup_exe); - // generate.addDirectoryArg(upstream.path(".")); - // const makesetup_out = generate.addOutputDirectoryArg("gen"); - // generate.addFileArg(setup_bootstrap); - // generate.addFileArg(setup_stdlib); - // generate.addFileArg(upstream.path("Modules/Setup")); - // return makesetup_out; - - return b.path("."); + b.dependOnFileContents(upstream.path("Modules/Setup.stdlib.in")); + const setup_stdlib = replace.replace(b, stdlib_in_path, replacements.items); + defer b.allocator.free(setup_stdlib); + + const setup_in_path = b.pathJoin(&.{ dep_root_path, "Modules/Setup" }); + b.dependOnFileContents(upstream.path("Modules/Setup")); + + const setup_file = std.Io.Dir.cwd().readFileAlloc(b.graph.io, setup_in_path, b.allocator, .unlimited) catch |e| + std.debug.panic("open '{s}' failed with {t}", .{ setup_in_path, e }); + const setup = makesetup.makesetup(b, &.{ setup_bootstrap, setup_stdlib, setup_file }, &.{ bootstrap_in_path, stdlib_in_path, setup_in_path }); + + const config_c_in_path = b.pathJoin(&.{ dep_root_path, "Modules/config.c.in" }); + b.dependOnFileContents(upstream.path("Modules/config.c.in")); + const config_c_in = std.Io.Dir.cwd().readFileAlloc(b.graph.io, config_c_in_path, b.allocator, .unlimited) catch |e| + std.debug.panic("open file '{s}' failed with {t}", .{ config_c_in_path, e }); + + const wf = b.addWriteFiles(); + const config_contents = makesetup.writeConfigC(b, setup, config_c_in_path, config_c_in); + defer b.allocator.free(config_contents); + const config_c = wf.add("Modules/config.c", config_contents); + + return config_c; } fn addReplacements(list: *std.ArrayList([]const u8), b: *std.Build, comptime Modules: type, modules: Modules) void { @@ -1172,14 +1185,14 @@ fn ci( .optimize = optimize, })) |dep| dep.artifact("openssl") else null) else null, }; - const makesetup = addMakesetup(b, version, upstream, libs, .{ + const makesetups = addMakesetup(b, version, upstream, libs, .{ .os_tag = target.result.os.tag, .replace_exe = args.replace_exe, .makesetup_exe = args.makesetup_exe, }); const exe = addPythonExe(b, upstream, target, optimize, .{ .name = "python", - .makesetup_out = makesetup, + .makesetup_out = makesetups, .pyconfig = try addPyconfig(b, version, upstream, target, libs, args.configquery_exe), .stage = .{ .final = .{ .stage2 = args.stage2_frozen_mods, @@ -1214,3 +1227,4 @@ fn concat(allocator: std.mem.Allocator, lists: []const []const []const u8) []con const std = @import("std"); const ConfigHeaderExt = @import("ConfigHeaderExt.zig"); const replace = @import("replace.zig"); +const makesetup = @import("makesetup.zig"); diff --git a/makesetup.zig b/makesetup.zig index 1b8e080..74991a0 100644 --- a/makesetup.zig +++ b/makesetup.zig @@ -4,96 +4,63 @@ const print = std.debug.print; const ArrayListUnmanaged = std.ArrayListUnmanaged; const Allocator = std.mem.Allocator; -pub fn main(init: std.process.Init) !void { - const arena = init.arena.allocator(); - const all_args = try init.minimal.args.toSlice(arena); - const io = init.io; +pub fn makesetup(b: *std.Build, setup_files: []const []const u8, setup_files_src_paths: []const []const u8) Setup { + const arena = b.allocator; + const setup = try parseSetupFiles(arena, setup_files, setup_files_src_paths); - if (all_args.len <= 1) { - var stderr = std.Io.File.stderr().writer(io, &.{}); - try stderr.interface.writeAll("usage: makesetup UPSTREAM_SRC OUT_DIR SETUP_FILES...\n"); - std.process.exit(0xff); - } - const args = all_args[1..]; - if (args.len < 3) errExit("expected at least 3 cmdline args but got {}", .{args.len}); - - const upstream_src = args[0]; - const out_path = args[1]; - const setup_files = args[2..]; - - const setup = try parseSetupFiles(arena, io, setup_files); - - const config_in_path = std.Io.Dir.path.join(arena, &.{ upstream_src, "Modules", "config.c.in" }) catch |e| oom(e); - const config_in = std.Io.Dir.cwd().readFileAlloc(io, config_in_path, arena, .unlimited) catch |e| - std.debug.panic("open file '{s}' failed with {t}", .{ config_in_path, e }); - - var out_dir = try std.Io.Dir.cwd().createDirPathOpen(io, out_path, .{}); - defer out_dir.close(io); - - { - var file = try out_dir.createFile(io, "config.c", .{}); - defer file.close(io); - var out_file_buf: [4096]u8 = undefined; - var file_writer = file.writer(io, &out_file_buf); - writeConfigC(setup, config_in_path, config_in, &file_writer.interface) catch |err| switch (err) { - error.WriteFailed => return file_writer.err orelse error.Unexpected, - }; - } + return setup; - { - var out_file = try out_dir.createFile(io, "module-compile-args.txt", .{}); - defer out_file.close(io); - var out_file_buf: [4096]u8 = undefined; - var file_writer = out_file.writer(io, &out_file_buf); - writeCompileArgs(setup, &file_writer.interface) catch |err| switch (err) { - error.WriteFailed => return file_writer.err orelse error.Unexpected, - }; - } + // { + // var out_file = try out_dir.createFile(io, "module-compile-args.txt", .{}); + // defer out_file.close(io); + // var out_file_buf: [4096]u8 = undefined; + // var file_writer = out_file.writer(io, &out_file_buf); + // writeCompileArgs(setup, &file_writer.interface) catch |err| switch (err) { + // error.WriteFailed => return file_writer.err orelse error.Unexpected, + // }; + // } } -fn writeConfigC( +pub fn writeConfigC( + b: *std.Build, setup: Setup, config_in_path: []const u8, config_in: []const u8, - writer: *std.Io.Writer, -) error{WriteFailed}!void { - try writer.print("/* Generated automatically from {s} by makesetup. */\n", .{config_in_path}); +) []const u8 { + const alloc = b.allocator; + var list: std.ArrayList(u8) = .empty; + defer list.deinit(alloc); + + list.appendSlice(alloc, b.fmt("/* Generated automatically from {s} by makesetup. */\n", .{config_in_path})) catch @panic("OOM"); var lines = std.mem.splitScalar(u8, config_in, '\n'); while (lines.next()) |line| { if (std.mem.indexOf(u8, line, "MARKER 1")) |_| { var it = setup.modules.iterator(); while (it.next()) |entry| { if (!entry.value_ptr.enabled) continue; - try writer.print("extern PyObject* PyInit_{s}(void);\n", .{entry.key_ptr.*}); + list.appendSlice(alloc, b.fmt("extern PyObject* PyInit_{s}(void);\n", .{entry.key_ptr.*})) catch @panic("OOM"); } } else if (std.mem.indexOf(u8, line, "MARKER 2")) |_| { var it = setup.modules.iterator(); while (it.next()) |entry| { if (!entry.value_ptr.enabled) continue; - try writer.print(" {{\"{s}\", PyInit_{0s}}},\n", .{entry.key_ptr.*}); + list.appendSlice(alloc, b.fmt(" {{\"{s}\", PyInit_{0s}}},\n", .{entry.key_ptr.*})) catch @panic("OOM"); } } - try writer.writeAll(line); - try writer.writeByte('\n'); + list.append(alloc, '\n') catch @panic("OOM"); } - try writer.flush(); + return list.toOwnedSlice(alloc) catch @panic("OOM"); } -fn writeCompileArgs(setup: Setup, writer: *std.Io.Writer) error{WriteFailed}!void { +pub fn addCFiles(b: *std.Build, setup: Setup, module: std.Build.Module) void { var it = setup.modules.iterator(); while (it.next()) |entry| { - const module_name = entry.key_ptr.*; - { - const suffix: []const u8 = if (entry.value_ptr.enabled) "" else " (DISABLED)"; - try writer.print("# Module '{s}'{s}\n", .{ module_name, suffix }); - } const prefix: []const u8 = if (entry.value_ptr.enabled) "" else "# "; for (entry.value_ptr.compile_args) |compile_arg| switch (compile_arg) { - .source => |src| try writer.print("{s}Modules/{s}\n", .{ prefix, src }), - .include => |inc| try writer.print("{s}-I{s}\n", .{ prefix, inc }), + .source => |src| module.addCSourceFile(b.fmt("{s}Modules/{s}\n", .{ prefix, src })), + .include => |inc| module.addIncludePath(b.fmt("{s}-I{s}\n", .{ prefix, inc })), }; } - try writer.flush(); } const CompileArg = union(enum) { @@ -113,11 +80,9 @@ const Setup = struct { modules: std.StringArrayHashMapUnmanaged(Module) = .{}, }; -fn parseSetupFiles(arena: std.mem.Allocator, io: Io, setup_files: []const []const u8) !Setup { +fn parseSetupFiles(arena: std.mem.Allocator, setup_files: []const []const u8, setup_files_src_paths: []const []const u8) !Setup { var setup: Setup = .{}; - for (setup_files) |file_path| { - const content = std.Io.Dir.cwd().readFileAlloc(io, file_path, arena, .unlimited) catch |e| - std.debug.panic("open '{s}' failed with {t}", .{ file_path, e }); + for (setup_files, setup_files_src_paths) |content, file_path| { try parseSetupFile(arena, &setup, file_path, content); } return setup; diff --git a/replace.zig b/replace.zig index a1d073a..6f64329 100644 --- a/replace.zig +++ b/replace.zig @@ -1,7 +1,7 @@ const std = @import("std"); const Io = std.Io; -pub fn replace(b: *std.Build, in_path: []const u8, out_path: []const u8, replacements: []const []const u8) void { +pub fn replace(b: *std.Build, in_path: []const u8, replacements: []const []const u8) []const u8 { const arena = b.allocator; const io = b.graph.io; @@ -17,12 +17,7 @@ pub fn replace(b: *std.Build, in_path: []const u8, out_path: []const u8, replace const in = std.Io.Dir.cwd().readFileAlloc(io, in_path, arena, .unlimited) catch |e| std.debug.panic("open '{s}' failed with {t}", .{ in_path, e }); - var out_file = std.Io.Dir.cwd().createFile(io, out_path, .{}) catch @panic("Cannot create outfile"); - defer out_file.close(io); - - var out_file_buf: [4096]u8 = undefined; - var file_writer = out_file.writer(io, &out_file_buf); - writeFile(in_path, in, &map, &file_writer.interface) catch |err| std.debug.panic("write to '{s}' failed with {t}", .{ out_path, err }); + const returnval = writeFile(in_path, in, &map, b) catch |err| std.debug.panic("replace failed with {t}", .{err}); var unused_count: usize = 0; var it = map.iterator(); @@ -36,6 +31,8 @@ pub fn replace(b: *std.Build, in_path: []const u8, out_path: []const u8, replace std.log.err("{} unused variable(s), the did not appear in template '{s}'", .{ unused_count, in_path }); std.process.exit(0xff); } + + return returnval; } const MapNode = struct { @@ -47,13 +44,17 @@ fn writeFile( in_path: []const u8, in: []const u8, map: *const std.StringHashMapUnmanaged(MapNode), - writer: *std.Io.Writer, -) error{WriteFailed}!void { + b: *std.Build, +) ![]const u8 { + const alloc = b.allocator; + var list: std.ArrayList(u8) = .empty; + defer list.deinit(b.allocator); + var missing_count: usize = 0; var offset: usize = 0; while (true) { const at_index = std.mem.indexOfScalarPos(u8, in, offset, '@') orelse break; - try writer.writeAll(in[offset..at_index]); + try list.appendSlice(alloc, in[offset..at_index]); const end = std.mem.indexOfScalarPos(u8, in, at_index + 1, '@') orelse errExit( "{s}: unterminated '@' at offset {}", .{ in_path, at_index }, @@ -61,17 +62,16 @@ fn writeFile( const name = in[at_index + 1 .. end]; if (map.getEntry(name)) |entry| { entry.value_ptr.count += 1; - try writer.writeAll(entry.value_ptr.value); + try list.appendSlice(alloc, entry.value_ptr.value); } else { std.log.err("undefined variable '{s}'", .{name}); - try writer.print("MISSING_VAR_{s}", .{name}); + try list.appendSlice(alloc, b.fmt("MISSING_VAR_{s}", .{name})); missing_count += 1; } offset = end + 1; } - try writer.writeAll(in[offset..]); - try writer.flush(); if (missing_count > 0) errExit("{} missing variable(s) for template '{s}'", .{ missing_count, in_path }); + return list.toOwnedSlice(alloc); } fn errExit(comptime fmt: []const u8, args: anytype) noreturn { From 7fcd2c3f0a5747f4c49b9415c2fd2edf1328bdcc Mon Sep 17 00:00:00 2001 From: Kenneth Bogert Date: Thu, 22 Oct 2026 22:45:39 -0400 Subject: [PATCH 04/28] Use the setup structure directly to add cSourceFiles and Include paths to the module --- build.zig | 348 +++++++++++++++++++++----------------------------- makesetup.zig | 14 +- 2 files changed, 148 insertions(+), 214 deletions(-) diff --git a/build.zig b/build.zig index a718abf..bb57b59 100644 --- a/build.zig +++ b/build.zig @@ -43,20 +43,13 @@ const Stage2FrozenMods = struct { pub fn build(b: *std.Build) !void { const version: Version = b.option(Version, "version", "Python Version") orelse .latest; - // const configquery_exe = b.addExecutable(.{ - // .name = "configquery", - // .root_module = b.createModule(.{ - // .root_source_file = b.path("configquery.zig"), - // .target = b.graph.host, - // }), - // }); - // const makesetup_exe = b.addExecutable(.{ - // .name = "makesetup", - // .root_module = b.createModule(.{ - // .root_source_file = b.path("makesetup.zig"), - // .target = b.graph.host, - // }), - // }); + const configquery_exe = b.addExecutable(.{ + .name = "configquery", + .root_module = b.createModule(.{ + .root_source_file = b.path("configquery.zig"), + .target = b.graph.host, + }), + }); const upstream: *std.Build.Dependency = switch (version) { .@"3.11.13" => if (b.lazyDependency("upstream_3.11.13", .{})) |d| d else noUpstream(b), @@ -88,132 +81,131 @@ pub fn build(b: *std.Build) !void { const makesetup_host = addMakesetup(b, version, upstream, libs_host, b.graph.host.result.os.tag); const makesetup_target = addMakesetup(b, version, upstream, libs_target, target.result.os.tag); - _ = makesetup_host; - _ = makesetup_target; - // const pyconfig_host = try addPyconfig(b, version, upstream, b.graph.host, .{ .zlib = null, .openssl = null }, configquery_exe); + const pyconfig_host = try addPyconfig(b, version, upstream, b.graph.host, .{ .zlib = null, .openssl = null }, configquery_exe); - // const freeze_module_exe = addPythonExe(b, upstream, b.graph.host, .Debug, .{ - // .name = "freeze_module", - // .makesetup_out = makesetup_host, - // .pyconfig = pyconfig_host, - // .stage = .freeze_module, - // }); + const freeze_module_exe = addPythonExe(b, upstream, b.graph.host, .Debug, .{ + .name = "freeze_module", + .setup = makesetup_host, + .pyconfig = pyconfig_host, + .stage = .freeze_module, + }); - // const stage2_frozen_mods: Stage2FrozenMods = .{ - // .getpath_h = blk: { - // const freeze = b.addRunArtifact(freeze_module_exe); - // freeze.addArg("getpath"); - // freeze.addFileArg(upstream.path("Modules/getpath.py")); - // break :blk freeze.addOutputFileArg("Python/frozen_modules/getpath.h"); - // }, - // .importlib_bootstrap_h = blk: { - // const freeze = b.addRunArtifact(freeze_module_exe); - // freeze.addArg("importlib._bootstrap"); - // freeze.addFileArg(upstream.path("Lib/importlib/_bootstrap.py")); - // break :blk freeze.addOutputFileArg("Python/frozen_modules/importlib._bootstrap.h"); - // }, - // .importlib_bootstrap_external_h = blk: { - // const freeze = b.addRunArtifact(freeze_module_exe); - // freeze.addArg("importlib._bootstrap_external"); - // freeze.addFileArg(upstream.path("Lib/importlib/_bootstrap_external.py")); - // break :blk freeze.addOutputFileArg("Python/frozen_modules/importlib._bootstrap_external.h"); - // }, - // .zipimport_h = blk: { - // const freeze = b.addRunArtifact(freeze_module_exe); - // freeze.addArg("zipimport"); - // freeze.addFileArg(upstream.path("Lib/zipimport.py")); - // break :blk freeze.addOutputFileArg("Python/frozen_modules/zipimport.h"); - // }, - // }; - - // const frozen_headers, const deepfreeze_c = blk_deepfreeze_c: { - // const bootstrap_python_exe = addPythonExe(b, upstream, b.graph.host, .Debug, .{ - // .name = "bootstrap_python", - // .makesetup_out = makesetup_host, - // .pyconfig = pyconfig_host, - // .stage = .{ .bootstrap = stage2_frozen_mods }, - // }); - // const bootstrap_packaged = packagePython(b, version, upstream, bootstrap_python_exe); - - // const frozen_headers = b.allocator.alloc(std.Build.LazyPath, frozen_modules.len) catch @panic("OOM"); - // // don't free - - // const freeze_step = b.step("freeze", ""); - // for (frozen_modules, frozenModuleNames(version), frozen_headers) |mod_path, mod_name, *header| { - // const freeze = std.Build.Step.Run.create(b, b.fmt("run _freeze_module.py for '{s}'", .{mod_path})); - // freeze.addFileArg(bootstrap_packaged.exe); - // freeze.addFileArg(upstream.path("Programs/_freeze_module.py")); - // freeze.addArg(mod_name); - // freeze.addFileArg(upstream.path(mod_path)); - // header.* = freeze.addOutputFileArg(b.fmt("frozen_modules/{s}.h", .{mod_name})); - // freeze_step.dependOn(&freeze.step); - // } - - // const run = std.Build.Step.Run.create(b, "run deepfreeze.py"); - // run.addFileArg(bootstrap_packaged.exe); - // run.addFileArg(upstream.path(switch (version) { - // .@"3.11.13" => "Tools/scripts/deepfreeze.py", - // else => "Tools/build/deepfreeze.py", - // })); - // run.addArg("-o"); - // const deepfreeze_c = run.addOutputFileArg("deepfreeze.c"); - // { - // // Need to create a custom step because std.Build.Step.Run doesn't - // // have addSuffixedOutputArg. - // const AddModules = struct { - // step: std.Build.Step, - // version: Version, - // run_deepfreeze: *std.Build.Step.Run, - // headers: []const std.Build.LazyPath, - // }; - // const add_modules_make = struct { - // fn make(step: *std.Build.Step, options: std.Build.Step.StepOptions) anyerror!void { - // _ = options; - // const b2 = step.owner; - // const self: *AddModules = @fieldParentPtr("step", step); - // for (frozenModuleNames(self.version), self.headers) |mod_name, header| { - // self.run_deepfreeze.addArg(b2.fmt("{s}:{s}", .{ header.getPath(b2), mod_name })); - // } - // } - // }.make; - // const add_modules = b.allocator.create(AddModules) catch @panic("OOM"); - // add_modules.* = .{ - // .step = std.Build.Step.init(.{ - // .tag = .run, - // .name = "add modules to run deepfreeze.py", - // .owner = b, - // }), - // .version = version, - // .run_deepfreeze = run, - // .headers = frozen_headers, - // }; - // add_modules.step.dependOn(freeze_step); - // run.step.dependOn(&add_modules.step); - // } - - // b.step("deepfreeze", "").dependOn(&run.step); - // break :blk_deepfreeze_c .{ frozen_headers, deepfreeze_c }; - // }; - - // const final_exe = addPythonExe(b, upstream, target, optimize, .{ - // .name = "python", - // .makesetup_out = makesetup_target, - // .pyconfig = try addPyconfig(b, version, upstream, target, libs_target, configquery_exe), - // .stage = .{ - // .final = .{ - // .stage2 = stage2_frozen_mods, - // .frozen_headers = frozen_headers, - // .deepfreeze_c = deepfreeze_c, - // }, - // }, - // }); - // const final_packaged = packagePython(b, version, upstream, final_exe); - // const install_final = b.addInstallDirectory(.{ - // .source_dir = final_packaged.root, - // .install_dir = .prefix, - // .install_subdir = "", - // }); - // b.getInstallStep().dependOn(&install_final.step); + const stage2_frozen_mods: Stage2FrozenMods = .{ + .getpath_h = blk: { + const freeze = b.addRunArtifact(freeze_module_exe); + freeze.addArg("getpath"); + freeze.addFileArg(upstream.path("Modules/getpath.py")); + break :blk freeze.addOutputFileArg("Python/frozen_modules/getpath.h"); + }, + .importlib_bootstrap_h = blk: { + const freeze = b.addRunArtifact(freeze_module_exe); + freeze.addArg("importlib._bootstrap"); + freeze.addFileArg(upstream.path("Lib/importlib/_bootstrap.py")); + break :blk freeze.addOutputFileArg("Python/frozen_modules/importlib._bootstrap.h"); + }, + .importlib_bootstrap_external_h = blk: { + const freeze = b.addRunArtifact(freeze_module_exe); + freeze.addArg("importlib._bootstrap_external"); + freeze.addFileArg(upstream.path("Lib/importlib/_bootstrap_external.py")); + break :blk freeze.addOutputFileArg("Python/frozen_modules/importlib._bootstrap_external.h"); + }, + .zipimport_h = blk: { + const freeze = b.addRunArtifact(freeze_module_exe); + freeze.addArg("zipimport"); + freeze.addFileArg(upstream.path("Lib/zipimport.py")); + break :blk freeze.addOutputFileArg("Python/frozen_modules/zipimport.h"); + }, + }; + + const frozen_headers, const deepfreeze_c = blk_deepfreeze_c: { + const bootstrap_python_exe = addPythonExe(b, upstream, b.graph.host, .Debug, .{ + .name = "bootstrap_python", + .setup = makesetup_host, + .pyconfig = pyconfig_host, + .stage = .{ .bootstrap = stage2_frozen_mods }, + }); + const bootstrap_packaged = packagePython(b, version, upstream, bootstrap_python_exe); + + const frozen_headers = b.allocator.alloc(std.Build.LazyPath, frozen_modules.len) catch @panic("OOM"); + // don't free + + const freeze_step = b.step("freeze", ""); + for (frozen_modules, frozenModuleNames(version), frozen_headers) |mod_path, mod_name, *header| { + const freeze = std.Build.Step.Run.create(b, b.fmt("run _freeze_module.py for '{s}'", .{mod_path})); + freeze.addFileArg(bootstrap_packaged.exe); + freeze.addFileArg(upstream.path("Programs/_freeze_module.py")); + freeze.addArg(mod_name); + freeze.addFileArg(upstream.path(mod_path)); + header.* = freeze.addOutputFileArg(b.fmt("frozen_modules/{s}.h", .{mod_name})); + freeze_step.dependOn(&freeze.step); + } + + const run = std.Build.Step.Run.create(b, "run deepfreeze.py"); + run.addFileArg(bootstrap_packaged.exe); + run.addFileArg(upstream.path(switch (version) { + .@"3.11.13" => "Tools/scripts/deepfreeze.py", + else => "Tools/build/deepfreeze.py", + })); + run.addArg("-o"); + const deepfreeze_c = run.addOutputFileArg("deepfreeze.c"); + // { + // // Need to create a custom step because std.Build.Step.Run doesn't + // // have addSuffixedOutputArg. + // const AddModules = struct { + // step: std.Build.Step, + // version: Version, + // run_deepfreeze: *std.Build.Step.Run, + // headers: []const std.Build.LazyPath, + // }; + // const add_modules_make = struct { + // fn make(step: *std.Build.Step, options: std.Build.Step.StepOptions) anyerror!void { + // _ = options; + // const b2 = step.owner; + // const self: *AddModules = @fieldParentPtr("step", step); + // for (frozenModuleNames(self.version), self.headers) |mod_name, header| { + // self.run_deepfreeze.addArg(b2.fmt("{s}:{s}", .{ header.getPath(b2), mod_name })); + // } + // } + // }.make; + // _ = add_modules_make; + // const add_modules = b.allocator.create(AddModules) catch @panic("OOM"); + // add_modules.* = .{ + // .step = std.Build.Step.init(.{ + // .tag = .run, + // .name = "add modules to run deepfreeze.py", + // .owner = b, + // }), + // .version = version, + // .run_deepfreeze = run, + // .headers = frozen_headers, + // }; + // add_modules.step.dependOn(freeze_step); + // run.step.dependOn(&add_modules.step); + // } + + b.step("deepfreeze", "").dependOn(&run.step); + break :blk_deepfreeze_c .{ frozen_headers, deepfreeze_c }; + }; + + const final_exe = addPythonExe(b, upstream, target, optimize, .{ + .name = "python", + .setup = makesetup_target, + .pyconfig = try addPyconfig(b, version, upstream, target, libs_target, configquery_exe), + .stage = .{ + .final = .{ + .stage2 = stage2_frozen_mods, + .frozen_headers = frozen_headers, + .deepfreeze_c = deepfreeze_c, + }, + }, + }); + const final_packaged = packagePython(b, version, upstream, final_exe); + const install_final = b.addInstallDirectory(.{ + .source_dir = final_packaged.root, + .install_dir = .prefix, + .install_subdir = "", + }); + b.getInstallStep().dependOn(&install_final.step); // const ci_step = b.step("ci", "The build/test step to run on the CI"); // ci_step.dependOn(b.getInstallStep()); @@ -239,7 +231,7 @@ fn addMakesetup( upstream: *std.Build.Dependency, libs: Libs, os_tag: std.Target.Os.Tag, -) std.Build.LazyPath { +) makesetup.Setup { const is_posix = (os_tag != .windows); const stdlib_modules_common = .{ @@ -379,7 +371,7 @@ fn addMakesetup( const setup_file = std.Io.Dir.cwd().readFileAlloc(b.graph.io, setup_in_path, b.allocator, .unlimited) catch |e| std.debug.panic("open '{s}' failed with {t}", .{ setup_in_path, e }); - const setup = makesetup.makesetup(b, &.{ setup_bootstrap, setup_stdlib, setup_file }, &.{ bootstrap_in_path, stdlib_in_path, setup_in_path }); + var setup = makesetup.makesetup(b, &.{ setup_bootstrap, setup_stdlib, setup_file }, &.{ bootstrap_in_path, stdlib_in_path, setup_in_path }); const config_c_in_path = b.pathJoin(&.{ dep_root_path, "Modules/config.c.in" }); b.dependOnFileContents(upstream.path("Modules/config.c.in")); @@ -390,8 +382,9 @@ fn addMakesetup( const config_contents = makesetup.writeConfigC(b, setup, config_c_in_path, config_c_in); defer b.allocator.free(config_contents); const config_c = wf.add("Modules/config.c", config_contents); + setup.outfile = config_c; - return config_c; + return setup; } fn addReplacements(list: *std.ArrayList([]const u8), b: *std.Build, comptime Modules: type, modules: Modules) void { @@ -437,7 +430,7 @@ fn addPythonExe( optimize: std.builtin.OptimizeMode, args: struct { name: []const u8, - makesetup_out: std.Build.LazyPath, + setup: makesetup.Setup, pyconfig: Pyconfig, stage: PythonExeStage, }, @@ -502,66 +495,17 @@ fn addPythonExe( "-DVPATH=\"\"", }; - { - const AddModules = struct { - step: std.Build.Step, - upstream: *std.Build.Dependency, - exe: *std.Build.Step.Compile, - module_compile_args_file: std.Build.LazyPath, - }; - const add_modules_make = struct { - fn make(step: *std.Build.Step, options: std.Build.Step.StepOptions) anyerror!void { - _ = options; - const io = step.owner.graph.io; - const self: *AddModules = @fieldParentPtr("step", step); - const file_path = self.module_compile_args_file.getPath2(step.owner, step); - - const module_compile_args = try std.Io.Dir.cwd().readFileAlloc(io, file_path, step.owner.allocator, .unlimited); - defer step.owner.allocator.free(module_compile_args); - - var files: std.ArrayList([]const u8) = .empty; - defer files.deinit(step.owner.allocator); - - var line_it = std.mem.splitScalar(u8, module_compile_args, '\n'); - while (line_it.next()) |line| { - if (line.len == 0) continue; - if (std.mem.startsWith(u8, line, "# ")) continue; - if (std.mem.endsWith(u8, line, ".c")) { - try files.append(step.owner.allocator, line); - } else if (std.mem.startsWith(u8, line, "-I")) { - const path = line[2..]; - const prefix = "$(srcdir)/"; - if (!std.mem.startsWith(u8, path, prefix)) std.debug.panic( - "expected include path to start with '-I{s}' but got: '{s}'", - .{ prefix, line }, - ); - const inc_sub_path = step.owner.dupe(path[prefix.len..]); - self.exe.root_module.addIncludePath(self.upstream.path(inc_sub_path)); - } else std.debug.panic("todo: parse module-compile-args line '{s}'", .{line}); - } - - self.exe.root_module.addCSourceFiles(.{ - .root = self.upstream.path("."), - .files = files.items, + var it = args.setup.modules.iterator(); + while (it.next()) |entry| { + if (entry.value_ptr.enabled) { + for (entry.value_ptr.compile_args) |compile_arg| switch (compile_arg) { + .source => |src| exe.root_module.addCSourceFile(.{ + .file = b.path(b.fmt("Modules/{s}", .{src})), .flags = &flags_common, - }); - } - }.make; - - _ = add_modules_make; - const add_modules = b.allocator.create(AddModules) catch @panic("OOM"); - add_modules.* = .{ - .step = std.Build.Step.init(.{ - .tag = .update_source_files, - .name = b.fmt("add module sources/includes to {s} exe", .{exe.name}), - .owner = b, - }), - .upstream = upstream, - .exe = exe, - .module_compile_args_file = args.makesetup_out.path(b, "module-compile-args.txt"), - }; - add_modules.module_compile_args_file.addStepDependencies(&add_modules.step); - exe.step.dependOn(&add_modules.step); + }), + .include => |inc| exe.root_module.addIncludePath(b.path(b.fmt("{s}", .{inc}))), + }; + } } exe.root_module.addCSourceFiles(.{ @@ -612,7 +556,7 @@ fn addPythonExe( }); exe.root_module.addCSourceFile(.{ - .file = args.makesetup_out.path(b, "config.c"), + .file = args.setup.outfile orelse @panic("Missing config.c file"), .flags = &flags_common, }); diff --git a/makesetup.zig b/makesetup.zig index 74991a0..1fb2ec4 100644 --- a/makesetup.zig +++ b/makesetup.zig @@ -52,17 +52,6 @@ pub fn writeConfigC( return list.toOwnedSlice(alloc) catch @panic("OOM"); } -pub fn addCFiles(b: *std.Build, setup: Setup, module: std.Build.Module) void { - var it = setup.modules.iterator(); - while (it.next()) |entry| { - const prefix: []const u8 = if (entry.value_ptr.enabled) "" else "# "; - for (entry.value_ptr.compile_args) |compile_arg| switch (compile_arg) { - .source => |src| module.addCSourceFile(b.fmt("{s}Modules/{s}\n", .{ prefix, src })), - .include => |inc| module.addIncludePath(b.fmt("{s}-I{s}\n", .{ prefix, inc })), - }; - } -} - const CompileArg = union(enum) { source: []const u8, include: []const u8, @@ -76,8 +65,9 @@ const Module = struct { compile_args: []const CompileArg, libs: []const []const u8, }; -const Setup = struct { +pub const Setup = struct { modules: std.StringArrayHashMapUnmanaged(Module) = .{}, + outfile: ?std.Build.LazyPath = null, }; fn parseSetupFiles(arena: std.mem.Allocator, setup_files: []const []const u8, setup_files_src_paths: []const []const u8) !Setup { From d91953449de04e7a63267c775cb3900a44aab182 Mon Sep 17 00:00:00 2001 From: Kenneth Bogert Date: Thu, 22 Oct 2026 22:48:01 -0400 Subject: [PATCH 05/28] Path mistake --- build.zig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.zig b/build.zig index bb57b59..9e5676e 100644 --- a/build.zig +++ b/build.zig @@ -500,10 +500,10 @@ fn addPythonExe( if (entry.value_ptr.enabled) { for (entry.value_ptr.compile_args) |compile_arg| switch (compile_arg) { .source => |src| exe.root_module.addCSourceFile(.{ - .file = b.path(b.fmt("Modules/{s}", .{src})), + .file = upstream.path(b.fmt("Modules/{s}", .{src})), .flags = &flags_common, }), - .include => |inc| exe.root_module.addIncludePath(b.path(b.fmt("{s}", .{inc}))), + .include => |inc| exe.root_module.addIncludePath(upstream.path(b.fmt("{s}", .{inc}))), }; } } From d87ab5f9ce91cd3bf594eaca2e9a5502ff1e031c Mon Sep 17 00:00:00 2001 From: Kenneth Bogert Date: Fri, 23 Oct 2026 23:23:08 -0400 Subject: [PATCH 06/28] Configure compiles and runs but build fails, at the moment due to corrupted c source file names. --- build.zig | 68 ++++++++++------------- configquery.zig | 144 ++++++++++++++++-------------------------------- 2 files changed, 76 insertions(+), 136 deletions(-) diff --git a/build.zig b/build.zig index 9e5676e..1f5caef 100644 --- a/build.zig +++ b/build.zig @@ -43,20 +43,12 @@ const Stage2FrozenMods = struct { pub fn build(b: *std.Build) !void { const version: Version = b.option(Version, "version", "Python Version") orelse .latest; - const configquery_exe = b.addExecutable(.{ - .name = "configquery", - .root_module = b.createModule(.{ - .root_source_file = b.path("configquery.zig"), - .target = b.graph.host, - }), - }); - const upstream: *std.Build.Dependency = switch (version) { .@"3.11.13" => if (b.lazyDependency("upstream_3.11.13", .{})) |d| d else noUpstream(b), .@"3.12.11" => if (b.lazyDependency("upstream_3.12.11", .{})) |d| d else noUpstream(b), }; - if (b.graph.unlazy_deps.count() > 0) return; + if (b.graph.needed_lazy_dependencies.count() > 0) return; const target = b.standardTargetOptions(.{}); const optimize = b.standardOptimizeOption(.{}); @@ -81,7 +73,7 @@ pub fn build(b: *std.Build) !void { const makesetup_host = addMakesetup(b, version, upstream, libs_host, b.graph.host.result.os.tag); const makesetup_target = addMakesetup(b, version, upstream, libs_target, target.result.os.tag); - const pyconfig_host = try addPyconfig(b, version, upstream, b.graph.host, .{ .zlib = null, .openssl = null }, configquery_exe); + const pyconfig_host = try addPyconfig(b, version, upstream, b.graph.host, .{ .zlib = null, .openssl = null }); const freeze_module_exe = addPythonExe(b, upstream, b.graph.host, .Debug, .{ .name = "freeze_module", @@ -190,7 +182,7 @@ pub fn build(b: *std.Build) !void { const final_exe = addPythonExe(b, upstream, target, optimize, .{ .name = "python", .setup = makesetup_target, - .pyconfig = try addPyconfig(b, version, upstream, target, libs_target, configquery_exe), + .pyconfig = try addPyconfig(b, version, upstream, target, libs_target), .stage = .{ .final = .{ .stage2 = stage2_frozen_mods, @@ -621,14 +613,7 @@ const Libs = struct { openssl: ?*std.Build.Step.Compile, }; -fn addPyconfig( - b: *std.Build, - version: Version, - upstream: *std.Build.Dependency, - target: std.Build.ResolvedTarget, - libs: Libs, - configquery_exe: *std.Build.Step.Compile, -) !Pyconfig { +fn addPyconfig(b: *std.Build, version: Version, upstream: *std.Build.Dependency, target: std.Build.ResolvedTarget, libs: Libs) !Pyconfig { const t = target.result; if (t.os.tag == .windows) return .{ .version = version, @@ -808,24 +793,31 @@ fn addPyconfig( } { - const run = b.addRunArtifact(configquery_exe); - run.addArg("--zig-exe"); - run.addArg(b.graph.zig_exe); - run.addArg("--cache-dir"); - run.addDirectoryArg(std.Build.LazyPath.cache_root); - run.addArg("-target"); - run.addArg(try target.query.zigTriple(b.allocator)); - run.addArg("-mcpu"); - run.addArg(try target.query.serializeCpuAlloc(b.allocator)); - if (libs.zlib) |zlib| run.addPrefixedDirectoryArg("-I", zlib.getEmittedIncludeTree()); - if (libs.openssl) |openssl| run.addPrefixedDirectoryArg("-I", openssl.getEmittedIncludeTree()); - run.addFileArg(b.path("config-common")); - run.addFileArg(switch (version) { - .@"3.11.13" => b.path("config-3.11.13"), - .@"3.12.11" => b.path("config-3.12.11"), - }); - run.addArg("-o"); - ConfigHeaderExt.addFile(config_header, run.addOutputFileArg("config")); + var configquery_config: configquery.Config = .{}; + configquery_config.zig_exe = b.graph.zig_exe; + configquery_config.target_triple = try target.query.zigTriple(b.allocator); + configquery_config.mcpu = try target.query.serializeCpuAlloc(b.allocator); + + const vers_config_file = switch (version) { + .@"3.11.13" => "config-3.11.13", + .@"3.12.11" => "config-3.12.11", + }; + b.dependOnFileContents(b.path(vers_config_file)); + + const build_root = b.root.root_dir.path orelse "."; + + const vers_file_path = b.pathJoin(&.{ build_root, vers_config_file }); + + const config_common_path = b.pathJoin(&.{ build_root, "config-common" }); + b.dependOnFileContents(b.path("config-common")); + + try configquery.resolveQueries(b, &.{ config_common_path, vers_file_path }, config_header, configquery_config); + + // hardcode for now + if (libs.zlib) |_| config_header.values.put(b.allocator, "HAVE_ZLIB_COPY", .{ .int = 1 }) catch @panic("OOM"); + + // if (libs.openssl) |openssl| try configquery_config.include_dirs.append(b.allocator, openssl.getEmittedIncludeTree()); + } return .{ @@ -1169,6 +1161,6 @@ fn concat(allocator: std.mem.Allocator, lists: []const []const []const u8) []con } const std = @import("std"); -const ConfigHeaderExt = @import("ConfigHeaderExt.zig"); const replace = @import("replace.zig"); const makesetup = @import("makesetup.zig"); +const configquery = @import("configquery.zig"); diff --git a/configquery.zig b/configquery.zig index 4339f9f..507713d 100644 --- a/configquery.zig +++ b/configquery.zig @@ -1,87 +1,12 @@ -pub fn main(init: std.process.Init) !void { - const arena = init.arena.allocator(); - const io = init.io; - - var template_files: std.ArrayList([]const u8) = .empty; - var output_path: ?[]const u8 = null; - var config: Config = .{}; - - { - var args = try init.minimal.args.iterateAllocator(arena); - _ = args.next(); - while (args.next()) |arg| { - if (std.mem.eql(u8, arg, "-o")) { - output_path = args.next() orelse fatal("-o requires an argument", .{}); - } else if (std.mem.eql(u8, arg, "--zig-exe")) { - config.zig_exe = args.next() orelse fatal("--zig-exe requires an argument", .{}); - } else if (std.mem.eql(u8, arg, "--cache-dir")) { - config.cache_dir = args.next() orelse fatal("--cache-dir requires an argument", .{}); - } else if (std.mem.eql(u8, arg, "-target")) { - config.target_triple = args.next() orelse fatal("-target requires an argument", .{}); - } else if (std.mem.eql(u8, arg, "-mcpu")) { - config.mcpu = args.next() orelse fatal("-mcpu requires an argument", .{}); - } else if (std.mem.startsWith(u8, arg, "-I")) { - config.include_dirs.append(arena, arg) catch |e| oom(e); - } else { - template_files.append(arena, arg) catch |e| oom(e); - } - } - } - - if (template_files.items.len == 0) { - const usage = - \\Usage: configquery [options] [template-files] - \\ - \\Processes template files line by line. Lines starting with # are - \\comments. Each line is NAME VALUE where VALUE is either a literal - \\or a query starting with ?. - \\ - \\Options: - \\ -o Write output to file (default: stdout) - \\ --zig-exe [exe] Path to zig executable (for compile queries) - \\ -target [name] -- see the targets command - \\ -mcpu [cpu] Specify target CPU and feature set - \\ -I[dir] Add directory to include search path - \\ --cache-dir [path] The local cache directory - \\ - \\Literal Values - \\ SIZEOF_INT 4 - \\ RETSIGTYPE .void - \\ PY_HASH "md5,sha1" - \\ HAVE_FEATURE defined - \\ MISSING_FEATURE undef - \\ - \\Query syntax: NAME ? PASS|FAIL [define=DEF,...] [include=HDR,...] [COMPILE_BODY] - \\ - \\ HAVE_ALLOCA_H ? 1|undef include=alloca.h - \\ HAVE_FORK ? 1|undef include=unistd.h int main(){fork();} - \\ HAVE_PRLIMIT ? 1|undef include=sys/time.h,sys/resource.h int main(){prlimit(0,0,0,0);} - \\ HAVE_CLOSE_RANGE ? 1|undef define=_GNU_SOURCE include=unistd.h int main(){close_range(0,0,0);} - \\ - \\configquery is purposely limited to compile-only (no link). Its up to the caller to ensure - \\header/symbol availability matches library symbol availability. - \\ - ; - var stderr = std.Io.File.stderr().writer(io, &.{}); - stderr.interface.writeAll(usage) catch return stderr.err.?; - stderr.interface.flush() catch return stderr.err.?; - std.process.exit(1); - } - - var out_buf: [4096]u8 = undefined; - var out_file = if (output_path) |path| std.Io.Dir.cwd().createFile(io, path, .{}) catch |err| fatal( - "failed to create '{s}' with {t}", - .{ path, err }, - ) else std.Io.File.stdout(); - defer if (output_path != null) out_file.close(io); - var out_writer = out_file.writer(io, &out_buf); - const out = &out_writer.interface; +pub fn resolveQueries(b: *std.Build, template_files: []const []const u8, config_header: *ConfigHeader, config: Config) !void { + const arena = b.allocator; + const io = b.graph.io; var queries: std.ArrayList(Query) = .empty; var name_set: std.StringHashMapUnmanaged(u32) = .empty; var error_count: u32 = 0; - for (template_files.items) |template_path| { + for (template_files) |template_path| { const content = std.Io.Dir.cwd().readFileAlloc(io, template_path, arena, .unlimited) catch |err| fatal( "failed to read '{s}' with {t}", .{ template_path, err }, @@ -98,7 +23,12 @@ pub fn main(init: std.process.Init) !void { }, .literal => |lit| { checkUnique(arena, &name_set, io, template_path, line_num, lit.config_name, &error_count); - out.print("{s} {s}\n", .{ lit.config_name, lit.value_str }) catch return out_writer.err.?; + if (parseValue(lit.value_str)) |entry| { + config_header.values.put(b.allocator, lit.config_name, entry) catch @panic("OOM"); + } else { + error_count += 1; + reportError(io, template_path, line_num, "{s} '{s}'", .{ lit.config_name, line_untrimmed }); + } }, .query => |input| { checkUnique(arena, &name_set, io, template_path, line_num, input.config_name, &error_count); @@ -109,7 +39,7 @@ pub fn main(init: std.process.Init) !void { .line_num = line_num, }) catch |e| oom(e); } else { - out.print("{s} {s}\n", .{ input.config_name, input.pass_text }) catch return out_writer.err.?; + config_header.values.put(b.allocator, input.config_name, .{ .string = input.pass_text }) catch @panic("OOM"); } }, } @@ -119,13 +49,12 @@ pub fn main(init: std.process.Init) !void { if (error_count > 0) fatal("{} errors in config templates", .{error_count}); if (queries.items.len > 0) { - const zig_exe = config.zig_exe orelse fatal("compile query requires --zig-exe", .{}); - const cache_dir = config.cache_dir orelse fatal("compile query requires --cache-dir", .{}); + const zig_exe = config.zig_exe orelse fatal("compile query requires zig-exe", .{}); const argv_template = buildArgvTemplate(arena, zig_exe, &config); var group: std.Io.Group = .init; for (queries.items, 0..) |*q, i| { - group.async(io, runCompileCheck, .{ arena, io, q, argv_template, cache_dir, i }); + group.async(io, runCompileCheck, .{ arena, io, q, argv_template, i }); } group.await(io) catch |err| switch (err) { error.Canceled => fatal("canceled", .{}), @@ -133,22 +62,30 @@ pub fn main(init: std.process.Init) !void { for (queries.items) |*q| { const result = q.result orelse fatal("compile query for '{s}' has no result", .{q.input.config_name}); - const value_text = if (result.success) q.input.pass_text else q.input.fail_text; - out.print("{s}{s} {s}\n", .{ result.error_comments, q.input.config_name, value_text }) catch return out_writer.err.?; if (result.fatal_msg) |msg| { error_count += 1; reportError(io, q.file_path, q.line_num, "{s}", .{msg}); + } else { + const value_text = if (result.success) q.input.pass_text else q.input.fail_text; + + if (parseValue(value_text)) |entry| { + config_header.values.put(b.allocator, q.input.config_name, entry) catch @panic("OOM"); + } else { + error_count += 1; + reportError(io, q.file_path, q.line_num, "{s} '{s}'", .{ q.input.config_name, value_text }); + } + if (result.error_comments.len > 0) { + std.log.debug("{s}{s} {s} : {s}\n", .{ result.error_comments, q.input.config_name, q.input.pass_text, q.input.fail_text }); + } } } } - out.flush() catch return out_writer.err.?; if (error_count > 0) fatal("{} errors", .{error_count}); } -const Config = struct { +pub const Config = struct { zig_exe: ?[]const u8 = null, - cache_dir: ?[]const u8 = null, target_triple: ?[]const u8 = null, mcpu: ?[]const u8 = null, include_dirs: std.ArrayList([]const u8) = .empty, @@ -185,6 +122,17 @@ const Query = struct { }; }; +pub fn parseValue(str: []const u8) ?ConfigHeader.Value { + if (std.mem.eql(u8, str, "undef")) return .undef; + if (std.mem.eql(u8, str, "defined")) return .defined; + if (std.mem.eql(u8, str, "false")) return .{ .boolean = false }; + if (std.mem.eql(u8, str, "true")) return .{ .boolean = true }; + if (std.fmt.parseInt(i64, str, 10)) |int| return .{ .int = int } else |_| {} + if (std.mem.startsWith(u8, str, ":")) return .{ .ident = str[1..] }; + if (str.len >= 2 and str[0] == '"' and str[str.len - 1] == '"') return .{ .string = str[1 .. str.len - 1] }; + return null; +} + fn parseLine(line_untrimmed: []const u8) Line { const line = std.mem.trim(u8, line_untrimmed, &std.ascii.whitespace); if (line.len == 0 or line[0] == '#') return .skip; @@ -194,18 +142,18 @@ fn parseLine(line_untrimmed: []const u8) Line { const value_str = std.mem.trimStart(u8, line[first_space + 1 ..], " "); if (!std.mem.startsWith(u8, value_str, "?")) { - _ = ConfigHeaderExt.parseValue(value_str) orelse + _ = parseValue(value_str) orelse return .{ .err = "invalid config value" }; return .{ .literal = .{ .config_name = config_name, .value_str = value_str } }; } const pass_str, const after_pass = scanConfigValue(value_str, 1); - _ = ConfigHeaderExt.parseValue(pass_str) orelse return .{ .err = "expected PASS_VALUE after ?" }; + _ = parseValue(pass_str) orelse return .{ .err = "expected PASS_VALUE after ?" }; const pipe_index = skipWhitespace(value_str, after_pass); if (pipe_index >= value_str.len or value_str[pipe_index] != '|') return .{ .err = "expected '|' after PASS_VALUE" }; const fail_str, const after_fail = scanConfigValue(value_str, pipe_index + 1); - _ = ConfigHeaderExt.parseValue(fail_str) orelse return .{ .err = "expected FAIL_VALUE after '|'" }; + _ = parseValue(fail_str) orelse return .{ .err = "expected FAIL_VALUE after '|'" }; var rest = std.mem.trimStart(u8, value_str[after_fail..], " "); const defines = parseExprClause(&rest, "define="); const includes = parseExprClause(&rest, "include="); @@ -302,10 +250,9 @@ fn runCompileCheck( io: std.Io, query: *Query, argv_template: []const []const u8, - cache_dir: []const u8, index: usize, ) void { - query.result = doCompileCheck(arena, io, query, argv_template, cache_dir, index); + query.result = doCompileCheck(arena, io, query, argv_template, index); } fn doCompileCheck( @@ -313,7 +260,6 @@ fn doCompileCheck( io: std.Io, query: *const Query, argv_template: []const []const u8, - cache_dir: []const u8, index: usize, ) Query.Result { const sep = std.fs.path.sep_str; @@ -324,7 +270,9 @@ fn doCompileCheck( else => @compileError("unsupported OS"), }; var task_dir_buf: [std.fs.max_path_bytes]u8 = undefined; - const task_dir = std.fmt.bufPrint(&task_dir_buf, "{s}" ++ sep ++ "tmp" ++ sep ++ "cq-{}-{}", .{ cache_dir, pid, index }) catch + const base_dir = "."; + + const task_dir = std.fmt.bufPrint(&task_dir_buf, "{s}" ++ sep ++ "tmp" ++ sep ++ "cq-{}-{}", .{ base_dir, pid, index }) catch fatal("cache-dir path too long", .{}); std.Io.Dir.cwd().createDirPath(io, task_dir) catch |err| fatal("failed to create '{s}': {t}", .{ task_dir, err }); @@ -346,8 +294,6 @@ fn doCompileCheck( const argv = blk: { var a = std.ArrayList([]const u8).initCapacity(arena, argv_template.len + 3) catch |e| oom(e); a.appendSliceAssumeCapacity(argv_template); - a.appendAssumeCapacity("--cache-dir"); - a.appendAssumeCapacity(task_dir); a.appendAssumeCapacity(source_path); break :blk a.items; }; @@ -513,3 +459,5 @@ fn fatal(comptime fmt: []const u8, args: anytype) noreturn { const std = @import("std"); const ConfigHeaderExt = @import("ConfigHeaderExt.zig"); +const ConfigHeader = std.Build.Step.ConfigHeader; +const LazyPath = std.Build.LazyPath; From 191639b042b8b6d1b0e6f7e1409d106ff2cfd6e8 Mon Sep 17 00:00:00 2001 From: Kenneth Bogert Date: Fri, 23 Oct 2026 23:44:45 -0400 Subject: [PATCH 07/28] Solve issue with string corruptions, working on getting the freeze module build to compile --- makesetup.zig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/makesetup.zig b/makesetup.zig index 1fb2ec4..bc5f181 100644 --- a/makesetup.zig +++ b/makesetup.zig @@ -143,7 +143,7 @@ fn parseSetupFile( if (std.mem.startsWith(u8, part, "#")) { break; } else if (std.mem.endsWith(u8, part, ".c")) { - compile_args.append(arena, .{ .source = part }) catch |e| oom(e); + compile_args.append(arena, .{ .source = arena.dupe(u8, part) catch |e| oom(e) }) catch |e| oom(e); } else if (std.mem.endsWith(u8, part, ".a")) { libraries.append(arena, part) catch |e| oom(e); } else if (std.mem.startsWith(u8, part, "-D")) { @@ -151,7 +151,7 @@ fn parseSetupFile( defines.append(arena, part[2..]) catch |e| oom(e); } else if (std.mem.startsWith(u8, part, "-I")) { if (part.len == 2) errExit("{s}:{}: expected '-IPATH' but just got '-I'", .{ file_path, lineno }); - compile_args.append(arena, .{ .include = part[2..] }) catch |e| oom(e); + compile_args.append(arena, .{ .include = arena.dupe(u8, part[2..]) catch |e| oom(e) }) catch |e| oom(e); } else if (std.mem.startsWith(u8, part, "-l")) { if (part.len == 2) errExit("{s}:{}: expected '-lLIB' but just got '-l'", .{ file_path, lineno }); libs.append(arena, part[2..]) catch |e| oom(e); From d974acdceab07c8ad1e8a22cb553a9dd639021ed Mon Sep 17 00:00:00 2001 From: Kenneth Bogert Date: Sat, 24 Oct 2026 00:01:52 -0400 Subject: [PATCH 08/28] Not sure if this is what deepfreeze.py wants? --- build.zig | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/build.zig b/build.zig index 1f5caef..e229e81 100644 --- a/build.zig +++ b/build.zig @@ -140,6 +140,10 @@ pub fn build(b: *std.Build) !void { })); run.addArg("-o"); const deepfreeze_c = run.addOutputFileArg("deepfreeze.c"); + for (frozenModuleNames(version), frozen_headers) |mod_name, header| { + run.addArg(b.fmt("{f}:{s}", .{ header, mod_name })); + } + // { // // Need to create a custom step because std.Build.Step.Run doesn't // // have addSuffixedOutputArg. @@ -814,7 +818,10 @@ fn addPyconfig(b: *std.Build, version: Version, upstream: *std.Build.Dependency, try configquery.resolveQueries(b, &.{ config_common_path, vers_file_path }, config_header, configquery_config); // hardcode for now - if (libs.zlib) |_| config_header.values.put(b.allocator, "HAVE_ZLIB_COPY", .{ .int = 1 }) catch @panic("OOM"); + if (libs.zlib) |_| { + config_header.values.put(b.allocator, "HAVE_ZLIB_COPY", .{ .int = 1 }) catch @panic("OOM"); + config_header.values.put(b.allocator, "HAVE_ZLIB_H", .{ .int = 1 }) catch @panic("OOM"); + } // if (libs.openssl) |openssl| try configquery_config.include_dirs.append(b.allocator, openssl.getEmittedIncludeTree()); From be0c09532551a644c52c850e79b6bae0cece708e Mon Sep 17 00:00:00 2001 From: Kenneth Bogert Date: Sat, 24 Oct 2026 00:12:10 -0400 Subject: [PATCH 09/28] Missed this line --- makesetup.zig | 1 + 1 file changed, 1 insertion(+) diff --git a/makesetup.zig b/makesetup.zig index bc5f181..8b07a7f 100644 --- a/makesetup.zig +++ b/makesetup.zig @@ -47,6 +47,7 @@ pub fn writeConfigC( list.appendSlice(alloc, b.fmt(" {{\"{s}\", PyInit_{0s}}},\n", .{entry.key_ptr.*})) catch @panic("OOM"); } } + list.appendSlice(alloc, line) catch @panic("OOM"); list.append(alloc, '\n') catch @panic("OOM"); } return list.toOwnedSlice(alloc) catch @panic("OOM"); From f014b4107ed9e86e770948b5c0457977494485d5 Mon Sep 17 00:00:00 2001 From: Kenneth Bogert Date: Sat, 24 Oct 2026 09:06:32 -0400 Subject: [PATCH 10/28] First successful build --- build.zig | 3 ++- makesetup.zig | 5 ++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/build.zig b/build.zig index e229e81..49298e8 100644 --- a/build.zig +++ b/build.zig @@ -141,7 +141,8 @@ pub fn build(b: *std.Build) !void { run.addArg("-o"); const deepfreeze_c = run.addOutputFileArg("deepfreeze.c"); for (frozenModuleNames(version), frozen_headers) |mod_name, header| { - run.addArg(b.fmt("{f}:{s}", .{ header, mod_name })); + const mod_name_part = b.fmt(":{s}", .{ mod_name }); + run.addFileArg2(header, .{.suffix = mod_name_part}); } // { diff --git a/makesetup.zig b/makesetup.zig index 8b07a7f..b9927f6 100644 --- a/makesetup.zig +++ b/makesetup.zig @@ -152,7 +152,10 @@ fn parseSetupFile( defines.append(arena, part[2..]) catch |e| oom(e); } else if (std.mem.startsWith(u8, part, "-I")) { if (part.len == 2) errExit("{s}:{}: expected '-IPATH' but just got '-I'", .{ file_path, lineno }); - compile_args.append(arena, .{ .include = arena.dupe(u8, part[2..]) catch |e| oom(e) }) catch |e| oom(e); + if (part.len > 11 and std.mem.startsWith(u8, part, "-I$(srcdir)")) { + compile_args.append(arena, .{ .include = arena.dupe(u8, part[11..]) catch |e| oom(e) }) catch |e| oom(e); + } else + compile_args.append(arena, .{ .include = arena.dupe(u8, part[2..]) catch |e| oom(e) }) catch |e| oom(e); } else if (std.mem.startsWith(u8, part, "-l")) { if (part.len == 2) errExit("{s}:{}: expected '-lLIB' but just got '-l'", .{ file_path, lineno }); libs.append(arena, part[2..]) catch |e| oom(e); From 3294eeca47a6d150210e66347100baa246e78158 Mon Sep 17 00:00:00 2001 From: Kenneth Bogert Date: Sat, 24 Oct 2026 09:15:50 -0400 Subject: [PATCH 11/28] Cleanup and enabke CI --- build.zig | 66 +++++++++---------------------------------------------- 1 file changed, 10 insertions(+), 56 deletions(-) diff --git a/build.zig b/build.zig index 49298e8..bfec8c8 100644 --- a/build.zig +++ b/build.zig @@ -144,42 +144,6 @@ pub fn build(b: *std.Build) !void { const mod_name_part = b.fmt(":{s}", .{ mod_name }); run.addFileArg2(header, .{.suffix = mod_name_part}); } - - // { - // // Need to create a custom step because std.Build.Step.Run doesn't - // // have addSuffixedOutputArg. - // const AddModules = struct { - // step: std.Build.Step, - // version: Version, - // run_deepfreeze: *std.Build.Step.Run, - // headers: []const std.Build.LazyPath, - // }; - // const add_modules_make = struct { - // fn make(step: *std.Build.Step, options: std.Build.Step.StepOptions) anyerror!void { - // _ = options; - // const b2 = step.owner; - // const self: *AddModules = @fieldParentPtr("step", step); - // for (frozenModuleNames(self.version), self.headers) |mod_name, header| { - // self.run_deepfreeze.addArg(b2.fmt("{s}:{s}", .{ header.getPath(b2), mod_name })); - // } - // } - // }.make; - // _ = add_modules_make; - // const add_modules = b.allocator.create(AddModules) catch @panic("OOM"); - // add_modules.* = .{ - // .step = std.Build.Step.init(.{ - // .tag = .run, - // .name = "add modules to run deepfreeze.py", - // .owner = b, - // }), - // .version = version, - // .run_deepfreeze = run, - // .headers = frozen_headers, - // }; - // add_modules.step.dependOn(freeze_step); - // run.step.dependOn(&add_modules.step); - // } - b.step("deepfreeze", "").dependOn(&run.step); break :blk_deepfreeze_c .{ frozen_headers, deepfreeze_c }; }; @@ -204,16 +168,13 @@ pub fn build(b: *std.Build) !void { }); b.getInstallStep().dependOn(&install_final.step); - // const ci_step = b.step("ci", "The build/test step to run on the CI"); - // ci_step.dependOn(b.getInstallStep()); - // try ci(b, version, ssl_enabled, upstream, ci_step, .{ - // .replace_exe = replace_exe, - // .makesetup_exe = makesetup_exe, - // .configquery_exe = configquery_exe, - // .stage2_frozen_mods = stage2_frozen_mods, - // .frozen_headers = frozen_headers, - // .deepfreeze_c = deepfreeze_c, - // }); + const ci_step = b.step("ci", "The build/test step to run on the CI"); + ci_step.dependOn(b.getInstallStep()); + try ci(b, version, ssl_enabled, upstream, ci_step, .{ + .stage2_frozen_mods = stage2_frozen_mods, + .frozen_headers = frozen_headers, + .deepfreeze_c = deepfreeze_c, + }); } fn noUpstream(b: *std.Build) *std.Build.Dependency { @@ -1081,9 +1042,6 @@ fn ci( upstream: *std.Build.Dependency, ci_step: *std.Build.Step, args: struct { - replace_exe: *std.Build.Step.Compile, - makesetup_exe: *std.Build.Step.Compile, - configquery_exe: *std.Build.Step.Compile, stage2_frozen_mods: Stage2FrozenMods, frozen_headers: []const std.Build.LazyPath, deepfreeze_c: std.Build.LazyPath, @@ -1129,15 +1087,11 @@ fn ci( .optimize = optimize, })) |dep| dep.artifact("openssl") else null) else null, }; - const makesetups = addMakesetup(b, version, upstream, libs, .{ - .os_tag = target.result.os.tag, - .replace_exe = args.replace_exe, - .makesetup_exe = args.makesetup_exe, - }); + const makesetups = addMakesetup(b, version, upstream, libs, target.result.os.tag); const exe = addPythonExe(b, upstream, target, optimize, .{ .name = "python", - .makesetup_out = makesetups, - .pyconfig = try addPyconfig(b, version, upstream, target, libs, args.configquery_exe), + .setup = makesetups, + .pyconfig = try addPyconfig(b, version, upstream, target, libs), .stage = .{ .final = .{ .stage2 = args.stage2_frozen_mods, .frozen_headers = args.frozen_headers, From 11ddaa9a73103717a4669b0cc6b9d75a6c2111b5 Mon Sep 17 00:00:00 2001 From: Kenneth Bogert Date: Sat, 24 Oct 2026 09:53:11 -0400 Subject: [PATCH 12/28] Add Todo notes --- build.zig | 3 ++- configquery.zig | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/build.zig b/build.zig index bfec8c8..c2f1402 100644 --- a/build.zig +++ b/build.zig @@ -779,12 +779,13 @@ fn addPyconfig(b: *std.Build, version: Version, upstream: *std.Build.Dependency, try configquery.resolveQueries(b, &.{ config_common_path, vers_file_path }, config_header, configquery_config); - // hardcode for now + // TODO: Hardcode for now, need a configure accessible path to a dependency's upstream's include paths if (libs.zlib) |_| { config_header.values.put(b.allocator, "HAVE_ZLIB_COPY", .{ .int = 1 }) catch @panic("OOM"); config_header.values.put(b.allocator, "HAVE_ZLIB_H", .{ .int = 1 }) catch @panic("OOM"); } + // TODO: OpenSSL doesn't impact the configure? // if (libs.openssl) |openssl| try configquery_config.include_dirs.append(b.allocator, openssl.getEmittedIncludeTree()); } diff --git a/configquery.zig b/configquery.zig index 507713d..b5c7a8e 100644 --- a/configquery.zig +++ b/configquery.zig @@ -270,7 +270,7 @@ fn doCompileCheck( else => @compileError("unsupported OS"), }; var task_dir_buf: [std.fs.max_path_bytes]u8 = undefined; - const base_dir = "."; + const base_dir = "."; // TODO: Need a reliable temporary directory instead of the build path to place the test programs const task_dir = std.fmt.bufPrint(&task_dir_buf, "{s}" ++ sep ++ "tmp" ++ sep ++ "cq-{}-{}", .{ base_dir, pid, index }) catch fatal("cache-dir path too long", .{}); From a0460760a525cf706f69deeebb718a931d391e19 Mon Sep 17 00:00:00 2001 From: Kenneth Bogert Date: Sat, 24 Oct 2026 10:03:13 -0400 Subject: [PATCH 13/28] Add build option to turn on logging of compile comments during config query. --- build.zig | 15 +++++++++------ configquery.zig | 4 ++-- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/build.zig b/build.zig index c2f1402..3e5f89b 100644 --- a/build.zig +++ b/build.zig @@ -43,6 +43,8 @@ const Stage2FrozenMods = struct { pub fn build(b: *std.Build) !void { const version: Version = b.option(Version, "version", "Python Version") orelse .latest; + const log_error_comments = b.option(bool, "log_error_comments", "Log compile errors during config query") orelse false; + const upstream: *std.Build.Dependency = switch (version) { .@"3.11.13" => if (b.lazyDependency("upstream_3.11.13", .{})) |d| d else noUpstream(b), .@"3.12.11" => if (b.lazyDependency("upstream_3.12.11", .{})) |d| d else noUpstream(b), @@ -73,7 +75,7 @@ pub fn build(b: *std.Build) !void { const makesetup_host = addMakesetup(b, version, upstream, libs_host, b.graph.host.result.os.tag); const makesetup_target = addMakesetup(b, version, upstream, libs_target, target.result.os.tag); - const pyconfig_host = try addPyconfig(b, version, upstream, b.graph.host, .{ .zlib = null, .openssl = null }); + const pyconfig_host = try addPyconfig(b, version, upstream, b.graph.host, .{ .zlib = null, .openssl = null }, log_error_comments); const freeze_module_exe = addPythonExe(b, upstream, b.graph.host, .Debug, .{ .name = "freeze_module", @@ -151,7 +153,7 @@ pub fn build(b: *std.Build) !void { const final_exe = addPythonExe(b, upstream, target, optimize, .{ .name = "python", .setup = makesetup_target, - .pyconfig = try addPyconfig(b, version, upstream, target, libs_target), + .pyconfig = try addPyconfig(b, version, upstream, target, libs_target, log_error_comments), .stage = .{ .final = .{ .stage2 = stage2_frozen_mods, @@ -174,7 +176,7 @@ pub fn build(b: *std.Build) !void { .stage2_frozen_mods = stage2_frozen_mods, .frozen_headers = frozen_headers, .deepfreeze_c = deepfreeze_c, - }); + }, log_error_comments); } fn noUpstream(b: *std.Build) *std.Build.Dependency { @@ -579,7 +581,7 @@ const Libs = struct { openssl: ?*std.Build.Step.Compile, }; -fn addPyconfig(b: *std.Build, version: Version, upstream: *std.Build.Dependency, target: std.Build.ResolvedTarget, libs: Libs) !Pyconfig { +fn addPyconfig(b: *std.Build, version: Version, upstream: *std.Build.Dependency, target: std.Build.ResolvedTarget, libs: Libs, log_error_comments: bool) !Pyconfig { const t = target.result; if (t.os.tag == .windows) return .{ .version = version, @@ -777,7 +779,7 @@ fn addPyconfig(b: *std.Build, version: Version, upstream: *std.Build.Dependency, const config_common_path = b.pathJoin(&.{ build_root, "config-common" }); b.dependOnFileContents(b.path("config-common")); - try configquery.resolveQueries(b, &.{ config_common_path, vers_file_path }, config_header, configquery_config); + try configquery.resolveQueries(b, &.{ config_common_path, vers_file_path }, config_header, configquery_config, log_error_comments); // TODO: Hardcode for now, need a configure accessible path to a dependency's upstream's include paths if (libs.zlib) |_| { @@ -1047,6 +1049,7 @@ fn ci( frozen_headers: []const std.Build.LazyPath, deepfreeze_c: std.Build.LazyPath, }, + log_error_comments: bool, ) !void { const CiTarget = struct { triple: []const u8, ssl: bool }; const ci_targets = [_]CiTarget{ @@ -1092,7 +1095,7 @@ fn ci( const exe = addPythonExe(b, upstream, target, optimize, .{ .name = "python", .setup = makesetups, - .pyconfig = try addPyconfig(b, version, upstream, target, libs), + .pyconfig = try addPyconfig(b, version, upstream, target, libs, log_error_comments), .stage = .{ .final = .{ .stage2 = args.stage2_frozen_mods, .frozen_headers = args.frozen_headers, diff --git a/configquery.zig b/configquery.zig index b5c7a8e..f862076 100644 --- a/configquery.zig +++ b/configquery.zig @@ -1,4 +1,4 @@ -pub fn resolveQueries(b: *std.Build, template_files: []const []const u8, config_header: *ConfigHeader, config: Config) !void { +pub fn resolveQueries(b: *std.Build, template_files: []const []const u8, config_header: *ConfigHeader, config: Config, log_error_comments: bool) !void { const arena = b.allocator; const io = b.graph.io; @@ -74,7 +74,7 @@ pub fn resolveQueries(b: *std.Build, template_files: []const []const u8, config_ error_count += 1; reportError(io, q.file_path, q.line_num, "{s} '{s}'", .{ q.input.config_name, value_text }); } - if (result.error_comments.len > 0) { + if (result.error_comments.len > 0 and log_error_comments) { std.log.debug("{s}{s} {s} : {s}\n", .{ result.error_comments, q.input.config_name, q.input.pass_text, q.input.fail_text }); } } From 6083ed1197b337bf1ce319fefe13a44017057f9f Mon Sep 17 00:00:00 2001 From: Kenneth Bogert Date: Sat, 24 Oct 2026 11:32:38 -0400 Subject: [PATCH 14/28] Need to check the lazy dependencies after all build options --- build.zig | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/build.zig b/build.zig index 3e5f89b..a2bd8ed 100644 --- a/build.zig +++ b/build.zig @@ -50,8 +50,6 @@ pub fn build(b: *std.Build) !void { .@"3.12.11" => if (b.lazyDependency("upstream_3.12.11", .{})) |d| d else noUpstream(b), }; - if (b.graph.needed_lazy_dependencies.count() > 0) return; - const target = b.standardTargetOptions(.{}); const optimize = b.standardOptimizeOption(.{}); @@ -72,6 +70,8 @@ pub fn build(b: *std.Build) !void { })) |dep| dep.artifact("openssl") else null) else null, }; + if (b.graph.needed_lazy_dependencies.count() > 0) return; + const makesetup_host = addMakesetup(b, version, upstream, libs_host, b.graph.host.result.os.tag); const makesetup_target = addMakesetup(b, version, upstream, libs_target, target.result.os.tag); @@ -143,8 +143,8 @@ pub fn build(b: *std.Build) !void { run.addArg("-o"); const deepfreeze_c = run.addOutputFileArg("deepfreeze.c"); for (frozenModuleNames(version), frozen_headers) |mod_name, header| { - const mod_name_part = b.fmt(":{s}", .{ mod_name }); - run.addFileArg2(header, .{.suffix = mod_name_part}); + const mod_name_part = b.fmt(":{s}", .{mod_name}); + run.addFileArg2(header, .{ .suffix = mod_name_part }); } b.step("deepfreeze", "").dependOn(&run.step); break :blk_deepfreeze_c .{ frozen_headers, deepfreeze_c }; From 2e4997fed71286d180a90fba879637e05443f1cd Mon Sep 17 00:00:00 2001 From: Kenneth Bogert Date: Sat, 24 Oct 2026 11:43:19 -0400 Subject: [PATCH 15/28] Update zon file --- build.zig.zon | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/build.zig.zon b/build.zig.zon index 97def5a..a51558f 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -1,8 +1,8 @@ .{ .name = .cpython, .fingerprint = 0x3224901d1babdd14, - .version = "0.1.0", - .minimum_zig_version = "0.16.0", + .version = "0.2.0", + .minimum_zig_version = "0.17.0", .dependencies = .{ .@"upstream_3.11.13" = .{ .url = "git+https://github.com/python/cpython#498b971ea3673012a1d4b21860b229d55fc6e575", @@ -31,6 +31,8 @@ "makesetup.zig", "replace.zig", "ConfigHeaderExt.zig", - "config-*", + "config-common", + "config-3.11.13", + "config-3.12.11", }, } From adff5b40a94f4410b8297a70f8c24bc7955d833d Mon Sep 17 00:00:00 2001 From: Kenneth Bogert Date: Sun, 25 Oct 2026 00:30:41 -0400 Subject: [PATCH 16/28] Enable the SHA2 module for cPython >= 3.12 by compiling _hacl to a static library as upstream does. Closes #17 --- build.zig | 50 +++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 47 insertions(+), 3 deletions(-) diff --git a/build.zig b/build.zig index a2bd8ed..5d03289 100644 --- a/build.zig +++ b/build.zig @@ -58,7 +58,27 @@ pub fn build(b: *std.Build) !void { else => true, }; - const libs_host: Libs = .{ .zlib = null, .openssl = null }; + var hacl: ?*std.Build.Step.Compile = undefined; + if (version == .@"3.12.11") { + hacl = b.addLibrary(.{ + .name = "hacl", + .linkage = .static, + .root_module = b.createModule(.{ + .target = target, + .optimize = optimize, + .link_libc = true, + }), + }); + hacl.?.root_module.addIncludePath(upstream.path("./Modules/_hacl/include")); + hacl.?.root_module.addIncludePath(upstream.path("./Modules/_hacl/")); + hacl.?.root_module.addCSourceFile(.{ .file = upstream.path("./Modules/_hacl/Hacl_Hash_SHA2.c"), .flags = &.{ + "-D_BSD_SOURCE", "-D_DEFAULT_SOURCE", "-fwrapv", + "-std=c11", "-fvisibility=hidden", "-DVPATH=\"\"", + } }); + b.installArtifact(hacl.?); + } else hacl = null; + + const libs_host: Libs = .{ .zlib = null, .openssl = null, .hacl = hacl }; const libs_target: Libs = .{ .zlib = (b.dependency("zlib", .{ .target = target, @@ -68,6 +88,7 @@ pub fn build(b: *std.Build) !void { .target = target, .optimize = optimize, })) |dep| dep.artifact("openssl") else null) else null, + .hacl = hacl, }; if (b.graph.needed_lazy_dependencies.count() > 0) return; @@ -75,7 +96,7 @@ pub fn build(b: *std.Build) !void { const makesetup_host = addMakesetup(b, version, upstream, libs_host, b.graph.host.result.os.tag); const makesetup_target = addMakesetup(b, version, upstream, libs_target, target.result.os.tag); - const pyconfig_host = try addPyconfig(b, version, upstream, b.graph.host, .{ .zlib = null, .openssl = null }, log_error_comments); + const pyconfig_host = try addPyconfig(b, version, upstream, b.graph.host, libs_host, log_error_comments); const freeze_module_exe = addPythonExe(b, upstream, b.graph.host, .Debug, .{ .name = "freeze_module", @@ -288,7 +309,7 @@ fn addMakesetup( }; const @"stdlib_modules_3.12.11" = .{ ._ctypes = false, - ._sha2 = false, + ._sha2 = true, .xxsubtype = false, ._xxinterpchannels = false, }; @@ -555,6 +576,7 @@ fn addPythonExe( if (args.pyconfig.libs.zlib) |zlib| exe.root_module.linkLibrary(zlib); if (args.pyconfig.libs.openssl) |openssl| exe.root_module.linkLibrary(openssl); + if (args.pyconfig.libs.hacl) |hacl| exe.root_module.linkLibrary(hacl); if (target.result.os.tag == .windows) { exe.root_module.linkSystemLibrary("ws2_32", .{}); @@ -579,6 +601,7 @@ const Pyconfig = struct { const Libs = struct { zlib: ?*std.Build.Step.Compile, openssl: ?*std.Build.Step.Compile, + hacl: ?*std.Build.Step.Compile, }; fn addPyconfig(b: *std.Build, version: Version, upstream: *std.Build.Dependency, target: std.Build.ResolvedTarget, libs: Libs, log_error_comments: bool) !Pyconfig { @@ -1081,6 +1104,26 @@ fn ci( const install = b.step(b.fmt("install-{s}", .{ci_target.triple}), ""); ci_step.dependOn(install); + var hacl: ?*std.Build.Step.Compile = undefined; + if (version == .@"3.12.11") { + hacl = b.addLibrary(.{ + .name = "hacl", + .linkage = .static, + .root_module = b.createModule(.{ + .target = target, + .optimize = optimize, + .link_libc = true, + }), + }); + hacl.?.root_module.addIncludePath(upstream.path("./Modules/_hacl/include")); + hacl.?.root_module.addIncludePath(upstream.path("./Modules/_hacl/")); + hacl.?.root_module.addCSourceFile(.{ .file = upstream.path("./Modules/_hacl/Hacl_Hash_SHA2.c"), .flags = &.{ + "-D_BSD_SOURCE", "-D_DEFAULT_SOURCE", "-fwrapv", + "-std=c11", "-fvisibility=hidden", "-DVPATH=\"\"", + } }); + b.installArtifact(hacl.?); + } else hacl = null; + const libs: Libs = .{ .zlib = (b.dependency("zlib", .{ .target = target, @@ -1090,6 +1133,7 @@ fn ci( .target = target, .optimize = optimize, })) |dep| dep.artifact("openssl") else null) else null, + .hacl = hacl, }; const makesetups = addMakesetup(b, version, upstream, libs, target.result.os.tag); const exe = addPythonExe(b, upstream, target, optimize, .{ From 3bcd2cda780c8ef2507f37d624cc9eebc4701d36 Mon Sep 17 00:00:00 2001 From: Kenneth Bogert Date: Sun, 25 Oct 2026 12:49:03 -0400 Subject: [PATCH 17/28] Only need sha2 for the target binary, so we can disable it for the two other builds (and avoid the need to compile hacl for both the host and target archs) --- build.zig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.zig b/build.zig index 5d03289..c82467d 100644 --- a/build.zig +++ b/build.zig @@ -78,7 +78,7 @@ pub fn build(b: *std.Build) !void { b.installArtifact(hacl.?); } else hacl = null; - const libs_host: Libs = .{ .zlib = null, .openssl = null, .hacl = hacl }; + const libs_host: Libs = .{ .zlib = null, .openssl = null, .hacl = null }; const libs_target: Libs = .{ .zlib = (b.dependency("zlib", .{ .target = target, @@ -309,7 +309,7 @@ fn addMakesetup( }; const @"stdlib_modules_3.12.11" = .{ ._ctypes = false, - ._sha2 = true, + ._sha2 = (libs.hacl != null), .xxsubtype = false, ._xxinterpchannels = false, }; From bcae5c97266a5359eb14893bd71ba373b4af0cd0 Mon Sep 17 00:00:00 2001 From: Kenneth Bogert Date: Sun, 25 Oct 2026 15:23:07 -0400 Subject: [PATCH 18/28] Minimally fix help('modules') --- build.zig | 18 ++++++++++++++++++ makesetup.zig | 17 +++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/build.zig b/build.zig index c82467d..e60ef4d 100644 --- a/build.zig +++ b/build.zig @@ -474,6 +474,7 @@ fn addPythonExe( "-std=c11", "-fvisibility=hidden", "-DVPATH=\"\"", + "-DABIFLAGS=\"\"", }; var it = args.setup.modules.iterator(); @@ -815,6 +816,23 @@ fn addPyconfig(b: *std.Build, version: Version, upstream: *std.Build.Dependency, } + const sysconfigdata_contents = makesetup.writeSysConfigData(b, config_header); + defer b.allocator.free(sysconfigdata_contents); + + const sysconfigdata_filename = b.fmt("_sysconfigdata__{s}_.py", .{ + switch (t.os.tag) { + .linux => "linux", + .macos => "darwin", + .windows => "win32", + else => std.debug.panic("todo: populate PLATFORM for os '{s}'", .{@tagName(t.os.tag)}), + } + }); + + const wf = b.addWriteFiles(); + const sysconfigdata_file = wf.add(sysconfigdata_filename, sysconfigdata_contents); + const install_step = b.addInstallFile(sysconfigdata_file, b.fmt("lib/python{s}/{s}", .{version.libName(), sysconfigdata_filename})); + b.getInstallStep().dependOn(&install_step.step); + return .{ .version = version, .libs = libs, diff --git a/makesetup.zig b/makesetup.zig index b9927f6..7893b18 100644 --- a/makesetup.zig +++ b/makesetup.zig @@ -246,3 +246,20 @@ fn errExit(comptime fmt: []const u8, args: anytype) noreturn { std.log.err(fmt, args); std.process.exit(0xff); } + +pub fn writeSysConfigData(b: *std.Build, configheader: *std.Build.Step.ConfigHeader) [] const u8 { + + _ = configheader; + + const alloc = b.allocator; + var list: std.ArrayList(u8) = .empty; + defer list.deinit(alloc); + + list.appendSlice(alloc, "build_time_vars = {'ABIFLAGS': ''") catch @panic("OOM"); + + // TODO: Output the values of the config header in a python format + + list.appendSlice(alloc, "}\n") catch @panic("OOM"); + + return list.toOwnedSlice(alloc) catch @panic("OOM"); +} \ No newline at end of file From 5448b5867f127535c426196c2a5f2bf96faa443f Mon Sep 17 00:00:00 2001 From: Kenneth Bogert Date: Mon, 26 Oct 2026 20:17:33 -0400 Subject: [PATCH 19/28] Make the named writefiles include the generated sysconfigdata to ease downstream dependency --- build.zig | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/build.zig b/build.zig index e60ef4d..8b90d8f 100644 --- a/build.zig +++ b/build.zig @@ -139,7 +139,7 @@ pub fn build(b: *std.Build) !void { .pyconfig = pyconfig_host, .stage = .{ .bootstrap = stage2_frozen_mods }, }); - const bootstrap_packaged = packagePython(b, version, upstream, bootstrap_python_exe); + const bootstrap_packaged = packagePython(b, version, upstream, bootstrap_python_exe, &.{}); const frozen_headers = b.allocator.alloc(std.Build.LazyPath, frozen_modules.len) catch @panic("OOM"); // don't free @@ -171,10 +171,11 @@ pub fn build(b: *std.Build) !void { break :blk_deepfreeze_c .{ frozen_headers, deepfreeze_c }; }; + const final_pyconfig = try addPyconfig(b, version, upstream, target, libs_target, log_error_comments); const final_exe = addPythonExe(b, upstream, target, optimize, .{ .name = "python", .setup = makesetup_target, - .pyconfig = try addPyconfig(b, version, upstream, target, libs_target, log_error_comments), + .pyconfig = final_pyconfig, .stage = .{ .final = .{ .stage2 = stage2_frozen_mods, @@ -183,7 +184,7 @@ pub fn build(b: *std.Build) !void { }, }, }); - const final_packaged = packagePython(b, version, upstream, final_exe); + const final_packaged = packagePython(b, version, upstream, final_exe, &.{ final_pyconfig.sysconfigdata.? }); const install_final = b.addInstallDirectory(.{ .source_dir = final_packaged.root, .install_dir = .prefix, @@ -384,17 +385,26 @@ fn addReplacements(list: *std.ArrayList([]const u8), b: *std.Build, comptime Mod } } -fn packagePython(b: *std.Build, version: Version, upstream: *std.Build.Dependency, exe: *std.Build.Step.Compile) struct { +const other_libs = struct { + path: std.Build.LazyPath, + name: []const u8, +}; + +fn packagePython(b: *std.Build, version: Version, upstream: *std.Build.Dependency, exe: *std.Build.Step.Compile, libs: []const other_libs) struct { root: std.Build.LazyPath, exe: std.Build.LazyPath, } { const write_files = b.addNamedWriteFiles(exe.name); _ = write_files.addCopyDirectory(upstream.path("Lib"), b.fmt("lib/python{s}", .{version.libName()}), .{}); + for (libs) |lib| { + _ = write_files.addCopyFile(lib.path, b.fmt("lib/python{s}/{s}", .{version.libName(), lib.name})); + } const empty_dir = b.addWriteFiles().getDirectory(); _ = write_files.addCopyDirectory(empty_dir, b.fmt("lib/python{s}/lib-dynload", .{version.libName()}), .{}); if (exe.producesPdbFile()) { _ = write_files.addCopyFile(exe.getEmittedPdb(), b.fmt("bin/{s}.pdb", .{exe.name})); } + b.getInstallStep().dependOn(&write_files.step); return .{ .root = write_files.getDirectory(), .exe = write_files.addCopyFile( @@ -597,6 +607,7 @@ const Pyconfig = struct { path: std.Build.LazyPath, config_header: *std.Build.Step.ConfigHeader, }, + sysconfigdata: ?other_libs, }; const Libs = struct { @@ -611,6 +622,7 @@ fn addPyconfig(b: *std.Build, version: Version, upstream: *std.Build.Dependency, .version = version, .libs = libs, .header = .{ .path = upstream.path("PC/pyconfig.h") }, + .sysconfigdata = null, }; const config_header = b.addConfigHeader(.{ @@ -830,13 +842,12 @@ fn addPyconfig(b: *std.Build, version: Version, upstream: *std.Build.Dependency, const wf = b.addWriteFiles(); const sysconfigdata_file = wf.add(sysconfigdata_filename, sysconfigdata_contents); - const install_step = b.addInstallFile(sysconfigdata_file, b.fmt("lib/python{s}/{s}", .{version.libName(), sysconfigdata_filename})); - b.getInstallStep().dependOn(&install_step.step); return .{ .version = version, .libs = libs, .header = .{ .config_header = config_header }, + .sysconfigdata = .{.path =sysconfigdata_file, .name=sysconfigdata_filename}, }; } From f91292874cb85832af0bf78038ec03fb8d5c88af Mon Sep 17 00:00:00 2001 From: Kenneth Bogert Date: Thu, 29 Oct 2026 13:08:03 -0400 Subject: [PATCH 20/28] Need to not sanitize functions if compiling in ReleaseSafe --- build.zig | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/build.zig b/build.zig index 8b90d8f..ae67e77 100644 --- a/build.zig +++ b/build.zig @@ -184,7 +184,7 @@ pub fn build(b: *std.Build) !void { }, }, }); - const final_packaged = packagePython(b, version, upstream, final_exe, &.{ final_pyconfig.sysconfigdata.? }); + const final_packaged = packagePython(b, version, upstream, final_exe, &.{final_pyconfig.sysconfigdata.?}); const install_final = b.addInstallDirectory(.{ .source_dir = final_packaged.root, .install_dir = .prefix, @@ -397,14 +397,14 @@ fn packagePython(b: *std.Build, version: Version, upstream: *std.Build.Dependenc const write_files = b.addNamedWriteFiles(exe.name); _ = write_files.addCopyDirectory(upstream.path("Lib"), b.fmt("lib/python{s}", .{version.libName()}), .{}); for (libs) |lib| { - _ = write_files.addCopyFile(lib.path, b.fmt("lib/python{s}/{s}", .{version.libName(), lib.name})); + _ = write_files.addCopyFile(lib.path, b.fmt("lib/python{s}/{s}", .{ version.libName(), lib.name })); } const empty_dir = b.addWriteFiles().getDirectory(); _ = write_files.addCopyDirectory(empty_dir, b.fmt("lib/python{s}/lib-dynload", .{version.libName()}), .{}); if (exe.producesPdbFile()) { _ = write_files.addCopyFile(exe.getEmittedPdb(), b.fmt("bin/{s}.pdb", .{exe.name})); } - b.getInstallStep().dependOn(&write_files.step); + b.getInstallStep().dependOn(&write_files.step); return .{ .root = write_files.getDirectory(), .exe = write_files.addCopyFile( @@ -485,6 +485,7 @@ fn addPythonExe( "-fvisibility=hidden", "-DVPATH=\"\"", "-DABIFLAGS=\"\"", + "-fno-sanitize=function", }; var it = args.setup.modules.iterator(); @@ -831,14 +832,12 @@ fn addPyconfig(b: *std.Build, version: Version, upstream: *std.Build.Dependency, const sysconfigdata_contents = makesetup.writeSysConfigData(b, config_header); defer b.allocator.free(sysconfigdata_contents); - const sysconfigdata_filename = b.fmt("_sysconfigdata__{s}_.py", .{ - switch (t.os.tag) { - .linux => "linux", - .macos => "darwin", - .windows => "win32", - else => std.debug.panic("todo: populate PLATFORM for os '{s}'", .{@tagName(t.os.tag)}), - } - }); + const sysconfigdata_filename = b.fmt("_sysconfigdata__{s}_.py", .{switch (t.os.tag) { + .linux => "linux", + .macos => "darwin", + .windows => "win32", + else => std.debug.panic("todo: populate PLATFORM for os '{s}'", .{@tagName(t.os.tag)}), + }}); const wf = b.addWriteFiles(); const sysconfigdata_file = wf.add(sysconfigdata_filename, sysconfigdata_contents); @@ -847,7 +846,7 @@ fn addPyconfig(b: *std.Build, version: Version, upstream: *std.Build.Dependency, .version = version, .libs = libs, .header = .{ .config_header = config_header }, - .sysconfigdata = .{.path =sysconfigdata_file, .name=sysconfigdata_filename}, + .sysconfigdata = .{ .path = sysconfigdata_file, .name = sysconfigdata_filename }, }; } From 96382d11ecfe51b001519f48edafc4f5601c56c0 Mon Sep 17 00:00:00 2001 From: Kenneth Bogert Date: Fri, 30 Oct 2026 09:00:26 -0400 Subject: [PATCH 21/28] Stop hacl from being built for all CI platforms when CI is not being run. --- build.zig | 1 - 1 file changed, 1 deletion(-) diff --git a/build.zig b/build.zig index ae67e77..eb66b5d 100644 --- a/build.zig +++ b/build.zig @@ -1149,7 +1149,6 @@ fn ci( "-D_BSD_SOURCE", "-D_DEFAULT_SOURCE", "-fwrapv", "-std=c11", "-fvisibility=hidden", "-DVPATH=\"\"", } }); - b.installArtifact(hacl.?); } else hacl = null; const libs: Libs = .{ From f3ff28bcd52b63294927016a3a2d855ea09405fb Mon Sep 17 00:00:00 2001 From: Kenneth Bogert Date: Fri, 30 Oct 2026 09:00:26 -0400 Subject: [PATCH 22/28] Stop hacl from being built for all CI platforms when CI is not being run. --- build.zig | 1 - 1 file changed, 1 deletion(-) diff --git a/build.zig b/build.zig index e60ef4d..0823e8f 100644 --- a/build.zig +++ b/build.zig @@ -1139,7 +1139,6 @@ fn ci( "-D_BSD_SOURCE", "-D_DEFAULT_SOURCE", "-fwrapv", "-std=c11", "-fvisibility=hidden", "-DVPATH=\"\"", } }); - b.installArtifact(hacl.?); } else hacl = null; const libs: Libs = .{ From 07897f0c035c621eb2011bd52e2e092a35a44405 Mon Sep 17 00:00:00 2001 From: Kenneth Bogert Date: Fri, 30 Oct 2026 09:33:03 -0400 Subject: [PATCH 23/28] Reduce redundant compiler flags. --- build.zig | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/build.zig b/build.zig index 0823e8f..db479a0 100644 --- a/build.zig +++ b/build.zig @@ -483,7 +483,6 @@ fn addPythonExe( for (entry.value_ptr.compile_args) |compile_arg| switch (compile_arg) { .source => |src| exe.root_module.addCSourceFile(.{ .file = upstream.path(b.fmt("Modules/{s}", .{src})), - .flags = &flags_common, }), .include => |inc| exe.root_module.addIncludePath(upstream.path(b.fmt("{s}", .{inc}))), }; @@ -819,18 +818,16 @@ fn addPyconfig(b: *std.Build, version: Version, upstream: *std.Build.Dependency, const sysconfigdata_contents = makesetup.writeSysConfigData(b, config_header); defer b.allocator.free(sysconfigdata_contents); - const sysconfigdata_filename = b.fmt("_sysconfigdata__{s}_.py", .{ - switch (t.os.tag) { - .linux => "linux", - .macos => "darwin", - .windows => "win32", - else => std.debug.panic("todo: populate PLATFORM for os '{s}'", .{@tagName(t.os.tag)}), - } - }); + const sysconfigdata_filename = b.fmt("_sysconfigdata__{s}_.py", .{switch (t.os.tag) { + .linux => "linux", + .macos => "darwin", + .windows => "win32", + else => std.debug.panic("todo: populate PLATFORM for os '{s}'", .{@tagName(t.os.tag)}), + }}); const wf = b.addWriteFiles(); const sysconfigdata_file = wf.add(sysconfigdata_filename, sysconfigdata_contents); - const install_step = b.addInstallFile(sysconfigdata_file, b.fmt("lib/python{s}/{s}", .{version.libName(), sysconfigdata_filename})); + const install_step = b.addInstallFile(sysconfigdata_file, b.fmt("lib/python{s}/{s}", .{ version.libName(), sysconfigdata_filename })); b.getInstallStep().dependOn(&install_step.step); return .{ From 9b357b7832c1f877d3ea5d93736320f74641b675 Mon Sep 17 00:00:00 2001 From: Kenneth Bogert Date: Fri, 30 Oct 2026 09:33:03 -0400 Subject: [PATCH 24/28] Reduce redundant compiler flags. --- build.zig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build.zig b/build.zig index eb66b5d..91a306f 100644 --- a/build.zig +++ b/build.zig @@ -494,7 +494,6 @@ fn addPythonExe( for (entry.value_ptr.compile_args) |compile_arg| switch (compile_arg) { .source => |src| exe.root_module.addCSourceFile(.{ .file = upstream.path(b.fmt("Modules/{s}", .{src})), - .flags = &flags_common, }), .include => |inc| exe.root_module.addIncludePath(upstream.path(b.fmt("{s}", .{inc}))), }; @@ -841,6 +840,8 @@ fn addPyconfig(b: *std.Build, version: Version, upstream: *std.Build.Dependency, const wf = b.addWriteFiles(); const sysconfigdata_file = wf.add(sysconfigdata_filename, sysconfigdata_contents); + const install_step = b.addInstallFile(sysconfigdata_file, b.fmt("lib/python{s}/{s}", .{ version.libName(), sysconfigdata_filename })); + b.getInstallStep().dependOn(&install_step.step); return .{ .version = version, From 33264f4204929ae9a1e61c781e665a2ab3f63567 Mon Sep 17 00:00:00 2001 From: Kenneth Bogert Date: Fri, 30 Oct 2026 09:39:04 -0400 Subject: [PATCH 25/28] Merge error --- build.zig | 2 -- 1 file changed, 2 deletions(-) diff --git a/build.zig b/build.zig index 91a306f..9ac9fc2 100644 --- a/build.zig +++ b/build.zig @@ -840,8 +840,6 @@ fn addPyconfig(b: *std.Build, version: Version, upstream: *std.Build.Dependency, const wf = b.addWriteFiles(); const sysconfigdata_file = wf.add(sysconfigdata_filename, sysconfigdata_contents); - const install_step = b.addInstallFile(sysconfigdata_file, b.fmt("lib/python{s}/{s}", .{ version.libName(), sysconfigdata_filename })); - b.getInstallStep().dependOn(&install_step.step); return .{ .version = version, From 3acaa825f19ae46d1488e48501a344dc5228608e Mon Sep 17 00:00:00 2001 From: Kenneth Bogert Date: Mon, 2 Nov 2026 00:19:39 -0500 Subject: [PATCH 26/28] Revert configquery back into a seperate program run during build, and move the current ConfigHeader code out of build.zig and into this program. This requires duplicating the functionality offered by the ConfigHeader build step. However, keeping the execution of the compiler out of the configurer greatly speeds up the build process. --- build.zig | 289 +++++++----------------------- configquery.zig | 467 ++++++++++++++++++++++++++++++++++++++++++++++-- makesetup.zig | 12 +- 3 files changed, 519 insertions(+), 249 deletions(-) diff --git a/build.zig b/build.zig index 9ac9fc2..f156de2 100644 --- a/build.zig +++ b/build.zig @@ -43,8 +43,6 @@ const Stage2FrozenMods = struct { pub fn build(b: *std.Build) !void { const version: Version = b.option(Version, "version", "Python Version") orelse .latest; - const log_error_comments = b.option(bool, "log_error_comments", "Log compile errors during config query") orelse false; - const upstream: *std.Build.Dependency = switch (version) { .@"3.11.13" => if (b.lazyDependency("upstream_3.11.13", .{})) |d| d else noUpstream(b), .@"3.12.11" => if (b.lazyDependency("upstream_3.12.11", .{})) |d| d else noUpstream(b), @@ -93,10 +91,18 @@ pub fn build(b: *std.Build) !void { if (b.graph.needed_lazy_dependencies.count() > 0) return; + const configquery_exe = b.addExecutable(.{ + .name = "configquery", + .root_module = b.createModule(.{ + .root_source_file = b.path("configquery.zig"), + .target = b.graph.host, + }), + }); + const makesetup_host = addMakesetup(b, version, upstream, libs_host, b.graph.host.result.os.tag); const makesetup_target = addMakesetup(b, version, upstream, libs_target, target.result.os.tag); - const pyconfig_host = try addPyconfig(b, version, upstream, b.graph.host, libs_host, log_error_comments); + const pyconfig_host = try addPyconfig(b, version, upstream, b.graph.host, libs_host, configquery_exe); const freeze_module_exe = addPythonExe(b, upstream, b.graph.host, .Debug, .{ .name = "freeze_module", @@ -171,7 +177,7 @@ pub fn build(b: *std.Build) !void { break :blk_deepfreeze_c .{ frozen_headers, deepfreeze_c }; }; - const final_pyconfig = try addPyconfig(b, version, upstream, target, libs_target, log_error_comments); + const final_pyconfig = try addPyconfig(b, version, upstream, target, libs_target, configquery_exe); const final_exe = addPythonExe(b, upstream, target, optimize, .{ .name = "python", .setup = makesetup_target, @@ -198,7 +204,7 @@ pub fn build(b: *std.Build) !void { .stage2_frozen_mods = stage2_frozen_mods, .frozen_headers = frozen_headers, .deepfreeze_c = deepfreeze_c, - }, log_error_comments); + }, configquery_exe); } fn noUpstream(b: *std.Build) *std.Build.Dependency { @@ -455,10 +461,7 @@ fn addPythonExe( .windows => "\"win32\"", else => std.debug.panic("todo: populate PLATFORM for os '{s}'", .{@tagName(target.result.os.tag)}), }); - switch (args.pyconfig.header) { - .path => |path| exe.root_module.addIncludePath(path.dirname()), - .config_header => |h| exe.root_module.addConfigHeader(h), - } + exe.root_module.addIncludePath(args.pyconfig.header.dirname()); exe.root_module.addIncludePath(upstream.path(".")); exe.root_module.addIncludePath(upstream.path("Include")); exe.root_module.addIncludePath(upstream.path("Include/internal")); @@ -603,10 +606,7 @@ fn addPythonExe( const Pyconfig = struct { version: Version, libs: Libs, - header: union(enum) { - path: std.Build.LazyPath, - config_header: *std.Build.Step.ConfigHeader, - }, + header: std.Build.LazyPath, sysconfigdata: ?other_libs, }; @@ -616,226 +616,64 @@ const Libs = struct { hacl: ?*std.Build.Step.Compile, }; -fn addPyconfig(b: *std.Build, version: Version, upstream: *std.Build.Dependency, target: std.Build.ResolvedTarget, libs: Libs, log_error_comments: bool) !Pyconfig { +fn addPyconfig( + b: *std.Build, + version: Version, + upstream: *std.Build.Dependency, + target: std.Build.ResolvedTarget, + libs: Libs, + configquery_exe: *std.Build.Step.Compile, +) !Pyconfig { const t = target.result; if (t.os.tag == .windows) return .{ .version = version, .libs = libs, - .header = .{ .path = upstream.path("PC/pyconfig.h") }, + .header = upstream.path("PC/pyconfig.h"), .sysconfigdata = null, }; - const config_header = b.addConfigHeader(.{ - .style = .{ .autoconf_undef = upstream.path("pyconfig.h.in") }, - .include_path = "pyconfig.h", - }, .{ - .ALIGNOF_LONG = 8, - .ALIGNOF_SIZE_T = 8, - .DOUBLE_IS_LITTLE_ENDIAN_IEEE754 = 1, - .ENABLE_IPV6 = 1, - .MAJOR_IN_SYSMACROS = have(t.os.tag == .linux), - .PTHREAD_KEY_T_IS_COMPATIBLE_WITH_INT = 1, - .PTHREAD_SYSTEM_SCHED_SUPPORTED = 1, - .PY_BUILTIN_HASHLIB_HASHES = "md5,sha1,sha256,sha512,sha3,blake2", - .PY_COERCE_C_LOCALE = 1, - .PY_SSL_DEFAULT_CIPHERS = 1, - .PY_SUPPORT_TIER = 2, - .RETSIGTYPE = .void, - .SIZEOF_DOUBLE = 8, - .SIZEOF_FLOAT = 4, - .SIZEOF_FPOS_T = 16, - .SIZEOF_INT = 4, - .SIZEOF_LONG = 8, - .SIZEOF_LONG_DOUBLE = 16, - .SIZEOF_LONG_LONG = 8, - .SIZEOF_OFF_T = 8, - .SIZEOF_PID_T = 4, - .SIZEOF_PTHREAD_KEY_T = 4, - .SIZEOF_PTHREAD_T = 8, - .SIZEOF_SHORT = 2, - .SIZEOF_SIZE_T = 8, - .SIZEOF_TIME_T = 8, - .SIZEOF_UINTPTR_T = 8, - .SIZEOF_VOID_P = 8, - .SIZEOF_WCHAR_T = 4, - .SIZEOF__BOOL = 1, - .STDC_HEADERS = 1, - .SYS_SELECT_WITH_SYS_TIME = 1, - .WITH_DECIMAL_CONTEXTVAR = 1, - .WITH_DOC_STRINGS = 1, - .WITH_FREELISTS = 1, - .WITH_PYMALLOC = 1, - ._DARWIN_C_SOURCE = 1, - ._FILE_OFFSET_BITS = 64, - ._LARGEFILE_SOURCE = 1, - ._NETBSD_SOURCE = 1, - ._POSIX_C_SOURCE = .@"200809L", - ._PYTHONFRAMEWORK = "", - ._REENTRANT = 1, - ._XOPEN_SOURCE = 700, - ._XOPEN_SOURCE_EXTENDED = 1, - .__BSD_VISIBLE = 1, - ._ALL_SOURCE = 1, - ._GNU_SOURCE = 1, - ._POSIX_PTHREAD_SEMANTICS = 1, - ._TANDEM_SOURCE = 1, - .__EXTENSIONS__ = 1, - - .AC_APPLE_UNIVERSAL_BUILD = null, - .AIX_BUILDDATE = null, - .AIX_GENUINE_CPLUSPLUS = null, - .ALT_SOABI = null, - .ANDROID_API_LEVEL = null, - .DOUBLE_IS_ARM_MIXED_ENDIAN_IEEE754 = null, - .DOUBLE_IS_BIG_ENDIAN_IEEE754 = null, - .GETPGRP_HAVE_ARG = null, - .MAJOR_IN_MKDEV = null, - .MVWDELCH_IS_EXPRESSION = null, - .PACKAGE_BUGREPORT = null, - .PACKAGE_NAME = null, - .PACKAGE_STRING = null, - .PACKAGE_TARNAME = null, - .PACKAGE_URL = null, - .PACKAGE_VERSION = null, - .POSIX_SEMAPHORES_NOT_ENABLED = null, - .PYLONG_BITS_IN_DIGIT = null, - .PY_SQLITE_ENABLE_LOAD_EXTENSION = null, - .PY_SQLITE_HAVE_SERIALIZE = null, - .PY_SSL_DEFAULT_CIPHER_STRING = null, - .Py_DEBUG = null, - .Py_ENABLE_SHARED = null, - .Py_HASH_ALGORITHM = null, - .Py_STATS = null, - .Py_SUNOS_VERSION = null, - .Py_TRACE_REFS = null, - .SETPGRP_HAVE_ARG = null, - .SIGNED_RIGHT_SHIFT_ZERO_FILLS = null, - .THREAD_STACK_SIZE = null, - .TIMEMODULE_LIB = null, - .TM_IN_SYS_TIME = null, - .USE_COMPUTED_GOTOS = null, - .WINDOW_HAS_FLAGS = null, - .WITH_DTRACE = null, - .WITH_DYLD = null, - .WITH_EDITLINE = null, - .WITH_LIBINTL = null, - .WITH_NEXT_FRAMEWORK = null, - .WITH_VALGRIND = null, - .X87_DOUBLE_ROUNDING = null, - ._BSD_SOURCE = null, - ._INCLUDE__STDC_A1_SOURCE = null, - ._LARGE_FILES = null, - ._MINIX = null, - ._POSIX_1_SOURCE = null, - ._POSIX_SOURCE = null, - ._POSIX_THREADS = null, - ._WASI_EMULATED_GETPID = null, - ._WASI_EMULATED_PROCESS_CLOCKS = null, - ._WASI_EMULATED_SIGNAL = null, - .clock_t = null, - .@"const" = null, - .gid_t = null, - .mode_t = null, - .off_t = null, - .pid_t = null, - .signed = null, - .size_t = null, - .socklen_t = null, - .uid_t = null, - .WORDS_BIGENDIAN = null, - - .HAVE_BROKEN_MBSTOWCS = null, - .HAVE_BROKEN_NICE = null, - .HAVE_BROKEN_PIPE_BUF = null, - .HAVE_BROKEN_POLL = null, - .HAVE_BROKEN_POSIX_SEMAPHORES = null, - .HAVE_BROKEN_PTHREAD_SIGMASK = null, - .HAVE_BROKEN_SEM_GETVALUE = null, - .HAVE_BROKEN_UNSETENV = null, - - .HAVE_PTHREAD_STUBS = null, - .HAVE_USABLE_WCHAR_T = null, - .HAVE_NON_UNICODE_WCHAR_T_REPRESENTATION = null, - .HAVE_CHROOT = have(t.os.tag == .linux), - .HAVE_GCC_ASM_FOR_MC68881 = have(t.cpu.arch == .m68k), - .HAVE_GCC_ASM_FOR_X64 = have(t.cpu.arch == .x86_64), - .HAVE_GCC_ASM_FOR_X87 = have(t.cpu.arch == .x86_64 or t.cpu.arch == .x86), - // Readline type (static configuration, not function test) - .HAVE_RL_COMPDISP_FUNC_T = null, + const vers_config_file = switch (version) { + .@"3.11.13" => "config-3.11.13", + .@"3.12.11" => "config-3.12.11", + }; + const vers_config_file_path = b.path(vers_config_file); + b.dependOnFileContents(vers_config_file_path); + b.dependOnFileContents(b.path("config-common")); + + const pyconfig_h_in_path = upstream.path("pyconfig.h.in"); + b.dependOnFileContents(pyconfig_h_in_path); + + const run = b.addRunArtifact(configquery_exe); + run.addArg("--zig-exe"); + run.addArg(b.graph.zig_exe); + run.addArg("--cache-dir"); + run.addDirectoryArg(std.Build.LazyPath.cache_root); + run.addArg("-target"); + run.addArg(try target.query.zigTriple(b.allocator)); + run.addArg("-mcpu"); + run.addArg(try target.query.serializeCpuAlloc(b.allocator)); + run.addArg("-version"); + run.addArg(switch (version) { + .@"3.11.13" => "3.11.13", + .@"3.12.11" => "3.12.11", }); - switch (version) { - .@"3.11.13" => config_header.addValues(.{ - .PY_FORMAT_SIZE_T = "z", - .TIME_WITH_SYS_TIME = 1, - .FLOAT_WORDS_BIGENDIAN = null, - }), - .@"3.12.11" => config_header.addValues(.{ - .ALIGNOF_MAX_ALIGN_T = @as(u32, switch (t.cpu.arch) { - .x86_64, .aarch64 => 16, - .x86, .arm => 8, - else => 8, - }), - - // ncurses library (static configuration, not function test) - .HAVE_NCURSESW = null, - - // Performance trampoline feature - .PY_HAVE_PERF_TRAMPOLINE = null, - - ._HPUX_ALT_XOPEN_SOCKET_API = null, - ._OPENBSD_SOURCE = null, - - // C standard feature test macros (all set to null as they're optional) - .__STDC_WANT_IEC_60559_ATTRIBS_EXT__ = null, - .__STDC_WANT_IEC_60559_BFP_EXT__ = null, - .__STDC_WANT_IEC_60559_DFP_EXT__ = null, - .__STDC_WANT_IEC_60559_FUNCS_EXT__ = null, - .__STDC_WANT_IEC_60559_TYPES_EXT__ = null, - .__STDC_WANT_LIB_EXT2__ = null, - .__STDC_WANT_MATH_SPEC_FUNCS__ = null, - }), - } - - { - var configquery_config: configquery.Config = .{}; - configquery_config.zig_exe = b.graph.zig_exe; - configquery_config.target_triple = try target.query.zigTriple(b.allocator); - configquery_config.mcpu = try target.query.serializeCpuAlloc(b.allocator); - - const vers_config_file = switch (version) { - .@"3.11.13" => "config-3.11.13", - .@"3.12.11" => "config-3.12.11", - }; - b.dependOnFileContents(b.path(vers_config_file)); - - const build_root = b.root.root_dir.path orelse "."; - - const vers_file_path = b.pathJoin(&.{ build_root, vers_config_file }); - - const config_common_path = b.pathJoin(&.{ build_root, "config-common" }); - b.dependOnFileContents(b.path("config-common")); - - try configquery.resolveQueries(b, &.{ config_common_path, vers_file_path }, config_header, configquery_config, log_error_comments); - - // TODO: Hardcode for now, need a configure accessible path to a dependency's upstream's include paths - if (libs.zlib) |_| { - config_header.values.put(b.allocator, "HAVE_ZLIB_COPY", .{ .int = 1 }) catch @panic("OOM"); - config_header.values.put(b.allocator, "HAVE_ZLIB_H", .{ .int = 1 }) catch @panic("OOM"); - } - - // TODO: OpenSSL doesn't impact the configure? - // if (libs.openssl) |openssl| try configquery_config.include_dirs.append(b.allocator, openssl.getEmittedIncludeTree()); - - } - - const sysconfigdata_contents = makesetup.writeSysConfigData(b, config_header); + run.addArg("-infile"); + run.addFileArg(pyconfig_h_in_path); + if (libs.zlib) |zlib| run.addPrefixedDirectoryArg("-I", zlib.getEmittedIncludeTree()); + if (libs.openssl) |openssl| run.addPrefixedDirectoryArg("-I", openssl.getEmittedIncludeTree()); + run.addFileArg(b.path("config-common")); + run.addFileArg(vers_config_file_path); + run.addArg("-o"); + const config_header = run.addOutputFileArg("pyconfig.h"); + + const sysconfigdata_contents = makesetup.writeSysConfigData(b); defer b.allocator.free(sysconfigdata_contents); - const sysconfigdata_filename = b.fmt("_sysconfigdata__{s}_.py", .{switch (t.os.tag) { + const sysconfigdata_filename = b.fmt("_sysconfigdata__{s}_.py", .{switch (target.result.os.tag) { .linux => "linux", .macos => "darwin", .windows => "win32", - else => std.debug.panic("todo: populate PLATFORM for os '{s}'", .{@tagName(t.os.tag)}), + else => std.debug.panic("todo: populate PLATFORM for os '{s}'", .{@tagName(target.result.os.tag)}), }}); const wf = b.addWriteFiles(); @@ -844,15 +682,11 @@ fn addPyconfig(b: *std.Build, version: Version, upstream: *std.Build.Dependency, return .{ .version = version, .libs = libs, - .header = .{ .config_header = config_header }, + .header = config_header, .sysconfigdata = .{ .path = sysconfigdata_file, .name = sysconfigdata_filename }, }; } -fn have(x: bool) ?u1 { - return if (x) 1 else null; -} - const Config = struct { name: []const u8, string: []const u8 }; fn concatConfigs(comptime first: anytype, comptime second: anytype) [std.meta.fields(@TypeOf(first)).len + std.meta.fields(@TypeOf(second)).len]Config { const first_len = std.meta.fields(@TypeOf(first)).len; @@ -1099,7 +933,7 @@ fn ci( frozen_headers: []const std.Build.LazyPath, deepfreeze_c: std.Build.LazyPath, }, - log_error_comments: bool, + configquery_exe: *std.Build.Step.Compile, ) !void { const CiTarget = struct { triple: []const u8, ssl: bool }; const ci_targets = [_]CiTarget{ @@ -1165,7 +999,7 @@ fn ci( const exe = addPythonExe(b, upstream, target, optimize, .{ .name = "python", .setup = makesetups, - .pyconfig = try addPyconfig(b, version, upstream, target, libs, log_error_comments), + .pyconfig = try addPyconfig(b, version, upstream, target, libs, configquery_exe), .stage = .{ .final = .{ .stage2 = args.stage2_frozen_mods, .frozen_headers = args.frozen_headers, @@ -1199,4 +1033,3 @@ fn concat(allocator: std.mem.Allocator, lists: []const []const []const u8) []con const std = @import("std"); const replace = @import("replace.zig"); const makesetup = @import("makesetup.zig"); -const configquery = @import("configquery.zig"); diff --git a/configquery.zig b/configquery.zig index f862076..0f46171 100644 --- a/configquery.zig +++ b/configquery.zig @@ -1,12 +1,105 @@ -pub fn resolveQueries(b: *std.Build, template_files: []const []const u8, config_header: *ConfigHeader, config: Config, log_error_comments: bool) !void { - const arena = b.allocator; - const io = b.graph.io; +pub fn main(init: std.process.Init) !void { + const arena = init.arena.allocator(); + const io = init.io; + + var template_files: std.ArrayList([]const u8) = .empty; + var output_path: ?[]const u8 = null; + var config: Config = .{}; + var log_error_comments = false; + + { + var args = try init.minimal.args.iterateAllocator(arena); + _ = args.next(); + while (args.next()) |arg| { + if (std.mem.eql(u8, arg, "-o")) { + output_path = args.next() orelse fatal("-o requires an argument", .{}); + } else if (std.mem.eql(u8, arg, "--zig-exe")) { + config.zig_exe = args.next() orelse fatal("--zig-exe requires an argument", .{}); + } else if (std.mem.eql(u8, arg, "--cache-dir")) { + config.cache_dir = args.next() orelse fatal("--cache-dir requires an argument", .{}); + } else if (std.mem.eql(u8, arg, "-target")) { + config.target_triple = args.next() orelse fatal("-target requires an argument", .{}); + } else if (std.mem.eql(u8, arg, "-mcpu")) { + config.mcpu = args.next() orelse fatal("-mcpu requires an argument", .{}); + } else if (std.mem.eql(u8, arg, "-version")) { + config.version = args.next() orelse fatal("-version requires an argument", .{}); + } else if (std.mem.eql(u8, arg, "-infile")) { + config.infile = args.next() orelse fatal("-infile requires an argument", .{}); + } else if (std.mem.eql(u8, arg, "-log_err")) { + log_error_comments = true; + } else if (std.mem.startsWith(u8, arg, "-I")) { + config.include_dirs.append(arena, arg) catch |e| oom(e); + } else { + template_files.append(arena, arg) catch |e| oom(e); + } + } + } + + if (template_files.items.len == 0) { + const usage = + \\Usage: configquery [options] [template-files] + \\ + \\Processes template files line by line. Lines starting with # are + \\comments. Each line is NAME VALUE where VALUE is either a literal + \\or a query starting with ?. + \\ + \\Options: + \\ -o Write output to file (default: stdout) + \\ --zig-exe [exe] Path to zig executable (for compile queries) + \\ -target [name] -- see the targets command + \\ -mcpu [cpu] Specify target CPU and feature set + \\ -version [version] Specify Python version + \\ -infile [python.h.in] Path to python.h.in file + \\ -I[dir] Add directory to include search path + \\ -log_err Log to stderr the failed query output + \\ --cache-dir [path] The local cache directory + \\ + \\Literal Values + \\ SIZEOF_INT 4 + \\ RETSIGTYPE .void + \\ PY_HASH "md5,sha1" + \\ HAVE_FEATURE defined + \\ MISSING_FEATURE undef + \\ + \\Query syntax: NAME ? PASS|FAIL [define=DEF,...] [include=HDR,...] [COMPILE_BODY] + \\ + \\ HAVE_ALLOCA_H ? 1|undef include=alloca.h + \\ HAVE_FORK ? 1|undef include=unistd.h int main(){fork();} + \\ HAVE_PRLIMIT ? 1|undef include=sys/time.h,sys/resource.h int main(){prlimit(0,0,0,0);} + \\ HAVE_CLOSE_RANGE ? 1|undef define=_GNU_SOURCE include=unistd.h int main(){close_range(0,0,0);} + \\ + \\configquery is purposely limited to compile-only (no link). Its up to the caller to ensure + \\header/symbol availability matches library symbol availability. + \\ + ; + var stderr = std.Io.File.stderr().writer(io, &.{}); + stderr.interface.writeAll(usage) catch return stderr.err.?; + stderr.interface.flush() catch return stderr.err.?; + std.process.exit(1); + } + + const config_h_in = std.Io.Dir.cwd().readFileAlloc(io, config.infile.?, arena, .unlimited) catch |err| fatal( + "failed to read '{s}' with {t}", + .{ config.infile.?, err }, + ); + + var config_header: std.array_hash_map.String(ConfigHeader.Value) = .empty; + try initialize_config(io, arena, config, &config_header); + + var out_buf: [4096]u8 = undefined; + var out_file = if (output_path) |path| std.Io.Dir.cwd().createFile(io, path, .{}) catch |err| fatal( + "failed to create '{s}' with {t}", + .{ path, err }, + ) else std.Io.File.stdout(); + defer if (output_path != null) out_file.close(io); + var out_writer = out_file.writer(io, &out_buf); + const out = &out_writer.interface; var queries: std.ArrayList(Query) = .empty; var name_set: std.StringHashMapUnmanaged(u32) = .empty; var error_count: u32 = 0; - for (template_files) |template_path| { + for (template_files.items) |template_path| { const content = std.Io.Dir.cwd().readFileAlloc(io, template_path, arena, .unlimited) catch |err| fatal( "failed to read '{s}' with {t}", .{ template_path, err }, @@ -24,7 +117,7 @@ pub fn resolveQueries(b: *std.Build, template_files: []const []const u8, config_ .literal => |lit| { checkUnique(arena, &name_set, io, template_path, line_num, lit.config_name, &error_count); if (parseValue(lit.value_str)) |entry| { - config_header.values.put(b.allocator, lit.config_name, entry) catch @panic("OOM"); + config_header.put(arena, lit.config_name, entry) catch @panic("OOM"); } else { error_count += 1; reportError(io, template_path, line_num, "{s} '{s}'", .{ lit.config_name, line_untrimmed }); @@ -39,7 +132,7 @@ pub fn resolveQueries(b: *std.Build, template_files: []const []const u8, config_ .line_num = line_num, }) catch |e| oom(e); } else { - config_header.values.put(b.allocator, input.config_name, .{ .string = input.pass_text }) catch @panic("OOM"); + config_header.put(arena, input.config_name, .{ .string = input.pass_text }) catch @panic("OOM"); } }, } @@ -50,11 +143,12 @@ pub fn resolveQueries(b: *std.Build, template_files: []const []const u8, config_ if (queries.items.len > 0) { const zig_exe = config.zig_exe orelse fatal("compile query requires zig-exe", .{}); + const cache_dir = config.cache_dir orelse fatal("compile query requires --cache-dir", .{}); const argv_template = buildArgvTemplate(arena, zig_exe, &config); var group: std.Io.Group = .init; for (queries.items, 0..) |*q, i| { - group.async(io, runCompileCheck, .{ arena, io, q, argv_template, i }); + group.async(io, runCompileCheck, .{ arena, io, q, argv_template, cache_dir, i }); } group.await(io) catch |err| switch (err) { error.Canceled => fatal("canceled", .{}), @@ -69,7 +163,7 @@ pub fn resolveQueries(b: *std.Build, template_files: []const []const u8, config_ const value_text = if (result.success) q.input.pass_text else q.input.fail_text; if (parseValue(value_text)) |entry| { - config_header.values.put(b.allocator, q.input.config_name, entry) catch @panic("OOM"); + config_header.put(arena, q.input.config_name, entry) catch @panic("OOM"); } else { error_count += 1; reportError(io, q.file_path, q.line_num, "{s} '{s}'", .{ q.input.config_name, value_text }); @@ -81,13 +175,25 @@ pub fn resolveQueries(b: *std.Build, template_files: []const []const u8, config_ } } + const all_keys = config_header.keys(); + + var value_map: ValueMap = .empty; + try value_map.ensureTotalCapacity(arena, all_keys.len); + for (all_keys) |key| value_map.putAssumeCapacityNoClobber(key, false); + + try renderAutoConfUndef(config_h_in, out, &config_header, &value_map, config.infile.?); + + out.flush() catch return out_writer.err.?; if (error_count > 0) fatal("{} errors", .{error_count}); } pub const Config = struct { zig_exe: ?[]const u8 = null, + cache_dir: ?[]const u8 = null, target_triple: ?[]const u8 = null, mcpu: ?[]const u8 = null, + version: ?[]const u8 = null, + infile: ?[]const u8 = null, include_dirs: std.ArrayList([]const u8) = .empty, }; @@ -122,7 +228,245 @@ const Query = struct { }; }; -pub fn parseValue(str: []const u8) ?ConfigHeader.Value { +fn have(x: bool) ?u1 { + return if (x) 1 else null; +} + +fn initialize_config(io: std.Io, alloc: std.mem.Allocator, config: Config, config_header: *std.array_hash_map.String(ConfigHeader.Value)) !void { + const query = try std.Target.Query.parse(.{ .arch_os_abi = config.target_triple.? }); + const t = try std.zig.system.resolveTargetQuery(io, query); + + addValues(alloc, config_header, .{ + .ALIGNOF_LONG = 8, + .ALIGNOF_SIZE_T = 8, + .DOUBLE_IS_LITTLE_ENDIAN_IEEE754 = 1, + .ENABLE_IPV6 = 1, + .MAJOR_IN_SYSMACROS = have(t.os.tag == .linux), + .PTHREAD_KEY_T_IS_COMPATIBLE_WITH_INT = 1, + .PTHREAD_SYSTEM_SCHED_SUPPORTED = 1, + .PY_BUILTIN_HASHLIB_HASHES = "md5,sha1,sha256,sha512,sha3,blake2", + .PY_COERCE_C_LOCALE = 1, + .PY_SSL_DEFAULT_CIPHERS = 1, + .PY_SUPPORT_TIER = 2, + .RETSIGTYPE = .void, + .SIZEOF_DOUBLE = 8, + .SIZEOF_FLOAT = 4, + .SIZEOF_FPOS_T = 16, + .SIZEOF_INT = 4, + .SIZEOF_LONG = 8, + .SIZEOF_LONG_DOUBLE = 16, + .SIZEOF_LONG_LONG = 8, + .SIZEOF_OFF_T = 8, + .SIZEOF_PID_T = 4, + .SIZEOF_PTHREAD_KEY_T = 4, + .SIZEOF_PTHREAD_T = 8, + .SIZEOF_SHORT = 2, + .SIZEOF_SIZE_T = 8, + .SIZEOF_TIME_T = 8, + .SIZEOF_UINTPTR_T = 8, + .SIZEOF_VOID_P = 8, + .SIZEOF_WCHAR_T = 4, + .SIZEOF__BOOL = 1, + .STDC_HEADERS = 1, + .SYS_SELECT_WITH_SYS_TIME = 1, + .WITH_DECIMAL_CONTEXTVAR = 1, + .WITH_DOC_STRINGS = 1, + .WITH_FREELISTS = 1, + .WITH_PYMALLOC = 1, + ._DARWIN_C_SOURCE = 1, + ._FILE_OFFSET_BITS = 64, + ._LARGEFILE_SOURCE = 1, + ._NETBSD_SOURCE = 1, + ._POSIX_C_SOURCE = .@"200809L", + ._PYTHONFRAMEWORK = "", + ._REENTRANT = 1, + ._XOPEN_SOURCE = 700, + ._XOPEN_SOURCE_EXTENDED = 1, + .__BSD_VISIBLE = 1, + ._ALL_SOURCE = 1, + ._GNU_SOURCE = 1, + ._POSIX_PTHREAD_SEMANTICS = 1, + ._TANDEM_SOURCE = 1, + .__EXTENSIONS__ = 1, + + .AC_APPLE_UNIVERSAL_BUILD = null, + .AIX_BUILDDATE = null, + .AIX_GENUINE_CPLUSPLUS = null, + .ALT_SOABI = null, + .ANDROID_API_LEVEL = null, + .DOUBLE_IS_ARM_MIXED_ENDIAN_IEEE754 = null, + .DOUBLE_IS_BIG_ENDIAN_IEEE754 = null, + .GETPGRP_HAVE_ARG = null, + .MAJOR_IN_MKDEV = null, + .MVWDELCH_IS_EXPRESSION = null, + .PACKAGE_BUGREPORT = null, + .PACKAGE_NAME = null, + .PACKAGE_STRING = null, + .PACKAGE_TARNAME = null, + .PACKAGE_URL = null, + .PACKAGE_VERSION = null, + .POSIX_SEMAPHORES_NOT_ENABLED = null, + .PYLONG_BITS_IN_DIGIT = null, + .PY_SQLITE_ENABLE_LOAD_EXTENSION = null, + .PY_SQLITE_HAVE_SERIALIZE = null, + .PY_SSL_DEFAULT_CIPHER_STRING = null, + .Py_DEBUG = null, + .Py_ENABLE_SHARED = null, + .Py_HASH_ALGORITHM = null, + .Py_STATS = null, + .Py_SUNOS_VERSION = null, + .Py_TRACE_REFS = null, + .SETPGRP_HAVE_ARG = null, + .SIGNED_RIGHT_SHIFT_ZERO_FILLS = null, + .THREAD_STACK_SIZE = null, + .TIMEMODULE_LIB = null, + .TM_IN_SYS_TIME = null, + .USE_COMPUTED_GOTOS = null, + .WINDOW_HAS_FLAGS = null, + .WITH_DTRACE = null, + .WITH_DYLD = null, + .WITH_EDITLINE = null, + .WITH_LIBINTL = null, + .WITH_NEXT_FRAMEWORK = null, + .WITH_VALGRIND = null, + .X87_DOUBLE_ROUNDING = null, + ._BSD_SOURCE = null, + ._INCLUDE__STDC_A1_SOURCE = null, + ._LARGE_FILES = null, + ._MINIX = null, + ._POSIX_1_SOURCE = null, + ._POSIX_SOURCE = null, + ._POSIX_THREADS = null, + ._WASI_EMULATED_GETPID = null, + ._WASI_EMULATED_PROCESS_CLOCKS = null, + ._WASI_EMULATED_SIGNAL = null, + .clock_t = null, + .@"const" = null, + .gid_t = null, + .mode_t = null, + .off_t = null, + .pid_t = null, + .signed = null, + .size_t = null, + .socklen_t = null, + .uid_t = null, + .WORDS_BIGENDIAN = null, + + .HAVE_BROKEN_MBSTOWCS = null, + .HAVE_BROKEN_NICE = null, + .HAVE_BROKEN_PIPE_BUF = null, + .HAVE_BROKEN_POLL = null, + .HAVE_BROKEN_POSIX_SEMAPHORES = null, + .HAVE_BROKEN_PTHREAD_SIGMASK = null, + .HAVE_BROKEN_SEM_GETVALUE = null, + .HAVE_BROKEN_UNSETENV = null, + + .HAVE_PTHREAD_STUBS = null, + .HAVE_USABLE_WCHAR_T = null, + .HAVE_NON_UNICODE_WCHAR_T_REPRESENTATION = null, + .HAVE_CHROOT = have(t.os.tag == .linux), + .HAVE_GCC_ASM_FOR_MC68881 = have(t.cpu.arch == .m68k), + .HAVE_GCC_ASM_FOR_X64 = have(t.cpu.arch == .x86_64), + .HAVE_GCC_ASM_FOR_X87 = have(t.cpu.arch == .x86_64 or t.cpu.arch == .x86), + // Readline type (static configuration, not function test) + .HAVE_RL_COMPDISP_FUNC_T = null, + }); + if (std.mem.eql(u8, config.version.?, "3.11.13")) addValues(alloc, config_header, .{ + .PY_FORMAT_SIZE_T = "z", + .TIME_WITH_SYS_TIME = 1, + .FLOAT_WORDS_BIGENDIAN = null, + }); + if (std.mem.eql(u8, config.version.?, "3.12.11")) + addValues(alloc, config_header, .{ + .ALIGNOF_MAX_ALIGN_T = @as(u32, switch (t.cpu.arch) { + .x86_64, .aarch64 => 16, + .x86, .arm => 8, + else => 8, + }), + + // ncurses library (static configuration, not function test) + .HAVE_NCURSESW = null, + + // Performance trampoline feature + .PY_HAVE_PERF_TRAMPOLINE = null, + + ._HPUX_ALT_XOPEN_SOCKET_API = null, + ._OPENBSD_SOURCE = null, + + // C standard feature test macros (all set to null as they're optional) + .__STDC_WANT_IEC_60559_ATTRIBS_EXT__ = null, + .__STDC_WANT_IEC_60559_BFP_EXT__ = null, + .__STDC_WANT_IEC_60559_DFP_EXT__ = null, + .__STDC_WANT_IEC_60559_FUNCS_EXT__ = null, + .__STDC_WANT_IEC_60559_TYPES_EXT__ = null, + .__STDC_WANT_LIB_EXT2__ = null, + .__STDC_WANT_MATH_SPEC_FUNCS__ = null, + }); +} +pub fn addValue(arena: std.mem.Allocator, config_header: *std.array_hash_map.String(ConfigHeader.Value), name: []const u8, comptime T: type, value: T) void { + return addValueInner(arena, config_header, name, T, value) catch @panic("OOM"); +} + +fn addValueInner(arena: std.mem.Allocator, config_header: *std.array_hash_map.String(ConfigHeader.Value), name: []const u8, comptime T: type, value: T) !void { + switch (@typeInfo(T)) { + .null => { + try config_header.put(arena, name, .undef); + }, + .void => { + try config_header.put(arena, name, .defined); + }, + .bool => { + try config_header.put(arena, name, .{ .boolean = value }); + }, + .int => { + try config_header.put(arena, name, .{ .int = value }); + }, + .comptime_int => { + try config_header.put(arena, name, .{ .int = value }); + }, + .@"enum", .enum_literal => { + try config_header.put(arena, name, .{ .ident = @tagName(value) }); + }, + .optional => { + if (value) |x| { + return addValueInner(arena, config_header, name, @TypeOf(x), x); + } else { + try config_header.put(arena, name, .undef); + } + }, + .pointer => |ptr| { + switch (@typeInfo(ptr.child)) { + .array => |array| { + if (ptr.size == .one and array.child == u8) { + try config_header.put(arena, name, .{ .string = value }); + return; + } + }, + .int => { + if (ptr.size == .slice and ptr.child == u8) { + try config_header.put(arena, name, .{ .string = value }); + return; + } + }, + else => {}, + } + + @compileError("unsupported ConfigHeader value type: " ++ @typeName(T)); + }, + else => @compileError("unsupported ConfigHeader value type: " ++ @typeName(T)), + } +} + +pub fn addValues(arena: std.mem.Allocator, config_header: *std.array_hash_map.String(ConfigHeader.Value), values: anytype) void { + const info = @typeInfo(@TypeOf(values)).@"struct"; + inline for (info.field_names, info.field_types) |field_name, field_type| { + addValue(arena, config_header, field_name, field_type, @field(values, field_name)); + } +} + +fn parseValue(ostr: ?[]const u8) ?ConfigHeader.Value { + if (ostr == null) return .undef; + const str = ostr.?; if (std.mem.eql(u8, str, "undef")) return .undef; if (std.mem.eql(u8, str, "defined")) return .defined; if (std.mem.eql(u8, str, "false")) return .{ .boolean = false }; @@ -250,9 +594,10 @@ fn runCompileCheck( io: std.Io, query: *Query, argv_template: []const []const u8, + cache_dir: []const u8, index: usize, ) void { - query.result = doCompileCheck(arena, io, query, argv_template, index); + query.result = doCompileCheck(arena, io, query, argv_template, cache_dir, index); } fn doCompileCheck( @@ -260,6 +605,7 @@ fn doCompileCheck( io: std.Io, query: *const Query, argv_template: []const []const u8, + cache_dir: []const u8, index: usize, ) Query.Result { const sep = std.fs.path.sep_str; @@ -270,9 +616,7 @@ fn doCompileCheck( else => @compileError("unsupported OS"), }; var task_dir_buf: [std.fs.max_path_bytes]u8 = undefined; - const base_dir = "."; // TODO: Need a reliable temporary directory instead of the build path to place the test programs - - const task_dir = std.fmt.bufPrint(&task_dir_buf, "{s}" ++ sep ++ "tmp" ++ sep ++ "cq-{}-{}", .{ base_dir, pid, index }) catch + const task_dir = std.fmt.bufPrint(&task_dir_buf, "{s}" ++ sep ++ "tmp" ++ sep ++ "cq-{}-{}", .{ cache_dir, pid, index }) catch fatal("cache-dir path too long", .{}); std.Io.Dir.cwd().createDirPath(io, task_dir) catch |err| fatal("failed to create '{s}': {t}", .{ task_dir, err }); @@ -442,6 +786,101 @@ test parseLine { try std.testing.expect(parseLine("NOVALUE") == .err); } +fn ensureAllValuesUsed( + value_map: *ValueMap, + src_path: []const u8, +) !void { + var any_errors = false; + for (value_map.keys(), value_map.values()) |name, used| { + if (used) continue; + std.log.err("{s}: config header value unused: {s}", .{ src_path, name }); + any_errors = true; + } + if (any_errors) unreachable; +} + +const os_newline = if (@import("builtin").os.tag == .windows) "\r\n" else "\n"; + +fn detectNewline(contents: []const u8) []const u8 { + const lf_index = std.mem.findScalar(u8, contents, '\n') orelse return os_newline; + return if (lf_index > 0 and contents[lf_index - 1] == '\r') "\r\n" else "\n"; +} + +const header_text = "This file was generated by ConfigHeader using the Zig Build System."; +const c_generated_line = "/* " ++ header_text ++ " */"; +const asm_generated_line = "; " ++ header_text; + +fn renderAutoConfUndef( + contents: []const u8, + w: *Writer, + config_header: *const std.array_hash_map.String(ConfigHeader.Value), + value_map: *ValueMap, + src_path: []const u8, +) !void { + const newline = detectNewline(contents); + + try w.writeAll(c_generated_line); + try w.writeAll(newline); + + var any_errors = false; + var line_index: u32 = 0; + var line_it = std.mem.splitScalar(u8, contents, '\n'); + while (line_it.next()) |raw_line| : (line_index += 1) { + const last_line = line_it.index == line_it.buffer.len; + const line = std.mem.trimEnd(u8, raw_line, "\r"); + + if (!std.mem.startsWith(u8, line, "#")) { + try w.writeAll(line); + if (!last_line) try w.writeAll(newline); + continue; + } + var it = std.mem.tokenizeAny(u8, line[1..], " \t\r"); + const undef = it.next().?; + if (!std.mem.eql(u8, undef, "undef")) { + try w.writeAll(line); + if (!last_line) try w.writeAll(newline); + continue; + } + const name = it.next().?; + const index = value_map.getIndex(name) orelse { + std.log.err("{s}:{d}: unspecified config header value: {s}", .{ + src_path, line_index + 1, name, + }); + any_errors = true; + continue; + }; + value_map.values()[index] = true; // Set to used. + try renderValueC(w, newline, name, config_header.get(name).?); + } + + try ensureAllValuesUsed(value_map, src_path); + if (any_errors) return error.MakeFailed; +} + +fn renderValueC(w: *Writer, newline: []const u8, name: []const u8, value: ConfigHeader.Value) !void { + switch (value) { + .undef => try w.print("/* #undef {s} */{s}", .{ name, newline }), + .defined => try w.print("#define {s}{s}", .{ name, newline }), + .boolean => |b| return renderValueCBool(w, newline, name, b), + .int => |i| try w.print("#define {s} {d}{s}", .{ name, i, newline }), + .ident => |ident| return renderValueCIdent(w, newline, name, ident), + .string => |string| try w.print("#define {s} \"{f}\"{s}", .{ name, std.zig.fmtString(string), newline }), + } +} + +fn renderValueCBool(w: *Writer, newline: []const u8, name: []const u8, b: bool) Writer.Error!void { + return w.print("#define {s} {c}{s}", .{ name, @as(u8, '0') + @intFromBool(b), newline }); +} + +fn renderValueCIdent(w: *Writer, newline: []const u8, name: []const u8, ident: []const u8) Writer.Error!void { + try w.print("#define {s}", .{name}); + if (ident.len > 0) { + try w.writeByte(' '); + try w.writeAll(ident); + } + return w.writeAll(newline); +} + fn reportError(io: std.Io, file: []const u8, line: u32, comptime fmt: []const u8, args: anytype) void { var stderr = std.Io.File.stderr().writer(io, &.{}); stderr.interface.print("{s}:{}: " ++ fmt ++ "\n", .{ file, line } ++ args) catch @@ -461,3 +900,5 @@ const std = @import("std"); const ConfigHeaderExt = @import("ConfigHeaderExt.zig"); const ConfigHeader = std.Build.Step.ConfigHeader; const LazyPath = std.Build.LazyPath; +const Writer = std.Io.Writer; +const ValueMap = std.array_hash_map.String(bool); diff --git a/makesetup.zig b/makesetup.zig index 7893b18..8a7d959 100644 --- a/makesetup.zig +++ b/makesetup.zig @@ -154,8 +154,7 @@ fn parseSetupFile( if (part.len == 2) errExit("{s}:{}: expected '-IPATH' but just got '-I'", .{ file_path, lineno }); if (part.len > 11 and std.mem.startsWith(u8, part, "-I$(srcdir)")) { compile_args.append(arena, .{ .include = arena.dupe(u8, part[11..]) catch |e| oom(e) }) catch |e| oom(e); - } else - compile_args.append(arena, .{ .include = arena.dupe(u8, part[2..]) catch |e| oom(e) }) catch |e| oom(e); + } else compile_args.append(arena, .{ .include = arena.dupe(u8, part[2..]) catch |e| oom(e) }) catch |e| oom(e); } else if (std.mem.startsWith(u8, part, "-l")) { if (part.len == 2) errExit("{s}:{}: expected '-lLIB' but just got '-l'", .{ file_path, lineno }); libs.append(arena, part[2..]) catch |e| oom(e); @@ -247,19 +246,16 @@ fn errExit(comptime fmt: []const u8, args: anytype) noreturn { std.process.exit(0xff); } -pub fn writeSysConfigData(b: *std.Build, configheader: *std.Build.Step.ConfigHeader) [] const u8 { - - _ = configheader; - +pub fn writeSysConfigData(b: *std.Build) []const u8 { const alloc = b.allocator; var list: std.ArrayList(u8) = .empty; defer list.deinit(alloc); - list.appendSlice(alloc, "build_time_vars = {'ABIFLAGS': ''") catch @panic("OOM"); + list.appendSlice(alloc, "build_time_vars = {'ABIFLAGS': ''") catch @panic("OOM"); // TODO: Output the values of the config header in a python format list.appendSlice(alloc, "}\n") catch @panic("OOM"); return list.toOwnedSlice(alloc) catch @panic("OOM"); -} \ No newline at end of file +} From c9610bcf382bed6c1b8190a907d139e15a5d642c Mon Sep 17 00:00:00 2001 From: Kenneth Bogert Date: Thu, 5 Nov 2026 10:31:41 -0500 Subject: [PATCH 27/28] Remove unused ConfigHeaderExt.zig --- ConfigHeaderExt.zig | 81 --------------------------------------------- configquery.zig | 1 - 2 files changed, 82 deletions(-) delete mode 100644 ConfigHeaderExt.zig diff --git a/ConfigHeaderExt.zig b/ConfigHeaderExt.zig deleted file mode 100644 index 1973a2a..0000000 --- a/ConfigHeaderExt.zig +++ /dev/null @@ -1,81 +0,0 @@ -/// Add config values to a ConfigHeader from a lazy path. -/// The lazy path should contain lines in the format: NAME VALUE -pub fn addFile(config_header: *ConfigHeader, config_results: std.Build.LazyPath) void { - const b = config_header.step.owner; - // This ApplyConfigStep is just a HACK which *should work* but the proper solution is to - // add LazyPath support in ConfigHeader itself. - const apply = b.allocator.create(ApplyConfigStep) catch @panic("OOM"); - apply.* = .{ - .step = std.Build.Step.init(.{ - .tag = .config_header, - .name = "add configuration from lazy path", - .owner = b, - }), - .config_header = config_header, - .config_results = config_results, - }; - config_results.addStepDependencies(&apply.step); - config_header.step.dependOn(&apply.step); -} - -pub fn parseValue(str: []const u8) ?ConfigHeader.Value { - if (std.mem.eql(u8, str, "undef")) return .undef; - if (std.mem.eql(u8, str, "defined")) return .defined; - if (std.mem.eql(u8, str, "false")) return .{ .boolean = false }; - if (std.mem.eql(u8, str, "true")) return .{ .boolean = true }; - if (std.fmt.parseInt(i64, str, 10)) |int| return .{ .int = int } else |_| {} - if (std.mem.startsWith(u8, str, ":")) return .{ .ident = str[1..] }; - if (str.len >= 2 and str[0] == '"' and str[str.len - 1] == '"') return .{ .string = str[1 .. str.len - 1] }; - return null; -} - -pub const FileEntry = struct { - name: []const u8, - value: ConfigHeader.Value, - - pub fn parse(line: []const u8) error{ MissingValue, InvalidValue }!FileEntry { - const first_space = std.mem.indexOfScalar(u8, line, ' ') orelse return error.MissingValue; - return .{ - .name = line[0..first_space], - .value = parseValue(line[first_space + 1 ..]) orelse return error.InvalidValue, - }; - } -}; - -const ApplyConfigStep = struct { - step: std.Build.Step, - config_header: *ConfigHeader, - config_results: std.Build.LazyPath, - - fn make(step: *std.Build.Step, options: std.Build.Step.MakeOptions) anyerror!void { - _ = options; - const b = step.owner; - const self: *ApplyConfigStep = @fieldParentPtr("step", step); - - const file_path = try self.config_results.getPath4(b, step); - const content = file_path.root_dir.handle.readFileAlloc( - b.graph.io, - file_path.subPathOrDot(), - b.allocator, - .unlimited, - ) catch |err| return step.fail( - "unable to read config values from '{f}': {t}", - .{ file_path, err }, - ); - var line_it = std.mem.splitScalar(u8, content, '\n'); - var line_num: u32 = 0; - while (line_it.next()) |line| { - line_num += 1; - if (line.len == 0 or line[0] == '#') continue; - if (FileEntry.parse(line)) |entry| { - self.config_header.values.put(b.allocator, entry.name, entry.value) catch @panic("OOM"); - } else |err| { - step.addError("{f}:{d}: {t} '{s}'", .{ file_path, line_num, err, line }) catch @panic("OOM"); - } - } - if (step.result_error_msgs.items.len != 0) return error.MakeFailed; - } -}; - -const std = @import("std"); -const ConfigHeader = std.Build.Step.ConfigHeader; diff --git a/configquery.zig b/configquery.zig index 0f46171..000bab7 100644 --- a/configquery.zig +++ b/configquery.zig @@ -897,7 +897,6 @@ fn fatal(comptime fmt: []const u8, args: anytype) noreturn { } const std = @import("std"); -const ConfigHeaderExt = @import("ConfigHeaderExt.zig"); const ConfigHeader = std.Build.Step.ConfigHeader; const LazyPath = std.Build.LazyPath; const Writer = std.Io.Writer; From 84572cabf98b9dadaa1d06158fcca28ae5c08421 Mon Sep 17 00:00:00 2001 From: Kenneth Bogert Date: Thu, 5 Nov 2026 12:52:26 -0500 Subject: [PATCH 28/28] Don't need libhacl.a --- build.zig | 1 - 1 file changed, 1 deletion(-) diff --git a/build.zig b/build.zig index 882b605..1cc45de 100644 --- a/build.zig +++ b/build.zig @@ -73,7 +73,6 @@ pub fn build(b: *std.Build) !void { "-D_BSD_SOURCE", "-D_DEFAULT_SOURCE", "-fwrapv", "-std=c11", "-fvisibility=hidden", "-DVPATH=\"\"", } }); - b.installArtifact(hacl.?); } else hacl = null; const libs_host: Libs = .{ .zlib = null, .openssl = null, .hacl = null };