|
|
|
@ -17,7 +17,7 @@ import subprocess, os.path |
|
|
|
|
import tempfile |
|
|
|
|
from .import mesonlib |
|
|
|
|
from . import mlog |
|
|
|
|
from .mesonlib import MesonException |
|
|
|
|
from .mesonlib import MesonException, version_compare |
|
|
|
|
from . import coredata |
|
|
|
|
|
|
|
|
|
"""This file contains the data files of all compilers Meson knows |
|
|
|
@ -707,12 +707,16 @@ int main () {{ {1}; }}''' |
|
|
|
|
args = self.unix_link_flags_to_native(cargs + extra_args) |
|
|
|
|
# Read c_args/cpp_args/etc from the cross-info file (if needed) |
|
|
|
|
args += self.get_cross_extra_flags(env, compile=True, link=False) |
|
|
|
|
# Add CFLAGS/CXXFLAGS/OBJCFLAGS/OBJCXXFLAGS from the env |
|
|
|
|
# We assume that the user has ensured these are compiler-specific |
|
|
|
|
args += env.coredata.external_args[self.language] |
|
|
|
|
# We only want to compile; not link |
|
|
|
|
args += self.get_compile_only_args() |
|
|
|
|
with self.compile(code, args) as p: |
|
|
|
|
return p.returncode == 0 |
|
|
|
|
|
|
|
|
|
def links(self, code, env, extra_args=None, dependencies=None): |
|
|
|
|
def _links_wrapper(self, code, env, extra_args, dependencies): |
|
|
|
|
"Shares common code between self.links and self.run" |
|
|
|
|
if extra_args is None: |
|
|
|
|
extra_args = [] |
|
|
|
|
elif isinstance(extra_args, str): |
|
|
|
@ -729,27 +733,19 @@ int main () {{ {1}; }}''' |
|
|
|
|
args += self.get_linker_debug_crt_args() |
|
|
|
|
# Read c_args/c_link_args/cpp_args/cpp_link_args/etc from the cross-info file (if needed) |
|
|
|
|
args += self.get_cross_extra_flags(env, compile=True, link=True) |
|
|
|
|
with self.compile(code, args) as p: |
|
|
|
|
# Add LDFLAGS from the env. We assume that the user has ensured these |
|
|
|
|
# are compiler-specific |
|
|
|
|
args += env.coredata.external_link_args[self.language] |
|
|
|
|
return self.compile(code, args) |
|
|
|
|
|
|
|
|
|
def links(self, code, env, extra_args=None, dependencies=None): |
|
|
|
|
with self._links_wrapper(code, env, extra_args, dependencies) as p: |
|
|
|
|
return p.returncode == 0 |
|
|
|
|
|
|
|
|
|
def run(self, code, env, extra_args=None, dependencies=None): |
|
|
|
|
if extra_args is None: |
|
|
|
|
extra_args = [] |
|
|
|
|
if dependencies is None: |
|
|
|
|
dependencies = [] |
|
|
|
|
elif not isinstance(dependencies, list): |
|
|
|
|
dependencies = [dependencies] |
|
|
|
|
if self.is_cross and self.exe_wrapper is None: |
|
|
|
|
raise CrossNoRunException('Can not run test applications in this cross environment.') |
|
|
|
|
cargs = [a for d in dependencies for a in d.get_compile_args()] |
|
|
|
|
link_args = [a for d in dependencies for a in d.get_link_args()] |
|
|
|
|
# Convert flags to the native type of the selected compiler |
|
|
|
|
args = self.unix_link_flags_to_native(cargs + link_args + extra_args) |
|
|
|
|
# Select a CRT if needed since we're linking |
|
|
|
|
args += self.get_linker_debug_crt_args() |
|
|
|
|
# Read c_link_args/cpp_link_args/etc from the cross-info file |
|
|
|
|
args += self.get_cross_extra_flags(env, compile=True, link=True) |
|
|
|
|
with self.compile(code, args) as p: |
|
|
|
|
with self._links_wrapper(code, env, extra_args, dependencies) as p: |
|
|
|
|
if p.returncode != 0: |
|
|
|
|
mlog.debug('Could not compile test file %s: %d\n' % ( |
|
|
|
|
p.input_name, |
|
|
|
@ -878,55 +874,65 @@ int main(int argc, char **argv) { |
|
|
|
|
raise EnvironmentException('Could not determine alignment of %s. Sorry. You might want to file a bug.' % typename) |
|
|
|
|
return align |
|
|
|
|
|
|
|
|
|
def has_function(self, funcname, prefix, env, extra_args=None, dependencies=None): |
|
|
|
|
@staticmethod |
|
|
|
|
def _no_prototype_templ(): |
|
|
|
|
""" |
|
|
|
|
First, this function looks for the symbol in the default libraries |
|
|
|
|
provided by the compiler (stdlib + a few others usually). If that |
|
|
|
|
fails, it checks if any of the headers specified in the prefix provide |
|
|
|
|
an implementation of the function, and if that fails, it checks if it's |
|
|
|
|
implemented as a compiler-builtin. |
|
|
|
|
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. |
|
|
|
|
""" |
|
|
|
|
if extra_args is None: |
|
|
|
|
extra_args = [] |
|
|
|
|
# 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 the symbol to something else since it is defined by the |
|
|
|
|
# includes or defines listed by the user (prefix -> {0}) or by the |
|
|
|
|
# compiler. Then, undef the symbol to get rid of it completely. |
|
|
|
|
head = ''' |
|
|
|
|
#define {1} meson_disable_define_of_{1} |
|
|
|
|
#include <limits.h> |
|
|
|
|
{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 += ''' |
|
|
|
|
head += ''' |
|
|
|
|
#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. |
|
|
|
|
# We always include limits.h above to ensure that these are defined for |
|
|
|
|
# stub functions. |
|
|
|
|
stubs_fail = ''' |
|
|
|
|
#if defined __stub_{1} || defined __stub___{1} |
|
|
|
|
fail fail fail this function is not going to work |
|
|
|
|
#endif |
|
|
|
|
''' |
|
|
|
|
templ += stubs_fail |
|
|
|
|
|
|
|
|
|
# And finally the actual function call |
|
|
|
|
templ += ''' |
|
|
|
|
int |
|
|
|
|
main () |
|
|
|
|
# The actual function call |
|
|
|
|
main = ''' |
|
|
|
|
int main () |
|
|
|
|
{{ |
|
|
|
|
return {1} (); |
|
|
|
|
}}''' |
|
|
|
|
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 |
|
|
|
|
head = '#include <limits.h>\n{0}\n' |
|
|
|
|
# We don't know what the function takes or returns, so try to use it as |
|
|
|
|
# a function pointer |
|
|
|
|
main = '\nint main() {{ int a = (int) &{1}; }}' |
|
|
|
|
return head, main |
|
|
|
|
|
|
|
|
|
def has_function(self, funcname, prefix, env, extra_args=None, dependencies=None): |
|
|
|
|
""" |
|
|
|
|
First, this function looks for the symbol in the default libraries |
|
|
|
|
provided by the compiler (stdlib + a few others usually). If that |
|
|
|
|
fails, it checks if any of the headers specified in the prefix provide |
|
|
|
|
an implementation of the function, and if that fails, it checks if it's |
|
|
|
|
implemented as a compiler-builtin. |
|
|
|
|
""" |
|
|
|
|
if extra_args is None: |
|
|
|
|
extra_args = [] |
|
|
|
|
|
|
|
|
|
# Short-circuit if the check is already provided by the cross-info file |
|
|
|
|
varname = 'has function ' + funcname |
|
|
|
|
varname = varname.replace(' ', '_') |
|
|
|
|
if self.is_cross: |
|
|
|
@ -935,16 +941,35 @@ int main(int argc, char **argv) { |
|
|
|
|
if isinstance(val, bool): |
|
|
|
|
return val |
|
|
|
|
raise EnvironmentException('Cross variable {0} is not a boolean.'.format(varname)) |
|
|
|
|
if self.links(templ.format(prefix, funcname), env, extra_args, dependencies): |
|
|
|
|
return True |
|
|
|
|
|
|
|
|
|
# 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 already included limits.h earlier to ensure that these are defined |
|
|
|
|
# for stub functions. |
|
|
|
|
stubs_fail = ''' |
|
|
|
|
#if defined __stub_{1} || defined __stub___{1} |
|
|
|
|
fail fail fail this function is not going to work |
|
|
|
|
#endif |
|
|
|
|
''' |
|
|
|
|
|
|
|
|
|
# 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 |
|
|
|
|
# includes. If not, then try to do the Autoconf-style check with |
|
|
|
|
# a dummy prototype definition of our own. |
|
|
|
|
# This is needed when the linker determines symbol availability from an |
|
|
|
|
# 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 |
|
|
|
|
|
|
|
|
|
# Add -O0 to ensure that the symbol isn't optimized away by the compiler |
|
|
|
|
args = extra_args + self.get_no_optimization_args() |
|
|
|
|
# Sometimes the implementation is provided by the header, or the header |
|
|
|
|
# redefines the symbol to be something else. In that case, we want to |
|
|
|
|
# still detect the function. We still want to fail if __stub_foo or |
|
|
|
|
# _stub_foo are defined, of course. |
|
|
|
|
header_templ = '#include <limits.h>\n{0}\n' + stubs_fail + '\nint main() {{ {1}; }}' |
|
|
|
|
if self.links(header_templ.format(prefix, funcname), env, args, dependencies): |
|
|
|
|
if self.links(templ.format(prefix, funcname), env, extra_args, dependencies): |
|
|
|
|
return True |
|
|
|
|
# Some functions like alloca() are defined as compiler built-ins which |
|
|
|
|
# are inlined by the compiler, so test for that instead. Built-ins are |
|
|
|
@ -2073,6 +2098,20 @@ class ClangCompiler(): |
|
|
|
|
raise MesonException('Unreachable code when converting clang type to gcc type.') |
|
|
|
|
return get_gcc_soname_args(gcc_type, prefix, shlib_name, suffix, path, soversion) |
|
|
|
|
|
|
|
|
|
def has_argument(self, arg, env): |
|
|
|
|
return super().has_argument(['-Werror=unknown-warning-option', arg], env) |
|
|
|
|
|
|
|
|
|
def has_function(self, funcname, prefix, env, extra_args=None, dependencies=None): |
|
|
|
|
if extra_args is None: |
|
|
|
|
extra_args = [] |
|
|
|
|
# Starting with XCode 8, we need to pass this to force linker |
|
|
|
|
# visibility to obey OS X and iOS minimum version targets with |
|
|
|
|
# -mmacosx-version-min, -miphoneos-version-min, etc. |
|
|
|
|
# https://github.com/Homebrew/homebrew-core/issues/3727 |
|
|
|
|
if self.clang_type == CLANG_OSX and version_compare(self.version, '>=8.0'): |
|
|
|
|
extra_args.append('-Wl,-no_weak_imports') |
|
|
|
|
return super().has_function(funcname, prefix, env, extra_args, dependencies) |
|
|
|
|
|
|
|
|
|
class ClangCCompiler(ClangCompiler, CCompiler): |
|
|
|
|
def __init__(self, exelist, version, clang_type, is_cross, exe_wrapper=None): |
|
|
|
|
CCompiler.__init__(self, exelist, version, is_cross, exe_wrapper) |
|
|
|
@ -2099,11 +2138,8 @@ class ClangCCompiler(ClangCompiler, CCompiler): |
|
|
|
|
def get_option_link_args(self, options): |
|
|
|
|
return [] |
|
|
|
|
|
|
|
|
|
def has_argument(self, arg, env): |
|
|
|
|
return super().has_argument(['-Werror=unknown-warning-option', arg], env) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ClangCPPCompiler(ClangCompiler, CPPCompiler): |
|
|
|
|
class ClangCPPCompiler(ClangCompiler, CPPCompiler): |
|
|
|
|
def __init__(self, exelist, version, cltype, is_cross, exe_wrapper=None): |
|
|
|
|
CPPCompiler.__init__(self, exelist, version, is_cross, exe_wrapper) |
|
|
|
|
ClangCompiler.__init__(self, cltype) |
|
|
|
@ -2127,28 +2163,17 @@ class ClangCPPCompiler(ClangCompiler, CPPCompiler): |
|
|
|
|
def get_option_link_args(self, options): |
|
|
|
|
return [] |
|
|
|
|
|
|
|
|
|
def has_argument(self, arg, env): |
|
|
|
|
return super().has_argument(['-Werror=unknown-warning-option', arg], env) |
|
|
|
|
|
|
|
|
|
class ClangObjCCompiler(GnuObjCCompiler): |
|
|
|
|
class ClangObjCCompiler(ClangCompiler, GnuObjCCompiler): |
|
|
|
|
def __init__(self, exelist, version, cltype, is_cross, exe_wrapper=None): |
|
|
|
|
super().__init__(exelist, version, is_cross, exe_wrapper) |
|
|
|
|
self.id = 'clang' |
|
|
|
|
GnuObjCCompiler.__init__(self, exelist, version, is_cross, exe_wrapper) |
|
|
|
|
ClangCompiler.__init__(self, cltype) |
|
|
|
|
self.base_options = ['b_pch', 'b_lto', 'b_pgo', 'b_sanitize', 'b_coverage'] |
|
|
|
|
self.clang_type = cltype |
|
|
|
|
if self.clang_type != CLANG_OSX: |
|
|
|
|
self.base_options.append('b_lundef') |
|
|
|
|
self.base_options.append('b_asneeded') |
|
|
|
|
|
|
|
|
|
class ClangObjCPPCompiler(GnuObjCPPCompiler): |
|
|
|
|
class ClangObjCPPCompiler(ClangCompiler, GnuObjCPPCompiler): |
|
|
|
|
def __init__(self, exelist, version, cltype, is_cross, exe_wrapper=None): |
|
|
|
|
super().__init__(exelist, version, is_cross, exe_wrapper) |
|
|
|
|
self.id = 'clang' |
|
|
|
|
self.clang_type = cltype |
|
|
|
|
GnuObjCPPCompiler.__init__(self, exelist, version, is_cross, exe_wrapper) |
|
|
|
|
ClangCompiler.__init__(self, cltype) |
|
|
|
|
self.base_options = ['b_pch', 'b_lto', 'b_pgo', 'b_sanitize', 'b_coverage'] |
|
|
|
|
if self.clang_type != CLANG_OSX: |
|
|
|
|
self.base_options.append('b_lundef') |
|
|
|
|
self.base_options.append('b_asneeded') |
|
|
|
|
|
|
|
|
|
class FortranCompiler(Compiler): |
|
|
|
|
def __init__(self, exelist, version, is_cross, exe_wrapper=None): |
|
|
|
|