diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 567ed09..632509a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -48,7 +48,7 @@ jobs: dub build :droptest - name: (Zig) Build Shaders - run: zig build shaders + run: zig build -Dshaders - name: (Zig) Running Test if: runner.os != 'Windows' run: zig build test -DzigCC diff --git a/README.md b/README.md index 91a63b0..1f20131 100644 --- a/README.md +++ b/README.md @@ -95,20 +95,18 @@ Checkout [sokol-tools](https://github.com/floooh/sokol-tools) for a sokol shader here have been compiled using it with `-f sokol_d`! ```bash -zig build shaders # (re)generate D bindings from shaders. +zig build -Dshaders # (re)generate D bindings from shaders. ```
## License and attributions - -This code is released under the zlib license (see `LICENSE` for info). Parts of `gen_d.py` have been copied and modified from -the zig-bindings (https://github.com/floooh/sokol-zig/) and rust-bindings (https://github.com/floooh/sokol-rust/) for sokol. - +This code is released under the zlib license (see [LICENSE](LICENSE) for info). Parts of `gen_d.py` have been copied and modified from +the zig-bindings[^1] and rust-bindings[^2] for sokol. +The sokol headers are created by Andre Weissflog (floooh) and sokol is released under its own license[^3]. - -The sokol headers are created by Andre Weissflog (floooh) and sokol is released under its own license here: https://github.com/floooh/sokol/blob/master/LICENSE - -
+[^1]: https://github.com/floooh/sokol-zig/ +[^2]: https://github.com/floooh/sokol-rust/ +[^3]: https://github.com/floooh/sokol/blob/master/LICENSE \ No newline at end of file diff --git a/build.zig b/build.zig index d003f4e..4b9bfd0 100644 --- a/build.zig +++ b/build.zig @@ -80,11 +80,13 @@ pub fn buildLibSokol(b: *Build, options: LibSokolOptions) !*CompileStep { } // one-time setup of Emscripten SDK if (!options.with_sokol_imgui) { - if (try emSdkSetupStep(b, options.emsdk.?)) |emsdk_setup| { - lib.step.dependOn(&emsdk_setup.step); + if (options.emsdk) |emsdk| { + if (try emSdkSetupStep(b, emsdk)) |emsdk_setup| { + lib.step.dependOn(&emsdk_setup.step); + } + // add the Emscripten system include seach path + lib.addIncludePath(emSdkLazyPath(b, emsdk, &.{ "upstream", "emscripten", "cache", "sysroot", "include" })); } - // add the Emscripten system include seach path - lib.addIncludePath(emSdkLazyPath(b, options.emsdk.?, &.{ "upstream", "emscripten", "cache", "sysroot", "include" })); } } @@ -217,13 +219,16 @@ pub fn build(b: *Build) !void { // LDC-options options const dub_artifact = b.option(bool, "artifact", "Build artifacts (default: false)") orelse false; - const enable_betterC = b.option(bool, "betterC", "Omit generating some runtime information and helper functions (default: false)") orelse false; - const enable_zigcc = b.option(bool, "zigCC", "Use zig cc as compiler and linker (default: false)") orelse false; + const opt_betterC = b.option(bool, "betterC", "Omit generating some runtime information and helper functions (default: false)") orelse false; + const opt_zigcc = b.option(bool, "zigCC", "Use zig cc as compiler and linker (default: false)") orelse false; + // Build Shaders + const opt_shaders = b.option(bool, "shaders", "Build shaders (default: false)") orelse false; // ldc2 w/ druntime + phobos2 works on MSVC const target = b.standardTargetOptions(.{ .default_target = if (builtin.os.tag == .windows) try std.Target.Query.parse(.{ .arch_os_abi = "native-windows-msvc" }) else .{} }); const optimize = b.standardOptimizeOption(.{}); - const emsdk = b.lazyDependency("emsdk", .{}) orelse null; + // Get emsdk dependency if targeting WebAssembly, otherwise null + const emsdk = enableWasm(b, target); const lib_sokol = try buildLibSokol(b, .{ .target = target, .optimize = optimize, @@ -234,6 +239,8 @@ pub fn build(b: *Build) !void { .with_sokol_imgui = opt_with_sokol_imgui, .emsdk = emsdk, }); + if (opt_shaders) + buildShaders(b, target); if (dub_artifact) { b.installArtifact(lib_sokol); } else { @@ -271,14 +278,14 @@ pub fn build(b: *Build) !void { .sources = &[_][]const u8{ b.fmt("{s}/src/examples/{s}.d", .{ rootPath(), example }), }, - .betterC = if (std.mem.eql(u8, example, "user-data")) false else enable_betterC, + .betterC = if (std.mem.eql(u8, example, "user-data")) false else opt_betterC, .dflags = &.{ "-w", "-preview=rvaluerefparam", "-preview=dip1000", }, // fixme: https://github.com/kassane/sokol-d/issues/1 - betterC works on darwin - .zig_cc = if (target.result.isDarwin() and !enable_betterC) false else enable_zigcc, + .zig_cc = if (target.result.isDarwin() and !opt_betterC) false else opt_zigcc, .target = target, .optimize = optimize, // send ldc2-obj (wasm artifact) to emcc @@ -289,7 +296,6 @@ pub fn build(b: *Build) !void { b.getInstallStep().dependOn(&ldc.step); } } - buildShaders(b, target); // build tests // fixme: not building on Windows libsokol w/ kind test (missing cc [??]) @@ -652,7 +658,7 @@ pub fn ldcBuildStep(b: *Build, options: DCompileStep) !*std.Build.Step.InstallDi .lib_main = artifact, .target = options.target, .optimize = options.optimize, - .emsdk = options.emsdk.?, + .emsdk = options.emsdk orelse null, .use_webgpu = backend == .wgpu, .use_webgl2 = backend != .wgpu, .use_emmalloc = options.betterC, @@ -664,7 +670,7 @@ pub fn ldcBuildStep(b: *Build, options: DCompileStep) !*std.Build.Step.InstallDi .extra_args = &.{"-sSTACK_SIZE=512KB"}, }); link_step.step.dependOn(&ldc_exec.step); - const emrun = emRunStep(b, .{ .name = options.name, .emsdk = options.emsdk.? }); + const emrun = emRunStep(b, .{ .name = options.name, .emsdk = options.emsdk orelse null }); emrun.step.dependOn(&link_step.step); run.dependOn(&emrun.step); } else { @@ -775,7 +781,6 @@ fn buildShaders(b: *Build, target: Build.ResolvedTarget) void { return; } const shdc_path = b.findProgram(&.{"sokol-shdc"}, &.{}) catch b.pathJoin(&.{ sokol_tools_bin_dir, optional_shdc.? }); - const shdc_step = b.step("shaders", "Compile shaders (needs ../sokol-tools-bin)"); const glsl = if (target.result.isDarwin()) "glsl410" else "glsl430"; const slang = glsl ++ ":metal_macos:hlsl5:glsl300es:wgsl"; if (builtin.os.tag == .linux or builtin.os.tag == .macos) { @@ -799,20 +804,27 @@ fn buildShaders(b: *Build, target: Build.ResolvedTarget) void { "-f", "sokol_d", }); - shdc_step.dependOn(&cmd.step); + b.default_step.dependOn(&cmd.step); } } } // ------------------------ Wasm Configuration ------------------------ +// Enable fetch and install the Emscripten SDK +fn enableWasm(b: *Build, target: Build.ResolvedTarget) ?*Build.Dependency { + if (target.result.isWasm()) + return b.lazyDependency("emsdk", .{}) orelse null; + return null; +} + // for wasm32-emscripten, need to run the Emscripten linker from the Emscripten SDK // NOTE: ideally this would go into a separate emsdk-zig package pub const EmLinkOptions = struct { target: Build.ResolvedTarget, optimize: std.builtin.OptimizeMode, lib_main: *Build.Step.Compile, - emsdk: *Build.Dependency, + emsdk: ?*Build.Dependency, release_use_closure: bool = true, release_use_lto: bool = false, use_webgpu: bool = false, @@ -826,84 +838,89 @@ pub const EmLinkOptions = struct { }; pub fn emLinkStep(b: *Build, options: EmLinkOptions) !*Build.Step.InstallDir { - const emcc_path = emSdkLazyPath(b, options.emsdk, &.{ "upstream", "emscripten", "emcc" }).getPath(b); - const emcc = b.addSystemCommand(&.{emcc_path}); - emcc.setName("emcc"); // hide emcc path - if (options.optimize == .Debug) { - emcc.addArgs(&.{ - "-Og", - "-sSAFE_HEAP=1", - "-sSTACK_OVERFLOW_CHECK=1", - }); - } else { - emcc.addArg("-sASSERTIONS=0"); - if (options.optimize == .ReleaseSmall) { - emcc.addArg("-Oz"); + if (options.emsdk) |emsdk| { + const emcc_path = emSdkLazyPath(b, emsdk, &.{ "upstream", "emscripten", "emcc" }).getPath(b); + const emcc = b.addSystemCommand(&.{emcc_path}); + emcc.setName("emcc"); // hide emcc path + if (options.optimize == .Debug) { + emcc.addArgs(&.{ + "-Og", + "-sSAFE_HEAP=1", + "-sSTACK_OVERFLOW_CHECK=1", + }); } else { - emcc.addArg("-O3"); + emcc.addArg("-sASSERTIONS=0"); + if (options.optimize == .ReleaseSmall) { + emcc.addArg("-Oz"); + } else { + emcc.addArg("-O3"); + } + if (options.release_use_lto) { + emcc.addArg("-flto"); + } + if (options.release_use_closure) { + emcc.addArgs(&.{ "--closure", "1" }); + } } - if (options.release_use_lto) { - emcc.addArg("-flto"); + if (options.use_webgpu) { + emcc.addArg("-sUSE_WEBGPU=1"); } - if (options.release_use_closure) { - emcc.addArgs(&.{ "--closure", "1" }); + if (options.use_webgl2) { + emcc.addArg("-sUSE_WEBGL2=1"); + } + if (!options.use_filesystem) { + emcc.addArg("-sNO_FILESYSTEM=1"); + } + if (options.use_emmalloc) { + emcc.addArg("-sMALLOC='emmalloc'"); + } + if (options.use_ubsan) { + emcc.addArg("-fsanitize=undefined"); + } + if (options.shell_file_path) |shell_file_path| { + emcc.addPrefixedFileArg("--shell-file=", shell_file_path); + } + for (options.extra_args) |arg| { + emcc.addArg(arg); } - } - if (options.use_webgpu) { - emcc.addArg("-sUSE_WEBGPU=1"); - } - if (options.use_webgl2) { - emcc.addArg("-sUSE_WEBGL2=1"); - } - if (!options.use_filesystem) { - emcc.addArg("-sNO_FILESYSTEM=1"); - } - if (options.use_emmalloc) { - emcc.addArg("-sMALLOC='emmalloc'"); - } - if (options.use_ubsan) { - emcc.addArg("-fsanitize=undefined"); - } - if (options.shell_file_path) |shell_file_path| { - emcc.addPrefixedFileArg("--shell-file=", shell_file_path); - } - for (options.extra_args) |arg| { - emcc.addArg(arg); - } - if (options.use_drt) { - const libdruntime = fetch(b, .{ - .url = "https://github.com/opendlang/opend/releases/download/CI/opend-latest-xpack-emscripten.tar.xz", - .file_name = "lib/libdruntime-ldc.a", - }); - const libphobos2 = fetch(b, .{ - .url = "https://github.com/opendlang/opend/releases/download/CI/opend-latest-xpack-emscripten.tar.xz", - .file_name = "lib/libphobos2-ldc.a", - }); - emcc.addFileArg(libdruntime); - emcc.addFileArg(libphobos2); - } - // add the main lib, and then scan for library dependencies and add those too - emcc.addArtifactArg(options.lib_main); - for (options.lib_main.getCompileDependencies(false)) |item| { - if (item.kind == .lib) { - emcc.addArtifactArg(item); + if (options.use_drt) { + const libdruntime = fetch(b, .{ + .url = "https://github.com/opendlang/opend/releases/download/CI/opend-latest-xpack-emscripten.tar.xz", + .file_name = "lib/libdruntime-ldc.a", + }); + const libphobos2 = fetch(b, .{ + .url = "https://github.com/opendlang/opend/releases/download/CI/opend-latest-xpack-emscripten.tar.xz", + .file_name = "lib/libphobos2-ldc.a", + }); + emcc.addFileArg(libdruntime); + emcc.addFileArg(libphobos2); } - } - emcc.addArg("-o"); - const out_file = emcc.addOutputFileArg(b.fmt("{s}.html", .{options.lib_main.name})); + // add the main lib, and then scan for library dependencies and add those too + emcc.addArtifactArg(options.lib_main); + for (options.lib_main.getCompileDependencies(false)) |item| { + if (item.kind == .lib) { + emcc.addArtifactArg(item); + } + } + emcc.addArg("-o"); + const out_file = emcc.addOutputFileArg(b.fmt("{s}.html", .{options.lib_main.name})); + // the emcc linker creates 3 output files (.html, .wasm and .js) + const install = b.addInstallDirectory(.{ + .source_dir = out_file.dirname(), + .install_dir = .prefix, + .install_subdir = "web", + }); + install.step.dependOn(&emcc.step); - // the emcc linker creates 3 output files (.html, .wasm and .js) - const install = b.addInstallDirectory(.{ - .source_dir = out_file.dirname(), + // get the emcc step to run on 'zig build' + b.getInstallStep().dependOn(&install.step); + return install; + } else return b.addInstallDirectory(.{ + .source_dir = b.path(""), .install_dir = .prefix, .install_subdir = "web", }); - install.step.dependOn(&emcc.step); - - // get the emcc step to run on 'zig build' - b.getInstallStep().dependOn(&install.step); - return install; } // Use 'zig fetch' to download and unpack the specified URL, optionally verifying the checksum. @@ -963,12 +980,23 @@ fn fetch(b: *std.Build, options: struct { // NOTE: ideally this would go into a separate emsdk-zig package pub const EmRunOptions = struct { name: []const u8, - emsdk: *Build.Dependency, + emsdk: ?*Build.Dependency, }; pub fn emRunStep(b: *Build, options: EmRunOptions) *Build.Step.Run { - const emrun_path = b.findProgram(&.{"emrun"}, &.{}) catch emSdkLazyPath(b, options.emsdk, &.{ "upstream", "emscripten", "emrun" }).getPath(b); - const emrun = b.addSystemCommand(&.{ emrun_path, b.fmt("{s}/web/{s}.html", .{ b.install_path, options.name }) }); - return emrun; + if (options.emsdk) |emsdk| { + const emrun_path = b.findProgram(&.{"emrun"}, &.{}) catch emSdkLazyPath(b, emsdk, &.{ "upstream", "emscripten", "emrun" }).getPath(b); + const emrun = b.addSystemCommand(&.{ emrun_path, b.fmt("{s}/web/{s}.html", .{ b.install_path, options.name }) }); + return emrun; + } + // workaround for emsdk not being available (non-artifact build) + return b.addRunArtifact(Build.Step.Compile.create(b, .{ + .name = options.name, + .root_module = b.createModule(.{ + .target = b.graph.host, + .optimize = .Debug, + }), + .kind = .obj, + })); } // helper function to build a LazyPath from the emsdk root and provided path components @@ -1043,18 +1071,20 @@ fn buildImgui(b: *Build, options: libImGuiOptions) !*CompileStep { const cimgui = dep.path(imguiver_path); libimgui.addIncludePath(cimgui); - if (libimgui.rootModuleTarget().isWasm()) { - if (try emSdkSetupStep(b, options.emsdk.?)) |emsdk_setup| { - libimgui.step.dependOn(&emsdk_setup.step); + if (options.emsdk) |emsdk| { + if (libimgui.rootModuleTarget().isWasm()) { + if (try emSdkSetupStep(b, emsdk)) |emsdk_setup| { + libimgui.step.dependOn(&emsdk_setup.step); + } + // add the Emscripten system include seach path + libimgui.addIncludePath(emSdkLazyPath(b, emsdk, &.{ + "upstream", + "emscripten", + "cache", + "sysroot", + "include", + })); } - // add the Emscripten system include seach path - libimgui.addIncludePath(emSdkLazyPath(b, options.emsdk.?, &.{ - "upstream", - "emscripten", - "cache", - "sysroot", - "include", - })); } libimgui.addCSourceFiles(.{ .root = cimgui,