diff options
31 files changed, 539 insertions, 232 deletions
diff --git a/.appveyor.yml b/.appveyor.yml index c79e250..96a4ed8 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -5,6 +5,10 @@ os: Visual Studio 2015 environment: matrix: - arch: x86 + compiler: msys2-mingw + backend: ninja + + - arch: x86 compiler: msvc2010 backend: ninja @@ -20,7 +24,11 @@ environment: compiler: msvc2015 backend: vs2015 - - arch: x86 + - arch: x64 + compiler: cygwin + backend: ninja + + - arch: x64 compiler: msys2-mingw backend: ninja @@ -34,14 +42,6 @@ environment: backend: vs2017 APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 - - arch: x64 - compiler: msys2-mingw - backend: ninja - - - arch: x64 - compiler: cygwin - backend: ninja - platform: - x64 diff --git a/authors.txt b/authors.txt index 8117d45..467ab75 100644 --- a/authors.txt +++ b/authors.txt @@ -78,3 +78,4 @@ Dylan Baker Aaron Plattner Jon Turney Wade Berrier +Richard Hughes diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py index efc5bff..2e630bd 100644 --- a/mesonbuild/backend/backends.py +++ b/mesonbuild/backend/backends.py @@ -601,7 +601,7 @@ class Backend: for t in target.get_generated_sources(): if not isinstance(t, build.CustomTarget): continue - for f in t.output: + for f in t.get_outputs(): if self.environment.is_library(f): libs.append(os.path.join(self.get_target_dir(t), f)) return libs @@ -642,7 +642,7 @@ class Backend: build_root = self.environment.get_source_dir() outdir = os.path.join(self.environment.get_build_dir(), outdir) outputs = [] - for i in target.output: + for i in target.get_outputs(): outputs.append(os.path.join(outdir, i)) inputs = self.get_custom_target_sources(target) # Evaluate the command list diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index 5a9462f..ec6d050 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -633,40 +633,88 @@ int dummy; def generate_target_install(self, d): for t in self.build.get_targets().values(): - if t.should_install(): + if not t.should_install(): + continue + # Find the installation directory. + outdirs = t.get_custom_install_dir() + custom_install_dir = False + if outdirs[0] is not None and outdirs[0] is not True: + # Either the value is set, or is set to False which means + # we want this specific output out of many outputs to not + # be installed. + custom_install_dir = True + elif isinstance(t, build.SharedModule): + outdirs[0] = self.environment.get_shared_module_dir() + elif isinstance(t, build.SharedLibrary): + outdirs[0] = self.environment.get_shared_lib_dir() + elif isinstance(t, build.StaticLibrary): + outdirs[0] = self.environment.get_static_lib_dir() + elif isinstance(t, build.Executable): + outdirs[0] = self.environment.get_bindir() + else: + assert(isinstance(t, build.BuildTarget)) + # XXX: Add BuildTarget-specific install dir cases here + outdirs[0] = self.environment.get_libdir() + # Sanity-check the outputs and install_dirs + num_outdirs, num_out = len(outdirs), len(t.get_outputs()) + if num_outdirs != 1 and num_outdirs != num_out: + m = 'Target {!r} has {} outputs: {!r}, but only {} "install_dir"s were found.\n' \ + "Pass 'false' for outputs that should not be installed and 'true' for\n" \ + 'using the default installation directory for an output.' + raise MesonException(m.format(t.name, num_out, t.get_outputs(), num_outdirs)) + # Install the target output(s) + if isinstance(t, build.BuildTarget): should_strip = self.get_option_for_target('strip', t) - # Find the installation directory. FIXME: Currently only one - # installation directory is supported for each target - outdir = t.get_custom_install_dir() - if outdir is not None: - pass - elif isinstance(t, build.SharedLibrary): - # For toolchains/platforms that need an import library for + # Install primary build output (library/executable/jar, etc) + # Done separately because of strip/aliases/rpath + if outdirs[0] is not False: + i = [self.get_target_filename(t), outdirs[0], + t.get_aliases(), should_strip, t.install_rpath] + d.targets.append(i) + # On toolchains/platforms that use an import library for # linking (separate from the shared library with all the - # code), we need to install the import library (dll.a/.lib) - if t.get_import_filename(): + # code), we need to install that too (dll.a/.lib). + if isinstance(t, build.SharedLibrary) and t.get_import_filename(): + if custom_install_dir: + # If the DLL is installed into a custom directory, + # install the import library into the same place so + # it doesn't go into a surprising place + implib_install_dir = outdirs[0] + else: + implib_install_dir = self.environment.get_import_lib_dir() # Install the import library. i = [self.get_target_filename_for_linking(t), - self.environment.get_import_lib_dir(), + implib_install_dir, # It has no aliases, should not be stripped, and # doesn't have an install_rpath {}, False, ''] d.targets.append(i) - outdir = self.environment.get_shared_lib_dir() - elif isinstance(t, build.StaticLibrary): - outdir = self.environment.get_static_lib_dir() - elif isinstance(t, build.Executable): - outdir = self.environment.get_bindir() - else: - # XXX: Add BuildTarget-specific install dir cases here - outdir = self.environment.get_libdir() - if isinstance(t, build.BuildTarget): - i = [self.get_target_filename(t), outdir, t.get_aliases(), - should_strip, t.install_rpath] - d.targets.append(i) - elif isinstance(t, build.CustomTarget): + # Install secondary outputs. Only used for Vala right now. + if num_outdirs > 1: + for output, outdir in zip(t.get_outputs()[1:], outdirs[1:]): + # User requested that we not install this output + if outdir is False: + continue + f = os.path.join(self.get_target_dir(t), output) + d.targets.append([f, outdir, {}, False, None]) + elif isinstance(t, build.CustomTarget): + # If only one install_dir is specified, assume that all + # outputs will be installed into it. This is for + # backwards-compatibility and because it makes sense to + # avoid repetition since this is a common use-case. + # + # To selectively install only some outputs, pass `false` as + # the install_dir for the corresponding output by index + if num_outdirs == 1 and num_out > 1: for output in t.get_outputs(): f = os.path.join(self.get_target_dir(t), output) + d.targets.append([f, outdirs[0], {}, False, None]) + else: + for output, outdir in zip(t.get_outputs(), outdirs): + # User requested that we not install this output + if outdir is False: + continue + f = os.path.join(self.get_target_dir(t), output) d.targets.append([f, outdir, {}, False, None]) def generate_custom_install_script(self, d): @@ -1032,10 +1080,12 @@ int dummy; # Without this, it will write it inside c_out_dir args += ['--vapi', os.path.join('..', target.vala_vapi)] valac_outputs.append(vapiname) + target.outputs += [target.vala_header, target.vala_vapi] if isinstance(target.vala_gir, str): girname = os.path.join(self.get_target_dir(target), target.vala_gir) args += ['--gir', os.path.join('..', target.vala_gir)] valac_outputs.append(girname) + target.outputs.append(target.vala_gir) if self.get_option_for_target('werror', target): args += valac.get_werror_args() for d in target.get_external_deps(): diff --git a/mesonbuild/backend/vs2010backend.py b/mesonbuild/backend/vs2010backend.py index 139360c..feae79e 100644 --- a/mesonbuild/backend/vs2010backend.py +++ b/mesonbuild/backend/vs2010backend.py @@ -418,6 +418,9 @@ class Vs2010Backend(backends.Backend): cmd.append(os.path.join(self.environment.get_build_dir(), self.get_target_filename(i))) elif isinstance(i, dependencies.ExternalProgram): cmd += i.get_command() + elif isinstance(i, File): + relfname = i.rel_to_builddir(self.build_to_src) + cmd.append(os.path.join(self.environment.get_build_dir(), relfname)) else: cmd.append(i) cmd_templ = '''"%s" ''' * len(cmd) diff --git a/mesonbuild/build.py b/mesonbuild/build.py index 537c91b..df3f37b 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -19,7 +19,7 @@ from . import environment from . import dependencies from . import mlog from .mesonlib import File, MesonException -from .mesonlib import flatten, stringlistify, classify_unity_sources +from .mesonlib import flatten, typeslistify, stringlistify, classify_unity_sources from .mesonlib import get_filenames_templates_dict, substitute_values from .environment import for_windows, for_darwin, for_cygwin from .compilers import is_object, clike_langs, sort_clike, lang_suffixes @@ -318,6 +318,9 @@ class BuildTarget(Target): self.name_prefix_set = False self.name_suffix_set = False self.filename = 'no_name' + # The list of all files outputted by this target. Useful in cases such + # as Vala which generates .vapi and .h besides the compiled output. + self.outputs = [self.filename] self.need_install = False self.pch = {} self.extra_args = {} @@ -544,7 +547,7 @@ class BuildTarget(Target): return result def get_custom_install_dir(self): - return self.custom_install_dir + return self.install_dir def process_kwargs(self, kwargs, environment): super().process_kwargs(kwargs) @@ -591,7 +594,7 @@ class BuildTarget(Target): if not isinstance(self, Executable): self.vala_header = kwargs.get('vala_header', self.name + '.h') self.vala_vapi = kwargs.get('vala_vapi', self.name + '.vapi') - self.vala_gir = kwargs.get('vala_gir', None) + self.vala_gir = kwargs.get('vala_gir', None) dlist = stringlistify(kwargs.get('d_args', [])) self.add_compiler_args('d', dlist) self.link_args = kwargs.get('link_args', []) @@ -617,10 +620,10 @@ class BuildTarget(Target): if not isinstance(deplist, list): deplist = [deplist] self.add_deps(deplist) - self.custom_install_dir = kwargs.get('install_dir', None) - if self.custom_install_dir is not None: - if not isinstance(self.custom_install_dir, str): - raise InvalidArguments('Custom_install_dir must be a string') + # If an item in this list is False, the output corresponding to + # the list index of that item will not be installed + self.install_dir = typeslistify(kwargs.get('install_dir', [None]), + (str, bool)) main_class = kwargs.get('main_class', '') if not isinstance(main_class, str): raise InvalidArguments('Main class must be a string') @@ -691,7 +694,7 @@ class BuildTarget(Target): return self.filename def get_outputs(self): - return [self.filename] + return self.outputs def get_extra_args(self, language): return self.extra_args.get(language, []) @@ -1005,6 +1008,7 @@ class Executable(BuildTarget): self.filename = self.name if self.suffix: self.filename += '.' + self.suffix + self.outputs = [self.filename] def type_suffix(self): return "@exe" @@ -1032,6 +1036,7 @@ class StaticLibrary(BuildTarget): else: self.suffix = 'a' self.filename = self.prefix + self.name + '.' + self.suffix + self.outputs = [self.filename] def type_suffix(self): return "@sta" @@ -1160,6 +1165,7 @@ class SharedLibrary(BuildTarget): if self.suffix is None: self.suffix = suffix self.filename = self.filename_tpl.format(self) + self.outputs = [self.filename] def process_kwargs(self, kwargs, environment): super().process_kwargs(kwargs, environment) @@ -1253,6 +1259,7 @@ class SharedModule(SharedLibrary): if 'soversion' in kwargs: raise MesonException('Shared modules must not specify the soversion kwarg.') super().__init__(name, subdir, subproject, is_cross, sources, objects, environment, kwargs) + self.import_filename = None class CustomTarget(Target): known_kwargs = {'input': True, @@ -1334,13 +1341,13 @@ class CustomTarget(Target): self.sources = [self.sources] if 'output' not in kwargs: raise InvalidArguments('Missing keyword argument "output".') - self.output = kwargs['output'] - if not isinstance(self.output, list): - self.output = [self.output] + self.outputs = kwargs['output'] + if not isinstance(self.outputs, list): + self.outputs = [self.outputs] # This will substitute values from the input into output and return it. inputs = get_sources_string_names(self.sources) values = get_filenames_templates_dict(inputs, []) - for i in self.output: + for i in self.outputs: if not(isinstance(i, str)): raise InvalidArguments('Output argument not a string.') if '/' in i: @@ -1355,9 +1362,9 @@ class CustomTarget(Target): m = "Output cannot contain @PLAINNAME@ or @BASENAME@ when " \ "there is more than one input (we can't know which to use)" raise InvalidArguments(m) - self.output = substitute_values(self.output, values) + self.outputs = substitute_values(self.outputs, values) self.capture = kwargs.get('capture', False) - if self.capture and len(self.output) != 1: + if self.capture and len(self.outputs) != 1: raise InvalidArguments('Capturing can only output to a single file.') if 'command' not in kwargs: raise InvalidArguments('Missing keyword argument "command".') @@ -1379,12 +1386,14 @@ class CustomTarget(Target): raise InvalidArguments('"install" must be boolean.') if self.install: if 'install_dir' not in kwargs: - raise InvalidArguments('"install_dir" not specified.') - self.install_dir = kwargs['install_dir'] - if not(isinstance(self.install_dir, str)): - raise InvalidArguments('"install_dir" must be a string.') + raise InvalidArguments('"install_dir" must be specified ' + 'when installing a target') + # If an item in this list is False, the output corresponding to + # the list index of that item will not be installed + self.install_dir = typeslistify(kwargs['install_dir'], (str, bool)) else: self.install = False + self.install_dir = [None] self.build_always = kwargs.get('build_always', False) if not isinstance(self.build_always, bool): raise InvalidArguments('Argument build_always must be a boolean.') @@ -1417,10 +1426,10 @@ class CustomTarget(Target): return self.install_dir def get_outputs(self): - return self.output + return self.outputs def get_filename(self): - return self.output[0] + return self.outputs[0] def get_sources(self): return self.sources @@ -1479,6 +1488,7 @@ class Jar(BuildTarget): if not s.endswith('.java'): raise InvalidArguments('Jar source %s is not a java file.' % s) self.filename = self.name + '.jar' + self.outputs = [self.filename] self.java_args = kwargs.get('java_args', []) def get_main_class(self): diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py index 7861612..93a41e8 100644 --- a/mesonbuild/environment.py +++ b/mesonbuild/environment.py @@ -741,6 +741,10 @@ class Environment: "Install dir for the import library (library used for linking)" return self.get_libdir() + def get_shared_module_dir(self): + "Install dir for shared modules that are loaded at runtime" + return self.get_libdir() + def get_shared_lib_dir(self): "Install dir for the shared library" if self.win_libdir_layout: diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index 8c8000c..18f91ea 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -1109,7 +1109,7 @@ class MesonMain(InterpreterObject): found = self._found_source_scripts[key] else: found = dependencies.ExternalProgram(name, search_dir=search_dir) - if found: + if found.found(): self._found_source_scripts[key] = found else: raise InterpreterException('Script {!r} not found'.format(name)) @@ -2243,7 +2243,7 @@ class Interpreter(InterpreterBase): if 'install_mode' not in kwargs: return None install_mode = [] - mode = mesonlib.stringintlistify(kwargs.get('install_mode', [])) + mode = mesonlib.typeslistify(kwargs.get('install_mode', []), (str, int)) for m in mode: # We skip any arguments that are set to `false` if m is False: diff --git a/mesonbuild/mesonlib.py b/mesonbuild/mesonlib.py index a2ab484..5377d8e 100644 --- a/mesonbuild/mesonlib.py +++ b/mesonbuild/mesonlib.py @@ -467,25 +467,22 @@ def replace_if_different(dst, dst_tmp): else: os.unlink(dst_tmp) -def stringintlistify(item): - if isinstance(item, (str, int)): +def typeslistify(item, types): + ''' + Ensure that type(@item) is one of @types or a + list of items all of which are of type @types + ''' + if isinstance(item, types): item = [item] if not isinstance(item, list): - raise MesonException('Item must be a list, a string, or an int') + raise MesonException('Item must be a list or one of {!r}'.format(types)) for i in item: - if not isinstance(i, (str, int, type(None))): - raise MesonException('List item must be a string or an int') + if i is not None and not isinstance(i, types): + raise MesonException('List item must be one of {!r}'.format(types)) return item def stringlistify(item): - if isinstance(item, str): - item = [item] - if not isinstance(item, list): - raise MesonException('Item is not a list') - for i in item: - if not isinstance(i, str): - raise MesonException('List item not a string.') - return item + return typeslistify(item, str) def expand_arguments(args): expended_args = [] diff --git a/mesonbuild/modules/gnome.py b/mesonbuild/modules/gnome.py index 4b366bf..adb6fa8 100644 --- a/mesonbuild/modules/gnome.py +++ b/mesonbuild/modules/gnome.py @@ -766,6 +766,8 @@ class GnomeModule(ExtensionModule): cmd += ['--interface-prefix', kwargs.pop('interface_prefix')] if 'namespace' in kwargs: cmd += ['--c-namespace', kwargs.pop('namespace')] + if kwargs.get('object_manager', False): + cmd += ['--c-generate-object-manager'] # https://git.gnome.org/browse/glib/commit/?id=ee09bb704fe9ccb24d92dd86696a0e6bb8f0dc1a if mesonlib.version_compare(self._get_native_glib_version(state), '>= 2.51.3'): @@ -999,7 +1001,7 @@ class GnomeModule(ExtensionModule): target.get_subdir()) outdir = os.path.join(state.environment.get_build_dir(), target.get_subdir()) - outfile = target.output[0][:-5] # Strip .vapi + outfile = target.get_outputs()[0][:-5] # Strip .vapi ret.append('--vapidir=' + outdir) ret.append('--girdir=' + outdir) ret.append('--pkg=' + outfile) @@ -1066,7 +1068,7 @@ class GnomeModule(ExtensionModule): link_with += self._get_vapi_link_with(i.held_object) subdir = os.path.join(state.environment.get_build_dir(), i.held_object.get_subdir()) - gir_file = os.path.join(subdir, i.held_object.output[0]) + gir_file = os.path.join(subdir, i.held_object.get_outputs()[0]) cmd.append(gir_file) else: raise MesonException('Input must be a str or GirTarget') diff --git a/mesonbuild/modules/pkgconfig.py b/mesonbuild/modules/pkgconfig.py index e46c239..e79371f 100644 --- a/mesonbuild/modules/pkgconfig.py +++ b/mesonbuild/modules/pkgconfig.py @@ -76,8 +76,9 @@ class PkgConfigModule(ExtensionModule): if isinstance(l, str): yield l else: - if l.custom_install_dir: - yield '-L${prefix}/%s ' % l.custom_install_dir + install_dir = l.get_custom_install_dir()[0] + if install_dir: + yield '-L${prefix}/%s ' % install_dir else: yield '-L${libdir}' lname = self._get_lname(l, msg, pcfile) diff --git a/mesontest.py b/mesontest.py index c4d1178..b59d1ed 100755 --- a/mesontest.py +++ b/mesontest.py @@ -21,6 +21,8 @@ import subprocess, sys, os, argparse import pickle from mesonbuild import build from mesonbuild import environment +from mesonbuild.dependencies import ExternalProgram +from mesonbuild import mlog import time, datetime, multiprocessing, json import concurrent.futures as conc @@ -282,7 +284,16 @@ class TestHarness: result_str = '%s %s %s%s%s%5.2f s' % \ (num, name, padding1, result.res, padding2, result.duration) if not self.options.quiet or result.res != 'OK': - print(result_str) + if result.res != 'OK' and mlog.colorize_console: + if result.res == 'FAIL' or result.res == 'TIMEOUT': + decorator = mlog.red + elif result.res == 'SKIP': + decorator = mlog.yellow + else: + sys.exit('Unreachable code was ... well ... reached.') + print(decorator(result_str).get_text(True)) + else: + print(result_str) result_str += "\n\n" + result.get_log() if (result.returncode != GNU_SKIP_RETURNCODE) \ and (result.returncode != 0) != result.should_fail: @@ -574,12 +585,21 @@ def run(args): print('Can not be both quiet and verbose at the same time.') return 1 + check_bin = None if options.gdb: options.verbose = True if options.wrapper: print('Must not specify both a wrapper and gdb at the same time.') return 1 + check_bin = 'gdb' + + if options.wrapper: + check_bin = options.wrapper[0] + if check_bin is not None: + exe = ExternalProgram(check_bin, silent=True) + if not exe.found(): + sys.exit("Could not find requested program: %s" % check_bin) options.wd = os.path.abspath(options.wd) if not options.no_rebuild: diff --git a/run_project_tests.py b/run_project_tests.py index dc05524..bcb375d 100755 --- a/run_project_tests.py +++ b/run_project_tests.py @@ -26,6 +26,7 @@ from mesonbuild import mesonlib from mesonbuild import mlog from mesonbuild import mesonmain from mesonbuild.mesonlib import stringlistify, Popen_safe +from mesonbuild.coredata import backendlist import argparse import xml.etree.ElementTree as ET import time @@ -33,7 +34,7 @@ import multiprocessing import concurrent.futures as conc import re -from mesonbuild.coredata import backendlist +from run_tests import get_backend_commands, get_backend_args_for_dir, Backend class BuildStep(Enum): @@ -42,6 +43,7 @@ class BuildStep(Enum): test = 3 install = 4 clean = 5 + validate = 6 class TestResult: @@ -153,50 +155,36 @@ def stop_handler(signal, frame): signal.signal(signal.SIGINT, stop_handler) signal.signal(signal.SIGTERM, stop_handler) -# unity_flags = ['--unity'] -unity_flags = [] - -backend_flags = None -compile_commands = None -test_commands = None -install_commands = [] -clean_commands = [] +# Needed when running cross tests because we don't generate prebuilt files +compiler = None -def setup_commands(backend): - global backend_flags, compile_commands, test_commands, install_commands, clean_commands +def setup_commands(optbackend): + global do_debug, backend, backend_flags + global compile_commands, clean_commands, test_commands, install_commands, uninstall_commands + backend = optbackend msbuild_exe = shutil.which('msbuild') - if (backend and backend.startswith('vs')) or (backend is None and msbuild_exe is not None): - if backend is None: - backend = 'vs2010' + # Auto-detect backend if unspecified + if backend is None: + if msbuild_exe is not None: + backend = 'vs' # Meson will auto-detect VS version to use + elif mesonlib.is_osx(): + backend = 'xcode' + else: + backend = 'ninja' + # Set backend arguments for Meson + if backend.startswith('vs'): backend_flags = ['--backend=' + backend] - compile_commands = ['msbuild'] - test_commands = ['msbuild', 'RUN_TESTS.vcxproj'] - elif backend == 'xcode' or (backend is None and mesonlib.is_osx()): + backend = Backend.vs + elif backend == 'xcode': backend_flags = ['--backend=xcode'] - compile_commands = ['xcodebuild'] - test_commands = ['xcodebuild', '-target', 'RUN_TESTS'] - else: - backend_flags = [] - # We need at least 1.6 because of -w dupbuild=err - ninja_command = environment.detect_ninja(version='1.6') - if ninja_command is None: - raise RuntimeError('Could not find Ninja v1.6 or newer') - if do_debug: - compile_commands = [ninja_command, '-v'] - else: - compile_commands = [ninja_command] - compile_commands += ['-w', 'dupbuild=err'] - test_commands = [ninja_command, 'test', 'benchmark'] - install_commands = [ninja_command, 'install'] - clean_commands = [ninja_command, 'clean'] - -def get_compile_commands_for_dir(compile_commands, test_build_dir): - if 'msbuild' in compile_commands[0]: - sln_name = glob(os.path.join(test_build_dir, '*.sln'))[0] - comp = compile_commands + [os.path.split(sln_name)[-1]] + backend = Backend.xcode + elif backend == 'ninja': + backend_flags = ['--backend=ninja'] + backend = Backend.ninja else: - comp = compile_commands - return comp + raise RuntimeError('Unknown backend: {!r}'.format(backend)) + compile_commands, clean_commands, test_commands, install_commands, \ + uninstall_commands = get_backend_commands(backend, do_debug) def get_relative_files_list_from_dir(fromdir): paths = [] @@ -223,7 +211,7 @@ def platform_fix_name(fname): return fname -def validate_install(srcdir, installdir): +def validate_install(srcdir, installdir, compiler): # List of installed files info_file = os.path.join(srcdir, 'installed_files.txt') # If this exists, the test does not install any other files @@ -317,18 +305,18 @@ def parse_test_args(testdir): pass return args -def run_test(skipped, testdir, extra_args, flags, compile_commands, should_fail): +def run_test(skipped, testdir, extra_args, compiler, backend, flags, commands, should_fail): if skipped: return None with AutoDeletedDir(tempfile.mkdtemp(prefix='b ', dir='.')) as build_dir: with AutoDeletedDir(tempfile.mkdtemp(prefix='i ', dir=os.getcwd())) as install_dir: try: - return _run_test(testdir, build_dir, install_dir, extra_args, flags, compile_commands, should_fail) + return _run_test(testdir, build_dir, install_dir, extra_args, compiler, backend, flags, commands, should_fail) finally: mlog.shutdown() # Close the log file because otherwise Windows wets itself. -def _run_test(testdir, test_build_dir, install_dir, extra_args, flags, compile_commands, should_fail): - global install_commands, clean_commands +def _run_test(testdir, test_build_dir, install_dir, extra_args, compiler, backend, flags, commands, should_fail): + compile_commands, clean_commands, install_commands, uninstall_commands = commands test_args = parse_test_args(testdir) gen_start = time.time() # Configure in-process @@ -349,9 +337,9 @@ def _run_test(testdir, test_build_dir, install_dir, extra_args, flags, compile_c if returncode != 0: return TestResult('Generating the build system failed.', BuildStep.configure, stdo, stde, mesonlog, gen_time) # Build with subprocess - comp = get_compile_commands_for_dir(compile_commands, test_build_dir) + dir_args = get_backend_args_for_dir(backend, test_build_dir) build_start = time.time() - pc, o, e = Popen_safe(comp, cwd=test_build_dir) + pc, o, e = Popen_safe(compile_commands + dir_args, cwd=test_build_dir) build_time = time.time() - build_start stdo += o stde += e @@ -378,25 +366,26 @@ def _run_test(testdir, test_build_dir, install_dir, extra_args, flags, compile_c return TestResult('Test that should have failed to run unit tests succeeded', BuildStep.test, stdo, stde, mesonlog, gen_time) if returncode != 0: return TestResult('Running unit tests failed.', BuildStep.test, stdo, stde, mesonlog, gen_time, build_time, test_time) - if len(install_commands) == 0: - return TestResult('', BuildStep.install, '', '', mesonlog, gen_time, build_time, test_time) - env = os.environ.copy() - env['DESTDIR'] = install_dir - # Install with subprocess - pi, o, e = Popen_safe(install_commands, cwd=test_build_dir, env=env) - stdo += o - stde += e - if pi.returncode != 0: - return TestResult('Running install failed.', BuildStep.install, stdo, stde, mesonlog, gen_time, build_time, test_time) - if len(clean_commands) != 0: + # Do installation, if the backend supports it + if len(install_commands) != 0: env = os.environ.copy() - # Clean with subprocess - pi, o, e = Popen_safe(clean_commands, cwd=test_build_dir, env=env) + env['DESTDIR'] = install_dir + # Install with subprocess + pi, o, e = Popen_safe(install_commands, cwd=test_build_dir, env=env) stdo += o stde += e if pi.returncode != 0: - return TestResult('Running clean failed.', BuildStep.clean, stdo, stde, mesonlog, gen_time, build_time, test_time) - return TestResult(validate_install(testdir, install_dir), BuildStep.clean, stdo, stde, mesonlog, gen_time, build_time, test_time) + return TestResult('Running install failed.', BuildStep.install, stdo, stde, mesonlog, gen_time, build_time, test_time) + # Clean with subprocess + env = os.environ.copy() + pi, o, e = Popen_safe(clean_commands + dir_args, cwd=test_build_dir, env=env) + stdo += o + stde += e + if pi.returncode != 0: + return TestResult('Running clean failed.', BuildStep.clean, stdo, stde, mesonlog, gen_time, build_time, test_time) + if len(install_commands) == 0: + return TestResult('', BuildStep.install, '', '', mesonlog, gen_time, build_time, test_time) + return TestResult(validate_install(testdir, install_dir, compiler), BuildStep.validate, stdo, stde, mesonlog, gen_time, build_time, test_time) def gather_tests(testdir): tests = [t.replace('\\', '/').split('/', 2)[2] for t in glob(os.path.join(testdir, '*'))] @@ -421,23 +410,6 @@ def have_java(): return True return False -def using_backend(backends): - if isinstance(backends, str): - backends = (backends,) - for backend in backends: - if backend == 'ninja': - if not backend_flags: - return True - elif backend == 'xcode': - if backend_flags == '--backend=xcode': - return True - elif backend == 'vs': - if backend_flags.startswith('--backend=vs'): - return True - else: - raise AssertionError('Unknown backend type: ' + backend) - return False - def detect_tests_to_run(): all_tests = [] all_tests.append(('common', gather_tests('test cases/common'), False)) @@ -450,15 +422,15 @@ def detect_tests_to_run(): all_tests.append(('platform-windows', gather_tests('test cases/windows'), False if mesonlib.is_windows() or mesonlib.is_cygwin() else True)) all_tests.append(('platform-linux', gather_tests('test cases/linuxlike'), False if not (mesonlib.is_osx() or mesonlib.is_windows()) else True)) all_tests.append(('framework', gather_tests('test cases/frameworks'), False if not mesonlib.is_osx() and not mesonlib.is_windows() and not mesonlib.is_cygwin() else True)) - all_tests.append(('java', gather_tests('test cases/java'), False if using_backend('ninja') and not mesonlib.is_osx() and have_java() else True)) - all_tests.append(('C#', gather_tests('test cases/csharp'), False if using_backend('ninja') and shutil.which('mcs') else True)) - all_tests.append(('vala', gather_tests('test cases/vala'), False if using_backend('ninja') and shutil.which('valac') else True)) - all_tests.append(('rust', gather_tests('test cases/rust'), False if using_backend('ninja') and shutil.which('rustc') else True)) - all_tests.append(('d', gather_tests('test cases/d'), False if using_backend('ninja') and have_d_compiler() else True)) - all_tests.append(('objective c', gather_tests('test cases/objc'), False if using_backend(('ninja', 'xcode')) and not mesonlib.is_windows() else True)) - all_tests.append(('fortran', gather_tests('test cases/fortran'), False if using_backend('ninja') and shutil.which('gfortran') else True)) - all_tests.append(('swift', gather_tests('test cases/swift'), False if using_backend(('ninja', 'xcode')) and shutil.which('swiftc') else True)) - all_tests.append(('python3', gather_tests('test cases/python3'), False if using_backend('ninja') and shutil.which('python3') else True)) + all_tests.append(('java', gather_tests('test cases/java'), False if backend is Backend.ninja and not mesonlib.is_osx() and have_java() else True)) + all_tests.append(('C#', gather_tests('test cases/csharp'), False if backend is Backend.ninja and shutil.which('mcs') else True)) + all_tests.append(('vala', gather_tests('test cases/vala'), False if backend is Backend.ninja and shutil.which('valac') else True)) + all_tests.append(('rust', gather_tests('test cases/rust'), False if backend is Backend.ninja and shutil.which('rustc') else True)) + all_tests.append(('d', gather_tests('test cases/d'), False if backend is Backend.ninja and have_d_compiler() else True)) + all_tests.append(('objective c', gather_tests('test cases/objc'), False if backend in (Backend.ninja, Backend.xcode) and not mesonlib.is_windows() else True)) + all_tests.append(('fortran', gather_tests('test cases/fortran'), False if backend is Backend.ninja and shutil.which('gfortran') else True)) + all_tests.append(('swift', gather_tests('test cases/swift'), False if backend in (Backend.ninja, Backend.xcode) and shutil.which('swiftc') else True)) + all_tests.append(('python3', gather_tests('test cases/python3'), False if backend is Backend.ninja and shutil.which('python3') else True)) return all_tests def run_tests(all_tests, log_name_base, extra_args): @@ -473,6 +445,7 @@ def run_tests(all_tests, log_name_base, extra_args): passing_tests = 0 failing_tests = 0 skipped_tests = 0 + commands = (compile_commands, clean_commands, install_commands, uninstall_commands) try: # This fails in some CI environments for unknown reasons. @@ -502,7 +475,7 @@ def run_tests(all_tests, log_name_base, extra_args): should_fail = False if name.startswith('failing'): should_fail = name.split('failing-')[1] - result = executor.submit(run_test, skipped, t, extra_args, unity_flags + backend_flags, compile_commands, should_fail) + result = executor.submit(run_test, skipped, t, extra_args, compiler, backend, backend_flags, commands, should_fail) futures.append((testname, t, result)) for (testname, t, result) in futures: sys.stdout.flush() @@ -617,7 +590,7 @@ def generate_prebuilt(): return objectfile, stlibfile def check_meson_commands_work(): - global meson_command, compile_commands, test_commands, install_commands + global backend, meson_command, compile_commands, test_commands, install_commands testdir = 'test cases/common/1 trivial' with AutoDeletedDir(tempfile.mkdtemp(prefix='b ', dir='.')) as build_dir: print('Checking that configuring works...') @@ -626,8 +599,8 @@ def check_meson_commands_work(): if pc.returncode != 0: raise RuntimeError('Failed to configure {!r}:\n{}\n{}'.format(testdir, e, o)) print('Checking that building works...') - compile_cmd = get_compile_commands_for_dir(compile_commands, build_dir) - pc, o, e = Popen_safe(compile_cmd, cwd=build_dir) + dir_args = get_backend_args_for_dir(backend, build_dir) + pc, o, e = Popen_safe(compile_commands + dir_args, cwd=build_dir) if pc.returncode != 0: raise RuntimeError('Failed to build {!r}:\n{}\n{}'.format(testdir, e, o)) print('Checking that testing works...') @@ -649,21 +622,6 @@ if __name__ == '__main__': options = parser.parse_args() setup_commands(options.backend) - # Appveyor sets the `platform` environment variable which completely messes - # up building with the vs2010 and vs2015 backends. - # - # Specifically, MSBuild reads the `platform` environment variable to set - # the configured value for the platform (Win32/x64/arm), which breaks x86 - # builds. - # - # Appveyor setting this also breaks our 'native build arch' detection for - # Windows in environment.py:detect_windows_arch() by overwriting the value - # of `platform` set by vcvarsall.bat. - # - # While building for x86, `platform` should be unset. - if 'APPVEYOR' in os.environ and os.environ['arch'] == 'x86': - os.environ.pop('platform') - script_dir = os.path.split(__file__)[0] if script_dir != '': os.chdir(script_dir) diff --git a/run_tests.py b/run_tests.py index 02aa701..d0a67e8 100755 --- a/run_tests.py +++ b/run_tests.py @@ -20,28 +20,138 @@ import shutil import subprocess import platform from mesonbuild import mesonlib +from mesonbuild.environment import detect_ninja +from enum import Enum +from glob import glob -def using_vs_backend(): - for arg in sys.argv[1:]: - if arg.startswith('--backend=vs'): - return True - return False +Backend = Enum('Backend', 'ninja vs xcode') + +if mesonlib.is_windows() or mesonlib.is_cygwin(): + exe_suffix = '.exe' +else: + exe_suffix = '' + +def get_backend_args_for_dir(backend, builddir): + ''' + Visual Studio backend needs to be given the solution to build + ''' + if backend is Backend.vs: + sln_name = glob(os.path.join(builddir, '*.sln'))[0] + return [os.path.split(sln_name)[-1]] + return [] + +def find_vcxproj_with_target(builddir, target): + import re, fnmatch + t, ext = os.path.splitext(target) + if ext: + p = '<TargetName>{}</TargetName>\s*<TargetExt>\{}</TargetExt>'.format(t, ext) + else: + p = '<TargetName>{}</TargetName>'.format(t) + for root, dirs, files in os.walk(builddir): + for f in fnmatch.filter(files, '*.vcxproj'): + f = os.path.join(builddir, f) + with open(f, 'r', encoding='utf-8') as o: + if re.search(p, o.read(), flags=re.MULTILINE): + return f + raise RuntimeError('No vcxproj matching {!r} in {!r}'.format(p, builddir)) + +def get_builddir_target_args(backend, builddir, target): + dir_args = [] + if not target: + dir_args = get_backend_args_for_dir(backend, builddir) + if target is None: + return dir_args + if backend is Backend.vs: + vcxproj = find_vcxproj_with_target(builddir, target) + target_args = [vcxproj] + elif backend is Backend.xcode: + target_args = ['-target', target] + elif backend is Backend.ninja: + target_args = [target] + else: + raise AssertionError('Unknown backend: {!r}'.format(backend)) + return target_args + dir_args + +def get_backend_commands(backend, debug=False): + install_cmd = [] + uninstall_cmd = [] + if backend is Backend.vs: + cmd = ['msbuild'] + clean_cmd = cmd + ['/target:Clean'] + test_cmd = cmd + ['RUN_TESTS.vcxproj'] + elif backend is Backend.xcode: + cmd = ['xcodebuild'] + clean_cmd = cmd + ['-alltargets', 'clean'] + test_cmd = cmd + ['-target', 'RUN_TESTS'] + elif backend is Backend.ninja: + # We need at least 1.6 because of -w dupbuild=err + cmd = [detect_ninja('1.6'), '-w', 'dupbuild=err'] + if cmd[0] is None: + raise RuntimeError('Could not find Ninja v1.6 or newer') + if debug: + cmd += ['-v'] + clean_cmd = cmd + ['clean'] + test_cmd = cmd + ['test', 'benchmark'] + install_cmd = cmd + ['install'] + uninstall_cmd = cmd + ['uninstall'] + else: + raise AssertionError('Unknown backend: {!r}'.format(backend)) + return cmd, clean_cmd, test_cmd, install_cmd, uninstall_cmd + +def get_fake_options(prefix): + import argparse + opts = argparse.Namespace() + opts.cross_file = None + opts.wrap_mode = None + opts.prefix = prefix + return opts + +class FakeEnvironment(object): + def __init__(self): + self.cross_info = None + + def is_cross_build(self): + return False if __name__ == '__main__': returncode = 0 + # Iterate over list in reverse order to find the last --backend arg + backend = Backend.ninja + for arg in reversed(sys.argv[1:]): + if arg.startswith('--backend'): + if arg.startswith('--backend=vs'): + backend = Backend.vs + elif arg == '--backend=xcode': + backend = Backend.xcode + break # Running on a developer machine? Be nice! if not mesonlib.is_windows() and 'TRAVIS' not in os.environ: os.nice(20) + # Appveyor sets the `platform` environment variable which completely messes + # up building with the vs2010 and vs2015 backends. + # + # Specifically, MSBuild reads the `platform` environment variable to set + # the configured value for the platform (Win32/x64/arm), which breaks x86 + # builds. + # + # Appveyor setting this also breaks our 'native build arch' detection for + # Windows in environment.py:detect_windows_arch() by overwriting the value + # of `platform` set by vcvarsall.bat. + # + # While building for x86, `platform` should be unset. + if 'APPVEYOR' in os.environ and os.environ['arch'] == 'x86': + os.environ.pop('platform') + # Run tests print('Running unittests.\n') units = ['InternalTests', 'AllPlatformTests'] if mesonlib.is_linux(): units += ['LinuxlikeTests'] elif mesonlib.is_windows(): units += ['WindowsTests'] - # Unit tests always use the Ninja backend, so just skip them if we're - # testing the VS backend - if not using_vs_backend(): - returncode += subprocess.call([sys.executable, 'run_unittests.py', '-v'] + units) + # Can't pass arguments to unit tests, so set the backend to use in the environment + env = os.environ.copy() + env['MESON_UNIT_TEST_BACKEND'] = backend.name + returncode += subprocess.call([sys.executable, 'run_unittests.py', '-v'] + units, env=env) # Ubuntu packages do not have a binary without -6 suffix. if shutil.which('arm-linux-gnueabihf-gcc-6') and not platform.machine().startswith('arm'): print('Running cross compilation tests.\n') diff --git a/run_unittests.py b/run_unittests.py index 72e74f1..6ea1d41 100755 --- a/run_unittests.py +++ b/run_unittests.py @@ -25,13 +25,12 @@ import mesonbuild.compilers import mesonbuild.environment import mesonbuild.mesonlib from mesonbuild.mesonlib import is_windows, is_osx, is_cygwin -from mesonbuild.environment import detect_ninja, Environment +from mesonbuild.environment import Environment from mesonbuild.dependencies import PkgConfigDependency, ExternalProgram -if is_windows() or is_cygwin(): - exe_suffix = '.exe' -else: - exe_suffix = '' +from run_tests import exe_suffix, get_fake_options, FakeEnvironment +from run_tests import get_builddir_target_args, get_backend_commands, Backend + def get_soname(fname): # HACK, fix to not use shell. @@ -44,21 +43,6 @@ def get_soname(fname): return m.group(1) raise RuntimeError('Could not determine soname:\n\n' + raw_out) -def get_fake_options(prefix): - import argparse - opts = argparse.Namespace() - opts.cross_file = None - opts.wrap_mode = None - opts.prefix = prefix - return opts - -class FakeEnvironment(object): - def __init__(self): - self.cross_info = None - - def is_cross_build(self): - return False - class InternalTests(unittest.TestCase): def test_version_number(self): @@ -346,11 +330,18 @@ class BasePlatformTests(unittest.TestCase): self.prefix = '/usr' self.libdir = os.path.join(self.prefix, 'lib') self.installdir = os.path.join(self.builddir, 'install') - self.meson_command = [sys.executable, os.path.join(src_root, 'meson.py')] + # Get the backend + # FIXME: Extract this from argv? + self.backend = getattr(Backend, os.environ.get('MESON_UNIT_TEST_BACKEND', 'ninja')) + self.meson_command = [sys.executable, os.path.join(src_root, 'meson.py'), + '--backend=' + self.backend.name] self.mconf_command = [sys.executable, os.path.join(src_root, 'mesonconf.py')] self.mintro_command = [sys.executable, os.path.join(src_root, 'mesonintrospect.py')] self.mtest_command = [sys.executable, os.path.join(src_root, 'mesontest.py'), '-C', self.builddir] - self.ninja_command = [detect_ninja(), '-C', self.builddir] + # Backend-specific build commands + self.build_command, self.clean_command, self.test_command, self.install_command, \ + self.uninstall_command = get_backend_commands(self.backend) + # Test directories self.common_test_dir = os.path.join(src_root, 'test cases/common') self.vala_test_dir = os.path.join(src_root, 'test cases/vala') self.framework_test_dir = os.path.join(src_root, 'test cases/frameworks') @@ -370,14 +361,14 @@ class BasePlatformTests(unittest.TestCase): os.environ = self.orig_env super().tearDown() - def _run(self, command): + def _run(self, command, workdir=None): ''' Run a command while printing the stdout and stderr to stdout, and also return a copy of it ''' p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, env=os.environ.copy(), - universal_newlines=True) + universal_newlines=True, cwd=workdir) output = p.communicate()[0] print(output) if p.returncode != 0: @@ -398,27 +389,36 @@ class BasePlatformTests(unittest.TestCase): raise self.privatedir = os.path.join(self.builddir, 'meson-private') - def build(self, extra_args=None): + def build(self, target=None, extra_args=None): if extra_args is None: extra_args = [] - self._run(self.ninja_command + extra_args) + # Add arguments for building the target (if specified), + # and using the build dir (if required, with VS) + args = get_builddir_target_args(self.backend, self.builddir, target) + self._run(self.build_command + args + extra_args, workdir=self.builddir) + + def clean(self): + dir_args = get_builddir_target_args(self.backend, self.builddir, None) + self._run(self.clean_command + dir_args, workdir=self.builddir) def run_tests(self): - self._run(self.ninja_command + ['test']) + self._run(self.test_command, workdir=self.builddir) def install(self): + if self.backend is not Backend.ninja: + raise unittest.SkipTest('{!r} backend can\'t install files'.format(self.backend.name)) os.environ['DESTDIR'] = self.installdir - self._run(self.ninja_command + ['install']) + self._run(self.install_command, workdir=self.builddir) def uninstall(self): - self._run(self.ninja_command + ['uninstall']) + self._run(self.uninstall_command, workdir=self.builddir) def run_target(self, target): ''' Run a Ninja target while printing the stdout and stderr to stdout, and also return a copy of it ''' - return self._run(self.ninja_command + [target]) + return self.build(target=target) def setconf(self, arg, will_build=True): # This is needed to increase the difference between build.ninja's @@ -432,13 +432,15 @@ class BasePlatformTests(unittest.TestCase): shutil.rmtree(self.builddir) def get_compdb(self): + if self.backend is not Backend.ninja: + raise unittest.SkipTest('Compiler db not available with {} backend'.format(self.backend.name)) with open(os.path.join(self.builddir, 'compile_commands.json')) as ifile: contents = json.load(ifile) # If Ninja is using .rsp files, generate them, read their contents, and # replace it as the command for all compile commands in the parsed json. if len(contents) > 0 and contents[0]['command'].endswith('.rsp'): # Pretend to build so that the rsp files are generated - self.build(['-d', 'keeprsp', '-n']) + self.build(extra_args=['-d', 'keeprsp', '-n']) for each in contents: # Extract the actual command from the rsp file compiler, rsp = each['command'].split(' @') @@ -613,6 +615,8 @@ class AllPlatformTests(BasePlatformTests): Tests that the Meson introspection API exposes install filenames correctly https://github.com/mesonbuild/meson/issues/829 ''' + if self.backend is not Backend.ninja: + raise unittest.SkipTest('{!r} backend can\'t install files'.format(self.backend.name)) testdir = os.path.join(self.common_test_dir, '8 install') self.init(testdir) intro = self.introspect('--targets') @@ -722,7 +726,7 @@ class AllPlatformTests(BasePlatformTests): exe = os.path.join(self.builddir, 'fooprog' + exe_suffix) self.assertTrue(os.path.exists(genfile)) self.assertFalse(os.path.exists(exe)) - self._run(self.ninja_command + ['fooprog' + exe_suffix]) + self.build(target=('fooprog' + exe_suffix)) self.assertTrue(os.path.exists(exe)) def test_internal_include_order(self): @@ -964,6 +968,15 @@ class AllPlatformTests(BasePlatformTests): os.environ['CFLAGS'] = '-DMESON_FAIL_VALUE=cflags-read'.format(define) self.init(testdir, ['-D{}={}'.format(define, value)]) + def test_custom_target_exe_data_deterministic(self): + testdir = os.path.join(self.common_test_dir, '117 custom target capture') + self.init(testdir) + meson_exe_dat1 = glob(os.path.join(self.privatedir, 'meson_exe*.dat')) + self.wipe() + self.init(testdir) + meson_exe_dat2 = glob(os.path.join(self.privatedir, 'meson_exe*.dat')) + self.assertListEqual(meson_exe_dat1, meson_exe_dat2) + class WindowsTests(BasePlatformTests): ''' @@ -1229,15 +1242,6 @@ class LinuxlikeTests(BasePlatformTests): Oargs = [arg for arg in cmd if arg.startswith('-O')] self.assertEqual(Oargs, [Oflag, '-O0']) - def test_custom_target_exe_data_deterministic(self): - testdir = os.path.join(self.common_test_dir, '117 custom target capture') - self.init(testdir) - meson_exe_dat1 = glob(os.path.join(self.privatedir, 'meson_exe*.dat')) - self.wipe() - self.init(testdir) - meson_exe_dat2 = glob(os.path.join(self.privatedir, 'meson_exe*.dat')) - self.assertListEqual(meson_exe_dat1, meson_exe_dat2) - def _test_stds_impl(self, testdir, compiler, p): lang_std = p + '_std' # Check that all the listed -std=xxx options for this compiler work diff --git a/test cases/common/139 custom target multiple outputs/generator.py b/test cases/common/139 custom target multiple outputs/generator.py new file mode 100755 index 0000000..39dbd11 --- /dev/null +++ b/test cases/common/139 custom target multiple outputs/generator.py @@ -0,0 +1,14 @@ +#!/usr/bin/env python3 + +import sys, os + +if len(sys.argv) != 3: + print(sys.argv[0], '<namespace>', '<output dir>') + +name = sys.argv[1] +odir = sys.argv[2] + +with open(os.path.join(odir, name + '.h'), 'w') as f: + f.write('int func();\n') +with open(os.path.join(odir, name + '.sh'), 'w') as f: + f.write('#!/bin/bash') diff --git a/test cases/common/139 custom target multiple outputs/installed_files.txt b/test cases/common/139 custom target multiple outputs/installed_files.txt new file mode 100644 index 0000000..21e1249 --- /dev/null +++ b/test cases/common/139 custom target multiple outputs/installed_files.txt @@ -0,0 +1,6 @@ +usr/include/diff.h +usr/include/first.h +usr/bin/diff.sh +usr/bin/second.sh +opt/same.h +opt/same.sh diff --git a/test cases/common/139 custom target multiple outputs/meson.build b/test cases/common/139 custom target multiple outputs/meson.build new file mode 100644 index 0000000..6412864 --- /dev/null +++ b/test cases/common/139 custom target multiple outputs/meson.build @@ -0,0 +1,28 @@ +project('multiple outputs install', 'c') + +gen = find_program('generator.py') + +custom_target('different-install-dirs', + output : ['diff.h', 'diff.sh'], + command : [gen, 'diff', '@OUTDIR@'], + install : true, + install_dir : [join_paths(get_option('prefix'), get_option('includedir')), + join_paths(get_option('prefix'), get_option('bindir'))]) + +custom_target('same-install-dir', + output : ['same.h', 'same.sh'], + command : [gen, 'same', '@OUTDIR@'], + install : true, + install_dir : '/opt') + +custom_target('only-install-first', + output : ['first.h', 'first.sh'], + command : [gen, 'first', '@OUTDIR@'], + install : true, + install_dir : [join_paths(get_option('prefix'), get_option('includedir')), false]) + +custom_target('only-install-second', + output : ['second.h', 'second.sh'], + command : [gen, 'second', '@OUTDIR@'], + install : true, + install_dir : [false, join_paths(get_option('prefix'), get_option('bindir'))]) diff --git a/test cases/failing/43 custom target outputs not matching install_dirs/generator.py b/test cases/failing/43 custom target outputs not matching install_dirs/generator.py new file mode 100755 index 0000000..4ac6179 --- /dev/null +++ b/test cases/failing/43 custom target outputs not matching install_dirs/generator.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python3 + +import sys, os + +if len(sys.argv) != 3: + print(sys.argv[0], '<namespace>', '<output dir>') + +name = sys.argv[1] +odir = sys.argv[2] + +with open(os.path.join(odir, name + '.h'), 'w') as f: + f.write('int func();\n') +with open(os.path.join(odir, name + '.c'), 'w') as f: + f.write('int main(int argc, char *argv[]) { return 0; }') +with open(os.path.join(odir, name + '.sh'), 'w') as f: + f.write('#!/bin/bash') diff --git a/test cases/failing/43 custom target outputs not matching install_dirs/installed_files.txt b/test cases/failing/43 custom target outputs not matching install_dirs/installed_files.txt new file mode 100644 index 0000000..21e1249 --- /dev/null +++ b/test cases/failing/43 custom target outputs not matching install_dirs/installed_files.txt @@ -0,0 +1,6 @@ +usr/include/diff.h +usr/include/first.h +usr/bin/diff.sh +usr/bin/second.sh +opt/same.h +opt/same.sh diff --git a/test cases/failing/43 custom target outputs not matching install_dirs/meson.build b/test cases/failing/43 custom target outputs not matching install_dirs/meson.build new file mode 100644 index 0000000..45bd7b3 --- /dev/null +++ b/test cases/failing/43 custom target outputs not matching install_dirs/meson.build @@ -0,0 +1,13 @@ +project('outputs not matching install_dirs', 'c') + +gen = find_program('generator.py') + +if meson.backend() != 'ninja' + error('Failing manually, test is only for the ninja backend') +endif + +custom_target('too-few-install-dirs', + output : ['toofew.h', 'toofew.c', 'toofew.sh'], + command : [gen, 'toofew', '@OUTDIR@'], + install : true, + install_dir : [join_paths(get_option('prefix'), get_option('includedir')), false]) diff --git a/test cases/linuxlike/7 library versions/installed_files.txt b/test cases/linuxlike/7 library versions/installed_files.txt index b997e53..763a907 100644 --- a/test cases/linuxlike/7 library versions/installed_files.txt +++ b/test cases/linuxlike/7 library versions/installed_files.txt @@ -7,3 +7,4 @@ usr/lib/libonlyversion.so.1 usr/lib/libonlyversion.so.1.4.5 usr/lib/libonlysoversion.so usr/lib/libonlysoversion.so.5 +usr/lib/libmodule.so diff --git a/test cases/linuxlike/7 library versions/meson.build b/test cases/linuxlike/7 library versions/meson.build index 451e42e..d156eb0 100644 --- a/test cases/linuxlike/7 library versions/meson.build +++ b/test cases/linuxlike/7 library versions/meson.build @@ -47,3 +47,5 @@ test('manually linked 3', executable('manuallink3', out, test('manually linked 4', executable('manuallink4', out, link_args : ['-L.', '-lonlysoversion', rpath_arg])) + +shared_module('module', 'lib.c', install : true) diff --git a/test cases/osx/2 library versions/installed_files.txt b/test cases/osx/2 library versions/installed_files.txt index fc76046..de7b078 100644 --- a/test cases/osx/2 library versions/installed_files.txt +++ b/test cases/osx/2 library versions/installed_files.txt @@ -5,3 +5,4 @@ usr/lib/libonlyversion.dylib usr/lib/libonlyversion.1.dylib usr/lib/libonlysoversion.dylib usr/lib/libonlysoversion.5.dylib +usr/lib/libmodule.dylib diff --git a/test cases/osx/2 library versions/meson.build b/test cases/osx/2 library versions/meson.build index b1962ca..9624998 100644 --- a/test cases/osx/2 library versions/meson.build +++ b/test cases/osx/2 library versions/meson.build @@ -39,3 +39,5 @@ test('manually linked 3', executable('manuallink3', out, test('manually linked 4', executable('manuallink4', out, link_args : ['-L.', '-lonlysoversion'])) + +shared_module('module', 'lib.c', install : true) diff --git a/test cases/vala/7 shared library/installed_files.txt b/test cases/vala/7 shared library/installed_files.txt new file mode 100644 index 0000000..16ea442 --- /dev/null +++ b/test cases/vala/7 shared library/installed_files.txt @@ -0,0 +1,8 @@ +usr/lib/libinstalled_vala_lib.so +usr/lib/libinstalled_vala_all.so +usr/include/installed_vala_all.h +usr/include/installed_vala_all_nolib.h +usr/include/installed_vala_onlyh.h +usr/share/vala/vapi/installed_vala_all.vapi +usr/share/vala/vapi/installed_vala_all_nolib.vapi +usr/share/vala/vapi/installed_vala_onlyvapi.vapi diff --git a/test cases/vala/7 shared library/lib/meson.build b/test cases/vala/7 shared library/lib/meson.build index 8eca0d4..bb1e800 100644 --- a/test cases/vala/7 shared library/lib/meson.build +++ b/test cases/vala/7 shared library/lib/meson.build @@ -1 +1,33 @@ l = shared_library('valalib', 'mylib.vala', dependencies : valadeps) + +shared_library('installed_vala_lib', 'mylib.vala', + dependencies : valadeps, + install : true) + +shared_library('installed_vala_all', 'mylib.vala', + dependencies : valadeps, + install : true, + install_dir : [true, + join_paths(get_option('prefix'), get_option('includedir')), + join_paths(get_option('prefix'), get_option('datadir'), 'vala', 'vapi')]) + +shared_library('installed_vala_all_nolib', 'mylib.vala', + dependencies : valadeps, + install : true, + install_dir : [false, + join_paths(get_option('prefix'), get_option('includedir')), + join_paths(get_option('prefix'), get_option('datadir'), 'vala', 'vapi')]) + +shared_library('installed_vala_onlyh', 'mylib.vala', + dependencies : valadeps, + install : true, + install_dir : [false, + join_paths(get_option('prefix'), get_option('includedir')), + false]) + +shared_library('installed_vala_onlyvapi', 'mylib.vala', + dependencies : valadeps, + install : true, + install_dir : [false, + false, + join_paths(get_option('prefix'), get_option('datadir'), 'vala', 'vapi')]) diff --git a/test cases/windows/7 mingw dll versioning/installed_files.txt b/test cases/windows/7 mingw dll versioning/installed_files.txt index 661005c..26e14a7 100644 --- a/test cases/windows/7 mingw dll versioning/installed_files.txt +++ b/test cases/windows/7 mingw dll versioning/installed_files.txt @@ -6,3 +6,6 @@ usr/bin/?libonlyversion-1.dll usr/lib/libonlyversion.dll.a usr/bin/?libonlysoversion-5.dll usr/lib/libonlysoversion.dll.a +usr/libexec/?libcustomdir.dll +usr/libexec/libcustomdir.dll.a +usr/lib/?libmodule.dll diff --git a/test cases/windows/7 mingw dll versioning/meson.build b/test cases/windows/7 mingw dll versioning/meson.build index d1fe73a..1d6562c 100644 --- a/test cases/windows/7 mingw dll versioning/meson.build +++ b/test cases/windows/7 mingw dll versioning/meson.build @@ -47,3 +47,9 @@ test('manually linked 3', executable('manuallink3', out, test('manually linked 4', executable('manuallink4', out, link_args : ['-L.', '-lonlysoversion'])) + +shared_library('customdir', 'lib.c', + install : true, + install_dir : get_option('libexecdir')) + +shared_module('module', 'lib.c', install : true) diff --git a/test cases/windows/8 msvc dll versioning/installed_files.txt b/test cases/windows/8 msvc dll versioning/installed_files.txt index ae0fa1f..df43343 100644 --- a/test cases/windows/8 msvc dll versioning/installed_files.txt +++ b/test cases/windows/8 msvc dll versioning/installed_files.txt @@ -8,3 +8,6 @@ usr/bin/onlyversion-1.dll usr/lib/onlyversion.lib usr/bin/onlysoversion-5.dll usr/lib/onlysoversion.lib +usr/libexec/customdir.dll +usr/libexec/customdir.lib +usr/lib/module.dll diff --git a/test cases/windows/8 msvc dll versioning/meson.build b/test cases/windows/8 msvc dll versioning/meson.build index b72c5ec..4074747 100644 --- a/test cases/windows/8 msvc dll versioning/meson.build +++ b/test cases/windows/8 msvc dll versioning/meson.build @@ -48,3 +48,9 @@ test('manually linked 3', executable('manuallink3', out, test('manually linked 4', executable('manuallink4', out, link_args : ['-L.', '-lonlysoversion'])) + +shared_library('customdir', 'lib.c', + install : true, + install_dir : get_option('libexecdir')) + +shared_module('module', 'lib.c', install : true) |