mirror of
				https://github.com/roc-lang/roc.git
				synced 2025-10-30 04:37:11 +00:00 
			
		
		
		
	 cb42d26e11
			
		
	
	
		cb42d26e11
		
			
		
	
	
	
	
		
			
			* use zig Builder to generate LLVM bc for platform host shim * WIP * Working embedded LLVM compilation * lints * Update test_shared_memory_system.zig * Update main.zig * Refactor out builder into separate file * remove clang fallback, remove -Dllvm build flag * WIP change platform header * WIP no hardcoded platform entrypoints * WIP no hardcoded entrypoints * remove hardcoded interpreter shim entrypoint * WIP multiple entrypoints * WIP multiple entrypoints * WIP alignment issue * it's working!! * cleanup * fmt * fix tests and snapshots * fix cross-compile * WIP fix linking linux * improved debug logging in rocRun * WIP fix linux segfaults * cleanup stray dbgs * fix Windows linking * WIP remove std.debug.print in prebuilt shim * remove libc stubs, try C shim for platform host main * WORKING ON LINUX!!! * WIP fixing int platform * prevent double mapping of shared memory * WIP * remove clang fallback * cleanup test platforms * vendor linux object files for musl and gnu in test platforms * fix windows __main export * typo * avoide hardcoding libc path and dynamic linker on linux * some fixes * try CI fix for linux ARM64 * try use system CRT for ARM64 * use absolute pats for vendored CRT * minimal roc build * use target os for filename not host os * implement app stubs for test platforms * fix glibc * WIP cross compilation * fix run, fix build for native * Merge remote/main * fix macos * add bookends * remove hosts * fix cross-compile for linux on macos * fix files paths for Windows * Update main.zig * test ubu 24.04 too Signed-off-by: Anton-4 <17049058+Anton-4@users.noreply.github.com> * debug: log all used instructions * fmt * get bad instruction with gdb * install gdb * Revert last 4 commits * simpler cross-compile arm64 runtime files * add minimal cross-compilation for glibc * simplify stub generation * Update test_int_platform.sh * Update ci_cross_compile.yml * Update ci_cross_compile.yml * try alpine3.18 x64musl files * Claude's fix + removed CPU instructions * fix fuzz crash empty after merge * update snapshot * restore full CI * some cleanup * remove debugging from CI - print all supported CPU instructions * try using generic when LLVM compiles app stub * enhanced error handling for app stub compilation using LLVM * check machine ABI on linux * try more debugging * update test script to inidicate truncated error logs, temporarily display everything for arm64 linux errors * fix missing arm64 libc search paths * back to normal CI * try without .git See https://github.com/ziglang/zig/issues/21316#issuecomment-2408071050 Signed-off-by: Anton-4 <17049058+Anton-4@users.noreply.github.com> * undo .git change Signed-off-by: Anton-4 <17049058+Anton-4@users.noreply.github.com> * retry zig build command Signed-off-by: Anton-4 <17049058+Anton-4@users.noreply.github.com> * different retry strategy Signed-off-by: Anton-4 <17049058+Anton-4@users.noreply.github.com> --------- Signed-off-by: Anton-4 <17049058+Anton-4@users.noreply.github.com> Co-authored-by: Anton-4 <17049058+Anton-4@users.noreply.github.com>
		
			
				
	
	
		
			168 lines
		
	
	
	
		
			6.3 KiB
		
	
	
	
		
			Zig
		
	
	
	
	
	
			
		
		
	
	
			168 lines
		
	
	
	
		
			6.3 KiB
		
	
	
	
		
			Zig
		
	
	
	
	
	
| //! Simple platform host that calls into a simplified Roc entrypoint with two integers and prints the result.
 | |
| 
 | |
| const std = @import("std");
 | |
| const builtins = @import("builtins");
 | |
| 
 | |
| /// Host environment - contains our arena allocator
 | |
| const HostEnv = struct {
 | |
|     arena: std.heap.ArenaAllocator,
 | |
| };
 | |
| 
 | |
| /// Roc allocation function
 | |
| fn rocAllocFn(roc_alloc: *builtins.host_abi.RocAlloc, env: *anyopaque) callconv(.C) void {
 | |
|     const host: *HostEnv = @ptrCast(@alignCast(env));
 | |
|     const allocator = host.arena.allocator();
 | |
| 
 | |
|     const log2_align = std.math.log2_int(u32, @intCast(roc_alloc.alignment));
 | |
|     const align_enum: std.mem.Alignment = @enumFromInt(log2_align);
 | |
| 
 | |
|     const result = allocator.rawAlloc(roc_alloc.length, align_enum, @returnAddress());
 | |
| 
 | |
|     roc_alloc.answer = result orelse {
 | |
|         @panic("Host allocation failed");
 | |
|     };
 | |
| }
 | |
| 
 | |
| /// Roc deallocation function
 | |
| fn rocDeallocFn(roc_dealloc: *builtins.host_abi.RocDealloc, env: *anyopaque) callconv(.C) void {
 | |
|     _ = roc_dealloc;
 | |
|     _ = env;
 | |
|     // NoOp as our arena frees all memory at once
 | |
| }
 | |
| 
 | |
| /// Roc reallocation function
 | |
| fn rocReallocFn(roc_realloc: *builtins.host_abi.RocRealloc, env: *anyopaque) callconv(.C) void {
 | |
|     _ = roc_realloc;
 | |
|     _ = env;
 | |
|     @panic("Realloc not implemented in this example");
 | |
| }
 | |
| 
 | |
| /// Roc debug function
 | |
| fn rocDbgFn(roc_dbg: *const builtins.host_abi.RocDbg, env: *anyopaque) callconv(.C) void {
 | |
|     _ = env;
 | |
|     const message = roc_dbg.utf8_bytes[0..roc_dbg.len];
 | |
|     std.debug.print("ROC DBG: {s}\n", .{message});
 | |
| }
 | |
| 
 | |
| /// Roc expect failed function
 | |
| fn rocExpectFailedFn(roc_expect: *const builtins.host_abi.RocExpectFailed, env: *anyopaque) callconv(.C) void {
 | |
|     _ = env;
 | |
|     const message = roc_expect.utf8_bytes[0..roc_expect.len];
 | |
|     std.debug.print("ROC EXPECT FAILED: {s}\n", .{message});
 | |
| }
 | |
| 
 | |
| /// Roc crashed function
 | |
| fn rocCrashedFn(roc_crashed: *const builtins.host_abi.RocCrashed, env: *anyopaque) callconv(.C) noreturn {
 | |
|     _ = env;
 | |
|     const message = roc_crashed.utf8_bytes[0..roc_crashed.len];
 | |
|     @panic(message);
 | |
| }
 | |
| 
 | |
| // External symbols provided by the Roc runtime object file
 | |
| // Follows RocCall ABI: ops, ret_ptr, then argument pointers
 | |
| extern fn roc__addInts(ops: *builtins.host_abi.RocOps, ret_ptr: *anyopaque, arg_ptr: ?*anyopaque) callconv(.C) void;
 | |
| extern fn roc__multiplyInts(ops: *builtins.host_abi.RocOps, ret_ptr: *anyopaque, arg_ptr: ?*anyopaque) callconv(.C) void;
 | |
| 
 | |
| // OS-specific entry point handling
 | |
| comptime {
 | |
|     // Export main for all platforms
 | |
|     @export(&main, .{ .name = "main" });
 | |
|     
 | |
|     // Windows MinGW/MSVCRT compatibility: export __main stub
 | |
|     if (@import("builtin").os.tag == .windows) {
 | |
|         @export(&__main, .{ .name = "__main" });
 | |
|     }
 | |
| }
 | |
| 
 | |
| // Windows MinGW/MSVCRT compatibility stub
 | |
| // The C runtime on Windows calls __main from main for constructor initialization
 | |
| fn __main() callconv(.C) void {}
 | |
| 
 | |
| // C compatible main for runtime
 | |
| fn main(argc: c_int, argv: [*][*:0]u8) callconv(.C) c_int {
 | |
|     _ = argc;
 | |
|     _ = argv;
 | |
|     platform_main() catch |err| {
 | |
|         std.io.getStdErr().writer().print("HOST ERROR: {?}", .{err}) catch unreachable;
 | |
|         return 1;
 | |
|     };
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| /// Platform host entrypoint -- this is where the roc application starts and does platform things
 | |
| /// before the platform calls into Roc to do application-specific things.
 | |
| fn platform_main() !void {
 | |
|     var host_env = HostEnv{
 | |
|         .arena = std.heap.ArenaAllocator.init(std.heap.page_allocator),
 | |
|     };
 | |
|     defer host_env.arena.deinit(); // Clean up all allocations on exit
 | |
| 
 | |
|     const stdout = std.io.getStdOut().writer();
 | |
| 
 | |
|     // Create the RocOps struct
 | |
|     var roc_ops = builtins.host_abi.RocOps{
 | |
|         .env = @as(*anyopaque, @ptrCast(&host_env)),
 | |
|         .roc_alloc = rocAllocFn,
 | |
|         .roc_dealloc = rocDeallocFn,
 | |
|         .roc_realloc = rocReallocFn,
 | |
|         .roc_dbg = rocDbgFn,
 | |
|         .roc_expect_failed = rocExpectFailedFn,
 | |
|         .roc_crashed = rocCrashedFn,
 | |
|         .host_fns = undefined, // No host functions for this simple example
 | |
|     };
 | |
| 
 | |
|     // Generate random integers using current timestamp as seed
 | |
|     var rand = std.Random.DefaultPrng.init(@intCast(std.time.timestamp()));
 | |
|     const a = rand.random().intRangeAtMost(i64, 0, 100);
 | |
|     const b = rand.random().intRangeAtMost(i64, 0, 100);
 | |
| 
 | |
|     // Arguments struct for passing two integers to Roc as a tuple
 | |
|     const Args = extern struct { a: i64, b: i64 };
 | |
|     var args = Args{ .a = a, .b = b };
 | |
| 
 | |
|     try stdout.print("Generated numbers: a = {}, b = {}\n", .{ a, b });
 | |
| 
 | |
|     // Test first entrypoint: addInts (entry_idx = 0)
 | |
|     try stdout.print("\n=== Testing addInts (entry_idx = 0) ===\n", .{});
 | |
| 
 | |
|     var add_result: i64 = undefined;
 | |
|     roc__addInts(&roc_ops, @as(*anyopaque, @ptrCast(&add_result)), @as(*anyopaque, @ptrCast(&args)));
 | |
| 
 | |
|     const expected_add = a +% b; // Use wrapping addition to match Roc behavior
 | |
|     try stdout.print("Expected add result: {}\n", .{expected_add});
 | |
|     try stdout.print("Roc computed add: {}\n", .{add_result});
 | |
| 
 | |
|     var success_count: u32 = 0;
 | |
|     if (add_result == expected_add) {
 | |
|         try stdout.print("\x1b[32mSUCCESS\x1b[0m: addInts results match!\n", .{});
 | |
|         success_count += 1;
 | |
|     } else {
 | |
|         try stdout.print("\x1b[31mFAIL\x1b[0m: addInts results differ!\n", .{});
 | |
|     }
 | |
| 
 | |
|     // Test second entrypoint: multiplyInts (entry_idx = 1)
 | |
|     try stdout.print("\n=== Testing multiplyInts (entry_idx = 1) ===\n", .{});
 | |
| 
 | |
|     var multiply_result: i64 = undefined;
 | |
|     roc__multiplyInts(&roc_ops, @as(*anyopaque, @ptrCast(&multiply_result)), @as(*anyopaque, @ptrCast(&args)));
 | |
| 
 | |
|     const expected_multiply = a *% b; // Use wrapping multiplication to match Roc behavior
 | |
|     try stdout.print("Expected multiply result: {}\n", .{expected_multiply});
 | |
|     try stdout.print("Roc computed multiply: {}\n", .{multiply_result});
 | |
| 
 | |
|     if (multiply_result == expected_multiply) {
 | |
|         try stdout.print("\x1b[32mSUCCESS\x1b[0m: multiplyInts results match!\n", .{});
 | |
|         success_count += 1;
 | |
|     } else {
 | |
|         try stdout.print("\x1b[31mFAIL\x1b[0m: multiplyInts results differ!\n", .{});
 | |
|     }
 | |
| 
 | |
|     // Final summary
 | |
|     try stdout.print("\n=== FINAL RESULT ===\n", .{});
 | |
|     if (success_count == 2) {
 | |
|         try stdout.print("\x1b[32mALL TESTS PASSED\x1b[0m: Both entrypoints work correctly!\n", .{});
 | |
|     } else {
 | |
|         try stdout.print("\x1b[31mSOME TESTS FAILED\x1b[0m: {}/2 tests passed\n", .{success_count});
 | |
|         std.process.exit(1);
 | |
|     }
 | |
| }
 |