Skip to content

Commit 47c69de

Browse files
committed
std.Build: allow adding exact search prefixes with function and command option
This allows more granurality when adding search pathes for cross-compiling. By default old (all variant) system added `bin`, `include` and `lib` subdirectories from `search-prefix` argument path when cross-compiling, but on some distros it's not correct and can lead to some errors. For example, on my Gentoo system I have libcurl installed as both 32-bit and 64-bit versions, which are located in `/usr/lib` and `/usr/lib64` directories respectively. If I use plain `--search-prefix`, it fails because it tries to add 32-bit libraries: ```console $ zig build -Dtarget=x86_64-linux-gnu.2.35 --search-prefix /usr/ install └─ install true_or_false └─ zig build-exe true_or_false Debug x86_64-linux.6.11.7-gnu.2.40 3 errors error: ld.lld: /usr/lib/libcurl.so is incompatible with elf_x86_64 error: ld.lld: /usr/lib/libssl.so is incompatible with elf_x86_64 error: ld.lld: /usr/lib/libcrypto.so is incompatible with elf_x86_64 ``` Another example is `libgccjit` library, which shared objects are located (at least on my system) in `/usr/lib/gcc/x86_64-pc-linux-gnu/14/`, and include files in include subdir there. One solution I used recently was to create temporary directory and symlink files so that they have names expected by Zig, but it's not the best solution. With this PR you can now supply file which will instruct build system to add pathes written there as-is, without trying to guess subdirs there. Something like: ```zig .{ .libraries = "/usr/lib64", } ``` or ```zig .{ .binaries = "/usr/x86_64-pc-linux-gnu/gcc-bin/14/", .libraries = "/usr/lib/gcc/x86_64-pc-linux-gnu/14", .includes = "/usr/lib/gcc/x86_64-pc-linux-gnu/14/include/", } ``` can be saved in some file like paths.zon and then passed using `--search-prefix-exact paths.zon`. This also helps to use this config on a system (distro) level, without messing with build.zig. Signed-off-by: Eric Joldasov <bratishkaerik@landless-city.net>
1 parent 5782905 commit 47c69de

File tree

2 files changed

+64
-0
lines changed

2 files changed

+64
-0
lines changed

lib/compiler/build_runner.zig

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,13 @@ pub fn main() !void {
176176
} else if (mem.eql(u8, arg, "--search-prefix")) {
177177
const search_prefix = nextArgOrFatal(args, &arg_idx);
178178
builder.addSearchPrefix(search_prefix);
179+
} else if (mem.eql(u8, arg, "--search-prefix-exact")) {
180+
const search_prefix_spec_path = nextArgOrFatal(args, &arg_idx);
181+
182+
const search_prefix = parseZonFile(std.Build.SearchPrefix.Exact, builder, search_prefix_spec_path) catch |err|
183+
return fatal("Unable to parse ZON file '{s}': {s}", .{ search_prefix_spec_path, @errorName(err) });
184+
185+
builder.addSearchPrefixExact(search_prefix);
179186
} else if (mem.eql(u8, arg, "--libc")) {
180187
builder.libc_file = nextArgOrFatal(args, &arg_idx);
181188
} else if (mem.eql(u8, arg, "--color")) {
@@ -1317,6 +1324,7 @@ fn usage(b: *std.Build, out_stream: anytype) !void {
13171324
\\ --search-prefix [path] Add a path to look for binaries, libraries, headers
13181325
\\ --sysroot [path] Set the system root directory (usually /)
13191326
\\ --libc [file] Provide a file which specifies libc paths
1327+
\\ --search-prefix-exact [file] Provide a file which specifies exact search paths
13201328
\\
13211329
\\ --system [pkgdir] Disable package fetching; enable all integrations
13221330
\\ -fsys=[name] Enable a system integration
@@ -1518,3 +1526,55 @@ fn createModuleDependenciesForStep(step: *Step) Allocator.Error!void {
15181526
};
15191527
}
15201528
}
1529+
1530+
/// Parse ZON file where all fields are paths relative to
1531+
/// current working directory.
1532+
fn parseZonFile(comptime T: type, b: *std.Build, path: []const u8) !T {
1533+
const spec_file = try std.fs.cwd().openFile(path, .{});
1534+
defer spec_file.close();
1535+
1536+
const gpa = b.allocator;
1537+
1538+
const spec = try std.zig.readSourceFileToEndAlloc(gpa, spec_file, null);
1539+
defer gpa.free(spec);
1540+
1541+
var ast: std.zig.Ast = try .parse(gpa, spec, .zon);
1542+
defer ast.deinit(gpa);
1543+
1544+
const zoir = try std.zig.ZonGen.generate(gpa, ast);
1545+
defer zoir.deinit(gpa);
1546+
1547+
if (zoir.hasCompileErrors()) {
1548+
std.log.err("Can't parse ZON file '{s}: {d} errors", .{ path, zoir.compile_errors.len });
1549+
for (zoir.compile_errors, 1..) |compile_error, i| {
1550+
std.log.err("[{d}] {s}", .{ i, compile_error.msg.get(zoir) });
1551+
for (compile_error.getNotes(zoir)) |note| {
1552+
std.log.err("note: {s}", .{note.msg.get(zoir)});
1553+
}
1554+
}
1555+
return process.exit(1);
1556+
}
1557+
1558+
var result: T = .{};
1559+
const root_struct = switch (std.zig.Zoir.Node.Index.root.get(zoir)) {
1560+
.struct_literal => |struct_literal| struct_literal,
1561+
.empty_literal => return result,
1562+
else => return fatal("Can't parse ZON file '{s}': not a struct", .{path}),
1563+
};
1564+
1565+
for (root_struct.names, 0..) |name_i, val_i| {
1566+
const name = name_i.get(zoir);
1567+
const val = root_struct.vals.at(@intCast(val_i)).get(zoir);
1568+
1569+
inline for (@typeInfo(T).@"struct".fields) |field| {
1570+
if (std.mem.eql(u8, name, field.name)) {
1571+
const string = switch (val) {
1572+
.string_literal => |string_literal| string_literal,
1573+
else => return fatal("Can't parse field '{s}' in ZON file '{s}': not a string", .{ field.name, path }),
1574+
};
1575+
@field(result, field.name) = .{ .cwd_relative = b.dupePath(string) };
1576+
}
1577+
}
1578+
}
1579+
return result;
1580+
}

lib/std/Build.zig

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2089,6 +2089,10 @@ pub fn addSearchPrefix(b: *Build, search_prefix: []const u8) void {
20892089
}) catch @panic("OOM");
20902090
}
20912091

2092+
pub fn addSearchPrefixExact(b: *Build, search_prefix_exact: SearchPrefix.Exact) void {
2093+
b.search_prefixes.append(b.allocator, .{ .exact = search_prefix_exact }) catch @panic("OOM");
2094+
}
2095+
20922096
pub fn getInstallPath(b: *Build, dir: InstallDir, dest_rel_path: []const u8) []const u8 {
20932097
assert(!fs.path.isAbsolute(dest_rel_path)); // Install paths must be relative to the prefix
20942098
const base_dir = switch (dir) {

0 commit comments

Comments
 (0)