Using the C library from Swift: thoughts

He might mean that char is unsigned. char in C is always a distinct type from either signed char or unsigned char, and whether char itself is signed or not is implementation-defined.

4 Likes

Yeah but he's wrong. I checked. By default, char is signed on Windows. There is an MSVC++ flag you can pass to make it unsigned, however.

It is what @Joe_Groff was saying - I was thinking about char. I might have had it backwards though - Windows has a signed char and Darwin has unsigned char perhaps?

… char is signed on Windows and on Darwin.

I would phrase it as compiler-specific, not platform-specific. char is signed by default by Visual C++’s CL.EXE unless you pass /J, which the docs warn may cause ATL or MFC apps to fail to build. I did a quick search but couldn’t find anything about whether the Windows SDK itself has a dependency on char being signed.

Indeed, MSVC++ likes having options for everything.

Does clang have an equivalent to /J? If not, it seems moot, since Swift's C interop is ultimately based on the view of C exposed by clang.

GCC has -fsigned-char, which clang inherited. When invoked as clang-cl, clang also supports /J.

2 Likes

Since Swift does not invoke clang-cl, sounds like it is indeed moot.

Please reread :)

-fsigned-char is the default for Windows, you can use -funsigned-char to mimic /J.

1 Like

Since Swift does not pass -funsigned-char on its own, it's still moot. :stuck_out_tongue:

My original point—that none of the major vendors use unsigned char by default, and so the unknown signedness of CChar makes a portable C module more difficult when we could maybe just put our foots down and say "it's always signed in Swift"—still stands.

Oh yes, good point, there are a bunch that need to be macros/inline functions for performance too.

Yes, that makes sense. This might even be an opportunity to also deal with errno. Currently, there's no guaranteed way to deal with errno correctly in Swift because any libc (or others that write into errno) function call may overwrite the value. But we have ARC which deterministically but mostly unpredictably (particularly under inlining) places swift_release calls, which might turn into deinits which runs arbitrary code. Hence, we may want to fetch the return value & errno together without running any Swift code in between.

1 Like

That’s how system calls actually work, at least on Linux. errno is just a fiction created by libc. So maybe we could bypass libc entirely and just wrap the system calls directly like Go does. :slight_smile:

9 Likes

Unfortunately, this really only works on Linux. No one else has stable syscalls, especially not Darwin.

2 Likes

There are also standard C and POSIX calls that set errno but aren't backed by syscalls. So we would still need a way to call one of those functions and grab the subsequent errno as a single operation to interact with those APIs.

3 Likes

For instance, if _GNU_SOURCE isn't defined before you include a header from glibc, you don't get access to all its interfaces. And SwiftGlibc.h (?) doesn't define _GNU_SOURCE , so in order to access something like pthread_setname_np(), you need to either resort to dynamic loading with dlsym() or to adding a C module to your package that provides wrapper functions. (Swift Testing has both. Yay.)

Speaking of _GNU_SOURCE stuff, it reminds of the discussion of using dladdr in Swift. Many people (including me) has a demand for it and currently we have to use a C shim layer to export it for Linux platform.

I recall having a real problem importing liburing because its header defined _XOPEN_SOURCE, which makes all the socket structures incompatible. The workaround was not elegant.

Cross posting as I meant to add it to here

That seems like a left-pad fix, :wink: which may work for SwiftPM packages but not for alternative build systems like CMake and Bazel or within the toolchain itself (note how many files he had to add that new FreeBSD overlay to in just the compiler repo).

I'm not against trying your idea out, but it has to be vended by someplace official, given the obvious scope for abuse, say from @0xTim and the swift-server org? If they agree, I'm happy to pitch in to create this simple import alias there.

I don't expect to ever "fix" it, the idea would be to replace it altogether with your import C99 idea or whatever the community comes up with then. The Swift team has pragmatically added such temporary features like @_cdecl to the compiler in the past, to provide some incomplete solution for today while we figure out a better solution to finally add to the language later.

I see no reason we can't put this alias in now as import _platformC or whatever ridiculous name to signify it is temporary, write some doc to emphasize how limited it is, and ship it in the stdlib today to fix a small but real problem for those writing multi-platform code.

3 Likes

I was going to say that there's nothing that would stop the compiler project from adopting an internal shorthand for itself (much as it's already done for availability attribute), but I see that many of these uses are non-trivially different from each other, including some that declare typealiases, so it's not clear to me actually how much mileage such an internal feature would get. It's also not clear to me how many are using only C standard library facilities versus platform APIs—not that it clinches the point, but I see a lot of import Darwin and no import Darwin.C.

I wonder what that breakdown would be for third-party uses of the import dance today--if people tend to customize the platforms recited and want the entire platform SDK for each, then the ask isn't some precursor that can ever be replaced with import C99.