aboutsummaryrefslogtreecommitdiff
path: root/mesonbuild
diff options
context:
space:
mode:
Diffstat (limited to 'mesonbuild')
-rw-r--r--mesonbuild/coredata.py2
-rw-r--r--mesonbuild/dependencies/base.py53
-rw-r--r--mesonbuild/environment.py10
-rw-r--r--mesonbuild/interpreter.py6
-rw-r--r--mesonbuild/modules/fs.py100
-rw-r--r--mesonbuild/scripts/commandrunner.py7
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__':