From 85b8e92bc447a13a19d42bc9ebe8758cd05be463 Mon Sep 17 00:00:00 2001 From: Nirbheek Chauhan Date: Thu, 26 Jan 2017 09:27:47 +0530 Subject: 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 --- mesonbuild/compilers.py | 49 ++++++++++++++------------- test cases/common/43 has function/meson.build | 29 ++++++++++++---- 2 files changed, 48 insertions(+), 30 deletions(-) diff --git a/mesonbuild/compilers.py b/mesonbuild/compilers.py index 6e60ba1..c800bbe 100644 --- a/mesonbuild/compilers.py +++ b/mesonbuild/compilers.py @@ -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: diff --git a/test cases/common/43 has function/meson.build b/test cases/common/43 has function/meson.build index b2bb43a..d4a2431 100644 --- a/test cases/common/43 has function/meson.build +++ b/test cases/common/43 has function/meson.build @@ -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 ', args : unit_test_args), 'couldn\'t detect "poll" when defined by a header') lchmod_prefix = '#include \n#include ' - 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 ', 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 \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 -- cgit v1.1