summaryrefslogtreecommitdiffstats
path: root/python/mozbuild/mozbuild/test/configure/test_compile_checks.py
diff options
context:
space:
mode:
Diffstat (limited to 'python/mozbuild/mozbuild/test/configure/test_compile_checks.py')
-rw-r--r--python/mozbuild/mozbuild/test/configure/test_compile_checks.py599
1 files changed, 599 insertions, 0 deletions
diff --git a/python/mozbuild/mozbuild/test/configure/test_compile_checks.py b/python/mozbuild/mozbuild/test/configure/test_compile_checks.py
new file mode 100644
index 0000000000..37988d535f
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/configure/test_compile_checks.py
@@ -0,0 +1,599 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+import os
+import textwrap
+import unittest
+
+import mozpack.path as mozpath
+from buildconfig import topsrcdir
+from mozunit import main
+from six import StringIO
+from test_toolchain_helpers import FakeCompiler
+
+from common import ConfigureTestSandbox
+from mozbuild.util import exec_
+
+
+class BaseCompileChecks(unittest.TestCase):
+ def get_mock_compiler(self, expected_test_content=None, expected_flags=None):
+ expected_flags = expected_flags or []
+
+ def mock_compiler(stdin, args):
+ if args != ["--version"]:
+ test_file = [a for a in args if not a.startswith("-")]
+ self.assertEqual(len(test_file), 1)
+ test_file = test_file[0]
+ args = [a for a in args if a.startswith("-")]
+ self.assertIn("-c", args)
+ for flag in expected_flags:
+ self.assertIn(flag, args)
+
+ if expected_test_content:
+ with open(test_file) as fh:
+ test_content = fh.read()
+ self.assertEqual(test_content, expected_test_content)
+
+ return FakeCompiler()(None, args)
+
+ return mock_compiler
+
+ def do_compile_test(self, command, expected_test_content=None, expected_flags=None):
+
+ paths = {
+ os.path.abspath("/usr/bin/mockcc"): self.get_mock_compiler(
+ expected_test_content=expected_test_content,
+ expected_flags=expected_flags,
+ ),
+ }
+
+ base_dir = os.path.join(topsrcdir, "build", "moz.configure")
+
+ mock_compiler_defs = textwrap.dedent(
+ """\
+ @depends(when=True)
+ def extra_toolchain_flags():
+ return []
+
+ @depends(when=True)
+ def linker_ldflags():
+ return []
+
+ target = depends(when=True)(lambda: True)
+
+ @depends(when=True)
+ def configure_cache():
+
+ class ConfigureCache(dict):
+ pass
+
+ cache_data = {}
+
+ cache = ConfigureCache(cache_data)
+ cache.version_checked_compilers = set()
+
+ return cache
+
+ include('%s/compilers-util.configure')
+
+ @template
+ def wrap_compiler(compiler):
+ return compiler_class(compiler, False)
+
+ @wrap_compiler
+ @depends(when=True)
+ def c_compiler():
+ return namespace(
+ flags=[],
+ type='gcc',
+ compiler=os.path.abspath('/usr/bin/mockcc'),
+ wrapper=[],
+ language='C',
+ )
+
+ @wrap_compiler
+ @depends(when=True)
+ def host_c_compiler():
+ return namespace(
+ flags=[],
+ type='gcc',
+ compiler=os.path.abspath('/usr/bin/mockcc'),
+ wrapper=[],
+ language='C',
+ )
+
+ @wrap_compiler
+ @depends(when=True)
+ def cxx_compiler():
+ return namespace(
+ flags=[],
+ type='gcc',
+ compiler=os.path.abspath('/usr/bin/mockcc'),
+ wrapper=[],
+ language='C++',
+ )
+
+ @wrap_compiler
+ @depends(when=True)
+ def host_cxx_compiler():
+ return namespace(
+ flags=[],
+ type='gcc',
+ compiler=os.path.abspath('/usr/bin/mockcc'),
+ wrapper=[],
+ language='C++',
+ )
+ """
+ % mozpath.normsep(base_dir)
+ )
+
+ config = {}
+ out = StringIO()
+ sandbox = ConfigureTestSandbox(paths, config, {}, ["/bin/configure"], out, out)
+ sandbox.include_file(os.path.join(base_dir, "util.configure"))
+ sandbox.include_file(os.path.join(base_dir, "checks.configure"))
+ exec_(mock_compiler_defs, sandbox)
+ sandbox.include_file(os.path.join(base_dir, "compile-checks.configure"))
+
+ status = 0
+ try:
+ exec_(command, sandbox)
+ sandbox.run()
+ except SystemExit as e:
+ status = e.code
+
+ return config, out.getvalue(), status
+
+
+class TestHeaderChecks(BaseCompileChecks):
+ def test_try_compile_include(self):
+ expected_test_content = textwrap.dedent(
+ """\
+ #include <foo.h>
+ #include <bar.h>
+ int
+ main(void)
+ {
+
+ ;
+ return 0;
+ }
+ """
+ )
+
+ cmd = textwrap.dedent(
+ """\
+ try_compile(['foo.h', 'bar.h'], language='C')
+ """
+ )
+
+ config, out, status = self.do_compile_test(cmd, expected_test_content)
+ self.assertEqual(status, 0)
+ self.assertEqual(config, {})
+
+ def test_try_compile_flags(self):
+ expected_flags = ["--extra", "--flags"]
+
+ cmd = textwrap.dedent(
+ """\
+ try_compile(language='C++', flags=['--flags', '--extra'])
+ """
+ )
+
+ config, out, status = self.do_compile_test(cmd, expected_flags=expected_flags)
+ self.assertEqual(status, 0)
+ self.assertEqual(config, {})
+
+ def test_try_compile_failure(self):
+ cmd = textwrap.dedent(
+ """\
+ have_fn = try_compile(body='somefn();', flags=['-funknown-flag'])
+ set_config('HAVE_SOMEFN', have_fn)
+
+ have_another = try_compile(body='anotherfn();', language='C')
+ set_config('HAVE_ANOTHERFN', have_another)
+ """
+ )
+
+ config, out, status = self.do_compile_test(cmd)
+ self.assertEqual(status, 0)
+ self.assertEqual(
+ config,
+ {
+ "HAVE_ANOTHERFN": True,
+ },
+ )
+
+ def test_try_compile_msg(self):
+ cmd = textwrap.dedent(
+ """\
+ known_flag = try_compile(language='C++', flags=['-fknown-flag'],
+ check_msg='whether -fknown-flag works')
+ set_config('HAVE_KNOWN_FLAG', known_flag)
+ """
+ )
+ config, out, status = self.do_compile_test(cmd)
+ self.assertEqual(status, 0)
+ self.assertEqual(config, {"HAVE_KNOWN_FLAG": True})
+ self.assertEqual(
+ out,
+ textwrap.dedent(
+ """\
+ checking whether -fknown-flag works... yes
+ """
+ ),
+ )
+
+ def test_check_header(self):
+ expected_test_content = textwrap.dedent(
+ """\
+ #include <foo.h>
+ int
+ main(void)
+ {
+
+ ;
+ return 0;
+ }
+ """
+ )
+
+ cmd = textwrap.dedent(
+ """\
+ check_header('foo.h')
+ """
+ )
+
+ config, out, status = self.do_compile_test(
+ cmd, expected_test_content=expected_test_content
+ )
+ self.assertEqual(status, 0)
+ self.assertEqual(config, {"DEFINES": {"HAVE_FOO_H": True}})
+ self.assertEqual(
+ out,
+ textwrap.dedent(
+ """\
+ checking for foo.h... yes
+ """
+ ),
+ )
+
+ def test_check_header_conditional(self):
+ cmd = textwrap.dedent(
+ """\
+ check_headers('foo.h', 'bar.h', when=never)
+ """
+ )
+
+ config, out, status = self.do_compile_test(cmd)
+ self.assertEqual(status, 0)
+ self.assertEqual(out, "")
+ self.assertEqual(config, {"DEFINES": {}})
+
+ def test_check_header_include(self):
+ expected_test_content = textwrap.dedent(
+ """\
+ #include <std.h>
+ #include <bar.h>
+ #include <foo.h>
+ int
+ main(void)
+ {
+
+ ;
+ return 0;
+ }
+ """
+ )
+
+ cmd = textwrap.dedent(
+ """\
+ have_foo = check_header('foo.h', includes=['std.h', 'bar.h'])
+ set_config('HAVE_FOO_H', have_foo)
+ """
+ )
+
+ config, out, status = self.do_compile_test(
+ cmd, expected_test_content=expected_test_content
+ )
+
+ self.assertEqual(status, 0)
+ self.assertEqual(
+ config,
+ {
+ "HAVE_FOO_H": True,
+ "DEFINES": {
+ "HAVE_FOO_H": True,
+ },
+ },
+ )
+ self.assertEqual(
+ out,
+ textwrap.dedent(
+ """\
+ checking for foo.h... yes
+ """
+ ),
+ )
+
+ def test_check_headers_multiple(self):
+ cmd = textwrap.dedent(
+ """\
+ baz_bar, quux_bar = check_headers('baz/foo-bar.h', 'baz-quux/foo-bar.h')
+ set_config('HAVE_BAZ_BAR', baz_bar)
+ set_config('HAVE_QUUX_BAR', quux_bar)
+ """
+ )
+
+ config, out, status = self.do_compile_test(cmd)
+ self.assertEqual(status, 0)
+ self.assertEqual(
+ config,
+ {
+ "HAVE_BAZ_BAR": True,
+ "HAVE_QUUX_BAR": True,
+ "DEFINES": {
+ "HAVE_BAZ_FOO_BAR_H": True,
+ "HAVE_BAZ_QUUX_FOO_BAR_H": True,
+ },
+ },
+ )
+ self.assertEqual(
+ out,
+ textwrap.dedent(
+ """\
+ checking for baz/foo-bar.h... yes
+ checking for baz-quux/foo-bar.h... yes
+ """
+ ),
+ )
+
+ def test_check_headers_not_found(self):
+
+ cmd = textwrap.dedent(
+ """\
+ baz_bar, quux_bar = check_headers('baz/foo-bar.h', 'baz-quux/foo-bar.h',
+ flags=['-funknown-flag'])
+ set_config('HAVE_BAZ_BAR', baz_bar)
+ set_config('HAVE_QUUX_BAR', quux_bar)
+ """
+ )
+
+ config, out, status = self.do_compile_test(cmd)
+ self.assertEqual(status, 0)
+ self.assertEqual(config, {"DEFINES": {}})
+ self.assertEqual(
+ out,
+ textwrap.dedent(
+ """\
+ checking for baz/foo-bar.h... no
+ checking for baz-quux/foo-bar.h... no
+ """
+ ),
+ )
+
+
+class TestWarningChecks(BaseCompileChecks):
+ def get_warnings(self):
+ return textwrap.dedent(
+ """\
+ set_config('_WARNINGS_CFLAGS', warnings_flags.cflags)
+ set_config('_WARNINGS_CXXFLAGS', warnings_flags.cxxflags)
+ """
+ )
+
+ def test_check_and_add_warning(self):
+ for flag, expected_flags in (
+ ("-Wfoo", ["-Werror", "-Wfoo"]),
+ ("-Wno-foo", ["-Werror", "-Wfoo"]),
+ ("-Werror=foo", ["-Werror=foo"]),
+ ("-Wno-error=foo", ["-Wno-error=foo"]),
+ ):
+ cmd = (
+ textwrap.dedent(
+ """\
+ check_and_add_warning('%s')
+ """
+ % flag
+ )
+ + self.get_warnings()
+ )
+
+ config, out, status = self.do_compile_test(
+ cmd, expected_flags=expected_flags
+ )
+ self.assertEqual(status, 0)
+ self.assertEqual(
+ config,
+ {
+ "_WARNINGS_CFLAGS": [flag],
+ "_WARNINGS_CXXFLAGS": [flag],
+ },
+ )
+ self.assertEqual(
+ out,
+ textwrap.dedent(
+ """\
+ checking whether the C compiler supports {flag}... yes
+ checking whether the C++ compiler supports {flag}... yes
+ """.format(
+ flag=flag
+ )
+ ),
+ )
+
+ def test_check_and_add_warning_one(self):
+ cmd = (
+ textwrap.dedent(
+ """\
+ check_and_add_warning('-Wfoo', cxx_compiler)
+ """
+ )
+ + self.get_warnings()
+ )
+
+ config, out, status = self.do_compile_test(cmd)
+ self.assertEqual(status, 0)
+ self.assertEqual(
+ config,
+ {
+ "_WARNINGS_CFLAGS": [],
+ "_WARNINGS_CXXFLAGS": ["-Wfoo"],
+ },
+ )
+ self.assertEqual(
+ out,
+ textwrap.dedent(
+ """\
+ checking whether the C++ compiler supports -Wfoo... yes
+ """
+ ),
+ )
+
+ def test_check_and_add_warning_when(self):
+ cmd = (
+ textwrap.dedent(
+ """\
+ @depends(when=True)
+ def never():
+ return False
+ check_and_add_warning('-Wfoo', cxx_compiler, when=never)
+ """
+ )
+ + self.get_warnings()
+ )
+
+ config, out, status = self.do_compile_test(cmd)
+ self.assertEqual(status, 0)
+ self.assertEqual(
+ config,
+ {
+ "_WARNINGS_CFLAGS": [],
+ "_WARNINGS_CXXFLAGS": [],
+ },
+ )
+ self.assertEqual(out, "")
+
+ cmd = (
+ textwrap.dedent(
+ """\
+ @depends(when=True)
+ def always():
+ return True
+ check_and_add_warning('-Wfoo', cxx_compiler, when=always)
+ """
+ )
+ + self.get_warnings()
+ )
+
+ config, out, status = self.do_compile_test(cmd)
+ self.assertEqual(status, 0)
+ self.assertEqual(
+ config,
+ {
+ "_WARNINGS_CFLAGS": [],
+ "_WARNINGS_CXXFLAGS": ["-Wfoo"],
+ },
+ )
+ self.assertEqual(
+ out,
+ textwrap.dedent(
+ """\
+ checking whether the C++ compiler supports -Wfoo... yes
+ """
+ ),
+ )
+
+ def test_add_warning(self):
+ cmd = (
+ textwrap.dedent(
+ """\
+ add_warning('-Wfoo')
+ """
+ )
+ + self.get_warnings()
+ )
+
+ config, out, status = self.do_compile_test(cmd)
+ self.assertEqual(status, 0)
+ self.assertEqual(
+ config,
+ {
+ "_WARNINGS_CFLAGS": ["-Wfoo"],
+ "_WARNINGS_CXXFLAGS": ["-Wfoo"],
+ },
+ )
+ self.assertEqual(out, "")
+
+ def test_add_warning_one(self):
+ cmd = (
+ textwrap.dedent(
+ """\
+ add_warning('-Wfoo', c_compiler)
+ """
+ )
+ + self.get_warnings()
+ )
+
+ config, out, status = self.do_compile_test(cmd)
+ self.assertEqual(status, 0)
+ self.assertEqual(
+ config,
+ {
+ "_WARNINGS_CFLAGS": ["-Wfoo"],
+ "_WARNINGS_CXXFLAGS": [],
+ },
+ )
+ self.assertEqual(out, "")
+
+ def test_add_warning_when(self):
+ cmd = (
+ textwrap.dedent(
+ """\
+ @depends(when=True)
+ def never():
+ return False
+ add_warning('-Wfoo', c_compiler, when=never)
+ """
+ )
+ + self.get_warnings()
+ )
+
+ config, out, status = self.do_compile_test(cmd)
+ self.assertEqual(status, 0)
+ self.assertEqual(
+ config,
+ {
+ "_WARNINGS_CFLAGS": [],
+ "_WARNINGS_CXXFLAGS": [],
+ },
+ )
+ self.assertEqual(out, "")
+
+ cmd = (
+ textwrap.dedent(
+ """\
+ @depends(when=True)
+ def always():
+ return True
+ add_warning('-Wfoo', c_compiler, when=always)
+ """
+ )
+ + self.get_warnings()
+ )
+
+ config, out, status = self.do_compile_test(cmd)
+ self.assertEqual(status, 0)
+ self.assertEqual(
+ config,
+ {
+ "_WARNINGS_CFLAGS": ["-Wfoo"],
+ "_WARNINGS_CXXFLAGS": [],
+ },
+ )
+ self.assertEqual(out, "")
+
+
+if __name__ == "__main__":
+ main()