Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to consume Swift modules when Cxx interop is enabled #15

Open
tony-go opened this issue Apr 30, 2024 · 1 comment
Open

How to consume Swift modules when Cxx interop is enabled #15

tony-go opened this issue Apr 30, 2024 · 1 comment

Comments

@tony-go
Copy link

tony-go commented Apr 30, 2024

Hey there 👋🏼

First, thanks for this repository, he helped me learn a lot about Swift and CMake and Swift/Cxx interop.

I was experimenting with Swift/Cxx interoperability, especially with consuming a Swift class from C++.

It worked nicely until I needed to import a Swift module from one file to another.

Here is my project structure:

├── CMakeLists.txt
├── app
│   ├── App.cc  
│   ├── App.swift                 // HERE, I NEED to import module from window.swift
│   ├── CMakeLists.txt
│   └── include
│       ├── application.h
│       └── module.modulemap
├── main.cc
└── window
    ├── CMakeLists.txt
    ├── include
    │   ├── module.modulemap
    │   └── window.h
    ├── window.cc
    └── window.swift
import Ui

But it does not work as expected:

[4/8] Generating '/Users/tonygo/oss/native-research/build/app/include/app-swift.h'
FAILED: app/include/app-swift.h /Users/tonygo/oss/native-research/build/app/include/app-swift.h
cd /Users/tonygo/oss/native-research/build/app && /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swiftc -frontend -typecheck -I/Users/tonygo/oss/native-research/app/include /Users/tonygo/oss/native-research/app/App.swift -sdk /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.2.sdk -module-name Native -cxx-interoperability-mode=default -emit-clang-header-path /Users/tonygo/oss/native-research/build/app/include/app-swift.h
/Users/tonygo/oss/native-research/app/App.swift:3:8: error: no such module 'Ui'
import Ui
       ^

But when I looked at the build output, I saw Ui module files generated:

├── build
│   └── window
│       ├── CMakeFiles
│       │   └── window.dir
│       │       ├── output-file-map.json
│       │       ├── window.cc.o
│       │       ├── window.swift.o
│       │       ├── window.swift.o.d
│       │       ├── window.swift.swiftdoc
│       │       ├── window.swift.swiftmodule
│       │       ├── window.swift.swiftsourceinfo
│       │       └── window.swiftdeps
│       ├── Ui.abi.json
│       ├── Ui.swiftdoc
│       ├── Ui.swiftmodule
│       ├── Ui.swiftsourceinfo
│       ├── cmake_install.cmake
│       ├── include
│       │   └── window-swift.h
│       └── libwindow.a

I also tried with:

import window

Like it is done here: https://github.com/apple/swift-cmake-examples/tree/main/2_executable_library

I checked that app is linked to window target.

I wonder if it is not just a CMake knowledge that I miss or something else. I run out of ideas 😅.

@etcwilde
Copy link
Member

Hi, thanks for being patient.
It looks like swiftc failing to find the module while generating the C++ header for app_h from the Swift sources and isn't actually building the app target at all. The app_h target is missing the search path to where the Ui.swiftmodule lives.

The easiest way to fix that is to just pass it via the SEARCH_PATHS list so that the header generation finds both the Ui.swiftmodule and the module.modulemap:

generate_cxx_header_target_from_swift(
  app_h
  Native
  "${CMAKE_CURRENT_BINARY_DIR}/include/app-swift.h"
  SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/App.swift"
  SEARCH_PATHS
    "${CMAKE_CURRENT_SOURCE_DIR}/include"
    "${CMAKE_BINARY_DIR}/window"
    "${CMAKE_SOURCE_DIR}/window/include")

Then from there, I think it'll get into confusion between Ui::Window and Window. It's a bit risky to have the two modules with the same name (the Swift module and the C++ modulemap module are both called Ui). I honestly don't know what to expect with how that gets imported.

Anyway, I think this is enough to get you rolling again. I've done some fairly extensive reworking of how the header generation works so that it actually just wraps the base target and doesn't create a separate target (it doesn't automatically propagate include directories so you'll still hit this, though I think I can update it to handle that too. Not 100% sure if that will fix this specific issue though.).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants