compilers: Fix has_function check for builtins

Use a single check for both cases when we have includes and when we
don't. This way we ensure three things:

1. Built-in checks are 100% reliable with clang and on macOS since clang
   implements __has_builtin
2. When the #include is present, this ensures that __builtin_func is not
   checked for (because of MSYS, and because it is faster)
3. We fallback to checking __builtin_func when all else fails
pull/1328/head
Nirbheek Chauhan 8 years ago
parent 748fe80423
commit 85b8e92bc4
  1. 49
      mesonbuild/compilers.py
  2. 29
      test cases/common/43 has function/meson.build

@ -1045,33 +1045,34 @@ class CCompiler(Compiler):
if self.links(templ.format(**fargs), env, extra_args, dependencies):
return True
# Detect function as a built-in
#
# Some functions like alloca() are defined as compiler built-ins which
# are inlined by the compiler, so look for __builtin_symbol in the libc
# if there's no #include-s in prefix which would've #define-d the
# symbol correctly. If there is a #include, just check for the symbol
# directly. This is needed because the above #undef fancy footwork
# doesn't work for builtins.
# This fixes instances such as #1083 where MSYS2 defines
# __builtin_posix_memalign in the C library but doesn't define
# posix_memalign in the headers to point to that builtin which results
# in an invalid detection.
if '#include' not in prefix:
# Detect function as a built-in
fargs['func'] = '__builtin_' + fargs['func']
code = '''
int main() {{
#ifdef __has_builtin
#if !__has_builtin({func})
#error "built-in {func} not found"
#endif
# are inlined by the compiler and you can't take their address, so we
# need to look for them differently. On nice compilers like clang, we
# can just directly use the __has_builtin() macro.
fargs['no_includes'] = '#include' not in prefix
t = '''{prefix}
int main() {{
#ifdef __has_builtin
#if !__has_builtin(__builtin_{func})
#error "__builtin_{func} not found"
#endif
#elif ! defined({func})
/* Check for __builtin_{func} only if no includes were added to the
* prefix above, which means no definition of {func} can be found.
* We would always check for this, but we get false positives on
* MSYS2 if we do. Their toolchain is broken, but we can at least
* give them a workaround. */
#if {no_includes:d}
__builtin_{func};
#else
{func};
#error "No definition for __builtin_{func} found in the prefix"
#endif
}}'''
else:
# Directly look for the function itself
code = '{prefix}\n' + stubs_fail + '\nint main() {{ {func}; }}'
return self.links(code.format(**fargs), env, extra_args, dependencies)
#endif
}}'''
return self.links(t.format(**fargs), env, extra_args, dependencies)
def has_members(self, typename, membernames, prefix, env, extra_args=None, dependencies=None):
if extra_args is None:

@ -4,6 +4,10 @@ host_system = host_machine.system()
# This is used in the `test_compiler_check_flags_order` unit test
unit_test_args = '-I/tmp'
defines_has_builtin = '''#ifndef __has_builtin
#error "no __has_builtin"
#endif
'''
compilers = [meson.get_compiler('c'), meson.get_compiler('cpp')]
foreach cc : compilers
@ -40,20 +44,33 @@ foreach cc : compilers
# We can't check for the C library used here of course, but if it's not
# implemented in glibc it's probably not implemented in any other 'slimmer'
# C library variants either, so the check should be safe either way hopefully.
if host_system == 'linux'
if host_system == 'linux' or host_system == 'darwin'
assert (cc.has_function('poll', prefix : '#include <poll.h>',
args : unit_test_args),
'couldn\'t detect "poll" when defined by a header')
lchmod_prefix = '#include <sys/stat.h>\n#include <unistd.h>'
assert (not cc.has_function('lchmod', prefix : lchmod_prefix,
args : unit_test_args),
'"lchmod" check should have failed')
if host_system == 'linux'
assert (not cc.has_function('lchmod', prefix : lchmod_prefix,
args : unit_test_args),
'"lchmod" check should have failed')
else
# macOS and *BSD have lchmod
assert (cc.has_function('lchmod', prefix : lchmod_prefix,
args : unit_test_args),
'"lchmod" check should have succeeded')
endif
# Check that built-ins are found properly both with and without headers
assert(cc.has_function('alloca', args : unit_test_args),
'built-in alloca must be found on Linux')
'built-in alloca must be found on ' + host_system)
assert(cc.has_function('alloca', prefix : '#include <alloca.h>',
args : unit_test_args),
'built-in alloca must be found on Linux with #include')
'built-in alloca must be found with #include')
if not cc.compiles(defines_has_builtin, args : unit_test_args)
assert(not cc.has_function('alloca',
prefix : '#include <alloca.h>\n#undef alloca',
args : unit_test_args),
'built-in alloca must not be found with #include and #undef')
endif
endif
# For some functions one needs to define _GNU_SOURCE before including the

Loading…
Cancel
Save