diff options
Diffstat (limited to 'mesonbuild')
-rw-r--r-- | mesonbuild/coredata.py | 2 | ||||
-rw-r--r-- | mesonbuild/dependencies/base.py | 53 | ||||
-rw-r--r-- | mesonbuild/environment.py | 10 | ||||
-rw-r--r-- | mesonbuild/interpreter.py | 6 | ||||
-rw-r--r-- | mesonbuild/modules/fs.py | 100 | ||||
-rw-r--r-- | mesonbuild/scripts/commandrunner.py | 7 |
6 files changed, 104 insertions, 74 deletions
diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py index 05cde4d..a5898f1 100644 --- a/mesonbuild/coredata.py +++ b/mesonbuild/coredata.py @@ -776,7 +776,7 @@ class CmdLineFileParser(configparser.ConfigParser): def __init__(self): # We don't want ':' as key delimiter, otherwise it would break when # storing subproject options like "subproject:option=value" - super().__init__(delimiters=['=']) + super().__init__(delimiters=['='], interpolation=None) def get_cmd_line_file(build_dir): return os.path.join(build_dir, 'meson-private', 'cmd_line.txt') diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py index b190414..1666e0c 100644 --- a/mesonbuild/dependencies/base.py +++ b/mesonbuild/dependencies/base.py @@ -33,7 +33,6 @@ from .. import mesonlib from ..compilers import clib_langs from ..environment import BinaryTable, Environment, MachineInfo from ..cmake import CMakeExecutor, CMakeTraceParser, CMakeException -from ..linkers import GnuLikeDynamicLinkerMixin from ..mesonlib import MachineChoice, MesonException, OrderedSet, PerMachine from ..mesonlib import Popen_safe, version_compare_many, version_compare, listify, stringlistify, extract_as_list, split_args from ..mesonlib import Version, LibType @@ -748,18 +747,16 @@ class PkgConfigDependency(ExternalDependency): (self.name, err)) self.compile_args = self._convert_mingw_paths(self._split_args(out)) - def _search_libs(self, out, out_raw, out_all): + def _search_libs(self, out, out_raw): ''' @out: PKG_CONFIG_ALLOW_SYSTEM_LIBS=1 pkg-config --libs @out_raw: pkg-config --libs - @out_all: pkg-config --libs --static We always look for the file ourselves instead of depending on the compiler to find it with -lfoo or foo.lib (if possible) because: 1. We want to be able to select static or shared 2. We need the full path of the library to calculate RPATH values 3. De-dup of libraries is easier when we have absolute paths - 4. We need to find the directories in which secondary dependencies reside Libraries that are provided by the toolchain or are not found by find_library() will be added with -L -l pairs. @@ -793,18 +790,6 @@ class PkgConfigDependency(ExternalDependency): continue if arg.startswith('-L') and arg[2:] not in prefix_libpaths: system_libpaths.add(arg[2:]) - # collect all secondary library paths - secondary_libpaths = OrderedSet() - all_args = self._convert_mingw_paths(shlex.split(out_all)) - for arg in all_args: - if arg.startswith('-L') and not arg.startswith(('-L-l', '-L-L')): - path = arg[2:] - if not os.path.isabs(path): - # Resolve the path as a compiler in the build directory would - path = os.path.join(self.env.get_build_dir(), path) - if path not in prefix_libpaths and path not in system_libpaths: - secondary_libpaths.add(path) - # Use this re-ordered path list for library resolution libpaths = list(prefix_libpaths) + list(system_libpaths) # Track -lfoo libraries to avoid duplicate work @@ -812,12 +797,8 @@ class PkgConfigDependency(ExternalDependency): # Track not-found libraries to know whether to add library paths libs_notfound = [] libtype = LibType.STATIC if self.static else LibType.PREFER_SHARED - # Generate link arguments for this library, by - # first appending secondary link arguments for ld + # Generate link arguments for this library link_args = [] - if self.clib_compiler and self.clib_compiler.linker and isinstance(self.clib_compiler.linker, GnuLikeDynamicLinkerMixin): - link_args = ['-Wl,-rpath-link,' + p for p in secondary_libpaths] - for lib in full_args: if lib.startswith(('-L-l', '-L-L')): # These are D language arguments, add them as-is @@ -887,26 +868,6 @@ class PkgConfigDependency(ExternalDependency): libcmd = [self.name, '--libs'] if self.static: libcmd.append('--static') - # We need to find *all* secondary dependencies of a library - # - # Say we have libA.so, located in /non/standard/dir1/, and - # libB.so, located in /non/standard/dir2/, which links to - # libA.so. Now when linking exeC to libB.so, the linker will - # walk the complete symbol tree to determine that all undefined - # symbols can be resolved. Because libA.so lives in a directory - # not known to the linker by default, you will get errors like - # - # ld: warning: libA.so, needed by /non/standard/dir2/libB.so, - # not found (try using -rpath or -rpath-link) - # ld: /non/standard/dir2/libB.so: undefined reference to `foo()' - # - # To solve this, we load the -L paths of *all* dependencies, by - # relying on --static to provide us with a complete picture. All - # -L paths that are found via a --static lookup but that are not - # contained in the normal lookup have to originate from secondary - # dependencies. See also: - # http://www.kaizou.org/2015/01/linux-libraries/ - libcmd_all = [self.name, '--libs', '--static'] # Force pkg-config to output -L fields even if they are system # paths so we can do manual searching with cc.find_library() later. env = os.environ.copy() @@ -920,13 +881,9 @@ class PkgConfigDependency(ExternalDependency): # gnome.generate_gir + gnome.gtkdoc which need -L -l arguments. ret, out_raw, err_raw = self._call_pkgbin(libcmd) if ret != 0: - raise DependencyException('Could not generate libs for %s:\n%s\n' % - (self.name, err_raw)) - ret, out_all, err_all = self._call_pkgbin(libcmd_all) - if ret != 0: - mlog.warning('Could not determine complete list of dependencies for %s:\n%s\n' % - (self.name, err_all)) - self.link_args, self.raw_link_args = self._search_libs(out, out_raw, out_all) + raise DependencyException('Could not generate libs for %s:\n\n%s' % + (self.name, out_raw)) + self.link_args, self.raw_link_args = self._search_libs(out, out_raw) def get_pkgconfig_variable(self, variable_name, kwargs): options = ['--variable=' + variable_name, self.name] diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py index 072e7c3..f53f17f 100644 --- a/mesonbuild/environment.py +++ b/mesonbuild/environment.py @@ -835,6 +835,8 @@ class Environment: for compiler in compilers: if isinstance(compiler, str): compiler = [compiler] + compiler_name = os.path.basename(compiler[0]) + if not set(['cl', 'cl.exe', 'clang-cl', 'clang-cl.exe']).isdisjoint(compiler): # Watcom C provides it's own cl.exe clone that mimics an older # version of Microsoft's compiler. Since Watcom's cl.exe is @@ -855,11 +857,11 @@ class Environment: if found_cl in watcom_cls: continue arg = '/?' - elif 'armcc' in compiler[0]: + elif 'armcc' in compiler_name: arg = '--vsn' - elif 'ccrx' in compiler[0]: + elif 'ccrx' in compiler_name: arg = '-v' - elif 'icl' in compiler[0]: + elif 'icl' in compiler_name: # if you pass anything to icl you get stuck in a pager arg = '' else: @@ -871,7 +873,7 @@ class Environment: popen_exceptions[' '.join(compiler + [arg])] = e continue - if 'ccrx' in compiler[0]: + if 'ccrx' in compiler_name: out = err full_version = out.split('\n', 1)[0] diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index 72370ed..3179fb4 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -2382,6 +2382,7 @@ external dependencies (including libraries) must go to "dependencies".''') m = 'must be a string, or the output of find_program(), files() '\ 'or configure_file(), or a compiler object; not {!r}' + expanded_args = [] if isinstance(cmd, ExternalProgramHolder): cmd = cmd.held_object if isinstance(cmd, build.Executable): @@ -2392,12 +2393,14 @@ external dependencies (including libraries) must go to "dependencies".''') if not cmd.found(): raise InterpreterException('command {!r} not found or not executable'.format(cmd)) elif isinstance(cmd, CompilerHolder): - cmd = cmd.compiler.get_exelist()[0] + exelist = cmd.compiler.get_exelist() + cmd = exelist[0] prog = ExternalProgram(cmd, silent=True) if not prog.found(): raise InterpreterException('Program {!r} not found ' 'or not executable'.format(cmd)) cmd = prog + expanded_args = exelist[1:] else: if isinstance(cmd, mesonlib.File): cmd = cmd.absolute_path(srcdir, builddir) @@ -2417,7 +2420,6 @@ external dependencies (including libraries) must go to "dependencies".''') if not os.path.isabs(cmd_path): if cmd_path not in self.build_def_files: self.build_def_files.append(cmd_path) - expanded_args = [] for a in listify(cargs): if isinstance(a, str): expanded_args.append(a) diff --git a/mesonbuild/modules/fs.py b/mesonbuild/modules/fs.py index 61ad917..86861ae 100644 --- a/mesonbuild/modules/fs.py +++ b/mesonbuild/modules/fs.py @@ -12,13 +12,18 @@ # See the License for the specific language governing permissions and # limitations under the License. -import os +import typing +import hashlib +from pathlib import Path, PurePath +from .. import mlog from . import ExtensionModule from . import ModuleReturnValue from ..mesonlib import MesonException from ..interpreterbase import stringArgs, noKwargs +if typing.TYPE_CHECKING: + from ..interpreter import ModuleState class FSModule(ExtensionModule): @@ -26,34 +31,93 @@ class FSModule(ExtensionModule): super().__init__(interpreter) self.snippets.add('generate_dub_file') + def _resolve_dir(self, state: 'ModuleState', arg: str) -> Path: + """ + resolves (makes absolute) a directory relative to calling meson.build, + if not already absolute + """ + return Path(state.source_root) / state.subdir / Path(arg).expanduser() + + def _check(self, check: str, state: 'ModuleState', args: typing.Sequence[str]) -> ModuleReturnValue: + if len(args) != 1: + MesonException('fs.{} takes exactly one argument.'.format(check)) + test_file = self._resolve_dir(state, args[0]) + return ModuleReturnValue(getattr(test_file, check)(), []) + @stringArgs @noKwargs - def exists(self, state, args, kwargs): - if len(args) != 1: - MesonException('method takes exactly one argument.') - test_file = os.path.join(state.source_root, state.subdir, args[0]) - return ModuleReturnValue(os.path.exists(test_file), []) + def exists(self, state: 'ModuleState', args: typing.Sequence[str], kwargs: dict) -> ModuleReturnValue: + return self._check('exists', state, args) - def _check(self, check_fun, state, args): - if len(args) != 1: - MesonException('method takes exactly one argument.') - test_file = os.path.join(state.source_root, state.subdir, args[0]) - return ModuleReturnValue(check_fun(test_file), []) + @stringArgs + @noKwargs + def is_symlink(self, state: 'ModuleState', args: typing.Sequence[str], kwargs: dict) -> ModuleReturnValue: + return self._check('is_symlink', state, args) @stringArgs @noKwargs - def is_symlink(self, state, args, kwargs): - return self._check(os.path.islink, state, args) + def is_file(self, state: 'ModuleState', args: typing.Sequence[str], kwargs: dict) -> ModuleReturnValue: + return self._check('is_file', state, args) @stringArgs @noKwargs - def is_file(self, state, args, kwargs): - return self._check(os.path.isfile, state, args) + def is_dir(self, state: 'ModuleState', args: typing.Sequence[str], kwargs: dict) -> ModuleReturnValue: + return self._check('is_dir', state, args) @stringArgs @noKwargs - def is_dir(self, state, args, kwargs): - return self._check(os.path.isdir, state, args) + def hash(self, state: 'ModuleState', args: typing.Sequence[str], kwargs: dict) -> ModuleReturnValue: + if len(args) != 2: + MesonException('method takes exactly two arguments.') + file = self._resolve_dir(state, args[0]) + if not file.is_file(): + raise MesonException('{} is not a file and therefore cannot be hashed'.format(file)) + try: + h = hashlib.new(args[1]) + except ValueError: + raise MesonException('hash algorithm {} is not available'.format(args[1])) + mlog.debug('computing {} sum of {} size {} bytes'.format(args[1], file, file.stat().st_size)) + h.update(file.read_bytes()) + return ModuleReturnValue(h.hexdigest(), []) + + @stringArgs + @noKwargs + def size(self, state: 'ModuleState', args: typing.Sequence[str], kwargs: dict) -> ModuleReturnValue: + if len(args) != 1: + MesonException('method takes exactly one argument.') + file = self._resolve_dir(state, args[0]) + if not file.is_file(): + raise MesonException('{} is not a file and therefore cannot be sized'.format(file)) + try: + return ModuleReturnValue(file.stat().st_size, []) + except ValueError: + raise MesonException('{} size could not be determined'.format(args[0])) + + @stringArgs + @noKwargs + def samefile(self, state: 'ModuleState', args: typing.Sequence[str], kwargs: dict) -> ModuleReturnValue: + if len(args) != 2: + MesonException('method takes exactly two arguments.') + file1 = self._resolve_dir(state, args[0]) + file2 = self._resolve_dir(state, args[1]) + if not file1.exists(): + raise MesonException('{} is not a file, symlink or directory and therefore cannot be compared'.format(file1)) + if not file2.exists(): + raise MesonException('{} is not a file, symlink or directory and therefore cannot be compared'.format(file2)) + try: + return ModuleReturnValue(file1.samefile(file2), []) + except OSError: + raise MesonException('{} could not be compared to {}'.format(file1, file2)) + + @stringArgs + @noKwargs + def replace_suffix(self, state: 'ModuleState', args: typing.Sequence[str], kwargs: dict) -> ModuleReturnValue: + if len(args) != 2: + MesonException('method takes exactly two arguments.') + original = PurePath(args[0]) + new = original.with_suffix(args[1]) + return ModuleReturnValue(str(new), []) + -def initialize(*args, **kwargs): +def initialize(*args, **kwargs) -> FSModule: return FSModule(*args, **kwargs) diff --git a/mesonbuild/scripts/commandrunner.py b/mesonbuild/scripts/commandrunner.py index 3807114..22da417 100644 --- a/mesonbuild/scripts/commandrunner.py +++ b/mesonbuild/scripts/commandrunner.py @@ -71,7 +71,12 @@ def run(args): command = args[4] arguments = args[5:] pc = run_command(src_dir, build_dir, subdir, meson_command, command, arguments) - pc.wait() + while True: + try: + pc.wait() + break + except KeyboardInterrupt: + pass return pc.returncode if __name__ == '__main__': |