aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNirbheek Chauhan <nirbheek@centricular.com>2016-11-29 03:15:03 +0530
committerNirbheek Chauhan <nirbheek@centricular.com>2016-12-04 00:32:24 +0530
commitcee9638cc43682b6e371cc2becae745876c73bda (patch)
tree58f414d5acc2144e286c9f58d01039528a8dd2fa
parentc1efaafec46ad837a2e9a0d409dd98302b619141 (diff)
downloadmeson-cee9638cc43682b6e371cc2becae745876c73bda.zip
meson-cee9638cc43682b6e371cc2becae745876c73bda.tar.gz
meson-cee9638cc43682b6e371cc2becae745876c73bda.tar.bz2
Compiler check and extra args should always override
We want compiler check arguments (-O0, -fpermissive, etc) to override all other arguments, and we want extra_args passed in by the build file to always override everything. To do this properly, we must split include arguments out, append them first, append all other arguments as usual, and then append the rest. As part of this, we also add the compiler check flags to the cc.compiles() and cc.links() helper functions since they also most likely need them. Also includes a unit test for all this.
-rw-r--r--mesonbuild/compilers.py59
-rwxr-xr-xrun_unittests.py28
-rw-r--r--test cases/common/43 has function/meson.build32
3 files changed, 96 insertions, 23 deletions
diff --git a/mesonbuild/compilers.py b/mesonbuild/compilers.py
index 8f8851f..ef37226 100644
--- a/mesonbuild/compilers.py
+++ b/mesonbuild/compilers.py
@@ -701,8 +701,28 @@ int main () {{
#endif
return 0;
}}'''
- args = extra_args + self.get_compiler_check_args()
- return self.compiles(templ.format(hname, symbol, prefix), env, args, dependencies)
+ return self.compiles(templ.format(hname, symbol, prefix), env,
+ extra_args, dependencies)
+
+ @staticmethod
+ def _override_args(args, override):
+ '''
+ Add @override to @args in such a way that arguments are overrided
+ correctly.
+
+ We want the include directories to be added first (since they are
+ chosen left-to-right) and all other arguments later (since they
+ override previous arguments or add to a list that's chosen
+ right-to-left).
+ '''
+ before_args = []
+ after_args = []
+ for arg in override:
+ if arg.startswith(('-I', '/I')):
+ before_args.append(arg)
+ else:
+ after_args.append(arg)
+ return before_args + args + after_args
def compiles(self, code, env, extra_args=None, dependencies=None):
if extra_args is None:
@@ -713,9 +733,10 @@ int main () {{
dependencies = []
elif not isinstance(dependencies, list):
dependencies = [dependencies]
+ # Add compile flags needed by dependencies after converting to the
+ # native type of the selected compiler
cargs = [a for d in dependencies for a in d.get_compile_args()]
- # Convert flags to the native type of the selected compiler
- args = self.unix_link_flags_to_native(cargs + extra_args)
+ args = self.unix_link_flags_to_native(cargs)
# 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
@@ -723,6 +744,11 @@ int main () {{
args += env.coredata.external_args[self.language]
# We only want to compile; not link
args += self.get_compile_only_args()
+ # Append extra_args to the compiler check args such that it overrides
+ extra_args = self._override_args(self.get_compiler_check_args(), extra_args)
+ extra_args = self.unix_link_flags_to_native(extra_args)
+ # Append both to the compiler args such that they override them
+ args = self._override_args(args, extra_args)
with self.compile(code, args) as p:
return p.returncode == 0
@@ -736,17 +762,24 @@ int main () {{
dependencies = []
elif not isinstance(dependencies, list):
dependencies = [dependencies]
+ # Add compile and link flags needed by dependencies after converting to
+ # the native type of the selected compiler
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)
+ args = self.unix_link_flags_to_native(cargs + link_args)
# Select a CRT if needed since we're linking
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)
+ # 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)
# Add LDFLAGS from the env. We assume that the user has ensured these
# are compiler-specific
args += env.coredata.external_link_args[self.language]
+ # Append extra_args to the compiler check args such that it overrides
+ extra_args = self._override_args(self.get_compiler_check_args(), extra_args)
+ extra_args = self.unix_link_flags_to_native(extra_args)
+ # Append both to the compiler args such that they override them
+ args = self._override_args(args, extra_args)
return self.compile(code, args)
def links(self, code, env, extra_args=None, dependencies=None):
@@ -795,7 +828,6 @@ int main(int argc, char **argv) {{
%s
int temparray[%d-sizeof(%s)];
'''
- args = extra_args + self.get_compiler_check_args()
if not self.compiles(element_exists_templ.format(prefix, element), env, args, dependencies):
return -1
for i in range(1, 1024):
@@ -844,7 +876,6 @@ struct tmp {
int testarray[%d-offsetof(struct tmp, target)];
'''
- args = extra_args + self.get_compiler_check_args()
if not self.compiles(type_exists_templ.format(typename), env, args, dependencies):
return -1
for i in range(1, 1024):
@@ -980,14 +1011,14 @@ int main(int argc, char **argv) {
head, main = self._no_prototype_templ()
templ = head + stubs_fail + main
- args = extra_args + self.get_compiler_check_args()
- if self.links(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
# special functions that ignore all includes and defines, so we just
# directly try to link via main().
- return self.links('int main() {{ {0}; }}'.format('__builtin_' + funcname), env, args, dependencies)
+ return self.links('int main() {{ {0}; }}'.format('__builtin_' + funcname),
+ env, extra_args, dependencies)
def has_members(self, typename, membernames, prefix, env, extra_args=None, dependencies=None):
if extra_args is None:
@@ -1071,8 +1102,8 @@ class CPPCompiler(CCompiler):
#include <{0}>
using {1};
int main () {{ return 0; }}'''
- args = extra_args + self.get_compiler_check_args()
- return self.compiles(templ.format(hname, symbol, prefix), env, args, dependencies)
+ return self.compiles(templ.format(hname, symbol, prefix), env,
+ extra_args, dependencies)
class ObjCCompiler(CCompiler):
def __init__(self, exelist, version, is_cross, exe_wrap):
diff --git a/run_unittests.py b/run_unittests.py
index 8b1f13f..b8d23b8 100755
--- a/run_unittests.py
+++ b/run_unittests.py
@@ -94,6 +94,16 @@ class LinuxlikeTests(unittest.TestCase):
with open(os.path.join(self.builddir, 'meson-logs', 'meson-log.txt')) as f:
return f.readlines()
+ def get_meson_log_compiler_checks(self):
+ '''
+ Fetch a list command-lines run by meson for compiler checks.
+ Each command-line is returned as a list of arguments.
+ '''
+ log = self.get_meson_log()
+ prefix = 'Command line:'
+ cmds = [l[len(prefix):].split() for l in log if l.startswith(prefix)]
+ return cmds
+
def introspect(self, arg):
out = subprocess.check_output(self.mintro_command + [arg, self.builddir])
return json.loads(out.decode('utf-8'))
@@ -262,5 +272,23 @@ class LinuxlikeTests(unittest.TestCase):
self.assertEqual(self.get_soname(bothset), 'libbothset.so.1.2.3')
self.assertEqual(len(glob(bothset[:-3] + '*')), 3)
+ def test_compiler_check_flags_order(self):
+ '''
+ Test that compiler check flags override all other flags. This can't be
+ an ordinary test case because it needs the environment to be set.
+ '''
+ Oflag = '-O3'
+ os.environ['CFLAGS'] = os.environ['CXXFLAGS'] = Oflag
+ testdir = os.path.join(self.common_test_dir, '43 has function')
+ self.init(testdir)
+ cmds = self.get_meson_log_compiler_checks()
+ for cmd in cmds:
+ # Verify that -I flags from the `args` kwarg are first
+ # This is set in the '43 has function' test case
+ self.assertEqual(cmd[2], '-I/tmp')
+ # Verify that -O3 set via the environment is overriden by -O0
+ Oargs = [arg for arg in cmd if arg.startswith('-O')]
+ self.assertEqual(Oargs, [Oflag, '-O0'])
+
if __name__ == '__main__':
unittest.main()
diff --git a/test cases/common/43 has function/meson.build b/test cases/common/43 has function/meson.build
index 61f96e1..e0d3344 100644
--- a/test cases/common/43 has function/meson.build
+++ b/test cases/common/43 has function/meson.build
@@ -1,9 +1,12 @@
project('has function', 'c', 'cpp')
+# This is used in the `test_compiler_check_flags_order` unit test
+unit_test_args = '-I/tmp'
compilers = [meson.get_compiler('c'), meson.get_compiler('cpp')]
foreach cc : compilers
- if not cc.has_function('printf', prefix : '#include<stdio.h>')
+ if not cc.has_function('printf', prefix : '#include<stdio.h>',
+ args : unit_test_args)
error('"printf" function not found (should always exist).')
endif
@@ -13,12 +16,16 @@ foreach cc : compilers
# On MSVC fprintf is defined as an inline function in the header, so it cannot
# be found without the include.
if cc.get_id() != 'msvc'
- assert(cc.has_function('fprintf'), '"fprintf" function not found without include (on !msvc).')
+ assert(cc.has_function('fprintf', args : unit_test_args),
+ '"fprintf" function not found without include (on !msvc).')
else
- assert(cc.has_function('fprintf', prefix : '#include <stdio.h>'), '"fprintf" function not found with include (on msvc).')
+ assert(cc.has_function('fprintf', prefix : '#include <stdio.h>',
+ args : unit_test_args),
+ '"fprintf" function not found with include (on msvc).')
endif
- if cc.has_function('hfkerhisadf', prefix : '#include<stdio.h>')
+ if cc.has_function('hfkerhisadf', prefix : '#include<stdio.h>',
+ args : unit_test_args)
error('Found non-existent function "hfkerhisadf".')
endif
@@ -28,16 +35,23 @@ foreach cc : compilers
# 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')
+ assert (cc.has_function('poll', prefix : '#include <poll.h>',
+ args : unit_test_args),
+ 'couldn\'t detect "poll" when defined by a header')
+ lchmod_prefix = '#include <sys/stat.h>\n#include <unistd.h>'
+ assert (not cc.has_function('lchmod', prefix : lchmod_prefix,
+ args : unit_test_args),
+ '"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')
+ if cc.has_header_symbol('sys/socket.h', 'recvmmsg',
+ prefix : '#define _GNU_SOURCE',
+ args : unit_test_args)
# We assume that if recvmmsg exists sendmmsg does too
- assert (cc.has_function('sendmmsg'), 'Failed to detect function "sendmmsg" (should always exist).')
+ assert (cc.has_function('sendmmsg', args : unit_test_args),
+ 'Failed to detect function "sendmmsg" (should always exist).')
endif
endforeach