aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mesonbuild/backend/backends.py2
-rw-r--r--mesonbuild/backend/ninjabackend.py10
-rw-r--r--mesonbuild/backend/vs2010backend.py2
-rw-r--r--mesonbuild/backend/xcodebackend.py2
-rw-r--r--mesonbuild/build.py8
-rw-r--r--mesonbuild/compilers.py2
-rw-r--r--mesonbuild/coredata.py119
-rw-r--r--mesonbuild/dependencies.py2
-rw-r--r--mesonbuild/environment.py8
-rw-r--r--mesonbuild/interpreter.py11
-rw-r--r--mesonbuild/mconf.py48
-rw-r--r--mesonbuild/mesonlib.py7
-rw-r--r--mesonbuild/mesonmain.py72
-rw-r--r--mesonbuild/modules/gnome.py2
-rw-r--r--mesonbuild/modules/pkgconfig.py12
-rw-r--r--mesonbuild/modules/qt4.py2
-rw-r--r--mesonbuild/modules/qt5.py2
-rw-r--r--mesonbuild/modules/windows.py2
-rw-r--r--mesonbuild/mparser.py2
-rw-r--r--mesonbuild/optinterpreter.py7
-rw-r--r--mesonbuild/scripts/meson_benchmark.py3
-rw-r--r--mesonbuild/scripts/meson_test.py108
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:]))