mirror of
https://codeberg.org/ziglang/zig.git
synced 2026-03-08 02:24:33 +01:00
android: detect native ABI and API level correctly
ABI detection previously did not take into account the non-standard directory structure of Android. This has been fixed. The API level is detected by running `getprop ro.build.version.sdk`, since we don't want to depend on bionic, and reading system properties ourselves is not trivially possible.
This commit is contained in:
parent
e8af0f2cc0
commit
04e73d03bd
2 changed files with 68 additions and 2 deletions
|
|
@ -2131,6 +2131,10 @@ pub inline fn isMuslLibC(target: *const Target) bool {
|
|||
return target.os.tag == .linux and target.abi.isMusl();
|
||||
}
|
||||
|
||||
pub inline fn isBionicLibC(target: *const Target) bool {
|
||||
return target.os.tag == .linux and target.abi.isAndroid();
|
||||
}
|
||||
|
||||
pub inline fn isDarwinLibC(target: *const Target) bool {
|
||||
return switch (target.abi) {
|
||||
.none, .simulator => target.os.tag.isDarwin(),
|
||||
|
|
|
|||
|
|
@ -211,6 +211,8 @@ pub const DetectError = error{
|
|||
DeviceBusy,
|
||||
OSVersionDetectionFail,
|
||||
Unexpected,
|
||||
/// Android-only. Querying API level through `getprop` failed.
|
||||
ApiLevelQueryFailed,
|
||||
} || Io.Cancelable;
|
||||
|
||||
/// Given a `Target.Query`, which specifies in detail which parts of the
|
||||
|
|
@ -500,6 +502,28 @@ pub fn resolveTargetQuery(io: Io, query: Target.Query) DetectError!Target {
|
|||
}
|
||||
}
|
||||
|
||||
if (builtin.os.tag == .linux and result.isBionicLibC() and query.os_tag == null and query.android_api_level == null) {
|
||||
result.os.version_range.linux.android = detectAndroidApiLevel(io) catch |err| return switch (err) {
|
||||
error.InvalidWtf8,
|
||||
error.CurrentWorkingDirectoryUnlinked,
|
||||
error.InvalidBatchScriptArg,
|
||||
=> unreachable, // Windows-only
|
||||
error.ApiLevelQueryFailed => |e| e,
|
||||
else => blk: {
|
||||
std.log.err("spawning or reading from getprop failed ({s})", .{@errorName(err)});
|
||||
switch (err) {
|
||||
error.SystemResources,
|
||||
error.FileSystem,
|
||||
error.ProcessFdQuotaExceeded,
|
||||
error.SystemFdQuotaExceeded,
|
||||
error.SymLinkLoop,
|
||||
=> |e| break :blk e,
|
||||
else => break :blk error.ApiLevelQueryFailed,
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -1046,8 +1070,11 @@ fn detectAbiAndDynamicLinker(io: Io, cpu: Target.Cpu, os: Target.Os, query: Targ
|
|||
error.NetworkNotFound,
|
||||
error.FileTooBig,
|
||||
error.Unexpected,
|
||||
=> return error.UnableToOpenElfFile,
|
||||
|
||||
=> |e| if (e == error.FileNotFound and os.tag == .linux and mem.eql(u8, file_name, "/usr/bin/env")) {
|
||||
// Android does not have a /usr directory, so try again
|
||||
file_name = "/system/bin/env";
|
||||
continue;
|
||||
} else return error.UnableToOpenElfFile,
|
||||
else => |e| return e,
|
||||
};
|
||||
var is_elf_file = false;
|
||||
|
|
@ -1131,6 +1158,41 @@ const LdInfo = struct {
|
|||
abi: Target.Abi,
|
||||
};
|
||||
|
||||
fn detectAndroidApiLevel(io: Io) !u32 {
|
||||
comptime if (builtin.os.tag != .linux) unreachable;
|
||||
|
||||
var child = try std.process.spawn(io, .{
|
||||
.argv = &.{
|
||||
"/system/bin/getprop",
|
||||
"ro.build.version.sdk",
|
||||
},
|
||||
.stdin = .ignore,
|
||||
.stdout = .pipe,
|
||||
.stderr = .ignore,
|
||||
});
|
||||
errdefer child.kill(io);
|
||||
|
||||
// PROP_VALUE_MAX is 92, output is value + newline.
|
||||
// Currently API levels are two-digit numbers, but we want to make sure we never read a partial value.
|
||||
var stdout_buf: [92 + 1]u8 = undefined;
|
||||
var reader = child.stdout.?.readerStreaming(io, &.{});
|
||||
const n = try reader.interface.readSliceShort(&stdout_buf);
|
||||
const api_level = std.fmt.parseInt(u32, stdout_buf[0 .. n - 1], 10) catch |e| {
|
||||
std.log.err(
|
||||
"Could not parse API level, unexpected getprop output '{s}' ({s})",
|
||||
.{ stdout_buf[0 .. n - 1], @errorName(e) },
|
||||
);
|
||||
return error.ApiLevelQueryFailed;
|
||||
};
|
||||
|
||||
const term = try child.wait(io);
|
||||
if (term != .exited or term.exited != 0) {
|
||||
std.log.err("getprop terminated abnormally: {}", .{term});
|
||||
return error.ApiLevelQueryFailed;
|
||||
}
|
||||
return api_level;
|
||||
}
|
||||
|
||||
test {
|
||||
_ = NativePaths;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue