6.3 KiB
Getting started with C++ Interoperability
This document is designed to get you started with bidirectional API-level interoperability between Swift and C++.
Table of Contents
- Creating a Module to contain your C++ source code
- Adding C++ to an Xcode project
- Creating a Swift Package
- Building with CMake
Creating a Module to contain your C++ source code
- Create a new target in Xcode via File | New | Target, select Library.
- Within the directory of the newly created target, create a new C++ implementation and header file
- For this example we will call the files CxxTest, so we should have a CxxTest.cpp and CxxTest.hpp.
- Next create an empty file and call it
module.modulemap, in this file create the module for your source code, and define your C++ header (requires cplusplusisn't required but it's convention for C++ modules, especially if they use C++ features).
// In module.modulemap
module CxxTest {
header "CxxTest.hpp"
requires cplusplus
}
Adding C++ to an Xcode project
- In your xcode project, follow the steps Creating a Module to contain your C++ source code in your project directory
Add the C++ module to the include path and enable C++ interop:
-
Navigate to your project directory
-
In
Projectnavigate toBuild Settings->Swift Compiler -
Under
Custom Flags->Other Swift Flagsadd-cxx-interoperability-mode=default -
Under
Search Paths->Import Pathsadd your search path to the C++ module (i.e,./ProjectName/CxxTest). -
This should now allow your to import your C++ Module into any
.swiftfile.
//In ContentView.swift
import SwiftUI
import CxxTest
struct ContentView: View {
var body: some View {
Text("CxxTest function result: \(cxxFunction(7))")
.padding()
}
}
// In CxxTest.hpp
#ifndef CxxTest_hpp
#define CxxTest_hpp
int cxxFunction(int n);
#endif
// In CxxTest.cpp
#include "CxxTest.hpp"
int cxxFunction(int n) {
return n;
}
Creating a Swift Package
After creating your Swift package project, follow the steps Creating a Module to contain your C++ source code in your Source directory
- In your Package Manifest, you need to configure the Swift target's dependencies and compiler flags
- In this example the name of the package is
CxxInterop - Swift code will be in
Sources/CxxInteropcalledmain.swift - C++ source code follows the example shown in Creating a Module to contain your C++ source code
- Under targets, add the name of your C++ module and the directory containing the Swift code as a target.
- In the target defining your Swift target, add a
dependenciesto the C++ Module, thepath,source, andswiftSettingswithunsafeFlagswith the source to the C++ Module, and enable-cxx-interoperability-mode=default
//In Package Manifest
import PackageDescription
let package = Package(
name: "CxxInterop",
platforms: [.macOS(.v12)],
products: [
.library(
name: "CxxTest",
targets: ["CxxTest"]),
.library(
name: "CxxInterop",
targets: ["CxxInterop"]),
],
targets: [
.target(
name: "CxxTest",
dependencies: []
),
.executableTarget(
name: "CxxInterop",
dependencies: ["CxxTest"],
path: "./Sources/CxxInterop",
sources: [ "main.swift" ],
swiftSettings: [.unsafeFlags([
"-I", "Sources/CxxTest",
"-cxx-interoperability-mode=default",
])]
),
]
)
- We are now able to import our C++ Module into our swift code, and import the package into existing projects
//In main.swift
import CxxTest
public struct CxxInterop {
public func callCxxFunction(n: Int32) -> Int32 {
return cxxFunction(n: n)
}
}
print(CxxInterop().callCxxFunction(n: 7))
//outputs: 7
Building with CMake
After creating your project follow the steps Creating a Module to contain your C++ source code
- Create a
CMakeLists.txtfile and configure for your project - In
add_libraryinvokecxx-supportwith the path to the C++ implementation file - Add the
target_include_directorieswithcxx-supportand path to the C++ Module${CMAKE_SOURCE_DIR}/Sources/CxxTest - Add the
add_executableto the specific files/directory you would like to generate source, withSHELL:-cxx-interoperability-mode=default. - In the example below we will be following the file structure used in Creating a Swift Package
// In CMakeLists.txt
cmake_minimum_required(VERSION 3.18)
project(CxxInterop LANGUAGES CXX Swift)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED YES)
set(CMAKE_CXX_EXTENSIONS OFF)
add_library(cxx-support ./Sources/CxxTest/CxxTest.cpp)
target_compile_options(cxx-support PRIVATE
-fno-exceptions
-fignore-exceptions)
target_include_directories(cxx-support PUBLIC
${CMAKE_SOURCE_DIR}/Sources/CxxTest)
add_executable(CxxInterop ./Sources/CxxInterop/main.swift)
target_compile_options(CxxInterop PRIVATE
"SHELL:-cxx-interoperability-mode=default"
target_link_libraries(CxxInterop PRIVATE cxx-support)
//In main.swift
import CxxTest
public struct CxxInterop {
public static func main() {
let result = cxxFunction(7)
print(result)
}
}
CxxInterop.main()
-
In your project's directory, run
cmaketo generate the systems build files -
To generate an Xcode project run
cmake -GXcode -
To generate with Ninja run
cmake -GNinja -
For more information on
cmakesee the 'GettingStarted' documentation: (https://github.com/swiftlang/swift/blob/main/docs/HowToGuides/GettingStarted.md)