diff --git a/build.zig b/build.zig index 88a608e52..f76d21d7a 100644 --- a/build.zig +++ b/build.zig @@ -51,14 +51,22 @@ pub fn build(b: *std.Build) !void { , ) orelse .static; + const main_callbacks = b.option(bool, "main_callbacks", + \\build SDL3_main to enter the app through SDL_AppInit/Iterate/Event/Quit rather + \\than a classic SDL_main, defaults to false + ) orelse false; + + const can_san = target.result.os.tag != .ios; + // Cross-compiling to a target whose SDK isn't bundled with Zig (iOS, Android) needs the // SDK's headers/frameworks/libs passed in explicitly. Scoped to the SDL library only, unlike // `--sysroot` this does not re-roots paths across the whole build graph. - const system_paths: SystemPaths = .{ + // On Apple, if paths are not passed explicitly then fall back to the SDK found via `xcrun`. + const system_paths = withAppleSdkFallback(b, target.result, .{ .include = b.option(std.Build.LazyPath, "include_path", "SDK include dir, e.g. $(xcrun --sdk iphoneos --show-sdk-path)/usr/include or /usr/include"), .framework = b.option(std.Build.LazyPath, "framework_path", "SDK framework dir, e.g. $(xcrun --sdk iphoneos --show-sdk-path)/System/Library/Frameworks"), .library = b.option(std.Build.LazyPath, "library_path", "SDK library dir, e.g. $(xcrun --sdk iphoneos --show-sdk-path)/usr/lib"), - }; + }); // Get the SO version. This is the same as the SDL version, but the major version is elided // since it's baked into the name. This mirrors the official build process. @@ -73,6 +81,7 @@ pub fn build(b: *std.Build) !void { .target = target, .optimize = optimize, .link_libc = true, + .sanitize_c = if (can_san) null else .off, }), .linkage = linkage, .version = sdl_so_version, @@ -103,6 +112,24 @@ pub fn build(b: *std.Build) !void { .flags = flags, }); + const main_lib = b.addLibrary(.{ + .name = "SDL3_main", + .root_module = b.createModule(.{ + .target = target, + .optimize = optimize, + .link_libc = true, + .sanitize_c = if (can_san) null else .off, + }), + .linkage = .static, + }); + main_lib.root_module.addIncludePath(upstream.path("include")); + if (main_callbacks) { + main_lib.root_module.addCMacro("SDL_MAIN_USE_CALLBACKS", "1"); + } + main_lib.root_module.addCSourceFile(.{ .file = b.path("src/sdl_main.c") }); + addSystemPathsToModule(b, main_lib.root_module, system_paths); + b.installArtifact(main_lib); + if (default_target_config) { const build_config_h = b.addConfigHeader(.{ .style = .{ .cmake = upstream.path("include/build_config/SDL_build_config.h.cmake") }, @@ -152,6 +179,7 @@ pub fn build(b: *std.Build) !void { translate_c.defineCMacro("USING_GENERATED_CONFIG_H", "1"); translate_c.addIncludePath(upstream.path("include")); translate_c.addIncludePath(upstream.path("src/video/khronos")); + addSystemPathsToTranslateC(b, translate_c, system_paths); const module = translate_c.addModule("sdl3"); module.linkLibrary(lib); @@ -206,3 +234,46 @@ pub fn addDepIncludePath( lib.root_module.addIncludePath(dep.path(sub_path)); } } + +/// Fill in any of `paths` from the SDK found with `xcrun`. Left unset outside Apple or if no SDK is found. +pub fn withAppleSdkFallback(b: *std.Build, target: std.Target, paths: SystemPaths) SystemPaths { + if (!target.os.tag.isDarwin()) return paths; + if (paths.include != null and paths.framework != null) return paths; + + const sdk = std.zig.system.darwin.getSdk(b.allocator, b.graph.io, &target) orelse return paths; + + return .{ + .include = paths.include orelse .{ .cwd_relative = b.pathJoin(&.{ sdk, "usr/include" }) }, + .framework = paths.framework orelse .{ .cwd_relative = b.pathJoin(&.{ sdk, "System/Library/Frameworks" }) }, + .library = paths.library orelse .{ .cwd_relative = b.pathJoin(&.{ sdk, "usr/lib" }) }, + }; +} + +fn addSystemPathsToModule(b: *std.Build, module: *std.Build.Module, paths: SystemPaths) void { + if (paths.include) |p| module.addSystemIncludePath(p); + if (paths.framework) |p| { + module.addSystemFrameworkPath(p); + module.addSystemFrameworkPath(p.dirname().path(b, "SubFrameworks")); + } + if (paths.library) |p| module.addLibraryPath(p); +} + +fn addSystemPathsToTranslateC(b: *std.Build, translate_c: *std.Build.Step.TranslateC, paths: SystemPaths) void { + if (paths.include) |p| translate_c.addSystemIncludePath(p); + if (paths.framework) |p| { + translate_c.addSystemFrameworkPath(p); + translate_c.addSystemFrameworkPath(p.dirname().path(b, "SubFrameworks")); + } +} + +pub fn addAppleSdkPathsToModule(b: *std.Build, target: std.Target, module: *std.Build.Module) void { + if (!target.os.tag.isDarwin()) return; + + const sdk = std.zig.system.darwin.getSdk(b.allocator, b.graph.io, &target) orelse + @panic("Couldn't detect Apple SDK"); + + module.addSystemIncludePath(.{ .cwd_relative = b.pathJoin(&.{ sdk, "usr/include" }) }); + module.addSystemFrameworkPath(.{ .cwd_relative = b.pathJoin(&.{ sdk, "System/Library/Frameworks" }) }); + module.addSystemFrameworkPath(.{ .cwd_relative = b.pathJoin(&.{ sdk, "System/Library/SubFrameworks" }) }); + module.addLibraryPath(.{ .cwd_relative = b.pathJoin(&.{ sdk, "usr/lib" }) }); +} diff --git a/src/sdl_main.c b/src/sdl_main.c new file mode 100644 index 000000000..35e5e659d --- /dev/null +++ b/src/sdl_main.c @@ -0,0 +1,3 @@ +#ifdef SDL_MAIN_USE_CALLBACKS +#include +#endif