diff options
-rw-r--r-- | mesonbuild/backend/backends.py | 2 | ||||
-rw-r--r-- | mesonbuild/backend/ninjabackend.py | 10 | ||||
-rw-r--r-- | mesonbuild/backend/vs2010backend.py | 2 | ||||
-rw-r--r-- | mesonbuild/backend/xcodebackend.py | 2 | ||||
-rw-r--r-- | mesonbuild/build.py | 8 | ||||
-rw-r--r-- | mesonbuild/compilers.py | 2 | ||||
-rw-r--r-- | mesonbuild/coredata.py | 119 | ||||
-rw-r--r-- | mesonbuild/dependencies.py | 2 | ||||
-rw-r--r-- | mesonbuild/environment.py | 8 | ||||
-rw-r--r-- | mesonbuild/interpreter.py | 11 | ||||
-rw-r--r-- | mesonbuild/mconf.py | 48 | ||||
-rw-r--r-- | mesonbuild/mesonlib.py | 7 | ||||
-rw-r--r-- | mesonbuild/mesonmain.py | 72 | ||||
-rw-r--r-- | mesonbuild/modules/gnome.py | 2 | ||||
-rw-r--r-- | mesonbuild/modules/pkgconfig.py | 12 | ||||
-rw-r--r-- | mesonbuild/modules/qt4.py | 2 | ||||
-rw-r--r-- | mesonbuild/modules/qt5.py | 2 | ||||
-rw-r--r-- | mesonbuild/modules/windows.py | 2 | ||||
-rw-r--r-- | mesonbuild/mparser.py | 2 | ||||
-rw-r--r-- | mesonbuild/optinterpreter.py | 7 | ||||
-rw-r--r-- | mesonbuild/scripts/meson_benchmark.py | 3 | ||||
-rw-r--r-- | mesonbuild/scripts/meson_test.py | 108 |
22 files changed, 235 insertions, 198 deletions
diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py index c9d6197..ceb466b 100644 --- a/mesonbuild/backend/backends.py +++ b/mesonbuild/backend/backends.py @@ -18,7 +18,7 @@ from .. import dependencies from .. import mesonlib import json import subprocess -from ..coredata import MesonException +from ..mesonlib import MesonException class InstallData(): def __init__(self, source_dir, build_dir, prefix): diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index 5263d86..d53730a 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -18,10 +18,9 @@ from .. import build from .. import mlog from .. import dependencies from .. import compilers -from ..mesonlib import File +from ..mesonlib import File, MesonException from .backends import InstallData from ..build import InvalidArguments -from ..coredata import MesonException import os, sys, pickle, re import subprocess, shutil @@ -586,7 +585,12 @@ int dummy; valgrind = environment.find_valgrind() script_root = self.environment.get_script_dir() test_data = os.path.join(self.environment.get_scratch_dir(), 'meson_test_setup.dat') - cmd = [sys.executable, self.environment.get_build_command(), '--internal', 'test', test_data] + cmd = [ sys.executable, self.environment.get_build_command(), '--internal', 'test' ] + if not self.environment.coredata.get_builtin_option('stdsplit'): + cmd += ['--no-stdsplit'] + if self.environment.coredata.get_builtin_option('errorlogs'): + cmd += ['--print-errorlogs'] + cmd += [ test_data ] elem = NinjaBuildElement(self.all_outputs, 'test', 'CUSTOM_COMMAND', ['all', 'PHONY']) elem.add_item('COMMAND', cmd) elem.add_item('DESC', 'Running all tests.') diff --git a/mesonbuild/backend/vs2010backend.py b/mesonbuild/backend/vs2010backend.py index 36b7d57..725b8ed 100644 --- a/mesonbuild/backend/vs2010backend.py +++ b/mesonbuild/backend/vs2010backend.py @@ -25,7 +25,7 @@ from .. import dependencies from .. import mlog import xml.etree.ElementTree as ET import xml.dom.minidom -from ..coredata import MesonException +from ..mesonlib import MesonException from ..environment import Environment class RegenInfo(): diff --git a/mesonbuild/backend/xcodebackend.py b/mesonbuild/backend/xcodebackend.py index eb8b0b9..6bda826 100644 --- a/mesonbuild/backend/xcodebackend.py +++ b/mesonbuild/backend/xcodebackend.py @@ -17,7 +17,7 @@ from .. import build from .. import mesonlib import uuid, os, sys -from ..coredata import MesonException +from ..mesonlib import MesonException class XCodeBackend(backends.Backend): def __init__(self, build): diff --git a/mesonbuild/build.py b/mesonbuild/build.py index 2a91aa3..63cdcf3 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -17,7 +17,7 @@ from . import environment from . import dependencies from . import mlog import copy, os -from .mesonlib import File, flatten +from .mesonlib import File, flatten, MesonException known_basic_kwargs = {'install' : True, 'c_pch' : True, @@ -71,7 +71,7 @@ We are fully aware that these are not really usable or pleasant ways to do this but it's the best we can do given the way shell quoting works. ''' -class InvalidArguments(coredata.MesonException): +class InvalidArguments(MesonException): pass class Build: @@ -299,10 +299,10 @@ class BuildTarget(): srclist = [srclist] for src in srclist: if not isinstance(src, str): - raise coredata.MesonException('Extraction arguments must be strings.') + raise MesonException('Extraction arguments must be strings.') src = File(False, self.subdir, src) if src not in self.sources: - raise coredata.MesonException('Tried to extract unknown source %s.' % src) + raise MesonException('Tried to extract unknown source %s.' % src) obj_src.append(src) return ExtractedObjects(self, obj_src) diff --git a/mesonbuild/compilers.py b/mesonbuild/compilers.py index 880113d..4f55be4 100644 --- a/mesonbuild/compilers.py +++ b/mesonbuild/compilers.py @@ -16,7 +16,7 @@ import subprocess, os.path import tempfile from .import mesonlib from . import mlog -from .coredata import MesonException +from .mesonlib import MesonException from . import coredata """This file contains the data files of all compilers Meson knows diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py index d085532..ff45db5 100644 --- a/mesonbuild/coredata.py +++ b/mesonbuild/coredata.py @@ -13,36 +13,10 @@ # limitations under the License. import pickle, os, uuid +from .mesonlib import MesonException, default_libdir, default_libexecdir, default_prefix version = '0.31.0.dev1' -build_types = ['plain', 'debug', 'debugoptimized', 'release'] -layouts = ['mirror', 'flat'] -warning_levels = ['1', '2', '3'] -libtypelist = ['shared', 'static'] - -builtin_options = {'buildtype': True, - 'strip': True, - 'coverage': True, - 'unity': True, - 'prefix': True, - 'libdir' : True, - 'libexecdir' : True, - 'bindir' : True, - 'includedir' : True, - 'datadir' : True, - 'mandir' : True, - 'localedir' : True, - 'werror' : True, - 'warning_level': True, - 'layout' : True, - 'default_library': True, - } - -class MesonException(Exception): - def __init__(self, *args, **kwargs): - Exception.__init__(self, *args, **kwargs) - class UserOption: def __init__(self, name, description, choices): super().__init__() @@ -73,7 +47,7 @@ class UserStringOption(UserOption): class UserBooleanOption(UserOption): def __init__(self, name, description, value): - super().__init__(name, description, '[true, false]') + super().__init__(name, description, [ True, False ]) self.set_value(value) def tobool(self, thing): @@ -140,7 +114,6 @@ class CoreData(): self.regen_guid = str(uuid.uuid4()).upper() self.target_guids = {} self.version = version - self.builtin_options = {} self.init_builtins(options) self.user_options = {} self.compiler_options = {} @@ -158,36 +131,21 @@ class CoreData(): self.modules = {} def init_builtins(self, options): - self.builtin_options['prefix'] = UserStringOption('prefix', 'Installation prefix', options.prefix) - self.builtin_options['libdir'] = UserStringOption('libdir', 'Library dir', options.libdir) - self.builtin_options['libexecdir'] = UserStringOption('libexecdir', 'Library executables dir', options.libexecdir) - self.builtin_options['bindir'] = UserStringOption('bindir', 'Executable dir', options.bindir) - self.builtin_options['includedir'] = UserStringOption('includedir', 'Include dir', options.includedir) - self.builtin_options['datadir'] = UserStringOption('datadir', 'Data directory', options.datadir) - self.builtin_options['mandir'] = UserStringOption('mandir', 'Man page dir', options.mandir) - self.builtin_options['localedir'] = UserStringOption('localedir', 'Locale dir', options.localedir) - self.builtin_options['backend'] = UserStringOption('backend', 'Backend to use', options.backend) - self.builtin_options['buildtype'] = UserComboOption('buildtype', 'Build type', build_types, options.buildtype) - self.builtin_options['strip'] = UserBooleanOption('strip', 'Strip on install', options.strip) - self.builtin_options['unity'] = UserBooleanOption('unity', 'Unity build', options.unity) - self.builtin_options['warning_level'] = UserComboOption('warning_level', 'Warning level', warning_levels, options.warning_level) - self.builtin_options['werror'] = UserBooleanOption('werror', 'Warnings are errors', options.werror) - self.builtin_options['layout'] = UserComboOption('layout', 'Build dir layout', layouts, options.layout) - self.builtin_options['default_library'] = UserComboOption('default_library', 'Default_library type', libtypelist, options.default_library) + self.builtins = {} + for key in get_builtin_options(): + args = [key] + builtin_options[key][1:-1] + [ getattr(options, key, get_builtin_option_default(key)) ] + self.builtins[key] = builtin_options[key][0](*args) def get_builtin_option(self, optname): - if optname in self.builtin_options: - return self.builtin_options[optname].value - raise RuntimeError('Tried to get unknown builtin option %s' % optname) + if optname in self.builtins: + return self.builtins[optname].value + raise RuntimeError('Tried to get unknown builtin option %s.' % optname) def set_builtin_option(self, optname, value): - if optname in self.builtin_options: - self.builtin_options[optname].set_value(value) + if optname in self.builtins: + self.builtins[optname].set_value(value) else: - raise RuntimeError('Tried to set unknown builtin option %s' % optname) - - def is_builtin_option(self, optname): - return optname in self.builtin_options + raise RuntimeError('Tried to set unknown builtin option %s.' % optname) def load(filename): obj = pickle.load(open(filename, 'rb')) @@ -203,6 +161,59 @@ def save(obj, filename): raise RuntimeError('Fatal version mismatch corruption.') pickle.dump(obj, open(filename, 'wb')) +def get_builtin_options(): + return list(builtin_options.keys()) + +def is_builtin_option(optname): + return optname in get_builtin_options() + +def get_builtin_option_choices(optname): + if is_builtin_option(optname): + if builtin_options[optname][0] == UserStringOption: + return None + elif builtin_options[optname][0] == UserBooleanOption: + return [ True, False ] + else: + return builtin_options[optname][2] + else: + raise RuntimeError('Tried to get the supported values for an unknown builtin option \'%s\'.' % optname) + +def get_builtin_option_description(optname): + if is_builtin_option(optname): + return builtin_options[optname][1] + else: + raise RuntimeError('Tried to get the description for an unknown builtin option \'%s\'.' % optname) + +def get_builtin_option_default(optname): + if is_builtin_option(optname): + o = builtin_options[optname] + if o[0] == UserComboOption: + return o[3] + return o[2] + else: + raise RuntimeError('Tried to get the default value for an unknown builtin option \'%s\'.' % optname) + +builtin_options = { + 'buildtype' : [ UserComboOption, 'Build type to use.', [ 'plain', 'debug', 'debugoptimized', 'release' ], 'debug' ], + 'strip' : [ UserBooleanOption, 'Strip targets on install.', False ], + 'unity' : [ UserBooleanOption, 'Unity build.', False ], + 'prefix' : [ UserStringOption, 'Installation prefix.', default_prefix() ], + 'libdir' : [ UserStringOption, 'Library directory.', default_libdir() ], + 'libexecdir' : [ UserStringOption, 'Library executable directory.', default_libexecdir() ], + 'bindir' : [ UserStringOption, 'Executable directory.', 'bin' ], + 'includedir' : [ UserStringOption, 'Header file directory.', 'include' ], + 'datadir' : [ UserStringOption, 'Data file directory.', 'share' ], + 'mandir' : [ UserStringOption, 'Manual page directory.', 'share/man' ], + 'localedir' : [ UserStringOption, 'Locale data directory.', 'share/locale' ], + 'werror' : [ UserBooleanOption, 'Treat warnings as errors.', False ], + 'warning_level' : [ UserComboOption, 'Compiler warning level to use.', [ '1', '2', '3' ], '1'], + 'layout' : [ UserComboOption, 'Build directory layout.', ['mirror', 'flat' ], 'mirror' ], + 'default_library' : [ UserComboOption, 'Default library type.', [ 'shared', 'static' ], 'shared' ], + 'backend' : [ UserComboOption, 'Backend to use.', [ 'ninja', 'vs2010', 'xcode' ], 'ninja' ], + 'stdsplit' : [ UserBooleanOption, 'Split stdout and stderr in test logs.', True ], + 'errorlogs' : [ UserBooleanOption, "Whether to print the logs from failing tests.", False ], + } + forbidden_target_names = {'clean': None, 'clean-gcno': None, 'clean-gcda': None, diff --git a/mesonbuild/dependencies.py b/mesonbuild/dependencies.py index b9f5c89..d8081b0 100644 --- a/mesonbuild/dependencies.py +++ b/mesonbuild/dependencies.py @@ -22,7 +22,7 @@ import re import os, stat, glob, subprocess, shutil import sysconfig -from . coredata import MesonException +from . mesonlib import MesonException from . import mlog from . import mesonlib diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py index df848f8..6ff93cb 100644 --- a/mesonbuild/environment.py +++ b/mesonbuild/environment.py @@ -19,7 +19,7 @@ import configparser build_filename = 'meson.build' -class EnvironmentException(coredata.MesonException): +class EnvironmentException(mesonlib.MesonException): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -657,11 +657,11 @@ class CrossBuildInfo(): if 'target_machine' in self.config: return if not 'host_machine' in self.config: - raise coredata.MesonException('Cross info file must have either host or a target machine.') + raise mesonlib.MesonException('Cross info file must have either host or a target machine.') if not 'properties' in self.config: - raise coredata.MesonException('Cross file is missing "properties".') + raise mesonlib.MesonException('Cross file is missing "properties".') if not 'binaries' in self.config: - raise coredata.MesonException('Cross file is missing "binaries".') + raise mesonlib.MesonException('Cross file is missing "binaries".') def ok_type(self, i): return isinstance(i, str) or isinstance(i, int) or isinstance(i, bool) diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index 90a0a13..0a88ce4 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -28,7 +28,7 @@ from functools import wraps import importlib -class InterpreterException(coredata.MesonException): +class InterpreterException(mesonlib.MesonException): pass class InvalidCode(InterpreterException): @@ -932,7 +932,7 @@ class Interpreter(): assert(isinstance(code, str)) try: self.ast = mparser.Parser(code).parse() - except coredata.MesonException as me: + except mesonlib.MesonException as me: me.file = environment.build_filename raise me self.sanity_check_ast() @@ -1341,7 +1341,7 @@ class Interpreter(): return self.environment.coredata.compiler_options[optname].value except KeyError: pass - if optname not in coredata.builtin_options and self.is_subproject(): + if not coredata.is_builtin_option(optname) and self.is_subproject(): optname = self.subproject + ':' + optname try: return self.environment.coredata.user_options[optname].value @@ -1364,8 +1364,7 @@ class Interpreter(): if '=' not in option: raise InterpreterException('All default options must be of type key=value.') key, value = option.split('=', 1) - builtin_options = self.coredata.builtin_options - if key in builtin_options: + if coredata.is_builtin_option(key): if not self.environment.had_argument_for(key): self.coredata.set_builtin_option(key, value) # If this was set on the command line, do not override. @@ -1801,7 +1800,7 @@ class Interpreter(): assert(isinstance(code, str)) try: codeblock = mparser.Parser(code).parse() - except coredata.MesonException as me: + except mesonlib.MesonException as me: me.file = buildfilename raise me self.evaluate_codeblock(codeblock) diff --git a/mesonbuild/mconf.py b/mesonbuild/mconf.py index c8ea494..3d38712 100644 --- a/mesonbuild/mconf.py +++ b/mesonbuild/mconf.py @@ -18,7 +18,6 @@ import sys, os import pickle import argparse from . import coredata, mesonlib -from .coredata import build_types, warning_levels, libtypelist parser = argparse.ArgumentParser() @@ -26,7 +25,7 @@ parser.add_argument('-D', action='append', default=[], dest='sets', help='Set an option to the given value.') parser.add_argument('directory', nargs='*') -class ConfException(coredata.MesonException): +class ConfException(mesonlib.MesonException): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -62,7 +61,8 @@ class Conf: longest_name = max(longest_name, len(x[0])) longest_descr = max(longest_descr, len(x[1])) longest_value = max(longest_value, len(str(x[2]))) - longest_possible_value = max(longest_possible_value, len(x[3])) + if x[3]: + longest_possible_value = max(longest_possible_value, len(x[3])) if longest_possible_value > 0: titles[3] = 'Possible Values' @@ -71,10 +71,14 @@ class Conf: for i in arr: name = i[0] descr = i[1] - value = i[2] - if isinstance(value, bool): - value = 'true' if value else 'false' - possible_values = i[3] + value = i[2] if isinstance(i[2], str) else str(i[2]).lower() + possible_values = '' + if isinstance(i[3], list): + if len(i[3]) > 0: + i[3] = [s if isinstance(s, str) else str(s).lower() for s in i[3]] + possible_values = '[%s]' % ', '.join(map(str, i[3])) + elif i[3]: + possible_values = i[3] if isinstance(i[3], str) else str(i[3]).lower() namepad = ' '*(longest_name - len(name)) descrpad = ' '*(longest_descr - len(descr)) valuepad = ' '*(longest_value - len(str(value))) @@ -86,7 +90,7 @@ class Conf: if '=' not in o: raise ConfException('Value "%s" not of type "a=b".' % o) (k, v) = o.split('=', 1) - if self.coredata.is_builtin_option(k): + if coredata.is_builtin_option(k): self.coredata.set_builtin_option(k, v) elif k in self.coredata.user_options: tgt = self.coredata.user_options[k] @@ -123,13 +127,9 @@ class Conf: print('') print('Core options:') carr = [] - booleans = '[true, false]' - carr.append(['buildtype', 'Build type', self.coredata.get_builtin_option('buildtype'), build_types]) - carr.append(['warning_level', 'Warning level', self.coredata.get_builtin_option('warning_level'), warning_levels]) - carr.append(['werror', 'Treat warnings as errors', self.coredata.get_builtin_option('werror'), booleans]) - carr.append(['strip', 'Strip on install', self.coredata.get_builtin_option('strip'), booleans]) - carr.append(['unity', 'Unity build', self.coredata.get_builtin_option('unity'), booleans]) - carr.append(['default_library', 'Default library type', self.coredata.get_builtin_option('default_library'), libtypelist]) + for key in [ 'buildtype', 'warning_level', 'werror', 'strip', 'unity', 'default_library' ]: + carr.append([key, coredata.get_builtin_option_description(key), + self.coredata.get_builtin_option(key), coredata.get_builtin_option_choices(key)]) self.print_aligned(carr) print('') print('Base options:') @@ -164,14 +164,9 @@ class Conf: print('') print('Directories:') parr = [] - parr.append(['prefix', 'Install prefix', self.coredata.get_builtin_option('prefix'), '']) - parr.append(['libdir', 'Library directory', self.coredata.get_builtin_option('libdir'), '']) - parr.append(['libexecdir', 'Library executables directory', self.coredata.get_builtin_option('libexecdir'), '']) - parr.append(['bindir', 'Binary directory', self.coredata.get_builtin_option('bindir'), '']) - parr.append(['includedir', 'Header directory', self.coredata.get_builtin_option('includedir'), '']) - parr.append(['datadir', 'Data directory', self.coredata.get_builtin_option('datadir'), '']) - parr.append(['mandir', 'Man page directory', self.coredata.get_builtin_option('mandir'), '']) - parr.append(['localedir', 'Locale file directory', self.coredata.get_builtin_option('localedir'), '']) + for key in [ 'prefix', 'libdir', 'libexecdir', 'bindir', 'includedir', 'datadir', 'mandir', 'localedir' ]: + parr.append([key, coredata.get_builtin_option_description(key), + self.coredata.get_builtin_option(key), coredata.get_builtin_option_choices(key)]) self.print_aligned(parr) print('') print('Project options:') @@ -192,6 +187,13 @@ class Conf: choices = str(opt.choices); optarr.append([key, opt.description, opt.value, choices]) self.print_aligned(optarr) + print('') + print('Testing options:') + tarr = [] + for key in [ 'stdsplit', 'errorlogs' ]: + tarr.append([key, coredata.get_builtin_option_description(key), + self.coredata.get_builtin_option(key), coredata.get_builtin_option_choices(key)]) + self.print_aligned(tarr) def run(args): args = mesonlib.expand_arguments(args) diff --git a/mesonbuild/mesonlib.py b/mesonbuild/mesonlib.py index 2087eee..2ac0932 100644 --- a/mesonbuild/mesonlib.py +++ b/mesonbuild/mesonlib.py @@ -18,7 +18,9 @@ import platform, subprocess, operator, os, shutil, re, sys from glob import glob -from .coredata import MesonException +class MesonException(Exception): + def __init__(self, *args, **kwargs): + Exception.__init__(self, *args, **kwargs) class File: def __init__(self, is_built, subdir, fname): @@ -177,6 +179,9 @@ def default_libexecdir(): # There is no way to auto-detect this, so it must be set at build time return 'libexec' +def default_prefix(): + return 'c:/' if is_windows() else '/usr/local' + def get_library_dirs(): if is_windows(): return ['C:/mingw/lib'] # Fixme diff --git a/mesonbuild/mesonmain.py b/mesonbuild/mesonmain.py index 22b52e3..3b05afb 100644 --- a/mesonbuild/mesonmain.py +++ b/mesonbuild/mesonmain.py @@ -21,8 +21,7 @@ from . import environment, interpreter, mesonlib from . import build import platform from . import mlog, coredata - -from .coredata import MesonException, build_types, layouts, warning_levels, libtypelist +from .mesonlib import MesonException backendlist = ['ninja', 'vs2010', 'xcode'] @@ -30,49 +29,40 @@ parser = argparse.ArgumentParser() default_warning = '1' -if mesonlib.is_windows(): - def_prefix = 'c:/' -else: - def_prefix = '/usr/local' +def add_builtin_argument(name, **kwargs): + k = kwargs.get('dest', name.replace('-', '_')) + c = coredata.get_builtin_option_choices(k) + b = True if kwargs.get('action', None) in [ 'store_true', 'store_false' ] else False + h = coredata.get_builtin_option_description(k) + if not b: + h = h.rstrip('.') + ' (default: %s).' % coredata.get_builtin_option_default(k) + if c and not b: + kwargs['choices'] = c + parser.add_argument('--' + name, default=coredata.get_builtin_option_default(k), help=h, **kwargs) + +add_builtin_argument('prefix') +add_builtin_argument('libdir') +add_builtin_argument('libexecdir') +add_builtin_argument('bindir') +add_builtin_argument('includedir') +add_builtin_argument('datadir') +add_builtin_argument('mandir') +add_builtin_argument('localedir') +add_builtin_argument('backend') +add_builtin_argument('buildtype') +add_builtin_argument('strip', action='store_true') +add_builtin_argument('unity', action='store_true') +add_builtin_argument('werror', action='store_true') +add_builtin_argument('layout') +add_builtin_argument('default-library') +add_builtin_argument('warnlevel', dest='warning_level') -parser.add_argument('--prefix', default=def_prefix, dest='prefix', - help='the installation prefix (default: %(default)s)') -parser.add_argument('--libdir', default=mesonlib.default_libdir(), dest='libdir', - help='the installation subdir of libraries (default: %(default)s)') -parser.add_argument('--libexecdir', default=mesonlib.default_libexecdir(), dest='libexecdir', - help='the installation subdir of library executables (default: %(default)s)') -parser.add_argument('--bindir', default='bin', dest='bindir', - help='the installation subdir of executables (default: %(default)s)') -parser.add_argument('--includedir', default='include', dest='includedir', - help='relative path of installed headers (default: %(default)s)') -parser.add_argument('--datadir', default='share', dest='datadir', - help='relative path to the top of data file subdirectory (default: %(default)s)') -parser.add_argument('--mandir', default='share/man', dest='mandir', - help='relative path of man files (default: %(default)s)') -parser.add_argument('--localedir', default='share/locale', dest='localedir', - help='relative path of locale data (default: %(default)s)') -parser.add_argument('--backend', default='ninja', dest='backend', choices=backendlist, - help='backend to use (default: %(default)s)') -parser.add_argument('--buildtype', default='debug', choices=build_types, dest='buildtype', - help='build type go use (default: %(default)s)') -parser.add_argument('--strip', action='store_true', dest='strip', default=False,\ - help='strip targets on install (default: %(default)s)') -parser.add_argument('--unity', action='store_true', dest='unity', default=False,\ - help='unity build') -parser.add_argument('--werror', action='store_true', dest='werror', default=False,\ - help='Treat warnings as errors') -parser.add_argument('--layout', choices=layouts, dest='layout', default='mirror',\ - help='Build directory layout.') -parser.add_argument('--default-library', choices=libtypelist, dest='default_library', - default='shared', help='Default library type.') -parser.add_argument('--warnlevel', default=default_warning, dest='warning_level', choices=warning_levels,\ - help='Level of compiler warnings to use (larger is more, default is %(default)s)') -parser.add_argument('--cross-file', default=None, dest='cross_file', - help='file describing cross compilation environment') +parser.add_argument('--cross-file', default=None, + help='File describing cross compilation environment.') parser.add_argument('-D', action='append', dest='projectoptions', default=[], help='Set project options.') parser.add_argument('-v', '--version', action='store_true', dest='print_version', default=False, - help='Print version.') + help='Print version information.') parser.add_argument('directories', nargs='*') class MesonApp(): diff --git a/mesonbuild/modules/gnome.py b/mesonbuild/modules/gnome.py index 55bb321..f0de363 100644 --- a/mesonbuild/modules/gnome.py +++ b/mesonbuild/modules/gnome.py @@ -18,7 +18,7 @@ functionality such as gobject-introspection and gresources.''' from .. import build import os, sys import subprocess -from ..coredata import MesonException +from ..mesonlib import MesonException from .. import mlog from .. import mesonlib diff --git a/mesonbuild/modules/pkgconfig.py b/mesonbuild/modules/pkgconfig.py index ffe03e2..fe5ca45 100644 --- a/mesonbuild/modules/pkgconfig.py +++ b/mesonbuild/modules/pkgconfig.py @@ -55,7 +55,7 @@ class PkgConfigModule: def generate(self, state, args, kwargs): if len(args) > 0: - raise coredata.MesonException('Pkgconfig_gen takes no positional arguments.') + raise mesonlib.MesonException('Pkgconfig_gen takes no positional arguments.') libs = kwargs.get('libraries', []) if not isinstance(libs, list): libs = [libs] @@ -64,22 +64,22 @@ class PkgConfigModule: if hasattr(l, 'held_object'): l = l.held_object if not (isinstance(l, build.SharedLibrary) or isinstance(l, build.StaticLibrary)): - raise coredata.MesonException('Library argument not a library object.') + raise mesonlib.MesonException('Library argument not a library object.') processed_libs.append(l) libs = processed_libs subdirs = mesonlib.stringlistify(kwargs.get('subdirs', ['.'])) version = kwargs.get('version', '') if not isinstance(version, str): - raise coredata.MesonException('Version must be a string.') + raise mesonlib.MesonException('Version must be a string.') name = kwargs.get('name', None) if not isinstance(name, str): - raise coredata.MesonException('Name not specified.') + raise mesonlib.MesonException('Name not specified.') filebase = kwargs.get('filebase', name) if not isinstance(filebase, str): - raise coredata.MesonException('Filebase must be a string.') + raise mesonlib.MesonException('Filebase must be a string.') description = kwargs.get('description', None) if not isinstance(description, str): - raise coredata.MesonException('Description is not a string.') + raise mesonlib.MesonException('Description is not a string.') pub_reqs = mesonlib.stringlistify(kwargs.get('requires', [])) priv_reqs = mesonlib.stringlistify(kwargs.get('requires_private', [])) priv_libs = mesonlib.stringlistify(kwargs.get('libraries_private', [])) diff --git a/mesonbuild/modules/qt4.py b/mesonbuild/modules/qt4.py index 162b553..81a70fc 100644 --- a/mesonbuild/modules/qt4.py +++ b/mesonbuild/modules/qt4.py @@ -15,7 +15,7 @@ from .. import dependencies, mlog import os, subprocess from .. import build -from ..coredata import MesonException +from ..mesonlib import MesonException import xml.etree.ElementTree as ET class Qt4Module(): diff --git a/mesonbuild/modules/qt5.py b/mesonbuild/modules/qt5.py index cb743a6..f669d77 100644 --- a/mesonbuild/modules/qt5.py +++ b/mesonbuild/modules/qt5.py @@ -15,7 +15,7 @@ from .. import dependencies, mlog import os, subprocess from .. import build -from ..coredata import MesonException +from ..mesonlib import MesonException import xml.etree.ElementTree as ET class Qt5Module(): diff --git a/mesonbuild/modules/windows.py b/mesonbuild/modules/windows.py index a785250..29d6236 100644 --- a/mesonbuild/modules/windows.py +++ b/mesonbuild/modules/windows.py @@ -13,7 +13,7 @@ # limitations under the License. from .. import mesonlib, dependencies, build -from ..coredata import MesonException +from ..mesonlib import MesonException import os class WindowsModule: diff --git a/mesonbuild/mparser.py b/mesonbuild/mparser.py index 090684c..fd720fb 100644 --- a/mesonbuild/mparser.py +++ b/mesonbuild/mparser.py @@ -13,7 +13,7 @@ # limitations under the License. import re -from .coredata import MesonException +from .mesonlib import MesonException class ParseException(MesonException): def __init__(self, text, lineno, colno): diff --git a/mesonbuild/optinterpreter.py b/mesonbuild/optinterpreter.py index e2f7ca5..409f9dc 100644 --- a/mesonbuild/optinterpreter.py +++ b/mesonbuild/optinterpreter.py @@ -14,9 +14,10 @@ from . import mparser from . import coredata +from . import mesonlib import os, re -forbidden_option_names = coredata.builtin_options +forbidden_option_names = coredata.get_builtin_options() forbidden_prefixes = {'c_': True, 'cpp_': True, 'rust_': True, @@ -37,7 +38,7 @@ def is_invalid_name(name): return True return False -class OptionException(coredata.MesonException): +class OptionException(mesonlib.MesonException): pass optname_regex = re.compile('[^a-zA-Z0-9_-]') @@ -77,7 +78,7 @@ class OptionInterpreter: def process(self, option_file): try: ast = mparser.Parser(open(option_file, 'r', encoding='utf8').read()).parse() - except coredata.MesonException as me: + except mesonlib.MesonException as me: me.file = option_file raise me if not isinstance(ast, mparser.CodeBlockNode): diff --git a/mesonbuild/scripts/meson_benchmark.py b/mesonbuild/scripts/meson_benchmark.py index 26f1f95..d1107b6 100644 --- a/mesonbuild/scripts/meson_benchmark.py +++ b/mesonbuild/scripts/meson_benchmark.py @@ -39,9 +39,10 @@ def print_json_log(jsonlogfile, rawruns, test_name, i): for r in rawruns: runobj = {'duration': r.duration, 'stdout': r.stdo, - 'stderr': r.stde, 'returncode' : r.returncode, 'duration' : r.duration} + if r.stde: + runobj['stderr'] = r.stde runs.append(runobj) jsonobj['runs'] = runs jsonlogfile.write(json.dumps(jsonobj) + '\n') diff --git a/mesonbuild/scripts/meson_test.py b/mesonbuild/scripts/meson_test.py index 453ea61..5407f2b 100644 --- a/mesonbuild/scripts/meson_test.py +++ b/mesonbuild/scripts/meson_test.py @@ -25,7 +25,9 @@ def is_windows(): platname = platform.system().lower() return platname == 'windows' or 'mingw' in platname -tests_failed = [] +collected_logs = [] +error_count = 0 +options = None parser = argparse.ArgumentParser() parser.add_argument('--wrapper', default=None, dest='wrapper', @@ -34,17 +36,41 @@ parser.add_argument('--wd', default=None, dest='wd', help='directory to cd into before running') parser.add_argument('--suite', default=None, dest='suite', help='Only run tests belonging to this suite.') +parser.add_argument('--no-stdsplit', default=True, dest='split', action='store_false', + help='Do not split stderr and stdout in test logs.') +parser.add_argument('--print-errorlogs', default=False, action='store_true', + help="Whether to print faling tests' logs.") parser.add_argument('args', nargs='+') class TestRun(): - def __init__(self, res, returncode, duration, stdo, stde, cmd): + def __init__(self, res, returncode, should_fail, duration, stdo, stde, cmd): self.res = res self.returncode = returncode self.duration = duration self.stdo = stdo self.stde = stde self.cmd = cmd + self.should_fail = should_fail + + def get_log(self): + res = '--- command ---\n' + if self.cmd is None: + res += 'NONE\n' + else: + res += ' '.join(self.cmd) + '\n' + if self.stdo: + res += '--- stdout ---\n' + res += self.stdo + if self.stde: + if res[-1:] != '\n': + res += '\n' + res += '--- stderr ---\n' + res += self.stde + if res[-1:] != '\n': + res += '\n' + res += '-------\n\n' + return res def decode(stream): try: @@ -52,28 +78,16 @@ def decode(stream): except UnicodeDecodeError: return stream.decode('iso-8859-1', errors='ignore') -def write_log(logfile, test_name, result_str, result): - logfile.write(result_str + '\n\n') - logfile.write('--- command ---\n') - if result.cmd is None: - logfile.write('NONE') - else: - logfile.write(' '.join(result.cmd)) - logfile.write('\n--- "%s" stdout ---\n' % test_name) - logfile.write(result.stdo) - logfile.write('\n--- "%s" stderr ---\n' % test_name) - logfile.write(result.stde) - logfile.write('\n-------\n\n') - def write_json_log(jsonlogfile, test_name, result): - result = {'name' : test_name, + jresult = {'name' : test_name, 'stdout' : result.stdo, - 'stderr' : result.stde, 'result' : result.res, 'duration' : result.duration, 'returncode' : result.returncode, 'command' : result.cmd} - jsonlogfile.write(json.dumps(result) + '\n') + if result.stde: + jresult['stderr'] = result.stde + jsonlogfile.write(json.dumps(jresult) + '\n') def run_with_mono(fname): if fname.endswith('.exe') and not is_windows(): @@ -81,7 +95,7 @@ def run_with_mono(fname): return False def run_single_test(wrap, test): - global tests_failed + global options if test.fname[0].endswith('.jar'): cmd = ['java', '-jar'] + test.fname elif not test.is_cross and run_with_mono(test.fname[0]): @@ -102,7 +116,7 @@ def run_single_test(wrap, test): res = 'SKIP' duration = 0.0 stdo = 'Not run because can not execute cross compiled binaries.' - stde = '' + stde = None returncode = -1 else: cmd = wrap + cmd + test.cmd_args @@ -117,7 +131,7 @@ def run_single_test(wrap, test): setsid = os.setsid p = subprocess.Popen(cmd, stdout=subprocess.PIPE, - stderr=subprocess.PIPE, + stderr=subprocess.PIPE if options and options.split else subprocess.STDOUT, env=child_env, cwd=test.workdir, preexec_fn=setsid) @@ -137,20 +151,20 @@ def run_single_test(wrap, test): endtime = time.time() duration = endtime - starttime stdo = decode(stdo) - stde = decode(stde) + if stde: + stde = decode(stde) if timed_out: res = 'TIMEOUT' - tests_failed.append((test.name, stdo, stde)) elif (not test.should_fail and p.returncode == 0) or \ (test.should_fail and p.returncode != 0): res = 'OK' else: res = 'FAIL' - tests_failed.append((test.name, stdo, stde)) returncode = p.returncode - return TestRun(res, returncode, duration, stdo, stde, cmd) + return TestRun(res, returncode, test.should_fail, duration, stdo, stde, cmd) def print_stats(numlen, tests, name, result, i, logfile, jsonlogfile): + global collected_logs, error_count, options startpad = ' '*(numlen - len('%d' % (i+1))) num = '%s%d/%d' % (startpad, i+1, len(tests)) padding1 = ' '*(38-len(name)) @@ -158,7 +172,12 @@ def print_stats(numlen, tests, name, result, i, logfile, jsonlogfile): result_str = '%s %s %s%s%s%5.2f s' % \ (num, name, padding1, result.res, padding2, result.duration) print(result_str) - write_log(logfile, name, result_str, result) + result_str += "\n\n" + result.get_log() + if (result.returncode != 0) != result.should_fail: + error_count += 1 + if options.print_errorlogs: + collected_logs.append(result_str) + logfile.write(result_str) write_json_log(jsonlogfile, name, result) def drain_futures(futures): @@ -171,7 +190,8 @@ def filter_tests(suite, tests): return tests return [x for x in tests if suite in x.suite] -def run_tests(options, datafilename): +def run_tests(datafilename): + global options logfile_base = 'meson-logs/testlog' if options.wrapper is None: wrap = [] @@ -222,8 +242,9 @@ def run_tests(options, datafilename): return logfilename def run(args): - global tests_failed - tests_failed = [] # To avoid state leaks when invoked multiple times (running tests in-process) + global collected_logs, error_count, options + collected_logs = [] # To avoid state leaks when invoked multiple times (running tests in-process) + error_count = 0 options = parser.parse_args(args) if len(options.args) != 1: print('Test runner for Meson. Do not run on your own, mmm\'kay?') @@ -231,19 +252,22 @@ def run(args): if options.wd is not None: os.chdir(options.wd) datafile = options.args[0] - logfilename = run_tests(options, datafile) - returncode = 0 - if len(tests_failed) > 0: - print('\nOutput of failed tests (max 10):') - for (name, stdo, stde) in tests_failed[:10]: - print("{} stdout:\n".format(name)) - print(stdo) - print('\n{} stderr:\n'.format(name)) - print(stde) - print('\n') - returncode = 1 - print('\nFull log written to %s.' % logfilename) - return returncode + logfilename = run_tests(datafile) + if len(collected_logs) > 0: + if len(collected_logs) > 10: + print('\nThe output from 10 first failed tests:\n') + else: + print('\nThe output from the failed tests:\n') + for log in collected_logs[:10]: + lines = log.splitlines() + if len(lines) > 100: + print(line[0]) + print('--- Listing only the last 100 lines from a long log. ---') + lines = lines[-99:] + for line in lines: + print(line) + print('Full log written to %s.' % logfilename) + return error_count if __name__ == '__main__': sys.exit(run(sys.argv[1:])) |