Skip to content

Commit 417adb5

Browse files
authored
C++ Interop Getting Started Documentation (#41580)
1 parent 922201e commit 417adb5

File tree

2 files changed

+209
-0
lines changed

2 files changed

+209
-0
lines changed
Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
# Getting started with C++ Interoperability
2+
3+
This document is desgined to get you started with bidirectional API-level interoperability between Swift and C++.
4+
5+
## Table of Contents
6+
7+
- [Creating a Module to contain your C++ source code](#creating-a-module-to-contain-your-c-source-code)
8+
- [Adding C++ to an Xcode project](#adding-c-to-an-xcode-project)
9+
- [Creating a Swift Package](#Creating-a-Swift-Package)
10+
- [Building with CMake](#building-with-cmake)
11+
12+
## Creating a Module to contain your C++ source code
13+
14+
- Create a new C++ implementation and header file
15+
- For this example we will call the files Cxx, so we should have a Cxx.cpp and Cxx.hpp.
16+
- 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 cplusplus` isn't required but it's convention for C++ modules, especially if they use C++ features).
17+
18+
```
19+
//In module.modulemap
20+
module Cxx {
21+
//note that your header should be the file that containts your method implementations
22+
header "Cxx.hpp"
23+
requires cplusplus
24+
}
25+
```
26+
27+
- Move the newly created files (Cxx.cpp, Cxx.hpp, module.modulemap) into a separate directory (this should remain in your project directory)
28+
29+
<img width="252" alt="Screen Shot 2022-02-26 at 9 14 06 PM" src="https://user-images.githubusercontent.com/62521716/155867937-9d9d6c62-4418-414d-bc4e-5d12c2055022.png">
30+
31+
## Adding C++ to an Xcode project
32+
- In your xcode project, follow the steps [Creating a Module to contain your C++ source code](#creating-a-module-to-contain-your-c-source-code) in your project directory
33+
34+
Add the C++ module to the include path and enable C++ interop:
35+
- Navigate to your project directory
36+
- In `Project` navigate to `Build Settings` -> `Swift Compiler`
37+
- Under `Custom Flags` -> `Other Swift Flags` add`-Xfrontend -enable-cxx-interop`
38+
- Under `Search Paths` -> `Import Paths` add your search path to the C++ module (i.e, `./ProjectName/Cxx`).
39+
40+
```
41+
//Add to Other Swift Flags and Import Paths respectively
42+
-Xfrontend -enable-cxx-interop
43+
-I./ProjectName/Cxx
44+
```
45+
46+
- This should now allow your to import your C++ Module into any `.swift` file.
47+
48+
```
49+
//In ViewController.swift
50+
import UIKit
51+
import Cxx
52+
53+
class ViewController: UIViewController {
54+
override func viewDidLoad() {
55+
super.viewDidLoad()
56+
let result = cxxFunction(7)
57+
print(result)
58+
}
59+
}
60+
```
61+
62+
```
63+
//In Cxx.cpp
64+
65+
#include "Cxx.hpp"
66+
int cxxFunction(int n) {
67+
return n;
68+
}
69+
70+
```
71+
72+
```
73+
//In Cxx.hpp
74+
75+
#ifndef Cxx_hpp
76+
#define Cxx_hpp
77+
78+
int cxxFunction(int n);
79+
80+
#endif
81+
82+
```
83+
84+
85+
## Creating a Swift Package
86+
After creating your Swift package project, follow the steps [Creating a Module to contain your C++ source code](#creating-a-module-to-contain-your-c-source-code) in your `Source` directory
87+
88+
- In your Package Manifest, you need to configure the Swift target's dependencies and compiler flags
89+
- In this example the name of the package is `Cxx_Interop`
90+
- Swift code will be in `Sources/Cxx_Interop` called `main.swift`
91+
- C++ source code follows the example shown in [Creating a Module to contain your C++ source code](#creating-a-module-to-contain-your-c-source-code)
92+
- Under targets, add the name of your C++ module and the directory containing the Swift code as a target.
93+
- In the target defining your Swift target, add a`dependencies` to the C++ Module, the `path`, `source`, and `swiftSettings` with `unsafeFlags` with the source to the C++ Module, and enable `-enable-cxx-interop`
94+
95+
```
96+
//In Package Manifest
97+
98+
import PackageDescription
99+
100+
let package = Package(
101+
name: "Cxx_Interop",
102+
platforms: [.macOS(.v12)],
103+
products: [
104+
.library(
105+
name: "Cxx",
106+
targets: ["Cxx"]),
107+
.library(
108+
name: "Cxx_Interop",
109+
targets: ["Cxx_Interop"]),
110+
],
111+
targets: [
112+
.target(
113+
name: "Cxx",
114+
dependencies: []
115+
),
116+
.executableTarget(
117+
name: "Cxx_Interop",
118+
dependencies: ["Cxx"],
119+
path: "./Sources/Cxx_Interop",
120+
sources: [ "main.swift" ],
121+
swiftSettings: [.unsafeFlags([
122+
"-I", "Sources/Cxx",
123+
"-Xfrontend", "-enable-cxx-interop",
124+
])]
125+
),
126+
]
127+
)
128+
129+
```
130+
131+
- We are now able to import our C++ Module into our swift code, and import the package into existing projects
132+
133+
```
134+
//In main.swift
135+
136+
import Cxx
137+
138+
public struct Cxx_Interop {
139+
140+
public func callCxxFunction(n: Int32) -> Int32 {
141+
return cxxFunction(n: n)
142+
}
143+
}
144+
145+
print(Cxx_Interop().callCxxFunction(n: 7))
146+
//outputs: 7
147+
148+
```
149+
150+
## Building with CMake
151+
After creating your project follow the steps [Creating a Module to contain your C++ source code](#creating-a-module-to-contain-your-c-source-code)
152+
153+
- Create a `CMakeLists.txt` file and configure for your project
154+
- In`add_library` invoke `cxx-support` with the path to the C++ implementation file
155+
- Add the `target_include_directories` with `cxx-support` and path to the C++ Module `${CMAKE_SOURCE_DIR}/Sources/Cxx`
156+
- Add the `add_executable` to the specific files/directory you would like to generate source, with`SHELL:-Xfrontend -enable-cxx-interop`.
157+
- In the example below we will be following the file structure used in [Creating a Swift Package](#Creating-a-Swift-Package)
158+
159+
```
160+
//In CMakeLists.txt
161+
162+
cmake_minimum_required(VERSION 3.18)
163+
164+
project(Cxx_Interop LANGUAGES CXX Swift)
165+
166+
set(CMAKE_CXX_STANDARD 11)
167+
set(CMAKE_CXX_STANDARD_REQUIRED YES)
168+
set(CMAKE_CXX_EXTENSIONS OFF)
169+
170+
add_library(cxx-support ./Sources/Cxx/Cxx.cpp)
171+
target_compile_options(cxx-support PRIVATE
172+
-I${SWIFT_CXX_TOOLCHAIN}/usr/include/c++/v1
173+
-fno-exceptions
174+
-fignore-exceptions
175+
-nostdinc++)
176+
target_include_directories(cxx-support PUBLIC
177+
${CMAKE_SOURCE_DIR}/Sources/Cxx)
178+
179+
add_executable(Cxx_Interop ./Sources/Cxx_Interop/main.swift)
180+
target_compile_options(Cxx_Interop PRIVATE
181+
"SHELL:-Xfrontend -enable-cxx-interop"
182+
target_link_libraries(Cxx_Interop PRIVATE cxx-support)
183+
184+
```
185+
186+
```
187+
//In main.swift
188+
189+
import Cxx
190+
191+
public struct Cxx_Interop {
192+
public static func main() {
193+
let result = cxxFunction(7)
194+
print(result)
195+
}
196+
}
197+
198+
Cxx_Interop.main()
199+
200+
```
201+
202+
- In your projects direcetoy, run `cmake` to generate the systems build files
203+
204+
- To generate an Xcode project run `cmake -GXcode`
205+
- To generate with Ninja run `cmake -GNinja`
206+
207+
- For more information on `cmake` see the 'GettingStarted' documentation: (https://github.com/apple/swift/blob/main/docs/HowToGuides/GettingStarted.md)
208+
209+

0 commit comments

Comments
 (0)