diff options
-rw-r--r-- | mesonbuild/compilers.py | 46 | ||||
-rw-r--r-- | test cases/common/43 has function/meson.build | 24 |
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 |