Verify that C++ can import Swift headers

pull/14261/head
Marco Rebhan 2 weeks ago
parent 86496f0e5d
commit c627aa6f2f
No known key found for this signature in database
  1. 9
      mesonbuild/build.py
  2. 10
      mesonbuild/compilers/cpp.py
  3. 3
      mesonbuild/compilers/swift.py
  4. 40
      mesonbuild/interpreter/interpreter.py

@ -790,6 +790,15 @@ class BuildTarget(Target):
if self.vala_gir:
self.outputs.append(self.vala_gir)
self.install_tag.append('devel')
if 'cpp' in self.compilers and \
any('swift' in t.compilers for t in itertools.chain([self], self.link_targets, self.link_whole_targets)):
from .compilers.cpp import CPPCompiler
cpp = self.compilers['cpp']
assert isinstance(cpp, CPPCompiler)
if not cpp.works_with_swift():
raise MesonException(f'target "{self.name}" tries to link Swift objects with C++ objects, '
'but the C++ and Swift compilers are incompatible')
def __repr__(self):
repr_str = "<{0} {1}: {2}>"

@ -9,7 +9,7 @@ import typing as T
from .. import options
from .. import mlog
from ..mesonlib import MesonException, version_compare
from ..mesonlib import MesonBugException, MesonException, version_compare
from .compilers import (
gnu_winlibs,
@ -70,6 +70,8 @@ class CPPCompiler(CLikeCompiler, Compiler):
info: 'MachineInfo',
linker: T.Optional['DynamicLinker'] = None,
full_version: T.Optional[str] = None):
self._works_with_swift: T.Optional[bool] = None
# If a child ObjCPP class has already set it, don't set it ourselves
Compiler.__init__(self, ccache, exelist, version, for_machine, info,
is_cross=is_cross, linker=linker,
@ -90,6 +92,12 @@ class CPPCompiler(CLikeCompiler, Compiler):
code = 'class breakCCompiler;int main(void) { return 0; }\n'
return self._sanity_check_impl(work_dir, environment, 'sanitycheckcpp.cc', code)
def works_with_swift(self) -> bool:
if self._works_with_swift is None:
raise MesonBugException('Called CPPCompiler.works_with_swift() but compatibility was never checked')
return self._works_with_swift
def get_compiler_check_args(self, mode: CompileCheckMode) -> T.List[str]:
# -fpermissive allows non-conforming code to compile which is necessary
# for many C++ checks. Particularly, the has_header_symbol check is

@ -146,6 +146,9 @@ class SwiftCompiler(Compiler):
return ['-working-directory', path]
def get_library_args(self) -> T.List[str]:
return ['-parse-as-library']
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']

@ -1504,6 +1504,7 @@ class Interpreter(InterpreterBase, HoldableObject):
args = [a.lower() for a in args]
langs = set(self.compilers[for_machine].keys())
langs.update(args)
new_langs = set()
# We'd really like to add cython's default language here, but it can't
# actually be done because the cython compiler hasn't been initialized,
# so we can't actually get the option yet. Because we can't know what
@ -1558,9 +1559,48 @@ class Interpreter(InterpreterBase, HoldableObject):
mlog.bold(' '.join(comp.linker.get_exelist())), comp.linker.id, comp.linker.version)
self.build.ensure_static_linker(comp)
self.compilers[for_machine][lang] = comp
new_langs.add(lang)
if new_langs:
self.did_add_languages_for(for_machine, new_langs)
return success
def did_add_languages_for(self, for_machine: MachineChoice, new_languages: T.Set[str]):
swift_and_cpp = {'swift', 'cpp'}
# call this once, after both have been added
if all(name in self.compilers[for_machine] for name in swift_and_cpp) and \
new_languages.intersection(swift_and_cpp):
self.check_cpp_can_import_swift_header(for_machine)
def check_cpp_can_import_swift_header(self, for_machine: MachineChoice):
from mesonbuild.compilers.cpp import CPPCompiler
from mesonbuild.compilers.swift import SwiftCompiler
from mesonbuild.mesonlib import Popen_safe_logged
compilers = self.compilers[for_machine]
swiftc = compilers['swift']
cpp = compilers['cpp']
assert isinstance(swiftc, SwiftCompiler)
assert isinstance(cpp, CPPCompiler)
header_name = 'swift-export.h'
swift_command = [*swiftc.get_exelist(), *swiftc.get_header_gen_args(header_name), *swiftc.get_library_args(),
*swiftc.get_module_args('Check'), *swiftc.get_cxx_interoperability_args(compilers), '-']
p, _, _ = Popen_safe_logged(swift_command, cwd=self.environment.get_scratch_dir())
works, _ = cpp.compiles(f'#include "{header_name}"\nclass breakCCompiler;int main(void) {{ return 0; }}\n',
self.environment, extra_args=[f'-I{self.environment.get_scratch_dir()}'], disable_cache=True)
msg = ['C++ compiler', *[mlog.bold(el) for el in cpp.get_exelist()], 'compiles Swift-exported headers:']
verbose = for_machine == MachineChoice.HOST or self.environment.is_cross_build()
logger_fun = mlog.log if verbose else mlog.debug
logger_fun(*msg, mlog.green('YES') if works else mlog.red('NO'))
cpp._works_with_swift = works
def program_from_file_for(self, for_machine: MachineChoice, prognames: T.List[mesonlib.FileOrString]
) -> T.Optional[ExternalProgram]:
for p in prognames:

Loading…
Cancel
Save