Looking through the documentation, I see mention of the ability to use C++ from Swift, but not many examples beyond the simple case of using the std C++ library with "import CxxStdlib".
I haven't found a robust example even of a Hello World program that uses C++ so far. So I must ask, if I want to import some random C++ library's header and link with that library, how is that done?
I tried specifying a module map, like the documentation suggests, and swiftc 5.9 just ignored it. I did an import Foo and provided a -I to the correct header directory, and swiftc gave an error on the line "import Foo".
This project demonstrates bi-directional swift c++ interop. The most important parts are probably getting the module map set up, setting the module search path with -I, and telling the compiler to import headers in C++ mode with-cxx-interoperability-mode=default. Let me know if you want more. If I weren’t on a phone at the moment, I would type out a little example as a makefile with the exact commands.
For a more real-world program example, I used the above example repo (mainly for the CMake and module map) as a template for writing a tiny http server that uses bidirectional C++-Interop along with Swift's Async+Await:
Network code is C and C++, most of the http proto handling code for get requests is C++, minetypes are handled by a call back to swift using reverse interop (passed std::strings), a std::vector is passed from Swift to C++ that contains a socket and a request ID. Concurrency is handled by Swift.
Both of these examples are for C++ which is in the local directory.
What about if I want to use C++ code that is in e.g. /usr/local/include & /usr/local/lib?
Yep. The headers need to be in a module map file for swift to import it. That work is done for you in the Darwin SDKs, not so much elsewhere. Sometimes you’ll want to use vfs-overlays to inject the module map into the right locations, like what was done with the windows swift stuff, to enable importing the windows SDK headers without needing to change the VisualStudio itself.
I tried to hook up Magick++ into Swift with C++-Interop, but ran into modularity issues. For instance, if proper nesting isn't enforced then the library isn't modular ( as per ⚙ D11844 [Modules] More descriptive diagnostics for misplaced import directive), you'll get something like: error: import of module 'Darwin.C.float' appears within namespace 'MagickCore'
I ran into this due to code that resembles the following:
//
// Include ImageMagick headers into namespace "MagickCore". If
// MAGICKCORE_IMPLEMENTATION is defined, include ImageMagick development
// headers. This scheme minimizes the possibility of conflict with
// user code.
//
namespace MagickCore
{
#include <MagickCore/MagickCore.h>
#include <MagickWand/MagickWand.h>
#undef inline // Remove possible definition from config.h
#undef class
}
I know for certain that lots of non-trivial and robust Darwin SDK's work with interop that are not in the local dir either. They may not be C++ (except that compiling with C++ does enable C++-isms relating to extern "C" and enum behavior etc).
It's still not quite working for me. It seems swiftc is creating a "public enum" of the namespace and it expects that all classes within the namespace will be values of that enum. But my class isn't.
error: 'TheCppClass' is not a member type of enum '__ObjC.TheCppModule'