Commit 4fc2acdaa4

Cody Tapscott <topolarity@tapscott.me>
2022-07-16 02:25:38
build.zig: Emit warning if "config.h" cannot be found
We now warn the user if config.h could not be located. This also updates the search to stop early upon encountering a `.git` directory, so that we avoid recursing outside of the zig source if possible.
1 parent b3d0694
Changed files (1)
build.zig
@@ -238,7 +238,15 @@ pub fn build(b: *Builder) !void {
     exe_options.addOption([:0]const u8, "version", try b.allocator.dupeZ(u8, version));
 
     if (enable_llvm) {
-        const cmake_cfg = if (static_llvm) null else findAndParseConfigH(b, config_h_path_option);
+        const cmake_cfg = if (static_llvm) null else blk: {
+            if (findConfigH(b, config_h_path_option)) |config_h_path| {
+                const file_contents = fs.cwd().readFileAlloc(b.allocator, config_h_path, max_config_h_bytes) catch unreachable;
+                break :blk parseConfigH(b, file_contents);
+            } else {
+                std.log.warn("config.h could not be located automatically. Consider providing it explicitly via \"-Dconfig_h\"", .{});
+                break :blk null;
+            }
+        };
 
         if (is_stage1) {
             const softfloat = b.addStaticLibrary("softfloat", null);
@@ -689,31 +697,53 @@ const CMakeConfig = struct {
 
 const max_config_h_bytes = 1 * 1024 * 1024;
 
-fn findAndParseConfigH(b: *Builder, config_h_path_option: ?[]const u8) ?CMakeConfig {
-    const config_h_text: []const u8 = if (config_h_path_option) |config_h_path| blk: {
-        break :blk fs.cwd().readFileAlloc(b.allocator, config_h_path, max_config_h_bytes) catch unreachable;
-    } else blk: {
-        // TODO this should stop looking for config.h once it detects we hit the
-        // zig source root directory.
-        var check_dir = fs.path.dirname(b.zig_exe).?;
-        while (true) {
-            var dir = fs.cwd().openDir(check_dir, .{}) catch unreachable;
-            defer dir.close();
-
-            break :blk dir.readFileAlloc(b.allocator, "config.h", max_config_h_bytes) catch |err| switch (err) {
-                error.FileNotFound => {
-                    const new_check_dir = fs.path.dirname(check_dir);
-                    if (new_check_dir == null or mem.eql(u8, new_check_dir.?, check_dir)) {
-                        return null;
-                    }
-                    check_dir = new_check_dir.?;
-                    continue;
-                },
-                else => unreachable,
-            };
-        } else unreachable; // TODO should not need `else unreachable`.
-    };
+fn findConfigH(b: *Builder, config_h_path_option: ?[]const u8) ?[]const u8 {
+    if (config_h_path_option) |path| {
+        var config_h_or_err = fs.cwd().openFile(path, .{});
+        if (config_h_or_err) |*file| {
+            file.close();
+            return path;
+        } else |_| {
+            std.log.err("Could not open provided config.h: \"{s}\"", .{path});
+            std.os.exit(1);
+        }
+    }
+
+    var check_dir = fs.path.dirname(b.zig_exe).?;
+    while (true) {
+        var dir = fs.cwd().openDir(check_dir, .{}) catch unreachable;
+        defer dir.close();
+
+        // Check if config.h is present in dir
+        var config_h_or_err = dir.openFile("config.h", .{});
+        if (config_h_or_err) |*file| {
+            file.close();
+            return fs.path.join(
+                b.allocator,
+                &[_][]const u8{ check_dir, "config.h" },
+            ) catch unreachable;
+        } else |e| switch (e) {
+            error.FileNotFound => {},
+            else => unreachable,
+        }
+
+        // Check if we reached the source root by looking for .git, and bail if so
+        var git_dir_or_err = dir.openDir(".git", .{});
+        if (git_dir_or_err) |*git_dir| {
+            git_dir.close();
+            return null;
+        } else |_| {}
+
+        // Otherwise, continue search in the parent directory
+        const new_check_dir = fs.path.dirname(check_dir);
+        if (new_check_dir == null or mem.eql(u8, new_check_dir.?, check_dir)) {
+            return null;
+        }
+        check_dir = new_check_dir.?;
+    } else unreachable; // TODO should not need `else unreachable`.
+}
 
+fn parseConfigH(b: *Builder, config_h_text: []const u8) ?CMakeConfig {
     var ctx: CMakeConfig = .{
         .llvm_linkage = undefined,
         .cmake_binary_dir = undefined,