Commit d73808f3ff

Andrew Kelley <andrew@ziglang.org>
2020-04-04 17:57:28
remove `zig BUILD_INFO` hack
Rather than stuffing configuration information into the Zig binary, the build script reads it from config.h. This solves a problem for package maintainers and improves the use case of deterministic builds. closes #3758
1 parent e89c426
Changed files (2)
src/main.cpp
@@ -260,18 +260,6 @@ static int main0(int argc, char **argv) {
     char *arg0 = argv[0];
     Error err;
 
-    if (argc == 2 && strcmp(argv[1], "BUILD_INFO") == 0) {
-        printf("%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
-                ZIG_CMAKE_BINARY_DIR,
-                ZIG_CXX_COMPILER,
-                ZIG_LLVM_CONFIG_EXE,
-                ZIG_LLD_INCLUDE_PATH,
-                ZIG_LLD_LIBRARIES,
-                ZIG_CLANG_LIBRARIES,
-                ZIG_DIA_GUIDS_LIB);
-        return 0;
-    }
-
     if (argc >= 2 && (strcmp(argv[1], "clang") == 0 ||
             strcmp(argv[1], "-cc1") == 0 || strcmp(argv[1], "-cc1as") == 0))
     {
build.zig
@@ -34,22 +34,7 @@ pub fn build(b: *Builder) !void {
 
     const test_step = b.step("test", "Run all the tests");
 
-    // find the stage0 build artifacts because we're going to re-use config.h and zig_cpp library
-    const build_info = try b.exec(&[_][]const u8{
-        b.zig_exe,
-        "BUILD_INFO",
-    });
-    var index: usize = 0;
-    var ctx = Context{
-        .cmake_binary_dir = nextValue(&index, build_info),
-        .cxx_compiler = nextValue(&index, build_info),
-        .llvm_config_exe = nextValue(&index, build_info),
-        .lld_include_dir = nextValue(&index, build_info),
-        .lld_libraries = nextValue(&index, build_info),
-        .clang_libraries = nextValue(&index, build_info),
-        .dia_guids_lib = nextValue(&index, build_info),
-        .llvm = undefined,
-    };
+    var ctx = try findAndParseConfigH(b);
     ctx.llvm = try findLLVM(b, ctx.llvm_config_exe);
 
     var test_stage2 = b.addTest("src-self-hosted/test.zig");
@@ -262,25 +247,6 @@ fn findLLVM(b: *Builder, llvm_config_exe: []const u8) !LibraryDep {
     return result;
 }
 
-fn nextValue(index: *usize, build_info: []const u8) []const u8 {
-    const start = index.*;
-    while (true) : (index.* += 1) {
-        switch (build_info[index.*]) {
-            '\n' => {
-                const result = build_info[start..index.*];
-                index.* += 1;
-                return result;
-            },
-            '\r' => {
-                const result = build_info[start..index.*];
-                index.* += 2;
-                return result;
-            },
-            else => continue,
-        }
-    }
-}
-
 fn configureStage2(b: *Builder, exe: var, ctx: Context) !void {
     exe.addIncludeDir("src");
     exe.addIncludeDir(ctx.cmake_binary_dir);
@@ -376,3 +342,79 @@ const Context = struct {
     dia_guids_lib: []const u8,
     llvm: LibraryDep,
 };
+
+fn findAndParseConfigH(b: *Builder) !Context {
+    var check_dir = fs.path.dirname(b.zig_exe).?;
+    const config_h_text = while (true) {
+        var dir = try fs.cwd().openDir(check_dir, .{});
+        defer dir.close();
+
+        const max_bytes = 1 * 1024 * 1024;
+        const config_h_text = dir.readFileAlloc(b.allocator, "config.h", max_bytes) catch |err| switch (err) {
+            error.FileNotFound => {
+                check_dir = fs.path.dirname(check_dir) orelse {
+                    std.debug.warn("Unable to find config.h file relative to Zig executable.\n", .{});
+                    std.debug.warn("`zig build` must be run using a Zig executable within the source tree.\n", .{});
+                    std.process.exit(1);
+                };
+                continue;
+            },
+            else => |e| return e,
+        };
+        break config_h_text;
+    } else unreachable; // TODO should not need `else unreachable`.
+
+    var ctx: Context = .{
+        .cmake_binary_dir = undefined,
+        .cxx_compiler = undefined,
+        .llvm_config_exe = undefined,
+        .lld_include_dir = undefined,
+        .lld_libraries = undefined,
+        .clang_libraries = undefined,
+        .dia_guids_lib = undefined,
+        .llvm = undefined,
+    };
+
+    const mappings = [_]struct { prefix: []const u8, field: []const u8 }{
+        .{
+            .prefix = "#define ZIG_CMAKE_BINARY_DIR ",
+            .field = "cmake_binary_dir",
+        },
+        .{
+            .prefix = "#define ZIG_CXX_COMPILER ",
+            .field = "cxx_compiler",
+        },
+        .{
+            .prefix = "#define ZIG_LLD_INCLUDE_PATH ",
+            .field = "lld_include_dir",
+        },
+        .{
+            .prefix = "#define ZIG_LLD_LIBRARIES ",
+            .field = "lld_libraries",
+        },
+        .{
+            .prefix = "#define ZIG_CLANG_LIBRARIES ",
+            .field = "clang_libraries",
+        },
+        .{
+            .prefix = "#define ZIG_LLVM_CONFIG_EXE ",
+            .field = "llvm_config_exe",
+        },
+        .{
+            .prefix = "#define ZIG_DIA_GUIDS_LIB ",
+            .field = "dia_guids_lib",
+        },
+    };
+
+    var lines_it = mem.tokenize(config_h_text, "\r\n");
+    while (lines_it.next()) |line| {
+        inline for (mappings) |mapping| {
+            if (mem.startsWith(u8, line, mapping.prefix)) {
+                var it = mem.separate(line, "\"");
+                _ = it.next().?; // skip the stuff before the quote
+                @field(ctx, mapping.field) = it.next().?; // the stuff inside the quote
+            }
+        }
+    }
+    return ctx;
+}