diff options
-rw-r--r-- | manual tests/9 nostdlib/meson.build | 4 | ||||
-rw-r--r-- | mesonbuild/backend/backends.py | 11 | ||||
-rw-r--r-- | mesonbuild/backend/ninjabackend.py | 22 | ||||
-rw-r--r-- | mesonbuild/build.py | 5 | ||||
-rw-r--r-- | mesonbuild/compilers.py | 30 | ||||
-rw-r--r-- | mesonbuild/dependencies.py | 6 | ||||
-rw-r--r-- | mesonbuild/environment.py | 3 | ||||
-rw-r--r-- | mesonbuild/interpreter.py | 88 | ||||
-rw-r--r-- | mesonbuild/modules/i18n.py | 4 | ||||
-rw-r--r-- | mesonbuild/scripts/meson_install.py | 22 | ||||
-rw-r--r-- | test cases/common/58 run target/converter.py | 5 | ||||
-rwxr-xr-x | test cases/common/58 run target/fakeburner.py | 13 | ||||
-rw-r--r-- | test cases/common/58 run target/meson.build | 30 | ||||
-rw-r--r-- | test cases/failing/29 no crossprop/meson.build | 3 |
14 files changed, 204 insertions, 42 deletions
diff --git a/manual tests/9 nostdlib/meson.build b/manual tests/9 nostdlib/meson.build index 3ef743e..9c5f949 100644 --- a/manual tests/9 nostdlib/meson.build +++ b/manual tests/9 nostdlib/meson.build @@ -1,5 +1,9 @@ project('own libc', 'c') +# Not related to this test, but could not find a better place for this test. +assert(meson.get_cross_property('nonexisting', 'defaultvalue') == 'defaultvalue', + 'Cross prop getting is broken.') + # A simple project that uses its own libc. # Note that we don't need to specify anything, the flags to use diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py index ded3ea2..d2693b2 100644 --- a/mesonbuild/backend/backends.py +++ b/mesonbuild/backend/backends.py @@ -83,8 +83,9 @@ class Backend(): return i raise RuntimeError('No compiler for language ' + lang) - def get_compiler_for_source(self, src): - for i in self.build.compilers: + def get_compiler_for_source(self, src, is_cross): + comp = self.build.cross_compilers if is_cross else self.build.compilers + for i in comp: if i.can_compile(src): return i if isinstance(src, mesonlib.File): @@ -92,6 +93,7 @@ class Backend(): raise RuntimeError('No specified compiler can handle file ' + src) def get_target_filename(self, target): + assert(isinstance(target, (build.BuildTarget, build.CustomTarget))) targetdir = self.get_target_dir(target) fname = target.get_filename() if isinstance(fname, list): @@ -101,6 +103,9 @@ class Backend(): filename = os.path.join(targetdir, fname) return filename + def get_target_filename_abs(self, target): + return os.path.join(self.environment.get_build_dir(), self.get_target_filename(target)) + def get_target_filename_for_linking(self, target): # On some platforms (msvc for instance), the file that is used for # dynamic linking is not the same as the dynamic library itself. This @@ -133,7 +138,7 @@ class Backend(): abs_files = [] result = [] for src in unity_src: - comp = self.get_compiler_for_source(src) + comp = self.get_compiler_for_source(src, target.is_cross) language = comp.get_language() suffix = '.' + comp.get_default_suffix() if language not in langlist: diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index f6a3c75..b84a144 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -347,11 +347,8 @@ int dummy; if isinstance(s, build.GeneratedList): self.generate_genlist_for_target(s, target, outfile) - def generate_custom_target(self, target, outfile): - self.custom_target_generator_inputs(target, outfile) - (srcs, ofilenames, cmd) = self.eval_custom_target_command(target) + def unwrap_dep_list(self, target): deps = [] - desc = 'Generating {0} with a {1} command.' for i in target.get_dependencies(): # FIXME, should not grab element at zero but rather expand all. if isinstance(i, list): @@ -360,6 +357,13 @@ int dummy; if isinstance(fname, list): fname = fname[0] deps.append(os.path.join(self.get_target_dir(i), fname)) + return deps + + def generate_custom_target(self, target, outfile): + self.custom_target_generator_inputs(target, outfile) + (srcs, ofilenames, cmd) = self.eval_custom_target_command(target) + deps = self.unwrap_dep_list(target) + desc = 'Generating {0} with a {1} command.' if target.build_always: deps.append('PHONY') elem = NinjaBuildElement(self.all_outputs, ofilenames, 'CUSTOM_COMMAND', srcs) @@ -397,19 +401,19 @@ int dummy; def generate_run_target(self, target, outfile): runnerscript = [sys.executable, self.environment.get_build_command(), '--internal', 'commandrunner'] - deps = [] + deps = self.unwrap_dep_list(target) arg_strings = [] for i in target.args: if isinstance(i, str): arg_strings.append(i) elif isinstance(i, (build.BuildTarget, build.CustomTarget)): relfname = self.get_target_filename(i) - deps.append(relfname) arg_strings.append(os.path.join(self.environment.get_build_dir(), relfname)) else: mlog.debug(str(i)) raise MesonException('Unreachable code in generate_run_target.') elem = NinjaBuildElement(self.all_outputs, target.name, 'CUSTOM_COMMAND', deps) + elem.add_dep(deps) cmd = runnerscript + [self.environment.get_source_dir(), self.environment.get_build_dir(), target.subdir] texe = target.command try: @@ -676,7 +680,7 @@ int dummy; outname_rel = os.path.join(self.get_target_dir(target), fname) src_list = target.get_sources() class_list = [] - compiler = self.get_compiler_for_source(src_list[0]) + compiler = self.get_compiler_for_source(src_list[0], False) assert(compiler.get_language() == 'java') c = 'c' m = '' @@ -727,7 +731,7 @@ int dummy; fname = target.get_filename() outname_rel = os.path.join(self.get_target_dir(target), fname) src_list = target.get_sources() - compiler = self.get_compiler_for_source(src_list[0]) + compiler = self.get_compiler_for_source(src_list[0], False) assert(compiler.get_language() == 'cs') rel_srcs = [s.rel_to_builddir(self.build_to_src) for s in src_list] deps = [] @@ -1435,7 +1439,7 @@ rule FORTRAN_DEP_HACK if isinstance(src, RawFilename) and src.fname.endswith('.h'): raise RuntimeError('Fug') extra_orderdeps = [] - compiler = self.get_compiler_for_source(src) + compiler = self.get_compiler_for_source(src, target.is_cross) commands = [] # The first thing is implicit include directories: source, build and private. commands += compiler.get_include_args(self.get_target_private_dir(target), False) diff --git a/mesonbuild/build.py b/mesonbuild/build.py index 1ff834c..b610bb8 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -1088,10 +1088,11 @@ class CustomTarget: return "@cus" class RunTarget: - def __init__(self, name, command, args, subdir): + def __init__(self, name, command, args, dependencies, subdir): self.name = name self.command = command self.args = args + self.dependencies = dependencies self.subdir = subdir def __repr__(self): @@ -1105,7 +1106,7 @@ class RunTarget: return self.name def get_dependencies(self): - return [] + return self.dependencies def get_generated_sources(self): return [] diff --git a/mesonbuild/compilers.py b/mesonbuild/compilers.py index a091dc9..55a4384 100644 --- a/mesonbuild/compilers.py +++ b/mesonbuild/compilers.py @@ -129,6 +129,10 @@ msvc_winlibs = ['kernel32.lib', 'user32.lib', 'gdi32.lib', 'winspool.lib', 'shell32.lib', 'ole32.lib', 'oleaut32.lib', 'uuid.lib', 'comdlg32.lib', 'advapi32.lib'] +gnu_color_args = {'auto' : ['-fdiagnostics-color=auto'], + 'always': ['-fdiagnostics-color=always'], + 'never' : ['-fdiagnostics-color=never'], + } base_options = { 'b_pch': coredata.UserBooleanOption('b_pch', 'Use precompiled headers', True), @@ -144,6 +148,9 @@ base_options = { 'b_coverage': coredata.UserBooleanOption('b_coverage', 'Enable coverage tracking.', False), + 'b_colorout' : coredata.UserComboOption('b_colorout', 'Use colored output', + ['auto', 'always', 'never'], + 'always'), } def sanitizer_compile_args(value): @@ -169,6 +176,10 @@ def get_base_compile_args(options, compiler): except KeyError: pass try: + args += compiler.get_colorout_args(options['b_colorout'].value) + except KeyError: + pass + try: args += sanitizer_compile_args(options['b_sanitize'].value) except KeyError: pass @@ -332,6 +343,9 @@ class Compiler(): extra_flags += environment.cross_info.config['properties'].get(lang_link_args_key, []) return extra_flags + def get_colorout_args(self, colortype): + return [] + class CCompiler(Compiler): def __init__(self, exelist, version, is_cross, exe_wrapper=None): super().__init__(exelist, version) @@ -1643,10 +1657,16 @@ class GnuCCompiler(CCompiler): self.warn_args = {'1': ['-Wall', '-Winvalid-pch'], '2': ['-Wall', '-Wextra', '-Winvalid-pch'], '3' : ['-Wall', '-Wpedantic', '-Wextra', '-Winvalid-pch']} - self.base_options = ['b_pch', 'b_lto', 'b_pgo', 'b_sanitize', 'b_coverage'] + self.base_options = ['b_pch', 'b_lto', 'b_pgo', 'b_sanitize', 'b_coverage', + 'b_colorout'] if self.gcc_type != GCC_OSX: self.base_options.append('b_lundef') + def get_colorout_args(self, colortype): + if mesonlib.version_compare(self.version, '>=4.9.0'): + return gnu_color_args[colortype][:] + return [] + def get_pic_args(self): if self.gcc_type == GCC_MINGW: return [] # On Window gcc defaults to fpic being always on. @@ -1826,10 +1846,16 @@ class GnuCPPCompiler(CPPCompiler): self.warn_args = {'1': ['-Wall', '-Winvalid-pch', '-Wnon-virtual-dtor'], '2': ['-Wall', '-Wextra', '-Winvalid-pch', '-Wnon-virtual-dtor'], '3': ['-Wall', '-Wpedantic', '-Wextra', '-Winvalid-pch', '-Wnon-virtual-dtor']} - self.base_options = ['b_pch', 'b_lto', 'b_pgo', 'b_sanitize', 'b_coverage'] + self.base_options = ['b_pch', 'b_lto', 'b_pgo', 'b_sanitize', 'b_coverage', + 'b_colorout'] if self.gcc_type != GCC_OSX: self.base_options.append('b_lundef') + def get_colorout_args(self, colortype): + if mesonlib.version_compare(self.version, '>=4.9.0'): + return gnu_color_args[colortype][:] + return [] + def get_always_args(self): return ['-pipe'] diff --git a/mesonbuild/dependencies.py b/mesonbuild/dependencies.py index 544291b..2b77706 100644 --- a/mesonbuild/dependencies.py +++ b/mesonbuild/dependencies.py @@ -1105,11 +1105,13 @@ class Python3Dependency(Dependency): super().__init__() self.name = 'python3' self.is_found = False + self.version = "3.something_maybe" try: pkgdep = PkgConfigDependency('python3', environment, kwargs) if pkgdep.found(): self.cargs = pkgdep.cargs self.libs = pkgdep.libs + self.version = pkgdep.get_version() self.is_found = True return except Exception: @@ -1127,6 +1129,7 @@ class Python3Dependency(Dependency): self.libs = ['-L{}/libs'.format(basedir), '-lpython{}'.format(vernum)] self.is_found = True + self.version = sysconfig.get_config_var('py_version_short') elif mesonlib.is_osx(): # In OSX the Python 3 framework does not have a version # number in its name. @@ -1146,6 +1149,9 @@ class Python3Dependency(Dependency): def get_link_args(self): return self.libs + def get_version(self): + return self.version + def get_dep_identifier(name, kwargs): elements = [name] modlist = kwargs.get('modules', []) diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py index f74b588..47414ca 100644 --- a/mesonbuild/environment.py +++ b/mesonbuild/environment.py @@ -770,6 +770,9 @@ class CrossBuildInfo(): def get_stdlib(self, language): return self.config['properties'][language + '_stdlib'] + def get_properties(self): + return self.config['properties'] + # Wehn compiling a cross compiler we use the native compiler for everything. # But not when cross compiling a cross compiler. def need_cross_compiler(self): diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index c997e0e..df4cb0d 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -23,11 +23,13 @@ from . import compilers from .wrap import wrap from . import mesonlib -import os, sys, platform, subprocess, shutil, uuid, re +import os, sys, subprocess, shutil, uuid, re from functools import wraps import importlib +run_depr_printed = False + class InterpreterException(mesonlib.MesonException): pass @@ -473,6 +475,7 @@ class BuildTargetHolder(InterpreterObject): 'extract_all_objects' : self.extract_all_objects_method, 'get_id': self.get_id_method, 'outdir' : self.outdir_method, + 'full_path' : self.full_path_method, 'private_dir_include' : self.private_dir_include_method, }) @@ -483,6 +486,9 @@ class BuildTargetHolder(InterpreterObject): return IncludeDirsHolder(build.IncludeDirs('', [], False, [self.interpreter.backend.get_target_private_dir(self.held_object)])) + def full_path_method(self, args, kwargs): + return self.interpreter.backend.get_target_filename_abs(self.held_object) + def outdir_method(self, args, kwargs): return self.interpreter.backend.get_target_dir(self.held_object) @@ -514,19 +520,19 @@ class JarHolder(BuildTargetHolder): super().__init__(target, interp) class CustomTargetHolder(InterpreterObject): - def __init__(self, object_to_hold): + def __init__(self, object_to_hold, interp): + super().__init__() self.held_object = object_to_hold + self.interpreter = interp + self.methods.update({'full_path' : self.full_path_method, + }) - def is_cross(self): - return self.held_object.is_cross() - - def extract_objects_method(self, args, kwargs): - gobjs = self.held_object.extract_objects(args) - return GeneratedObjectsHolder(gobjs) + def full_path_method(self, args, kwargs): + return self.interpreter.backend.get_target_filename_abs(self.held_object) class RunTargetHolder(InterpreterObject): - def __init__(self, name, command, args, subdir): - self.held_object = build.RunTarget(name, command, args, subdir) + def __init__(self, name, command, args, dependencies, subdir): + self.held_object = build.RunTarget(name, command, args, dependencies, subdir) class Test(InterpreterObject): def __init__(self, name, suite, exe, is_parallel, cmd_args, env, should_fail, valgrind_args, timeout, workdir): @@ -860,6 +866,7 @@ class MesonMain(InterpreterObject): 'install_dependency_manifest': self.install_dependency_manifest_method, 'project_version': self.project_version_method, 'project_name' : self.project_name_method, + 'get_cross_property': self.get_cross_property_method, }) def add_install_script_method(self, args, kwargs): @@ -959,6 +966,20 @@ class MesonMain(InterpreterObject): def project_name_method(self, args, kwargs): return self.interpreter.active_projectname + def get_cross_property_method(self, args, kwargs): + if len(args) < 1 or len(args) > 2: + raise InterpreterException('Must have one or two arguments.') + propname = args[0] + if not isinstance(propname, str): + raise InterpreterException('Property name must be string.') + try: + props = self.interpreter.environment.cross_info.get_properties() + return props[propname] + except Exception: + if len(args) == 2: + return args[1] + raise InterpreterException('Unknown cross property: %s.' % propname) + class Interpreter(): def __init__(self, build, backend, subproject='', subdir='', subproject_dir='subprojects'): @@ -1069,7 +1090,7 @@ class Interpreter(): for v in invalues: if isinstance(v, build.CustomTarget): self.add_target(v.name, v) - outvalues.append(CustomTargetHolder(v)) + outvalues.append(CustomTargetHolder(v, self)) elif isinstance(v, int) or isinstance(v, str): outvalues.append(v) elif isinstance(v, build.Executable): @@ -1754,16 +1775,32 @@ class Interpreter(): if len(args) != 1: raise InterpreterException('Incorrect number of arguments') name = args[0] - tg = CustomTargetHolder(build.CustomTarget(name, self.subdir, kwargs)) + tg = CustomTargetHolder(build.CustomTarget(name, self.subdir, kwargs), self) self.add_target(name, tg.held_object) return tg - @noKwargs def func_run_target(self, node, args, kwargs): - if len(args) < 2: - raise InterpreterException('Incorrect number of arguments') + global run_depr_printed + if len(args) > 1: + if not run_depr_printed: + mlog.log(mlog.red('DEPRECATION'), 'positional version of run_target is deprecated, use the keyword version instead.') + run_depr_printed = True + if 'command' in kwargs: + raise InterpreterException('Can not have command both in positional and keyword arguments.') + all_args = args[1:] + deps = [] + elif len(args) == 1: + if not 'command' in kwargs: + raise InterpreterException('Missing "command" keyword argument') + all_args = kwargs['command'] + deps = kwargs.get('depends', []) + if not isinstance(deps, list): + deps = [deps] + else: + raise InterpreterException('Run_target needs at least one positional argument.') + cleaned_args = [] - for i in args: + for i in all_args: try: i = i.held_object except AttributeError: @@ -1772,10 +1809,21 @@ class Interpreter(): mlog.debug('Wrong type:', str(i)) raise InterpreterException('Invalid argument to run_target.') cleaned_args.append(i) - name = cleaned_args[0] - command = cleaned_args[1] - cmd_args = cleaned_args[2:] - tg = RunTargetHolder(name, command, cmd_args, self.subdir) + name = args[0] + if not isinstance(name, str): + raise InterpreterException('First argument must be a string.') + cleaned_deps = [] + for d in deps: + try: + d = d.held_object + except AttributeError: + pass + if not isinstance(d, (build.BuildTarget, build.CustomTarget)): + raise InterpreterException('Depends items must be build targets.') + cleaned_deps.append(d) + command = cleaned_args[0] + cmd_args = cleaned_args[1:] + tg = RunTargetHolder(name, command, cmd_args, cleaned_deps, self.subdir) self.add_target(name, tg.held_object) return tg diff --git a/mesonbuild/modules/i18n.py b/mesonbuild/modules/i18n.py index 4b529c7..33874fa 100644 --- a/mesonbuild/modules/i18n.py +++ b/mesonbuild/modules/i18n.py @@ -26,9 +26,9 @@ class I18nModule: raise coredata.MesonException('List of languages empty.') extra_args = mesonlib.stringlistify(kwargs.get('args', [])) potargs = [state.environment.get_build_command(), '--internal', 'gettext', 'pot', packagename] + extra_args - pottarget = build.RunTarget(packagename + '-pot', sys.executable, potargs, state.subdir) + pottarget = build.RunTarget(packagename + '-pot', sys.executable, potargs, [], state.subdir) gmoargs = [state.environment.get_build_command(), '--internal', 'gettext', 'gen_gmo'] + languages - gmotarget = build.RunTarget(packagename + '-gmo', sys.executable, gmoargs, state.subdir) + gmotarget = build.RunTarget(packagename + '-gmo', sys.executable, gmoargs, [], state.subdir) installcmd = [sys.executable, state.environment.get_build_command(), '--internal', diff --git a/mesonbuild/scripts/meson_install.py b/mesonbuild/scripts/meson_install.py index 3768614..1924b95 100644 --- a/mesonbuild/scripts/meson_install.py +++ b/mesonbuild/scripts/meson_install.py @@ -19,6 +19,14 @@ from glob import glob from mesonbuild.scripts import depfixer from mesonbuild.scripts import destdir_join +install_log_file = None + +def append_to_log(line): + install_log_file.write(line) + if not line.endswith('\n'): + install_log_file.write('\n') + install_log_file.flush() + def do_copy(from_file, to_file): try: # Python's copyfile fails if the target file already exists. @@ -27,6 +35,7 @@ def do_copy(from_file, to_file): pass shutil.copyfile(from_file, to_file) shutil.copystat(from_file, to_file) + append_to_log(to_file) def do_install(datafilename): ifile = open(datafilename, 'rb') @@ -78,6 +87,7 @@ def install_subdirs(data): os.mkdir(parent_dir) shutil.copystat(os.path.split(abs_src)[0], parent_dir) shutil.copy2(abs_src, abs_dst, follow_symlinks=False) + append_to_log(abs_dst) def install_data(d): for i in d.data: @@ -104,6 +114,7 @@ def install_man(d): if outfilename.endswith('.gz') and not full_source_filename.endswith('.gz'): open(outfilename, 'wb').write(gzip.compress(open(full_source_filename, 'rb').read())) shutil.copystat(full_source_filename, outfilename) + append_to_log(outfilename) else: do_copy(full_source_filename, outfilename) @@ -209,6 +220,7 @@ def install_targets(d): except FileNotFoundError: pass os.symlink(os.path.split(fname)[-1], symlinkfilename) + append_to_log(symlinkfilename) except (NotImplementedError, OSError): if not printed_symlink_error: print("Symlink creation does not work on this platform.") @@ -224,11 +236,19 @@ def install_targets(d): raise def run(args): + global install_log_file if len(args) != 1: print('Installer script for Meson. Do not run on your own, mmm\'kay?') print('meson_install.py [install info file]') datafilename = args[0] - do_install(datafilename) + private_dir = os.path.split(datafilename)[0] + log_dir = os.path.join(private_dir, '../meson-logs') + with open(os.path.join(log_dir, 'install-log.txt'), 'w') as lf: + install_log_file = lf + append_to_log('# List of files installed by Meson') + append_to_log('# Does not contain files installed by custom scripts.') + do_install(datafilename) + install_log_file = None return 0 if __name__ == '__main__': diff --git a/test cases/common/58 run target/converter.py b/test cases/common/58 run target/converter.py new file mode 100644 index 0000000..6acbc84 --- /dev/null +++ b/test cases/common/58 run target/converter.py @@ -0,0 +1,5 @@ +#!/usr/bin/env python3 + +import sys + +open(sys.argv[2], 'wb').write(open(sys.argv[1], 'rb').read()) diff --git a/test cases/common/58 run target/fakeburner.py b/test cases/common/58 run target/fakeburner.py new file mode 100755 index 0000000..a100a6f --- /dev/null +++ b/test cases/common/58 run target/fakeburner.py @@ -0,0 +1,13 @@ +#!/usr/bin/env python3 + +import sys + +plain_arg = sys.argv[1] +_, filename, _ = plain_arg.split(':') +try: + content = open(filename, 'rb').read() +except FileNotFoundError: + print('Could not open file. Missing dependency?') + sys.exit(1) +print('File opened, pretending to send it somewhere.') +print(len(content), 'bytes uploaded') diff --git a/test cases/common/58 run target/meson.build b/test cases/common/58 run target/meson.build index fa25f2a..0febe35 100644 --- a/test cases/common/58 run target/meson.build +++ b/test cases/common/58 run target/meson.build @@ -1,12 +1,36 @@ project('run target', 'c') -run_target('mycommand', 'scripts/script.sh') +# deprecated format, fix once we remove support for it. +run_target('mycommand','scripts/script.sh') # Make it possible to run built programs. # In cross builds exe_wrapper should be added if it exists. exe = executable('helloprinter', 'helloprinter.c') -run_target('runhello', exe, 'argument') +run_target('runhello', + command : [exe, 'argument']) + +converter = find_program('converter.py') + +hex = custom_target('exe.hex', + input : exe, + output : 'exe.hex', + command : [converter, '@INPUT@', '@OUTPUT@', + ], +) + +# These emulates the Arduino flasher application. It sandwiches the filename inside +# a packed argument. Thus we need to declare it manually. +run_target('upload', + command : ['fakeburner.py', 'x:@0@:y'.format(exe.full_path())], + depends : exe, +) + +run_target('upload2', + command : ['fakeburner.py', 'x:@0@:y'.format(hex.full_path())], + depends : hex, +) python3 = find_program('python3') -run_target('py3hi', python3, '-c', 'print("I am Python3.")') +run_target('py3hi', + command : [python3, '-c', 'print("I am Python3.")']) diff --git a/test cases/failing/29 no crossprop/meson.build b/test cases/failing/29 no crossprop/meson.build new file mode 100644 index 0000000..bd3a743 --- /dev/null +++ b/test cases/failing/29 no crossprop/meson.build @@ -0,0 +1,3 @@ +project('no crossprop', 'c') + +message(meson.get_cross_property('nonexisting')) |