Swift/C++ interop with a C++ custom standard library

Hello Swift/C++ Interoperability Workgroup,

The Chromium for iOS team is exploring enabling Swift/C++ interoperability within our codebase. We're very excited about the potential of this feature.

A key aspect of the Chromium build environment is that we use a custom version of libc++ with certain features restricted. We understand that the Swift compiler is tightly integrated with the platform's system C++ standard library, as noted in the documentation:

Swift compiler uses the platform’s default C++ standard library when interoperating with C++.

To work around this, we attempted to direct swiftc to our custom libc++ headers using -Xcc flags.

Here is the command we used:

$ swiftc -cxx-interoperability-mode=default \
-Xcc=-nostdinc++ \
-Xcc=-isystem <path-to-chromium>/third_party/libc++/src/include \
-Xcc=-isystem <path-to-chromium>/third_party/libc++abi/src/include \
<and other flags>

and what we get from the build:

<path-to-chromium>/src/out/Debug-iphoneos/../../third_party/libc++/src/include/stdexcept:188:34: error: 'std::overflow_error::overflow_error' from module 'Pointer' is not present in definition of 'std::overflow_error' in module 'Darwin.C.complex'
186 | class _LIBCPP_EXPORTED_FROM_ABI overflow_error : public runtime_error {
187 | public:
188 |   _LIBCPP_HIDE_FROM_ABI explicit overflow_error(const string& __s) : runtime_error(__s) {}
    |                                  |- error: 'std::overflow_error::overflow_error' from module 'Pointer' is not present in definition of 'std::overflow_error' in module 'Darwin.C.complex'
    |                                  `- note: declaration of 'overflow_error' does not match
189 |   _LIBCPP_HIDE_FROM_ABI explicit overflow_error(const char* __s) : runtime_error(__s) {}
    |                                  `- note: declaration of 'overflow_error' does not match
190 | 
191 | #  ifndef _LIBCPP_ABI_VCRUNTIME 192 |   _LIBCPP_HIDE_FROM_ABI overflow_error(const overflow_error&) _NOEXCEPT            = default;
    |                         `- note: declaration of 'overflow_error' does not match
193 |   _LIBCPP_HIDE_FROM_ABI overflow_error& operator=(const overflow_error&) _NOEXCEPT = default;
194 |   ~overflow_error() _NOEXCEPT override;

Our interpretation of this error is that the Swift compiler is importing C++ type definitions from a system module, which then conflicts with the definitions provided by our custom libc++ headers. This creates a redefinition or mismatch error.

Given this context, we have a few questions:

Does our interpretation sound correct?

Is there a way to prevent the Swift compiler from importing the C++ standard library from system modules?

Any idea or workaround to achieve Swift/C++ interop in such an environment?

Any guidance or insight would be greatly appreciated. Thank you for your time and for all your work on this project.

3 Likes

Hi @d0iasm,

Really excited that you are considering using Swift/C++ interop in Chromium!

In general, the Swift compiler supports building with a custom C++ stdlib. The error you’re seeing here is coming out of Clang, it looks like an issue with Clang modules – some of the std:: types are being assigned to wrong Clang modules. I suspect the problem here might be an incorrect order of include search paths. Could you please try running swiftc with -Xcc -v to get an ordered list of the include search paths?

3 Likes

Thank you for your response.

The custom libc++ header files exist in third_party/libc++/src/include, which are listed after some sdk/xcode_links directories. Should we bring it to the beginning to the list?

#include "..." search starts here:
#include <...> search starts here:
 ../../buildtools/third_party/libc++
 ../..
 gen
 ../../third_party/perfetto/include
 gen/third_party/perfetto/build_config
 gen/third_party/perfetto
 ../../base/allocator/partition_allocator/src
 gen/base/allocator/partition_allocator/src
 ../../third_party/abseil-cpp
 ../../third_party/boringssl/src/include
 ../../third_party/protobuf/src
 sdk/xcode_links/iPhoneSimulator.platform/Developer/usr/lib
 sdk/xcode_links/iPhoneSimulator.platform/Developer/Library/Frameworks (framework directory)
 sdk/xcode_links/iPhoneSimulator18.5.sdk/Developer/Library/Frameworks (framework directory)
 /<path-to-chromium>/src/out/Debug-iphonesimulator/sdk/xcode_links/iPhoneSimulator18.5.sdk/usr/lib/swift/shims
 /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift
 ../../third_party/libc++/src/include
 ../../third_party/libc++abi/src/include
 /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/clang/include
 /<path-to-chromium>/src/out/Debug-iphonesimulator/sdk/xcode_links/iPhoneSimulator18.5.sdk/usr/include
 /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include
 /<path-to-chromium>/src/out/Debug-iphonesimulator/sdk/xcode_links/iPhoneSimulator18.5.sdk/System/Library/Frameworks (framework directory)
End of search list.
1 Like

Hello @egor.zhdan,

I succeeded to make a standalone app to reproduce the error.

The key point of this project is having multiple modules that depend on the same libc++ and libc++ is not a platform’s default C++ standard.

Interestingly, the errors only appear from the clean build. You may need to clear the cache under `~/Library/Developer/Xcode/DerivedData` to see the errors.


module A {
  ... // this includes some libc++ like #include <string>
}

module B {
  ... // this also includes the same libc++ as module A includes.
}

I found a workaround to avoid the errors. Wrapping all user defined modules with an outer module solved the errors.

module wrapper { // <-- add a wrapper module
module A {
  ... // this includes some libc++ like #include <string>
}

module B {
  ... // this also includes the same libc++ as module A includes.
}
}

I’m guessing that the compiler interprets modules one by one and has a different subset of libc++ in each module.