diff options
-rw-r--r-- | mesonbuild/compilers/detect.py | 91 | ||||
-rw-r--r-- | mesonbuild/compilers/mixins/clang.py | 7 |
2 files changed, 77 insertions, 21 deletions
diff --git a/mesonbuild/compilers/detect.py b/mesonbuild/compilers/detect.py index f16e40f..255812c 100644 --- a/mesonbuild/compilers/detect.py +++ b/mesonbuild/compilers/detect.py @@ -340,7 +340,7 @@ def _detect_c_or_cpp_compiler(env: 'Environment', lang: str, for_machine: Machin guess_gcc_or_lcc = None if guess_gcc_or_lcc: - defines = _get_gnu_compiler_defines(compiler) + defines = _get_gnu_compiler_defines(compiler, lang) if not defines: popen_exceptions[join_args(compiler)] = 'no pre-processor defines' continue @@ -449,7 +449,7 @@ def _detect_c_or_cpp_compiler(env: 'Environment', lang: str, for_machine: Machin if 'clang' in out or 'Clang' in out: linker = None - defines = _get_clang_compiler_defines(compiler) + defines = _get_clang_compiler_defines(compiler, lang) # Even if the for_machine is darwin, we could be using vanilla # clang. @@ -676,7 +676,7 @@ def detect_fortran_compiler(env: 'Environment', for_machine: MachineChoice) -> C guess_gcc_or_lcc = 'lcc' if guess_gcc_or_lcc: - defines = _get_gnu_compiler_defines(compiler) + defines = _get_gnu_compiler_defines(compiler, 'fortran') if not defines: popen_exceptions[join_args(compiler)] = 'no pre-processor defines' continue @@ -843,7 +843,7 @@ def _detect_objc_or_objcpp_compiler(env: 'Environment', lang: str, for_machine: continue version = search_version(out) if 'Free Software Foundation' in out: - defines = _get_gnu_compiler_defines(compiler) + defines = _get_gnu_compiler_defines(compiler, lang) if not defines: popen_exceptions[join_args(compiler)] = 'no pre-processor defines' continue @@ -855,7 +855,7 @@ def _detect_objc_or_objcpp_compiler(env: 'Environment', lang: str, for_machine: defines, linker=linker) if 'clang' in out: linker = None - defines = _get_clang_compiler_defines(compiler) + defines = _get_clang_compiler_defines(compiler, lang) if not defines: popen_exceptions[join_args(compiler)] = 'no pre-processor defines' continue @@ -1329,19 +1329,43 @@ def detect_masm_compiler(env: 'Environment', for_machine: MachineChoice) -> Comp # GNU/Clang defines and version # ============================= -def _get_gnu_compiler_defines(compiler: T.List[str]) -> T.Dict[str, str]: +def _get_gnu_compiler_defines(compiler: T.List[str], lang: str) -> T.Dict[str, str]: """ Get the list of GCC pre-processor defines """ + from .mixins.gnu import _LANG_MAP as gnu_LANG_MAP + + def _try_obtain_compiler_defines(args: T.List[str]) -> str: + mlog.debug(f'Running command: {join_args(args)}') + p, output, error = Popen_safe(compiler + args, write='', stdin=subprocess.PIPE) + if p.returncode != 0: + raise EnvironmentException('Unable to get gcc pre-processor defines:\n' + f'Compiler stdout:\n{output}\n-----\n' + f'Compiler stderr:\n{error}\n-----\n') + return output + # Arguments to output compiler pre-processor defines to stdout # gcc, g++, and gfortran all support these arguments - args = compiler + ['-E', '-dM', '-'] - mlog.debug(f'Running command: {join_args(args)}') - p, output, error = Popen_safe(args, write='', stdin=subprocess.PIPE) - if p.returncode != 0: - raise EnvironmentException('Unable to detect gcc pre-processor defines:\n' - f'Compiler stdout:\n{output}\n-----\n' - f'Compiler stderr:\n{error}\n-----\n') + baseline_test_args = ['-E', '-dM', '-'] + try: + # We assume that when _get_gnu_compiler_defines is called, it's + # close enough to a GCCish compiler so we reuse the _LANG_MAP + # from the GCC mixin. This isn't a dangerous assumption because + # we fallback if the detection fails anyway. + + # We might not have a match for Fortran, so fallback to detection + # based on the driver. + lang = gnu_LANG_MAP[lang] + + # The compiler may not infer the target language based on the driver name + # so first, try with '-cpp -x lang', then fallback without given it's less + # portable. We try with '-cpp' as GCC needs it for Fortran at least, and + # it seems to do no harm. + output = _try_obtain_compiler_defines(['-cpp', '-x', lang] + baseline_test_args) + except (EnvironmentException, KeyError): + mlog.debug(f'pre-processor extraction using -cpp -x {lang} failed, falling back w/o lang') + output = _try_obtain_compiler_defines(baseline_test_args) + # Parse several lines of the type: # `#define ___SOME_DEF some_value` # and extract `___SOME_DEF` @@ -1358,17 +1382,42 @@ def _get_gnu_compiler_defines(compiler: T.List[str]) -> T.Dict[str, str]: defines[rest[0]] = rest[1] return defines -def _get_clang_compiler_defines(compiler: T.List[str]) -> T.Dict[str, str]: +def _get_clang_compiler_defines(compiler: T.List[str], lang: str) -> T.Dict[str, str]: """ Get the list of Clang pre-processor defines """ - args = compiler + ['-E', '-dM', '-'] - mlog.debug(f'Running command: {join_args(args)}') - p, output, error = Popen_safe(args, write='', stdin=subprocess.PIPE) - if p.returncode != 0: - raise EnvironmentException('Unable to get clang pre-processor defines:\n' - f'Compiler stdout:\n{output}\n-----\n' - f'Compiler stderr:\n{error}\n-----\n') + from .mixins.clang import _LANG_MAP as clang_LANG_MAP + + def _try_obtain_compiler_defines(args: T.List[str]) -> str: + mlog.debug(f'Running command: {join_args(args)}') + p, output, error = Popen_safe(compiler + args, write='', stdin=subprocess.PIPE) + if p.returncode != 0: + raise EnvironmentException('Unable to get clang pre-processor defines:\n' + f'Compiler stdout:\n{output}\n-----\n' + f'Compiler stderr:\n{error}\n-----\n') + return output + + # Arguments to output compiler pre-processor defines to stdout + baseline_test_args = ['-E', '-dM', '-'] + try: + # We assume that when _get_clang_compiler_defines is called, it's + # close enough to a Clangish compiler so we reuse the _LANG_MAP + # from the Clang mixin. This isn't a dangerous assumption because + # we fallback if the detection fails anyway. + + # We might not have a match for Fortran, so fallback to detection + # based on the driver. + lang = clang_LANG_MAP[lang] + + # The compiler may not infer the target language based on the driver name + # so first, try with '-cpp -x lang', then fallback without given it's less + # portable. We try with '-cpp' as GCC needs it for Fortran at least, and + # it seems to do no harm. + output = _try_obtain_compiler_defines(['-cpp', '-x', lang] + baseline_test_args) + except (EnvironmentException, KeyError): + mlog.debug(f'pre-processor extraction using -cpp -x {lang} failed, falling back w/o lang') + output = _try_obtain_compiler_defines(baseline_test_args) + defines: T.Dict[str, str] = {} for line in output.split('\n'): if not line: diff --git a/mesonbuild/compilers/mixins/clang.py b/mesonbuild/compilers/mixins/clang.py index a9bf566..de9d8f8 100644 --- a/mesonbuild/compilers/mixins/clang.py +++ b/mesonbuild/compilers/mixins/clang.py @@ -36,6 +36,13 @@ clang_optimization_args: T.Dict[str, T.List[str]] = { 's': ['-Oz'], } +_LANG_MAP = { + 'c': 'c', + 'cpp': 'c++', + 'objc': 'objective-c', + 'objcpp': 'objective-c++', +} + class ClangCompiler(GnuLikeCompiler): id = 'clang' |