> Instead [of using a library like libffi], Swift embeds a copy of clang, the C and C++ compiler, which is able to directly translate between the languages avoiding penalties in code size and runtime performance.
How exactly does this work? Is it compiling C/C++ code alongside the Swift code and transforming that into some kind of Swift implementation?
The embedded copy of Clang is doing some heavy work I think. At no point does any of the C or C++ code get transformed into Swift. Instead, it's used to import the the header directly into Swift (in a manner similar to a pre-compiled header), and then Swift is able to use the platform C calling convention to directly call the C code. Swift is generally really good at code-switching between various calling conventions, including its own, C, Objective-C msg_send, etc.
Many languages have some facility for importing declarations like that and even using C calling convention to invoke them (e.g. Rust + bindgen), but Swift goes much further than just importing declarations; if the header happens to contain C definition code, it actually compiles that code directly and then can then emit a call to it.
In the case of C++, which doesn't have a stable ABI on most platforms, it likely also knows and emits code using Clang's C++ calling convention for the platform (e.g. Clang on Windows uses the MSVC calling convention and so does Swift when calling C++). But Swift's ability to actually compile C++ code is very powerful in dealing with template functions and classes because Swift can instantiate and compile templated code in the C++ headers. AFAIK it's the only major production language I've seen that even attempts to do this.
If it works like in Zig (which also currently integrates Clang), then it will compile C, C++ and ObjC source files directly to LLVM IR, and headers to AST-level and then use that rich AST information to generate Swift interfaces on the fly. The main difference to Zig seems to be that Swift can also generate bindings for C++ interfaces while Zig is limited to C interfaces.
A Swift package can have modules/targets that are C/C++. It delegates the module building to clang, and Swift can both read/use those modules and publish its own API for use from C/C++. In Swift the "unsafe" family of API's converts Swift objects to C/C++ pointers relatively ergonomically. Note that Swift 5 added a lot of features to support ABI stability.
5 comments
[ 5.2 ms ] story [ 181 ms ] threadHow exactly does this work? Is it compiling C/C++ code alongside the Swift code and transforming that into some kind of Swift implementation?
Many languages have some facility for importing declarations like that and even using C calling convention to invoke them (e.g. Rust + bindgen), but Swift goes much further than just importing declarations; if the header happens to contain C definition code, it actually compiles that code directly and then can then emit a call to it.
In the case of C++, which doesn't have a stable ABI on most platforms, it likely also knows and emits code using Clang's C++ calling convention for the platform (e.g. Clang on Windows uses the MSVC calling convention and so does Swift when calling C++). But Swift's ability to actually compile C++ code is very powerful in dealing with template functions and classes because Swift can instantiate and compile templated code in the C++ headers. AFAIK it's the only major production language I've seen that even attempts to do this.
https://www.swift.org/documentation/cxx-interop/