aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim-Philipp Müller <tim@centricular.com>2016-04-07 20:19:52 +0530
committerNirbheek Chauhan <nirbheek@centricular.com>2016-04-07 20:53:12 +0530
commit1934ddfc5b21d3dd2bb16dfeae67605e11808bdf (patch)
treee08a5854ca1b6fc8e226669f11c8d27e01eb94df
parent700010e452517d0a0b11e8e460d65b257a449302 (diff)
downloadmeson-1934ddfc5b21d3dd2bb16dfeae67605e11808bdf.zip
meson-1934ddfc5b21d3dd2bb16dfeae67605e11808bdf.tar.gz
meson-1934ddfc5b21d3dd2bb16dfeae67605e11808bdf.tar.bz2
Improve cc.has_function() check to not require any includes and detect stubs
We now use .links() to detect if a C compiler function is available or not, that way the user doesn't need to specify all the possible includes for the check, which simplifies things considerably. Also detect glibc stub functions that will never work and return false for them. Closes #437
-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