зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1269517 - Implement try_compile for Python configure. r=glandium
MozReview-Commit-ID: AE7uRVneGXJ
This commit is contained in:
Родитель
46a1df138f
Коммит
414823b805
|
@ -0,0 +1,55 @@
|
|||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# 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/.
|
||||
|
||||
|
||||
# Generates a test program and attempts to compile it. In case of failure, the
|
||||
# resulting check will return None. If the test program succeeds, it will return
|
||||
# the output of the test program.
|
||||
# - `includes` are the includes (as file names) that will appear at the top of
|
||||
# the generated test program.
|
||||
# - `body` is the code that will appear in the main function of the generated
|
||||
# test program. `return 0;` is appended to the function body automatically.
|
||||
# - `language` is the language selection, so that the appropriate compiler is
|
||||
# used.
|
||||
# - `flags` are the flags to be passed to the compiler, in addition to `-c`.
|
||||
# - `check_msg` is the message to be printed to accompany compiling the test
|
||||
# program.
|
||||
@template
|
||||
@imports('textwrap')
|
||||
def try_compile(includes=None, body='', language='C++', flags=None, check_msg=None):
|
||||
includes = includes or []
|
||||
source_lines = ['#include <%s>' % f for f in includes]
|
||||
source = '\n'.join(source_lines) + '\n'
|
||||
source += textwrap.dedent('''\
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
%s
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
''' % body)
|
||||
flags = flags or []
|
||||
flags.append('-c')
|
||||
|
||||
if check_msg:
|
||||
def checking_fn(fn):
|
||||
return checking(check_msg, callback=lambda r: r is not None)(fn)
|
||||
else:
|
||||
def checking_fn(fn):
|
||||
return fn
|
||||
|
||||
@depends(cxx_compiler, c_compiler)
|
||||
@checking_fn
|
||||
def check(cxx_info, c_info):
|
||||
info = {
|
||||
'C': c_info,
|
||||
'C++': cxx_info,
|
||||
}[language]
|
||||
return try_invoke_compiler(info.wrapper + [info.compiler] + info.flags,
|
||||
language, source, flags,
|
||||
onerror=lambda: None)
|
||||
return check
|
|
@ -676,6 +676,8 @@ host_cxx_compiler = compiler('C++', host, c_compiler=host_c_compiler,
|
|||
other_compiler=cxx_compiler,
|
||||
other_c_compiler=c_compiler)
|
||||
|
||||
include('compilechecks.configure')
|
||||
|
||||
@depends(c_compiler)
|
||||
def default_debug_flags(compiler_info):
|
||||
# Debug info is ON by default.
|
||||
|
|
|
@ -39,6 +39,7 @@ PYTHON_UNIT_TESTS += [
|
|||
'mozbuild/mozbuild/test/compilation/test_warnings.py',
|
||||
'mozbuild/mozbuild/test/configure/test_checks_configure.py',
|
||||
'mozbuild/mozbuild/test/configure/test_configure.py',
|
||||
'mozbuild/mozbuild/test/configure/test_header_checks.py',
|
||||
'mozbuild/mozbuild/test/configure/test_moz_configure.py',
|
||||
'mozbuild/mozbuild/test/configure/test_options.py',
|
||||
'mozbuild/mozbuild/test/configure/test_toolchain_configure.py',
|
||||
|
|
|
@ -0,0 +1,154 @@
|
|||
# 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/.
|
||||
|
||||
from __future__ import absolute_import, print_function, unicode_literals
|
||||
|
||||
import os
|
||||
import textwrap
|
||||
import unittest
|
||||
|
||||
from StringIO import StringIO
|
||||
|
||||
from buildconfig import topsrcdir
|
||||
from common import ConfigureTestSandbox
|
||||
from mozbuild.util import exec_
|
||||
from mozunit import main
|
||||
from test_toolchain_helpers import FakeCompiler
|
||||
|
||||
|
||||
class TestHeaderChecks(unittest.TestCase):
|
||||
|
||||
def get_mock_compiler(self, expected_test_content=None, expected_flags=None):
|
||||
expected_flags = expected_flags or []
|
||||
def mock_compiler(stdin, args):
|
||||
args, test_file = args[:-1], args[-1]
|
||||
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),
|
||||
}
|
||||
|
||||
mock_compiler_defs = textwrap.dedent('''\
|
||||
@depends('--help')
|
||||
def c_compiler(_):
|
||||
return namespace(
|
||||
flags=[],
|
||||
compiler=os.path.abspath('/usr/bin/mockcc'),
|
||||
wrapper=[],
|
||||
)
|
||||
|
||||
@depends('--help')
|
||||
def cxx_compiler(_):
|
||||
return namespace(
|
||||
flags=[],
|
||||
compiler=os.path.abspath('/usr/bin/mockcc'),
|
||||
wrapper=[],
|
||||
)
|
||||
''')
|
||||
|
||||
config = {}
|
||||
out = StringIO()
|
||||
sandbox = ConfigureTestSandbox(paths, config, {}, ['/bin/configure'],
|
||||
out, out)
|
||||
base_dir = os.path.join(topsrcdir, 'build', 'moz.configure')
|
||||
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, 'compilechecks.configure'))
|
||||
|
||||
status = 0
|
||||
try:
|
||||
exec_(command, sandbox)
|
||||
sandbox.run()
|
||||
except SystemExit as e:
|
||||
status = e.code
|
||||
|
||||
return config, out.getvalue(), status
|
||||
|
||||
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('''\
|
||||
@depends(try_compile(body='somefn();', flags=['-funknown-flag']))
|
||||
def have_fn(value):
|
||||
if value is not None:
|
||||
return True
|
||||
set_config('HAVE_SOMEFN', have_fn)
|
||||
|
||||
@depends(try_compile(body='anotherfn();', language='C'))
|
||||
def have_another(value):
|
||||
if value is not None:
|
||||
return True
|
||||
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('''\
|
||||
@depends(try_compile(language='C++', flags=['-fknown-flag'],
|
||||
check_msg='whether -fknown-flag works'))
|
||||
def known_flag(result):
|
||||
if result is not None:
|
||||
return True
|
||||
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
|
||||
'''))
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
Загрузка…
Ссылка в новой задаче