aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mesonbuild/compilers.py46
-rw-r--r--test cases/common/43 has function/meson.build24
2 files changed, 60 insertions, 10 deletions
diff --git a/mesonbuild/compilers.py b/mesonbuild/compilers.py
index 229d224..0a4473b 100644
--- a/mesonbuild/compilers.py
+++ b/mesonbuild/compilers.py
@@ -647,15 +647,41 @@ int main(int argc, char **argv) {
return align
def has_function(self, funcname, prefix, env, extra_args=[]):
- # This fails (returns true) if funcname is a ptr or a variable.
- # The correct check is a lot more difficult.
- # Fix this to do that eventually.
- templ = '''%s
-int main(int argc, char **argv) {
- void *ptr = (void*)(%s);
- return 0;
-};
-'''
+ # Define the symbol to something else in case it is defined by the
+ # includes or defines listed by the user `{0}` or by the compiler.
+ # Then, undef the symbol to get rid of it completely.
+ templ = '''
+ #define {1} meson_disable_define_of_{1}
+ {0}
+ #undef {1}
+ '''
+
+ # 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.
+ templ += '''
+ #ifdef __cplusplus
+ extern "C"
+ #endif
+ char {1} ();
+ '''
+
+ # 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.
+ templ += '''
+ #if defined __stub_{1} || defined __stub___{1}
+ fail fail fail this function is not going to work
+ #endif
+ '''
+
+ # And finally the actual function call
+ templ += '''
+ int
+ main ()
+ {{
+ return {1} ();
+ }}'''
varname = 'has function ' + funcname
varname = varname.replace(' ', '_')
if self.is_cross:
@@ -664,7 +690,7 @@ int main(int argc, char **argv) {
if isinstance(val, bool):
return val
raise EnvironmentException('Cross variable {0} is not a boolean.'.format(varname))
- return self.compiles(templ % (prefix, funcname), extra_args)
+ return self.links(templ.format(prefix, funcname), extra_args)
def has_member(self, typename, membername, prefix, extra_args=[]):
templ = '''%s
diff --git a/test cases/common/43 has function/meson.build b/test cases/common/43 has function/meson.build
index 8fccaef..3736a3d 100644
--- a/test cases/common/43 has function/meson.build
+++ b/test cases/common/43 has function/meson.build
@@ -6,6 +6,30 @@ if not cc.has_function('printf', prefix : '#include<stdio.h>')
error('Existing function not found.')
endif
+# Should also be able to detect it without specifying the header
+# We check for a different function here to make sure the result is
+# not taken from a cache (ie. the check above)
+assert(cc.has_function('fprintf'), 'Existing function not found without include')
+
if cc.has_function('hfkerhisadf', prefix : '#include<stdio.h>')
error('Found non-existant function.')
endif
+
+# With glibc on Linux lchmod is a stub that will always return an error,
+# we want to detect that and declare that the function is not available.
+# 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_machine.system() == 'linux' and cc.get_id() == 'gcc'
+ assert (cc.has_function('poll', prefix : '#include <poll.h>'), 'couldn\'t detect poll when defined by a header')
+ assert (not cc.has_function('lchmod', prefix : '''#include <sys/stat.h>
+ #include <unistd.h>'''), 'lchmod check should have failed')
+endif
+
+# For some functions one needs to define _GNU_SOURCE before including the
+# right headers to get them picked up. Make sure we can detect these functions
+# as well without any prefix
+if cc.has_header_symbol('sys/socket.h', 'recvmmsg', prefix : '#define _GNU_SOURCE')
+ # We assume that if recvmmsg exists sendmmsg does too
+ assert (cc.has_function('sendmmsg'), 'Failed to detect existing function')
+endif