From 9b6c338bcd8f8a5224d67182ea781b8ea7b765c9 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 3 Sep 2020 00:12:47 +0200 Subject: [PATCH] environment: use ExternalProgram to find ninja This allows the NINJA environment variable to support all the Windows special cases, especially allowing an absolute path without extension. Based on a patch by Yonggang Luo. Fixes: #7659 Suggested-by: Nirbheek Chauhan Signed-off-by: Paolo Bonzini --- mesonbuild/backend/ninjabackend.py | 4 ++-- mesonbuild/environment.py | 16 ++++++++++------ mesonbuild/mcompile.py | 2 +- mesonbuild/mdist.py | 12 ++++++------ mesonbuild/minit.py | 2 +- mesonbuild/mtest.py | 2 +- mesonbuild/scripts/scanbuild.py | 2 +- 7 files changed, 22 insertions(+), 18 deletions(-) diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index 44ea71472..8afb80ed6 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -543,7 +543,7 @@ int dummy; rules += [ "%s%s" % (rule, ext) for rule in [self.get_pch_rule_name(lang, for_machine)] for ext in ['', '_RSP']] compdb_options = ['-x'] if mesonlib.version_compare(self.ninja_version, '>=1.9') else [] - ninja_compdb = [self.ninja_command, '-t', 'compdb'] + compdb_options + rules + ninja_compdb = self.ninja_command + ['-t', 'compdb'] + compdb_options + rules builddir = self.environment.get_build_dir() try: jsondb = subprocess.check_output(ninja_compdb, cwd=builddir) @@ -2959,7 +2959,7 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485''')) self.add_build(elem) elem = NinjaBuildElement(self.all_outputs, 'meson-clean', 'CUSTOM_COMMAND', 'PHONY') - elem.add_item('COMMAND', [self.ninja_command, '-t', 'clean']) + elem.add_item('COMMAND', self.ninja_command + ['-t', 'clean']) elem.add_item('description', 'Cleaning') # Alias that runs the above-defined meson-clean target self.create_target_alias('meson-clean') diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py index 24c465d29..c825bd876 100644 --- a/mesonbuild/environment.py +++ b/mesonbuild/environment.py @@ -158,15 +158,19 @@ def find_coverage_tools(): return gcovr_exe, gcovr_new_rootdir, lcov_exe, genhtml_exe, llvm_cov_exe -def detect_ninja(version: str = '1.7', log: bool = False) -> str: +def detect_ninja(version: str = '1.7', log: bool = False) -> T.List[str]: r = detect_ninja_command_and_version(version, log) return r[0] if r else None -def detect_ninja_command_and_version(version: str = '1.7', log: bool = False) -> (str, str): +def detect_ninja_command_and_version(version: str = '1.7', log: bool = False) -> (T.List[str], str): + from .dependencies.base import ExternalProgram env_ninja = os.environ.get('NINJA', None) for n in [env_ninja] if env_ninja else ['ninja', 'ninja-build', 'samu']: + prog = ExternalProgram(n, silent=True) + if not prog.found(): + continue try: - p, found = Popen_safe([n, '--version'])[0:2] + p, found = Popen_safe(prog.command + ['--version'])[0:2] except (FileNotFoundError, PermissionError): # Doesn't exist in PATH or isn't executable continue @@ -174,7 +178,6 @@ def detect_ninja_command_and_version(version: str = '1.7', log: bool = False) -> # Perhaps we should add a way for the caller to know the failure mode # (not found or too old) if p.returncode == 0 and mesonlib.version_compare(found, '>=' + version): - n = shutil.which(n) if log: name = os.path.basename(n) if name.endswith('-' + found): @@ -183,8 +186,9 @@ def detect_ninja_command_and_version(version: str = '1.7', log: bool = False) -> name = 'ninja' if name == 'samu': name = 'samurai' - mlog.log('Found {}-{} at {}'.format(name, found, quote_arg(n))) - return (n, found) + mlog.log('Found {}-{} at {}'.format(name, found, + ' '.join([quote_arg(x) for x in prog.command]))) + return (prog.command, found) def get_llvm_tool_names(tool: str) -> T.List[str]: # Ordered list of possible suffixes of LLVM executables to try. Start with diff --git a/mesonbuild/mcompile.py b/mesonbuild/mcompile.py index 3199f593d..8e2a38fbf 100644 --- a/mesonbuild/mcompile.py +++ b/mesonbuild/mcompile.py @@ -139,7 +139,7 @@ def get_parsed_args_ninja(options: 'argparse.Namespace', builddir: Path) -> T.Li raise MesonException('Cannot find ninja.') mlog.log('Found runner:', runner) - cmd = [runner, '-C', builddir.as_posix()] + cmd = runner + ['-C', builddir.as_posix()] if options.targets: intro_data = parse_introspect_data(builddir) diff --git a/mesonbuild/mdist.py b/mesonbuild/mdist.py index 9d94ace05..fbda240cf 100644 --- a/mesonbuild/mdist.py +++ b/mesonbuild/mdist.py @@ -180,19 +180,19 @@ def create_dist_hg(dist_name, archives, src_root, bld_root, dist_sub, dist_scrip output_names.append(zipname) return output_names -def run_dist_steps(meson_command, unpacked_src_dir, builddir, installdir, ninja_bin): +def run_dist_steps(meson_command, unpacked_src_dir, builddir, installdir, ninja_args): if subprocess.call(meson_command + ['--backend=ninja', unpacked_src_dir, builddir]) != 0: print('Running Meson on distribution package failed') return 1 - if subprocess.call([ninja_bin], cwd=builddir) != 0: + if subprocess.call(ninja_args, cwd=builddir) != 0: print('Compiling the distribution package failed') return 1 - if subprocess.call([ninja_bin, 'test'], cwd=builddir) != 0: + if subprocess.call(ninja_args + ['test'], cwd=builddir) != 0: print('Running unit tests on the distribution package failed') return 1 myenv = os.environ.copy() myenv['DESTDIR'] = installdir - if subprocess.call([ninja_bin, 'install'], cwd=builddir, env=myenv) != 0: + if subprocess.call(ninja_args + ['install'], cwd=builddir, env=myenv) != 0: print('Installing the distribution package failed') return 1 return 0 @@ -206,7 +206,7 @@ def check_dist(packagename, meson_command, extra_meson_args, bld_root, privdir): if os.path.exists(p): windows_proof_rmtree(p) os.mkdir(p) - ninja_bin = detect_ninja() + ninja_args = detect_ninja() shutil.unpack_archive(packagename, unpackdir) unpacked_files = glob(os.path.join(unpackdir, '*')) assert(len(unpacked_files) == 1) @@ -216,7 +216,7 @@ def check_dist(packagename, meson_command, extra_meson_args, bld_root, privdir): if o['name'] not in ['backend', 'install_umask', 'buildtype']] meson_command += extra_meson_args - ret = run_dist_steps(meson_command, unpacked_src_dir, builddir, installdir, ninja_bin) + ret = run_dist_steps(meson_command, unpacked_src_dir, builddir, installdir, ninja_args) if ret > 0: print('Dist check build directory was {}'.format(builddir)) else: diff --git a/mesonbuild/minit.py b/mesonbuild/minit.py index d0aff49a7..06e6dd4f3 100644 --- a/mesonbuild/minit.py +++ b/mesonbuild/minit.py @@ -174,7 +174,7 @@ def run(options) -> int: ret = subprocess.run(cmd) if ret.returncode: raise SystemExit - cmd = [detect_ninja(), '-C', options.builddir] + cmd = detect_ninja() + ['-C', options.builddir] ret = subprocess.run(cmd) if ret.returncode: raise SystemExit diff --git a/mesonbuild/mtest.py b/mesonbuild/mtest.py index e6b12e53b..c28bdd230 100644 --- a/mesonbuild/mtest.py +++ b/mesonbuild/mtest.py @@ -1173,7 +1173,7 @@ def rebuild_all(wd: str) -> bool: print("Can't find ninja, can't rebuild test.") return False - ret = subprocess.run([ninja, '-C', wd]).returncode + ret = subprocess.run(ninja + ['-C', wd]).returncode if ret != 0: print('Could not rebuild {}'.format(wd)) return False diff --git a/mesonbuild/scripts/scanbuild.py b/mesonbuild/scripts/scanbuild.py index b9e96d20e..0190067e2 100644 --- a/mesonbuild/scripts/scanbuild.py +++ b/mesonbuild/scripts/scanbuild.py @@ -22,7 +22,7 @@ from ..environment import detect_ninja, detect_scanbuild def scanbuild(exelist, srcdir, blddir, privdir, logdir, args): with tempfile.TemporaryDirectory(dir=privdir) as scandir: meson_cmd = exelist + args - build_cmd = exelist + ['-o', logdir, detect_ninja(), '-C', scandir] + build_cmd = exelist + ['-o', logdir] + detect_ninja() + ['-C', scandir] rc = subprocess.call(meson_cmd + [srcdir, scandir]) if rc != 0: return rc