Open jonahnm opened 6 months ago
To override the SDK the zig libc
mechanism is used. Basically:
xcrun --show-sdk-path --sdk iphoneos
for the pathzig libc > libc.txt
/usr/include
. Here's an example:
include_dir=/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS17.4.sdk/usr/include
sys_include_dir=/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS17.4.sdk/usr/include
crt_dir=
msvc_lib_dir=
kernel32_lib_dir=
gcc_dir=
zig build-exe --libc libc.txt ...
and things should work:
zig build-exe z1.zig --libc libc.txt --verbose-link -target aarch64-ios
LLVM Emit Object... zig ld -dynamic -platform_version ios 12.0.0 17.4 -syslibroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS17.4.sdk -e _main z1.o /Users/mike/project/zig/work/main/zig-cache/o/172afb7523b9b2cec813e0de72bbdc07/libcompiler_rt.a -o z1 -lSystem
Using the zig build system is a little more complicated. We currently do not integrate this but here's a quick take on making it work. But a slight warning, I don't use zig build that much and I believe there was talk of removing zig custom steps, which is what I implemented the libc.txt
generator with.
const std = @import("std");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const exe = b.addExecutable(.{
.name = "hw",
.root_source_file = .{ .path = "src/main.zig" },
.target = target,
.optimize = optimize,
});
b.installArtifact(exe);
// map Target.Os → xcrun SDK name
const o_sdk: ?[]const u8 = switch (target.result.os.tag) {
.ios => "iphoneos",
.macos => "macosx",
.tvos => "appletvos",
.watchos => "watchos",
else => null,
};
if (o_sdk) |sdk| {
const xcrun = b.addSystemCommand(&.{ "xcrun", "--show-sdk-path", "--sdk", sdk });
exe.step.dependOn(&xcrun.step);
const g = GenLibCFile.create(b, xcrun.captureStdOut());
g.step.dependOn(&xcrun.step);
exe.step.dependOn(&g.step);
exe.setLibCFile(g.output);
}
}
const GenLibCFile = struct {
step: std.Build.Step,
sdkroot: std.Build.LazyPath,
generated: std.Build.GeneratedFile,
output: std.Build.LazyPath,
fn create(owner: *std.Build, sdkroot: std.Build.LazyPath) *GenLibCFile {
const self = owner.allocator.create(GenLibCFile) catch @panic("OOM");
self.* = .{
.step = std.Build.Step.init(.{
.id = .custom,
.name = "GenLibCFile",
.owner = owner,
.makeFn = make,
}),
.sdkroot = sdkroot,
.generated = .{ .step = &self.step },
.output = .{ .generated = &self.generated },
};
return self;
}
fn make(step: *std.Build.Step, prog_node: *std.Progress.Node) !void {
const b = step.owner;
const self = @fieldParentPtr(GenLibCFile, "step", step);
prog_node.activate();
defer prog_node.end();
// read xcrun output
var buf: [std.c.PATH_MAX]u8 = undefined;
var path = try std.fs.cwd().readFile(self.sdkroot.getPath(b), &buf);
// want first line
for (path, 0..) |c, i| {
if (c == '\n') {
path.len = i;
break;
}
}
prog_node.completeOne();
var man = b.graph.cache.obtain();
defer man.deinit();
man.hash.addBytes("GenLibCFile");
man.hash.addBytes(&[_]u8{ 0x2e, 0x4c, 0x48, 0x3d, 0x66, 0x3c, 0xc2, 0x80 });
man.hash.addBytes(path);
if (try step.cacheHit(&man)) {
const digest = man.final();
self.generated.path = try b.cache_root.join(b.allocator, &.{ "o", &digest, "libc.txt" });
return;
}
const digest = man.final();
self.generated.path = try b.cache_root.join(b.allocator, &.{ "o", &digest, "libc.txt" });
const cache_path = "o" ++ std.fs.path.sep_str ++ digest;
var cache_dir = b.cache_root.handle.makeOpenPath(cache_path, .{}) catch |err| {
return step.fail("unable to make path '{}{s}': {s}", .{
b.cache_root, cache_path, @errorName(err),
});
};
defer cache_dir.close();
var f = try cache_dir.createFile("libc.txt", .{});
defer f.close();
try f.writeAll("include_dir=");
try f.writeAll(path);
try f.writeAll(std.fs.path.sep_str ++ "usr" ++ std.fs.path.sep_str ++ "include");
try f.writeAll("\nsys_include_dir=");
try f.writeAll(path);
try f.writeAll(std.fs.path.sep_str ++ "usr" ++ std.fs.path.sep_str ++ "include");
try f.writeAll("\ncrt_dir=");
try f.writeAll("\nmsvc_lib_dir=");
try f.writeAll("\nkernel32_lib_dir=");
try f.writeAll("\ngcc_dir=");
try f.writeAll("\n");
try step.writeManifest(&man);
prog_node.completeOne();
}
};
or... there is an environment variable that seems to do the trick as well which activates a previously prepared libc.txt
ZIG_LIBC=libc.txt zig build -Dtarget=aarch64-ios --verbose
or... there is an environment variable that seems to do the trick as well which activates a previously prepared
libc.txt
ZIG_LIBC=libc.txt zig build -Dtarget=aarch64-ios --verbose
This does allow it to compile indeed, but I believe a better solution should be incorporated.
I met the same problem when I installed XCode 16 for Sonoma and rerun my zig file using zig 0.13.0. And I solved this by:
# ref: https://github.com/zed-industries/zed/blob/main/docs/src/development/macos.md
sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer
# ref: brew said this when I tried to uinstall zig, this feels right
sudo xcodebuild -license accept
# and brew uninstall and reinstall zlg, & zig
Zig Version
0.12.0-dev.3154+0b744da84
Steps to Reproduce and Observed Behavior
Run
zig build
targeting iOS with iOS SDK in build file, and you get error:error: unable to find libSystem system library
.Expected Behavior
Successful compilation.