Skip to content

Conversation

@silbinarywolf
Copy link
Contributor

@silbinarywolf silbinarywolf commented Jun 9, 2024

Description

I've been experimenting with getting my app running on the Wii via the DevkitPro toolchain, and I've gotten various things working using the standard library which includes reading/writing files to an SD card.

However to make it work, it required patching upstream with something like this.

How I use it

Used for Wii SDL2 application here:

Example C OS zig files:

main.zig

pub const os = struct {
    pub const c = @import("c/os.zig");
};

c/os.zig

const std = @import("std");
const c = @import("c.zig");

/// os is the C operating system definitions, ie. c/wasi.zig
pub const os = @import("wii.zig");

pub const pthread_mutex_t = @compileError("pthread not supported by Wii library. Must compile single threaded unless we polyfill pthread functions");

// NOTE(jae): 2024-06-03
// AT is seemingly not supported for the Wii as it also doesn't support "openat"
// we polyfill "openat" ourselves.
pub const AT = struct {
    /// Special value used to indicate openat should use the current working directory
    pub const FDCWD = -2;
};

// NOTE(jae): 2024-06-03
// Copied from lib/std/os/linux.zig, section: .powerpc, .powerpcle, .powerpc64, .powerpc64le
pub const O = packed struct(u32) {
    ACCMODE: std.posix.ACCMODE = .RDONLY,
    _2: u4 = 0,
    CREAT: bool = false,
    EXCL: bool = false,
    NOCTTY: bool = false,
    TRUNC: bool = false,
    APPEND: bool = false,
    NONBLOCK: bool = false,
    DSYNC: bool = false,
    ASYNC: bool = false,
    DIRECTORY: bool = false,
    NOFOLLOW: bool = false,
    LARGEFILE: bool = false,
    DIRECT: bool = false,
    NOATIME: bool = false,
    CLOEXEC: bool = false,
    SYNC: bool = false,
    PATH: bool = false,
    TMPFILE: bool = false,
    _: u9 = 0,
};

c/wii.zig

const builtin = @import("builtin");
const std = @import("std");
const c = @import("c.zig");

pub const _errno = struct {
    extern fn __errno() *c_int;
}.__errno;

pub const PATH_MAX = 4096;

pub const mode_t = u32;
pub const time_t = i64;

pub const STDIN_FILENO = 0;
pub const STDOUT_FILENO = 1;
pub const STDERR_FILENO = 2;

const clockid_t = i32;

// ... much more things in here, etc ...

c/c.zig

pub usingnamespace @cImport({
    // OGC Library
    @cInclude("ogcsys.h");
    @cInclude("gccore.h");

    // C library
    @cInclude("stdio.h");
    @cInclude("errno.h");
    @cInclude("fcntl.h");
    @cInclude("dirent.h");
});

Seperate to this we also have a "runtime" we build to polyfill things.
c/runtime.zig

const root = @import("root");
const std = @import("std");
const builtin = @import("builtin");
const c = @import("c.zig");

comptime {
    @export(openat, .{ .name = "openat", .linkage = .strong });
    @export(write, .{ .name = "__wrap_write", .linkage = .strong });
    if (builtin.os.tag == .wasi) {
        @export(wasi_errno, .{ .name = "errno", .linkage = .strong });
    }
}

/// openat is polyfilled as it doesn't have an implementation for devkitPPC
fn openat(dirfd: c_int, pathname: [*c]const u8, flags: c_int) callconv(.C) c_int {
    // TODO(jae): 2024-06-02
    // Make this actually use dirfd
    _ = dirfd; // autofix
    const file = c.open(pathname, flags);
    return file;
}

/// wrap "write" to get printf debugging in Dolphin emulator, if the "fd" is STDOUT or STDERR we call print.
/// otherwise fallback to writing to the file descriptor
fn write(fd: i32, buf: [*]const u8, count: usize) callconv(.C) isize {
    const __real_write = struct {
        extern "c" fn __real_write(fd: std.c.fd_t, buf: [*]const u8, nbyte: usize) isize;
    }.__real_write;
    if (fd == std.c.STDOUT_FILENO or fd == std.c.STDERR_FILENO) {
        // https://stackoverflow.com/a/3767300
        return @intCast(c.printf("%.*s", count, buf));
    }
    return __real_write(fd, buf, count);
}

/// wasi_errno calls the underlying Wii toolchain errno for builds targetting .wasi
fn wasi_errno() callconv(.C) *c_int {
    const _errno = struct {
        extern fn __errno() *c_int;
    }.__errno;
    return _errno();
}

silbinarywolf added a commit to silbinarywolf/zig-wii-sdk that referenced this pull request Jun 11, 2024
…g#20241 is merged and working for now)

- update gcc to use -O2 flag is optimize is set to .ReleaseFast
- improve printf by buffering a little before \n so that in Dolphin the text prints out together
@alexrp
Copy link
Member

alexrp commented Jul 21, 2024

I can't speak to whether this direction is desirable, but in any case, it will need rebasing after #20679.

@silbinarywolf
Copy link
Contributor Author

mmm, I think a better version of this would be good in the future but for the time-being, I've opted to go with a hacky approach with my zig-wii-sdk and target .wasi, then provide those Wasi functions and call the underlying C library code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants