Skip to content

Commit

Permalink
Linux toolchain: Add basic test for linker args
Browse files Browse the repository at this point in the history
  • Loading branch information
ehaas committed Aug 17, 2023
1 parent 7fa8788 commit 14602f5
Show file tree
Hide file tree
Showing 4 changed files with 138 additions and 17 deletions.
1 change: 1 addition & 0 deletions build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ pub fn build(b: *Build) !void {

var unit_tests = b.addTest(.{ .root_source_file = .{ .path = "src/main.zig" } });
unit_tests.addModule("zig", zig_module);
unit_tests.addOptions("system_defaults", system_defaults);
const run_test = b.addRunArtifact(unit_tests);
tests_step.dependOn(&run_test.step);

Expand Down
54 changes: 37 additions & 17 deletions src/driver/Filesystem.zig
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,42 @@ const builtin = @import("builtin");
const system_defaults = @import("system_defaults");
const is_windows = builtin.os.tag == .windows;

fn findProgramByNameFake(allocator: std.mem.Allocator, name: []const u8, path: ?[]const u8, buf: []u8) ?[]const u8 {
_ = path;
_ = buf;
_ = name;
_ = allocator;
@panic("TODO");
fn findProgramByNameFake(entries: []const Filesystem.Entry, name: []const u8, path: ?[]const u8, buf: []u8) ?[]const u8 {
@setCold(true);
if (mem.indexOfScalar(u8, name, '/') != null) {
@memcpy(buf[0..name.len], name);
return buf[0..name.len];
}
const path_env = path orelse return null;
var fib = std.heap.FixedBufferAllocator.init(buf);

var it = mem.tokenizeScalar(u8, path_env, system_defaults.path_sep);
while (it.next()) |path_dir| {
defer fib.reset();
const full_path = std.fs.path.join(fib.allocator(), &.{ path_dir, name }) catch continue;
if (canExecuteFake(entries, full_path)) return full_path;
}

return null;
}

fn canExecuteFake(paths: []const []const u8, path: []const u8) bool {
_ = path;
_ = paths;
fn canExecuteFake(entries: []const Filesystem.Entry, path: []const u8) bool {
@setCold(true);
@panic("TODO");
for (entries) |entry| {
if (mem.eql(u8, entry.path, path)) {
return entry.executable;
}
}
return false;
}

fn existsFake(paths: []const []const u8, path: []const u8) bool {
fn existsFake(entries: []const Filesystem.Entry, path: []const u8) bool {
@setCold(true);
var buf: [std.fs.MAX_PATH_BYTES]u8 = undefined;
var fib = std.heap.FixedBufferAllocator.init(&buf);
const resolved = std.fs.path.resolvePosix(fib.allocator(), &.{path}) catch return false;
for (paths) |fakepath| {
if (mem.eql(u8, fakepath, resolved)) return true;
for (entries) |entry| {
if (mem.eql(u8, entry.path, resolved)) return true;
}
return false;
}
Expand Down Expand Up @@ -71,7 +86,12 @@ fn findProgramByNamePosix(name: []const u8, path: ?[]const u8, buf: []u8) ?[]con

pub const Filesystem = union(enum) {
real: void,
fake: []const []const u8,
fake: []const Entry,

const Entry = struct {
path: []const u8,
executable: bool = false,
};

pub fn exists(fs: Filesystem, path: []const u8) bool {
switch (fs) {
Expand All @@ -93,7 +113,7 @@ pub const Filesystem = union(enum) {
pub fn canExecute(fs: Filesystem, path: []const u8) bool {
return switch (fs) {
.real => if (is_windows) canExecuteWindows(path) else canExecutePosix(path),
.fake => |paths| canExecuteFake(paths, path),
.fake => |entries| canExecuteFake(entries, path),
};
}

Expand All @@ -104,14 +124,14 @@ pub const Filesystem = union(enum) {
std.debug.assert(name.len > 0);
return switch (fs) {
.real => if (is_windows) findProgramByNameWindows(allocator, name, path, buf) else findProgramByNamePosix(name, path, buf),
.fake => findProgramByNameFake(allocator, name, path, buf),
.fake => |entries| findProgramByNameFake(entries, name, path, buf),
};
}
};

test "Fake filesystem" {
const fs: Filesystem = .{ .fake = &.{
"/usr/bin",
.{ .path = "/usr/bin" },
} };
try std.testing.expect(fs.exists("/usr/bin"));
try std.testing.expect(fs.exists("/usr/bin/foo/.."));
Expand Down
1 change: 1 addition & 0 deletions src/main.zig
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ test {
_ = @import("Source.zig");
_ = @import("Tokenizer.zig");
_ = @import("driver/GCCVersion.zig");
_ = @import("toolchains/Linux.zig");
_ = @import("Tree.zig");
_ = @import("Type.zig");
_ = @import("target.zig");
Expand Down
99 changes: 99 additions & 0 deletions src/toolchains/Linux.zig
Original file line number Diff line number Diff line change
Expand Up @@ -375,3 +375,102 @@ fn getOSLibDir(target: std.Target) []const u8 {
}
return "lib64";
}

test Linux {
var arena_instance = std.heap.ArenaAllocator.init(std.testing.allocator);
defer arena_instance.deinit();
const arena = arena_instance.allocator();

var comp = Compilation.init(std.testing.allocator);
defer comp.deinit();
comp.environment = .{
.path = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
};

const raw_triple = "x86_64-linux-gnu";
const cross = std.zig.CrossTarget.parse(.{ .arch_os_abi = raw_triple }) catch unreachable;
comp.target = cross.toTarget(); // TODO deprecated
comp.langopts.setEmulatedCompiler(.gcc);

var driver: Driver = .{ .comp = &comp };
defer driver.deinit();
driver.raw_target_triple = raw_triple;

const link_obj = try driver.comp.gpa.dupe(u8, "/tmp/foo.o");
try driver.link_objects.append(driver.comp.gpa, link_obj);
driver.temp_file_count += 1;

var toolchain: Toolchain = .{ .driver = &driver, .arena = arena, .filesystem = .{ .fake = &.{
.{ .path = "/tmp" },
.{ .path = "/usr" },
.{ .path = "/usr/lib64" },
.{ .path = "/usr/bin" },
.{ .path = "/usr/bin/ld", .executable = true },
.{ .path = "/lib" },
.{ .path = "/lib/x86_64-linux-gnu" },
.{ .path = "/lib/x86_64-linux-gnu/crt1.o" },
.{ .path = "/lib/x86_64-linux-gnu/crti.o" },
.{ .path = "/lib/x86_64-linux-gnu/crtn.o" },
.{ .path = "/lib64" },
.{ .path = "/usr/lib" },
.{ .path = "/usr/lib/gcc" },
.{ .path = "/usr/lib/gcc/x86_64-linux-gnu" },
.{ .path = "/usr/lib/gcc/x86_64-linux-gnu/9" },
.{ .path = "/usr/lib/gcc/x86_64-linux-gnu/9/crtbegin.o" },
.{ .path = "/usr/lib/gcc/x86_64-linux-gnu/9/crtend.o" },
.{ .path = "/usr/lib/x86_64-linux-gnu" },
} } };
defer toolchain.deinit();

try toolchain.discover();

var argv = std.ArrayList([]const u8).init(driver.comp.gpa);
defer argv.deinit();

var linker_path_buf: [std.fs.MAX_PATH_BYTES]u8 = undefined;
const linker_path = try toolchain.getLinkerPath(&linker_path_buf);
try argv.append(linker_path);

try toolchain.buildLinkerArgs(&argv);

const expected = [_][]const u8{
"/usr/bin/ld",
"-z",
"relro",
"--hash-style=gnu",
"--eh-frame-hdr",
"-m",
"elf_x86_64",
"-dynamic-linker",
"/lib64/ld-linux-x86-64.so.2",
"-o",
"a.out",
"/lib/x86_64-linux-gnu/crt1.o",
"/lib/x86_64-linux-gnu/crti.o",
"/usr/lib/gcc/x86_64-linux-gnu/9/crtbegin.o",
"-L/usr/lib/gcc/x86_64-linux-gnu/9",
"-L/usr/lib/gcc/x86_64-linux-gnu/9/../../../../lib64",
"-L/lib/x86_64-linux-gnu",
"-L/lib/../lib64",
"-L/usr/lib/x86_64-linux-gnu",
"-L/usr/lib/../lib64",
"-L/lib",
"-L/usr/lib",
link_obj,
"-lgcc",
"--as-needed",
"-lgcc_s",
"--no-as-needed",
"-lc",
"-lgcc",
"--as-needed",
"-lgcc_s",
"--no-as-needed",
"/usr/lib/gcc/x86_64-linux-gnu/9/crtend.o",
"/lib/x86_64-linux-gnu/crtn.o",
};
try std.testing.expectEqual(expected.len, argv.items.len);
for (expected, argv.items) |expected_item, actual_item| {
try std.testing.expectEqualStrings(expected_item, actual_item);
}
}

0 comments on commit 14602f5

Please sign in to comment.