SwiftWasm compilation with calls to Foundation's FileHandle errors out although API exists in corelibs

I’ve been experimenting with SwiftWASM recently as I’m gearing up for developing a web version of a macOS app I’ve worked on. So far I understand I should be able to reuse the Swift model layer from the Mac and I’m quite excited about that.

I’m rather new to using Swift on non-Darwin platforms and there's definitely a number a challenges I'm facing doing that, but I’ll start with what’s immediately blocking me right now.

Using Carton, I set up a simple website where Swift code is loading an HTML-embedded asset and renders several objects to the DOM via JavaScriptKit. I’d like to add HTML parsing so I’ve added the SwiftSoup package but I hit a snag because the package won’t compile for WASM.

Compiling (with swift build --triple wasm32-unknown-wasi) returns about 70 errors, all about missing APIs in Foundation's FileHandle. If SwiftSoup made calls to API not yet implemented in swift-corelibs-foundation that would have made sense to me, but each call I sampled appears to have been ported.

For example, here's one such error:

SwiftSoup/Sources/StreamReader.swift:23:42: error: incorrect argument label in call (have 'forReadingAtPath:', expected 'fileDescriptor:')
        guard let fileHandle = FileHandle(forReadingAtPath: path),

The compiler is basically pointing out that init(forReadingAtPath:) does not exist on FileHandle but it does appear to exist.

I've also isolated the call out to a new package and got the same error.

Would anyone know what's the cause and how to work around it? Thanks!

Disable file/dispatch-related code in Foundation for WASI by MaxDesiatov · Pull Request #3050 · apple/swift-corelibs-foundation · GitHub (WebAssembly doesn't have files, so Foundation.FileHandle & many other such things can't exist there)

Y'know, that wasn't a good answer.

Yes, files don't exist, so FileHandle can't, but that commit didn't remove it.

I can see that FileHandle.init?(path:...) calls _CFOpenFileWithMode which doesn't exist in WASI, and FileHandle.swift has no conditionals for WASI, so I think that FileHandle.swift can't be being compiled at all, but I don't see what's excluding it :(

Thank you for trying SwiftWasm toolchain and sorry for the inconvenience.

In theory, WASI provides most of typical file system features now, so FileHandle can be imported to wasm32-wasi. As far as I remember, the current guard condition is just for a tentative fix, so we can improve it to unlock those APIs.

Having said that, if you want to read/write file on WASI now, you can still use libc API fopen / fread / fwrite and so on like here.

Thanks for your responses, they helped me sort this out.

Looks like my mistake was assuming that SwiftWASM uses the upstream swift-corelibs-foundation, where in fact it has its own fork, in which there are indeed WASI conditionals in FileHandle.swift.

I am still a bit perplexed because, like @KeithBauerANZ , I can't see such conditionals used to exclude init(forReadingAtPath:) specifically. I'd love to understand what's going on there if anyone knows, but that's not crucial for continuing my experimentation.

Now that I know that the FileHandle API actually doesn't fully exist on WASI, I decided to simply fork SwiftSoup and move the calling code to a separate target that a WASI compilation skips.

If anyone is interested in how, check out my changes.

Cheers :grinning: