@@ -257,6 +257,23 @@ const BuiltinsObjects = struct {
257257 }
258258};
259259
260+ const DefaultPlatformRuntimeObjects = struct {
261+ const x64musl = if (builtin .is_test ) &[_ ]u8 {} else @embedFile ("targets/x64musl/roc_default_platform.o" );
262+ const arm64musl = if (builtin .is_test ) &[_ ]u8 {} else @embedFile ("targets/arm64musl/roc_default_platform.o" );
263+
264+ pub fn forTarget (target : RocTarget ) ? []const u8 {
265+ return switch (target ) {
266+ .x64musl = > x64musl ,
267+ .arm64musl = > arm64musl ,
268+ else = > null ,
269+ };
270+ }
271+
272+ pub fn filename () []const u8 {
273+ return "roc_default_platform.o" ;
274+ }
275+ };
276+
260277// Workaround for Zig standard library compilation issue on macOS ARM64.
261278//
262279// The Problem:
@@ -1814,6 +1831,7 @@ fn rocRun(ctx: *CliCtx, args: cli_args.RunArgs) anyerror!void {
18141831 host_input_paths .items ,
18151832 try hostedSymbolsFromLir (ctx .arena , & view .store ),
18161833 target_name ,
1834+ false ,
18171835 );
18181836 }
18191837
@@ -3570,13 +3588,9 @@ fn rocBuild(ctx: *CliCtx, args: cli_args.BuildArgs) anyerror!void {
35703588 return ;
35713589 }
35723590
3573- // Headerless apps use a simple builtin platform and cannot be compiled
3591+ // Headerless apps build through a synthetic default platform.
35743592 if (try readDefaultAppSource (ctx , args .path )) | source | {
3575- ctx .gpa .free (source );
3576- try renderProblem (ctx .gpa , ctx .io .stderr (), .{
3577- .build_not_supported_for_headerless = .{ .app_path = args .path },
3578- });
3579- return error .UnsupportedTarget ;
3593+ return rocBuildDefaultApp (ctx , args , source );
35803594 }
35813595
35823596 // Select build path based on optimization level
@@ -3587,6 +3601,63 @@ fn rocBuild(ctx: *CliCtx, args: cli_args.BuildArgs) anyerror!void {
35873601 }
35883602}
35893603
3604+ fn rocBuildDefaultApp (ctx : * CliCtx , args : cli_args.BuildArgs , original_source : []const u8 ) anyerror ! void {
3605+ defer ctx .gpa .free (original_source );
3606+
3607+ const temp_dir = createUniqueTempDir (ctx ) catch | err | {
3608+ return ctx .fail (.{ .temp_dir_failed = .{ .err = err } });
3609+ };
3610+ defer std .Io .Dir .cwd ().deleteTree (ctx .io .std_io , temp_dir ) catch {};
3611+
3612+ const platform_dir = try std .fs .path .join (ctx .arena , &.{ temp_dir , ".roc_echo_platform" });
3613+ try std .Io .Dir .cwd ().createDirPath (ctx .io .std_io , platform_dir );
3614+
3615+ const app_filename = std .fs .path .basename (args .path );
3616+ const app_path = try std .fs .path .join (ctx .arena , &.{ temp_dir , app_filename });
3617+ const platform_main_path = try std .fs .path .join (ctx .arena , &.{ platform_dir , "main.roc" });
3618+ const echo_module_path = try std .fs .path .join (ctx .arena , &.{ platform_dir , "Echo.roc" });
3619+
3620+ const header =
3621+ "app [main!] { pf: platform \" ./.roc_echo_platform/main.roc\" }\n\n " ++
3622+ "import pf.Echo\n\n " ++
3623+ "echo! = |msg| Echo.line!(msg)\n\n " ;
3624+ const synthetic_source = try std .mem .concat (ctx .gpa , u8 , &.{ header , original_source });
3625+ defer ctx .gpa .free (synthetic_source );
3626+
3627+ try std .Io .Dir .cwd ().writeFile (ctx .io .std_io , .{ .sub_path = app_path , .data = synthetic_source });
3628+ try std .Io .Dir .cwd ().writeFile (ctx .io .std_io , .{ .sub_path = platform_main_path , .data = defaultBuildPlatformSource (args ) });
3629+ try std .Io .Dir .cwd ().writeFile (ctx .io .std_io , .{ .sub_path = echo_module_path , .data = echo_platform .echo_module_source });
3630+
3631+ var synthetic_args = args ;
3632+ synthetic_args .path = app_path ;
3633+ synthetic_args .synthetic_default_platform = true ;
3634+ if (synthetic_args .output == null ) {
3635+ synthetic_args .output = try base .module_path .getModuleNameAlloc (ctx .arena , args .path );
3636+ }
3637+
3638+ switch (synthetic_args .opt ) {
3639+ .dev = > try rocBuildNative (ctx , synthetic_args ),
3640+ .interpreter = > try rocBuildEmbedded (ctx , synthetic_args ),
3641+ .size , .speed = > try rocBuildLlvm (ctx , synthetic_args ),
3642+ }
3643+ }
3644+
3645+ 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 ();
3650+
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+ };
3656+ }
3657+
3658+ return echo_platform .build_platform_main_source ;
3659+ }
3660+
35903661/// Build using the dev backend to generate native machine code.
35913662/// This produces truly compiled executables without an interpreter.
35923663fn nativeBuildEntrypoints (
@@ -3764,7 +3835,12 @@ fn verifyHostInputSymbols(
37643835 host_input_paths : []const []const u8 ,
37653836 hosted_symbols : []const []const u8 ,
37663837 target_name : []const u8 ,
3838+ synthetic_default_platform : bool ,
37673839) anyerror ! void {
3840+ if (host_input_paths .len == 0 and synthetic_default_platform ) {
3841+ return ;
3842+ }
3843+
37683844 var needed = std .ArrayList ([]const u8 ).empty ;
37693845 try needed .appendSlice (ctx .arena , & host_symbols .runtime_symbols );
37703846 try needed .appendSlice (ctx .arena , hosted_symbols );
@@ -3778,6 +3854,16 @@ fn verifyHostInputSymbols(
37783854 }
37793855}
37803856
3857+ fn writeDefaultPlatformRuntimeObject (ctx : * CliCtx , build_cache_dir : []const u8 , target : RocTarget ) anyerror ! ? []const u8 {
3858+ const bytes = DefaultPlatformRuntimeObjects .forTarget (target ) orelse return null ;
3859+ const runtime_path = try std .fs .path .join (ctx .arena , &.{ build_cache_dir , DefaultPlatformRuntimeObjects .filename () });
3860+ backend .writeFileWindowsAvSafe (ctx .io .std_io , runtime_path , bytes ) catch | err | {
3861+ std .log .err ("Failed to write default platform runtime object {s}: {}" , .{ runtime_path , err });
3862+ return err ;
3863+ };
3864+ return runtime_path ;
3865+ }
3866+
37813867/// The host inputs of a link, in link order.
37823868fn hostInputPaths (ctx : * CliCtx , link_inputs : PlatformLinkInputs ) std.mem.Allocator.Error ! []const []const u8 {
37833869 var paths = try std .array_list .Managed ([]const u8 ).initCapacity (
@@ -4459,6 +4545,8 @@ fn compileLlvmAppObject(
44594545 link_type : roc_target.OutputKind ,
44604546 lowered : * const lir.CheckedPipeline.LoweredProgram ,
44614547 entrypoints : []const backend.Entrypoint ,
4548+ enable_default_platform_runtime : bool ,
4549+ enable_default_platform_hosted_calls : bool ,
44624550) anyerror ! LlvmObjectPaths {
44634551 const std_target = try stdTargetForLlvmBuild (ctx , target );
44644552 const llvm_cpu = llvmCpuNameForTarget (std_target );
@@ -4471,6 +4559,9 @@ fn compileLlvmAppObject(
44714559 );
44724560 codegen .layout_store = & lowered .lir_result .layouts ;
44734561 codegen .emit_debug_info = true ;
4562+ codegen .enable_default_platform_runtime = enable_default_platform_runtime ;
4563+ codegen .enable_default_platform_hosted_calls = enable_default_platform_hosted_calls ;
4564+ codegen .enable_default_platform_diagnostics = enable_default_platform_hosted_calls and args .debug ;
44744565 codegen .debug_producer = "roc " ++ build_options .compiler_version ;
44754566 defer codegen .deinit ();
44764567
@@ -4624,7 +4715,7 @@ fn rocBuildWasmLlvm(
46244715 unreachable ;
46254716 }
46264717
4627- const app_object = try compileLlvmAppObject (ctx , args , build_cache_dir , .wasm32 , link_type , lowered , entrypoints );
4718+ const app_object = try compileLlvmAppObject (ctx , args , build_cache_dir , .wasm32 , link_type , lowered , entrypoints , false , false );
46284719
46294720 var owned_inputs : std .ArrayList ([]u8 ) = .empty ;
46304721 defer freeOwnedWasmInputs (ctx , & owned_inputs );
@@ -4890,6 +4981,7 @@ fn rocBuildLlvm(ctx: *CliCtx, args: cli_args.BuildArgs) anyerror!void {
48904981 .{
48914982 .target_usize = target_usize ,
48924983 .list_in_place_map = listInPlaceMapForOpt (args .opt ),
4984+ .proc_debug_names = args .synthetic_default_platform ,
48934985 },
48944986 );
48954987 defer lowered .deinit ();
@@ -4929,7 +5021,20 @@ fn rocBuildLlvm(ctx: *CliCtx, args: cli_args.BuildArgs) anyerror!void {
49295021 static_data_exports ,
49305022 );
49315023 } else {
4932- const app_object = try compileLlvmAppObject (ctx , args , build_cache_dir , target , link_type , & lowered , entrypoints );
5024+ 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 ;
5026+
5027+ const app_object = try compileLlvmAppObject (
5028+ ctx ,
5029+ args ,
5030+ build_cache_dir ,
5031+ target ,
5032+ link_type ,
5033+ & lowered ,
5034+ entrypoints ,
5035+ enable_default_platform_runtime ,
5036+ args .synthetic_default_platform ,
5037+ );
49335038
49345039 var static_data_obj_path : ? []const u8 = null ;
49355040 if (static_data_exports .len > 0 ) {
@@ -4952,15 +5057,23 @@ fn rocBuildLlvm(ctx: *CliCtx, args: cli_args.BuildArgs) anyerror!void {
49525057 if (static_data_obj_path ) | path | {
49535058 try object_files .append (path );
49545059 }
5060+ if (enable_default_platform_runtime ) {
5061+ if (try writeDefaultPlatformRuntimeObject (ctx , build_cache_dir , target )) | runtime_path | {
5062+ try object_files .append (runtime_path );
5063+ } else {
5064+ return error .UnsupportedTarget ;
5065+ }
5066+ }
49555067
49565068 if (link_type == .archive ) {
49575069 try writeArchiveOutput (ctx , target , final_output_path , link_inputs , object_files .items );
49585070 } else {
49595071 try verifyHostInputSymbols (
49605072 ctx ,
49615073 try hostInputPaths (ctx , link_inputs ),
4962- try hostedSymbolsFromLir ( ctx . arena , & lowered . lir_result . store ) ,
5074+ hosted_symbols ,
49635075 link_inputs .target_name ,
5076+ args .synthetic_default_platform ,
49645077 );
49655078
49665079 const force_undefined_symbols = try staticDataLinkRootSymbols (ctx , static_data_exports );
@@ -5179,6 +5292,7 @@ fn rocBuildNative(ctx: *CliCtx, args: cli_args.BuildArgs) anyerror!void {
51795292 .target_usize = target_usize ,
51805293 .inline_mode = postCheckInlineModeForOpt (args .opt ),
51815294 .list_in_place_map = listInPlaceMapForOpt (args .opt ),
5295+ .proc_debug_names = args .synthetic_default_platform ,
51825296 },
51835297 );
51845298 defer lowered .deinit ();
@@ -5292,6 +5406,7 @@ fn rocBuildNative(ctx: *CliCtx, args: cli_args.BuildArgs) anyerror!void {
52925406 try hostInputPaths (ctx , link_inputs ),
52935407 try hostedSymbolsFromLir (ctx .arena , & lowered .lir_result .store ),
52945408 link_inputs .target_name ,
5409+ false ,
52955410 );
52965411
52975412 const force_undefined_symbols = try staticDataLinkRootSymbols (ctx , static_data_exports );
0 commit comments