ziglang / zig

General-purpose programming language and toolchain for maintaining robust, optimal, and reusable software.
https://ziglang.org
MIT License
33.61k stars 2.46k forks source link

Compiling Zig compiler to `wasm32-wasi` target #20665

Open eliot-akira opened 1 month ago

eliot-akira commented 1 month ago

Zig Version

0.13.0

Steps to Reproduce and Observed Behavior

Clone Zig and compile the compiler to wasm32-wasi target.

git clone --recursive --depth 1 --single-branch --branch master https://github.com/ziglang/zig
cd zig
zig build -Dtarget=wasm32-wasi -Doptimize=ReleaseSmall -Dno-langref -Dno-lib

It results in errors.

~/zig/build.zig:600:25: error: no field or member function named 'addUpdateSourceFiles' in 'Build'
    const copy_zig_h = b.addUpdateSourceFiles();
                       ~^~~~~~~~~~~~~~~~~~~~~
~/.local/lib/zig/lib/std/Build.zig:1:1: note: struct declared here
const std = @import("std.zig");
^~~~~
referenced by:
    build: ~/zig/build.zig:537:9
    runBuild__anon_8848: ~/.local/lib/zig/lib/std/Build.zig:2117:37
    remaining reference traces hidden; use '-freference-trace' to see all reference traces
~/zig/build.zig:1289:64: error: no field named 'zig_lib_directory' in struct 'Build.Graph'
        cmd.addArgs(&.{ "--zig-lib-dir", b.fmt("{}", .{b.graph.zig_lib_directory}) });
                                                               ^~~~~~~~~~~~~~~~~
~/.local/lib/zig/lib/std/Build.zig:112:19: note: struct declared here
pub const Graph = struct {
                  ^~~~~~
~/zig/test/tests.zig:775:45: error: type '[]const u8' does not support struct initialization syntax
        const cleanup = b.addRemoveDirTree(.{ .cwd_relative = tmp_path });
                                           ~^~~~~~~~~~~~~~~~~~~~~~~~~~~~
~/zig/test/standalone/cmakedefine/build.zig:83:66: error: root struct of file 'Build.Step' has no member named 'MakeOptions'
fn compare_headers(step: *std.Build.Step, options: std.Build.Step.MakeOptions) !void {
                                                   ~~~~~~~~~~~~~~^~~~~~~~~~~~
~/.local/lib/zig/lib/std/Build/Step.zig:1:1: note: struct declared here
id: Id,
^~

Expected Behavior

The Zig compiler can be compiled to wasm32-wasi target for running in the browser.

Attempts toward a solution

The closest solution I found is in the Zig Playground repo, specifically ZIG_WASM.md.

It's a patch that allows the compilation to succeed. I'll include it below for reference.

diff --git a/build.zig b/build.zig
index 9e6e86386..ec8b6b9bd 100644
--- a/build.zig
+++ b/build.zig
@@ -237,7 +237,7 @@ pub fn build(b: *std.Build) !void {
     exe_options.addOption(bool, "llvm_has_xtensa", llvm_has_xtensa);
     exe_options.addOption(bool, "force_gpa", force_gpa);
     exe_options.addOption(bool, "only_c", only_c);
-    exe_options.addOption(bool, "only_core_functionality", only_c);
+    exe_options.addOption(bool, "only_core_functionality", true);

     if (link_libc) {
         exe.linkLibC();
diff --git a/src/link.zig b/src/link.zig
index 703dfb873..3bc4039e7 100644
--- a/src/link.zig
+++ b/src/link.zig
@@ -765,9 +765,9 @@ pub const File = struct {
     /// Commit pending changes and write headers. Takes into account final output mode
     /// and `use_lld`, not only `effectiveOutputMode`.
     pub fn flush(base: *File, comp: *Compilation, prog_node: *std.Progress.Node) FlushError!void {
-        if (build_options.only_c) {
-            assert(base.tag == .c);
-            return @fieldParentPtr(C, "base", base).flush(comp, prog_node);
+        if (true) {
+            assert(base.tag == .wasm);
+            return @fieldParentPtr(Wasm, "base", base).flush(comp, prog_node);
         }
         if (comp.clang_preprocessor_mode == .yes) {
             const emit = base.options.emit orelse return; // -fno-emit-bin
diff --git a/src/link/Wasm/Archive.zig b/src/link/Wasm/Archive.zig
index c4fb9b829..7fdc018ab 100644
--- a/src/link/Wasm/Archive.zig
+++ b/src/link/Wasm/Archive.zig
@@ -208,9 +208,9 @@ pub fn parseObject(archive: Archive, allocator: Allocator, file_offset: u32) !Ob

     const object_name = try archive.parseName(header);
     const name = name: {
-        var buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined;
-        const path = try std.os.realpath(archive.name, &buffer);
-        break :name try std.fmt.allocPrint(allocator, "{s}({s})", .{ path, object_name });
+        // var buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined;
+        // const path = try std.os.realpath(archive.name, &buffer);
+        break :name try std.fmt.allocPrint(allocator, "{s}({s})", .{ archive.name, object_name });
     };
     defer allocator.free(name);

diff --git a/src/main.zig b/src/main.zig
index 39a7adc42..616518d15 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -200,7 +200,7 @@ pub fn main() anyerror!void {
     }

     // Short circuit some of the other logic for bootstrapping.
-    if (build_options.only_c) {
+    if (true) {
         if (mem.eql(u8, args[1], "build-exe")) {
             return buildOutputType(gpa, arena, args, .{ .build = .Exe });
         } else if (mem.eql(u8, args[1], "build-obj")) {
@@ -1544,7 +1544,7 @@ fn buildOutputType(
             }
         },
         .cc, .cpp => {
-            if (build_options.only_c) unreachable;
+            if (true) unreachable;

             emit_h = .no;
             soname = .no;
@@ -3238,7 +3238,7 @@ fn buildOutputType(
     switch (listen) {
         .none => {},
         .stdio => {
-            if (build_options.only_c) unreachable;
+            if (true) unreachable;
             try serve(
                 comp,
                 std.io.getStdIn(),
@@ -3286,7 +3286,7 @@ fn buildOutputType(
         error.SemanticAnalyzeFail => if (listen == .none) process.exit(1),
         else => |e| return e,
     };
-    if (build_options.only_c) return cleanExit();
+    if (true) return cleanExit();
     try comp.makeBinFileExecutable();

     if (test_exec_args.items.len == 0 and object_format == .c) default_exec_args: {

Notably, I found the patch only works for Zig version 0.11.


Versions above 0.11 result in compile errors related to os.realpath(). I think the following issue is related:

On version 0.13, for example, after applying the patch and running below (removed deprecated option -Dno-autodocs and added option -freference-trace recommended by the error message).

zig build -Dtarget=wasm32-wasi -Doptimize=ReleaseSmall -Dno-langref -Dno-lib -freference-trace

The error:

~/.local/lib/zig/lib/std/posix.zig:5340:9: error: WASI does not support os.realpath
        @compileError("WASI does not support os.realpath");
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
referenced by:
    realpathAlloc: ~/.local/lib/zig/lib/std/fs.zig:726:40
    create: src/codegen/llvm.zig:913:38
    create: src/Compilation.zig:1649:64
    buildOutputType: src/main.zig:3213:29
    main: src/main.zig:203:20
    callMain: ~/.local/lib/zig/lib/std/start.zig:524:32
    wasi_start: ~/.local/lib/zig/lib/std/start.zig:207:65
gooncreeper commented 1 month ago

Actual errors if you build it correctly:

src/introspect.zig:41:9: error: this function is unsupported on WASI
        @compileError("this function is unsupported on WASI");
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/introspect.zig:85:9: error: on WASI the global cache dir must be resolved with preopens
        @compileError("on WASI the global cache dir must be resolved with preopens");
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
lib/std/posix.zig:145:28: error: root struct of file 'c' has no member named 'sockaddr'
pub const sockaddr = system.sockaddr;
                     ~~~~~~^~~~~~~~~
lib/std/c.zig:1:1: note: struct declared here
const std = @import("std");

Command (change your paths to whatever matches your system): ~/release.z/zig-linux-x86_64-0.14.0-dev.311+c50f30038/zig build -Dtarget=wasm32-wasi -Doptimize=ReleaseSmall --zig-lib-dir ~/git/ziglang/zig/lib

eliot-akira commented 1 month ago

Thank you for the response.

OK, so I'll set the options as suggested, especially --zig-lib-dir to point to lib in the source directory. I did make sure to use the same version of the compiler as the source to compile itself.

Maybe this should have been posted as a question in the forums, or a feature request for an additional target in ziglang/zig-bootstrap.

gooncreeper commented 2 weeks ago

10716

Seems to be a regression