Swift/C++ interoperability: SWIFT_PRIVATE_ATTR compilation error on Ubuntu

Hi There :wave:

I'm trying to tame Swift and C++ interoperability with CMake.

On macOS, everything works fine, but I have an issue on Ubuntu:

[3/4] /usr/bin/clang++-15  -I/home/runner/work/eat-swift-from-cpp/eat-swift-from-cpp/build/include -std=gnu++17 -MD -MT CMakeFiles/cpp_ex.dir/main.cc.o -MF CMakeFiles/cpp_ex.dir/main.cc.o.d -o CMakeFiles/cpp_ex.dir/main.cc.o -c /home/runner/work/eat-swift-from-cpp/eat-swift-from-cpp/main.cc
make: *** [Makefile:16: build] Error 1
FAILED: CMakeFiles/cpp_ex.dir/main.cc.o 
/usr/bin/clang++-15  -I/home/runner/work/eat-swift-from-cpp/eat-swift-from-cpp/build/include -std=gnu++17 -MD -MT CMakeFiles/cpp_ex.dir/main.cc.o -MF CMakeFiles/cpp_ex.dir/main.cc.o.d -o CMakeFiles/cpp_ex.dir/main.cc.o -c /home/runner/work/eat-swift-from-cpp/eat-swift-from-cpp/main.cc
In file included from /home/runner/work/eat-swift-from-cpp/eat-swift-from-cpp/main.cc:1:
/home/runner/work/eat-swift-from-cpp/eat-swift-from-cpp/build/include/swift-lib.h:323:17: error: expected '{'
namespace swift SWIFT_PRIVATE_ATTR {
                ^
/home/runner/work/eat-swift-from-cpp/eat-swift-from-cpp/build/include/swift-lib.h:323:17: error: a type specifier is required for all declarations
/home/runner/work/eat-swift-from-cpp/eat-swift-from-cpp/build/include/swift-lib.h:325:1: error: expected expression
namespace _impl {
^
/home/runner/work/eat-swift-from-cpp/eat-swift-from-cpp/build/include/swift-lib.h:542:2: error: expected ';' after top level declarator
} // namespace swift
 ^
 ;
4 errors generated.

It seems that on Ubuntu, clang is unhappy with the generated header file :confused:

Clang: 15.0.7
Swift: 5.9.2
OS: Ubuntu 22.04.4

I have a reproducible example of GH action: ci: install swift via swift-actions/setup-swift@v2 · tony-go/eat-swift-from-cpp@8da6b98 · GitHub

I also have a working example for macOS: ci: install swift via swift-actions/setup-swift@v2 · tony-go/eat-swift-from-cpp@8da6b98 · GitHub

I tried to make the compiler and Swift version match on both OSes, but the error still persists.

I open a pull request here: ci: add linux by tony-go · Pull Request #1 · tony-go/eat-swift-from-cpp · GitHub

Could you please try building with the Clang compiler that is included in the Swift toolchain – would the same issue reproduce there?

I am experiencing a similar error on Rhel 9.

Thanks, I'll try :)

The problem is caused by the C++ compiler not being able to find _SwiftCxxInteroperability.h. The generated header file has some logic that tries to find it, but if it doesn't then it just fails silently.

To fix this you need to find where this file is located on your system and add that path to the include directories. For example:

  • I've found out that this file is located in /usr/lib/swift/lib/swift/swiftToCxx/_SwiftCxxInteroperability.h.
  • The generated header file tries to include swiftToCxx/_SwiftCxxInteroperability.h as a first step, so we need to add /usr/lib/swift/lib/swift/ to the include search path,
  • Since I'm using CMake in my project, I'll add -DCMAKE_CXX_FLAGS=-isystem\ /usr/lib/swift/lib/swift/, and this solves the problem.

This is a bit of a bugbear of mine, that you need to use unsafe flags and some heuristics (based on the compiler path) to add the include directory for these headers when using SwiftPM. (Ditto for the block and dispatch headers.) I did file an issue at some point...

Personally I think that having the logic is one thing, but failing silently is something completely different, as the resulting error in the end is kind of confusing. If it failed stating directly that a header file cannot be found then I guess that it would save a bit of time while debugging :wink:

1 Like