Skip to content
This repository has been archived by the owner on Nov 22, 2023. It is now read-only.

VFS support #4

Open
stevefan1999-personal opened this issue Aug 13, 2023 · 5 comments
Open

VFS support #4

stevefan1999-personal opened this issue Aug 13, 2023 · 5 comments

Comments

@stevefan1999-personal
Copy link

We need it so that we can build TCC to make it run on WASM, or make it possible so that we can run TCC on Compiler Explorer.

I personally uses libtcc mainly for experimental headers and libraries embedding, so I can just compile libtcc.c and leverage the ONE_SOURCE feature. And then I instruct the C compiler to override the necessary functions.

    if cfg!(feature = "vfs") {
        cc.define("open", "vfs_open");
        cc.define("read", "vfs_read");
        cc.define("lseek", "vfs_lseek");
        cc.define("close", "vfs_close");
    }

And then I implemented a tiny VFS wrapper:

extern "C" {
    fn open(path: *const c_char, oflag: c_int, ap: VaList) -> c_int;
}


#[no_mangle]
pub unsafe extern "C" fn vfs_open(path: *const c_char, oflag: c_int, mut args: ...) -> c_int {
    fn insert_vfs(vfs: Box<impl VFS + Send + Sync + Clone + 'static>) -> c_int {
        loop {
            let vfs = vfs.clone();
            let key: c_int = unsafe { RNG.gen_range(0..c_int::MAX) };
            if let Ok(_) = unsafe { FILES.try_insert(key, vfs) } {
                return key;
            }
        }
    }

    if let Ok(path) = CStr::from_ptr(path).to_str() {
        let prefix = "memory:///headers/";

        if path.starts_with(prefix) {
            let path = path.strip_prefix(prefix).unwrap();

            if let Some(file) = crate::headers::ASSET_MAP.get(path) {
                return insert_vfs(Box::new(MemoryVFS::from_static(file.contents_bytes)));
            }
        }

        let prefix = "memory:///libraries/";

        if path.starts_with(prefix) {
            let path = path.strip_prefix(prefix).unwrap();
            if let Some(file) = crate::LIBRARIES.get_file(path) {
                return insert_vfs(Box::new(MemoryVFS::from_static(file.contents())));
            }
        }
    }

    let fd = open(path, oflag, args.as_va_list());
    if fd >= 0 {
        insert_vfs(Box::new(PosixVFS::new(fd)))
    } else {
        fd
    }
}

This one worked out pretty well, but I think this is very hacky, and there is a lack of write support. Specifically, if we want to run this on Godbolt, we need to capture the output executable, but the current implementation of TCC writes directly to a file descriptor. Instead, we should have a dynamic stream API that supports byte stream or file stream.

@EscapeCharacter-dev
Copy link

This is a mirror of tinycc.

@stevefan1999-personal
Copy link
Author

@stevefan1999-personal
Sounds good. Go for it dude.
Fork the repo into another thing here on CChads (or your user) and you can start working

Sure thing

@stevefan1999-personal
Copy link
Author

This is a mirror of tinycc.

I don't think this is exactly it because there are some changes not in mob branch. But I will try to push to both sides

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants
@stevefan1999-personal @EscapeCharacter-dev and others