Skip to content

Commit ce9259c

Browse files
authored
build.zig: Fix various issues around -Dconfig (#4398)
* build.zig: Fix various issues around `-Dconfig` * build.zig: Parse all relevant flags from `src/config.h` at comptime
1 parent 23354e1 commit ce9259c

File tree

1 file changed

+78
-42
lines changed

1 file changed

+78
-42
lines changed

src/build.zig

+78-42
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,36 @@ fn srcDir(b: *std.Build) []const u8 {
7272
return std.fs.path.dirname(src_file) orelse ".";
7373
}
7474

75+
/// A list of all flags from `src/config.h` that one may override
76+
const config_h_flags = outer: {
77+
// Set this value higher if compile errors happen as `src/config.h` gets larger
78+
@setEvalBranchQuota(1 << 20);
79+
80+
const config_h = @embedFile("config.h");
81+
var flags: [std.mem.count(u8, config_h, "\n") + 1][]const u8 = undefined;
82+
83+
var i = 0;
84+
var lines = std.mem.tokenizeScalar(u8, config_h, '\n');
85+
while (lines.next()) |line| {
86+
if (!std.mem.containsAtLeast(u8, line, 1, "SUPPORT")) continue;
87+
if (std.mem.startsWith(u8, line, "//")) continue;
88+
if (std.mem.startsWith(u8, line, "#if")) continue;
89+
90+
var flag = std.mem.trimLeft(u8, line, " \t"); // Trim whitespace
91+
flag = flag["#define ".len - 1 ..]; // Remove #define
92+
flag = std.mem.trimLeft(u8, flag, " \t"); // Trim whitespace
93+
flag = flag[0 .. std.mem.indexOf(u8, flag, " ") orelse continue]; // Flag is only one word, so capture till space
94+
flag = "-D" ++ flag; // Prepend with -D
95+
96+
flags[i] = flag;
97+
i += 1;
98+
}
99+
100+
// Uncomment this to check what flags normally get passed
101+
//@compileLog(flags[0..i].*);
102+
break :outer flags[0..i].*;
103+
};
104+
75105
fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode, options: Options) !*std.Build.Step.Compile {
76106
raylib_flags_arr.clearRetainingCapacity();
77107

@@ -86,33 +116,36 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.
86116
"-fno-sanitize=undefined", // https://github.com/raysan5/raylib/issues/3674
87117
});
88118
if (options.config.len > 0) {
89-
const file = b.pathJoin(&.{ srcDir(b), "config.h" });
90-
const content = try std.fs.cwd().readFileAlloc(b.allocator, file, std.math.maxInt(usize));
91-
defer b.allocator.free(content);
92-
93-
var lines = std.mem.splitScalar(u8, content, '\n');
94-
while (lines.next()) |line| {
95-
if (!std.mem.containsAtLeast(u8, line, 1, "SUPPORT")) continue;
96-
if (std.mem.startsWith(u8, line, "//")) continue;
97-
if (std.mem.startsWith(u8, line, "#if")) continue;
98-
99-
var flag = std.mem.trimLeft(u8, line, " \t"); // Trim whitespace
100-
flag = flag["#define ".len - 1 ..]; // Remove #define
101-
flag = std.mem.trimLeft(u8, flag, " \t"); // Trim whitespace
102-
flag = flag[0 .. std.mem.indexOf(u8, flag, " ") orelse continue]; // Flag is only one word, so capture till space
103-
flag = try std.fmt.allocPrint(b.allocator, "-D{s}", .{flag}); // Prepend with -D
104-
105-
// If user specifies the flag skip it
106-
if (std.mem.containsAtLeast(u8, options.config, 1, flag)) continue;
107-
108-
// Append default value from config.h to compile flags
109-
try raylib_flags_arr.append(b.allocator, flag);
110-
}
119+
// Sets a flag indiciating the use of a custom `config.h`
120+
try raylib_flags_arr.append(b.allocator, "-DEXTERNAL_CONFIG_FLAGS");
111121

112-
// Append config flags supplied by user to compile flags
113-
try raylib_flags_arr.append(b.allocator, options.config);
122+
// Splits a space-separated list of config flags into multiple flags
123+
//
124+
// Note: This means certain flags like `-x c++` won't be processed properly.
125+
// `-xc++` or similar should be used when possible
126+
var config_iter = std.mem.tokenizeScalar(u8, options.config, ' ');
127+
128+
// Apply config flags supplied by the user
129+
while (config_iter.next()) |config_flag|
130+
try raylib_flags_arr.append(b.allocator, config_flag);
131+
132+
// Apply all relevant configs from `src/config.h` *except* the user-specified ones
133+
//
134+
// Note: Currently using a suboptimal `O(m*n)` time algorithm where:
135+
// `m` corresponds roughly to the number of lines in `src/config.h`
136+
// `n` corresponds to the number of user-specified flags
137+
outer: for (config_h_flags) |flag| {
138+
// If a user already specified the flag, skip it
139+
while (config_iter.next()) |config_flag| {
140+
// For a user-specified flag to match, it must share the same prefix and have the
141+
// same length or be followed by an equals sign
142+
if (!std.mem.startsWith(u8, config_flag, flag)) continue;
143+
if (config_flag.len == flag.len or config_flag[flag.len] == '=') continue :outer;
144+
}
114145

115-
try raylib_flags_arr.append(b.allocator, "-DEXTERNAL_CONFIG_FLAGS");
146+
// Otherwise, append default value from config.h to compile flags
147+
try raylib_flags_arr.append(b.allocator, flag);
148+
}
116149
}
117150

118151
if (options.shared) {
@@ -319,10 +352,28 @@ pub const Options = struct {
319352
shared: bool = false,
320353
linux_display_backend: LinuxDisplayBackend = .Both,
321354
opengl_version: OpenglVersion = .auto,
322-
/// config should be a list of cflags, eg, "-DSUPPORT_CUSTOM_FRAME_CONTROL"
355+
/// config should be a list of space-separated cflags, eg, "-DSUPPORT_CUSTOM_FRAME_CONTROL"
323356
config: []const u8 = &.{},
324357

325358
raygui_dependency_name: []const u8 = "raygui",
359+
360+
const defaults = Options{};
361+
362+
fn getOptions(b: *std.Build) Options {
363+
return .{
364+
.platform = b.option(PlatformBackend, "platform", "Choose the platform backedn for desktop target") orelse defaults.platform,
365+
.raudio = b.option(bool, "raudio", "Compile with audio support") orelse defaults.raudio,
366+
.raygui = b.option(bool, "raygui", "Compile with raygui support") orelse defaults.raygui,
367+
.rmodels = b.option(bool, "rmodels", "Compile with models support") orelse defaults.rmodels,
368+
.rtext = b.option(bool, "rtext", "Compile with text support") orelse defaults.rtext,
369+
.rtextures = b.option(bool, "rtextures", "Compile with textures support") orelse defaults.rtextures,
370+
.rshapes = b.option(bool, "rshapes", "Compile with shapes support") orelse defaults.rshapes,
371+
.shared = b.option(bool, "shared", "Compile as shared library") orelse defaults.shared,
372+
.linux_display_backend = b.option(LinuxDisplayBackend, "linux_display_backend", "Linux display backend to use") orelse defaults.linux_display_backend,
373+
.opengl_version = b.option(OpenglVersion, "opengl_version", "OpenGL version to use") orelse defaults.opengl_version,
374+
.config = b.option([]const u8, "config", "Compile with custom define macros overriding config.h") orelse &.{},
375+
};
376+
}
326377
};
327378

328379
pub const OpenglVersion = enum {
@@ -371,22 +422,7 @@ pub fn build(b: *std.Build) !void {
371422
// set a preferred release mode, allowing the user to decide how to optimize.
372423
const optimize = b.standardOptimizeOption(.{});
373424

374-
const defaults = Options{};
375-
const options = Options{
376-
.platform = b.option(PlatformBackend, "platform", "Choose the platform backedn for desktop target") orelse defaults.platform,
377-
.raudio = b.option(bool, "raudio", "Compile with audio support") orelse defaults.raudio,
378-
.raygui = b.option(bool, "raygui", "Compile with raygui support") orelse defaults.raygui,
379-
.rmodels = b.option(bool, "rmodels", "Compile with models support") orelse defaults.rmodels,
380-
.rtext = b.option(bool, "rtext", "Compile with text support") orelse defaults.rtext,
381-
.rtextures = b.option(bool, "rtextures", "Compile with textures support") orelse defaults.rtextures,
382-
.rshapes = b.option(bool, "rshapes", "Compile with shapes support") orelse defaults.rshapes,
383-
.shared = b.option(bool, "shared", "Compile as shared library") orelse defaults.shared,
384-
.linux_display_backend = b.option(LinuxDisplayBackend, "linux_display_backend", "Linux display backend to use") orelse defaults.linux_display_backend,
385-
.opengl_version = b.option(OpenglVersion, "opengl_version", "OpenGL version to use") orelse defaults.opengl_version,
386-
.config = b.option([]const u8, "config", "Compile with custom define macros overriding config.h") orelse &.{},
387-
};
388-
389-
const lib = try compileRaylib(b, target, optimize, options);
425+
const lib = try compileRaylib(b, target, optimize, Options.getOptions(b));
390426

391427
lib.installHeader(b.path(b.pathJoin(&.{ srcDir(b), "raylib.h" })), "raylib.h");
392428
lib.installHeader(b.path(b.pathJoin(&.{ srcDir(b), "raymath.h" })), "raymath.h");

0 commit comments

Comments
 (0)