diff options
-rw-r--r-- | README.md | 6 | ||||
-rw-r--r-- | mesonbuild/backend/backends.py | 13 | ||||
-rw-r--r-- | mesonbuild/backend/vs2010backend.py | 106 | ||||
-rw-r--r-- | mesonbuild/build.py | 10 | ||||
-rw-r--r-- | mesonbuild/compilers.py | 40 | ||||
-rw-r--r-- | mesonbuild/coredata.py | 2 | ||||
-rw-r--r-- | mesonbuild/dependencies.py | 19 | ||||
-rw-r--r-- | mesonbuild/environment.py | 3 | ||||
-rw-r--r-- | mesonbuild/interpreter.py | 89 | ||||
-rw-r--r-- | mesonbuild/mconf.py | 1 | ||||
-rw-r--r-- | mesonbuild/mesonlib.py | 4 | ||||
-rw-r--r-- | mesonbuild/mesonmain.py | 2 | ||||
-rw-r--r-- | mesonbuild/optinterpreter.py | 2 | ||||
-rw-r--r-- | mesonbuild/scripts/meson_install.py | 16 | ||||
-rw-r--r-- | test cases/common/42 string formatting/meson.build | 6 | ||||
-rw-r--r-- | test cases/common/68 number arithmetic/meson.build | 3 | ||||
-rw-r--r-- | test cases/common/91 plusassign/meson.build | 25 | ||||
-rw-r--r-- | test cases/frameworks/4 qt5/meson.build | 22 | ||||
-rw-r--r-- | test cases/linuxlike/2 external library/meson.build | 5 |
19 files changed, 256 insertions, 118 deletions
@@ -18,8 +18,10 @@ options here>`. Meson is also available from [PyPi](https://pypi.python.org/pypi/meson), so it can be installed -with `pip install meson` (this does not require a source checkout, pip -will download the package automatically). +with `pip3 install meson` (this does not require a source checkout, +pip will download the package automatically). The exact command to +type to install with pip can very between systems, be sure to use the +Python 3 version of pip. ####Running diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py index 5c2f709..3a24f30 100644 --- a/mesonbuild/backend/backends.py +++ b/mesonbuild/backend/backends.py @@ -142,7 +142,7 @@ class Backend(): return os.path.relpath(os.path.join('dummyprefixdir', todir),\ os.path.join('dummyprefixdir', fromdir)) - def flatten_object_list(self, target, proj_dir_to_build_root=''): + def flatten_object_list(self, target, proj_dir_to_build_root='', include_dir_names=True): obj_list = [] for obj in target.get_objects(): if isinstance(obj, str): @@ -150,7 +150,7 @@ class Backend(): self.build_to_src, target.get_subdir(), obj) obj_list.append(o) elif isinstance(obj, build.ExtractedObjects): - obj_list += self.determine_ext_objs(obj, proj_dir_to_build_root) + obj_list += self.determine_ext_objs(obj, proj_dir_to_build_root, include_dir_names) else: raise MesonException('Unknown data type in object list.') return obj_list @@ -207,7 +207,7 @@ class Backend(): return c raise RuntimeError('Unreachable code') - def determine_ext_objs(self, extobj, proj_dir_to_build_root=''): + def determine_ext_objs(self, extobj, proj_dir_to_build_root='', include_dir_names=True): result = [] targetdir = self.get_target_private_dir(extobj.target) suffix = '.' + self.environment.get_object_suffix() @@ -221,7 +221,12 @@ class Backend(): if pathsegs[0] == 'subprojects': pathsegs = pathsegs[2:] fixedpath = os.sep.join(pathsegs) - objbase = osrc.fname.replace('/', '_').replace('\\', '_') + if include_dir_names: + objbase = osrc_base.replace('/', '_').replace('\\', '_') + else: + # vs2010 backend puts all obj files without directory prefixes into build dir, so just + # use the file name without a directory (will be stripped by os.path.basename() below). + objbase = osrc_base objname = os.path.join(proj_dir_to_build_root, targetdir, os.path.basename(objbase) + suffix) result.append(objname) diff --git a/mesonbuild/backend/vs2010backend.py b/mesonbuild/backend/vs2010backend.py index 0d7ac06..84ef8c3 100644 --- a/mesonbuild/backend/vs2010backend.py +++ b/mesonbuild/backend/vs2010backend.py @@ -36,7 +36,7 @@ class Vs2010Backend(backends.Backend): super().__init__(build) self.project_file_version = '10.0.30319.1' # foo.c compiles to foo.obj, not foo.c.obj - self.source_suffix_in_obj = False + self.source_suffix_in_objs = False def generate_custom_generator_commands(self, target, parent_node): all_output_files = [] @@ -116,14 +116,14 @@ class Vs2010Backend(backends.Backend): result = {} for o in obj_list: if isinstance(o, build.ExtractedObjects): - result[o.target.get_basename()] = True + result[o.target.get_id()] = True return result.keys() def determine_deps(self, p): all_deps = {} target = self.build.targets[p[0]] if isinstance(target, build.CustomTarget): - for d in target.dependencies: + for d in target.get_target_dependencies(): all_deps[d.get_id()] = True return all_deps if isinstance(target, build.RunTarget): @@ -220,14 +220,21 @@ class Vs2010Backend(backends.Backend): sources = [] headers = [] objects = [] + languages = [] for i in srclist: if self.environment.is_header(i): headers.append(i) elif self.environment.is_object(i): objects.append(i) - else: + elif self.environment.is_source(i): sources.append(i) - return (sources, headers, objects) + lang = self.lang_from_source_file(i) + if lang not in languages: + languages.append(lang) + else: + # Everything that is not an object or source file is considered a header. + headers.append(i) + return (sources, headers, objects, languages) def target_to_build_root(self, target): if target.subdir == '': @@ -312,16 +319,20 @@ class Vs2010Backend(backends.Backend): tree = ET.ElementTree(root) tree.write(ofname, encoding='utf-8', xml_declaration=True) + @classmethod + def lang_from_source_file(cls, src): + ext = src.split('.')[-1] + if ext in compilers.c_suffixes: + return 'c' + if ext in compilers.cpp_suffixes: + return 'cpp' + raise MesonException('Could not guess language from source file %s.' % src) + def add_pch(self, inc_cl, proj_to_src_dir, pch_sources, source_file): if len(pch_sources) <= 1: # We only need per file precompiled headers if we have more than 1 language. return - if source_file.split('.')[-1] in compilers.c_suffixes: - lang = 'c' - elif source_file.split('.')[-1] in compilers.cpp_suffixes: - lang = 'cpp' - else: - return + lang = Vs2010Backend.lang_from_source_file(source_file) header = os.path.join(proj_to_src_dir, pch_sources[lang][0]) pch_file = ET.SubElement(inc_cl, 'PrecompiledHeaderFile') pch_file.text = header @@ -330,6 +341,13 @@ class Vs2010Backend(backends.Backend): pch_out = ET.SubElement(inc_cl, 'PrecompiledHeaderOutputFile') pch_out.text = '$(IntDir)$(TargetName)-%s.pch' % lang + def add_additional_options(self, source_file, parent_node, extra_args, has_additional_options_set): + if has_additional_options_set: + # We only need per file options if they were not set per project. + return + lang = Vs2010Backend.lang_from_source_file(source_file) + ET.SubElement(parent_node, "AdditionalOptions").text = ' '.join(extra_args[lang]) + ' %(AdditionalOptions)' + def gen_vcxproj(self, target, ofname, guid, compiler): mlog.debug('Generating vcxproj %s.' % target.name) entrypoint = 'WinMainCRTStartup' @@ -353,7 +371,7 @@ class Vs2010Backend(backends.Backend): down = self.target_to_build_root(target) proj_to_src_root = os.path.join(down, self.build_to_src) proj_to_src_dir = os.path.join(proj_to_src_root, target.subdir) - (sources, headers, objects) = self.split_sources(target.sources) + (sources, headers, objects, languages) = self.split_sources(target.sources) buildtype = self.buildtype project_name = target.name target_name = target.name @@ -386,7 +404,7 @@ class Vs2010Backend(backends.Backend): ET.SubElement(type_config, 'UseDebugLibraries').text = 'true' ET.SubElement(root, 'Import', Project='$(VCTargetsPath)\Microsoft.Cpp.props') generated_files = self.generate_custom_generator_commands(target, root) - (gen_src, gen_hdrs, gen_objs) = self.split_sources(generated_files) + (gen_src, gen_hdrs, gen_objs, gen_langs) = self.split_sources(generated_files) direlem = ET.SubElement(root, 'PropertyGroup') fver = ET.SubElement(direlem, '_ProjectFileVersion') fver.text = self.project_file_version @@ -408,28 +426,44 @@ class Vs2010Backend(backends.Backend): if cur_dir == '': cur_dir= '.' inc_dirs.append(cur_dir) - extra_args = [] - # SUCKS, VS can not handle per-language type flags, so just use - # them all. - extra_args += compiler.get_buildtype_args(self.buildtype) - for l in self.environment.coredata.external_args.values(): - for a in l: - extra_args.append(a) - for l in self.build.global_args.values(): - for a in l: - extra_args.append(a) - for l in target.extra_args.values(): - for a in l: - extra_args.append(a) + + extra_args = {'c': [], 'cpp': []} + for l, args in self.environment.coredata.external_args.items(): + if l in extra_args: + extra_args[l] += args + for l, args in self.build.global_args.items(): + if l in extra_args: + extra_args[l] += args + for l, args in target.extra_args.items(): + if l in extra_args: + extra_args[l] += args + general_args = compiler.get_buildtype_args(self.buildtype) # FIXME all the internal flags of VS (optimization etc) are represented # by their own XML elements. In theory we should split all flags to those # that have an XML element and those that don't and serialise them # properly. This is a crapton of work for no real gain, so just dump them # here. - extra_args = compiler.get_option_compile_args(self.environment.coredata.compiler_options) - if len(extra_args) > 0: - extra_args.append('%(AdditionalOptions)') - ET.SubElement(clconf, "AdditionalOptions").text = ' '.join(extra_args) + general_args += compiler.get_option_compile_args(self.environment.coredata.compiler_options) + for d in target.get_external_deps(): + try: + general_args += d.compile_args + except AttributeError: + pass + + languages += gen_langs + has_language_specific_args = any(l != extra_args['c'] for l in extra_args.values()) + additional_options_set = False + if not has_language_specific_args or len(languages) == 1: + if len(languages) == 0: + extra_args = [] + else: + extra_args = extra_args[languages[0]] + extra_args = general_args + extra_args + if len(extra_args) > 0: + extra_args.append('%(AdditionalOptions)') + ET.SubElement(clconf, "AdditionalOptions").text = ' '.join(extra_args) + additional_options_set = True + for d in target.include_dirs: for i in d.incdirs: curdir = os.path.join(d.curdir, i) @@ -490,9 +524,10 @@ class Vs2010Backend(backends.Backend): rel_path = self.relpath(lobj.subdir, target.subdir) linkname = os.path.join(rel_path, lobj.get_import_filename()) additional_links.append(linkname) - for o in self.flatten_object_list(target, down): + additional_objects = [] + for o in self.flatten_object_list(target, down, include_dir_names=False): assert(isinstance(o, str)) - additional_links.append(o) + additional_objects.append(o) if len(additional_links) > 0: additional_links.append('%(AdditionalDependencies)') ET.SubElement(link, 'AdditionalDependencies').text = ';'.join(additional_links) @@ -530,10 +565,12 @@ class Vs2010Backend(backends.Backend): relpath = s.rel_to_builddir(proj_to_src_root) inc_cl = ET.SubElement(inc_src, 'CLCompile', Include=relpath) self.add_pch(inc_cl, proj_to_src_dir, pch_sources, s) + self.add_additional_options(s, inc_cl, extra_args, additional_options_set) for s in gen_src: relpath = self.relpath(s, target.subdir) inc_cl = ET.SubElement(inc_src, 'CLCompile', Include=relpath) self.add_pch(inc_cl, proj_to_src_dir, pch_sources, s) + self.add_additional_options(s, inc_cl, extra_args, additional_options_set) for lang in pch_sources: header, impl, suffix = pch_sources[lang] relpath = os.path.join(proj_to_src_dir, impl) @@ -546,14 +583,17 @@ class Vs2010Backend(backends.Backend): # MSBuild searches for the header relative from the implementation, so we have to use # just the file name instead of the relative path to the file. pch_file.text = os.path.split(header)[1] + self.add_additional_options(impl, inc_cl, extra_args, additional_options_set) - if len(objects) > 0: + if len(objects) + len(additional_objects) > 0: # Do not add gen_objs to project file. Those are automatically used by MSBuild, because they are part of # the CustomBuildStep Outputs. inc_objs = ET.SubElement(root, 'ItemGroup') for s in objects: relpath = s.rel_to_builddir(proj_to_src_root) ET.SubElement(inc_objs, 'Object', Include=relpath) + for s in additional_objects: + ET.SubElement(inc_objs, 'Object', Include=s) ET.SubElement(root, 'Import', Project='$(VCTargetsPath)\Microsoft.Cpp.targets') # Reference the regen target. ig = ET.SubElement(root, 'ItemGroup') diff --git a/mesonbuild/build.py b/mesonbuild/build.py index 315e4bc..ab9d0d5 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -806,6 +806,16 @@ class CustomTarget: def get_id(self): return self.name + self.type_suffix() + def get_target_dependencies(self): + deps = self.dependencies[:] + deps += self.extra_depends + for c in self.sources: + if hasattr(c, 'held_object'): + c = c.held_object + if isinstance(c, BuildTarget) or isinstance(c, CustomTarget): + deps.append(c) + return deps + def process_kwargs(self, kwargs): self.sources = kwargs.get('input', []) if not isinstance(self.sources, list): diff --git a/mesonbuild/compilers.py b/mesonbuild/compilers.py index f3ddf8d..cc554c4 100644 --- a/mesonbuild/compilers.py +++ b/mesonbuild/compilers.py @@ -190,7 +190,7 @@ class Compiler(): def unix_compile_flags_to_native(self, args): return args - def find_library(self, libname): + def find_library(self, libname, extra_dirs): raise EnvironmentException('Language {} does not support library finding.'.format(self.language)) class CCompiler(Compiler): @@ -298,6 +298,9 @@ class CCompiler(Compiler): def get_pch_name(self, header_name): return os.path.split(header_name)[-1] + '.' + self.get_pch_suffix() + def get_linker_search_args(self, dirname): + return ['-L'+dirname] + def sanity_check(self, work_dir): mlog.debug('Sanity testing C compiler:', ' '.join(self.exelist)) mlog.debug('Is cross compiler: %s.' % str(self.is_cross)) @@ -566,14 +569,17 @@ void bar() { ''' return self.compiles(templ % (prefix, typename), extra_args) - def find_library(self, libname): + def find_library(self, libname, extra_dirs): code = '''int main(int argc, char **argv) { return 0; } ''' - linkarg = '-l' + libname - if self.links(code, extra_args=[linkarg]): - return linkarg + args = [] + for i in extra_dirs: + args += self.get_linker_search_args(i) + args.append('-l' + libname) + if self.links(code, extra_args=args): + return args return None def thread_flags(self): @@ -1144,6 +1150,9 @@ class VisualStudioCCompiler(CCompiler): def get_linker_output_args(self, outputname): return ['/OUT:' + outputname] + def get_linker_search_args(self, dirname): + return ['/LIBPATH:' + dirname] + def get_pic_args(self): return [] # PIC is handled by the loader on Windows @@ -1175,6 +1184,19 @@ class VisualStudioCCompiler(CCompiler): def build_rpath_args(self, build_dir, rpath_paths, install_rpath): return [] + def find_library(self, libname, extra_dirs): + code = '''int main(int argc, char **argv) { + return 0; +} + ''' + args = [] + for i in extra_dirs: + args += self.get_linker_search_args(i) + args.append(libname + '.lib') + if self.links(code, extra_args=args): + return args + return None + # FIXME, no idea what these should be. def thread_flags(self): return [] @@ -1198,7 +1220,13 @@ class VisualStudioCCompiler(CCompiler): i = '/LIBPATH:' + i[2:] # Translate GNU-style -lfoo library name to the import library if i.startswith('-l'): - i = i[2:] + '.lib' + name = i[2:] + if name in ('m', 'c'): + # With MSVC, these are provided by the C runtime which is + # linked in by default + continue + else: + i = name + '.lib' result.append(i) return result diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py index 2a73577..9e927e3 100644 --- a/mesonbuild/coredata.py +++ b/mesonbuild/coredata.py @@ -28,6 +28,7 @@ builtin_options = {'buildtype': True, 'unity': True, 'prefix': True, 'libdir' : True, + 'libexecdir' : True, 'bindir' : True, 'includedir' : True, 'datadir' : True, @@ -159,6 +160,7 @@ class CoreData(): 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) diff --git a/mesonbuild/dependencies.py b/mesonbuild/dependencies.py index ee2dd62..b9f5c89 100644 --- a/mesonbuild/dependencies.py +++ b/mesonbuild/dependencies.py @@ -385,30 +385,29 @@ class ExternalProgram(): return self.name class ExternalLibrary(Dependency): - def __init__(self, name, fullpath=None, silent=False): + def __init__(self, name, link_args=None, silent=False): super().__init__() self.name = name # Rename fullpath to link_args once standalone find_library() gets removed. - if fullpath is not None: - if isinstance(fullpath, list): - self.fullpath = fullpath + if link_args is not None: + if isinstance(link_args, list): + self.link_args = link_args else: - self.fullpath = [fullpath] + self.link_args = [link_args] else: - self.fullpath = fullpath + self.link_args = link_args if not silent: if self.found(): - mlog.log('Library', mlog.bold(name), 'found:', mlog.green('YES'), - '(%s)' % self.fullpath) + mlog.log('Library', mlog.bold(name), 'found:', mlog.green('YES')) else: mlog.log('Library', mlog.bold(name), 'found:', mlog.red('NO')) def found(self): - return self.fullpath is not None + return self.link_args is not None def get_link_args(self): if self.found(): - return self.fullpath + return self.link_args return [] class BoostDependency(Dependency): diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py index 1586248..61954af 100644 --- a/mesonbuild/environment.py +++ b/mesonbuild/environment.py @@ -590,6 +590,9 @@ class Environment(): def get_libdir(self): return self.coredata.get_builtin_option('libdir') + def get_libexecdir(self): + return self.coredata.get_builtin_option('libexecdir') + def get_bindir(self): return self.coredata.get_builtin_option('bindir') diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index 2ade18a..04bfa07 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -27,8 +27,6 @@ from functools import wraps import importlib -find_lib_deprecation_printed = False - class InterpreterException(coredata.MesonException): pass @@ -762,8 +760,14 @@ class CompilerHolder(InterpreterObject): required = kwargs.get('required', True) if not isinstance(required, bool): raise InterpreterException('required must be boolean.') - linkarg = self.compiler.find_library(libname) - lib = dependencies.ExternalLibrary(libname, linkarg) + search_dirs = kwargs.get('dirs', []) + for i in search_dirs: + if not os.path.isabs(i): + raise InvalidCode('Search directory %s is not an absolute path.' % i) + linkargs = self.compiler.find_library(libname, search_dirs) + if required and linkargs is None: + raise InterpreterException('Library %s not found'.format(libname)) + lib = dependencies.ExternalLibrary(libname, linkargs) return ExternalLibraryHolder(lib) class ModuleState: @@ -921,7 +925,7 @@ class Interpreter(): mesonfile = os.path.join(self.source_root, self.subdir, environment.build_filename) if not os.path.isfile(mesonfile): raise InvalidArguments('Missing Meson file in %s' % mesonfile) - code = open(mesonfile).read() + code = open(mesonfile, encoding='utf8').read() if len(code.strip()) == 0: raise InvalidCode('Builder file is empty.') assert(isinstance(code, str)) @@ -1542,40 +1546,7 @@ class Interpreter(): return progobj def func_find_library(self, node, args, kwargs): - global find_lib_deprecation_printed - if not find_lib_deprecation_printed: - find_lib_deprecation_printed = True - mlog.log(mlog.red('DEPRECATION:'), 'find_library() is deprecated, use the corresponding method in compiler object instead.') - self.validate_arguments(args, 1, [str]) - required = kwargs.get('required', True) - if not isinstance(required, bool): - raise InvalidArguments('"required" argument must be a boolean.') - libname = args[0] - # We do not cache found libraries because they can come - # and go between invocations wildly. As an example we - # may find the 64 bit version but need instead the 32 bit - # one that is not installed. If we cache the found path - # then we will never found the new one if it get installed. - # This causes a bit of a slowdown as libraries are rechecked - # on every regen, but since it is a fast operation it should be - # ok. - if 'dirs' in kwargs: - search_dirs = kwargs['dirs'] - if not isinstance(search_dirs, list): - search_dirs = [search_dirs] - for i in search_dirs: - if not isinstance(i, str): - raise InvalidCode('Directory entry is not a string.') - if not os.path.isabs(i): - raise InvalidCode('Search directory %s is not an absolute path.' % i) - else: - search_dirs = None - result = self.environment.find_library(libname, search_dirs) - extlib = dependencies.ExternalLibrary(libname, result) - libobj = ExternalLibraryHolder(extlib) - if required and not libobj.found(): - raise InvalidArguments('External library "%s" not found.' % libname) - return libobj + mlog.log(mlog.red('DEPRECATION:'), 'find_library() is removed, use the corresponding method in compiler object instead.') def func_dependency(self, node, args, kwargs): self.validate_arguments(args, 1, [str]) @@ -1812,7 +1783,7 @@ class Interpreter(): absname = os.path.join(self.environment.get_source_dir(), buildfilename) if not os.path.isfile(absname): raise InterpreterException('Nonexistant build def file %s.' % buildfilename) - code = open(absname).read() + code = open(absname, encoding='utf8').read() assert(isinstance(code, str)) try: codeblock = mparser.Parser(code).parse() @@ -2046,6 +2017,30 @@ class Interpreter(): reduced_pos = [reduced_pos] return (reduced_pos, reduced_kw) + def bool_method_call(self, obj, method_name, args): + obj = self.to_native(obj) + (posargs, _) = self.reduce_arguments(args) + if method_name == 'to_string': + if len(posargs) == 0: + if obj == True: + return 'true' + else: + return 'false' + elif len(posargs) == 2 and isinstance(posargs[0], str) and isinstance(posargs[1], str): + if obj == True: + return posargs[0] + else: + return posargs[1] + else: + raise InterpreterException('bool.to_string() must have either no arguments or exactly two string arguments.') + elif method_name == 'to_int': + if obj == True: + return 1 + else: + return 0 + else: + raise InterpreterException('Unknown method "%s" for a boolean.' % method_name) + def string_method_call(self, obj, method_name, args): obj = self.to_native(obj) (posargs, _) = self.reduce_arguments(args) @@ -2118,6 +2113,8 @@ class Interpreter(): obj = obj.get_value() if isinstance(obj, str): return self.string_method_call(obj, method_name, args) + if isinstance(obj, bool): + return self.bool_method_call(obj, method_name, args) if isinstance(obj, list): return self.array_method_call(obj, method_name, self.reduce_arguments(args)[0]) if not isinstance(obj, InterpreterObject): @@ -2198,8 +2195,16 @@ class Interpreter(): # Remember that all variables are immutable. We must always create a # full new variable and then assign it. old_variable = self.get_variable(varname) - if not isinstance(old_variable, list): - raise InvalidArguments('The += operator currently only works with arrays.') + if isinstance(old_variable, str): + if not isinstance(addition, str): + raise InvalidArguments('The += operator requires a string on the right hand side if the variable on the left is a string') + new_value = old_variable + addition + elif isinstance(old_variable, int): + if not isinstance(addition, int): + raise InvalidArguments('The += operator requires an int on the right hand side if the variable on the left is an int') + new_value = old_variable + addition + elif not isinstance(old_variable, list): + raise InvalidArguments('The += operator currently only works with arrays, strings or ints ') # Add other data types here. else: if isinstance(addition, list): diff --git a/mesonbuild/mconf.py b/mesonbuild/mconf.py index 03cbe55..72b3fbe 100644 --- a/mesonbuild/mconf.py +++ b/mesonbuild/mconf.py @@ -154,6 +154,7 @@ class Conf: 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'), '']) diff --git a/mesonbuild/mesonlib.py b/mesonbuild/mesonlib.py index ac605bf..2087eee 100644 --- a/mesonbuild/mesonlib.py +++ b/mesonbuild/mesonlib.py @@ -173,6 +173,10 @@ def default_libdir(): return 'lib64' return 'lib' +def default_libexecdir(): + # There is no way to auto-detect this, so it must be set at build time + return 'libexec' + def get_library_dirs(): if is_windows(): return ['C:/mingw/lib'] # Fixme diff --git a/mesonbuild/mesonmain.py b/mesonbuild/mesonmain.py index 95e6731..0186006 100644 --- a/mesonbuild/mesonmain.py +++ b/mesonbuild/mesonmain.py @@ -39,6 +39,8 @@ 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', diff --git a/mesonbuild/optinterpreter.py b/mesonbuild/optinterpreter.py index f0c93ae..30a26ab 100644 --- a/mesonbuild/optinterpreter.py +++ b/mesonbuild/optinterpreter.py @@ -73,7 +73,7 @@ class OptionInterpreter: def process(self, option_file): try: - ast = mparser.Parser(open(option_file, 'r').read()).parse() + ast = mparser.Parser(open(option_file, 'r', encoding='utf8').read()).parse() except coredata.MesonException as me: me.file = option_file raise me diff --git a/mesonbuild/scripts/meson_install.py b/mesonbuild/scripts/meson_install.py index 792af6c..8e3d0ca 100644 --- a/mesonbuild/scripts/meson_install.py +++ b/mesonbuild/scripts/meson_install.py @@ -118,10 +118,14 @@ def run_install_script(d): if platform.system().lower() == 'windows' and suffix != '.bat': first_line = open(script).readline().strip() if first_line.startswith('#!'): - commands = first_line[2:].split('#')[0].strip().split() - commands[0] = shutil.which(commands[0].split('/')[-1]) - if commands[0] is None: - raise RuntimeError("Don't know how to run script %s." % script) + if shutil.which(first_line[2:]): + commands = [first_line[2:]] + else: + commands = first_line[2:].split('#')[0].strip().split() + commands[0] = shutil.which(commands[0].split('/')[-1]) + if commands[0] is None: + commands + raise RuntimeError("Don't know how to run script %s." % script) final_command = commands + [script] + i.cmd_arr[1:] else: final_command = i.cmd_arr @@ -129,8 +133,8 @@ def run_install_script(d): rc = subprocess.call(final_command, env=child_env) if rc != 0: sys.exit(rc) - except Exception: - print('Failed to run install script:', i.cmd_arr[0]) + except: + print('Failed to run install script:', *i.cmd_arr) sys.exit(1) def is_elf_platform(): diff --git a/test cases/common/42 string formatting/meson.build b/test cases/common/42 string formatting/meson.build index 99855b3..c2ee151 100644 --- a/test cases/common/42 string formatting/meson.build +++ b/test cases/common/42 string formatting/meson.build @@ -45,3 +45,9 @@ assert('#include <foo/bar.h>'.underscorify() == '_include__foo_bar_h_', 'Broken assert('Do SomeThing 09'.underscorify() == 'Do_SomeThing_09', 'Broken underscorify') assert('3'.to_int() == 3, 'String int conversion does not work.') + +assert(true.to_string() == 'true', 'bool string conversion failed') +assert(false.to_string() == 'false', 'bool string conversion failed') +assert(true.to_string('yes', 'no') == 'yes', 'bool string conversion with args failed') +assert(false.to_string('yes', 'no') == 'no', 'bool string conversion with args failed') +assert('@0@'.format(true) == 'true', 'bool string formatting failed') diff --git a/test cases/common/68 number arithmetic/meson.build b/test cases/common/68 number arithmetic/meson.build index 3872a11..4b98d73 100644 --- a/test cases/common/68 number arithmetic/meson.build +++ b/test cases/common/68 number arithmetic/meson.build @@ -32,3 +32,6 @@ assert(not(3 > 4), 'Gt broken') assert(4 >= 3, 'Gte broken') assert(not(3 >= 4), 'Gte broken') assert(3 >= 3, 'Gte broken') + +assert(true.to_int() == 1,'bool to_int() broken') +assert(false.to_int() == 0,'bool to_int() broken') diff --git a/test cases/common/91 plusassign/meson.build b/test cases/common/91 plusassign/meson.build index c1e47e0..ac477e7 100644 --- a/test cases/common/91 plusassign/meson.build +++ b/test cases/common/91 plusassign/meson.build @@ -43,3 +43,28 @@ x += x if x.length() != 4 error('Incorrect selfappend.') endif + +# += on strings + +bra = 'bra' +foo = 'A' +foo += bra +foo += 'cada' +foo += bra +assert (foo == 'Abracadabra', 'string += failure [@0@]'.format(foo)) +assert (bra == 'bra', 'string += modified right argument!') +foo += ' ' + foo +assert (foo == 'Abracadabra Abracadabra', 'string += failure [@0@]'.format(foo)) + +# += on ints + +foo = 5 +foo += 6 +assert (foo == 11, 'int += failure [@0@]'.format(foo)) +bar = 99 +foo += bar +assert (foo == 110, 'int += failure [@0@]'.format(foo)) +assert (bar == 99, 'int += modified right argument"') +bar += foo + 1 +assert (bar == 210, 'int += failure [@0@]'.format(bar)) +assert (foo == 110, 'int += modified right argument"') diff --git a/test cases/frameworks/4 qt5/meson.build b/test cases/frameworks/4 qt5/meson.build index bce9dbd..cfea5ba 100644 --- a/test cases/frameworks/4 qt5/meson.build +++ b/test cases/frameworks/4 qt5/meson.build @@ -4,15 +4,15 @@ qt5 = import('qt5') qt5dep = dependency('qt5', modules : ['Core', 'Gui', 'Widgets']) 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. -qresources : 'stuff.qrc', # Resource file for rcc compiler. + 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. + qresources : 'stuff.qrc', # Resource file for rcc compiler. ) q5exe = executable('qt5app', -sources : ['main.cpp', 'mainWindow.cpp', # Sources that don't need preprocessing. -prep], -dependencies : qt5dep) + sources : ['main.cpp', 'mainWindow.cpp', # Sources that don't need preprocessing. + prep], + dependencies : qt5dep) # We need a console test application because some test environments # do not have an X server. @@ -20,7 +20,7 @@ dependencies : qt5dep) qt5core = dependency('qt5', modules : 'Core') qt5coreapp = executable('q5core', 'q5core.cpp', -dependencies : qt5core) + dependencies : qt5core) test('qt5test', qt5coreapp) @@ -28,11 +28,11 @@ test('qt5test', qt5coreapp) # headers but the user must manually include moc # files from sources. manpreprocessed = qt5.preprocess( -moc_sources : 'manualinclude.cpp', -moc_headers : 'manualinclude.h') + moc_sources : 'manualinclude.cpp', + moc_headers : 'manualinclude.h') q5maninclude = executable('q5maninclude', -sources : ['manualinclude.cpp', manpreprocessed], -dependencies : qt5core) + sources : ['manualinclude.cpp', manpreprocessed], + dependencies : qt5core) test('q5maninclude', q5maninclude) diff --git a/test cases/linuxlike/2 external library/meson.build b/test cases/linuxlike/2 external library/meson.build index f83affc..5839c1a 100644 --- a/test cases/linuxlike/2 external library/meson.build +++ b/test cases/linuxlike/2 external library/meson.build @@ -1,8 +1,7 @@ project('external library', 'c') cc = meson.get_compiler('c') -zlib = find_library('z') # DEPRECATED -zlib2 = cc.find_library('z') # The modern way. +zlib = cc.find_library('z') # Verify that link testing works. linkcode = '''#include<zlib.h> @@ -25,7 +24,7 @@ assert(not cc.links(nolinkcode, name : 'Failing link'), 'Linking succeeded when e = executable('zprog', 'prog.c', dependencies : zlib) test('libtest', e) -e2 = executable('zprog_alt', 'prog.c', dependencies : zlib2) +e2 = executable('zprog_alt', 'prog.c', dependencies : zlib) test('libtest_alt', e2) # Test that ext deps work via an internal dep. |