android target + APK pipeline; LSP imports honor stdlib paths
Android (toolchain):
--target android / --target android-arm64 → aarch64-linux-android21.
target.zig discovers $ANDROID_NDK_HOME (or scans
~/Library/Android/sdk/ndk/* for the newest), invokes the NDK clang
with -shared -fPIC and links libsxhello.so against -llog -landroid
-lEGL -lGLESv3 -lm -ldl. native_app_glue.c from the NDK is compiled
and linked alongside the sx .o so apps can use the conventional
android_main(struct android_app*) shape; -u ANativeActivity_onCreate
keeps glue's symbol live.
Android (APK):
--apk <out> wraps the .so into a debug-signed installable APK.
target.zig discovers the SDK at $ANDROID_HOME (or
~/Library/Android/sdk), picks the newest build-tools + platforms,
generates a NativeActivity AndroidManifest.xml from --bundle-id,
packages via aapt2 link, appends the lib/ tree, zipalign, then
apksigner against ~/.android/debug.keystore (auto-generated via
keytool on first use). One command end-to-end:
sx build --target android --apk out.apk \\
--bundle-id co.swipelab.foo main.sx
Verified on Pixel 7 Pro: install + launch reaches android_main.
Compiler (entry-point linkage):
Top-level fn defs default to LLVM internal linkage and are lazily
lowered (only `main` was eagerly lowered before). Added
isExportedEntryName() — a small allowlist for names the OS loader
calls: `main`, `android_main`, `ANativeActivity_onCreate`,
`JNI_OnLoad`. These get eagerly lowered AND keep external linkage,
so they actually land in .dynsym.
LSP (imports):
DocumentStore now takes the install-discovered stdlib_paths and
forwards them into resolveImportPath, mirroring the compiler. Before
this, every `#import "modules/..."` resolved through the stdlib path
failed silently inside the LSP and identifiers from those modules
showed as `undefined variable`. Repro on label.sx: 1 false positive
before, 0 after.
This commit is contained in:
30
src/main.zig
30
src/main.zig
@@ -19,7 +19,7 @@ pub fn main(init: std.process.Init) !void {
|
||||
|
||||
// LSP subcommand doesn't need a file argument
|
||||
if (std.mem.eql(u8, command, "lsp")) {
|
||||
runLsp(allocator, io);
|
||||
runLsp(allocator, io, stdlib_paths);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -61,6 +61,10 @@ pub fn main(init: std.process.Init) !void {
|
||||
"arm64-apple-ios14.0-simulator"
|
||||
else if (std.mem.eql(u8, raw, "ios-sim-x86"))
|
||||
"x86_64-apple-ios14.0-simulator"
|
||||
else if (std.mem.eql(u8, raw, "android") or std.mem.eql(u8, raw, "android-arm64"))
|
||||
"aarch64-linux-android21"
|
||||
else if (std.mem.eql(u8, raw, "android-x86_64"))
|
||||
"x86_64-linux-android21"
|
||||
else
|
||||
raw;
|
||||
target_config.triple = (try allocator.dupeZ(u8, expanded)).ptr;
|
||||
@@ -92,6 +96,18 @@ pub fn main(init: std.process.Init) !void {
|
||||
i += 1;
|
||||
if (i >= args.len) { std.debug.print("error: --bundle requires a path (e.g. MyApp.app)\n", .{}); return; }
|
||||
target_config.bundle_path = args[i];
|
||||
} else if (std.mem.eql(u8, arg, "--apk")) {
|
||||
i += 1;
|
||||
if (i >= args.len) { std.debug.print("error: --apk requires a path (e.g. out.apk)\n", .{}); return; }
|
||||
target_config.apk_path = args[i];
|
||||
} else if (std.mem.eql(u8, arg, "--manifest")) {
|
||||
i += 1;
|
||||
if (i >= args.len) { std.debug.print("error: --manifest requires a path\n", .{}); return; }
|
||||
target_config.manifest_path = args[i];
|
||||
} else if (std.mem.eql(u8, arg, "--keystore")) {
|
||||
i += 1;
|
||||
if (i >= args.len) { std.debug.print("error: --keystore requires a path\n", .{}); return; }
|
||||
target_config.keystore_path = args[i];
|
||||
} else if (std.mem.eql(u8, arg, "--bundle-id")) {
|
||||
i += 1;
|
||||
if (i >= args.len) { std.debug.print("error: --bundle-id requires a value (e.g. co.swipelab.myapp)\n", .{}); return; }
|
||||
@@ -335,7 +351,7 @@ fn printUsage() void {
|
||||
, .{});
|
||||
}
|
||||
|
||||
fn runLsp(allocator: std.mem.Allocator, io: std.Io) void {
|
||||
fn runLsp(allocator: std.mem.Allocator, io: std.Io, stdlib_paths: []const []const u8) void {
|
||||
const Transport = sx.lsp.transport.Transport;
|
||||
const Server = sx.lsp.server.Server;
|
||||
|
||||
@@ -346,7 +362,7 @@ fn runLsp(allocator: std.mem.Allocator, io: std.Io) void {
|
||||
var stdin_reader = stdin_file.readerStreaming(io, &read_buf);
|
||||
|
||||
var transport = Transport.init(allocator, io, &stdin_reader.interface, stdout_file);
|
||||
var server = Server.init(allocator, &transport, io);
|
||||
var server = Server.init(allocator, &transport, io, stdlib_paths);
|
||||
|
||||
while (true) {
|
||||
const msg = transport.readMessage() catch |err| {
|
||||
@@ -583,6 +599,14 @@ fn compileWithTimer(allocator: std.mem.Allocator, io: std.Io, input_path: []cons
|
||||
std.debug.print("bundled: {s}\n", .{bp});
|
||||
}
|
||||
|
||||
// Wrap into an .apk if requested (Android).
|
||||
if (merged_config.apk_path) |ap| {
|
||||
timer.mark();
|
||||
sx.target.createApk(allocator, io, final_output, merged_config) catch std.process.exit(1);
|
||||
timer.record("apk");
|
||||
std.debug.print("apk: {s}\n", .{ap});
|
||||
}
|
||||
|
||||
// Post-process wasm HTML: inject content hash for cache busting
|
||||
if (merged_config.isEmscripten() and std.mem.endsWith(u8, final_output, ".html")) {
|
||||
sx.target.postProcessWasmHtml(allocator, io, final_output);
|
||||
|
||||
Reference in New Issue
Block a user