Tuesday, September 1, 2026

Bringing Package Management to Swift's C++ InteroperabilityIf you’ve ever wanted to call a C++ library directly from Swift, you’ve probably ended up writing a C facade or an Objective-C++ wrapper first. Swift has been able to import C and Objective-C APIs since its early releases, but its C importer couldn’t represent C++ features such as namespaces, overloaded functions, templates, constructors, destructors, and standard-library types, so a wrapper was the only way in. Swift 5.9 changed that by introducing direct C++ interoperability: Swift can now import C++ headers and call supported C++ APIs with no wrapper layer in between. To try this with an existing package, we use LunaSVG , a C++ SVG rendering library packaged in ConanCenter. The application creates an SVG scene in Swift and asks LunaSVG to render it to a PNG. Swift knows how to call supported C++ APIs, while Conan provides LunaSVG, its transitive dependencies, and the information needed to compile and link the application. A small Clang module map makes LunaSVG’s headers importable from Swift. The complete project is available in the Conan examples repository : cxx_interop/ ├── conanfile.py ├── demo.xcodeproj/ ├── main.swift ├── ci_test_example.py └── README.md Starting with the C++ API Before looking at Swift, it helps to see how the LunaSVG API would normally be used from C++. Given svg and css as std::string values holding an SVG document and a stylesheet, and output as the destination PNG path, rendering and writing the file looks like this: auto document = lunasvg :: Document :: loadFromData ( svg ); document -> applyStyleSheet ( css ); auto bitmap = document -> renderToBitmap (); bitmap . writeToPng ( output ); Although short, this fragment already touches several C++ features: a namespace, a static method, a std::unique_ptr , member functions, and a Bitmap returned by value. Making the C++ API Visible to Swift Before Swift can call this API, it needs to know which C++ header to import and the module name it should use. Swift gets this information through a Clang module map. module LunaSVGMod { header "/path/to/include/lunasvg/lunasvg.h" export * } This gives the LunaSVG header a module name, LunaSVGMod . Swift must then be compiled with C++ interoperability enabled and the module-map option is forwarded to the Clang importer used by the Swift compiler: -cxx-interoperability-mode=default -Xcc -fmodule-map-file=/path/to/lunasvg.modulemap -Xcc passes the following option to the Clang instance embedded in the Swift compiler. With these options, Swift can import LunaSVGMod and use the supported declarations from the header. The Xcode configuration shown later adds the same options using the module map generated by Conan. Note : Despite the similar terminology, this is a Clang module , not a named C++20 module. Swift does not currently import C++20 modules. Calling the Same API from Swift With the C++ standard library and LunaSVGMod imported, main.swift calls the same API to render the demo scene: import CxxStdlib import LunaSVGMod let svg = " ... " let css = ".sky{fill:#8ECBEB} ..." let document = lunasvg . Document . loadFromData ( std . string ( svg )) document . pointee . applyStyleSheet ( std . string ( css )) let bitmap = document . pointee . renderToBitmap () _ = bitmap . writeToPng ( std . string ( "summer.png" )) svg and css are ordinary Swift strings. The mapping is visible in the code: The C++ namespace lunasvg remains visible in Swift. Document::loadFromData becomes a static method. document is the std::unique_ptr that loadFromData returns, the smart pointer that owns the C++ object. Swift reaches the object it owns through pointee , the same role -> plays in the C++ version above. renderToBitmap returns a C++ Bitmap by value. writeToPng remains an ordinary member-function call. The std.string(...) conversions are explicit because Swift does not automatically bridge a dynamic Swift String to std::string . Constructing the C++ string allocates and copies the string data. Running this produces the actual LunaSVG output, summer.png : Putting It All Together Conan feeds Xcode through two generators, XcodeDeps and XcodeToolchain , which turn the dependency graph into a set of .xcconfig files an Xcode project can use as its build configuration. The generators provide the dependency and C++ toolchain settings, but they do not add the Swift-specific interoperability options required by this target. The -cxx-interoperability-mode flag and the module map still have to reach swiftc , through OTHER_SWIFT_FLAGS , the build setting Xcode passes straight to the Swift compiler. XcodeToolchain exposes build_settings , a plain dict of build settings to add to the .xcconfig file it generates. The consumer recipe’s generate() sets it alongside the module map from earlier, while layout() collects everything the generators write into a generators folder: def layout ( self ): self . folders . generators = "generators" def generate ( self ): XcodeDeps ( self ). generate () include_dir = self . dependencies [ "lunasvg" ]. cpp_info . includedir header = f " { include_dir } /lunasvg/lunasvg.h" modulemap_path = os . path . join ( self . generators_folder , "lunasvg.modulemap" ) modulemap = textwrap . dedent ( f ''' \ module LunaSVGMod {{ header " { header } " export * }} ''' ) save ( self , modulemap_path , modulemap ) cppstd = cppstd_flag ( self ) tc = XcodeToolchain ( self ) tc . build_settings [ "OTHER_SWIFT_FLAGS" ] = ( f '$(inherited) -cxx-interoperability-mode=default ' f '-Xcc { cppstd } -Xcc -fmodule-map-file=" { modulemap_path } "' ) tc . generate () cppstd_flag turns the profile’s compiler.cppstd into the matching -std= flag, so the headers are parsed with the same standard as the rest of the build. $(inherited) keeps any Swift flags the project already defines. build_settings needs Conan 2.32 or newer. The Xcode project uses generators/conan_config.xcconfig as the Base Configuration for its Release configuration, which makes everything Conan generates — include paths, linker options, and the Swift flags above — available to the target. Install the dependency, then open the project. Please use Conan 2.32 or newer. conan install . -s build_type = Release --build = missing open demo.xcodeproj From there it is a normal Xcode project: press Run, and Swift calls into LunaSVG. The same build also works from the command line: xcodebuild -project demo.xcodeproj -scheme demo -configuration Release \ -derivedDataPath build build ./build/Build/Products/Release/demo Running the executable writes summer.png to the working directory. Together, Conan, Xcode, and Swift’s C++ interoperability make an unmodified ConanCenter package directly callable from Swift, without a wrapper library. Direct access, however, does not remove the usual binary compatibility requirements of calling C++ code. The Limits of Direct Interoperability The module map exposes LunaSVG’s declarations, but Swift still calls a compiled C++ library through the platform C++ ABI. The headers and binary therefore need to agree on the target, compiler ABI, standard library, dependencies, and any option that changes public declarations. Conan’s package model is useful here: it selects or builds the native artifact that sits behind the imported API. Direct interop also does not turn a C++ API into a Swift-safe API. The most important points to keep in mind are: C++ ownership and lifetime rules still apply. The std::unique_ptr in this example must remain alive while Swift accesses pointee , and raw pointers or views require the same care they would in C++. Swift cannot catch C++ exceptions . A C++ exception that crosses the boundary terminates the program. Swift supports a growing subset of C++, not every template or standard-library type. The status page documents the current limitations. For libraries with unsupported constructs, exception-heavy APIs, or difficult lifetime rules, a small wrapper can still provide a cleaner boundary. The difference is that it is now a design choice rather than a requirement for every C++ library. Note : SwiftPM can also distribute C++ libraries for use through Swift’s C++ interoperability and is a convenient choice when a suitable package already exists. Here, Conan consumes LunaSVG and its transitive dependencies from ConanCenter without requiring the C++ dependency graph to be repackaged for SwiftPM. The Conan recipes reuse the libraries’ upstream build systems rather than rewriting their configuration and platform logic in Package.swift . Try the complete example and check the official Swift C++ interoperability guide for the complete mapping and safety rules. Happy coding! This post was written with AI assistance and reviewed by humans.📝Conan C/C++ Package Manager Blog

If this page is useful, please consider donating a coffee

Monday, August 31, 2026

No imageUpcoming events, Techtown and TokyoIn just a few short weeks it is time for the annual NDC Techtown conference where I this year will be giving the talk Mastering MC/DC from first principles . It is an excellent conference; the programme is splendid and I’m quite sure there will be many interesting conversations between sessions, I truly recommend attending. Do come see my talk and come chat with me. I will be also be giving a lecture on MC/DC in Tokyo and will be in Japan 4th-10th. If you would like to meet up, maybe have lunch or talk business, please send me an email and we’ll figure something out.📝patch – Blog

Sunday, August 30, 2026

Stanisław Lem foretold the current LLM mania in 1964Some time ago I visited a used book fair and came across this awesome piece of 80s scifi-asthetic. This book is a collection of short stories by the Polish author Stanisław Lem originally published in 1964. Its English title is The Cyberiad . One story, about Trurl's electronic troubadour, turned out to be surprisingly topical. Spoilers for the whole story follow The inventor Trurl (revealed in other stories to be a robot) wants to create a machine that can generate poetry. He begins by obtaining several hundred tonnes of books to use as training data. Trurl gets to work constructing the electric poetry machine. In the process they have to create massive data storage containers that stretch further out than one can see using binoculars. This is considered a necessary evil to get this great invention going. The machine will not work as expected. As a last resort Trurl rips out all logic circuits and replaces them with "narsistors". Then things start working. Trurl invites his friend Klapaucius over to test the new machine. They give it all sorts of weird and wacky instructions like "create a pastoral love poem that also contains mathematics and cybernetics". Basically they do a whole bunch of prompt engineering. They talk and behave exactly like people of 2021-2023 did when LLMs first appeared. Eventually the machine causes uproar among poets and there are protests demanding it to shut down. These go nowhere in part because the media secretly love the machine. They are using it to create their own content for pennies and thus don't want to see it come to harm. As all of this is going on various people develop symptoms quite similar to modern day AI psychosis. Things eventually crash when Trurl gets the machine's electrical bill, which turns out to be astronomical. He needs to get rid of the machine and manage to dump it on a visiting dignitary who takes it to his home planet where causes a supernova explosion. Trurl deems that to be sufficiently far away to not be his problem any more. The difference between fact and fiction In the story all the problems are caused by the fact that the machine's output is vastly higher quality than anything humans can create. Even the great Stanisław Lem could not predict that in reality the output would turn out to be mediocre garbage and still lead to all the same problems. Even though the story specifies that the machine is given some "basic instructions" first, nobody tries to do a prompt injection attack on it. That would only appear almost 30 years later in 1993's Paranoia novel Title Deleted for Security Reasons . An earlier example may well exist somewhere, it almost always does.📝Nibble Stew
C++26: Standard Library Hardening Experiments“Hardening” seems to be a very popular term in the C++ World in 2026. In this article we’ll explore what this word means and see some core examples. Can a hardened library make C++ fully safe? Let’s find out. The Core Idea When you learned about std::vector you may remember that you can access an element at the i -th position using at least two expressions: std :: vector int > v { 1 , 2 , 3 , 4 }; v [ i ] = 10 ; // for some i v . at ( j ) = 11 ; // for some j The main difference between those two is that [] is unchecked (and can generate undefined behaviour if you try to access an element which is not there), while .at() may throw std::out_of_range (so it’s a well defined behaviour). C++26 Changes In C++26, the Standard introduces the notion of a hardened implementation . Whether a standard-library implementation is hardened, and how that mode is enabled, is implementation-defined. For std::vector ::operator[](size_type pos) : C++ Standard Condition until C++26 If pos is false , the behavior is undefined. since C++26 If pos is false : If the implementation is hardened, a contract violation occurs, If the implementation is not hardened, the behavior is undefined. In other words, if you switch this “hardened” mode you’ll get some well specified error/violation rather than just an undefined behaviour. Let’s untangle the wording and common questions: For .at() you may get an exception… so why do we need a new alternative? That’s fair question. In short at() and [] has different interfaces and performance/error-handling approaches. What’s more important you cannot turn exceptions off easily (you can, and std::terminate will be called, but that’s not very flexible). So Hardening does not change operator[] into at() - it detects a programming error and terminates instead of allowing memory-unsafe undefined behaviour. “A contract violation occurs” - this is the key thing here. The “hardening” feature is expressed in terms of Contracts that also were accepted into C++26. C++26 specifies hardened preconditions using the new Contracts model: violating one in a hardened implementation causes a contract violation evaluated with a terminating semantic. However, a library implementation does not necessarily implement these checks using the actual pre , post , or contract_assert language syntax. So what is this contract violation? Ordinary C++26 Contracts may use ignore, observe, enforce, or quick-enforce semantics. Hardened Standard Library preconditions are more restrictive: in a hardened implementation they must use a terminating semantic, so execution cannot continue after a failed check. It’s implementation dependent on how to switch between those modes. Read more here: Contract assertions (since C++26) - cppreference.com Does it work in runtime? Yes, actually it can run in constant expressions, but, more importantly, it runs at runtime. How does this relate to things like GLIBCXX_ASSERTIONS , _ITERATOR_DEBUG_LEVEL and others? C++26 tries to bring those vendor specific checkers and create a common, well defined, set of rules. The Main question: How to enable this thing? GCC / libstdc++: _GLIBCXX_ASSERTIONS enables lightweight Standard Library precondition checks. GCC’s broader -fhardened option enables it automatically together with other security options. Clang / libc++: use _LIBCPP_HARDENING_MODE , with NONE , FAST , EXTENSIVE , and DEBUG modes. MSVC STL: _MSVC_STL_HARDENING=1 enables hardening globally. Individual types can be controlled with macros such as _MSVC_STL_HARDENING_VECTOR and _MSVC_STL_HARDENING_OPTIONAL . Note: At the time of writing (August 2026), compiler and library vendors are still completing the C++26 feature. The options below are the current vendor hardening mechanisms and do not necessarily represent complete implementations of P3471/P3697/P3878 Core documents and proposals We have the following papers that make the whole feature, as of C++26: P3471 - main Standard library hardening P3697 - Minor additions to C++26 standard library hardening - basic_stacktrace, shared_ptr , view_interface (front, back), counted_iterator, common_iterator P3878 - Standard library hardening should use a terminating semantic. Ensures that a hardened-precondition violation cannot simply be observed and then continue into the UB that hardening was intended to prevent. Hardening Modes — libc++ documentation To specify hardening in the Standard, this proposal introduces the notion of a hardened precondition . A hardened precondition is a precondition that results in a contract violation in a hardened implementation . Adding hardening to the library largely consists of turning some of the existing preconditions into hardened preconditions in the specification. What conditions are candidates to get the hardened implementation? Violating the precondition results in a memory safety issue (an out-of-bounds access or an access to uninitialized memory); The call site has all the necessary data to perform the check; The check can be done in constant time and imposes relatively little overhead. C++26 hardened conditions Here’s a summary of what conditions/member functions are checked: Category Classes / types Hardened operations Sequence containers array , vector , inplace_vector , deque , list , forward_list operator[] , front() , back() , pop_front() , pop_back() Container views span , mdspan , view_interface construction, operator[] , front() , back() , first() , last() , subspan() Iterator adaptors common_iterator , counted_iterator construction, operator* , operator-> , operator[] , operator++ , arithmetic, comparisons, iter_move , iter_swap Strings basic_string , basic_string_view operator[] , front() , back() , pop_back() , remove_prefix() , remove_suffix() General utilities bitset , optional , expected operator[] , operator* , operator-> , error() Stacktrace basic_stacktrace current() , operator[] Smart pointers shared_ptr operator[] Numeric arrays valarray operator[] At cppreference.com there’s a cool table that summarizes all conditions and standard library types. See “Functions with hardened preconditions” at https://en.cppreference.com/cpp/standard_library A Basic Example Let’s start with a basic “hello world” example. We see the default compiler behaviour, and then how does it change with the hardening options. #include #include int main () { std :: vector int > v { 1 , 2 , 3 }; int a = 10 ; std :: cin >> a ; v [ a ] = a ; std :: cout "hello world!" ; } Running on GCC 16.1 with just -std=c++26 and passing 100000 as input: Program returned : 139 Program stderr / cefs / 38 / 383 ad2f84cbd57a52fd68bbe_consolidated / compilers_c ++ _x86_gcc_16 .1.0 / include / c ++/ 16.1.0 / bits / stl_vector . h : 1253 : constexpr std :: vector _Tp , _Alloc >:: reference std :: vector _Tp , _Alloc >:: operator []( size_type ) [ with _Tp = int ; _Alloc = std :: allocator int > ; reference = int & ; size_type = long unsigned int ] : Assertion ' __n this -> size () ' failed . Program terminated with signal : SIGSEGV Hmm… is it already hardened by default? See @Compiler Explorer With GCC 16.1 we don’t even have to explicitly enable hardening in an unoptimized build. Current libstdc++ enables _GLIBCXX_ASSERTIONS by default when compiling without optimization. Once optimization is enabled, these assertions are disabled by default. So compile with -O2 and we get: Program returned : 139 Program stderr Program terminated with signal : SIGSEGV See here @Compiler Explorer In other words without optimizations, you could already have some runtime checks enabled by default. On the other hand, to enable hardened mode in optimized GCC build we need to specify: -std=c++26 -O2 -D_GLIBCXX_ASSERTIONS Program returned : 139 Program stderr / cefs / 38 / 383 ad2f84cbd57a52fd68bbe_consolidated / compilers_c ++ _x86_gcc_16 .1.0 / include / c ++/ 16.1.0 / bits / stl_vector . h : 1253 : constexpr std :: vector _Tp , _Alloc >:: reference std :: vector _Tp , _Alloc >:: operator []( size_type ) [ with _Tp = int ; _Alloc = std :: allocator int > ; reference = int & ; size_type = long unsigned int ] : Assertion ' __n this -> size () ' failed . Program terminated with signal : SIGSEGV We can also use -fhardened that adds even more safety checks, for example: -D_FORTIFY_SOURCE=3 -D_GLIBCXX_ASSERTIONS -ftrivial-auto-var-init=zero -fPIE -pie -Wl,-z,relro,-z,now -fstack-protector-strong -fstack-clash-protection -fcf-protection=full On Clang Trunk I’m getting the following: compiled with: -std=c++26 -stdlib=libc++ -D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_DEBUG Program stderr vector.h:414: libc++ Hardening assertion __n Program terminated with signal: SIGSEGV See @compiler Explorer Note: libc++ offers NONE , FAST , EXTENSIVE , and DEBUG hardening modes. I’m using DEBUG here because it prints a useful diagnostic; libc++ recommends FAST for most production applications. Real-World Bugs Beyond std::vector Would you like to see more? In the extended version of the article @Patreon , we describe the following bugs that were found with enabling the hardening mode: Calling `std::deque::back()` on an Empty Container and Dereferencing an Empty `std::optional` See all Premium benefits here . How much does it cost at runtime? Would you like to see more? In the extended version of the article @Patreon , we discuss some basic assembler outputs, plus real-life experiments (done by some large companies). See all Premium benefits here . Summary In the text we looked at the important C++26 feature “Standard Library hardening”. We started with the classic example of std::vector::operator[] , where an out-of-bounds index used to mean UB. In a hardened implementation, selected Standard Library preconditions are checked and violations use terminating semantics instead. We also saw that hardening is broader than bounds checking. It covers cases such as: accessing front() or back() on an empty container, dereferencing a disengaged std::optional , using std::expected in the wrong state, invalid operations on span , string_view , iterators, shared_ptr , and other library types. We also looked at the three main papers behind the C++26 feature: P3471, P3697, and P3878. Together they define which preconditions are hardened and, importantly, require hardened violations to use terminating semantics rather than allowing execution to continue. The implementation side is still very much in progress . The Standard deliberately leaves the mechanism for enabling a hardened implementation to vendors, and the major libraries currently expose different approaches: libstdc++ uses existing mechanisms such as _GLIBCXX_ASSERTIONS , also enabled as part of GCC’s broader -fhardened option; libc++ provides several hardening modes such as FAST , EXTENSIVE , and DEBUG ; MSVC STL uses _MSVC_STL_HARDENING together with more fine-grained per-library-type switches. Those implementations also do not necessarily use the actual C++26 pre , post , or contract_assert syntax internally. Compiler and Standard Library vendors are still completing and aligning their Contracts and hardening implementations. So C++26 hardening does not suddenly make C++ memory safe, nor does it replace sanitizers, static analysis, good API design, or careful validation. What it does provide is a standardized baseline for turning several common and dangerous Standard Library precondition violations from silent undefined behaviour into detectable, terminating failures. References and Links Technical references Compiler Options Hardening Guide for C and C++ | OpenSSF Best Practices Working Group STL Hardening · microsoft/STL Wiki · GitHub Books Secure Coding in C and C++ (SEI Series in Software Engineering) by Robert Seacord Embracing Modern C++ Safely by John Lakos, Vittorio Romeo, Rostislav Khlebnikov, and Alisdair Meredith C++ Memory Management by Patrice Roy📝C++ Stories

Saturday, August 29, 2026

Friday, August 28, 2026

Thursday, August 27, 2026