"Try the import first. A C target is for what Swift truly cannot see."
Why C Still Shows Up
Much of macOS below the frameworks is a C API: process information in libproc, archives in libarchive, sqlite3, POSIX sockets, forkpty. Swift imports many C headers directly through the SDK's module maps, so import Darwin gets you a lot. But some headers are not exposed as a clean Swift module, function-like macros do not import at all (WIFEXITED is simply not in scope from Swift), fixed-size C arrays arrive as awkward tuples, and some libraries you want are third-party. For those, SwiftPM lets a package contain a C target next to its Swift targets.
The Shape of a C Target
- A target folder like
Sources/CSparkProc/with.cfiles, and a public header underinclude/(the defaultpublicHeadersPath). - SwiftPM generates a module map for it, so a Swift target that depends on
CSparkProcsimply writesimport CSparkProc. - Keep the C surface tiny and boring: plain functions, plain types, a return code for failure. Put all interpretation on the Swift side.
The family's terminal app needed the working directory of the shell running in each pane, to open new panes in the same place. The answer lives in proc_pidinfo with PROC_PIDVNODEPATHINFO, and the app wrapped it in a one-file C target with a single public function, on the belief that libproc could not be imported from Swift. Measured on Swift 6.3.3 with the macOS 26.5 SDK, that belief is wrong: import Darwin exposes both names, and the call compiles and returns the working directory. The shim still earns its keep as one small, testable C surface that also carries a second call for the foreground process group of a pseudo-terminal, but the order is the lesson: try the import, and write C for what fails. A file workbench took the same route to wrap libarchive, linking the system library with linkerSettings: [.linkedLibrary("archive")].
Linking, and the Line You Should Not Cross Here
System libraries that ship with macOS link with .linkedLibrary (sqlite3, archive) or .linkedFramework (AppKit, PDFKit). A third-party library you install with Homebrew is a different matter: a green swift build against it proves only that your Mac has it. Shipping one means bundling every dylib in its dependency closure inside the app, rewriting their load paths and signing each one — the family's native video player does exactly that, and its quest (/cwk-quests/ashen-reel-quest) tells that story in depth. This lesson stays with the C that the OS already provides.
The Other Direction
Swift 6.3 added the @c attribute, which exposes a Swift function or enum to C and generates the matching header declaration. You will rarely need it in an app, but it is now the supported way to hand a Swift implementation to C code in the same project.