aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNirbheek Chauhan <nirbheek@centricular.com>2017-01-26 09:27:47 +0530
committerNirbheek Chauhan <nirbheek@centricular.com>2017-01-26 12:36:47 +0530
commit85b8e92bc447a13a19d42bc9ebe8758cd05be463 (patch)
treee03a3b98e698890a0ee2064163f3ce05b8fb1275
parent748fe80423b56ea52a5dbb26f84cfedd5b416b8e (diff)
downloadmeson-85b8e92bc447a13a19d42bc9ebe8758cd05be463.zip
meson-85b8e92bc447a13a19d42bc9ebe8758cd05be463.tar.gz
meson-85b8e92bc447a13a19d42bc9ebe8758cd05be463.tar.bz2
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
-rw-r--r--mesonbuild/compilers.py49
-rw-r--r--test cases/common/43 has function/meson.build29
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 <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