diff options
-rw-r--r-- | backends.py | 1 | ||||
-rw-r--r-- | compilers.py | 230 | ||||
-rw-r--r-- | coredata.py | 1 | ||||
-rw-r--r-- | interpreter.py | 20 | ||||
-rwxr-xr-x | mesonconf.py | 40 | ||||
-rwxr-xr-x | mesongui.py | 10 | ||||
-rwxr-xr-x | mesonintrospect.py | 17 | ||||
-rw-r--r-- | mesonlib.py | 76 | ||||
-rw-r--r-- | ninjabackend.py | 1 | ||||
-rw-r--r-- | optinterpreter.py | 103 | ||||
-rw-r--r-- | test cases/frameworks/1 boost/meson.build | 6 | ||||
-rw-r--r-- | test cases/frameworks/4 qt5/meson.build | 4 | ||||
-rw-r--r-- | test cases/frameworks/9 wxwidgets/meson.build | 2 |
13 files changed, 329 insertions, 182 deletions
diff --git a/backends.py b/backends.py index f13b3c7..4acf71c 100644 --- a/backends.py +++ b/backends.py @@ -210,6 +210,7 @@ class Backend(): commands += compiler.get_always_args() if self.environment.coredata.buildtype != 'plain': commands += compiler.get_warn_args(self.environment.coredata.warning_level) + commands += compiler.get_option_compile_args(self.environment.coredata.compiler_options) commands += self.build.get_global_args(compiler) commands += self.environment.coredata.external_args[compiler.get_language()] commands += target.get_extra_args(compiler.get_language()) diff --git a/compilers.py b/compilers.py index f817161..bb32069 100644 --- a/compilers.py +++ b/compilers.py @@ -91,6 +91,13 @@ mono_buildtype_args = {'plain' : [], 'debugoptimized': ['-debug', '-optimize+'], 'release' : ['-optimize+']} +gnu_winlibs = ['-lkernel32', '-luser32', '-lgdi32', '-lwinspool', '-lshell32', + '-lole32', '-loleaut32', '-luuid', '-lcomdlg32', '-ladvapi32'] + +msvc_winlibs = ['kernel32.lib', 'user32.lib', 'gdi32.lib', + 'winspool.lib', 'shell32.lib', 'ole32.lib', 'oleaut32.lib', + 'uuid.lib', 'comdlg32.lib', 'advapi32.lib'] + def build_unix_rpath_args(build_dir, rpath_paths, install_rpath): if len(rpath_paths) == 0 and len(install_rpath) == 0: return [] @@ -118,8 +125,8 @@ class RunResult(): self.stdout = stdout self.stderr = stderr -class CCompiler(): - def __init__(self, exelist, version, is_cross, exe_wrapper=None): +class Compiler(): + def __init__(self, exelist, version): if type(exelist) == type(''): self.exelist = [exelist] elif type(exelist) == type([]): @@ -127,6 +134,25 @@ class CCompiler(): else: raise TypeError('Unknown argument to CCompiler') self.version = version + + def get_always_args(self): + return [] + + def get_linker_always_args(self): + return [] + + def get_options(self): + return {} # build afresh every time + + def get_option_compile_args(self, options): + return [] + + def get_option_link_args(self, options): + return [] + +class CCompiler(Compiler): + def __init__(self, exelist, version, is_cross, exe_wrapper=None): + super().__init__(exelist, version) self.language = 'c' self.default_suffix = 'c' self.id = 'unknown' @@ -142,9 +168,6 @@ class CCompiler(): def get_always_args(self): return [] - def get_linker_always_args(self): - return [] - def get_warn_args(self, level): return self.warn_args[level] @@ -539,29 +562,17 @@ class ObjCPPCompiler(CPPCompiler): if pe.returncode != 0: raise EnvironmentException('Executables created by ObjC++ compiler %s are not runnable.' % self.name_string()) -class MonoCompiler(): +class MonoCompiler(Compiler): def __init__(self, exelist, version): - if type(exelist) == type(''): - self.exelist = [exelist] - elif type(exelist) == type([]): - self.exelist = exelist - else: - raise TypeError('Unknown argument to Mono compiler') - self.version = version + super().__init__(exelist, version) self.language = 'cs' self.default_suffix = 'cs' self.id = 'mono' self.monorunner = 'mono' - def get_always_args(self): - return [] - def get_output_args(self, fname): return ['-out:' + fname] - def get_linker_always_args(self): - return [] - def get_link_args(self, fname): return ['-r:' + fname] @@ -679,26 +690,14 @@ class MonoCompiler(): def get_buildtype_args(self, buildtype): return mono_buildtype_args[buildtype] -class JavaCompiler(): +class JavaCompiler(Compiler): def __init__(self, exelist, version): - if type(exelist) == type(''): - self.exelist = [exelist] - elif type(exelist) == type([]): - self.exelist = exelist - else: - raise TypeError('Unknown argument to JavaCompiler') - self.version = version + super().__init__(exelist, version) self.language = 'java' self.default_suffix = 'java' self.id = 'unknown' self.javarunner = 'java' - def get_always_args(self): - return [] - - def get_linker_always_args(self): - return [] - def get_soname_args(self, shlib_name, path, soversion): return [] @@ -819,14 +818,9 @@ class JavaCompiler(): def has_function(self, funcname, prefix, env): raise EnvironmentException('Java does not support function checks.') -class ValaCompiler(): +class ValaCompiler(Compiler): def __init__(self, exelist, version): - if isinstance(exelist, str): - self.exelist = [exelist] - elif type(exelist) == type([]): - self.exelist = exelist - else: - raise TypeError('Unknown argument to Vala compiler') + super().__init__(exelist, version) self.version = version self.id = 'unknown' self.language = 'vala' @@ -863,15 +857,9 @@ class ValaCompiler(): suffix = filename.split('.')[-1] return suffix in ('vala', 'vapi') -class RustCompiler(): +class RustCompiler(Compiler): def __init__(self, exelist, version): - if isinstance(exelist, str): - self.exelist = [exelist] - elif type(exelist) == type([]): - self.exelist = exelist - else: - raise TypeError('Unknown argument to Rust compiler') - self.version = version + super().__init__(exelist, version) self.id = 'unknown' self.language = 'rust' @@ -920,6 +908,7 @@ class VisualStudioCCompiler(CCompiler): vs2010_always_args = ['/nologo', '/showIncludes'] vs2013_always_args = ['/nologo', '/showIncludes', '/FS'] + def __init__(self, exelist, version, is_cross, exe_wrap): CCompiler.__init__(self, exelist, version, is_cross, exe_wrap) self.id = 'msvc' @@ -1012,6 +1001,15 @@ class VisualStudioCCompiler(CCompiler): def thread_link_flags(self): return [] + def get_options(self): + return {'c_winlibs' : mesonlib.UserStringArrayOption('c_winlibs', + 'Windows libs to link against.', + msvc_winlibs) + } + + def get_option_link_args(self, options): + return options['c_winlibs'].value + class VisualStudioCPPCompiler(VisualStudioCCompiler): def __init__(self, exelist, version, is_cross, exe_wrap): VisualStudioCCompiler.__init__(self, exelist, version, is_cross, exe_wrap) @@ -1042,6 +1040,26 @@ class VisualStudioCPPCompiler(VisualStudioCCompiler): if pe.returncode != 0: raise EnvironmentException('Executables created by C++ compiler %s are not runnable.' % self.name_string()) + def get_options(self): + return {'cpp_eh' : mesonlib.UserComboOption('cpp_eh', + 'C++ exception handling type.', + ['none', 'a', 's', 'sc'], + 'sc'), + 'cpp_winlibs' : mesonlib.UserStringArrayOption('cpp_winlibs', + 'Windows libs to link against.', + msvc_winlibs) + } + + def get_option_compile_args(self, options): + args = [] + std = options['cpp_eh'] + if std.value != 'none': + args.append('/EH' + std.value) + return args + + def get_option_link_args(self, options): + return options['cpp_winlibs'].value + GCC_STANDARD = 0 GCC_OSX = 1 GCC_MINGW = 2 @@ -1059,6 +1077,7 @@ def get_gcc_soname_args(gcc_type, shlib_name, path, soversion): else: raise RuntimeError('Not implemented yet.') + class GnuCCompiler(CCompiler): def __init__(self, exelist, version, gcc_type, is_cross, exe_wrapper=None): CCompiler.__init__(self, exelist, version, is_cross, exe_wrapper) @@ -1094,6 +1113,29 @@ class GnuCCompiler(CCompiler): def can_compile(self, filename): return super().can_compile(filename) or filename.split('.')[-1].lower() == 's' # Gcc can do asm, too. + def get_options(self): + opts = {'c_std' : mesonlib.UserComboOption('c_std', 'C language standard to use', + ['none', 'c89', 'c99', 'c11', 'gnu89', 'gnu99', 'gnu11'], + 'c11')} + if self.gcc_type == GCC_MINGW: + opts.update({ + 'c_winlibs': mesonlib.UserStringArrayOption('c_winlibs', 'Standard Win libraries to link against', + gnu_winlibs), + }) + return opts + + def get_option_compile_args(self, options): + args = [] + std = options['c_std'] + if std.value != 'none': + args.append('-std=' + std.value) + return args + + def get_option_link_args(self, options): + if self.gcc_type == GCC_MINGW: + return options['c_winlibs'].value + return [] + class GnuObjCCompiler(ObjCCompiler): std_opt_args = ['-O2'] @@ -1182,6 +1224,22 @@ class ClangCCompiler(CCompiler): # so it might change semantics at any time. return ['-include-pch', os.path.join (pch_dir, self.get_pch_name (header))] + def get_options(self): + return {'c_std' : mesonlib.UserComboOption('c_std', 'C language standard to use', + ['none', 'c89', 'c99', 'c11'], + 'c11')} + + def get_option_compile_args(self, options): + args = [] + std = options['c_std'] + if std.value != 'none': + args.append('-std=' + std.value) + return args + + def get_option_link_args(self, options): + if self.gcc_type == GCC_MINGW: + return options['c_winlibs'].value + return [] class GnuCPPCompiler(CPPCompiler): # may need to separate the latter to extra_debug_args or something @@ -1210,6 +1268,29 @@ class GnuCPPCompiler(CPPCompiler): def get_soname_args(self, shlib_name, path, soversion): return get_gcc_soname_args(self.gcc_type, shlib_name, path, soversion) + def get_options(self): + opts = {'cpp_std' : mesonlib.UserComboOption('cpp_std', 'C language standard to use', + ['none', 'c++03', 'c++11', 'c++1y'], + 'c++11')} + if self.gcc_type == GCC_MINGW: + opts.update({ + 'cpp_winlibs': mesonlib.UserStringArrayOption('c_winlibs', 'Standard Win libraries to link against', + gnu_winlibs), + }) + return opts + + def get_option_compile_args(self, options): + args = [] + std = options['cpp_std'] + if std.value != 'none': + args.append('-std=' + std.value) + return args + + def get_option_link_args(self, options): + if self.gcc_type == GCC_MINGW: + return options['cpp_winlibs'].value + return [] + class ClangCPPCompiler(CPPCompiler): def __init__(self, exelist, version, is_cross, exe_wrapper=None): CPPCompiler.__init__(self, exelist, version, is_cross, exe_wrapper) @@ -1233,11 +1314,24 @@ class ClangCPPCompiler(CPPCompiler): # so it might change semantics at any time. return ['-include-pch', os.path.join (pch_dir, self.get_pch_name (header))] -class FortranCompiler(): - def __init__(self, exelist, version,is_cross, exe_wrapper=None): - super().__init__() - self.exelist = exelist - self.version = version + def get_options(self): + return {'cpp_std' : mesonlib.UserComboOption('cpp_std', 'C++ language standard to use', + ['none', 'c++03', 'c++11', 'c++1y'], + 'c++11')} + + def get_option_compile_args(self, options): + args = [] + std = options['cpp_std'] + if std.value != 'none': + args.append('-std=' + std.value) + return args + + def get_option_link_args(self, options): + return [] + +class FortranCompiler(Compiler): + def __init__(self, exelist, version, is_cross, exe_wrapper=None): + super().__init__(exelist, version) self.is_cross = is_cross self.exe_wrapper = exe_wrapper self.language = 'fortran' @@ -1293,12 +1387,6 @@ end program prog if pe.returncode != 0: raise EnvironmentException('Executables created by Fortran compiler %s are not runnable.' % self.name_string()) - def get_always_args(self): - return ['-pipe'] - - def get_linker_always_args(self): - return [] - def get_std_warn_args(self, level): return FortranCompiler.std_warn_args @@ -1368,6 +1456,9 @@ class GnuFortranCompiler(FortranCompiler): self.gcc_type = gcc_type self.id = 'gcc' + def get_always_args(self): + return ['-pipe'] + class G95FortranCompiler(FortranCompiler): def __init__(self, exelist, version, is_cross, exe_wrapper=None): super().__init__(exelist, version, is_cross, exe_wrapper=None) @@ -1376,6 +1467,9 @@ class G95FortranCompiler(FortranCompiler): def get_module_outdir_args(self, path): return ['-fmod='+path] + def get_always_args(self): + return ['-pipe'] + class SunFortranCompiler(FortranCompiler): def __init__(self, exelist, version, is_cross, exe_wrapper=None): super().__init__(exelist, version, is_cross, exe_wrapper=None) @@ -1403,9 +1497,6 @@ class IntelFortranCompiler(FortranCompiler): def get_module_outdir_args(self, path): return ['-module', path] - def get_always_args(self): - return [] - def can_compile(self, src): suffix = os.path.splitext(src)[1].lower() if suffix == '.f' or suffix == '.f90': @@ -1425,9 +1516,6 @@ class PathScaleFortranCompiler(FortranCompiler): def get_module_outdir_args(self, path): return ['-module', path] - def get_always_args(self): - return [] - def can_compile(self, src): suffix = os.path.splitext(src)[1].lower() if suffix == '.f' or suffix == '.f90' or suffix == '.f95': @@ -1447,9 +1535,6 @@ class PGIFortranCompiler(FortranCompiler): def get_module_outdir_args(self, path): return ['-module', path] - def get_always_args(self): - return [] - def can_compile(self, src): suffix = os.path.splitext(src)[1].lower() if suffix == '.f' or suffix == '.f90' or suffix == '.f95': @@ -1470,9 +1555,6 @@ class Open64FortranCompiler(FortranCompiler): def get_module_outdir_args(self, path): return ['-module', path] - def get_always_args(self): - return [] - def can_compile(self, src): suffix = os.path.splitext(src)[1].lower() if suffix == '.f' or suffix == '.f90' or suffix == '.f95': @@ -1537,6 +1619,9 @@ class VisualStudioLinker(): def thread_link_flags(self): return [] + def get_option_link_args(self, options): + return [] + class ArLinker(): std_args = ['csr'] @@ -1570,3 +1655,6 @@ class ArLinker(): def thread_link_flags(self): return [] + + def get_option_link_args(self, options): + return [] diff --git a/coredata.py b/coredata.py index 793cd47..4c244c0 100644 --- a/coredata.py +++ b/coredata.py @@ -61,6 +61,7 @@ class CoreData(): self.werror = options.werror self.layout = options.layout self.user_options = {} + self.compiler_options = {} self.external_args = {} # These are set from "the outside" with e.g. mesonconf self.external_link_args = {} if options.cross_file is not None: diff --git a/interpreter.py b/interpreter.py index 914caa1..7e67711 100644 --- a/interpreter.py +++ b/interpreter.py @@ -1239,15 +1239,20 @@ class Interpreter(): if len(args) != 1: raise InterpreterException('Argument required for get_option.') optname = args[0] - if optname not in coredata.builtin_options and self.is_subproject(): - optname = self.subproject + ':' + optname try: return self.environment.get_coredata().get_builtin_option(optname) except RuntimeError: pass - if optname not in self.environment.coredata.user_options: + try: + return self.environment.coredata.compiler_options[optname].value + except KeyError: + pass + if optname not in coredata.builtin_options and self.is_subproject(): + optname = self.subproject + ':' + optname + try: + return self.environment.coredata.user_options[optname].value + except KeyError: raise InterpreterException('Tried to access unknown option "%s".' % optname) - return self.environment.coredata.user_options[optname].value @noKwargs def func_configuration_data(self, node, args, kwargs): @@ -1365,6 +1370,13 @@ class Interpreter(): if cross_comp is not None: cross_comp.sanity_check(self.environment.get_scratch_dir()) self.coredata.cross_compilers[lang] = cross_comp + new_options = comp.get_options() + optprefix = lang + '_' + for i in new_options: + if not i.startswith(optprefix): + raise InterpreterException('Internal error, %s has incorrect prefix.' % i) + new_options.update(self.coredata.compiler_options) + self.coredata.compiler_options = new_options mlog.log('Native %s compiler: ' % lang, mlog.bold(' '.join(comp.get_exelist())), ' (%s %s)' % (comp.id, comp.version), sep='') if not comp.get_language() in self.coredata.external_args: (ext_compile_args, ext_link_args) = environment.get_args_from_envvars(comp.get_language()) diff --git a/mesonconf.py b/mesonconf.py index db526b0..963585a 100755 --- a/mesonconf.py +++ b/mesonconf.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 -# Copyright 2014 The Meson development team +# Copyright 2014-2015 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,7 +17,7 @@ import sys, os import pickle import argparse -import coredata, optinterpreter +import coredata, mesonlib from meson import build_types, layouts, warning_levels parser = argparse.ArgumentParser() @@ -64,13 +64,6 @@ class Conf: f = '%s%s %s%s' % (name, namepad, descr, descrpad) print(f, value) - def tobool(self, thing): - if thing.lower() == 'true': - return True - if thing.lower() == 'false': - return False - raise ConfException('Value %s is not boolean (true or false).' % thing) - def set_options(self, options): for o in options: if '=' not in o: @@ -127,18 +120,10 @@ class Conf: self.coredata.localedir = v elif k in self.coredata.user_options: tgt = self.coredata.user_options[k] - if isinstance(tgt, optinterpreter.UserBooleanOption): - tgt.set_value(self.tobool(v)) - elif isinstance(tgt, optinterpreter.UserComboOption): - try: - tgt.set_value(v) - except optinterpreter.OptionException: - raise ConfException('Value of %s must be one of %s.' % - (k, tgt.choices)) - elif isinstance(tgt, optinterpreter.UserStringOption): - tgt.set_value(v) - else: - raise ConfException('Internal error, unknown option type.') + tgt.set_value(v) + elif k in self.coredata.compiler_options: + tgt = self.coredata.compiler_options[k] + tgt.set_value(v) elif k.endswith('linkargs'): lang = k[:-8] if not lang in self.coredata.external_link_args: @@ -181,6 +166,17 @@ class Conf: for (lang, args) in self.coredata.external_link_args.items(): print(lang + 'linkargs', str(args)) print('') + okeys = sorted(self.coredata.compiler_options.keys()) + if len(okeys) == 0: + print('No compiler options\n') + else: + print('Compiler options\n') + coarr = [] + for k in okeys: + o = self.coredata.compiler_options[k] + coarr.append([k, o.description, o.value]) + self.print_aligned(coarr) + print('') print('Directories\n') parr = [] parr.append(['prefix', 'Install prefix', self.coredata.prefix]) @@ -193,7 +189,7 @@ class Conf: self.print_aligned(parr) print('') if len(self.coredata.user_options) == 0: - print('This project does not have any options') + print('This project does not have user options') else: print('Project options\n') options = self.coredata.user_options diff --git a/mesongui.py b/mesongui.py index 10a84f7..bdd44bb 100755 --- a/mesongui.py +++ b/mesongui.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 -# Copyright 2013 The Meson development team +# Copyright 2013-2015 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -15,7 +15,7 @@ # limitations under the License. import sys, os, pickle, time, shutil -import build, coredata, environment, optinterpreter +import build, coredata, environment, mesonlib from PyQt5 import uic from PyQt5.QtWidgets import QApplication, QMainWindow, QHeaderView from PyQt5.QtWidgets import QComboBox, QCheckBox @@ -272,14 +272,14 @@ class OptionForm: self.opt_widgets = [] for key in keys: opt = options[key] - if isinstance(opt, optinterpreter.UserStringOption): + if isinstance(opt, mesonlib.UserStringOption): w = PyQt5.QtWidgets.QLineEdit(opt.value) w.textChanged.connect(self.user_option_changed) - elif isinstance(opt, optinterpreter.UserBooleanOption): + elif isinstance(opt, mesonlib.UserBooleanOption): w = QCheckBox('') w.setChecked(opt.value) w.stateChanged.connect(self.user_option_changed) - elif isinstance(opt, optinterpreter.UserComboOption): + elif isinstance(opt, mesonlib.UserComboOption): w = QComboBox() for i in opt.choices: w.addItem(i) diff --git a/mesonintrospect.py b/mesonintrospect.py index ffdd320..3ef2ab5 100755 --- a/mesonintrospect.py +++ b/mesonintrospect.py @@ -22,7 +22,7 @@ Currently only works for the Ninja backend. Others use generated project files and don't need this info.""" import json, pickle -import coredata, build, optinterpreter +import coredata, build, mesonlib import argparse import sys, os @@ -107,7 +107,11 @@ def list_buildoptions(coredata, builddata): 'description' : 'Unity build', 'name' : 'unity'} optlist = [buildtype, strip, coverage, pch, unity] - options = coredata.user_options + add_keys(optlist, coredata.user_options) + add_keys(optlist, coredata.compiler_options) + print(json.dumps(optlist)) + +def add_keys(optlist, options): keys = list(options.keys()) keys.sort() for key in keys: @@ -115,19 +119,20 @@ def list_buildoptions(coredata, builddata): optdict = {} optdict['name'] = key optdict['value'] = opt.value - if isinstance(opt, optinterpreter.UserStringOption): + if isinstance(opt, mesonlib.UserStringOption): typestr = 'string' - elif isinstance(opt, optinterpreter.UserBooleanOption): + elif isinstance(opt, mesonlib.UserBooleanOption): typestr = 'boolean' - elif isinstance(opt, optinterpreter.UserComboOption): + elif isinstance(opt, mesonlib.UserComboOption): optdict['choices'] = opt.choices typestr = 'combo' + elif isinstance(opt, mesonlib.UserStringArrayOption): + typestr = 'stringarray' else: raise RuntimeError("Unknown option type") optdict['type'] = typestr optdict['description'] = opt.description optlist.append(optdict) - print(json.dumps(optlist)) def list_buildsystem_files(coredata, builddata): src_dir = builddata.environment.get_source_dir() diff --git a/mesonlib.py b/mesonlib.py index d7c40f4..0c7c308 100644 --- a/mesonlib.py +++ b/mesonlib.py @@ -255,3 +255,79 @@ def replace_if_different(dst, dst_tmp): pass os.replace(dst_tmp, dst) +class UserOption: + def __init__(self, name, description): + super().__init__() + self.name = name + self.description = description + + def parse_string(self, valuestring): + return valuestring + +class UserStringOption(UserOption): + def __init__(self, name, description, value): + super().__init__(name, description) + self.set_value(value) + + def set_value(self, newvalue): + if not isinstance(newvalue, str): + raise MesonException('Value "%s" for string option "%s" is not a string.' % (str(newvalue), self.name)) + self.value = newvalue + +class UserBooleanOption(UserOption): + def __init__(self, name, description, value): + super().__init__(name, description) + self.set_value(value) + + def tobool(self, thing): + if isinstance(thing, bool): + return thing + if thing.lower() == 'true': + return True + if thing.lower() == 'false': + return False + raise MesonException('Value %s is not boolean (true or false).' % thing) + + def set_value(self, newvalue): + self.value = self.tobool(newvalue) + + def parse_string(self, valuestring): + if valuestring == 'false': + return False + if valuestring == 'true': + return True + raise MesonException('Value "%s" for boolean option "%s" is not a boolean.' % (valuestring, self.name)) + +class UserComboOption(UserOption): + def __init__(self, name, description, choices, value): + super().__init__(name, description) + self.choices = choices + if not isinstance(self.choices, list): + raise MesonException('Combo choices must be an array.') + for i in self.choices: + if not isinstance(i, str): + raise MesonException('Combo choice elements must be strings.') + self.set_value(value) + + def set_value(self, newvalue): + if newvalue not in self.choices: + optionsstring = ', '.join(['"%s"' % (item,) for item in self.choices]) + raise MesonException('Value "%s" for combo option "%s" is not one of the choices. Possible choices are: %s.' % (newvalue, self.name, optionsstring)) + self.value = newvalue + +class UserStringArrayOption(UserOption): + def __init__(self, name, description, value): + super().__init__(name, description) + self.set_value(value) + + def set_value(self, newvalue): + if isinstance(newvalue, str): + if not newvalue.startswith('['): + raise MesonException('Valuestring does not define an array: ' + newvalue) + newvalue = eval(newvalue, {}, {}) # Yes, it is unsafe. + if not isinstance(newvalue, list): + raise MesonException('String array value is not an array.') + for i in newvalue: + if not isinstance(i, str): + raise MesonException('String array element not a string.') + self.value = newvalue diff --git a/ninjabackend.py b/ninjabackend.py index ce78f67..bd074bf 100644 --- a/ninjabackend.py +++ b/ninjabackend.py @@ -1454,6 +1454,7 @@ rule FORTRAN_DEP_HACK commands = [] commands += linker.get_linker_always_args() commands += linker.get_buildtype_linker_args(self.environment.coredata.buildtype) + commands += linker.get_option_link_args(self.environment.coredata.compiler_options) if not(isinstance(target, build.StaticLibrary)): commands += self.environment.coredata.external_link_args[linker.get_language()] if isinstance(target, build.Executable): diff --git a/optinterpreter.py b/optinterpreter.py index 6906d31..d66aa1f 100644 --- a/optinterpreter.py +++ b/optinterpreter.py @@ -1,4 +1,4 @@ -# Copyright 2013-2014 The Meson development team +# Copyright 2013-2015 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -13,74 +13,53 @@ # limitations under the License. import mparser -import coredata +import coredata, mesonlib import os, re forbidden_option_names = coredata.builtin_options +forbidden_prefixes = {'c_': True, + 'cpp_': True, + 'rust_': True, + 'fortran_': True, + 'objc_': True, + 'objcpp_': True, + 'vala_': True, + 'csharp_': True + } + +def is_invalid_name(name): + if name in forbidden_option_names: + return True + if name in forbidden_prefixes: + return True + return False class OptionException(coredata.MesonException): pass optname_regex = re.compile('[^a-zA-Z0-9_-]') -class UserOption: - def __init__(self, name, kwargs): - super().__init__() - self.description = kwargs.get('description', '') - self.name = name - - def parse_string(self, valuestring): - return valuestring - -class UserStringOption(UserOption): - def __init__(self, name, kwargs): - super().__init__(name, kwargs) - self.set_value(kwargs.get('value', '')) - - def set_value(self, newvalue): - if not isinstance(newvalue, str): - raise OptionException('Value "%s" for string option "%s" is not a string.' % (str(newvalue), self.name)) - self.value = newvalue - -class UserBooleanOption(UserOption): - def __init__(self, name, kwargs): - super().__init__(name, kwargs) - self.set_value(kwargs.get('value', 'true')) - - def set_value(self, newvalue): - if not isinstance(newvalue, bool): - raise OptionException('Value "%s" for boolean option "%s" is not a boolean.' % (str(newvalue), self.name)) - self.value = newvalue - - def parse_string(self, valuestring): - if valuestring == 'false': - return False - if valuestring == 'true': - return True - raise OptionException('Value "%s" for boolean option "%s" is not a boolean.' % (valuestring, self.name)) - -class UserComboOption(UserOption): - def __init__(self, name, kwargs): - super().__init__(name, kwargs) - if 'choices' not in kwargs: - raise OptionException('Combo option missing "choices" keyword.') - self.choices = kwargs['choices'] - if not isinstance(self.choices, list): - raise OptionException('Combo choices must be an array.') - for i in self.choices: - if not isinstance(i, str): - raise OptionException('Combo choice elements must be strings.') - self.value = kwargs.get('value', self.choices[0]) - - def set_value(self, newvalue): - if newvalue not in self.choices: - optionsstring = ', '.join(['"%s"' % (item,) for item in self.choices]) - raise OptionException('Value "%s" for combo option "%s" is not one of the choices. Possible choices are: %s.' % (newvalue, self.name, optionsstring)) - self.value = newvalue - -option_types = {'string' : UserStringOption, - 'boolean' : UserBooleanOption, - 'combo' : UserComboOption, +def StringParser(name, description, kwargs): + return mesonlib.UserStringOption(name, description, + kwargs.get('value', '')) + +def BooleanParser(name, description, kwargs): + return mesonlib.UserBooleanOption(name, description, kwargs.get('value', True)) + +def ComboParser(name, description, kwargs): + if 'choices' not in kwargs: + raise OptionException('Combo option missing "choices" keyword.') + choices = kwargs['choices'] + if not isinstance(choices, list): + raise OptionException('Combo choices must be an array.') + for i in choices: + if not isinstance(i, str): + raise OptionException('Combo choice elements must be strings.') + return mesonlib.UserComboOption(name, description, choices, kwargs.get('value', choices[0])) + +option_types = {'string' : StringParser, + 'boolean' : BooleanParser, + 'combo' : ComboParser, } class OptionInterpreter: @@ -157,11 +136,11 @@ class OptionInterpreter: raise OptionException('Positional argument must be a string.') if optname_regex.search(opt_name) is not None: raise OptionException('Option names can only contain letters, numbers or dashes.') - if opt_name in forbidden_option_names: + if is_invalid_name(opt_name): raise OptionException('Option name %s is reserved.' % opt_name) if self.subproject != '': opt_name = self.subproject + ':' + opt_name - opt = option_types[opt_type](opt_name, kwargs) + opt = option_types[opt_type](opt_name, kwargs.get('description', ''), kwargs) if opt.description == '': opt.description = opt_name if opt_name in self.cmd_line_options: diff --git a/test cases/frameworks/1 boost/meson.build b/test cases/frameworks/1 boost/meson.build index 327d36f..454c161 100644 --- a/test cases/frameworks/1 boost/meson.build +++ b/test cases/frameworks/1 boost/meson.build @@ -1,11 +1,5 @@ project('boosttest', 'cpp') -if meson.get_compiler('cpp').get_id() != 'msvc' - add_global_arguments('-std=c++11', language : 'cpp') -else - add_global_arguments('/EHsc', language : 'cpp') -endif - # We want to have multiple separate configurations of Boost # within one project. The need to be independent of each other. # Use one without a library dependency and one with it. diff --git a/test cases/frameworks/4 qt5/meson.build b/test cases/frameworks/4 qt5/meson.build index 67761e9..bce9dbd 100644 --- a/test cases/frameworks/4 qt5/meson.build +++ b/test cases/frameworks/4 qt5/meson.build @@ -3,10 +3,6 @@ project('qt5 build test', 'cpp') qt5 = import('qt5') qt5dep = dependency('qt5', modules : ['Core', 'Gui', 'Widgets']) -if meson.get_compiler('cpp').get_id() != 'msvc' - add_global_arguments('-std=c++11', language : 'cpp') -endif - prep = qt5.preprocess( moc_headers : ['mainWindow.h'], # These need to be fed through the moc tool before use. ui_files : 'mainWindow.ui', # XML files that need to be compiled with the uic tol. diff --git a/test cases/frameworks/9 wxwidgets/meson.build b/test cases/frameworks/9 wxwidgets/meson.build index ecf0b39..4f4d251 100644 --- a/test cases/frameworks/9 wxwidgets/meson.build +++ b/test cases/frameworks/9 wxwidgets/meson.build @@ -1,7 +1,5 @@ project('wxwidgets test', 'cpp') -add_global_arguments('-std=c++11', language : 'cpp') - wxd = dependency('wxwidgets', version : '>=3.0.0') wp = executable('wxprog', 'wxprog.cpp', |