Swift/C++ interop.

I’m trying to use the relatively-new interop feature of Swift and C++.

Apple provides this example repo:

But their interop example only compiles using the Ninja generator, and fails with the Xcode generator.

Is there any example/resource on doing something like that in a way that works with Xcode as well?

The README for that repo explicitly says the following:

These projects build with the Ninja generator (e.g cmake -G 'Ninja' ... ) and likely do not work with the other generators.

You may need to open an issue in that repo to ask the authors of that repo to find out why. Evan Wilde is active in the CMake issue tracker for Swift-related things, but he doesn’t appear to have an account here in the CMake forums.

1 Like

Hey @craig.scott!

First of all I love your book, it’s been extremely helpful when I just got into CMake, so thank you!

I will open an issue with Apple’s repo now, but I don’t mind so much if Apple’s repo works or not.

I’m just looking for a way to get it to work myself. I wonder if that’s a CMake limitation, or a scripting issue that can be solved on the user’s side (mine)?

I definitely don’t mind passing special flags only to get the Xcode generator, if I could find some docs/examples to show what they are.

When I made vanilla repos myself, and passed similar compile options to the one Apple uses:

      -module-name "${ARG_MODULE_NAME}"
      -cxx-interoperability-mode=default
      -emit-clang-header-path ${header_path}

I got similar results (works with Ninja, fails with Xcode).

The Apple repository was forked from my original work - the only supported generator is the Ninja generator. The Xcode generator support for Swift is older and does not support all the features that Evan and I have worked on for Ninja. Neither one of us is actively working on the Xcode generator and if someone is interested in use of the new features in the Xcode generator, they would need to update the implementation for that.

2 Likes

Thank you @compnerd!

So are you saying CMake itself needs to implement something in the Xcode generator on the backend, or does the CMake script in the repo needs to be updated?

If it’s in CMake itself, can you perhaps give me a hint on what’s missing exactly? I might be able to attempt doing that myself and create a PR.

What I did notice is that the compiler command seems very different between the two generators - the Xcode generator is adding a lot more arguments which I also find worrying for other reasons (ideally, the binary created in each build system would be the same).

The Xcode generator is part of CMake itself. I cannot really give you a good hint as to what is missing, my hint would be re-write the entire Xcode generator support for Swift. It was originally added in the Swift 2.x or 3.x days and a lot has changed since. You will need to figure out what Xcode generates and under what conditions and map the various properties to the appropriate settings in the project file.

Note that you will not be able to get it to parity with the Ninja build as we have also adopted a more granular approach for Ninja and I do not believe that you can split out the Swift compilation without making the compilation a set of custom commands, and that would largely negate the value of the Xcode build.

NP, I’m happy to look into that and check out the implementation details.

The importance of the Xcode generator to me is the IDE support.

First because Xcode is the only IDE (to my knowledge) with good Swift support, but I’m also working with developers who use Xcode as their main IDE for C++ projects even when they don’t directly work on the Swift/Objective C portion of the cross platform codebase.

Anyway I’ll know more once I poke into the implementation - thank you for your help!

The high-level issue is that the Xcode project format is an unstable and undocumented format, which makes it difficult (or impossible) for anyone who isn’t working on the Xcode project format to match what Xcode does. For this reason, I wouldn’t generally recommend using the Xcode generator.

The project format doesn’t provide the same level of control over how the compilers are invoked or the build graph that tools like Ninja allow, which makes it much harder to communicate the build order dependencies needed to handle things like bi-directional C++ interop from external tools, like CMake, to the Xcode build system.

I would recommend looking into the VSCode Swift plugin. CMake 3.29 and newer (with CMP0157 set to NEW) is able to emit the compile-commands for Swift that SourceKit-LSP can ingest and provide semantic editor functionality for anything that has LSP support. This also includes Neovim, Emacs, and friends. There are articles on how to set those up, but since I’m new to this forum, I’m limited to two links. :sweat_smile:

No, it is not a fork of your repository. It was written from scratch.

1 Like

Thank you Evan!

Not using Xcode is a deal breaker in adoption of Swift for us.

It’s an IDE many/most of my collaborators over the years are using (even when it’s not my main one).

I’m also releasing iOS apps and I even though personally I prefer using CLion and VS Code, I wouldn’t be very comfortable releasing Mac and iOS apps without the tools built into Xcode/Instruments/Archiving utilities, etc.

I definitely understand the challenges in implementing this though - but since the Xcode generator can (generally speaking) build quite a lot of complicated exiting C++ and Objective C codebases, I’m fairly confident that with some effort, solutions on CMake’s side can be found - perhaps with some collaboration with Apple to document what’s missing on the Xcode document format?