Commit f2ca2ace09

Andrew Kelley <andrew@ziglang.org>
2019-03-11 20:22:05
zig build: do a better job of detecting system paths
See #2041
1 parent a909efa
Changed files (2)
std
test
standalone
use_alias
std/build.zig
@@ -23,9 +23,9 @@ pub const Builder = struct {
     have_uninstall_step: bool,
     have_install_step: bool,
     allocator: *Allocator,
-    lib_paths: ArrayList([]const u8),
-    include_paths: ArrayList([]const u8),
-    rpaths: ArrayList([]const u8),
+    native_system_lib_paths: ArrayList([]const u8),
+    native_system_include_dirs: ArrayList([]const u8),
+    native_system_rpaths: ArrayList([]const u8),
     user_input_options: UserInputOptionsMap,
     available_options_map: AvailableOptionsMap,
     available_options_list: ArrayList(AvailableOption),
@@ -108,9 +108,9 @@ pub const Builder = struct {
             .verbose_cimport = false,
             .invalid_user_input = false,
             .allocator = allocator,
-            .lib_paths = ArrayList([]const u8).init(allocator),
-            .include_paths = ArrayList([]const u8).init(allocator),
-            .rpaths = ArrayList([]const u8).init(allocator),
+            .native_system_lib_paths = ArrayList([]const u8).init(allocator),
+            .native_system_include_dirs = ArrayList([]const u8).init(allocator),
+            .native_system_rpaths = ArrayList([]const u8).init(allocator),
             .user_input_options = UserInputOptionsMap.init(allocator),
             .available_options_map = AvailableOptionsMap.init(allocator),
             .available_options_list = ArrayList(AvailableOption).init(allocator),
@@ -134,15 +134,15 @@ pub const Builder = struct {
             .have_install_step = false,
             .release_mode = null,
         };
-        self.processNixOSEnvVars();
+        self.detectNativeSystemPaths();
         self.default_step = self.step("default", "Build the project");
         return self;
     }
 
     pub fn deinit(self: *Builder) void {
-        self.lib_paths.deinit();
-        self.include_paths.deinit();
-        self.rpaths.deinit();
+        self.native_system_lib_paths.deinit();
+        self.native_system_include_dirs.deinit();
+        self.native_system_rpaths.deinit();
         self.env_map.deinit();
         self.top_level_steps.deinit();
     }
@@ -230,16 +230,16 @@ pub const Builder = struct {
         };
     }
 
-    pub fn addCIncludePath(self: *Builder, path: []const u8) void {
-        self.include_paths.append(path) catch unreachable;
+    pub fn addNativeSystemIncludeDir(self: *Builder, path: []const u8) void {
+        self.native_system_include_dirs.append(path) catch unreachable;
     }
 
-    pub fn addRPath(self: *Builder, path: []const u8) void {
-        self.rpaths.append(path) catch unreachable;
+    pub fn addNativeSystemRPath(self: *Builder, path: []const u8) void {
+        self.native_system_rpaths.append(path) catch unreachable;
     }
 
-    pub fn addLibPath(self: *Builder, path: []const u8) void {
-        self.lib_paths.append(path) catch unreachable;
+    pub fn addNativeSystemLibPath(self: *Builder, path: []const u8) void {
+        self.native_system_lib_paths.append(path) catch unreachable;
     }
 
     pub fn make(self: *Builder, step_names: []const []const u8) !void {
@@ -323,8 +323,10 @@ pub const Builder = struct {
         return error.InvalidStepName;
     }
 
-    fn processNixOSEnvVars(self: *Builder) void {
+    fn detectNativeSystemPaths(self: *Builder) void {
+        var is_nixos = false;
         if (os.getEnvVarOwned(self.allocator, "NIX_CFLAGS_COMPILE")) |nix_cflags_compile| {
+            is_nixos = true;
             var it = mem.tokenize(nix_cflags_compile, " ");
             while (true) {
                 const word = it.next() orelse break;
@@ -333,7 +335,7 @@ pub const Builder = struct {
                         warn("Expected argument after -isystem in NIX_CFLAGS_COMPILE\n");
                         break;
                     };
-                    self.addCIncludePath(include_path);
+                    self.addNativeSystemIncludeDir(include_path);
                 } else {
                     warn("Unrecognized C flag from NIX_CFLAGS_COMPILE: {}\n", word);
                     break;
@@ -343,6 +345,7 @@ pub const Builder = struct {
             assert(err == error.EnvironmentVariableNotFound);
         }
         if (os.getEnvVarOwned(self.allocator, "NIX_LDFLAGS")) |nix_ldflags| {
+            is_nixos = true;
             var it = mem.tokenize(nix_ldflags, " ");
             while (true) {
                 const word = it.next() orelse break;
@@ -351,10 +354,10 @@ pub const Builder = struct {
                         warn("Expected argument after -rpath in NIX_LDFLAGS\n");
                         break;
                     };
-                    self.addRPath(rpath);
+                    self.addNativeSystemRPath(rpath);
                 } else if (word.len > 2 and word[0] == '-' and word[1] == 'L') {
                     const lib_path = word[2..];
-                    self.addLibPath(lib_path);
+                    self.addNativeSystemLibPath(lib_path);
                 } else {
                     warn("Unrecognized C flag from NIX_LDFLAGS: {}\n", word);
                     break;
@@ -363,6 +366,26 @@ pub const Builder = struct {
         } else |err| {
             assert(err == error.EnvironmentVariableNotFound);
         }
+        if (is_nixos) return;
+        switch (builtin.os) {
+            builtin.Os.windows => {},
+            else => {
+                const triple = (CrossTarget{
+                    .arch = builtin.arch,
+                    .os = builtin.os,
+                    .abi = builtin.abi,
+                }).linuxTriple(self.allocator);
+
+                self.addNativeSystemIncludeDir("/usr/local/include");
+                self.addNativeSystemLibPath("/usr/local/lib");
+
+                self.addNativeSystemIncludeDir(self.fmt("/usr/include/{}", triple));
+                self.addNativeSystemLibPath(self.fmt("/usr/lib/{}", triple));
+
+                self.addNativeSystemIncludeDir("/usr/include");
+                self.addNativeSystemLibPath("/usr/lib");
+            },
+        }
     }
 
     pub fn option(self: *Builder, comptime T: type, name: []const u8, description: []const u8) ?T {
@@ -766,6 +789,27 @@ const CrossTarget = struct {
     arch: builtin.Arch,
     os: builtin.Os,
     abi: builtin.Abi,
+
+    pub fn zigTriple(cross_target: CrossTarget, allocator: *Allocator) []u8 {
+        return std.fmt.allocPrint(
+            allocator,
+            "{}{}-{}-{}",
+            @tagName(cross_target.arch),
+            Target.archSubArchName(cross_target.arch),
+            @tagName(cross_target.os),
+            @tagName(cross_target.abi),
+        ) catch unreachable;
+    }
+
+    pub fn linuxTriple(cross_target: CrossTarget, allocator: *Allocator) []u8 {
+        return std.fmt.allocPrint(
+            allocator,
+            "{}-{}-{}",
+            @tagName(cross_target.arch),
+            @tagName(cross_target.os),
+            @tagName(cross_target.abi),
+        ) catch unreachable;
+    }
 };
 
 pub const Target = union(enum) {
@@ -860,6 +904,15 @@ const CSourceFile = struct {
     args: []const []const u8,
 };
 
+fn isLibCLibrary(name: []const u8) bool {
+    const libc_libraries = [][]const u8{ "c", "m", "dl", "rt", "pthread" };
+    for (libc_libraries) |libc_lib_name| {
+        if (mem.eql(u8, name, libc_lib_name))
+            return true;
+    }
+    return false;
+}
+
 pub const LibExeObjStep = struct {
     step: Step,
     builder: *Builder,
@@ -898,6 +951,7 @@ pub const LibExeObjStep = struct {
     link_objects: ArrayList(LinkObject),
     include_dirs: ArrayList(IncludeDir),
     output_dir: ?[]const u8,
+    need_system_paths: bool,
 
     const LinkObject = union(enum) {
         StaticPath: []const u8,
@@ -985,6 +1039,7 @@ pub const LibExeObjStep = struct {
             .filter = null,
             .disable_gen_h = false,
             .output_dir = null,
+            .need_system_paths = false,
         };
         self.computeOutFileNames();
         return self;
@@ -1097,6 +1152,9 @@ pub const LibExeObjStep = struct {
 
     pub fn linkSystemLibrary(self: *LibExeObjStep, name: []const u8) void {
         self.link_objects.append(LinkObject{ .SystemLib = self.builder.dupe(name) }) catch unreachable;
+        if (!isLibCLibrary(name)) {
+            self.need_system_paths = true;
+        }
     }
 
     pub fn setNamePrefix(self: *LibExeObjStep, text: []const u8) void {
@@ -1372,16 +1430,8 @@ pub const LibExeObjStep = struct {
         switch (self.target) {
             Target.Native => {},
             Target.Cross => |cross_target| {
-                const triple = builder.fmt(
-                    "{}{}-{}-{}",
-                    @tagName(cross_target.arch),
-                    Target.archSubArchName(cross_target.arch),
-                    @tagName(cross_target.os),
-                    @tagName(cross_target.abi),
-                );
-
                 try zig_args.append("-target");
-                try zig_args.append(triple);
+                try zig_args.append(cross_target.zigTriple(builder.allocator));
             },
         }
 
@@ -1421,24 +1471,26 @@ pub const LibExeObjStep = struct {
             }
         }
 
-        for (builder.include_paths.toSliceConst()) |include_path| {
-            zig_args.append("-isystem") catch unreachable;
-            zig_args.append(builder.pathFromRoot(include_path)) catch unreachable;
-        }
-
-        for (builder.rpaths.toSliceConst()) |rpath| {
-            zig_args.append("-rpath") catch unreachable;
-            zig_args.append(rpath) catch unreachable;
-        }
-
         for (self.lib_paths.toSliceConst()) |lib_path| {
             zig_args.append("--library-path") catch unreachable;
             zig_args.append(lib_path) catch unreachable;
         }
 
-        for (builder.lib_paths.toSliceConst()) |lib_path| {
-            zig_args.append("--library-path") catch unreachable;
-            zig_args.append(lib_path) catch unreachable;
+        if (self.need_system_paths and self.target == Target.Native) {
+            for (builder.native_system_include_dirs.toSliceConst()) |include_path| {
+                zig_args.append("-isystem") catch unreachable;
+                zig_args.append(builder.pathFromRoot(include_path)) catch unreachable;
+            }
+
+            for (builder.native_system_rpaths.toSliceConst()) |rpath| {
+                zig_args.append("-rpath") catch unreachable;
+                zig_args.append(rpath) catch unreachable;
+            }
+
+            for (builder.native_system_lib_paths.toSliceConst()) |lib_path| {
+                zig_args.append("--library-path") catch unreachable;
+                zig_args.append(lib_path) catch unreachable;
+            }
         }
 
         if (self.target.isDarwin()) {
test/standalone/use_alias/build.zig
@@ -1,10 +1,9 @@
 const Builder = @import("std").build.Builder;
 
 pub fn build(b: *Builder) void {
-    b.addCIncludePath(".");
-
     const main = b.addTest("main.zig");
     main.setBuildMode(b.standardReleaseOptions());
+    main.addIncludeDir(".");
 
     const test_step = b.step("test", "Test it");
     test_step.dependOn(&main.step);