tinycc icon indicating copy to clipboard operation
tinycc copied to clipboard

VFS support

Open stevefan1999-personal opened this issue 10 months ago • 5 comments

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.

stevefan1999-personal avatar Aug 13 '23 05:08 stevefan1999-personal

This is a mirror of tinycc.

EscapeCharacter-dev avatar Sep 19 '23 12:09 EscapeCharacter-dev

@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 avatar Sep 20 '23 02:09 stevefan1999-personal

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

stevefan1999-personal avatar Sep 20 '23 02:09 stevefan1999-personal