Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[build][Zig] Make more flags from src/config.h configurable #4407

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
126 changes: 75 additions & 51 deletions build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,12 @@ pub fn addRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.
}

fn setDesktopPlatform(raylib: *std.Build.Step.Compile, platform: PlatformBackend) void {
raylib.defineCMacro("PLATFORM_DESKTOP", null);
raylib.root_module.addCMacro("PLATFORM_DESKTOP", "1");

switch (platform) {
.glfw => raylib.defineCMacro("PLATFORM_DESKTOP_GLFW", null),
.rgfw => raylib.defineCMacro("PLATFORM_DESKTOP_RGFW", null),
.sdl => raylib.defineCMacro("PLATFORM_DESKTOP_SDL", null),
.glfw => raylib.root_module.addCMacro("PLATFORM_DESKTOP_GLFW", "1"),
.rgfw => raylib.root_module.addCMacro("PLATFORM_DESKTOP_RGFW", "1"),
.sdl => raylib.root_module.addCMacro("PLATFORM_DESKTOP_SDL", "1"),
else => {},
}
}
Expand Down Expand Up @@ -76,33 +76,48 @@ fn emSdkSetupStep(b: *std.Build, emsdk: *std.Build.Dependency) !?*std.Build.Step
}
}

/// A list of all flags from `src/config.h` that one may override
/// A list of all flags and their corresponding values from `src/config.h` that one may override
const config_h_flags = outer: {
// Set this value higher if compile errors happen as `src/config.h` gets larger
@setEvalBranchQuota(1 << 20);

const config_h = @embedFile("src/config.h");
var flags: [std.mem.count(u8, config_h, "\n") + 1][]const u8 = undefined;
var flags = [1][2][]const u8{.{ undefined, "1" }} ** (std.mem.count(u8, config_h, "\n") + 1);

const first_def = "#define CONFIG_H\n";
const first_line_idx = std.mem.indexOf(u8, config_h, first_def) orelse @compileError("Invalid `src/config.h`?");

var i = 0;
var lines = std.mem.tokenizeScalar(u8, config_h, '\n');
var lines = std.mem.tokenizeScalar(u8, config_h[first_line_idx + first_def.len ..], '\n');
while (lines.next()) |line| {
if (!std.mem.containsAtLeast(u8, line, 1, "SUPPORT")) continue;
if (std.mem.startsWith(u8, line, "//")) continue;
if (std.mem.startsWith(u8, line, "#if")) continue;
// Jump past `#if` lines until `#endif` is reached
if (std.mem.startsWith(u8, line, "#if")) {
// Count of `#if`s found without a delimiting `#endif`
var unpaired_if: u32 = 1;
while (unpaired_if != 0) {
const next_line = lines.next() orelse @compileError("src/config.h: `#endif` not found");
if (std.mem.startsWith(u8, next_line, "#if")) unpaired_if += 1;
if (std.mem.startsWith(u8, next_line, "#endif")) unpaired_if -= 1;
}
}

var flag = std.mem.trimLeft(u8, line, " \t"); // Trim whitespace
flag = flag["#define ".len - 1 ..]; // Remove #define
flag = std.mem.trimLeft(u8, flag, " \t"); // Trim whitespace
flag = flag[0 .. std.mem.indexOf(u8, flag, " ") orelse continue]; // Flag is only one word, so capture till space
flag = "-D" ++ flag; // Prepend with -D
// Ignore everything but `#define` lines
const prefix = "#define ";
if (!std.mem.startsWith(u8, line, prefix)) continue;

// Get space-separated strings
var strs = std.mem.tokenizeScalar(u8, line[prefix.len..], ' ');

flags[i][0] = strs.next() orelse @compileError("src/config.h: Flag not found: " ++ line);
if (strs.next()) |value| {
if (!std.mem.startsWith(u8, value, "//")) flags[i][1] = value;
}

flags[i] = flag;
i += 1;
}

// Uncomment this to check what flags normally get passed
//@compileLog(flags[0..i].*);
//for (flags[0..i]) |flag| @compileLog(std.fmt.comptimePrint("{s}={s}", .{ flag[0], flag[1] }));
break :outer flags[0..i].*;
};

Expand All @@ -116,9 +131,27 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.
try raylib_flags_arr.appendSlice(b.allocator, &[_][]const u8{
"-std=gnu99",
"-D_GNU_SOURCE",
"-DGL_SILENCE_DEPRECATION=199309L",
"-fno-sanitize=undefined", // https://github.com/raysan5/raylib/issues/3674
});

if (options.shared) {
try raylib_flags_arr.appendSlice(b.allocator, shared_flags);
}

const raylib = if (options.shared)
b.addSharedLibrary(.{
.name = "raylib",
.target = target,
.optimize = optimize,
})
else
b.addStaticLibrary(.{
.name = "raylib",
.target = target,
.optimize = optimize,
});
raylib.linkLibC();

if (options.config.len > 0) {
// Sets a flag indiciating the use of a custom `config.h`
try raylib_flags_arr.append(b.allocator, "-DEXTERNAL_CONFIG_FLAGS");
Expand All @@ -135,42 +168,32 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.

// Apply all relevant configs from `src/config.h` *except* the user-specified ones
//
// Note: This entire loop might become unnecessary depending on https://github.com/raysan5/raylib/issues/4411
//
// Note: Currently using a suboptimal `O(m*n)` time algorithm where:
// `m` corresponds roughly to the number of lines in `src/config.h`
// `n` corresponds to the number of user-specified flags
outer: for (config_h_flags) |flag| {
outer: for (config_h_flags) |flag_val| {
const flag = flag_val[0];
const value = flag_val[1];

// If a user already specified the flag, skip it
config_iter.reset();
sagehane marked this conversation as resolved.
Show resolved Hide resolved
while (config_iter.next()) |config_flag| {
while (config_iter.next()) |user_flag| {
if (!std.mem.startsWith(u8, user_flag, "-D")) continue;
const u_flag_stripped = user_flag["-D".len..];

// For a user-specified flag to match, it must share the same prefix and have the
// same length or be followed by an equals sign
if (!std.mem.startsWith(u8, config_flag, flag)) continue;
if (config_flag.len == flag.len or config_flag[flag.len] == '=') continue :outer;
if (!std.mem.startsWith(u8, u_flag_stripped, flag)) continue;
if (u_flag_stripped.len == flag.len or u_flag_stripped[flag.len] == '=') continue :outer;
}

// Otherwise, append default value from config.h to compile flags
try raylib_flags_arr.append(b.allocator, flag);
// Otherwise, apply the default values from config.h
raylib.root_module.addCMacro(flag, value);
}
}

if (options.shared) {
try raylib_flags_arr.appendSlice(b.allocator, shared_flags);
}

const raylib = if (options.shared)
b.addSharedLibrary(.{
.name = "raylib",
.target = target,
.optimize = optimize,
})
else
b.addStaticLibrary(.{
.name = "raylib",
.target = target,
.optimize = optimize,
});
raylib.linkLibC();

// No GLFW required on PLATFORM_DRM
if (options.platform != .drm) {
raylib.addIncludePath(b.path("src/external/glfw/include"));
Expand All @@ -196,7 +219,7 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.
}

if (options.opengl_version != .auto) {
raylib.defineCMacro(options.opengl_version.toCMacroStr(), null);
raylib.root_module.addCMacro(options.opengl_version.toCMacroStr(), "1");
}

switch (target.result.os.tag) {
Expand All @@ -213,7 +236,7 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.
try c_source_files.append("src/rglfw.c");

if (options.linux_display_backend == .X11 or options.linux_display_backend == .Both) {
raylib.defineCMacro("_GLFW_X11", null);
raylib.root_module.addCMacro("_GLFW_X11", "1");
raylib.linkSystemLibrary("GLX");
raylib.linkSystemLibrary("X11");
raylib.linkSystemLibrary("Xcursor");
Expand All @@ -233,7 +256,7 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.
, .{});
@panic("`wayland-scanner` not found");
};
raylib.defineCMacro("_GLFW_WAYLAND", null);
raylib.root_module.addCMacro("_GLFW_WAYLAND", "1");
raylib.linkSystemLibrary("EGL");
raylib.linkSystemLibrary("wayland-client");
raylib.linkSystemLibrary("xkbcommon");
Expand All @@ -252,16 +275,15 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.
} else {
if (options.opengl_version == .auto) {
raylib.linkSystemLibrary("GLESv2");
raylib.defineCMacro("GRAPHICS_API_OPENGL_ES2", null);
raylib.root_module.addCMacro("GRAPHICS_API_OPENGL_ES2", "1");
}

raylib.linkSystemLibrary("EGL");
raylib.linkSystemLibrary("gbm");
raylib.linkSystemLibrary2("libdrm", .{ .use_pkg_config = .force });

raylib.defineCMacro("PLATFORM_DRM", null);
raylib.defineCMacro("EGL_NO_X11", null);
raylib.defineCMacro("DEFAULT_BATCH_BUFFER_ELEMENT", "2048");
raylib.root_module.addCMacro("PLATFORM_DRM", "1");
raylib.root_module.addCMacro("EGL_NO_X11", "1");
}
},
.freebsd, .openbsd, .netbsd, .dragonfly => {
Expand Down Expand Up @@ -289,6 +311,8 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.

// On macos rglfw.c include Objective-C files.
try raylib_flags_arr.append(b.allocator, "-ObjC");
// Silence OpenGL deprecation warnings on macOS
try raylib_flags_arr.append(b.allocator, "-DGL_SILENCE_DEPRECATION=199309L");
raylib.root_module.addCSourceFile(.{
.file = b.path("src/rglfw.c"),
.flags = raylib_flags_arr.items,
Expand All @@ -312,9 +336,9 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.
raylib.addIncludePath(dep.path("upstream/emscripten/cache/sysroot/include"));
}

raylib.defineCMacro("PLATFORM_WEB", null);
raylib.root_module.addCMacro("PLATFORM_WEB", "1");
if (options.opengl_version == .auto) {
raylib.defineCMacro("GRAPHICS_API_OPENGL_ES2", null);
raylib.root_module.addCMacro("GRAPHICS_API_OPENGL_ES2", "1");
}
},
else => {
Expand Down
Loading