diff options
| -rw-r--r-- | docs/markdown/snippets/swift_cxx_interoperability.md | 16 | ||||
| -rw-r--r-- | mesonbuild/backend/ninjabackend.py | 17 | ||||
| -rw-r--r-- | mesonbuild/backend/xcodebackend.py | 2 | ||||
| -rw-r--r-- | mesonbuild/build.py | 7 | ||||
| -rw-r--r-- | mesonbuild/compilers/compilers.py | 3 | ||||
| -rw-r--r-- | mesonbuild/compilers/swift.py | 13 | ||||
| -rw-r--r-- | mesonbuild/interpreter/kwargs.py | 1 | ||||
| -rw-r--r-- | mesonbuild/interpreter/type_checking.py | 1 | ||||
| -rw-r--r-- | test cases/swift/11 mixed cpp/meson.build | 2 | ||||
| -rw-r--r-- | test cases/swift/13 mixed objcpp/meson.build | 2 |
10 files changed, 47 insertions, 17 deletions
diff --git a/docs/markdown/snippets/swift_cxx_interoperability.md b/docs/markdown/snippets/swift_cxx_interoperability.md index f18e114d2..9e324f9bd 100644 --- a/docs/markdown/snippets/swift_cxx_interoperability.md +++ b/docs/markdown/snippets/swift_cxx_interoperability.md @@ -1,13 +1,23 @@ ## Swift/C++ interoperability is now supported It is now possible to create Swift executables that can link to C++ or -Objective-C++ libraries. Only specifying a bridging header for the Swift -target is required. +Objective-C++ libraries. To enable this feature, set the target kwarg +_swift\_interoperability\_mode_ to 'cpp'. + +To import C++ code, specify a bridging header in the Swift target's +sources, or use another way such as adding a directory containing a +Clang module map to its include path. + +Note: Enabling C++ interoperability in a library target is a breaking +change. Swift libraries that enable it need their consumers to enable +it as well, as per [the Swift documentation][1]. Swift 5.9 is required to use this feature. Xcode 15 is required if the Xcode backend is used. ```meson lib = static_library('mylib', 'mylib.cpp') -exe = executable('prog', 'main.swift', 'mylib.h', link_with: lib) +exe = executable('prog', 'main.swift', 'mylib.h', link_with: lib, swift_interoperability_mode: 'cpp') ``` + +[1]: https://www.swift.org/documentation/cxx-interop/project-build-setup/#vending-packages-that-enable-c-interoperability diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index b2fb60580..595a27a05 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -2266,6 +2266,20 @@ class NinjaBackend(backends.Backend): relsrc = [] abs_headers = [] header_imports = [] + + if not target.uses_swift_cpp_interop(): + cpp_targets = [t for t in target.link_targets if t.uses_swift_cpp_interop()] + if cpp_targets != []: + target_word = 'targets' if len(cpp_targets) > 1 else 'target' + first = ', '.join(repr(t.name) for t in cpp_targets[:-1]) + and_word = ' and ' if len(cpp_targets) > 1 else '' + last = repr(cpp_targets[-1].name) + enable_word = 'enable' if len(cpp_targets) > 1 else 'enables' + raise MesonException('Swift target {0} links against {1} {2}{3}{4} which {5} C++ interoperability. ' + 'This requires {0} to also have it enabled. ' + 'Add "swift_interoperability_mode: \'cpp\'" to the definition of {0}.' + .format(repr(target.name), target_word, first, and_word, last, enable_word)) + for i in target.get_sources(): if swiftc.can_compile(i): rels = i.rel_to_builddir(self.build_to_src) @@ -2282,8 +2296,7 @@ class NinjaBackend(backends.Backend): os.makedirs(self.get_target_private_dir_abs(target), exist_ok=True) compile_args = self.generate_basic_compiler_args(target, swiftc) compile_args += swiftc.get_module_args(module_name) - if mesonlib.version_compare(swiftc.version, '>=5.9'): - compile_args += swiftc.get_cxx_interoperability_args(target.compilers) + compile_args += swiftc.get_cxx_interoperability_args(target) compile_args += self.build.get_project_args(swiftc, target.subproject, target.for_machine) compile_args += self.build.get_global_args(swiftc, target.for_machine) if isinstance(target, (build.StaticLibrary, build.SharedLibrary)): diff --git a/mesonbuild/backend/xcodebackend.py b/mesonbuild/backend/xcodebackend.py index c0522e3c7..e7bd48700 100644 --- a/mesonbuild/backend/xcodebackend.py +++ b/mesonbuild/backend/xcodebackend.py @@ -1831,7 +1831,7 @@ class XCodeBackend(backends.Backend): settings_dict.add_item('SECTORDER_FLAGS', '') if is_swift and bridging_header: settings_dict.add_item('SWIFT_OBJC_BRIDGING_HEADER', bridging_header) - if self.objversion >= 60 and 'cpp' in langs: + if self.objversion >= 60 and target.uses_swift_cpp_interop(): settings_dict.add_item('SWIFT_OBJC_INTEROP_MODE', 'objcxx') settings_dict.add_item('BUILD_DIR', symroot) settings_dict.add_item('OBJROOT', f'{symroot}/build') diff --git a/mesonbuild/build.py b/mesonbuild/build.py index 9014d09fb..2adfb9803 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -75,7 +75,7 @@ lang_arg_kwargs |= { vala_kwargs = {'vala_header', 'vala_gir', 'vala_vapi'} rust_kwargs = {'rust_crate_type', 'rust_dependency_map'} cs_kwargs = {'resources', 'cs_args'} -swift_kwargs = {'swift_module_name'} +swift_kwargs = {'swift_interoperability_mode', 'swift_module_name'} buildtarget_kwargs = { 'build_by_default', @@ -1275,6 +1275,8 @@ class BuildTarget(Target): raise InvalidArguments(f'Invalid rust_dependency_map "{rust_dependency_map}": must be a dictionary with string values.') self.rust_dependency_map = rust_dependency_map + self.swift_interoperability_mode = kwargs.get('swift_interoperability_mode') + self.swift_module_name = kwargs.get('swift_module_name') if self.swift_module_name == '': self.swift_module_name = self.name @@ -1702,6 +1704,9 @@ class BuildTarget(Target): def uses_fortran(self) -> bool: return 'fortran' in self.compilers + def uses_swift_cpp_interop(self) -> bool: + return self.swift_interoperability_mode == 'cpp' and 'swift' in self.compilers + def get_using_msvc(self) -> bool: ''' Check if the dynamic linker is MSVC. Used by Executable, StaticLibrary, diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py index f32205db9..a823aeb00 100644 --- a/mesonbuild/compilers/compilers.py +++ b/mesonbuild/compilers/compilers.py @@ -1121,9 +1121,6 @@ class Compiler(HoldableObject, metaclass=abc.ABCMeta): def get_compile_only_args(self) -> T.List[str]: return [] - def get_cxx_interoperability_args(self, lang: T.Dict[str, Compiler]) -> T.List[str]: - raise EnvironmentException('This compiler does not support CXX interoperability') - def get_preprocess_only_args(self) -> T.List[str]: raise EnvironmentException('This compiler does not have a preprocessor') diff --git a/mesonbuild/compilers/swift.py b/mesonbuild/compilers/swift.py index 3fff7a1ff..89da306ab 100644 --- a/mesonbuild/compilers/swift.py +++ b/mesonbuild/compilers/swift.py @@ -153,11 +153,14 @@ class SwiftCompiler(Compiler): return ['-working-directory', path] - def get_cxx_interoperability_args(self, lang: T.Dict[str, Compiler]) -> T.List[str]: - if 'cpp' in lang or 'objcpp' in lang: - return ['-cxx-interoperability-mode=default'] - else: - return ['-cxx-interoperability-mode=off'] + def get_cxx_interoperability_args(self, target: T.Optional[build.BuildTarget] = None) -> T.List[str]: + if target is not None and not target.uses_swift_cpp_interop(): + return [] + + if version_compare(self.version, '<5.9'): + raise MesonException(f'Compiler {self} does not support C++ interoperability') + + return ['-cxx-interoperability-mode=default'] def get_library_args(self) -> T.List[str]: return ['-parse-as-library'] diff --git a/mesonbuild/interpreter/kwargs.py b/mesonbuild/interpreter/kwargs.py index 193e100f3..7dd49a1db 100644 --- a/mesonbuild/interpreter/kwargs.py +++ b/mesonbuild/interpreter/kwargs.py @@ -363,6 +363,7 @@ class _BuildTarget(_BaseBuildTarget): d_module_versions: T.List[T.Union[str, int]] d_unittest: bool rust_dependency_map: T.Dict[str, str] + swift_interoperability_mode: Literal['c', 'cpp'] swift_module_name: str sources: SourcesVarargsType c_args: T.List[str] diff --git a/mesonbuild/interpreter/type_checking.py b/mesonbuild/interpreter/type_checking.py index ffa561975..a551d0f7c 100644 --- a/mesonbuild/interpreter/type_checking.py +++ b/mesonbuild/interpreter/type_checking.py @@ -633,6 +633,7 @@ _BUILD_TARGET_KWS: T.List[KwargInfo] = [ default={}, since='1.2.0', ), + KwargInfo('swift_interoperability_mode', str, default='c', validator=in_set_validator({'c', 'cpp'}), since='1.9.0'), KwargInfo('swift_module_name', str, default='', since='1.9.0'), KwargInfo('build_rpath', str, default='', since='0.42.0'), KwargInfo( diff --git a/test cases/swift/11 mixed cpp/meson.build b/test cases/swift/11 mixed cpp/meson.build index 94b70f07b..60273415b 100644 --- a/test cases/swift/11 mixed cpp/meson.build +++ b/test cases/swift/11 mixed cpp/meson.build @@ -8,5 +8,5 @@ if not swiftc.version().version_compare('>= 5.9') endif lib = static_library('mylib', 'mylib.cpp') -exe = executable('prog', 'main.swift', 'mylib.h', link_with: lib) +exe = executable('prog', 'main.swift', 'mylib.h', link_with: lib, swift_interoperability_mode: 'cpp') test('cpp interface', exe) diff --git a/test cases/swift/13 mixed objcpp/meson.build b/test cases/swift/13 mixed objcpp/meson.build index 69098e246..a76162acb 100644 --- a/test cases/swift/13 mixed objcpp/meson.build +++ b/test cases/swift/13 mixed objcpp/meson.build @@ -8,5 +8,5 @@ if not swiftc.version().version_compare('>= 5.9') endif lib = static_library('mylib', 'mylib.mm') -exe = executable('prog', 'main.swift', 'mylib.h', link_with: lib) +exe = executable('prog', 'main.swift', 'mylib.h', link_with: lib, swift_interoperability_mode: 'cpp') test('objcpp interface', exe) |
