Skip to content

Commit 0fca4c7

Browse files
committed
Support extra default app build targets
1 parent d66ca78 commit 0fca4c7

4 files changed

Lines changed: 146 additions & 21 deletions

File tree

src/backend/llvm/MonoLlvmCodeGen.zig

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -997,14 +997,12 @@ pub const MonoLlvmCodeGen = struct {
997997
const file = try self.debugFileFor(builder, self.current_debug_file);
998998
const empty_expr = builder.debugExpression(&.{}) catch return error.OutOfMemory;
999999
const previous_debug_location = wip.debug_location;
1000-
if (self.enable_default_platform_diagnostics) {
1001-
wip.debug_location = .{ .location = .{
1002-
.line = proc_line,
1003-
.column = if (proc_line == 0) 0 else 1,
1004-
.scope = scope.toOptional(),
1005-
.inlined_at = .none,
1006-
} };
1007-
}
1000+
wip.debug_location = .{ .location = .{
1001+
.line = if (self.enable_default_platform_diagnostics) proc_line else 0,
1002+
.column = if (self.enable_default_platform_diagnostics and proc_line != 0) 1 else 0,
1003+
.scope = scope.toOptional(),
1004+
.inlined_at = .none,
1005+
} };
10081006
defer wip.debug_location = previous_debug_location;
10091007

10101008
for (self.store.getLocalSpan(proc.frame_locals)) |local_id| {

src/cli/main.zig

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3643,19 +3643,22 @@ fn rocBuildDefaultApp(ctx: *CliCtx, args: cli_args.BuildArgs, original_source: [
36433643
}
36443644

36453645
fn defaultBuildPlatformSource(args: cli_args.BuildArgs) []const u8 {
3646-
const target = if (args.target) |target_str|
3647-
RocTarget.fromString(target_str)
3648-
else
3649-
RocTarget.detectNative();
3646+
if (args.target) |target_str| {
3647+
if (RocTarget.fromString(target_str)) |target| {
3648+
return switch (target) {
3649+
.x64glibc, .arm64glibc, .x64mac, .arm64mac, .x64win, .arm64win => echo_platform.build_c_platform_main_source,
3650+
.wasm32 => echo_platform.build_wasm_archive_platform_main_source,
3651+
else => echo_platform.build_platform_main_source,
3652+
};
3653+
}
36503654

3651-
if (target) |roc_build_target| {
3652-
return switch (roc_build_target.toOsTag()) {
3653-
.macos, .windows => echo_platform.build_c_platform_main_source,
3654-
else => echo_platform.build_platform_main_source,
3655-
};
3655+
return echo_platform.build_platform_main_source;
36563656
}
36573657

3658-
return echo_platform.build_platform_main_source;
3658+
return switch (RocTarget.detectNative().toOsTag()) {
3659+
.macos, .windows => echo_platform.build_c_platform_main_source,
3660+
else => echo_platform.build_platform_main_source,
3661+
};
36593662
}
36603663

36613664
/// Build using the dev backend to generate native machine code.
@@ -5022,7 +5025,10 @@ fn rocBuildLlvm(ctx: *CliCtx, args: cli_args.BuildArgs) anyerror!void {
50225025
);
50235026
} else {
50245027
const hosted_symbols = try hostedSymbolsFromLir(ctx.arena, &lowered.lir_result.store);
5025-
const enable_default_platform_runtime = target_os == .linux and args.synthetic_default_platform;
5028+
const enable_default_platform_runtime = args.synthetic_default_platform and switch (target) {
5029+
.x64musl, .arm64musl => true,
5030+
else => false,
5031+
};
50265032

50275033
const app_object = try compileLlvmAppObject(
50285034
ctx,

src/cli/test/parallel_cli_runner.zig

Lines changed: 94 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,9 @@ const CustomCase = enum {
172172
generated_graph_200_5,
173173
list_builtin_inlined,
174174
default_platform_linux_disassembly,
175+
default_platform_build_x64glibc,
176+
default_platform_build_arm64glibc,
177+
default_platform_build_wasm32,
175178
default_platform_crash_x64musl,
176179
default_platform_crash_arm64musl,
177180
default_platform_crash_x64mac,
@@ -528,6 +531,9 @@ const subcommand_cases = [_]CliCase{
528531
.{ .id = 0, .suite = .subcommands, .name = "roc check generated module graph handles many imported files", .body = .{ .custom = .generated_graph_200_5 } },
529532
.{ .id = 0, .suite = .subcommands, .name = "list builtins inline in native --opt=speed build", .body = .{ .custom = .list_builtin_inlined } },
530533
.{ .id = 0, .suite = .subcommands, .name = "roc build default platform x64musl matches direct write assembly", .skip = .{ .always = "TODO: direct-write default-platform codegen" }, .body = .{ .custom = .default_platform_linux_disassembly } },
534+
.{ .id = 0, .suite = .subcommands, .name = "roc build default platform x64glibc succeeds", .body = .{ .custom = .default_platform_build_x64glibc } },
535+
.{ .id = 0, .suite = .subcommands, .name = "roc build default platform arm64glibc succeeds", .body = .{ .custom = .default_platform_build_arm64glibc } },
536+
.{ .id = 0, .suite = .subcommands, .name = "roc build default platform wasm32 archive succeeds", .body = .{ .custom = .default_platform_build_wasm32 } },
531537
.{ .id = 0, .suite = .subcommands, .name = "default platform crash prints debug backtrace on x64musl", .body = .{ .custom = .default_platform_crash_x64musl } },
532538
.{ .id = 0, .suite = .subcommands, .name = "default platform crash prints debug backtrace on arm64musl", .body = .{ .custom = .default_platform_crash_arm64musl } },
533539
.{ .id = 0, .suite = .subcommands, .name = "default platform crash prints debug backtrace on x64mac", .body = .{ .custom = .default_platform_crash_x64mac } },
@@ -1397,6 +1403,9 @@ fn runCustomCase(
13971403
.generated_graph_200_5 => customGeneratedModuleGraph(io, allocator, &env, &timer, timeout_ms, .{ .roc_file_count = 200, .symbols_per_file = 5 }),
13981404
.list_builtin_inlined => customListBuiltinInlined(io, allocator, &env, &timer, timeout_ms),
13991405
.default_platform_linux_disassembly => customDefaultPlatformLinuxDisassembly(io, allocator, &env, &timer, timeout_ms),
1406+
.default_platform_build_x64glibc => customDefaultPlatformBuild(io, allocator, &env, &timer, timeout_ms, .x64glibc),
1407+
.default_platform_build_arm64glibc => customDefaultPlatformBuild(io, allocator, &env, &timer, timeout_ms, .arm64glibc),
1408+
.default_platform_build_wasm32 => customDefaultPlatformBuild(io, allocator, &env, &timer, timeout_ms, .wasm32),
14001409
.default_platform_crash_x64musl => customDefaultPlatformDebugBacktrace(io, allocator, &env, &timer, timeout_ms, .x64musl, .crash),
14011410
.default_platform_crash_arm64musl => customDefaultPlatformDebugBacktrace(io, allocator, &env, &timer, timeout_ms, .arm64musl, .crash),
14021411
.default_platform_crash_x64mac => customDefaultPlatformDebugBacktrace(io, allocator, &env, &timer, timeout_ms, .x64mac, .crash),
@@ -1719,20 +1728,30 @@ fn isHexDigit(byte: u8) bool {
17191728
const DefaultPlatformTarget = enum {
17201729
x64musl,
17211730
arm64musl,
1731+
x64glibc,
1732+
arm64glibc,
17221733
x64mac,
17231734
arm64mac,
17241735
x64win,
17251736
arm64win,
1737+
wasm32,
17261738

17271739
fn cliName(self: DefaultPlatformTarget) []const u8 {
17281740
return @tagName(self);
17291741
}
17301742

1743+
fn canBuildOnHost(self: DefaultPlatformTarget) bool {
1744+
return switch (self) {
1745+
.x64glibc, .arm64glibc => builtin.os.tag == .linux,
1746+
else => true,
1747+
};
1748+
}
1749+
17311750
fn canRunOnHost(self: DefaultPlatformTarget) bool {
17321751
return switch (builtin.os.tag) {
17331752
.linux => switch (builtin.cpu.arch) {
1734-
.x86_64 => self == .x64musl,
1735-
.aarch64 => self == .arm64musl,
1753+
.x86_64 => self == .x64musl or self == .x64glibc,
1754+
.aarch64 => self == .arm64musl or self == .arm64glibc,
17361755
else => false,
17371756
},
17381757
.macos => switch (builtin.cpu.arch) {
@@ -1745,6 +1764,7 @@ const DefaultPlatformTarget = enum {
17451764
.aarch64 => self == .arm64win,
17461765
else => false,
17471766
},
1767+
.freestanding => false,
17481768
else => false,
17491769
};
17501770
}
@@ -1799,6 +1819,78 @@ const default_platform_stack_overflow_debug_app =
17991819
\\
18001820
;
18011821

1822+
const default_platform_echo_app =
1823+
\\main! = |_| {
1824+
\\ echo!("Hello, World!")
1825+
\\ Ok({})
1826+
\\}
1827+
\\
1828+
;
1829+
1830+
fn customDefaultPlatformBuild(
1831+
io: std.Io,
1832+
allocator: Allocator,
1833+
env: *const CaseEnv,
1834+
timer: *harness.Timer,
1835+
timeout_ms: u64,
1836+
target: DefaultPlatformTarget,
1837+
) ?TestResult {
1838+
if (!target.canBuildOnHost()) {
1839+
const message = std.fmt.allocPrint(
1840+
allocator,
1841+
"{s} default-platform build requires Linux host support",
1842+
.{target.cliName()},
1843+
) catch "default-platform build requires Linux host support";
1844+
return .{ .status = .skip, .phase = .setup, .duration_ns = timer.read(), .message = message };
1845+
}
1846+
1847+
const app_filename = std.fmt.allocPrint(allocator, "default_platform_build_{s}.roc", .{target.cliName()}) catch |err|
1848+
return customInfraFailure(allocator, timer, "failed to allocate default platform app filename: {}", .{err});
1849+
const app_path = std.fs.path.join(allocator, &.{ env.dirs.work_dir, app_filename }) catch |err|
1850+
return customInfraFailure(allocator, timer, "failed to allocate default platform app path: {}", .{err});
1851+
const output_path = std.fs.path.join(allocator, &.{ env.dirs.work_dir, "default_platform_build" }) catch |err|
1852+
return customInfraFailure(allocator, timer, "failed to allocate default platform output path: {}", .{err});
1853+
const target_arg = std.fmt.allocPrint(allocator, "--target={s}", .{target.cliName()}) catch |err|
1854+
return customInfraFailure(allocator, timer, "failed to allocate target arg: {}", .{err});
1855+
const out_arg = outputArg(allocator, output_path) catch |err|
1856+
return customInfraFailure(allocator, timer, "failed to allocate output arg: {}", .{err});
1857+
1858+
std.Io.Dir.cwd().writeFile(io, .{ .sub_path = app_path, .data = default_platform_echo_app }) catch |err|
1859+
return customInfraFailure(allocator, timer, "failed to write default platform app: {}", .{err});
1860+
1861+
if (runRocAndCheck(io, allocator, env, timer, timeout_ms, .{
1862+
.args = &.{ "build", "--opt=speed", "--no-cache", target_arg, out_arg },
1863+
.roc_file = app_path,
1864+
.contains = &.{.{ .stream = .stdout, .text = "Built " }},
1865+
})) |failure| return failure;
1866+
1867+
if (target == .wasm32) {
1868+
var file = std.Io.Dir.cwd().openFile(io, output_path, .{ .mode = .read_only }) catch |err|
1869+
return customInfraFailure(allocator, timer, "failed to open built wasm archive: {}", .{err});
1870+
defer file.close(io);
1871+
1872+
var magic: [8]u8 = undefined;
1873+
const bytes_read = file.readPositionalAll(io, &magic, 0) catch |err|
1874+
return customInfraFailure(allocator, timer, "failed to read built wasm archive: {}", .{err});
1875+
if (bytes_read != magic.len or !std.mem.eql(u8, magic[0..], "!<arch>\n")) {
1876+
return customFailure(allocator, timer, "wasm32 default platform output was not an archive", .{});
1877+
}
1878+
}
1879+
1880+
if (target.canRunOnHost()) {
1881+
const executable_path = runnableOutputPath(io, allocator, output_path) catch |err|
1882+
return customInfraFailure(allocator, timer, "failed to find built executable: {}", .{err});
1883+
1884+
if (runRawAndCheck(io, allocator, env, timer, timeout_ms, &.{executable_path}, env.dirs.work_dir, .{
1885+
.args = &.{},
1886+
.stdout_exact = "Hello, World!\n",
1887+
.stderr_exact = "",
1888+
})) |failure| return failure;
1889+
}
1890+
1891+
return null;
1892+
}
1893+
18021894
fn customDefaultPlatformDebugBacktrace(
18031895
io: std.Io,
18041896
allocator: Allocator,

src/echo_platform/mod.zig

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ pub const build_c_platform_main_source =
5858
\\ hosted { "roc_default_echo_line": Echo.line! }
5959
\\ targets: {
6060
\\ inputs: "targets/",
61+
\\ x64glibc: { inputs: [app] },
62+
\\ arm64glibc: { inputs: [app] },
6163
\\ x64mac: { inputs: [app] },
6264
\\ arm64mac: { inputs: [app] },
6365
\\ x64win: { inputs: [app] },
@@ -76,6 +78,33 @@ pub const build_c_platform_main_source =
7678
\\
7779
;
7880

81+
/// Build-only default platform for hostless wasm output. Without a platform
82+
/// host object there is no process entrypoint or stdout, so wasm default apps
83+
/// compile to an archive that a host can link and satisfy.
84+
pub const build_wasm_archive_platform_main_source =
85+
\\platform ""
86+
\\ requires {} { main! : List(Str) => Try({}, [Exit(I8), ..]) }
87+
\\ exposes [Echo]
88+
\\ packages {}
89+
\\ provides { "main": main_for_host! }
90+
\\ hosted { "roc_default_echo_line": Echo.line! }
91+
\\ targets: {
92+
\\ inputs: "targets/",
93+
\\ wasm32: { inputs: [app], output: Archive },
94+
\\ }
95+
\\
96+
\\import Echo
97+
\\
98+
\\main_for_host! : {} => I32
99+
\\main_for_host! = |_args|
100+
\\ match main!([]) {
101+
\\ Ok({}) => 0
102+
\\ Err(Exit(code)) => I8.to_i32(code)
103+
\\ Err(_) => 1
104+
\\ }
105+
\\
106+
;
107+
79108
/// Echo platform environment, passed as RocOps.env.
80109
/// On WASM the std_io field is unused (undefined); on native it holds the
81110
/// std.Io obtained from the process init or the global single-threaded I/O.

0 commit comments

Comments
 (0)