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 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
    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`
    defines: T.Dict[str, str] = {}
    for line in output.split('\n'):
        if not line:
            continue
        d, *rest = line.split(' ', 2)
        if d != '#define':
            continue
        if len(rest) == 1:
            defines[rest[0]] = ''
        if len(rest) == 2:
            defines[rest[0]] = rest[1]
    return defines

    Get the list of GCC pre-processor defines
    
mesonbuild/compilers/detect.py