diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 713076438..b9058b395 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -373,7 +373,6 @@ jobs: path: | /nix /zig - ~/Android/ndk # Install Nix and use that to run our tests so our environment matches exactly. - uses: cachix/install-nix-action@2126ae7fc54c9df00dd18f7f18754393182c73cd # v31.9.1 @@ -385,22 +384,20 @@ jobs: authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}" - name: Setup Android NDK - run: | - NDK_ROOT="$HOME/Android/ndk" - NDK_DIR="$NDK_ROOT/android-ndk-${{ env.ANDROID_NDK_VERSION }}" - if [ ! -d "$NDK_DIR" ]; then - curl -fsSL -o /tmp/ndk.zip \ - "https://dl.google.com/android/repository/android-ndk-${{ env.ANDROID_NDK_VERSION }}-linux.zip" - mkdir -p $NDK_ROOT - unzip -q /tmp/ndk.zip -d $NDK_ROOT - rm /tmp/ndk.zip - fi - echo "ANDROID_NDK_HOME=$NDK_DIR" >> "$GITHUB_ENV" + uses: nttld/setup-ndk@ed92fe6cadad69be94a966a7ee3271275e62f779 # v1.6.0 + id: setup-ndk + with: + ndk-version: r29 + add-to-path: false + link-to-sdk: false + local-cache: true - name: Build run: | nix develop -c zig build lib-vt \ -Dtarget=${{ matrix.target }} + env: + ANDROID_NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }} build-linux: strategy: diff --git a/pkg/android-ndk/build.zig b/pkg/android-ndk/build.zig index 8d4668fe5..5b005665b 100644 --- a/pkg/android-ndk/build.zig +++ b/pkg/android-ndk/build.zig @@ -25,9 +25,9 @@ pub fn addPaths(b: *std.Build, step: *std.Build.Step.Compile) !void { var map: std.AutoHashMapUnmanaged(Key, ?struct { libc: std.Build.LazyPath, - cpp_include: []const u8, - lib: []const u8, - }) = .{}; + cpp_include: std.Build.LazyPath, + lib: std.Build.LazyPath, + }) = .empty; }; const target = step.rootModuleTarget(); @@ -38,16 +38,7 @@ pub fn addPaths(b: *std.Build, step: *std.Build.Step.Compile) !void { }); if (!gop.found_existing) { - const ndk_path = findNDKPath(b.allocator) orelse { - gop.value_ptr.* = null; - return error.AndroidNDKNotFound; - }; - - var ndk_dir = std.fs.openDirAbsolute(ndk_path, .{}) catch { - gop.value_ptr.* = null; - return error.AndroidNDKNotFound; - }; - defer ndk_dir.close(); + const ndk_path = findNDKPath(b) orelse return error.AndroidNDKNotFound; const ndk_triple = ndkTriple(target) orelse { gop.value_ptr.* = null; @@ -59,27 +50,47 @@ pub fn addPaths(b: *std.Build, step: *std.Build.Step.Compile) !void { return error.AndroidNDKUnsupportedHost; }; - const sysroot = try std.fs.path.join(b.allocator, &.{ - ndk_path, "toolchains", "llvm", "prebuilt", host, "sysroot", + const sysroot = b.pathJoin(&.{ + ndk_path, + "toolchains", + "llvm", + "prebuilt", + host, + "sysroot", + }); + const include_dir = b.pathJoin(&.{ + sysroot, + "usr", + "include", + }); + const sys_include_dir = b.pathJoin(&.{ + sysroot, + "usr", + "include", + ndk_triple, + }); + const c_runtime_dir = b.pathJoin(&.{ + sysroot, + "usr", + "lib", + ndk_triple, + b.fmt("{d}", .{target.os.version_range.linux.android}), + }); + const lib = b.pathJoin(&.{ + sysroot, + "usr", + "lib", + ndk_triple, + }); + const cpp_include = b.pathJoin(&.{ + sysroot, + "usr", + "include", + "c++", + "v1", }); - const include_dir = try std.fs.path.join( - b.allocator, - &.{ sysroot, "usr", "include" }, - ); - const sys_include_dir = try std.fs.path.join( - b.allocator, - &.{ sysroot, "usr", "include", ndk_triple }, - ); - var api_buf: [10]u8 = undefined; - const api_level = target.os.version_range.linux.android; - const api_level_str = std.fmt.bufPrint(&api_buf, "{d}", .{api_level}) catch unreachable; - const c_runtime_dir = try std.fs.path.join( - b.allocator, - &.{ sysroot, "usr", "lib", ndk_triple, api_level_str }, - ); - - const libc_txt = try std.fmt.allocPrint(b.allocator, + const libc_txt = b.fmt( \\include_dir={s} \\sys_include_dir={s} \\crt_dir={s} @@ -90,79 +101,86 @@ pub fn addPaths(b: *std.Build, step: *std.Build.Step.Compile) !void { const wf = b.addWriteFiles(); const libc_path = wf.add("libc.txt", libc_txt); - const lib = try std.fs.path.join(b.allocator, &.{ sysroot, "usr", "lib", ndk_triple }); - const cpp_include = try std.fs.path.join(b.allocator, &.{ sysroot, "usr", "include", "c++", "v1" }); gop.value_ptr.* = .{ - .lib = lib, .libc = libc_path, - .cpp_include = cpp_include, + .cpp_include = .{ .cwd_relative = cpp_include }, + .lib = .{ .cwd_relative = lib }, }; } const value = gop.value_ptr.* orelse return error.AndroidNDKNotFound; step.setLibCFile(value.libc); - step.root_module.addSystemIncludePath(.{ .cwd_relative = value.cpp_include }); - step.root_module.addLibraryPath(.{ .cwd_relative = value.lib }); + step.root_module.addSystemIncludePath(value.cpp_include); + step.root_module.addLibraryPath(value.lib); } -fn findNDKPath(allocator: std.mem.Allocator) ?[]const u8 { +fn findNDKPath(b: *std.Build) ?[]const u8 { // Check if user has set the environment variable for the NDK path. - if (std.process.getEnvVarOwned(allocator, "ANDROID_NDK_HOME") catch null) |value| { - if (value.len > 0) return value; + if (std.process.getEnvVarOwned(b.allocator, "ANDROID_NDK_HOME") catch null) |value| { + if (value.len == 0) return null; + var dir = std.fs.openDirAbsolute(value, .{}) catch return null; + defer dir.close(); + return value; } // Check the common environment variables for the Android SDK path and look for the NDK inside it. inline for (.{ "ANDROID_HOME", "ANDROID_SDK_ROOT" }) |env| { - if (std.process.getEnvVarOwned(allocator, env) catch null) |sdk| { + if (std.process.getEnvVarOwned(b.allocator, env) catch null) |sdk| { if (sdk.len > 0) { - if (findLatestNDK(allocator, sdk)) |ndk| return ndk; + if (findLatestNDK(b, sdk)) |ndk| return ndk; } } } // As a fallback, we assume the most common/default SDK path based on the OS. const home = std.process.getEnvVarOwned( - allocator, + b.allocator, if (builtin.os.tag == .windows) "LOCALAPPDATA" else "HOME", ) catch return null; - const default_sdk_path = std.fs.path.join(allocator, &.{ - home, switch (builtin.os.tag) { - .linux => "Android/sdk", - .macos => "Library/Android/Sdk", - .windows => "Android/Sdk", - else => return null, + const default_sdk_path = b.pathJoin( + &.{ + home, + switch (builtin.os.tag) { + .linux => "Android/sdk", + .macos => "Library/Android/Sdk", + .windows => "Android/Sdk", + else => return null, + }, }, - }) catch return null; - return findLatestNDK(allocator, default_sdk_path); + ); + + return findLatestNDK(b, default_sdk_path); } -fn findLatestNDK(allocator: std.mem.Allocator, sdk_path: []const u8) ?[]const u8 { - const ndk_dir = std.fs.path.join(allocator, &.{ sdk_path, "ndk" }) catch return null; +fn findLatestNDK(b: *std.Build, sdk_path: []const u8) ?[]const u8 { + const ndk_dir = b.pathJoin(&.{ sdk_path, "ndk" }); var dir = std.fs.openDirAbsolute(ndk_dir, .{ .iterate = true }) catch return null; defer dir.close(); - var latest_version: ?[]const u8 = null; - var latest_parsed: ?std.SemanticVersion = null; + var latest_: ?struct { + name: []const u8, + version: std.SemanticVersion, + } = null; var iterator = dir.iterate(); while (iterator.next() catch null) |file| { if (file.kind != .directory) continue; - const parsed = std.SemanticVersion.parse(file.name) catch continue; - if (latest_version == null or parsed.order(latest_parsed.?) == .gt) { - if (latest_version) |old| allocator.free(old); - latest_version = allocator.dupe(u8, file.name) catch return null; - latest_parsed = parsed; + const version = std.SemanticVersion.parse(file.name) catch continue; + if (latest_) |latest| { + if (version.order(latest.version) != .gt) continue; } + latest_ = .{ + .name = file.name, + .version = version, + }; } - if (latest_version) |version| { - return std.fs.path.join(allocator, &.{ sdk_path, "ndk", version }) catch return null; - } + const latest = latest_ orelse return null; - return null; + return b.pathJoin(&.{ sdk_path, "ndk", latest.name }); } fn hostTag() ?[]const u8 { diff --git a/pkg/android-ndk/build.zig.zon b/pkg/android-ndk/build.zig.zon index 97febcefb..eb0de6820 100644 --- a/pkg/android-ndk/build.zig.zon +++ b/pkg/android-ndk/build.zig.zon @@ -1,7 +1,10 @@ .{ .name = .android_ndk, - .version = "0.0.1", - .dependencies = .{}, + .version = "0.0.2", .fingerprint = 0xee68d62c5a97b68b, - .paths = .{""}, + .dependencies = .{}, + .paths = .{ + "build.zig", + "build.zig.zon", + }, }