Skip to content

Commit eefad4a

Browse files
dblsaikojpakkane
authored andcommitted
Add swift_interoperability_mode kwarg
1 parent 6473a72 commit eefad4a

File tree

10 files changed

+47
-17
lines changed

10 files changed

+47
-17
lines changed
Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,23 @@
11
## Swift/C++ interoperability is now supported
22

33
It is now possible to create Swift executables that can link to C++ or
4-
Objective-C++ libraries. Only specifying a bridging header for the Swift
5-
target is required.
4+
Objective-C++ libraries. To enable this feature, set the target kwarg
5+
_swift\_interoperability\_mode_ to 'cpp'.
6+
7+
To import C++ code, specify a bridging header in the Swift target's
8+
sources, or use another way such as adding a directory containing a
9+
Clang module map to its include path.
10+
11+
Note: Enabling C++ interoperability in a library target is a breaking
12+
change. Swift libraries that enable it need their consumers to enable
13+
it as well, as per [the Swift documentation][1].
614

715
Swift 5.9 is required to use this feature. Xcode 15 is required if the
816
Xcode backend is used.
917

1018
```meson
1119
lib = static_library('mylib', 'mylib.cpp')
12-
exe = executable('prog', 'main.swift', 'mylib.h', link_with: lib)
20+
exe = executable('prog', 'main.swift', 'mylib.h', link_with: lib, swift_interoperability_mode: 'cpp')
1321
```
22+
23+
[1]: https://www.swift.org/documentation/cxx-interop/project-build-setup/#vending-packages-that-enable-c-interoperability

mesonbuild/backend/ninjabackend.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2266,6 +2266,20 @@ def generate_swift_target(self, target) -> None:
22662266
relsrc = []
22672267
abs_headers = []
22682268
header_imports = []
2269+
2270+
if not target.uses_swift_cpp_interop():
2271+
cpp_targets = [t for t in target.link_targets if t.uses_swift_cpp_interop()]
2272+
if cpp_targets != []:
2273+
target_word = 'targets' if len(cpp_targets) > 1 else 'target'
2274+
first = ', '.join(repr(t.name) for t in cpp_targets[:-1])
2275+
and_word = ' and ' if len(cpp_targets) > 1 else ''
2276+
last = repr(cpp_targets[-1].name)
2277+
enable_word = 'enable' if len(cpp_targets) > 1 else 'enables'
2278+
raise MesonException('Swift target {0} links against {1} {2}{3}{4} which {5} C++ interoperability. '
2279+
'This requires {0} to also have it enabled. '
2280+
'Add "swift_interoperability_mode: \'cpp\'" to the definition of {0}.'
2281+
.format(repr(target.name), target_word, first, and_word, last, enable_word))
2282+
22692283
for i in target.get_sources():
22702284
if swiftc.can_compile(i):
22712285
rels = i.rel_to_builddir(self.build_to_src)
@@ -2282,8 +2296,7 @@ def generate_swift_target(self, target) -> None:
22822296
os.makedirs(self.get_target_private_dir_abs(target), exist_ok=True)
22832297
compile_args = self.generate_basic_compiler_args(target, swiftc)
22842298
compile_args += swiftc.get_module_args(module_name)
2285-
if mesonlib.version_compare(swiftc.version, '>=5.9'):
2286-
compile_args += swiftc.get_cxx_interoperability_args(target.compilers)
2299+
compile_args += swiftc.get_cxx_interoperability_args(target)
22872300
compile_args += self.build.get_project_args(swiftc, target.subproject, target.for_machine)
22882301
compile_args += self.build.get_global_args(swiftc, target.for_machine)
22892302
if isinstance(target, (build.StaticLibrary, build.SharedLibrary)):

mesonbuild/backend/xcodebackend.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1831,7 +1831,7 @@ def generate_single_build_target(self, objects_dict, target_name, target) -> Non
18311831
settings_dict.add_item('SECTORDER_FLAGS', '')
18321832
if is_swift and bridging_header:
18331833
settings_dict.add_item('SWIFT_OBJC_BRIDGING_HEADER', bridging_header)
1834-
if self.objversion >= 60 and 'cpp' in langs:
1834+
if self.objversion >= 60 and target.uses_swift_cpp_interop():
18351835
settings_dict.add_item('SWIFT_OBJC_INTEROP_MODE', 'objcxx')
18361836
settings_dict.add_item('BUILD_DIR', symroot)
18371837
settings_dict.add_item('OBJROOT', f'{symroot}/build')

mesonbuild/build.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ class DFeatures(TypedDict):
7575
vala_kwargs = {'vala_header', 'vala_gir', 'vala_vapi'}
7676
rust_kwargs = {'rust_crate_type', 'rust_dependency_map'}
7777
cs_kwargs = {'resources', 'cs_args'}
78-
swift_kwargs = {'swift_module_name'}
78+
swift_kwargs = {'swift_interoperability_mode', 'swift_module_name'}
7979

8080
buildtarget_kwargs = {
8181
'build_by_default',
@@ -1275,6 +1275,8 @@ def process_kwargs(self, kwargs):
12751275
raise InvalidArguments(f'Invalid rust_dependency_map "{rust_dependency_map}": must be a dictionary with string values.')
12761276
self.rust_dependency_map = rust_dependency_map
12771277

1278+
self.swift_interoperability_mode = kwargs.get('swift_interoperability_mode')
1279+
12781280
self.swift_module_name = kwargs.get('swift_module_name')
12791281
if self.swift_module_name == '':
12801282
self.swift_module_name = self.name
@@ -1702,6 +1704,9 @@ def uses_rust_abi(self) -> bool:
17021704
def uses_fortran(self) -> bool:
17031705
return 'fortran' in self.compilers
17041706

1707+
def uses_swift_cpp_interop(self) -> bool:
1708+
return self.swift_interoperability_mode == 'cpp' and 'swift' in self.compilers
1709+
17051710
def get_using_msvc(self) -> bool:
17061711
'''
17071712
Check if the dynamic linker is MSVC. Used by Executable, StaticLibrary,

mesonbuild/compilers/compilers.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1121,9 +1121,6 @@ def get_crt_link_args(self, crt_val: str, buildtype: str) -> T.List[str]:
11211121
def get_compile_only_args(self) -> T.List[str]:
11221122
return []
11231123

1124-
def get_cxx_interoperability_args(self, lang: T.Dict[str, Compiler]) -> T.List[str]:
1125-
raise EnvironmentException('This compiler does not support CXX interoperability')
1126-
11271124
def get_preprocess_only_args(self) -> T.List[str]:
11281125
raise EnvironmentException('This compiler does not have a preprocessor')
11291126

mesonbuild/compilers/swift.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -153,11 +153,14 @@ def get_working_directory_args(self, path: str) -> T.Optional[T.List[str]]:
153153

154154
return ['-working-directory', path]
155155

156-
def get_cxx_interoperability_args(self, lang: T.Dict[str, Compiler]) -> T.List[str]:
157-
if 'cpp' in lang or 'objcpp' in lang:
158-
return ['-cxx-interoperability-mode=default']
159-
else:
160-
return ['-cxx-interoperability-mode=off']
156+
def get_cxx_interoperability_args(self, target: T.Optional[build.BuildTarget] = None) -> T.List[str]:
157+
if target is not None and not target.uses_swift_cpp_interop():
158+
return []
159+
160+
if version_compare(self.version, '<5.9'):
161+
raise MesonException(f'Compiler {self} does not support C++ interoperability')
162+
163+
return ['-cxx-interoperability-mode=default']
161164

162165
def get_library_args(self) -> T.List[str]:
163166
return ['-parse-as-library']

mesonbuild/interpreter/kwargs.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,7 @@ class _BuildTarget(_BaseBuildTarget):
363363
d_module_versions: T.List[T.Union[str, int]]
364364
d_unittest: bool
365365
rust_dependency_map: T.Dict[str, str]
366+
swift_interoperability_mode: Literal['c', 'cpp']
366367
swift_module_name: str
367368
sources: SourcesVarargsType
368369
c_args: T.List[str]

mesonbuild/interpreter/type_checking.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -633,6 +633,7 @@ def _name_suffix_validator(arg: T.Optional[T.Union[str, T.List]]) -> T.Optional[
633633
default={},
634634
since='1.2.0',
635635
),
636+
KwargInfo('swift_interoperability_mode', str, default='c', validator=in_set_validator({'c', 'cpp'}), since='1.9.0'),
636637
KwargInfo('swift_module_name', str, default='', since='1.9.0'),
637638
KwargInfo('build_rpath', str, default='', since='0.42.0'),
638639
KwargInfo(

test cases/swift/11 mixed cpp/meson.build

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,5 @@ if not swiftc.version().version_compare('>= 5.9')
88
endif
99

1010
lib = static_library('mylib', 'mylib.cpp')
11-
exe = executable('prog', 'main.swift', 'mylib.h', link_with: lib)
11+
exe = executable('prog', 'main.swift', 'mylib.h', link_with: lib, swift_interoperability_mode: 'cpp')
1212
test('cpp interface', exe)

test cases/swift/13 mixed objcpp/meson.build

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,5 @@ if not swiftc.version().version_compare('>= 5.9')
88
endif
99

1010
lib = static_library('mylib', 'mylib.mm')
11-
exe = executable('prog', 'main.swift', 'mylib.h', link_with: lib)
11+
exe = executable('prog', 'main.swift', 'mylib.h', link_with: lib, swift_interoperability_mode: 'cpp')
1212
test('objcpp interface', exe)

0 commit comments

Comments
 (0)