diff options
author | Nirbheek Chauhan <nirbheek@centricular.com> | 2017-02-07 17:22:18 +0530 |
---|---|---|
committer | Nirbheek Chauhan <nirbheek@centricular.com> | 2017-02-18 02:38:54 +0530 |
commit | 18bce476913de4deec18fcd028cb59d378c43812 (patch) | |
tree | e0c561119bc89ea4b98ffc6641a5028aa20556fc /mesonbuild | |
parent | d5b494492481a4379174786237cbc4d7eb037373 (diff) | |
download | meson-18bce476913de4deec18fcd028cb59d378c43812.zip meson-18bce476913de4deec18fcd028cb59d378c43812.tar.gz meson-18bce476913de4deec18fcd028cb59d378c43812.tar.bz2 |
find_program: Correctly use scripts found in PATH
We also need to check whether the program found in PATH can be executed
directly by Windows or if we need to figure out what the interpreter is
and add it to the list.
Also add `msc` to the list of extensions that can be executed natively
Includes a project test and a unit test for this and all expected
behaviours on Windows.
Diffstat (limited to 'mesonbuild')
-rw-r--r-- | mesonbuild/dependencies.py | 50 |
1 files changed, 38 insertions, 12 deletions
diff --git a/mesonbuild/dependencies.py b/mesonbuild/dependencies.py index 9525ffa..920a279 100644 --- a/mesonbuild/dependencies.py +++ b/mesonbuild/dependencies.py @@ -402,7 +402,7 @@ class WxDependency(Dependency): return self.is_found class ExternalProgram: - windows_exts = ('exe', 'com', 'bat') + windows_exts = ('exe', 'msc', 'com', 'bat') def __init__(self, name, fullpath=None, silent=False, search_dir=None): self.name = name @@ -420,6 +420,10 @@ class ExternalProgram: else: mlog.log('Program', mlog.bold(name), 'found:', mlog.red('NO')) + def __repr__(self): + r = '<{} {!r} -> {!r}>' + return r.format(self.__class__.__name__, self.name, self.fullpath) + @staticmethod def _shebang_to_cmd(script): """ @@ -473,27 +477,49 @@ class ExternalProgram: return self._shebang_to_cmd(trial) def _search(self, name, search_dir): + ''' + Search in the specified dir for the specified executable by name + and if not found search in PATH + ''' 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(): + if not mesonlib.is_windows(): # On UNIX-like platforms, the standard PATH search is enough return [fullpath] - # On Windows, if name is an absolute path, we need the extension too - for ext in self.windows_exts: - fullpath = '{}.{}'.format(name, ext) - if os.path.exists(fullpath): + # HERE BEGINS THE TERROR OF WINDOWS + if fullpath: + # On Windows, even if the PATH search returned a full path, we can't be + # sure that it can be run directly if it's not a native executable. + # For instance, interpreted scripts sometimes need to be run explicitly + # with an interpreter if the file association is not done properly. + name_ext = os.path.splitext(fullpath)[1] + if name_ext[1:].lower() in self.windows_exts: + # Good, it can be directly executed 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) + # Try to extract the interpreter from the shebang + commands = self._shebang_to_cmd(fullpath) if commands: return commands + else: + # Maybe the name is an absolute path to a native Windows + # executable, but without the extension. This is technically wrong, + # but many people do it because it works in the MinGW shell. + if os.path.isabs(name): + for ext in self.windows_exts: + fullpath = '{}.{}'.format(name, ext) + if os.path.exists(fullpath): + 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): |