From 1e24b3a87cb0015818cd51ec84483642326ea7ae Mon Sep 17 00:00:00 2001 From: Emil Lerch Date: Mon, 6 May 2024 13:54:47 -0700 Subject: [PATCH] zig 0.12.0: rework build interface to match a much improved package manager --- build.zig | 37 +++++++- src/universal_lambda_build.zig | 162 +++++++++++---------------------- 2 files changed, 83 insertions(+), 116 deletions(-) diff --git a/build.zig b/build.zig index 9a8d680..c9b177b 100644 --- a/build.zig +++ b/build.zig @@ -58,7 +58,31 @@ pub fn build(b: *std.Build) !void { }); const universal_lambda = @import("src/universal_lambda_build.zig"); universal_lambda.module_root = b.build_root.path; - _ = try universal_lambda.addModules(b, lib); + + // re-expose modules downstream + const flexilib_dep = b.dependency("flexilib", .{ + .target = target, + .optimize = optimize, + }); + const flexilib_module = flexilib_dep.module("flexilib-interface"); + _ = b.addModule("flexilib-interface", .{ + .root_source_file = flexilib_module.root_source_file, + .target = target, + .optimize = optimize, + }); + + _ = b.addModule("universal_lambda_interface", .{ + .root_source_file = b.path("src/interface.zig"), + .target = target, + .optimize = optimize, + }); + + _ = b.addModule("universal_lambda_handler", .{ + .root_source_file = b.path("src/universal_lambda.zig"), + .target = target, + .optimize = optimize, + }); + @import("src/universal_lambda_build.zig").addImports(b, lib, null); // This declares intent for the library to be installed into the standard // location when the user invokes the "install" step (the default step when @@ -72,7 +96,7 @@ pub fn build(b: *std.Build) !void { // but does not run it. const exe_tests = b.addTest(.{ .root_source_file = .{ .path = "src/test.zig" }, - .target = t, + .target = b.resolveTargetQuery(t), .optimize = optimize, }); _ = try universal_lambda.addModules(b, exe_tests); @@ -90,7 +114,7 @@ pub fn build(b: *std.Build) !void { // via shared library const lib_tests = b.addTest(.{ .root_source_file = .{ .path = "src/flexilib.zig" }, - .target = t, + .target = b.resolveTargetQuery(t), .optimize = optimize, }); _ = try universal_lambda.addModules(b, lib_tests); @@ -107,6 +131,9 @@ pub fn build(b: *std.Build) !void { pub fn configureBuild(b: *std.Build, cs: *std.Build.Step.Compile) !void { try @import("src/universal_lambda_build.zig").configureBuild(b, cs); } -pub fn addModules(b: *std.Build, cs: *std.Build.Step.Compile) ![]const u8 { - return try @import("src/universal_lambda_build.zig").addModules(b, cs); +pub fn addImports(b: *std.Build, cs: *std.Build.Step.Compile, universal_lambda_zig_dep: *std.Build.Dependency) void { + // The underlying call has an optional dependency here, but we do not. + // Downstream must provide the dependency, which will ensure that the + // modules we have exposed above do, in fact, get exposed + return @import("src/universal_lambda_build.zig").addImports(b, cs, universal_lambda_zig_dep); } diff --git a/src/universal_lambda_build.zig b/src/universal_lambda_build.zig index 232fa2b..cca7d29 100644 --- a/src/universal_lambda_build.zig +++ b/src/universal_lambda_build.zig @@ -17,12 +17,12 @@ pub var module_root: ?[]const u8 = null; pub fn configureBuild(b: *std.Build, cs: *std.Build.Step.Compile) !void { const function_name = b.option([]const u8, "function-name", "Function name for Lambda [zig-fn]") orelse "zig-fn"; - const file_location = try addModules(b, cs); + // const file_location = try addModules(b, cs); // Add steps - try @import("lambda_build.zig").configureBuild(b, cs, function_name); - try @import("cloudflare_build.zig").configureBuild(b, cs, function_name); - try @import("flexilib_build.zig").configureBuild(b, cs, file_location); + try @import("lambda-zig").configureBuild(b, cs, function_name); + try @import("cloudflare-worker-deploy").configureBuild(b, cs, function_name); + // try @import("flexilib_build.zig").configureBuild(b, cs, file_location); try @import("standalone_server_build.zig").configureBuild(b, cs); } @@ -33,127 +33,67 @@ pub fn configureBuild(b: *std.Build, cs: *std.Build.Step.Compile) !void { /// * universal_lambda_build_options /// * flexilib-interface /// * universal_lambda_handler -pub fn addModules(b: *std.Build, cs: *std.Build.Step.Compile) ![]const u8 { - const file_location = try findFileLocation(b); - const options_module = try createOptionsModule(b, cs); - - // We need to add the interface module here as well, so universal_lambda.zig - // can reference it. Unfortunately, this creates an issue that the consuming - // build.zig.zon must have flexilib included, even if they're not building - // flexilib. TODO: Accept for now, but we need to think through this situation - // This might be fixed in 0.12.0 (see https://github.com/ziglang/zig/issues/16172). - // We can also possibly use the findFileLocation hack above in concert with - // addAnonymousModule - const flexilib_dep = b.dependency("flexilib", .{ - .target = cs.target, - .optimize = cs.optimize, - }); - const flexilib_module = flexilib_dep.module("flexilib-interface"); - // Make the interface available for consumption - cs.addModule("flexilib-interface", flexilib_module); - cs.addAnonymousModule("universal_lambda_interface", .{ - .source_file = .{ .path = b.pathJoin(&[_][]const u8{ file_location, "interface.zig" }) }, - // We alsso need the interface module available here - .dependencies = &[_]std.Build.ModuleDependency{}, - }); - // Add module - cs.addAnonymousModule("universal_lambda_handler", .{ - // Source file can be anywhere on disk, does not need to be a subdirectory - .source_file = .{ .path = b.pathJoin(&[_][]const u8{ file_location, "universal_lambda.zig" }) }, - // We alsso need the interface module available here - .dependencies = &[_]std.Build.ModuleDependency{ - // Add options module so we can let our universal_lambda know what - // type of interface is necessary - .{ - .name = "universal_lambda_build_options", - .module = options_module, - }, - .{ - .name = "flexilib-interface", - .module = flexilib_module, - }, - .{ - .name = "universal_lambda_interface", - .module = cs.modules.get("universal_lambda_interface").?, - }, - }, - }); - return file_location; -} - -/// This function relies on internal implementation of the build runner -/// When a developer launches "zig build", a program is compiled, with the -/// main entrypoint existing in build_runner.zig (this can be overridden by -/// by command line). -/// -/// The code we see in build.zig is compiled into that program. The program -/// is named 'build' and stuck in the zig cache, then it is run. There are -/// two phases to the build. -/// -/// Build phase, where a graph is established of the steps that need to be run, -/// then the "make phase", where the steps are actually executed. Steps have -/// a make function that is called. -/// -/// This function is reaching into the struct that is the build_runner.zig, and -/// finding the location of the dependency for ourselves to determine the -/// location of our own file. This is, of course, brittle, but there does not -/// seem to be a better way at the moment, and we need this to be able to import -/// modules appropriately. -/// -/// For development of this process directly, we'll allow a build option to -/// override this process completely, because during development it's easier -/// for the example build.zig to simply import the file directly than it is -/// to pull from a download location and update hashes every time we change -fn findFileLocation(b: *std.Build) ![]const u8 { - if (module_root) |r| return b.pathJoin(&[_][]const u8{ r, "src" }); - const build_root = b.option( - []const u8, - "universal_lambda_build_root", - "Build root for universal lambda (development of universal lambda only)", - ); - if (build_root) |br| { - return b.pathJoin(&[_][]const u8{ br, "src" }); - } - // This is introduced post 0.11. Once it is available, we can skip the - // access check, and instead check the end of the path matches the dependency - // hash - // for (b.available_deps) |dep| { - // std.debug.print("{}", .{dep}); - // // if (std. - // } - const ulb_root = outer_blk: { - // trigger initlialization if it hasn't been initialized already - _ = b.dependency("universal_lambda_build", .{}); //b.args); - var str_iterator = b.initialized_deps.iterator(); - while (str_iterator.next()) |entry| { - const br = entry.key_ptr.*; - const marker_found = blk: { - // Check for a file that should only exist in our package - std.fs.accessAbsolute(b.pathJoin(&[_][]const u8{ br, "src", "flexilib.zig" }), .{}) catch break :blk false; - break :blk true; - }; - if (marker_found) break :outer_blk br; - } - return error.CannotFindUniversalLambdaBuildRoot; +pub fn addImports(b: *std.Build, cs: *std.Build.Step.Compile, universal_lambda_zig_dep: ?*std.Build.Dependency) void { + const Modules = struct { + flexilib_interface: *std.Build.Module, + universal_lambda_interface: *std.Build.Module, + universal_lambda_handler: *std.Build.Module, + universal_lambda_build_options: *std.Build.Module, }; - return b.pathJoin(&[_][]const u8{ ulb_root, "src" }); + const modules = + if (universal_lambda_zig_dep) |d| + Modules{ + .flexilib_interface = d.module("flexilib-interface"), + .universal_lambda_interface = d.module("universal_lambda_interface"), + .universal_lambda_handler = d.module("universal_lambda_handler"), + .universal_lambda_build_options = createOptionsModule(d.builder, cs), + } + else + Modules{ + .flexilib_interface = b.modules.get("flexilib-interface").?, + .universal_lambda_interface = b.modules.get("universal_lambda_interface").?, + .universal_lambda_handler = b.modules.get("universal_lambda_handler").?, + .universal_lambda_build_options = createOptionsModule(b, cs), + }; + + cs.root_module.addImport("universal_lambda_build_options", modules.universal_lambda_build_options); + cs.root_module.addImport("flexilib-interface", modules.flexilib_interface); + cs.root_module.addImport("universal_lambda_interface", modules.universal_lambda_interface); + cs.root_module.addImport("universal_lambda_handler", modules.universal_lambda_handler); + + // universal lambda handler also needs these imports + modules.universal_lambda_handler.addImport("universal_lambda_interface", modules.universal_lambda_interface); + modules.universal_lambda_handler.addImport("flexilib-interface", modules.flexilib_interface); + modules.universal_lambda_handler.addImport("universal_lambda_build_options", modules.universal_lambda_build_options); + + return; } + /// Make our target platform visible to runtime through an import /// called "universal_lambda_build_options". This will also be available to the consuming /// executable if needed -pub fn createOptionsModule(b: *std.Build, cs: *std.Build.Step.Compile) !*std.Build.Module { +pub fn createOptionsModule(b: *std.Build, cs: *std.Build.Step.Compile) *std.Build.Module { + if (b.modules.get("universal_lambda_build_options")) |m| return m; + // We need to go through the command line args, look for argument(s) // between "build" and anything prefixed with "-". First take, blow up // if there is more than one. That's the step we're rolling with // These frameworks I believe are inextricably tied to both build and // run behavior. // - var args = try std.process.argsAlloc(b.allocator); + const args = std.process.argsAlloc(b.allocator) catch @panic("OOM"); defer b.allocator.free(args); const options = b.addOptions(); options.addOption(BuildType, "build_type", findBuildType(args) orelse .exe_run); - cs.addOptions("universal_lambda_build_options", options); - return cs.modules.get("universal_lambda_build_options").?; + // The normal way to do this is with module.addOptions, but that actually just does + // an import, even though the parameter there is "module_name". addImport takes + // a module, but in zig 0.12.0, that's using options.createModule(), which creates + // a private module. This is a good default for them, but doesn't work for us + const module = b.addModule("universal_lambda_build_options", .{ + .root_source_file = options.getOutput(), + }); + cs.root_module.addImport("universal_lambda_build_options", module); + return module; } fn findBuildType(build_args: [][:0]u8) ?BuildType {