Closed 20kano closed 1 year ago
Yes. It worked just by modifying this part.
.
├── android_res
│ ├── drawable-hdpi
│ │ └── ic_launcher.png
│ ├── drawable-ldpi
│ │ └── ic_launcher.png
│ ├── drawable-mdpi
│ │ └── ic_launcher.png
│ └── drawable-xhdpi
│ └── ic_launcher.png
├── build.zig
└── src
├── sgl.zig
└── sokol -> /link/to/sokol-zig/src/sokol
sgl.zig
//------------------------------------------------------------------------------
// sgl.zig
//
// sokol_gl.h / sokol.sgl sample program.
//------------------------------------------------------------------------------
const sokol = @import("sokol/sokol.zig");
// No modification.
export fn sokol_main() sapp.Desc {
return .{
.init_cb = init,
.frame_cb = frame,
.cleanup_cb = cleanup,
.width = 512,
.height = 512,
.sample_count = 4,
.icon = .{ .sokol_default = true },
.window_title = "sgl.zig",
.logger = .{ .func = slog.func },
};
}
Only for my environment though..
build.zig
const std = @import("std");
pub fn build(b: *std.Build) void {
build_android(b, "src/sgl.zig", .{
.app_name = "SokolAndroidZig",
.app_pkg = "com.example.sokolandroidzig",
.lib_name = "sokolandroidzig"
});
}
const AndroidBuildParams = struct {
app_name: []const u8,
lib_name: []const u8,
app_pkg: []const u8,
sdk: []const u8 = "/opt/android-sdk",
api_level: []const u8 = "23",
pub fn platform(comptime abp: AndroidBuildParams) []const u8 {
return abp.sdk ++ "/platforms/android-" ++ abp.api_level ++ "/android.jar";
}
pub fn build_tools(comptime abp: AndroidBuildParams, comptime bin: []const u8) []const u8{
return abp.sdk ++ "/build-tools/30.0.3/" ++ bin;
}
pub fn ndk(comptime abp: AndroidBuildParams) []const u8 {
return abp.sdk ++ "/ndk/25.1.8937393";
}
pub fn llvm(comptime abp: AndroidBuildParams) []const u8 {
return abp.ndk() ++ "/toolchains/llvm/prebuilt/linux-x86_64";
}
pub fn ndk_sysroot(comptime abp: AndroidBuildParams) []const u8 {
return abp.llvm() ++ "/sysroot";
}
pub fn cc(comptime abp: AndroidBuildParams) []const u8 {
return abp.llvm() ++ "/bin/armv7a-linux-androideabi" ++ abp.api_level ++ "-clang";
}
pub fn cxx(comptime abp: AndroidBuildParams) []const u8 {
return abp.llvm() ++ "/bin/armv7a-linux-androideabi" ++ abp.api_level ++ "-clang++";
}
pub fn ar(comptime abp: AndroidBuildParams) []const u8 {
return abp.llvm() ++ "/bin/llvm-ar";
}
pub const ANDROID_RES_DIR = "android_res/";
pub const BUILD_DIR = "build_android";
pub const BUILD_JAVA_GEN_DIR = BUILD_DIR ++ "/gen"; // R.java
pub const BUILD_JAVA_OBJ_DIR = BUILD_DIR ++ "/obj";
pub const BUILD_APK_DIR = BUILD_DIR ++ "/apk";
pub const BUILD_APK_LIB_DIR = BUILD_APK_DIR ++ "/lib/armeabi-v7a";
fn getTarget() std.zig.CrossTarget {
return .{
.cpu_arch = .arm,
.os_tag = .linux,
.abi = .android,
.cpu_model = .baseline,
.cpu_features_add = std.Target.arm.featureSet(&.{.v7a}),
};
}
};
fn build_android(
b: *std.Build,
root_source_file: []const u8,
comptime abp: AndroidBuildParams
) void{
const dir = std.fs.cwd();
dir.makePath(AndroidBuildParams.BUILD_JAVA_GEN_DIR) catch unreachable;
dir.makePath(AndroidBuildParams.BUILD_JAVA_OBJ_DIR) catch unreachable;
dir.makePath(AndroidBuildParams.BUILD_APK_DIR) catch unreachable;
dir.makePath(AndroidBuildParams.BUILD_APK_LIB_DIR) catch unreachable;
compile(b, abp, root_source_file);
const package_step = package(b, abp);
const deploy_step = deploy(b, package_step, abp);
const build_run = b.step("run", "install apk to device and start app.");
build_run.dependOn(&deploy_step.step);
}
fn build_sokol(
b: *std.Build,
optimize: std.builtin.Mode,
target: std.zig.CrossTarget,
comptime prefix_path: []const u8,
comptime android: AndroidBuildParams,
) *std.Build.CompileStep {
var lib = b.addStaticLibrary(.{
.name = "sokol",
.optimize = optimize,
.target = target,
});
const sokol_path = prefix_path ++ "/c/";
// std.debug.print("sokol_path = {s}\n", .{sokol_path});
const csources = [_][]const u8 {
"sokol_app.c",
"sokol_gfx.c",
"sokol_gl.c",
"sokol_log.c",
"sokol_debugtext.c",
// "sokol_fontstash.c",
};
lib.linkLibC();
inline for (csources) |csrc| {
lib.addCSourceFile(sokol_path ++ csrc, &[_][]const u8{
"-DIMPL", "-D__ANDROID__", "-DSOKOL_GLES3", "-DSOKOL_DEBUG",
});
}
// 'asm/types.h'
lib.addIncludePath(comptime android.ndk_sysroot() ++ "/usr/include/arm-linux-androideabi");
setAndroidLibC(b, lib, android.ndk_sysroot(), android.api_level);
lib.linkSystemLibrary("android");
lib.linkSystemLibrary("GLESv3");
lib.linkSystemLibrary("EGL");
lib.linkSystemLibrary("log");
return lib;
}
fn setAndroidLibC(
b: *std.Build,
lib: *std.Build.CompileStep,
comptime ndk_sysroot: []const u8,
comptime api_level: []const u8
) void {
const s = "include_dir=" ++ ndk_sysroot ++ "/usr/include\n" ++
"sys_include_dir=" ++ ndk_sysroot ++ "/usr/include\n" ++
"crt_dir=" ++ ndk_sysroot ++ "/usr/lib/arm-linux-androideabi/" ++ api_level ++ "\n" ++
"msvc_lib_dir=\n" ++
"kernel32_lib_dir=\n" ++
"gcc_dir=\n";
// std.debug.print("{s}\n",.{s});
const fname = "android-" ++ api_level ++ "-armeabi.conf";
const step = b.addWriteFile(fname, s);
lib.setLibCFile(step.getFileSource(fname) orelse unreachable);
lib.libc_file.?.addStepDependencies(&lib.step);
lib.linkLibC();
}
fn compile(
b: *std.Build,
comptime abp: AndroidBuildParams,
root_source_file: []const u8
) void {
const mode = b.standardOptimizeOption(.{});
const target = AndroidBuildParams.getTarget();
// apk/lib/arm/xxxx.so はsheared-library
const so = b.addSharedLibrary(.{
.name = abp.lib_name,
.root_source_file = .{.path = root_source_file},
.optimize = mode,
.target = target,
});
setAndroidLibC(b, so, abp.ndk_sysroot(), abp.api_level);
const sokol_lib = build_sokol(b, mode, target, "src/sokol", abp);
so.linkLibrary(sokol_lib);
so.install();
}
fn package(b: *std.Build, comptime abp: AndroidBuildParams) *std.Build.RunStep {
const copy_lib = b.addSystemCommand(&[_][]const u8{
"cp",
b.fmt("zig-out/lib/lib{s}.so", .{abp.lib_name}),
b.fmt("{s}/lib{s}.so", .{AndroidBuildParams.BUILD_APK_LIB_DIR, abp.lib_name})
});
copy_lib.step.dependOn(b.getInstallStep());
const manifest_step = b.addWriteFile("AndroidManifest.xml", blk: {
var buf = std.ArrayList(u8).init(b.allocator);
errdefer buf.deinit();
var writer = buf.writer();
writer.print(
\\<manifest xmlns:android="http://schemas.android.com/apk/res/android"
\\ package="{s}"
\\ android:versionCode="1"
\\ android:versionName="1.0">
\\ <uses-sdk android:minSdkVersion="{s}" android:targetSdkVersion="{s}"/>
\\ <uses-feature android:glEsVersion="0x00030000" />
\\ <application
\\ android:label="{s}"
\\ android:hasCode="false"
\\ android:debuggable="true"
\\ android:theme="@android:style/Theme.NoTitleBar.Fullscreen">
\\ <activity
\\ android:name="android.app.NativeActivity"
\\ android:label="{s}"
\\ android:configChanges="orientation|screenSize|keyboard|keyboardHidden"
\\ android:exported="true"
\\ android:launchMode="singleTask"
\\ android:screenOrientation="fullUser">
\\ <meta-data android:name="android.app.lib_name" android:value="{s}"/>
\\ <intent-filter>
\\ <action android:name="android.intent.action.MAIN"/>
\\ <category android:name="android.intent.category.LAUNCHER"/>
\\ </intent-filter>
\\ </activity>
\\ </application>
\\</manifest>
, .{abp.app_pkg, abp.api_level, abp.api_level, abp.app_name, abp.app_name, abp.lib_name}) catch unreachable;
break :blk buf.toOwnedSlice() catch unreachable;
});
const gen_res = b.addSystemCommand(&[_][]const u8{
abp.build_tools("aapt") , "package", "-v", "-f",
"-m", "-J", AndroidBuildParams.BUILD_JAVA_GEN_DIR,
"-S", AndroidBuildParams.ANDROID_RES_DIR,
"-I", abp.platform(),
});
gen_res.addArg("-M");
gen_res.addFileSourceArg(manifest_step.getFileSource("AndroidManifest.xml").?);
gen_res.step.dependOn(©_lib.step);
const len = abp.app_pkg.len;
var PKG_DIR: [len]u8 = undefined;
_ = std.mem.replace(u8, abp.app_pkg, ".", "/", PKG_DIR[0..]);
const javac = b.addSystemCommand(&[_][]const u8{
"javac", "-verbose", "-source", "1.7", "-target", "1.7",
"-bootclasspath", abp.platform(),
"-d", AndroidBuildParams.BUILD_JAVA_OBJ_DIR,
b.fmt("{s}/{s}/R.java", .{AndroidBuildParams.BUILD_JAVA_GEN_DIR, PKG_DIR}),
});
javac.step.dependOn(&gen_res.step);
const dx = b.addSystemCommand(&[_][]const u8{
abp.build_tools("dx"), "--verbose", "--dex",
b.fmt("--output={s}/classes.dex", .{AndroidBuildParams.BUILD_APK_DIR}),
AndroidBuildParams.BUILD_JAVA_OBJ_DIR
});
dx.step.dependOn(&javac.step);
const packageApk = b.addSystemCommand(&[_][]const u8{
abp.build_tools("aapt"), "package", "-v", "-f",
"-S", AndroidBuildParams.ANDROID_RES_DIR,
"-I", abp.platform(),
"-F", b.fmt("{s}/{s}.unaligned.apk", .{AndroidBuildParams.BUILD_DIR, abp.app_name}),
// AndroidBuildParams.BUILD_APK_DIR,
});
packageApk.addArg("-M");
packageApk.addFileSourceArg(manifest_step.getFileSource("AndroidManifest.xml").?);
packageApk.addArg(AndroidBuildParams.BUILD_APK_DIR);
packageApk.step.dependOn(&dx.step);
const addLibToApk = b.addSystemCommand(&[_][]const u8{
abp.build_tools("aapt"), "add", "-v",
b.fmt("{s}/{s}.unaligned.apk", .{AndroidBuildParams.BUILD_DIR, abp.app_name}),
b.fmt("{s}/lib/armeabi-v7a/lib{s}.so", .{AndroidBuildParams.BUILD_APK_DIR, abp.lib_name})
});
addLibToApk.step.dependOn(&packageApk.step);
const zipalign = b.addSystemCommand(&[_][]const u8{
abp.build_tools("zipalign"), "-v", "-f", "4",
b.fmt("{s}/{s}.unaligned.apk", .{AndroidBuildParams.BUILD_DIR, abp.app_name}),
b.fmt("{s}/{s}.apk", .{AndroidBuildParams.BUILD_DIR, abp.app_name})
});
zipalign.step.dependOn(&addLibToApk.step);
const signApk = b.addSystemCommand(&[_][]const u8{
abp.build_tools("apksigner"), "sign", "-v",
"--ks", "/home/example/.android/debug.keystore",
"--v4-signing-enabled", "false",
"--ks-pass", "pass:android",
b.fmt("{s}/{s}.apk", .{AndroidBuildParams.BUILD_DIR, abp.app_name})
});
signApk.step.dependOn(&zipalign.step);
const cleanup = b.addSystemCommand(&[_][]const u8{
"rm",
b.fmt("{s}/{s}.unaligned.apk", .{AndroidBuildParams.BUILD_DIR, abp.app_name}),
});
cleanup.step.dependOn(&signApk.step);
return cleanup;
}
fn deploy(
b: *std.Build,
package_step: *std.Build.RunStep,
comptime abp: AndroidBuildParams
) *std.Build.RunStep {
const installApk = b.addSystemCommand(&[_][]const u8{
"adb", "install", "-r", b.fmt("{s}/{s}.apk", .{AndroidBuildParams.BUILD_DIR, abp.app_name})
});
installApk.step.dependOn(&package_step.step);
const startApp = b.addSystemCommand(&[_][]const u8{
"adb", "shell", "am", "start", "--activity-clear-top", "-n",
b.fmt("{s}/android.app.NativeActivity", .{abp.app_pkg})
});
startApp.step.dependOn(&installApk.step);
return startApp;
}
However, I do not know how to do memory management.
Ok merged. Many thanks! (also for the build.zig, very interesting)
Did you manage to get something working on Android?