@@ -340,7 +340,7 @@ def sanitize(p: T.Optional[str]) -> T.Optional[str]:
340340 guess_gcc_or_lcc = None
341341
342342 if guess_gcc_or_lcc :
343- defines = _get_gnu_compiler_defines (compiler )
343+ defines = _get_gnu_compiler_defines (compiler , lang )
344344 if not defines :
345345 popen_exceptions [join_args (compiler )] = 'no pre-processor defines'
346346 continue
@@ -449,7 +449,7 @@ def sanitize(p: T.Optional[str]) -> T.Optional[str]:
449449 if 'clang' in out or 'Clang' in out :
450450 linker = None
451451
452- defines = _get_clang_compiler_defines (compiler )
452+ defines = _get_clang_compiler_defines (compiler , lang )
453453
454454 # Even if the for_machine is darwin, we could be using vanilla
455455 # clang.
@@ -676,7 +676,7 @@ def detect_fortran_compiler(env: 'Environment', for_machine: MachineChoice) -> C
676676 guess_gcc_or_lcc = 'lcc'
677677
678678 if guess_gcc_or_lcc :
679- defines = _get_gnu_compiler_defines (compiler )
679+ defines = _get_gnu_compiler_defines (compiler , 'fortran' )
680680 if not defines :
681681 popen_exceptions [join_args (compiler )] = 'no pre-processor defines'
682682 continue
@@ -843,7 +843,7 @@ def _detect_objc_or_objcpp_compiler(env: 'Environment', lang: str, for_machine:
843843 continue
844844 version = search_version (out )
845845 if 'Free Software Foundation' in out :
846- defines = _get_gnu_compiler_defines (compiler )
846+ defines = _get_gnu_compiler_defines (compiler , lang )
847847 if not defines :
848848 popen_exceptions [join_args (compiler )] = 'no pre-processor defines'
849849 continue
@@ -855,7 +855,7 @@ def _detect_objc_or_objcpp_compiler(env: 'Environment', lang: str, for_machine:
855855 defines , linker = linker )
856856 if 'clang' in out :
857857 linker = None
858- defines = _get_clang_compiler_defines (compiler )
858+ defines = _get_clang_compiler_defines (compiler , lang )
859859 if not defines :
860860 popen_exceptions [join_args (compiler )] = 'no pre-processor defines'
861861 continue
@@ -1329,19 +1329,43 @@ def detect_masm_compiler(env: 'Environment', for_machine: MachineChoice) -> Comp
13291329# GNU/Clang defines and version
13301330# =============================
13311331
1332- def _get_gnu_compiler_defines (compiler : T .List [str ]) -> T .Dict [str , str ]:
1332+ def _get_gnu_compiler_defines (compiler : T .List [str ], lang : str ) -> T .Dict [str , str ]:
13331333 """
13341334 Get the list of GCC pre-processor defines
13351335 """
1336+ from .mixins .gnu import _LANG_MAP as gnu_LANG_MAP
1337+
1338+ def _try_obtain_compiler_defines (args : T .List [str ]) -> str :
1339+ mlog .debug (f'Running command: { join_args (args )} ' )
1340+ p , output , error = Popen_safe (compiler + args , write = '' , stdin = subprocess .PIPE )
1341+ if p .returncode != 0 :
1342+ raise EnvironmentException ('Unable to get gcc pre-processor defines:\n '
1343+ f'Compiler stdout:\n { output } \n -----\n '
1344+ f'Compiler stderr:\n { error } \n -----\n ' )
1345+ return output
1346+
13361347 # Arguments to output compiler pre-processor defines to stdout
13371348 # gcc, g++, and gfortran all support these arguments
1338- args = compiler + ['-E' , '-dM' , '-' ]
1339- mlog .debug (f'Running command: { join_args (args )} ' )
1340- p , output , error = Popen_safe (args , write = '' , stdin = subprocess .PIPE )
1341- if p .returncode != 0 :
1342- raise EnvironmentException ('Unable to detect gcc pre-processor defines:\n '
1343- f'Compiler stdout:\n { output } \n -----\n '
1344- f'Compiler stderr:\n { error } \n -----\n ' )
1349+ baseline_test_args = ['-E' , '-dM' , '-' ]
1350+ try :
1351+ # We assume that when _get_gnu_compiler_defines is called, it's
1352+ # close enough to a GCCish compiler so we reuse the _LANG_MAP
1353+ # from the GCC mixin. This isn't a dangerous assumption because
1354+ # we fallback if the detection fails anyway.
1355+
1356+ # We might not have a match for Fortran, so fallback to detection
1357+ # based on the driver.
1358+ lang = gnu_LANG_MAP [lang ]
1359+
1360+ # The compiler may not infer the target language based on the driver name
1361+ # so first, try with '-cpp -x lang', then fallback without given it's less
1362+ # portable. We try with '-cpp' as GCC needs it for Fortran at least, and
1363+ # it seems to do no harm.
1364+ output = _try_obtain_compiler_defines (['-cpp' , '-x' , lang ] + baseline_test_args )
1365+ except (EnvironmentException , KeyError ):
1366+ mlog .debug (f'pre-processor extraction using -cpp -x { lang } failed, falling back w/o lang' )
1367+ output = _try_obtain_compiler_defines (baseline_test_args )
1368+
13451369 # Parse several lines of the type:
13461370 # `#define ___SOME_DEF some_value`
13471371 # and extract `___SOME_DEF`
@@ -1358,17 +1382,42 @@ def _get_gnu_compiler_defines(compiler: T.List[str]) -> T.Dict[str, str]:
13581382 defines [rest [0 ]] = rest [1 ]
13591383 return defines
13601384
1361- def _get_clang_compiler_defines (compiler : T .List [str ]) -> T .Dict [str , str ]:
1385+ def _get_clang_compiler_defines (compiler : T .List [str ], lang : str ) -> T .Dict [str , str ]:
13621386 """
13631387 Get the list of Clang pre-processor defines
13641388 """
1365- args = compiler + ['-E' , '-dM' , '-' ]
1366- mlog .debug (f'Running command: { join_args (args )} ' )
1367- p , output , error = Popen_safe (args , write = '' , stdin = subprocess .PIPE )
1368- if p .returncode != 0 :
1369- raise EnvironmentException ('Unable to get clang pre-processor defines:\n '
1370- f'Compiler stdout:\n { output } \n -----\n '
1371- f'Compiler stderr:\n { error } \n -----\n ' )
1389+ from .mixins .clang import _LANG_MAP as clang_LANG_MAP
1390+
1391+ def _try_obtain_compiler_defines (args : T .List [str ]) -> str :
1392+ mlog .debug (f'Running command: { join_args (args )} ' )
1393+ p , output , error = Popen_safe (compiler + args , write = '' , stdin = subprocess .PIPE )
1394+ if p .returncode != 0 :
1395+ raise EnvironmentException ('Unable to get clang pre-processor defines:\n '
1396+ f'Compiler stdout:\n { output } \n -----\n '
1397+ f'Compiler stderr:\n { error } \n -----\n ' )
1398+ return output
1399+
1400+ # Arguments to output compiler pre-processor defines to stdout
1401+ baseline_test_args = ['-E' , '-dM' , '-' ]
1402+ try :
1403+ # We assume that when _get_clang_compiler_defines is called, it's
1404+ # close enough to a Clangish compiler so we reuse the _LANG_MAP
1405+ # from the Clang mixin. This isn't a dangerous assumption because
1406+ # we fallback if the detection fails anyway.
1407+
1408+ # We might not have a match for Fortran, so fallback to detection
1409+ # based on the driver.
1410+ lang = clang_LANG_MAP [lang ]
1411+
1412+ # The compiler may not infer the target language based on the driver name
1413+ # so first, try with '-cpp -x lang', then fallback without given it's less
1414+ # portable. We try with '-cpp' as GCC needs it for Fortran at least, and
1415+ # it seems to do no harm.
1416+ output = _try_obtain_compiler_defines (['-cpp' , '-x' , lang ] + baseline_test_args )
1417+ except (EnvironmentException , KeyError ):
1418+ mlog .debug (f'pre-processor extraction using -cpp -x { lang } failed, falling back w/o lang' )
1419+ output = _try_obtain_compiler_defines (baseline_test_args )
1420+
13721421 defines : T .Dict [str , str ] = {}
13731422 for line in output .split ('\n ' ):
13741423 if not line :
0 commit comments