123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226 |
- #!/usr/bin/env python3
- # Copyright 2012-2017 The Meson development team
- # Licensed under the Apache License, Version 2.0 (the "License");
- # you may not use this file except in compliance with the License.
- # You may obtain a copy of the License at
- # http://www.apache.org/licenses/LICENSE-2.0
- # Unless required by applicable law or agreed to in writing, software
- # distributed under the License is distributed on an "AS IS" BASIS,
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- # See the License for the specific language governing permissions and
- # limitations under the License.
- import os
- import sys
- import time
- import shutil
- import subprocess
- import tempfile
- import platform
- from mesonbuild import mesonlib
- from mesonbuild import mesonmain
- from mesonbuild import mlog
- from mesonbuild.environment import detect_ninja
- from io import StringIO
- from enum import Enum
- from glob import glob
- Backend = Enum('Backend', 'ninja vs xcode')
- if 'MESON_EXE' in os.environ:
- import shlex
- meson_exe = shlex.split(os.environ['MESON_EXE'])
- else:
- meson_exe = None
- if mesonlib.is_windows() or mesonlib.is_cygwin():
- exe_suffix = '.exe'
- else:
- exe_suffix = ''
- def get_backend_args_for_dir(backend, builddir):
- '''
- Visual Studio backend needs to be given the solution to build
- '''
- if backend is Backend.vs:
- sln_name = glob(os.path.join(builddir, '*.sln'))[0]
- return [os.path.split(sln_name)[-1]]
- return []
- def find_vcxproj_with_target(builddir, target):
- import re, fnmatch
- t, ext = os.path.splitext(target)
- if ext:
- p = '<TargetName>{}</TargetName>\s*<TargetExt>\{}</TargetExt>'.format(t, ext)
- else:
- p = '<TargetName>{}</TargetName>'.format(t)
- for root, dirs, files in os.walk(builddir):
- for f in fnmatch.filter(files, '*.vcxproj'):
- f = os.path.join(builddir, f)
- with open(f, 'r', encoding='utf-8') as o:
- if re.search(p, o.read(), flags=re.MULTILINE):
- return f
- raise RuntimeError('No vcxproj matching {!r} in {!r}'.format(p, builddir))
- def get_builddir_target_args(backend, builddir, target):
- dir_args = []
- if not target:
- dir_args = get_backend_args_for_dir(backend, builddir)
- if target is None:
- return dir_args
- if backend is Backend.vs:
- vcxproj = find_vcxproj_with_target(builddir, target)
- target_args = [vcxproj]
- elif backend is Backend.xcode:
- target_args = ['-target', target]
- elif backend is Backend.ninja:
- target_args = [target]
- else:
- raise AssertionError('Unknown backend: {!r}'.format(backend))
- return target_args + dir_args
- def get_backend_commands(backend, debug=False):
- install_cmd = []
- uninstall_cmd = []
- if backend is Backend.vs:
- cmd = ['msbuild']
- clean_cmd = cmd + ['/target:Clean']
- test_cmd = cmd + ['RUN_TESTS.vcxproj']
- elif backend is Backend.xcode:
- cmd = ['xcodebuild']
- clean_cmd = cmd + ['-alltargets', 'clean']
- test_cmd = cmd + ['-target', 'RUN_TESTS']
- elif backend is Backend.ninja:
- # We need at least 1.6 because of -w dupbuild=err
- cmd = [detect_ninja('1.6'), '-w', 'dupbuild=err', '-d', 'explain']
- if cmd[0] is None:
- raise RuntimeError('Could not find Ninja v1.6 or newer')
- if debug:
- cmd += ['-v']
- clean_cmd = cmd + ['clean']
- test_cmd = cmd + ['test', 'benchmark']
- install_cmd = cmd + ['install']
- uninstall_cmd = cmd + ['uninstall']
- else:
- raise AssertionError('Unknown backend: {!r}'.format(backend))
- return cmd, clean_cmd, test_cmd, install_cmd, uninstall_cmd
- def ensure_backend_detects_changes(backend):
- # We're using a ninja with QuLogic's patch for sub-1s resolution timestamps
- # and not running on HFS+ which only stores dates in seconds:
- # https://developer.apple.com/legacy/library/technotes/tn/tn1150.html#HFSPlusDates
- # FIXME: Upgrade Travis image to Apple FS when that becomes available
- if 'MESON_FIXED_NINJA' in os.environ and not mesonlib.is_osx():
- return
- # This is needed to increase the difference between build.ninja's
- # timestamp and the timestamp of whatever you changed due to a Ninja
- # bug: https://github.com/ninja-build/ninja/issues/371
- if backend is Backend.ninja:
- time.sleep(1)
- def get_fake_options(prefix):
- import argparse
- opts = argparse.Namespace()
- opts.cross_file = None
- opts.wrap_mode = None
- opts.prefix = prefix
- return opts
- def should_run_linux_cross_tests():
- return shutil.which('arm-linux-gnueabihf-gcc-7') and not platform.machine().lower().startswith('arm')
- def run_configure_inprocess(meson_command, commandlist):
- old_stdout = sys.stdout
- sys.stdout = mystdout = StringIO()
- old_stderr = sys.stderr
- sys.stderr = mystderr = StringIO()
- try:
- returncode = mesonmain.run(commandlist, meson_command)
- finally:
- sys.stdout = old_stdout
- sys.stderr = old_stderr
- return returncode, mystdout.getvalue(), mystderr.getvalue()
- def run_configure_external(full_command):
- pc, o, e = mesonlib.Popen_safe(full_command)
- return pc.returncode, o, e
- def run_configure(meson_command, commandlist):
- global meson_exe
- if meson_exe:
- return run_configure_external(meson_exe + commandlist)
- return run_configure_inprocess(meson_command, commandlist)
- def print_system_info():
- print(mlog.bold('System information.').get_text(mlog.colorize_console))
- print('Architecture:', platform.architecture())
- print('Machine:', platform.machine())
- print('Platform:', platform.system())
- print('Processor:', platform.processor())
- print('System:', platform.system())
- print('')
- if __name__ == '__main__':
- print_system_info()
- # Enable coverage early...
- enable_coverage = '--cov' in sys.argv
- if enable_coverage:
- os.makedirs('.coverage', exist_ok=True)
- sys.argv.remove('--cov')
- import coverage
- coverage.process_startup()
- returncode = 0
- # Iterate over list in reverse order to find the last --backend arg
- backend = Backend.ninja
- for arg in reversed(sys.argv[1:]):
- if arg.startswith('--backend'):
- if arg.startswith('--backend=vs'):
- backend = Backend.vs
- elif arg == '--backend=xcode':
- backend = Backend.xcode
- break
- # Running on a developer machine? Be nice!
- if not mesonlib.is_windows() and not mesonlib.is_haiku() and 'TRAVIS' not in os.environ:
- os.nice(20)
- # Appveyor sets the `platform` environment variable which completely messes
- # up building with the vs2010 and vs2015 backends.
- #
- # Specifically, MSBuild reads the `platform` environment variable to set
- # the configured value for the platform (Win32/x64/arm), which breaks x86
- # builds.
- #
- # Appveyor setting this also breaks our 'native build arch' detection for
- # Windows in environment.py:detect_windows_arch() by overwriting the value
- # of `platform` set by vcvarsall.bat.
- #
- # While building for x86, `platform` should be unset.
- if 'APPVEYOR' in os.environ and os.environ['arch'] == 'x86':
- os.environ.pop('platform')
- # Run tests
- print(mlog.bold('Running unittests.').get_text(mlog.colorize_console))
- print()
- # Can't pass arguments to unit tests, so set the backend to use in the environment
- env = os.environ.copy()
- env['MESON_UNIT_TEST_BACKEND'] = backend.name
- with tempfile.TemporaryDirectory() as td:
- # Enable coverage on all subsequent processes.
- if enable_coverage:
- with open(os.path.join(td, 'usercustomize.py'), 'w') as f:
- f.write('import coverage\n'
- 'coverage.process_startup()\n')
- env['COVERAGE_PROCESS_START'] = '.coveragerc'
- env['PYTHONPATH'] = os.pathsep.join([td] + env.get('PYTHONPATH', []))
- returncode += subprocess.call(mesonlib.python_command + ['run_unittests.py', '-v'], env=env)
- # Ubuntu packages do not have a binary without -6 suffix.
- if should_run_linux_cross_tests():
- print(mlog.bold('Running cross compilation tests.').get_text(mlog.colorize_console))
- print()
- returncode += subprocess.call(mesonlib.python_command + ['run_cross_test.py', 'cross/ubuntu-armhf.txt'],
- env=env)
- returncode += subprocess.call(mesonlib.python_command + ['run_project_tests.py'] + sys.argv[1:], env=env)
- sys.exit(returncode)
|