From 03cffdf357d79465fc745a1fc9328e161f20955f Mon Sep 17 00:00:00 2001 From: Evan Haas Date: Fri, 23 Feb 2024 16:32:47 -0800 Subject: [PATCH] Toolchain: improve include directory search for Linux --- src/aro/Compilation.zig | 26 ++++++--------------- src/aro/Driver.zig | 18 ++++++++++++--- src/aro/Toolchain.zig | 19 ++++++++++++++++ src/aro/toolchains/Linux.zig | 44 ++++++++++++++++++++++++++++++++++++ test/record_runner.zig | 2 +- test/runner.zig | 4 ++-- 6 files changed, 88 insertions(+), 25 deletions(-) diff --git a/src/aro/Compilation.zig b/src/aro/Compilation.zig index b3ac93d9..aa3c9af4 100644 --- a/src/aro/Compilation.zig +++ b/src/aro/Compilation.zig @@ -1057,9 +1057,8 @@ pub fn getCharSignedness(comp: *const Compilation) std.builtin.Signedness { return comp.langopts.char_signedness_override orelse comp.target.charSignedness(); } -pub fn defineSystemIncludes(comp: *Compilation, aro_dir: []const u8) !void { - var stack_fallback = std.heap.stackFallback(path_buf_stack_limit, comp.gpa); - const allocator = stack_fallback.get(); +/// Add built-in aro headers directory to system include paths +pub fn addBuiltinIncludeDir(comp: *Compilation, aro_dir: []const u8) !void { var search_path = aro_dir; while (std.fs.path.dirname(search_path)) |dirname| : (search_path = dirname) { var base_dir = std.fs.cwd().openDir(dirname, .{}) catch continue; @@ -1071,23 +1070,12 @@ pub fn defineSystemIncludes(comp: *Compilation, aro_dir: []const u8) !void { try comp.system_include_dirs.append(comp.gpa, path); break; } else return error.AroIncludeNotFound; +} - if (comp.target.os.tag == .linux) { - const triple_str = try comp.target.linuxTriple(allocator); - defer allocator.free(triple_str); - - const multiarch_path = try std.fs.path.join(allocator, &.{ "/usr/include", triple_str }); - defer allocator.free(multiarch_path); - - if (!std.meta.isError(std.fs.accessAbsolute(multiarch_path, .{}))) { - const duped = try comp.gpa.dupe(u8, multiarch_path); - errdefer comp.gpa.free(duped); - try comp.system_include_dirs.append(comp.gpa, duped); - } - } - const usr_include = try comp.gpa.dupe(u8, "/usr/include"); - errdefer comp.gpa.free(usr_include); - try comp.system_include_dirs.append(comp.gpa, usr_include); +pub fn addSystemIncludeDir(comp: *Compilation, path: []const u8) !void { + const duped = try comp.gpa.dupe(u8, path); + errdefer comp.gpa.free(duped); + try comp.system_include_dirs.append(comp.gpa, duped); } pub fn getSource(comp: *const Compilation, id: Source.Id) Source { diff --git a/src/aro/Driver.zig b/src/aro/Driver.zig index 6927d705..a38f23ac 100644 --- a/src/aro/Driver.zig +++ b/src/aro/Driver.zig @@ -44,6 +44,9 @@ verbose_pp: bool = false, verbose_ir: bool = false, verbose_linker_args: bool = false, color: ?bool = null, +nobuiltininc: bool = false, +nostdinc: bool = false, +nostdlibinc: bool = false, /// Full path to the aro executable aro_name: []const u8 = "", @@ -129,6 +132,10 @@ pub const usage = \\ -isystem Add directory to SYSTEM include search path \\ --emulate=[clang|gcc|msvc] \\ Select which C compiler to emulate (default clang) + \\ -nobuiltininc Do not search the compiler's builtin directory for include files + \\ -nostdinc, --no-standard-includes + \\ Do not search the standard system directories or compiler builtin directories for include files. + \\ -nostdlibinc Do not search the standard system directories for include files, but do search compiler builtin include directories \\ -o Write output to \\ -P, --no-line-commands Disable linemarker output in -E mode \\ -pedantic Warn on language extensions @@ -428,6 +435,12 @@ pub fn parseArgs( d.nodefaultlibs = true; } else if (mem.eql(u8, arg, "-nolibc")) { d.nolibc = true; + } else if (mem.eql(u8, arg, "-nobuiltininc")) { + d.nobuiltininc = true; + } else if (mem.eql(u8, arg, "-nostdinc") or mem.eql(u8, arg, "--no-standard-includes")) { + d.nostdinc = true; + } else if (mem.eql(u8, arg, "-nostdlibinc")) { + d.nostdlibinc = true; } else if (mem.eql(u8, arg, "-nostdlib")) { d.nostdlib = true; } else if (mem.eql(u8, arg, "-nostartfiles")) { @@ -569,7 +582,8 @@ pub fn main(d: *Driver, tc: *Toolchain, args: []const []const u8, comptime fast_ try d.comp.addDiagnostic(.{ .tag = .cli_unused_link_object, .extra = .{ .str = obj } }, &.{}); }; - d.comp.defineSystemIncludes(d.aro_name) catch |er| switch (er) { + try tc.discover(); + tc.defineSystemIncludes() catch |er| switch (er) { error.OutOfMemory => return error.OutOfMemory, error.AroIncludeNotFound => return d.fatal("unable to find Aro builtin headers", .{}), }; @@ -774,8 +788,6 @@ fn dumpLinkerArgs(items: []const []const u8) !void { /// The entry point of the Aro compiler. /// **MAY call `exit` if `fast_exit` is set.** pub fn invokeLinker(d: *Driver, tc: *Toolchain, comptime fast_exit: bool) !void { - try tc.discover(); - var argv = std.ArrayList([]const u8).init(d.comp.gpa); defer argv.deinit(); diff --git a/src/aro/Toolchain.zig b/src/aro/Toolchain.zig index 913432f9..fb2c11ad 100644 --- a/src/aro/Toolchain.zig +++ b/src/aro/Toolchain.zig @@ -487,3 +487,22 @@ pub fn addRuntimeLibs(tc: *const Toolchain, argv: *std.ArrayList([]const u8)) !v try argv.append("-ldl"); } } + +pub fn defineSystemIncludes(tc: *Toolchain) !void { + return switch (tc.inner) { + .uninitialized => unreachable, + .linux => |*linux| linux.defineSystemIncludes(tc), + .unknown => { + if (tc.driver.nostdinc) return; + + const comp = tc.driver.comp; + if (!tc.driver.nobuiltininc) { + try comp.addBuiltinIncludeDir(tc.driver.aro_name); + } + + if (!tc.driver.nostdlibinc) { + try comp.addSystemIncludeDir.append("/usr/include"); + } + }, + }; +} diff --git a/src/aro/toolchains/Linux.zig b/src/aro/toolchains/Linux.zig index 2dc2280e..b8f8fecb 100644 --- a/src/aro/toolchains/Linux.zig +++ b/src/aro/toolchains/Linux.zig @@ -373,6 +373,50 @@ fn getOSLibDir(target: std.Target) []const u8 { return "lib64"; } +pub fn defineSystemIncludes(self: *const Linux, tc: *const Toolchain) !void { + if (tc.driver.nostdinc) return; + + const comp = tc.driver.comp; + const target = tc.getTarget(); + + // musl prefers /usr/include before builtin includes, so musl targets will add builtins + // at the end of this function (unless disabled with nostdlibinc) + if (!tc.driver.nobuiltininc and (!target.isMusl() or tc.driver.nostdlibinc)) { + try comp.addBuiltinIncludeDir(tc.driver.aro_name); + } + + if (tc.driver.nostdlibinc) return; + + const sysroot = tc.getSysroot(); + const local_include = try std.fmt.allocPrint(comp.gpa, "{s}{s}", .{ sysroot, "/usr/local/include" }); + defer comp.gpa.free(local_include); + try comp.addSystemIncludeDir(local_include); + + if (self.gcc_detector.is_valid) { + const gcc_include_path = try std.fs.path.join(comp.gpa, &.{ self.gcc_detector.parent_lib_path, "..", self.gcc_detector.gcc_triple, "include" }); + defer comp.gpa.free(gcc_include_path); + try comp.addSystemIncludeDir(gcc_include_path); + } + + if (getMultiarchTriple(target)) |triple| { + const joined = try std.fs.path.join(comp.gpa, &.{ sysroot, "usr", "include", triple }); + errdefer comp.gpa.free(joined); + if (tc.filesystem.exists(joined)) { + try comp.addSystemIncludeDir(joined); + } + } + + if (target.os.tag == .rtems) return; + + try comp.addSystemIncludeDir("/include"); + try comp.addSystemIncludeDir("/usr/include"); + + std.debug.assert(!tc.driver.nostdlibinc); + if (!tc.driver.nobuiltininc and target.isMusl()) { + try comp.addBuiltinIncludeDir(tc.driver.aro_name); + } +} + test Linux { if (@import("builtin").os.tag == .windows) return error.SkipZigTest; diff --git a/test/record_runner.zig b/test/record_runner.zig index e1f6cfed..6c23739e 100644 --- a/test/record_runner.zig +++ b/test/record_runner.zig @@ -221,7 +221,7 @@ fn singleRun(alloc: std.mem.Allocator, test_dir: []const u8, test_case: TestCase defer comp.deinit(); try comp.addDefaultPragmaHandlers(); - try comp.defineSystemIncludes(test_dir); + try comp.addBuiltinIncludeDir(test_dir); const target = setTarget(&comp, test_case.target) catch |err| switch (err) { error.UnknownCpuModel => unreachable, diff --git a/test/runner.zig b/test/runner.zig index fe235b47..7bd1147d 100644 --- a/test/runner.zig +++ b/test/runner.zig @@ -58,7 +58,7 @@ fn testOne(allocator: std.mem.Allocator, path: []const u8, test_dir: []const u8) defer comp.deinit(); try comp.addDefaultPragmaHandlers(); - try comp.defineSystemIncludes(test_dir); + try comp.addBuiltinIncludeDir(test_dir); const file = try comp.addSourceFromPath(path); var macro_buf = std.ArrayList(u8).init(comp.gpa); @@ -173,7 +173,7 @@ pub fn main() !void { try initial_comp.include_dirs.append(gpa, cases_next_include_dir); try initial_comp.addDefaultPragmaHandlers(); - try initial_comp.defineSystemIncludes(test_dir); + try initial_comp.addBuiltinIncludeDir(test_dir); // apparently we can't use setAstCwd without libc on windows yet const win = @import("builtin").os.tag == .windows;