diff --git a/mesonbuild/dependencies.py b/mesonbuild/dependencies.py index 3f1e214df..b4f825b2d 100644 --- a/mesonbuild/dependencies.py +++ b/mesonbuild/dependencies.py @@ -353,37 +353,13 @@ class WxDependency(Dependency): class ExternalProgram(): def __init__(self, name, fullpath=None, silent=False, search_dir=None): self.name = name - self.fullpath = None if fullpath is not None: if not isinstance(fullpath, list): self.fullpath = [fullpath] else: self.fullpath = fullpath else: - self.fullpath = [shutil.which(name)] - if self.fullpath[0] is None and search_dir is not None: - trial = os.path.join(search_dir, name) - suffix = os.path.splitext(trial)[-1].lower()[1:] - if mesonlib.is_windows() and (suffix == 'exe' or suffix == 'com'\ - or suffix == 'bat'): - self.fullpath = [trial] - elif not mesonlib.is_windows() and os.access(trial, os.X_OK): - self.fullpath = [trial] - else: - # Now getting desperate. Maybe it is a script file that is a) not chmodded - # executable or b) we are on windows so they can't be directly executed. - try: - first_line = open(trial).readline().strip() - if first_line.startswith('#!'): - commands = first_line[2:].split('#')[0].strip().split() - if mesonlib.is_windows(): - # Windows does not have /usr/bin. - commands[0] = commands[0].split('/')[-1] - if commands[0] == 'env': - commands = commands[1:] - self.fullpath = commands + [trial] - except Exception: - pass + self.fullpath = self._search(name, search_dir) if not silent: if self.found(): mlog.log('Program', mlog.bold(name), 'found:', mlog.green('YES'), @@ -391,6 +367,67 @@ class ExternalProgram(): else: mlog.log('Program', mlog.bold(name), 'found:', mlog.red('NO')) + @staticmethod + def _shebang_to_cmd(script): + """ + Windows does not understand shebangs, so we check if the file has a + shebang and manually parse it to figure out the interpreter to use + """ + try: + first_line = open(script).readline().strip() + if first_line.startswith('#!'): + commands = first_line[2:].split('#')[0].strip().split() + if mesonlib.is_windows(): + # Windows does not have /usr/bin. + commands[0] = commands[0].split('/')[-1] + if commands[0] == 'env': + commands = commands[1:] + return commands + [script] + except Exception: + pass + return False + + @staticmethod + def _is_executable(path): + suffix = os.path.splitext(path)[-1].lower()[1:] + if mesonlib.is_windows(): + if suffix == 'exe' or suffix == 'com' or suffix == 'bat': + return True + elif os.access(path, os.X_OK): + return True + return False + + def _search_dir(self, name, search_dir): + if search_dir is None: + return False + trial = os.path.join(search_dir, name) + if not os.path.exists(trial): + return False + if self._is_executable(trial): + return [trial] + # Now getting desperate. Maybe it is a script file that is a) not chmodded + # executable or b) we are on windows so they can't be directly executed. + return self._shebang_to_cmd(trial) + + def _search(self, name, search_dir): + commands = self._search_dir(name, search_dir) + if commands: + return commands + # Do a standard search in PATH + fullpath = shutil.which(name) + if fullpath or not mesonlib.is_windows(): + # On UNIX-like platforms, the standard PATH search is enough + return [fullpath] + # On Windows, interpreted scripts must have an extension otherwise they + # cannot be found by a standard PATH search. So we do a custom search + # where we manually search for a script with a shebang in PATH. + search_dirs = os.environ.get('PATH', '').split(';') + for search_dir in search_dirs: + commands = self._search_dir(name, search_dir) + if commands: + return commands + return [None] + def found(self): return self.fullpath[0] is not None diff --git a/test cases/windows/9 find program/meson.build b/test cases/windows/9 find program/meson.build new file mode 100644 index 000000000..ef3458685 --- /dev/null +++ b/test cases/windows/9 find program/meson.build @@ -0,0 +1,4 @@ +project('find program', 'c') + +prog = find_program('test-script') +test('script', prog) diff --git a/test cases/windows/9 find program/test-script b/test cases/windows/9 find program/test-script new file mode 100644 index 000000000..d105a818d --- /dev/null +++ b/test cases/windows/9 find program/test-script @@ -0,0 +1,3 @@ +#!/usr/bin/env python + +print('1')