summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNirbheek Chauhan <nirbheek@centricular.com>2018-06-03 20:08:42 +0530
committerNirbheek Chauhan <nirbheek@centricular.com>2018-06-03 20:09:16 +0530
commitba14e89632c8e737ef994a7e5575502d99a895cb (patch)
tree7ffd323a2d7e043241b97d792ff9a2db94d58ec1
parentca1558a9bb98f154403afcf51308095de51ced4a (diff)
downloadmeson-nirbheek/mingw-has_function-quirks.tar.gz
has_function: Consolidate no-prototype and prototype templsnirbheek/mingw-has_function-quirks
This allows us to also accept functions that are simple pre-processor defines in the header pointing to an inline definition, built-in implementation, etc. Also add a test for all the builtins listed by @textshell here: https://github.com/mesonbuild/meson/pull/3675#issuecomment-394157560
-rw-r--r--mesonbuild/compilers/c.py121
-rw-r--r--test cases/common/43 has function/meson.build24
2 files changed, 78 insertions, 67 deletions
diff --git a/mesonbuild/compilers/c.py b/mesonbuild/compilers/c.py
index 37175413d..6809a2034 100644
--- a/mesonbuild/compilers/c.py
+++ b/mesonbuild/compilers/c.py
@@ -575,60 +575,64 @@ class CCompiler(Compiler):
raise EnvironmentException(m.format(fname))
@staticmethod
- def _no_prototype_templ():
+ def _get_has_function_templ():
"""
- Try to find the function without a prototype from a header by defining
- our own dummy prototype and trying to link with the C library (and
- whatever else the compiler links in by default). This is very similar
- to the check performed by Autoconf for AC_CHECK_FUNCS.
+ Returns a head-er and main() call that uses the headers listed by the
+ user for the function prototype while checking if a pre-processor
+ define of that name exists, or a function by that name exists.
+
+ If headers are not provided, it will try to find the function without
+ a prototype from a header by defining our own dummy prototype and
+ trying to link with the C library (and whatever else the compiler links
+ in by default). This is very similar to the check performed by Autoconf
+ for AC_CHECK_FUNCS.
"""
- # Define the symbol to something else since it is defined by the
- # includes or defines listed by the user or by the compiler. This may
- # include, for instance _GNU_SOURCE which must be defined before
- # limits.h, which includes features.h
- # Then, undef the symbol to get rid of it completely.
- head = '''
- #define {func} meson_disable_define_of_{func}
+ templ = '''
+ // Define the symbol to something else since it may be defined by the compiler.
+ #if {no_includes}
+ #define {func} meson_disable_define_of_{func}
+ #endif
+ // Include prefix first since it may include, for instance _GNU_SOURCE
+ // which must be defined before limits.h, which includes features.h
{prefix}
#include <limits.h>
- #undef {func}
- '''
- # Override any GCC internal prototype and declare our own definition for
- # the symbol. Use char because that's unlikely to be an actual return
- # value for a function which ensures that we override the definition.
- head += '''
- #ifdef __cplusplus
- extern "C"
+ #if {no_includes}
+ // Undef the symbol to get rid of it completely.
+ #undef {func}
+ // Override any GCC internal prototype and declare our own definition for
+ // the symbol. Use char because that's unlikely to be an actual return
+ //value for a function which ensures that we override the definition.
+ #ifdef __cplusplus
+ extern "C"
+ #endif
+ char {func} ();
+ #endif
+ // glibc defines functions that are not available on Linux as stubs that
+ // fail with ENOSYS (such as e.g. lchmod). In this case we want to fail
+ // instead of detecting the stub as a valid symbol.
+ // We also include limits.h to ensure that these are defined
+ // for stub functions.
+ #if defined __stub_{func} || defined __stub___{func}
+ fail fail fail this function is not going to work
#endif
- char {func} ();
- '''
- # The actual function call
- main = '''
- int main () {{
- return {func} ();
- }}'''
- return head, main
- @staticmethod
- def _have_prototype_templ():
- """
- Returns a head-er and main() call that uses the headers listed by the
- user for the function prototype while checking if a function exists.
- """
- # Add the 'prefix', aka defines, includes, etc that the user provides
- # This may include, for instance _GNU_SOURCE which must be defined
- # before limits.h, which includes features.h
- head = '{prefix}\n#include <limits.h>\n'
- # We don't know what the function takes or returns, so return it as an int.
- # Just taking the address or comparing it to void is not enough because
- # compilers are smart enough to optimize it away. The resulting binary
- # is not run so we don't care what the return value is.
- main = '''\nint main() {{
+ int main () {{
+ #if {no_includes}
+ return {func} ();
+ #elif defined({func})
+ // Assume that the definition is a function
+ #else
+ // We don't know what the function takes or returns, so return it as an
+ // int. Just taking the address or comparing it to void is not enough
+ // because the compiler might optimize it away (although we now pass -O0
+ // to compiler checks, so this shouldn't happen). The resulting binary
+ // is not run so we don't care what the return value is.
void *a = (void*) &{func};
long b = (long) a;
return (int) b;
+ #endif
}}'''
- return head, main
+ return templ
def has_function(self, funcname, prefix, env, extra_args=None, dependencies=None):
"""
@@ -651,18 +655,8 @@ class CCompiler(Compiler):
return val
raise EnvironmentException('Cross variable {0} is not a boolean.'.format(varname))
- fargs = {'prefix': prefix, 'func': funcname}
-
- # glibc defines functions that are not available on Linux as stubs that
- # fail with ENOSYS (such as e.g. lchmod). In this case we want to fail
- # instead of detecting the stub as a valid symbol.
- # We also include limits.h to ensure that these are defined
- # for stub functions.
- stubs_fail = '''
- #if defined __stub_{func} || defined __stub___{func}
- fail fail fail this function is not going to work
- #endif
- '''
+ fargs = {'prefix': prefix, 'func': funcname,
+ 'no_includes': int('#include' not in prefix)}
# If we have any includes in the prefix supplied by the user, assume
# that the user wants us to use the symbol prototype defined in those
@@ -672,11 +666,7 @@ class CCompiler(Compiler):
# SDK based on the prototype in the header provided by the SDK.
# Ignoring this prototype would result in the symbol always being
# marked as available.
- if '#include' in prefix:
- head, main = self._have_prototype_templ()
- else:
- head, main = self._no_prototype_templ()
- templ = head + stubs_fail + main
+ templ = self._get_has_function_templ()
if self.links(templ.format(**fargs), env, extra_args, dependencies):
return True
@@ -691,22 +681,21 @@ class CCompiler(Compiler):
# 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
- fargs['func_is_builtin'] = funcname.startswith('__builtin_')
+ fargs['func_is_builtin'] = int(funcname.startswith('__builtin_'))
t = '''{prefix}
#include <limits.h>
int main() {{
- #ifdef __has_builtin
+ #if defined(__has_builtin)
#if !__has_builtin({func})
#error "__builtin_{func} not found"
#endif
- #elif ! defined({func})
+ #else
/* 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} && !{func_is_builtin:d}
+ #if {no_includes} && !{func_is_builtin}
__builtin_{func};
// See above for why this is needed
#elif defined(__stub_{func}) || defined(_stub__{func})
diff --git a/test cases/common/43 has function/meson.build b/test cases/common/43 has function/meson.build
index 9cb4d60c4..294f04a40 100644
--- a/test cases/common/43 has function/meson.build
+++ b/test cases/common/43 has function/meson.build
@@ -102,8 +102,9 @@ foreach lang : langs
'strndup incorrectly detected')
endif
- # This is meant to be used as __builtin_smul_overflow, so we shouldn't find the unbuiltin version
+ # Test various builtins
if ['gcc', 'clang'].contains(cc.get_id())
+ # This is meant to be used as __builtin_smul_overflow, so we shouldn't find the unbuiltin version
assert(cc.has_function('__builtin_smul_overflow', args : unit_test_args),
'__builtin_smul_overflow must be found')
# FIXME: this fails on gcc, and we can't fix it without breaking builtin
@@ -112,5 +113,26 @@ foreach lang : langs
assert(not cc.has_function('smul_overflow', args : unit_test_args),
'smul_overflow is __builtin_smul_overflow and must not be found')
endif
+ # Math builtins
+ if lang == 'c'
+ foreach bf: ['fpclassify', 'isfinite', 'isnormal', 'isgreater', 'isnan',
+ 'isgreaterequal', 'isless', 'islessequal', 'islessgreater',
+ 'isunordered']
+ assert(cc.has_function(bf, prefix : '#include <math.h>', args : unit_test_args),
+ '@0@ must be found'.format(bf))
+ endforeach
+ endif
+ # String builtins
+ foreach bf: ['strncpy', 'strncat', 'strcspn', 'strspn']
+ assert(cc.has_function(bf, args : unit_test_args),
+ '@0@ must be found'.format(bf))
+ endforeach
+ # Other builtins
+ assert(cc.has_function('offsetof', prefix : '#include <stddef.h>', args : unit_test_args),
+ 'offsetof must be found')
+ foreach bf: ['va_start', 'va_end', 'va_arg']
+ assert(cc.has_function(bf, prefix : '#include <stdarg.h>', args : unit_test_args),
+ '@0@ must be found'.format(bf))
+ endforeach
endif
endforeach