From 8ac502599eade5d4d02e672565e1f40189f4a6a3 Mon Sep 17 00:00:00 2001 From: Jose Rico Date: Sat, 27 Jan 2024 15:13:12 -0500 Subject: [PATCH 01/14] initial setup --- build.zig | 123 ++++++++++++++++---------------------------------- build.zig.zon | 11 +++++ 2 files changed, 49 insertions(+), 85 deletions(-) create mode 100644 build.zig.zon diff --git a/build.zig b/build.zig index 8eb0cca..730c6f4 100644 --- a/build.zig +++ b/build.zig @@ -1,26 +1,54 @@ const std = @import("std"); + const generate = @import("generate.zig"); pub fn build(b: *std.Build) !void { - const raylibSrc = "raylib/src/"; - const target = b.standardTargetOptions(.{}); + const optimize = b.standardOptimizeOption(.{}); + + const raylib = b.dependency("raylib", .{ + .target = target, + .optimize = optimize, + }); + + // Set up "raylib_zig" module for use as a dependency. + const module = b.addModule("raylib_zig", .{ + .root_source_file = .{.path = "raylib.zig"}, + .target = target, + .optimize = optimize, + }); + module.addIncludePath(.{ + .path = try b.build_root.join(b.allocator, &[_][]const u8 {"."}) + }); + module.addIncludePath(raylib.path("src")); + module.addCSourceFiles(.{ + .files = &[_][]const u8{ + try b.build_root.join(b.allocator, &[_][]const u8 {"marshal.c"}), + }, + .flags = &.{} + }); + module.linkLibrary(raylib.artifact("raylib")); + module.link_libc = true; + // Set up binding generation library & exes. //--- parse raylib and generate JSONs for all signatures -------------------------------------- const jsons = b.step("parse", "parse raylib headers and generate raylib jsons"); const raylib_parser_build = b.addExecutable(.{ .name = "raylib_parser", - .root_source_file = std.build.FileSource.relative("raylib_parser.zig"), + .root_source_file = .{.path = "raylib_parser.zig"}, .target = target, - .optimize = .ReleaseFast, + .optimize = optimize, + }); + raylib_parser_build.addCSourceFile(.{ + .file = raylib.path("parser/raylib_parser.c"), + .flags = &.{} }); - raylib_parser_build.addCSourceFile(.{ .file = .{ .path = "raylib/parser/raylib_parser.c" }, .flags = &.{} }); raylib_parser_build.linkLibC(); //raylib const raylib_H = b.addRunArtifact(raylib_parser_build); raylib_H.addArgs(&.{ - "-i", raylibSrc ++ "raylib.h", + "-i", raylib.path("src/raylib.h").getPath(b), "-o", "raylib.json", "-f", "JSON", "-d", "RLAPI", @@ -30,7 +58,7 @@ pub fn build(b: *std.Build) !void { //raymath const raymath_H = b.addRunArtifact(raylib_parser_build); raymath_H.addArgs(&.{ - "-i", raylibSrc ++ "raymath.h", + "-i", raylib.path("src/raymath.h").getPath(b), "-o", "raymath.json", "-f", "JSON", "-d", "RMAPI", @@ -40,7 +68,7 @@ pub fn build(b: *std.Build) !void { //rlgl const rlgl_H = b.addRunArtifact(raylib_parser_build); rlgl_H.addArgs(&.{ - "-i", raylibSrc ++ "rlgl.h", + "-i", raylib.path("src/rlgl.h").getPath(b), "-o", "rlgl.json", "-f", "JSON", "-d", "RLAPI", @@ -51,7 +79,7 @@ pub fn build(b: *std.Build) !void { const intermediate = b.step("intermediate", "generate intermediate representation of the results from 'zig build parse' (keep custom=true)"); var intermediateZigStep = b.addRunArtifact(b.addExecutable(.{ .name = "intermediate", - .root_source_file = std.build.FileSource.relative("intermediate.zig"), + .root_source_file = .{.path = "intermediate.zig"}, .target = target, })); intermediate.dependOn(&intermediateZigStep.step); @@ -60,7 +88,7 @@ pub fn build(b: *std.Build) !void { const bindings = b.step("bindings", "generate bindings in from bindings.json"); var generateZigStep = b.addRunArtifact(b.addExecutable(.{ .name = "generate", - .root_source_file = std.build.FileSource.relative("generate.zig"), + .root_source_file = .{.path = "generate.zig"}, .target = target, })); const fmt = b.addFmt(.{ .paths = &.{generate.outputFile} }); @@ -72,78 +100,3 @@ pub fn build(b: *std.Build) !void { const generateBindings_install = b.addInstallArtifact(raylib_parser_build, .{}); raylib_parser_install.dependOn(&generateBindings_install.step); } - -// above: generate library -// below: linking (use as dependency) - -fn current_file() []const u8 { - return @src().file; -} - -const sep = std.fs.path.sep_str; -const cwd = std.fs.path.dirname(current_file()).?; -const dir_raylib = cwd ++ sep ++ "raylib" ++ sep ++ "src"; - -const raylib_build = @import("raylib/src/build.zig"); - -fn linkThisLibrary(b: *std.Build, target: std.Target.Query, optimize: std.builtin.Mode) *std.Build.Step.Compile { - const lib = b.addStaticLibrary(.{ .name = "raylib.zig", .target = b.resolveTargetQuery(target), .optimize = optimize }); - lib.addIncludePath(.{ .path = dir_raylib }); - lib.addIncludePath(.{ .path = cwd }); - lib.linkLibC(); - lib.addCSourceFile(.{ .file = .{ .path = cwd ++ sep ++ "marshal.c" }, .flags = &.{} }); - std.log.info("include '{s}' to {s}", .{ dir_raylib, lib.name }); - std.log.info("include '{s}' to {s}", .{ cwd, lib.name }); - return lib; -} - -/// add this package to exe -pub fn addTo(b: *std.Build, exe: *std.Build.Step.Compile, target: std.Target.Query, optimize: std.builtin.Mode, raylibOptions: raylib_build.Options) void { - exe.root_module.addAnonymousImport("raylib", .{ .root_source_file = .{ .path = cwd ++ sep ++ "raylib.zig" } }); - std.log.info("include '{s}' to {s}", .{ dir_raylib, exe.name }); - std.log.info("include '{s}' to {s}", .{ cwd, exe.name }); - exe.addIncludePath(.{ .path = dir_raylib }); - exe.addIncludePath(.{ .path = cwd }); - const lib = linkThisLibrary(b, target, optimize); - const lib_raylib = raylib_build.addRaylib(b, b.resolveTargetQuery(target), optimize, raylibOptions) catch |err| std.debug.panic("addRaylib: {any}", .{err}); - exe.linkLibrary(lib_raylib); - exe.linkLibrary(lib); - std.log.info("linked raylib.zig", .{}); -} - -pub fn linkSystemDependencies(exe: *std.build.Step.Compile) void { - switch (exe.target.getOsTag()) { - .macos => { - exe.linkFramework("Foundation"); - exe.linkFramework("Cocoa"); - exe.linkFramework("OpenGL"); - exe.linkFramework("CoreAudio"); - exe.linkFramework("CoreVideo"); - exe.linkFramework("IOKit"); - }, - .linux => { - exe.addLibraryPath(.{ .path = "/usr/lib" }); - exe.addIncludePath(.{ .path = "/usr/include" }); - exe.linkSystemLibrary("GL"); - exe.linkSystemLibrary("rt"); - exe.linkSystemLibrary("dl"); - exe.linkSystemLibrary("m"); - exe.linkSystemLibrary("X11"); - }, - .freebsd, .openbsd, .netbsd, .dragonfly => { - exe.linkSystemLibrary("GL"); - exe.linkSystemLibrary("rt"); - exe.linkSystemLibrary("dl"); - exe.linkSystemLibrary("m"); - exe.linkSystemLibrary("X11"); - exe.linkSystemLibrary("Xrandr"); - exe.linkSystemLibrary("Xinerama"); - exe.linkSystemLibrary("Xi"); - exe.linkSystemLibrary("Xxf86vm"); - exe.linkSystemLibrary("Xcursor"); - }, - else => {}, - } - - exe.linkLibC(); -} diff --git a/build.zig.zon b/build.zig.zon new file mode 100644 index 0000000..54664b9 --- /dev/null +++ b/build.zig.zon @@ -0,0 +1,11 @@ +.{ + .name = "raylib.zig", + .version = "0.0.0", + .paths = .{""}, + .dependencies = .{ + .raylib = .{ + .url = "https://github.com/raysan5/raylib/archive/40f3df5b865eee0cd87a9e4e1347cb04c87841f8.tar.gz", + .hash = "12209bb07b3926d027de330c05d9425eaa52cc1a40eed291628370ba759653d5f961", + }, + }, +} From 291fef5b12659b3b4d9a8b2095db73a5a44f0350 Mon Sep 17 00:00:00 2001 From: Jose Rico Date: Sat, 27 Jan 2024 16:20:52 -0500 Subject: [PATCH 02/14] fix paths --- build.zig | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/build.zig b/build.zig index 730c6f4..239f0bb 100644 --- a/build.zig +++ b/build.zig @@ -47,8 +47,9 @@ pub fn build(b: *std.Build) !void { //raylib const raylib_H = b.addRunArtifact(raylib_parser_build); + const path_raylib_H = try b.allocator.dupe(u8, raylib.path("src/raylib.h").getPath(b)); raylib_H.addArgs(&.{ - "-i", raylib.path("src/raylib.h").getPath(b), + "-i", path_raylib_H, "-o", "raylib.json", "-f", "JSON", "-d", "RLAPI", @@ -57,8 +58,9 @@ pub fn build(b: *std.Build) !void { //raymath const raymath_H = b.addRunArtifact(raylib_parser_build); + const path_raymath_H = try b.allocator.dupe(u8, raylib.path("src/raymath.h").getPath(b)); raymath_H.addArgs(&.{ - "-i", raylib.path("src/raymath.h").getPath(b), + "-i", path_raymath_H, "-o", "raymath.json", "-f", "JSON", "-d", "RMAPI", @@ -67,8 +69,9 @@ pub fn build(b: *std.Build) !void { //rlgl const rlgl_H = b.addRunArtifact(raylib_parser_build); + const path_rlgl_H = try b.allocator.dupe(u8, raylib.path("src/rlgl.h").getPath(b)); rlgl_H.addArgs(&.{ - "-i", raylib.path("src/rlgl.h").getPath(b), + "-i", path_rlgl_H, "-o", "rlgl.json", "-f", "JSON", "-d", "RLAPI", From 2aec2857c50f52dbde5a0140781f4c14275a8513 Mon Sep 17 00:00:00 2001 From: Jose Rico Date: Sat, 27 Jan 2024 18:33:30 -0500 Subject: [PATCH 03/14] remove submodule --- .gitmodules | 3 --- raylib | 1 - 2 files changed, 4 deletions(-) delete mode 100644 .gitmodules delete mode 160000 raylib diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 3ba065a..0000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "raylib"] - path = raylib - url = https://github.com/raysan5/raylib diff --git a/raylib b/raylib deleted file mode 160000 index 40f3df5..0000000 --- a/raylib +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 40f3df5b865eee0cd87a9e4e1347cb04c87841f8 From 57e865421232f987a6ffeff2e24e45dfbba2b2db Mon Sep 17 00:00:00 2001 From: Jose Rico Date: Sat, 27 Jan 2024 18:41:43 -0500 Subject: [PATCH 04/14] TODO emscripten --- build.zig | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/build.zig b/build.zig index 239f0bb..138751e 100644 --- a/build.zig +++ b/build.zig @@ -12,23 +12,30 @@ pub fn build(b: *std.Build) !void { }); // Set up "raylib_zig" module for use as a dependency. - const module = b.addModule("raylib_zig", .{ - .root_source_file = .{.path = "raylib.zig"}, - .target = target, - .optimize = optimize, - }); - module.addIncludePath(.{ - .path = try b.build_root.join(b.allocator, &[_][]const u8 {"."}) - }); - module.addIncludePath(raylib.path("src")); - module.addCSourceFiles(.{ - .files = &[_][]const u8{ - try b.build_root.join(b.allocator, &[_][]const u8 {"marshal.c"}), + switch (target.result.os.tag) { + .wasi, .emscripten => { + @panic("TODO: support emscripten build"); }, - .flags = &.{} - }); - module.linkLibrary(raylib.artifact("raylib")); - module.link_libc = true; + else => { + const module = b.addModule("raylib_zig", .{ + .root_source_file = .{.path = "raylib.zig"}, + .target = target, + .optimize = optimize, + }); + module.addIncludePath(.{ + .path = try b.build_root.join(b.allocator, &[_][]const u8 {"."}) + }); + module.addIncludePath(raylib.path("src")); + module.addCSourceFiles(.{ + .files = &[_][]const u8{ + try b.build_root.join(b.allocator, &[_][]const u8 {"marshal.c"}), + }, + .flags = &.{} + }); + module.linkLibrary(raylib.artifact("raylib")); + module.link_libc = true; + }, + } // Set up binding generation library & exes. //--- parse raylib and generate JSONs for all signatures -------------------------------------- From edf6e71e8782673a309f7b089ff2868515ed74af Mon Sep 17 00:00:00 2001 From: Jose Rico Date: Sat, 27 Jan 2024 19:48:14 -0500 Subject: [PATCH 05/14] almost but no --- build.zig | 45 +++++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/build.zig b/build.zig index 138751e..dec9252 100644 --- a/build.zig +++ b/build.zig @@ -12,29 +12,30 @@ pub fn build(b: *std.Build) !void { }); // Set up "raylib_zig" module for use as a dependency. - switch (target.result.os.tag) { - .wasi, .emscripten => { - @panic("TODO: support emscripten build"); - }, - else => { - const module = b.addModule("raylib_zig", .{ - .root_source_file = .{.path = "raylib.zig"}, - .target = target, - .optimize = optimize, - }); - module.addIncludePath(.{ - .path = try b.build_root.join(b.allocator, &[_][]const u8 {"."}) - }); - module.addIncludePath(raylib.path("src")); - module.addCSourceFiles(.{ - .files = &[_][]const u8{ - try b.build_root.join(b.allocator, &[_][]const u8 {"marshal.c"}), - }, - .flags = &.{} - }); - module.linkLibrary(raylib.artifact("raylib")); - module.link_libc = true; + const module = b.addModule("raylib_zig", .{ + .root_source_file = .{.path = "raylib.zig"}, + .target = target, + .optimize = optimize, + }); + module.addIncludePath(.{ + .path = try b.build_root.join(b.allocator, &.{"."}) + }); + module.addIncludePath(raylib.path("src")); + module.addCSourceFiles(.{ + .files = &[_][]const u8{ + try b.build_root.join(b.allocator, &.{"marshal.c"}), }, + .flags = &.{} + }); + module.linkLibrary(raylib.artifact("raylib")); + module.link_libc = true; + if (target.result.os.tag == .emscripten) { + if (b.sysroot == null) { + @panic("Pass '--sysroot \"$EMSDK/upstream/emscripten\"'"); + } + const cache_include = try std.fs.path.join(b.allocator, &.{ b.sysroot.?, "cache", "sysroot", "include" }); + module.addIncludePath(.{ .path = cache_include }); + // TODO hm... yeah, we have to link with emcc and stuff, so this isn't gonna cut it. } // Set up binding generation library & exes. From 2144db410e7e599f41a0c7cc86fc7c986706fdf0 Mon Sep 17 00:00:00 2001 From: Jose Rico Date: Sat, 27 Jan 2024 21:54:53 -0500 Subject: [PATCH 06/14] try to support web build --- build.zig | 153 +++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 133 insertions(+), 20 deletions(-) diff --git a/build.zig b/build.zig index dec9252..b824968 100644 --- a/build.zig +++ b/build.zig @@ -1,42 +1,104 @@ const std = @import("std"); +const builtin = @import("builtin"); const generate = @import("generate.zig"); -pub fn build(b: *std.Build) !void { - const target = b.standardTargetOptions(.{}); - const optimize = b.standardOptimizeOption(.{}); +const emccOutputDir = "zig-out" ++ std.fs.path.sep_str ++ "htmlout" ++ std.fs.path.sep_str; +const emccOutputFile = "index.html"; - const raylib = b.dependency("raylib", .{ - .target = target, - .optimize = optimize, +pub fn setup(app_builder: *std.Build, raylib_zig: *std.Build.Dependency, options: struct { + name: []const u8, + src: []const u8, + target: std.Build.ResolvedTarget, + optimize: std.builtin.OptimizeMode, + custom_entrypoint: ?[]const u8 = null, + deps: ?[]const std.Build.Module.Import = null, +}) !*std.Build.Step.Compile { + const this_builder = raylib_zig.builder; + const raylib = this_builder.dependency("raylib", .{ + .target = options.target, + .optimize = options.optimize, }); - // Set up "raylib_zig" module for use as a dependency. - const module = b.addModule("raylib_zig", .{ - .root_source_file = .{.path = "raylib.zig"}, - .target = target, - .optimize = optimize, + const module = app_builder.createModule(.{ + .root_source_file = .{.path = raylib_zig.path("raylib.zig").getPath(this_builder)}, + .target = options.target, + .optimize = options.optimize, }); module.addIncludePath(.{ - .path = try b.build_root.join(b.allocator, &.{"."}) + .path = try this_builder.build_root.join(app_builder.allocator, &.{"."}) }); module.addIncludePath(raylib.path("src")); module.addCSourceFiles(.{ - .files = &[_][]const u8{ - try b.build_root.join(b.allocator, &.{"marshal.c"}), + .files = &.{ + raylib_zig.path("marshal.c").getPath(this_builder), }, .flags = &.{} }); module.linkLibrary(raylib.artifact("raylib")); module.link_libc = true; - if (target.result.os.tag == .emscripten) { - if (b.sysroot == null) { - @panic("Pass '--sysroot \"$EMSDK/upstream/emscripten\"'"); + + var compile: *std.Build.Step.Compile = undefined; + switch (options.target.result.os.tag) { + .emscripten => { + if (app_builder.sysroot == null) { + @panic("Pass '--sysroot \"$EMSDK/upstream/emscripten\"'"); + } + const cache_include = try std.fs.path.join(app_builder.allocator, &.{ app_builder.sysroot.?, "cache", "sysroot", "include" }); + module.addIncludePath(.{ .path = cache_include }); + + compile = app_builder.addStaticLibrary(.{ + .name = options.name, + .root_source_file = .{.path = options.src}, + .target = options.target, + .optimize = options.optimize, + }); + // There are some symbols that need to be defined in C. + // const webhack_c_file_step = b.addWriteFiles(); + // const webhack_c_file = webhack_c_file_step.add("webhack.c", webhack_c); + // exe_lib.addCSourceFile(.{ .file = webhack_c_file, .flags = &[_][]u8{} }); + // Since it's creating a static library, the symbols raylib uses to webgl + // and glfw don't need to be linked by emscripten yet. + // exe_lib.step.dependOn(&webhack_c_file_step.step); + // const exe_lib = compileForEmscripten(b, ex.name, ex.path, target, optimize); + compile.root_module.addImport("raylib", module); + // exe_lib.addModule("raylib-math", raylib_math); + // const raylib_artifact = getArtifact(b, target, optimize); + + // Note that raylib itself isn't actually added to the exe_lib + // output file, so it also needs to be linked with emscripten. + // exe_lib.linkLibrary(raylib_artifact); + const link_step = try linkWithEmscripten(app_builder, &.{ compile }); + // link_step.addArg("--embed-file"); + // link_step.addArg("resources/"); + app_builder.getInstallStep().dependOn(&link_step.step); + + // const run_step = try emscriptenRunStep(b); + // run_step.step.dependOn(&link_step.step); + // const run_option = b.step(ex.name, ex.desc); + // run_option.dependOn(&run_step.step); + }, + else => { + compile = app_builder.addExecutable(.{ + .name = options.name, + .root_source_file = .{.path = options.src}, + .target = options.target, + .optimize = options.optimize, + }); + compile.root_module.addImport("raylib", module); } - const cache_include = try std.fs.path.join(b.allocator, &.{ b.sysroot.?, "cache", "sysroot", "include" }); - module.addIncludePath(.{ .path = cache_include }); - // TODO hm... yeah, we have to link with emcc and stuff, so this isn't gonna cut it. } + return compile; +} + +pub fn build(b: *std.Build) !void { + const target = b.standardTargetOptions(.{}); + const optimize = b.standardOptimizeOption(.{}); + + const raylib = b.dependency("raylib", .{ + .target = target, + .optimize = optimize, + }); // Set up binding generation library & exes. //--- parse raylib and generate JSONs for all signatures -------------------------------------- @@ -111,3 +173,54 @@ pub fn build(b: *std.Build) !void { const generateBindings_install = b.addInstallArtifact(raylib_parser_build, .{}); raylib_parser_install.dependOn(&generateBindings_install.step); } + +// Links a set of items together using emscripten. +// +// Will accept objects and static libraries as items to link. As for files to +// include, it is recomended to have a single resources directory and just pass +// the entire directory instead of passing every file individually. The entire +// path given will be the path to read the file within the program. So, if +// "resources/image.png" is passed, your program will use "resources/image.png" +// as the path to load the file. +// +// TODO: Test if shared libraries are accepted, I don't remember if emcc can +// link a shared library with a project or not. +// TODO: Add a parameter that allows a custom output directory. +fn linkWithEmscripten( + b: *std.Build, + itemsToLink: []const *std.Build.Step.Compile, +) !*std.Build.Step.Run { + const emcc_exe = switch (builtin.os.tag) { + .windows => "emcc.bat", + else => "emcc", + }; + const emcc_exe_path = try std.fmt.allocPrint(b.allocator, "{s}" ++ std.fs.path.sep_str ++ "{s}", .{ + b.sysroot.?, emcc_exe + }); + + // Create the output directory because emcc can't do it. + const mkdir_command = b.addSystemCommand(&.{ "mkdir", "-p", emccOutputDir }); + + // Actually link everything together. + const emcc_command = switch (builtin.os.tag) { + .windows => b.addSystemCommand(&.{"cmd", "/C", emcc_exe_path}), + else => b.addSystemCommand(&.{emcc_exe_path}), + }; + + for (itemsToLink) |item| { + emcc_command.addFileArg(item.getEmittedBin()); + emcc_command.step.dependOn(&item.step); + } + // This puts the file in zig-out/htmlout/index.html. + emcc_command.step.dependOn(&mkdir_command.step); + emcc_command.addArgs(&[_][]const u8{ + "-o", + emccOutputDir ++ emccOutputFile, + "-sFULL-ES3=1", + "-sUSE_GLFW=3", + "-sASYNCIFY", + "-O3", + "--emrun", + }); + return emcc_command; +} From b7130b87ac78ad3cef8bdc9e4ea754cb528c9883 Mon Sep 17 00:00:00 2001 From: Jose Rico Date: Sat, 27 Jan 2024 23:36:56 -0500 Subject: [PATCH 07/14] it works! I think --- build.zig | 90 +++++++++++++++++++++++++++---------------------------- 1 file changed, 45 insertions(+), 45 deletions(-) diff --git a/build.zig b/build.zig index b824968..daa62ae 100644 --- a/build.zig +++ b/build.zig @@ -11,8 +11,8 @@ pub fn setup(app_builder: *std.Build, raylib_zig: *std.Build.Dependency, options src: []const u8, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode, - custom_entrypoint: ?[]const u8 = null, deps: ?[]const std.Build.Module.Import = null, + createRunStep: bool, }) !*std.Build.Step.Compile { const this_builder = raylib_zig.builder; const raylib = this_builder.dependency("raylib", .{ @@ -21,7 +21,7 @@ pub fn setup(app_builder: *std.Build, raylib_zig: *std.Build.Dependency, options }); const module = app_builder.createModule(.{ - .root_source_file = .{.path = raylib_zig.path("raylib.zig").getPath(this_builder)}, + .root_source_file = raylib_zig.path("raylib.zig"), .target = options.target, .optimize = options.optimize, }); @@ -35,7 +35,6 @@ pub fn setup(app_builder: *std.Build, raylib_zig: *std.Build.Dependency, options }, .flags = &.{} }); - module.linkLibrary(raylib.artifact("raylib")); module.link_libc = true; var compile: *std.Build.Step.Compile = undefined; @@ -53,30 +52,15 @@ pub fn setup(app_builder: *std.Build, raylib_zig: *std.Build.Dependency, options .target = options.target, .optimize = options.optimize, }); - // There are some symbols that need to be defined in C. - // const webhack_c_file_step = b.addWriteFiles(); - // const webhack_c_file = webhack_c_file_step.add("webhack.c", webhack_c); - // exe_lib.addCSourceFile(.{ .file = webhack_c_file, .flags = &[_][]u8{} }); - // Since it's creating a static library, the symbols raylib uses to webgl - // and glfw don't need to be linked by emscripten yet. - // exe_lib.step.dependOn(&webhack_c_file_step.step); - // const exe_lib = compileForEmscripten(b, ex.name, ex.path, target, optimize); - compile.root_module.addImport("raylib", module); - // exe_lib.addModule("raylib-math", raylib_math); - // const raylib_artifact = getArtifact(b, target, optimize); - - // Note that raylib itself isn't actually added to the exe_lib - // output file, so it also needs to be linked with emscripten. - // exe_lib.linkLibrary(raylib_artifact); - const link_step = try linkWithEmscripten(app_builder, &.{ compile }); - // link_step.addArg("--embed-file"); - // link_step.addArg("resources/"); + const link_step = try linkWithEmscripten(app_builder, &.{compile, raylib.artifact("raylib")}); app_builder.getInstallStep().dependOn(&link_step.step); - // const run_step = try emscriptenRunStep(b); - // run_step.step.dependOn(&link_step.step); - // const run_option = b.step(ex.name, ex.desc); - // run_option.dependOn(&run_step.step); + if (options.createRunStep) { + const run_step = try emscriptenRunStep(app_builder); + run_step.step.dependOn(&link_step.step); + const run_option = app_builder.step("run", "Run"); + run_option.dependOn(&run_step.step); + } }, else => { compile = app_builder.addExecutable(.{ @@ -85,9 +69,26 @@ pub fn setup(app_builder: *std.Build, raylib_zig: *std.Build.Dependency, options .target = options.target, .optimize = options.optimize, }); - compile.root_module.addImport("raylib", module); + compile.linkLibrary(raylib.artifact("raylib")); + + if (options.createRunStep) { + const run_cmd = app_builder.addRunArtifact(compile); + run_cmd.step.dependOn(app_builder.getInstallStep()); + if (app_builder.args) |args| { + run_cmd.addArgs(args); + } + const run_option = app_builder.step("run", "Run"); + run_option.dependOn(&run_cmd.step); + } + } + } + if (options.deps) |deps| { + for (deps) |dep| { + compile.root_module.addImport(dep.name, dep.module); } } + compile.root_module.addImport("raylib", module); + return compile; } @@ -100,7 +101,6 @@ pub fn build(b: *std.Build) !void { .optimize = optimize, }); - // Set up binding generation library & exes. //--- parse raylib and generate JSONs for all signatures -------------------------------------- const jsons = b.step("parse", "parse raylib headers and generate raylib jsons"); const raylib_parser_build = b.addExecutable(.{ @@ -174,18 +174,19 @@ pub fn build(b: *std.Build) !void { raylib_parser_install.dependOn(&generateBindings_install.step); } -// Links a set of items together using emscripten. -// -// Will accept objects and static libraries as items to link. As for files to -// include, it is recomended to have a single resources directory and just pass -// the entire directory instead of passing every file individually. The entire -// path given will be the path to read the file within the program. So, if -// "resources/image.png" is passed, your program will use "resources/image.png" -// as the path to load the file. -// -// TODO: Test if shared libraries are accepted, I don't remember if emcc can -// link a shared library with a project or not. -// TODO: Add a parameter that allows a custom output directory. +fn emscriptenRunStep(b: *std.Build) !*std.Build.Step.Run { + const emrun_exe = switch (builtin.os.tag) { + .windows => "emrun.bat", + else => "emrun", + }; + const emrun_exe_path = try std.fmt.allocPrint(b.allocator, "{s}" ++ std.fs.path.sep_str ++ "{s}", .{ + b.sysroot.?, emrun_exe + }); + + const run_cmd = b.addSystemCommand(&[_][]const u8{ emrun_exe_path, emccOutputDir ++ emccOutputFile }); + return run_cmd; +} + fn linkWithEmscripten( b: *std.Build, itemsToLink: []const *std.Build.Step.Compile, @@ -198,21 +199,20 @@ fn linkWithEmscripten( b.sysroot.?, emcc_exe }); - // Create the output directory because emcc can't do it. - const mkdir_command = b.addSystemCommand(&.{ "mkdir", "-p", emccOutputDir }); + // Create the output directory. + try b.build_root.handle.makePath(emccOutputDir); - // Actually link everything together. + // Link everything together with emcc. + // TODO: The build doesn't work on Windows if emc_exe_path and any of the item + // emitted bin paths have spaces. const emcc_command = switch (builtin.os.tag) { .windows => b.addSystemCommand(&.{"cmd", "/C", emcc_exe_path}), else => b.addSystemCommand(&.{emcc_exe_path}), }; - for (itemsToLink) |item| { emcc_command.addFileArg(item.getEmittedBin()); emcc_command.step.dependOn(&item.step); } - // This puts the file in zig-out/htmlout/index.html. - emcc_command.step.dependOn(&mkdir_command.step); emcc_command.addArgs(&[_][]const u8{ "-o", emccOutputDir ++ emccOutputFile, From 7c882c229e8dc4fb6168e9a1cfed4ab1df31f40f Mon Sep 17 00:00:00 2001 From: Jose Rico Date: Sat, 27 Jan 2024 23:46:24 -0500 Subject: [PATCH 08/14] rm deps param --- build.zig | 6 ------ 1 file changed, 6 deletions(-) diff --git a/build.zig b/build.zig index daa62ae..b409bd8 100644 --- a/build.zig +++ b/build.zig @@ -11,7 +11,6 @@ pub fn setup(app_builder: *std.Build, raylib_zig: *std.Build.Dependency, options src: []const u8, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode, - deps: ?[]const std.Build.Module.Import = null, createRunStep: bool, }) !*std.Build.Step.Compile { const this_builder = raylib_zig.builder; @@ -82,11 +81,6 @@ pub fn setup(app_builder: *std.Build, raylib_zig: *std.Build.Dependency, options } } } - if (options.deps) |deps| { - for (deps) |dep| { - compile.root_module.addImport(dep.name, dep.module); - } - } compile.root_module.addImport("raylib", module); return compile; From f45964a96eb46ab7c0e7d725d880e40d9c0f5098 Mon Sep 17 00:00:00 2001 From: Jose Rico Date: Sun, 28 Jan 2024 00:08:05 -0500 Subject: [PATCH 09/14] delete old emscripten stuff --- emscripten/entry.c | 24 --- emscripten/minshell.html | 96 ------------ emscripten/shell.html | 328 --------------------------------------- 3 files changed, 448 deletions(-) delete mode 100644 emscripten/entry.c delete mode 100644 emscripten/minshell.html delete mode 100644 emscripten/shell.html diff --git a/emscripten/entry.c b/emscripten/entry.c deleted file mode 100644 index 245e9e5..0000000 --- a/emscripten/entry.c +++ /dev/null @@ -1,24 +0,0 @@ -#include -#include - -#include "emscripten/emscripten.h" -#include "raylib.h" - -// Zig compiles C code with -fstack-protector-strong which requires the following two symbols -// which don't seem to be provided by the emscripten toolchain(?) -void *__stack_chk_guard = (void *)0xdeadbeef; -void __stack_chk_fail(void) -{ - exit(1); -} - - -// emsc_main() is the Zig entry function in main.zig -extern int emsc_main(void); - -extern void emsc_set_window_size(int width, int height); - -int main() -{ - return emsc_main(); -} diff --git a/emscripten/minshell.html b/emscripten/minshell.html deleted file mode 100644 index 5095ad8..0000000 --- a/emscripten/minshell.html +++ /dev/null @@ -1,96 +0,0 @@ - - - - - - - - - - - - demo - - - - - - - - - - - - - {{{ SCRIPT }}} - - - \ No newline at end of file diff --git a/emscripten/shell.html b/emscripten/shell.html deleted file mode 100644 index 3ab8c3a..0000000 --- a/emscripten/shell.html +++ /dev/null @@ -1,328 +0,0 @@ - - - - - - - raylib web game - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - - - - - - - {{{ SCRIPT }}} - - From 2749992467f9bf2b0f8f4c72220643ae3485bc88 Mon Sep 17 00:00:00 2001 From: Jose Rico Date: Sun, 28 Jan 2024 00:10:38 -0500 Subject: [PATCH 10/14] run through zig fmt --- build.zig | 42 +++++++++++++++--------------------------- 1 file changed, 15 insertions(+), 27 deletions(-) diff --git a/build.zig b/build.zig index b409bd8..6adfe91 100644 --- a/build.zig +++ b/build.zig @@ -24,16 +24,11 @@ pub fn setup(app_builder: *std.Build, raylib_zig: *std.Build.Dependency, options .target = options.target, .optimize = options.optimize, }); - module.addIncludePath(.{ - .path = try this_builder.build_root.join(app_builder.allocator, &.{"."}) - }); + module.addIncludePath(.{ .path = try this_builder.build_root.join(app_builder.allocator, &.{"."}) }); module.addIncludePath(raylib.path("src")); - module.addCSourceFiles(.{ - .files = &.{ - raylib_zig.path("marshal.c").getPath(this_builder), - }, - .flags = &.{} - }); + module.addCSourceFiles(.{ .files = &.{ + raylib_zig.path("marshal.c").getPath(this_builder), + }, .flags = &.{} }); module.link_libc = true; var compile: *std.Build.Step.Compile = undefined; @@ -47,11 +42,11 @@ pub fn setup(app_builder: *std.Build, raylib_zig: *std.Build.Dependency, options compile = app_builder.addStaticLibrary(.{ .name = options.name, - .root_source_file = .{.path = options.src}, + .root_source_file = .{ .path = options.src }, .target = options.target, .optimize = options.optimize, }); - const link_step = try linkWithEmscripten(app_builder, &.{compile, raylib.artifact("raylib")}); + const link_step = try linkWithEmscripten(app_builder, &.{ compile, raylib.artifact("raylib") }); app_builder.getInstallStep().dependOn(&link_step.step); if (options.createRunStep) { @@ -64,7 +59,7 @@ pub fn setup(app_builder: *std.Build, raylib_zig: *std.Build.Dependency, options else => { compile = app_builder.addExecutable(.{ .name = options.name, - .root_source_file = .{.path = options.src}, + .root_source_file = .{ .path = options.src }, .target = options.target, .optimize = options.optimize, }); @@ -79,7 +74,7 @@ pub fn setup(app_builder: *std.Build, raylib_zig: *std.Build.Dependency, options const run_option = app_builder.step("run", "Run"); run_option.dependOn(&run_cmd.step); } - } + }, } compile.root_module.addImport("raylib", module); @@ -99,14 +94,11 @@ pub fn build(b: *std.Build) !void { const jsons = b.step("parse", "parse raylib headers and generate raylib jsons"); const raylib_parser_build = b.addExecutable(.{ .name = "raylib_parser", - .root_source_file = .{.path = "raylib_parser.zig"}, + .root_source_file = .{ .path = "raylib_parser.zig" }, .target = target, .optimize = optimize, }); - raylib_parser_build.addCSourceFile(.{ - .file = raylib.path("parser/raylib_parser.c"), - .flags = &.{} - }); + raylib_parser_build.addCSourceFile(.{ .file = raylib.path("parser/raylib_parser.c"), .flags = &.{} }); raylib_parser_build.linkLibC(); //raylib @@ -146,7 +138,7 @@ pub fn build(b: *std.Build) !void { const intermediate = b.step("intermediate", "generate intermediate representation of the results from 'zig build parse' (keep custom=true)"); var intermediateZigStep = b.addRunArtifact(b.addExecutable(.{ .name = "intermediate", - .root_source_file = .{.path = "intermediate.zig"}, + .root_source_file = .{ .path = "intermediate.zig" }, .target = target, })); intermediate.dependOn(&intermediateZigStep.step); @@ -155,7 +147,7 @@ pub fn build(b: *std.Build) !void { const bindings = b.step("bindings", "generate bindings in from bindings.json"); var generateZigStep = b.addRunArtifact(b.addExecutable(.{ .name = "generate", - .root_source_file = .{.path = "generate.zig"}, + .root_source_file = .{ .path = "generate.zig" }, .target = target, })); const fmt = b.addFmt(.{ .paths = &.{generate.outputFile} }); @@ -173,9 +165,7 @@ fn emscriptenRunStep(b: *std.Build) !*std.Build.Step.Run { .windows => "emrun.bat", else => "emrun", }; - const emrun_exe_path = try std.fmt.allocPrint(b.allocator, "{s}" ++ std.fs.path.sep_str ++ "{s}", .{ - b.sysroot.?, emrun_exe - }); + const emrun_exe_path = try std.fmt.allocPrint(b.allocator, "{s}" ++ std.fs.path.sep_str ++ "{s}", .{ b.sysroot.?, emrun_exe }); const run_cmd = b.addSystemCommand(&[_][]const u8{ emrun_exe_path, emccOutputDir ++ emccOutputFile }); return run_cmd; @@ -189,9 +179,7 @@ fn linkWithEmscripten( .windows => "emcc.bat", else => "emcc", }; - const emcc_exe_path = try std.fmt.allocPrint(b.allocator, "{s}" ++ std.fs.path.sep_str ++ "{s}", .{ - b.sysroot.?, emcc_exe - }); + const emcc_exe_path = try std.fmt.allocPrint(b.allocator, "{s}" ++ std.fs.path.sep_str ++ "{s}", .{ b.sysroot.?, emcc_exe }); // Create the output directory. try b.build_root.handle.makePath(emccOutputDir); @@ -200,7 +188,7 @@ fn linkWithEmscripten( // TODO: The build doesn't work on Windows if emc_exe_path and any of the item // emitted bin paths have spaces. const emcc_command = switch (builtin.os.tag) { - .windows => b.addSystemCommand(&.{"cmd", "/C", emcc_exe_path}), + .windows => b.addSystemCommand(&.{ "cmd", "/C", emcc_exe_path }), else => b.addSystemCommand(&.{emcc_exe_path}), }; for (itemsToLink) |item| { From a658e118e144e5206146cc982a7b12097d846eae Mon Sep 17 00:00:00 2001 From: Jose Rico Date: Sun, 28 Jan 2024 00:19:29 -0500 Subject: [PATCH 11/14] update README --- README.md | 56 +++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 36 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index c0c8870..7a434a8 100644 --- a/README.md +++ b/README.md @@ -26,26 +26,44 @@ For [raygui](https://github.com/raysan5/raygui) bindings see: https://github.com ## usage -The easy way would be adding this as submodule directly in your source folder. -Thats what I do until there is an official package manager for Zig. - -```sh -cd $YOUR_SRC_FOLDER -git submodule add https://github.com/ryupold/raylib.zig raylib -git submodule update --init --recursive +Add this as a dependency to your `build.zig.zon` +```zig +.{ + .name = "example", + .version = "1.0.0", + .paths = ..., + .dependencies = .{ + .raylib_zig = .{ + .url = "https://github.com/kapricorn-media/raylib.zig/archive/7c882c229e8dc4fb6168e9a1cfed4ab1df31f40f.tar.gz", + .hash = "1220141e38f5d075c77a9d4fbd5c2b622ed1f0207ff2bdfc67af3488609e5067289b", + }, + }, +} ``` -The bindings have been prebuilt so you just need to add raylib as module - -build.zig: +Then add the following setup to your `build.zig`: ```zig -const raylib = @import("path/to/raylib.zig/build.zig"); +const std = @import("std"); + +const raylib_zig_build = @import("raylib_zig"); -pub fn build(b: *std.Build) !void { +pub fn build(b: *std.Build) !void +{ const target = b.standardTargetOptions(.{}); - const mode = b.standardOptimizeOption(.{}); - const exe = ...; - raylib.addTo(b, exe, target, mode, .{}); + const optimize = b.standardOptimizeOption(.{}); + + const raylib_zig = b.dependency("raylib_zig", .{ + .target = target, + .optimize = optimize, + }); + const compile = try raylib_zig_build.setup(b, raylib_zig, .{ + .name = "example", + .src = "src/main.zig", + .target = target, + .optimize = optimize, + .createRunStep = true, + }); + b.installArtifact(compile); } ``` @@ -63,7 +81,7 @@ pub fn main() void { while (!raylib.WindowShouldClose()) { raylib.BeginDrawing(); defer raylib.EndDrawing(); - + raylib.ClearBackground(raylib.BLACK); raylib.DrawFPS(10, 10); @@ -72,11 +90,9 @@ pub fn main() void { } ``` -### WebGL (emscripten) builds - -For Webassembly builds see [examples-raylib.zig/build.zig](https://github.com/ryupold/examples-raylib.zig/blob/main/build.zig) +### WASM / emscripten builds -This weird workaround with `marshal.h/marshal.c` I actually had to make for Webassembly builds to work, because passing structs as function parameters or returning them cannot be done on the Zig side somehow. If I try it, I get a runtime error "index out of bounds". This happens only in WebAssembly builds. So `marshal.c` must be compiled with `emcc`. See [build.zig](https://github.com/ryupold/examples-raylib.zig/blob/main/build.zig) in the examples. +Download and install the [emscripten SDK](https://emscripten.org/docs/getting_started/downloads.html), and then add the flags `-Dtarget=wasm32-emscripten` and `--sysroot /upstream/emscripten` to the zig build. ## custom definitions An easy way to fix binding mistakes is to edit them in `bindings.json` and setting the custom flag to true. This way the binding will not be overriden when calling `zig build intermediate`. From e749fb046d12c2c559ef78502f6c22d6a52246d3 Mon Sep 17 00:00:00 2001 From: Jose Rico Date: Sun, 28 Jan 2024 10:30:08 -0500 Subject: [PATCH 12/14] move module to build function --- build.zig | 48 ++++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/build.zig b/build.zig index 6adfe91..e331441 100644 --- a/build.zig +++ b/build.zig @@ -3,9 +3,6 @@ const builtin = @import("builtin"); const generate = @import("generate.zig"); -const emccOutputDir = "zig-out" ++ std.fs.path.sep_str ++ "htmlout" ++ std.fs.path.sep_str; -const emccOutputFile = "index.html"; - pub fn setup(app_builder: *std.Build, raylib_zig: *std.Build.Dependency, options: struct { name: []const u8, src: []const u8, @@ -13,33 +10,14 @@ pub fn setup(app_builder: *std.Build, raylib_zig: *std.Build.Dependency, options optimize: std.builtin.OptimizeMode, createRunStep: bool, }) !*std.Build.Step.Compile { - const this_builder = raylib_zig.builder; - const raylib = this_builder.dependency("raylib", .{ + const raylib = raylib_zig.builder.dependency("raylib", .{ .target = options.target, .optimize = options.optimize, }); - const module = app_builder.createModule(.{ - .root_source_file = raylib_zig.path("raylib.zig"), - .target = options.target, - .optimize = options.optimize, - }); - module.addIncludePath(.{ .path = try this_builder.build_root.join(app_builder.allocator, &.{"."}) }); - module.addIncludePath(raylib.path("src")); - module.addCSourceFiles(.{ .files = &.{ - raylib_zig.path("marshal.c").getPath(this_builder), - }, .flags = &.{} }); - module.link_libc = true; - var compile: *std.Build.Step.Compile = undefined; switch (options.target.result.os.tag) { .emscripten => { - if (app_builder.sysroot == null) { - @panic("Pass '--sysroot \"$EMSDK/upstream/emscripten\"'"); - } - const cache_include = try std.fs.path.join(app_builder.allocator, &.{ app_builder.sysroot.?, "cache", "sysroot", "include" }); - module.addIncludePath(.{ .path = cache_include }); - compile = app_builder.addStaticLibrary(.{ .name = options.name, .root_source_file = .{ .path = options.src }, @@ -76,7 +54,7 @@ pub fn setup(app_builder: *std.Build, raylib_zig: *std.Build.Dependency, options } }, } - compile.root_module.addImport("raylib", module); + compile.root_module.addImport("raylib", raylib_zig.module("raylib")); return compile; } @@ -90,6 +68,25 @@ pub fn build(b: *std.Build) !void { .optimize = optimize, }); + // Add raylib module for use in dependencies. + const module = b.addModule("raylib", .{ + .root_source_file = .{ .path = "raylib.zig" }, + .target = target, + .optimize = optimize, + }); + module.addIncludePath(.{ .path = "." }); + module.addIncludePath(raylib.path("src")); + const marshal_c_path = try b.build_root.join(b.allocator, &.{"marshal.c"}); + module.addCSourceFile(.{ .file = .{.path = marshal_c_path}, .flags = &.{} }); + module.link_libc = true; + if (target.result.os.tag == .emscripten) { + if (b.sysroot == null) { + @panic("Pass '--sysroot \"$EMSDK/upstream/emscripten\"'"); + } + const emscripten_include_path = try std.fs.path.join(b.allocator, &.{ b.sysroot.?, "cache", "sysroot", "include" }); + module.addIncludePath(.{ .path = emscripten_include_path }); + } + //--- parse raylib and generate JSONs for all signatures -------------------------------------- const jsons = b.step("parse", "parse raylib headers and generate raylib jsons"); const raylib_parser_build = b.addExecutable(.{ @@ -160,6 +157,9 @@ pub fn build(b: *std.Build) !void { raylib_parser_install.dependOn(&generateBindings_install.step); } +const emccOutputDir = "zig-out" ++ std.fs.path.sep_str ++ "htmlout" ++ std.fs.path.sep_str; +const emccOutputFile = "index.html"; + fn emscriptenRunStep(b: *std.Build) !*std.Build.Step.Run { const emrun_exe = switch (builtin.os.tag) { .windows => "emrun.bat", From f7d7ca14a086b4866e0b37013da4d18ab2d4af59 Mon Sep 17 00:00:00 2001 From: Jose Rico Date: Sun, 28 Jan 2024 10:59:24 -0500 Subject: [PATCH 13/14] comment --- build.zig | 1 + 1 file changed, 1 insertion(+) diff --git a/build.zig b/build.zig index e331441..a0d431d 100644 --- a/build.zig +++ b/build.zig @@ -76,6 +76,7 @@ pub fn build(b: *std.Build) !void { }); module.addIncludePath(.{ .path = "." }); module.addIncludePath(raylib.path("src")); + // TODO: relative path doesn't work here when used as a dependency, not sure why... const marshal_c_path = try b.build_root.join(b.allocator, &.{"marshal.c"}); module.addCSourceFile(.{ .file = .{.path = marshal_c_path}, .flags = &.{} }); module.link_libc = true; From 44360a577aec4916e32337f9a900cd407aca4e13 Mon Sep 17 00:00:00 2001 From: Jose Rico Date: Sun, 28 Jan 2024 12:44:56 -0500 Subject: [PATCH 14/14] readme fix --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7a434a8..9c50e48 100644 --- a/README.md +++ b/README.md @@ -34,8 +34,8 @@ Add this as a dependency to your `build.zig.zon` .paths = ..., .dependencies = .{ .raylib_zig = .{ - .url = "https://github.com/kapricorn-media/raylib.zig/archive/7c882c229e8dc4fb6168e9a1cfed4ab1df31f40f.tar.gz", - .hash = "1220141e38f5d075c77a9d4fbd5c2b622ed1f0207ff2bdfc67af3488609e5067289b", + .url = "https://github.com/ryupold/raylib.zig/archive/.tar.gz", + .hash = "", }, }, }