Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 42 additions & 11 deletions .github/workflows/zig-embedded.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,53 @@ jobs:
strategy:
fail-fast: false
matrix:
targets:
- aarch64-linux-gnu
- aarch64-linux
- riscv64-linux-musl
- powerpc64-linux
- aarch64-windows
include:
- target: aarch64-linux-gnu
- target: aarch64-linux
- target: riscv64-linux-musl
- target: powerpc64-linux
- target: aarch64-windows
# Android targets (requires NDK)
- target: aarch64-linux-android
android_api: "28"
- target: arm-linux-androideabi
android_api: "28"
- target: x86_64-linux-android
android_api: "28"
- target: x86-linux-android
android_api: "28"
- target: riscv64-linux-android
android_api: "35"

runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
with:
fetch-depth: 0
- uses: mlugg/setup-zig@v2
# with:
# version: master
- name: Build Summary ${{ matrix.targets }}
run: zig build --summary all -freference-trace -Dtarget=${{ matrix.targets }}
- name: Build Summary - Zig Package ${{ matrix.targets }}
run: zig build --build-file $PWD/test_zigpkg/build.zig --summary all -freference-trace -Dtarget=${{ matrix.targets }}

- name: Setup Android NDK
if: contains(matrix.target, 'android')
id: setup-ndk
uses: nttld/setup-ndk@v1
with:
ndk-version: r29
local-cache: true

- name: Build Summary ${{ matrix.target }}
env:
ANDROID_NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }}
run: |
ARGS="-Dtarget=${{ matrix.target }}"
if [ -n "${{ matrix.android_api }}" ]; then
ARGS="$ARGS -Dandroid-api-level=${{ matrix.android_api }}"
fi
zig build --summary all -freference-trace $ARGS
- name: Build Summary - Zig Package ${{ matrix.target }}
env:
ANDROID_NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }}
run: |
ARGS="-Dtarget=${{ matrix.target }}"
zig build --build-file $PWD/test_zigpkg/build.zig --summary all -freference-trace $ARGS
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Welcome to the OpenSSL Project (Forked to zig-pkg support [v0.14.0 <-> 0.15.1 compat])
Welcome to the OpenSSL Project (Forked to zig-pkg support v0.15.2)
==============================

[![openssl logo]][www.openssl.org]
Expand Down
161 changes: 154 additions & 7 deletions build.zig
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
const std = @import("std");
const builtin = @import("builtin");

pub fn build(b: *std.Build) void {
pub fn build(b: *std.Build) !void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});

const crypto = libcrypto(b, target, optimize);
const ssl = libssl(b, target, optimize);
const android_api_level = b.option([]const u8, "android-api-level", "Android API Level (default: 29)") orelse "29";

const crypto = try libcrypto(b, target, optimize, android_api_level);
const ssl = try libssl(b, target, optimize, android_api_level);

crypto.installHeadersDirectory(b.path("include/crypto"), "crypto", .{});
crypto.installHeadersDirectory(b.path("include/internal"), "internal", .{});
Expand All @@ -15,7 +18,7 @@ pub fn build(b: *std.Build) void {
b.installArtifact(ssl);
}

fn libcrypto(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode) *std.Build.Step.Compile {
fn libcrypto(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode, android_api_level: []const u8) !*std.Build.Step.Compile {
const lib = b.addLibrary(.{
.name = "crypto",
.root_module = b.createModule(.{
Expand All @@ -28,6 +31,11 @@ fn libcrypto(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.buil
.Debug, .ReleaseSafe => lib.bundle_compiler_rt = true,
else => lib.root_module.strip = true,
}

if (target.result.abi == .android or target.result.abi == .androideabi) {
try ConfigureAndroidEnvironment(b, lib, target, android_api_level);
}

lib.root_module.addIncludePath(b.path("include"));
lib.root_module.addIncludePath(b.path("."));
lib.root_module.addIncludePath(b.path("providers/common/include"));
Expand Down Expand Up @@ -889,12 +897,12 @@ fn libcrypto(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.buil
},
.flags = cflags,
});
lib.root_module.linkLibrary(libprovider(b, target, optimize));
lib.root_module.linkLibrary(try libprovider(b, target, optimize, android_api_level));
lib.linkLibC();
return lib;
}

fn libssl(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode) *std.Build.Step.Compile {
fn libssl(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode, android_api_level: []const u8) !*std.Build.Step.Compile {
const lib = b.addLibrary(.{
.name = "ssl",
.root_module = b.createModule(.{
Expand All @@ -907,6 +915,11 @@ fn libssl(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.builtin
.Debug, .ReleaseSafe => lib.bundle_compiler_rt = true,
else => lib.root_module.strip = true,
}

if (target.result.abi == .android or target.result.abi == .androideabi) {
try ConfigureAndroidEnvironment(b, lib, target, android_api_level);
}

lib.root_module.addIncludePath(b.path("include"));
lib.root_module.addIncludePath(b.path("include_gen"));
lib.root_module.addCMacro("OPENSSL_NO_DEPRECATED", "");
Expand Down Expand Up @@ -1009,14 +1022,19 @@ fn libssl(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.builtin
return lib;
}

fn libprovider(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode) *std.Build.Step.Compile {
fn libprovider(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode, android_api_level: []const u8) !*std.Build.Step.Compile {
const lib = b.addLibrary(.{
.name = "providers",
.root_module = b.createModule(.{
.target = target,
.optimize = optimize,
}),
});

if (target.result.abi == .android or target.result.abi == .androideabi) {
try ConfigureAndroidEnvironment(b, lib, target, android_api_level);
}

lib.root_module.addIncludePath(b.path("include"));
lib.root_module.addIncludePath(b.path("."));
lib.root_module.addIncludePath(b.path("providers/common/include"));
Expand Down Expand Up @@ -1280,3 +1298,132 @@ const BuildInfo = struct {
return split.first();
}
};

const AndroidConfigError = error{
MissingNdkEnvironment,
InvalidNdkPathEncoding,
UnsupportedHostOperatingSystem,
UnsupportedHostArchitecture,
UnsupportedTargetArchitecture,
InvalidApiLevel,
NdkPathNotFound,
SysrootNotFound,
LibCRenderFailed,
OutOfMemory,
};

fn ConfigureAndroidEnvironment(b: *std.Build, compile: *std.Build.Step.Compile, target: std.Build.ResolvedTarget, api_level: []const u8) AndroidConfigError!void {
const api_level_int = std.fmt.parseInt(u32, api_level, 10) catch {
std.log.err("Invalid API level format: '{s}', expected numeric string (e.g., '21')", .{api_level});
return AndroidConfigError.InvalidApiLevel;
};

const cpu_arch = target.result.cpu.arch;

if (cpu_arch == .riscv64) {
if (api_level_int < 35) {
std.log.err("RISC-V 64 Android target requires API level 35 or higher (requested: {d}).", .{api_level_int});
return AndroidConfigError.InvalidApiLevel;
}
}

if (api_level_int < 24) {
std.log.warn("API level {d} is very low, modern NDKs may not support it.", .{api_level_int});
}

const NDK_ENV_VAR = "ANDROID_NDK_HOME";

const ndk_home = std.process.getEnvVarOwned(b.allocator, NDK_ENV_VAR) catch |err| switch (err) {
error.EnvironmentVariableNotFound => {
std.log.err("Environment variable '{s}' not found", .{NDK_ENV_VAR});
return AndroidConfigError.MissingNdkEnvironment;
},
error.InvalidWtf8 => {
std.log.err("Environment variable '{s}' contains invalid UTF-8 encoding", .{NDK_ENV_VAR});
return AndroidConfigError.InvalidNdkPathEncoding;
},
error.OutOfMemory => return AndroidConfigError.OutOfMemory,
};
defer b.allocator.free(ndk_home);

std.fs.accessAbsolute(ndk_home, .{}) catch {
std.log.err("NDK path not accessible: {s}", .{ndk_home});
return AndroidConfigError.NdkPathNotFound;
};

const host_os = builtin.os.tag;
const host_arch = builtin.cpu.arch;
const os_name = switch (host_os) {
.windows => "windows",
.linux => "linux",
.macos => "darwin",
else => {
std.log.err("Unsupported host OS: {s}", .{@tagName(host_os)});
return AndroidConfigError.UnsupportedHostOperatingSystem;
},
};
const arch_name = switch (host_arch) {
.x86_64 => "x86_64",
.aarch64 => "aarch64",
.x86 => "x86",
else => {
std.log.err("Unsupported host arch: {s}", .{@tagName(host_arch)});
return AndroidConfigError.UnsupportedHostArchitecture;
},
};
const host_tag = std.fmt.allocPrint(b.allocator, "{s}-{s}", .{ os_name, arch_name }) catch {
return AndroidConfigError.OutOfMemory;
};
defer b.allocator.free(host_tag);

const target_arch = switch (cpu_arch) {
.aarch64 => "aarch64-linux-android",
.x86_64 => "x86_64-linux-android",
.arm, .thumb => "arm-linux-androideabi",
.x86 => "i686-linux-android",
.riscv64 => "riscv64-linux-android",
else => {
std.log.err("Unsupported target arch: {s}", .{@tagName(cpu_arch)});
return AndroidConfigError.UnsupportedTargetArchitecture;
},
};

const sysroot_path = std.fs.path.join(b.allocator, &.{ ndk_home, "toolchains", "llvm", "prebuilt", host_tag, "sysroot" }) catch return AndroidConfigError.OutOfMemory;
defer b.allocator.free(sysroot_path);

std.fs.accessAbsolute(sysroot_path, .{}) catch {
std.log.err("Sysroot not found at: {s}", .{sysroot_path});
std.log.err("Check if your NDK version matches the expected directory structure.", .{});
return AndroidConfigError.SysrootNotFound;
};

const include_path = std.fs.path.join(b.allocator, &.{ sysroot_path, "usr", "include" }) catch return AndroidConfigError.OutOfMemory;
defer b.allocator.free(include_path);

const lib_path = std.fs.path.join(b.allocator, &.{ sysroot_path, "usr", "lib", target_arch, api_level }) catch return AndroidConfigError.OutOfMemory;
defer b.allocator.free(lib_path);

const system_include_path = std.fs.path.join(b.allocator, &.{ sysroot_path, "usr", "include", target_arch }) catch return AndroidConfigError.OutOfMemory;
defer b.allocator.free(system_include_path);

compile.root_module.addSystemIncludePath(.{ .cwd_relative = include_path });
compile.root_module.addSystemIncludePath(.{ .cwd_relative = system_include_path });

compile.root_module.addLibraryPath(.{ .cwd_relative = lib_path });

var writer = std.Io.Writer.Allocating.init(b.allocator);

const libc_installation = std.zig.LibCInstallation{
.include_dir = include_path,
.sys_include_dir = system_include_path,
.crt_dir = lib_path,
};

libc_installation.render(&writer.writer) catch {
std.log.err("Failed to render libc installation configuration.", .{});
return AndroidConfigError.LibCRenderFailed;
};
const libc_path = b.addWriteFiles().add("android-libc.conf", writer.written());

compile.setLibCFile(libc_path);
}
2 changes: 1 addition & 1 deletion build.zig.zon
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
.{
.name = .openssl,
.version = "3.6.0",
.minimum_zig_version = "0.14.0",
.minimum_zig_version = "0.15.2",
.fingerprint = 0x773a47f1ef0097c1,
.paths = .{
"build.zig",
Expand Down
3 changes: 2 additions & 1 deletion test_zigpkg/build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@ pub fn build(b: *std.Build) void {
.optimize = optimize,
});

const lib = b.addStaticLibrary(.{
const lib = b.addLibrary(.{
.name = "openssl",
.linkage = .static,
.root_module = mod_openssl,
});

Expand Down
Loading