diff --git a/CHANGELOG.md b/CHANGELOG.md index 8adb554..bd2ef75 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,3 +17,7 @@ to the example code or the supported Zig version. For actual Sokol header change The way the Emscripten SDK is integrated isn't the 'final form' form though. Eventually I want to move the Emscripten stuff into a separate `emsdk-zig` package, and rewrite the linker integration to be more 'Zig build system idiomatic'. + +Most of the work was done by @kassane, many thanks! + +Relevant PRs: https://github.com/floooh/sokol-zig/pull/50, https://github.com/floooh/sokol-zig/pull/51. diff --git a/README.md b/README.md index 08ab3f7..cb602bd 100644 --- a/README.md +++ b/README.md @@ -2,47 +2,49 @@ Auto-generated Zig bindings for the [sokol headers](https://github.com/floooh/sokol). -For Zig version 0.11.0 +For Zig version 0.12.0-dev. -For the latest 0.12.0-dev version, please use the branch `zig-0.12.0`. +In case of breaking changes in Zig, the bindings might fall behind. Please don't hesitate to +ping me via a Github issue, or even better, provide a PR :) + +Support for previous stable Zig version is in branches. Related projects: - [pacman.zig](https://github.com/floooh/pacman.zig) - [kc85.zig](https://github.com/floooh/kc85.zig) -> NOTE: for experimental package manager support see the branch [package](https://github.com/floooh/sokol-zig/tree/package), -> and as example for how to integrate sokol-zig as package the [pacman.zig branch sokol-package](https://github.com/floooh/pacman.zig/tree/sokol-package) - -## BUILD +## Building the samples -Supported platforms are: Windows, macOS, Linux (with X11) +Supported platforms are: Windows, macOS, Linux (with X11) and web On Linux install the following packages: libglu1-mesa-dev, mesa-common-dev, xorg-dev, libasound-dev (or generally: the dev packages required for X11, GL and ALSA development) +To build the platform-native samples: + ```sh # just build: -> zig build +zig build # build and run samples: -> zig build run-clear -> zig build run-triangle -> zig build run-quad -> zig build run-bufferoffsets -> zig build run-cube -> zig build run-noninterleaved -> zig build run-texcube -> zig build run-offscreen -> zig build run-instancing -> zig build run-mrt -> zig build run-saudio -> zig build run-sgl -> zig build run-sgl-context -> zig build run-sgl-points -> zig build run-debugtext -> zig build run-debugtext-print -> zig build run-debugtext-userfont -> zig build run-shapes +zig build run-clear +zig build run-triangle +zig build run-quad +zig build run-bufferoffsets +zig build run-cube +zig build run-noninterleaved +zig build run-texcube +zig build run-offscreen +zig build run-instancing +zig build run-mrt +zig build run-saudio +zig build run-sgl +zig build run-sgl-context +zig build run-sgl-points +zig build run-debugtext +zig build run-debugtext-print +zig build run-debugtext-userfont +zig build run-shapes ``` (also run ```zig build --help``` to inspect the build targets) @@ -66,17 +68,40 @@ sokol-zig ➤ zig build -Dgl=true run-clear Backend: .sokol.gfx.Backend.GLCORE33 ``` -## Use with the Zig package manager +For the web-samples, run: + +```sh +zig build -Dtarget=wasm32-emscripten +# or to build and run one of the samples +zig build run-clear -Dtarget=wasm32-emscripten +... +``` + +When building with target `wasm32-emscripten` for the first time, the build script will +install and activate the Emscripten SDK into the Zig package cache for the latest SDK +version. There is currently no build system functionality to update or delete the Emscripten SDK +after this first install. The current workaround is to delete the global Zig cache +(run `zig env` to see where the Zig cache resides). + +Improving the Emscripten SDK integration with the Zig build system is planned for the future. + + +## How to integrate sokol-zig into your project -Add a build.zig.zon file to your project: +Add a build.zig.zon file to your project which has at least a `.sokol` dependency: ```zig .{ - .name = "xxx", + .name = "my_project", .version = "0.1.0", + .path = .{ + "src" + "build.zig", + "build.zig.zon", + }, .dependencies = .{ .sokol = .{ - .url = "https://github.com/floooh/sokol-zig/archive/[commit-sha].tar.gz", + .url = "git+https://github.com/floooh/sokol-zig.git#[commit-hash]", .hash = "[content-hash]", }, }, @@ -88,27 +113,100 @@ For the `[commit-sha]` just pick the latest from here: https://github.com/floooh To find out the `[content-hash]`, just omit the `.hash` line, and run `zig build`, this will then output the expected hash on the terminal. Copy-paste this into the build.zig.zon file. -Next in your build.zig file, get a Dependency object like this: +For a native-only project, a `build.zig` file looks entirely vanilla: ```zig +const std = @import("std"); +const Build = std.Build; +const OptimizeMode = std.builtin.OptimizeMode; + +pub fn build(b: *Build) !void { + const target = b.standardTargetOptions(.{}); + const optimize = b.standardOptimizeOption(.{}); const dep_sokol = b.dependency("sokol", .{ .target = target, .optimize = optimize, - // optionally more options like `.gl: true` }); + const hello = b.addExecutable(.{ + .name = "hello", + .target = target, + .optimize = optimize, + .root_source_file = .{ .path = "src/hello.zig" }, + }); + hello.root_module.addImport("sokol", dep_sokol.module("sokol")); + b.installArtifact(hello); + const run = b.addRunArtifact(hello); + b.step("run", "Run hello").dependOn(&run.step); +} ``` -This dependency contains one module and one static-library artifact which can be added -to your executable CompileStep like this: +If you also want to run on the web via `-Dtarget=wasm32-emscripten`, the web platform +build must look special, because Emscripten must be used for linking, and to run +the build result in a browser, a special run step must be created. + +Such a 'hybrid' build script might look like this (copied straight from [pacman.zig](https://github.com/floooh/pacman.zig)): ```zig - const exe = b.addExecutable(.{ +const std = @import("std"); +const Build = std.Build; +const OptimizeMode = std.builtin.OptimizeMode; +const sokol = @import("sokol"); + +pub fn build(b: *Build) !void { + const target = b.standardTargetOptions(.{}); + const optimize = b.standardOptimizeOption(.{}); + const dep_sokol = b.dependency("sokol", .{ + .target = target, + .optimize = optimize, + }); + + // special case handling for native vs web build + if (target.result.isWasm()) { + try buildWeb(b, target, optimize, dep_sokol); + } else { + try buildNative(b, target, optimize, dep_sokol); + } +} + +// this is the regular build for all native platforms, nothing surprising here +fn buildNative(b: *Build, target: Build.ResolvedTarget, optimize: OptimizeMode, dep_sokol: *Build.Dependency) !void { + const pacman = b.addExecutable(.{ .name = "pacman", .target = target, .optimize = optimize, .root_source_file = .{ .path = "src/pacman.zig" }, }); - exe.addModule("sokol", dep_sokol.module("sokol")); - exe.linkLibrary(dep_sokol.artifact("sokol")); - b.installArtifact(exe); -``` + pacman.root_module.addImport("sokol", dep_sokol.module("sokol")); + b.installArtifact(pacman); + const run = b.addRunArtifact(pacman); + b.step("run", "Run pacman").dependOn(&run.step); +} + +// for web builds, the Zig code needs to be built into a library and linked with the Emscripten linker +fn buildWeb(b: *Build, target: Build.ResolvedTarget, optimize: OptimizeMode, dep_sokol: *Build.Dependency) !void { + const pacman = b.addStaticLibrary(.{ + .name = "pacman", + .target = target, + .optimize = optimize, + .root_source_file = .{ .path = "src/pacman.zig" }, + }); + pacman.root_module.addImport("sokol", dep_sokol.module("sokol")); + + // create a build step which invokes the Emscripten linker + const emsdk = dep_sokol.builder.dependency("emsdk", .{}); + const link_step = try sokol.emLinkStep(b, .{ + .lib_main = pacman, + .target = target, + .optimize = optimize, + .emsdk = emsdk, + .use_webgl2 = true, + .use_emmalloc = true, + .use_filesystem = false, + .shell_file_path = dep_sokol.path("src/sokol/web/shell.html").getPath(b), + }); + // ...and a special run step to start the web build output via 'emrun' + const run = sokol.emRunStep(b, .{ .name = "pacman", .emsdk = emsdk }); + run.step.dependOn(&link_step.step); + b.step("run", "Run pacman").dependOn(&run.step); +} +``` \ No newline at end of file