diff options
63 files changed, 598 insertions, 145 deletions
diff --git a/ci/appveyor-install.bat b/ci/appveyor-install.bat index 2d4a8cb..1e60179 100755 --- a/ci/appveyor-install.bat +++ b/ci/appveyor-install.bat @@ -10,10 +10,13 @@ echo Updating Cygwin and installing ninja and test prerequisites %CYGWIN_ROOT%\%SETUP% -qnNdO -R "%CYGWIN_ROOT%" -s "%CYGWIN_MIRROR%" -l "%CACHE%" -g -P ^ gcc-objc++,^ gcc-objc,^ +gobject-introspection,^ libboost-devel,^ libglib2.0-devel,^ +libgtk3-devel,^ ninja,^ python3-pip,^ +vala,^ zlib-devel echo Install done diff --git a/docs/markdown/Reference-manual.md b/docs/markdown/Reference-manual.md index e30b79c..a3e1ef0 100644 --- a/docs/markdown/Reference-manual.md +++ b/docs/markdown/Reference-manual.md @@ -403,7 +403,7 @@ be passed to [shared and static libraries](#library). flags here for all platforms. - `link_depends` strings, files, or custom targets the link step depends on such as a symbol visibility map. The purpose is to - automaticallytrigger a re-link (but not a re-compile) of the target + automatically trigger a re-link (but not a re-compile) of the target when this file changes. - `link_whole` links all contents of the given static libraries whether they are used by not, equivalent to the @@ -412,13 +412,18 @@ be passed to [shared and static libraries](#library). - `link_with`, one or more shared or static libraries (built by this project) that this target should be linked with, If passed a list this list will be flattened as of 0.41.0. +- `export_dynamic` when set to true causes the target's symbols to be + dynamically exported, allowing modules built using the + [`shared_module`](#shared_module) function to refer to functions, + variables and other symbols defined in the executable itself. Implies + the `implib` argument. Since 0.44.0 - `implib` when set to true, an import library is generated for the executable (the name of the import library is based on *exe_name*). Alternatively, when set to a string, that gives the base name for the import library. The import library is used when the returned build target object appears in `link_with:` elsewhere. Only has any - effect on platforms where that is meaningful (e.g. Windows). Since - 0.42.0 + effect on platforms where that is meaningful (e.g. Windows). Implies + the `export_dynamic` argument. Since 0.42.0 - `implicit_include_directories` is a boolean telling whether Meson adds the current source and build directories to the include path, defaults to `true`, since 0.42.0 @@ -1010,6 +1015,11 @@ This is useful for building modules that will be `dlopen()`ed and hence may contain undefined symbols that will be provided by the library that is loading it. +If you want the shared module to be able to refer to functions and +variables defined in the [`executable`](#executable) it is loaded by, +you will need to set the `export_dynamic` argument of the executable to +`true`. + *Added 0.37.0* ### static_library() @@ -1695,11 +1705,18 @@ This object is returned by [`generator()`](#generator) and contains a generator that is used to transform files from one type to another by an executable (e.g. `idl` files into source code and headers). -* `process(list_of_files)` takes a list of files, causes them to be - processed and returns an object containing the result which can +* `process(list_of_files, ...)` takes a list of files, causes them to + be processed and returns an object containing the result which can then, for example, be passed into a build target definition. The keyword argument `extra_args`, if specified, will be used to replace - an entry `@EXTRA_ARGS@` in the argument list. + an entry `@EXTRA_ARGS@` in the argument list. The keyword argument + `preserve_path_from`, if given, specifies that the output files need + to maintain their directory structure inside the target temporary + directory. The most common value for this is + `meson.current_source_dir()`. With this value when a file called + `subdir/one.input` is processed it generates a file `<target private + directory>/subdir/one.out` as opposed to `<target private + directory>/one.out`. ### `subproject` object diff --git a/docs/markdown/Reference-tables.md b/docs/markdown/Reference-tables.md index 8e048dc..ee3b8c2 100644 --- a/docs/markdown/Reference-tables.md +++ b/docs/markdown/Reference-tables.md @@ -57,6 +57,9 @@ These are provided by the `.system()` method call. | windows | Any version of Windows | | cygwin | The Cygwin environment for Windows | | haiku | | +| freebsd | FreeBSD and it's derivatives | +| dragonfly | DragonFly BSD | +| netbsd | | Any string not listed above is not guaranteed to remain stable in future releases. diff --git a/docs/markdown/snippets/gen-subdirs.md b/docs/markdown/snippets/gen-subdirs.md new file mode 100644 index 0000000..fdb5945 --- /dev/null +++ b/docs/markdown/snippets/gen-subdirs.md @@ -0,0 +1,21 @@ +## Generator outputs can preserve directory structure + +Normally when generating files with a generator, Meson flattens the +input files so they all go in the same directory. Some code +generators, such as Protocol Buffers, require that the generated files +have the same directory layout as the input files used to generate +them. This can now be achieved like this: + +```meson +g = generator(...) # Compiles protobuf sources +generated = gen.process('com/mesonbuild/one.proto', + 'com/mesonbuild/two.proto', + preserve_path_from : meson.current_source_dir()) + +This would cause the following files to be generated inside the target +private directory: + + com/mesonbuild/one.pb.h + com/mesonbuild/one.pb.cc + com/mesonbuild/two.pb.h + com/mesonbuild/two.pb.cc diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index 1057892..77c7d50 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -42,8 +42,12 @@ def ninja_quote(text): for char in ('$', ' ', ':'): text = text.replace(char, '$' + char) if '\n' in text: - raise MesonException('Ninja does not support newlines in rules. ' - 'Please report this error with a test case to the Meson bug tracker.') + errmsg = '''Ninja does not support newlines in rules. The content was: + +%s + +Please report this error with a test case to the Meson bug tracker.''' % text + raise MesonException(errmsg) return text @@ -1787,18 +1791,23 @@ rule FORTRAN_DEP_HACK continue self.generate_genlist_for_target(genlist, target, outfile) - def replace_paths(self, target, args): - source_target_dir = self.get_target_source_dir(target) + def replace_paths(self, target, args, override_subdir=None): + if override_subdir: + source_target_dir = os.path.join(self.build_to_src, override_subdir) + else: + source_target_dir = self.get_target_source_dir(target) relout = self.get_target_private_dir(target) args = [x.replace("@SOURCE_DIR@", self.build_to_src).replace("@BUILD_DIR@", relout) for x in args] args = [x.replace("@CURRENT_SOURCE_DIR@", source_target_dir) for x in args] args = [x.replace("@SOURCE_ROOT@", self.build_to_src).replace("@BUILD_ROOT@", '.') for x in args] + args = [x.replace('\\', '/') for x in args] return args def generate_genlist_for_target(self, genlist, target, outfile): generator = genlist.get_generator() + subdir = genlist.subdir exe = generator.get_exe() exe_arr = self.exe_object_to_cmd_array(exe) infilelist = genlist.get_inputs() @@ -1830,7 +1839,7 @@ rule FORTRAN_DEP_HACK if sole_output == '': outfilelist = outfilelist[len(generator.outputs):] relout = self.get_target_private_dir(target) - args = self.replace_paths(target, args) + args = self.replace_paths(target, args, override_subdir=subdir) cmdlist = exe_arr + self.replace_extra_args(args, genlist) if generator.capture: exe_data = self.serialize_executable( @@ -2254,7 +2263,7 @@ rule FORTRAN_DEP_HACK def generate_msvc_pch_command(self, target, compiler, pch): if len(pch) != 2: - raise RuntimeError('MSVC requires one header and one source to produce precompiled headers.') + raise MesonException('MSVC requires one header and one source to produce precompiled headers.') header = pch[0] source = pch[1] pchname = compiler.get_pch_name(header) @@ -2337,6 +2346,9 @@ rule FORTRAN_DEP_HACK # If gui_app, and that's significant on this platform if target.gui_app and hasattr(linker, 'get_gui_app_args'): commands += linker.get_gui_app_args() + # If export_dynamic, add the appropriate linker arguments + if target.export_dynamic: + commands += linker.gen_export_dynamic_link_args(self.environment) # If implib, and that's significant on this platform (i.e. Windows using either GCC or Visual Studio) if target.import_filename: commands += linker.gen_import_library_args(os.path.join(self.get_target_dir(target), target.import_filename)) diff --git a/mesonbuild/backend/vs2010backend.py b/mesonbuild/backend/vs2010backend.py index 6a587ac..1722db7 100644 --- a/mesonbuild/backend/vs2010backend.py +++ b/mesonbuild/backend/vs2010backend.py @@ -87,7 +87,6 @@ class Vs2010Backend(backends.Backend): custom_target_include_dirs = [] custom_target_output_files = [] target_private_dir = self.relpath(self.get_target_private_dir(target), self.get_target_dir(target)) - source_target_dir = self.get_target_source_dir(target) down = self.target_to_build_root(target) for genlist in target.get_generated_sources(): if isinstance(genlist, (build.CustomTarget, build.CustomTargetIndex)): @@ -103,6 +102,7 @@ class Vs2010Backend(backends.Backend): exe = generator.get_exe() infilelist = genlist.get_inputs() outfilelist = genlist.get_outputs() + source_dir = os.path.join(self.build_to_src, genlist.subdir) exe_arr = self.exe_object_to_cmd_array(exe) idgroup = ET.SubElement(parent_node, 'ItemGroup') for i in range(len(infilelist)): @@ -122,10 +122,11 @@ class Vs2010Backend(backends.Backend): args = [x.replace("@SOURCE_DIR@", self.environment.get_source_dir()) .replace("@BUILD_DIR@", target_private_dir) for x in args] - args = [x.replace("@CURRENT_SOURCE_DIR@", source_target_dir) for x in args] + args = [x.replace("@CURRENT_SOURCE_DIR@", source_dir) for x in args] args = [x.replace("@SOURCE_ROOT@", self.environment.get_source_dir()) .replace("@BUILD_ROOT@", self.environment.get_build_dir()) for x in args] + args = [x.replace('\\', '/') for x in args] cmd = exe_arr + self.replace_extra_args(args, genlist) if generator.capture: exe_data = self.serialize_executable( @@ -861,7 +862,14 @@ class Vs2010Backend(backends.Backend): if not pch: continue pch_node.text = 'Use' - pch_sources[lang] = [pch[0], pch[1], lang] + if compiler.id == 'msvc': + if len(pch) != 2: + raise MesonException('MSVC requires one header and one source to produce precompiled headers.') + pch_sources[lang] = [pch[0], pch[1], lang] + else: + # I don't know whether its relevant but let's handle other compilers + # used with a vs backend + pch_sources[lang] = [pch[0], None, lang] if len(pch_sources) == 1: # If there is only 1 language with precompiled headers, we can use it for the entire project, which # is cleaner than specifying it for each source file. @@ -1016,19 +1024,20 @@ class Vs2010Backend(backends.Backend): self.add_include_dirs(lang, inc_cl, file_inc_dirs) for lang in pch_sources: header, impl, suffix = pch_sources[lang] - relpath = os.path.join(proj_to_src_dir, impl) - inc_cl = ET.SubElement(inc_src, 'CLCompile', Include=relpath) - pch = ET.SubElement(inc_cl, 'PrecompiledHeader') - pch.text = 'Create' - pch_out = ET.SubElement(inc_cl, 'PrecompiledHeaderOutputFile') - pch_out.text = '$(IntDir)$(TargetName)-%s.pch' % suffix - pch_file = ET.SubElement(inc_cl, 'PrecompiledHeaderFile') - # 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(lang, inc_cl, file_args) - self.add_preprocessor_defines(lang, inc_cl, file_defines) - self.add_include_dirs(lang, inc_cl, file_inc_dirs) + if impl: + relpath = os.path.join(proj_to_src_dir, impl) + inc_cl = ET.SubElement(inc_src, 'CLCompile', Include=relpath) + pch = ET.SubElement(inc_cl, 'PrecompiledHeader') + pch.text = 'Create' + pch_out = ET.SubElement(inc_cl, 'PrecompiledHeaderOutputFile') + pch_out.text = '$(IntDir)$(TargetName)-%s.pch' % suffix + pch_file = ET.SubElement(inc_cl, 'PrecompiledHeaderFile') + # 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(lang, inc_cl, file_args) + self.add_preprocessor_defines(lang, inc_cl, file_defines) + self.add_include_dirs(lang, inc_cl, file_inc_dirs) if self.has_objects(objects, additional_objects, gen_objs): inc_objs = ET.SubElement(root, 'ItemGroup') diff --git a/mesonbuild/build.py b/mesonbuild/build.py index 8a2e716..5eab794 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -14,7 +14,7 @@ import copy, os, re from collections import OrderedDict -import itertools +import itertools, pathlib from . import environment from . import dependencies @@ -82,6 +82,7 @@ known_lib_kwargs.update({'version': True, # Only for shared libs known_exe_kwargs = known_basic_kwargs.copy() known_exe_kwargs.update({'implib': True, + 'export_dynamic': True }) class InvalidArguments(MesonException): @@ -1076,7 +1077,8 @@ class Generator: def get_base_outnames(self, inname): plainname = os.path.split(inname)[1] basename = os.path.splitext(plainname)[0] - return [x.replace('@BASENAME@', basename).replace('@PLAINNAME@', plainname) for x in self.outputs] + bases = [x.replace('@BASENAME@', basename).replace('@PLAINNAME@', plainname) for x in self.outputs] + return bases def get_dep_outname(self, inname): if self.depfile is None: @@ -1090,32 +1092,54 @@ class Generator: basename = os.path.splitext(plainname)[0] return [x.replace('@BASENAME@', basename).replace('@PLAINNAME@', plainname) for x in self.arglist] - def process_files(self, name, files, state, extra_args=[]): - output = GeneratedList(self, extra_args=extra_args) + def is_parent_path(self, parent, trial): + relpath = pathlib.PurePath(trial).relative_to(parent) + return relpath.parts[0] != '..' # For subdirs we can only go "down". + + def process_files(self, name, files, state, preserve_path_from=None, extra_args=[]): + output = GeneratedList(self, state.subdir, preserve_path_from, extra_args=extra_args) for f in files: if isinstance(f, str): f = File.from_source_file(state.environment.source_dir, state.subdir, f) elif not isinstance(f, File): raise InvalidArguments('{} arguments must be strings or files not {!r}.'.format(name, f)) - output.add_file(f) + if preserve_path_from: + abs_f = f.absolute_path(state.environment.source_dir, state.environment.build_dir) + if not self.is_parent_path(preserve_path_from, abs_f): + raise InvalidArguments('When using preserve_path_from, all input files must be in a subdirectory of the given dir.') + output.add_file(f, state) return output class GeneratedList: - def __init__(self, generator, extra_args=[]): + def __init__(self, generator, subdir, preserve_path_from=None, extra_args=[]): if hasattr(generator, 'held_object'): generator = generator.held_object self.generator = generator self.name = self.generator.exe + self.subdir = subdir self.infilelist = [] self.outfilelist = [] self.outmap = {} self.extra_depends = [] + self.preserve_path_from = preserve_path_from self.extra_args = extra_args - def add_file(self, newfile): + def add_preserved_path_segment(self, infile, outfiles, state): + result = [] + in_abs = infile.absolute_path(state.environment.source_dir, state.environment.build_dir) + assert(os.path.isabs(self.preserve_path_from)) + rel = os.path.relpath(in_abs, self.preserve_path_from) + path_segment = os.path.split(rel)[0] + for of in outfiles: + result.append(os.path.join(path_segment, of)) + return result + + def add_file(self, newfile, state): self.infilelist.append(newfile) outfiles = self.generator.get_base_outnames(newfile.fname) + if self.preserve_path_from: + outfiles = self.add_preserved_path_segment(newfile, outfiles, state) self.outfilelist += outfiles self.outmap[newfile] = outfiles @@ -1160,23 +1184,33 @@ class Executable(BuildTarget): # The import library that GCC would generate (and prefer) self.gcc_import_filename = None - # if implib appears, this target is linkwith:-able, but that only means - # something on Windows platforms. - self.is_linkwithable = False - if 'implib' in kwargs and kwargs['implib']: + # Check for export_dynamic + self.export_dynamic = False + if kwargs.get('export_dynamic'): + if not isinstance(kwargs['export_dynamic'], bool): + raise InvalidArguments('"export_dynamic" keyword argument must be a boolean') + self.export_dynamic = True + if kwargs.get('implib'): + self.export_dynamic = True + if self.export_dynamic and kwargs.get('implib') is False: + raise InvalidArguments('"implib" keyword argument must not be false for if "export_dynamic" is true') + + # If using export_dynamic, set the import library name + if self.export_dynamic: implib_basename = self.name + '.exe' - if not isinstance(kwargs['implib'], bool): + if not isinstance(kwargs.get('implib', False), bool): implib_basename = kwargs['implib'] - self.is_linkwithable = True if for_windows(is_cross, environment) or for_cygwin(is_cross, environment): self.vs_import_filename = '{0}.lib'.format(implib_basename) self.gcc_import_filename = 'lib{0}.a'.format(implib_basename) - if self.get_using_msvc(): self.import_filename = self.vs_import_filename else: self.import_filename = self.gcc_import_filename + # Only linkwithable if using export_dynamic + self.is_linkwithable = self.export_dynamic + def type_suffix(self): return "@exe" diff --git a/mesonbuild/compilers/c.py b/mesonbuild/compilers/c.py index 233fc84..4c6e3a2 100644 --- a/mesonbuild/compilers/c.py +++ b/mesonbuild/compilers/c.py @@ -183,6 +183,14 @@ class CCompiler(Compiler): def get_default_include_dirs(self): return [] + def gen_export_dynamic_link_args(self, env): + if for_windows(env.is_cross_build(), env): + return ['-Wl,--export-all-symbols'] + elif for_darwin(env.is_cross_build(), env): + return [] + else: + return ['-Wl,-export-dynamic'] + def gen_import_library_args(self, implibname): """ The name of the outputted import library diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py index b14074b..2602d14 100644 --- a/mesonbuild/compilers/compilers.py +++ b/mesonbuild/compilers/compilers.py @@ -855,7 +855,15 @@ class Compiler: paths = padding else: paths = paths + ':' + padding - args = ['-Wl,-rpath,' + paths] + args = [] + if mesonlib.is_dragonflybsd(): + # This argument instructs the compiler to record the value of + # ORIGIN in the .dynamic section of the elf. On Linux this is done + # by default, but is not on dragonfly for some reason. Without this + # $ORIGIN in the runtime path will be undefined and any binaries + # linked against local libraries will fail to resolve them. + args.append('-Wl,-z,origin') + args.append('-Wl,-rpath,' + paths) if get_compiler_is_linuxlike(self): # Rpaths to use while linking must be absolute. These are not # written to the binary. Needed only with GNU ld: diff --git a/mesonbuild/dependencies/__init__.py b/mesonbuild/dependencies/__init__.py index 4dc2b27..69235da 100644 --- a/mesonbuild/dependencies/__init__.py +++ b/mesonbuild/dependencies/__init__.py @@ -13,7 +13,7 @@ # limitations under the License. from .base import ( # noqa: F401 - Dependency, DependencyException, DependencyMethods, ExternalProgram, + Dependency, DependencyException, DependencyMethods, ExternalProgram, NonExistingExternalProgram, ExternalDependency, ExternalLibrary, ExtraFrameworkDependency, InternalDependency, PkgConfigDependency, find_external_dependency, get_dep_identifier, packages, _packages_accept_language) from .dev import GMockDependency, GTestDependency, LLVMDependency, ValgrindDependency diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py index 46cce43..e29d4de 100644 --- a/mesonbuild/dependencies/base.py +++ b/mesonbuild/dependencies/base.py @@ -400,11 +400,22 @@ class PkgConfigDependency(ExternalDependency): m = 'Invalid version of dependency, need {!r} {!r} found {!r}.' raise DependencyException(m.format(name, not_found, self.version)) return - found_msg += [mlog.green('YES'), self.version] - # Fetch cargs to be used while using this dependency - self._set_cargs() - # Fetch the libraries and library paths needed for using this - self._set_libs() + + try: + # Fetch cargs to be used while using this dependency + self._set_cargs() + # Fetch the libraries and library paths needed for using this + self._set_libs() + found_msg += [mlog.green('YES'), self.version] + except DependencyException as e: + if self.required: + raise + else: + self.compile_args = [] + self.link_args = [] + self.is_found = False + found_msg += [mlog.red('NO'), '; reason: {}'.format(str(e))] + # Print the found message only at the very end because fetching cflags # and libs can also fail if other needed pkg-config files aren't found. if not self.silent: @@ -754,6 +765,17 @@ class ExternalProgram: def get_name(self): return self.name +class NonExistingExternalProgram(ExternalProgram): + + def __init__(self): + super().__init__(name = 'nonexistingprogram', silent = True) + + def __repr__(self): + r = '<{} {!r} -> {!r}>' + return r.format(self.__class__.__name__, self.name, self.command) + + def found(self): + return False class ExternalLibrary(ExternalDependency): def __init__(self, name, link_args, environment, language, silent=False): diff --git a/mesonbuild/dependencies/dev.py b/mesonbuild/dependencies/dev.py index 91414d5..25316df 100644 --- a/mesonbuild/dependencies/dev.py +++ b/mesonbuild/dependencies/dev.py @@ -17,11 +17,10 @@ import os import re -import shutil from .. import mlog from .. import mesonlib -from ..mesonlib import version_compare, Popen_safe, stringlistify, extract_as_list +from ..mesonlib import version_compare, stringlistify, extract_as_list from .base import ( DependencyException, ExternalDependency, PkgConfigDependency, strip_system_libdirs, ConfigToolDependency, @@ -171,9 +170,37 @@ class LLVMDependency(ConfigToolDependency): else: self._set_old_link_args() self.link_args = strip_system_libdirs(environment, self.link_args) + self.link_args = self.__fix_bogus_link_args(self.link_args) + + @staticmethod + def __fix_bogus_link_args(args): + """This function attempts to fix bogus link arguments that llvm-config + generates. + + Currently it works around the following: + - FreeBSD: when statically linking -l/usr/lib/libexecinfo.so will + be generated, strip the -l in cases like this. + """ + new_args = [] + for arg in args: + if arg.startswith('-l') and arg.endswith('.so'): + new_args.append(arg.lstrip('-l')) + else: + new_args.append(arg) + return new_args def _set_new_link_args(self): """How to set linker args for LLVM versions >= 3.9""" + if ((mesonlib.is_dragonflybsd() or mesonlib.is_freebsd()) and not + self.static and version_compare(self.version, '>= 4.0')): + # llvm-config on DragonFly BSD and FreeBSD for versions 4.0, 5.0, + # and 6.0 have an error when generating arguments for shared mode + # linking, even though libLLVM.so is installed, because for some + # reason the tool expects to find a .so for each static library. + # This works around that. + self.link_args = self.get_config_value(['--ldflags'], 'link_args') + self.link_args.append('-lLLVM') + return link_args = ['--link-static', '--system-libs'] if self.static else ['--link-shared'] self.link_args = self.get_config_value( ['--libs', '--ldflags'] + link_args + list(self.required_modules), diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py index 0c9a2f3..e5aa43e 100644 --- a/mesonbuild/environment.py +++ b/mesonbuild/environment.py @@ -731,7 +731,7 @@ class Environment: return compilers.LLVMDCompiler(exelist, version, is_cross, full_version=full_version) elif 'gdc' in out: return compilers.GnuDCompiler(exelist, version, is_cross, full_version=full_version) - elif 'Digital Mars' in out: + elif 'The D Language Foundation' in out or 'Digital Mars' in out: return compilers.DmdDCompiler(exelist, version, is_cross, full_version=full_version) raise EnvironmentException('Unknown compiler "' + ' '.join(exelist) + '"') diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index 29b4033..c759892 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -375,7 +375,18 @@ class GeneratorHolder(InterpreterObject, ObjectHolder): def process_method(self, args, kwargs): extras = mesonlib.stringlistify(kwargs.get('extra_args', [])) - gl = self.held_object.process_files('Generator', args, self.interpreter, extra_args=extras) + if 'preserve_path_from' in kwargs: + preserve_path_from = kwargs['preserve_path_from'] + if not isinstance(preserve_path_from, str): + raise InvalidArguments('Preserve_path_from must be a string.') + preserve_path_from = os.path.normpath(preserve_path_from) + if not os.path.isabs(preserve_path_from): + # This is a bit of a hack. Fix properly before merging. + raise InvalidArguments('Preserve_path_from must be an absolute path for now. Sorry.') + else: + preserve_path_from = None + gl = self.held_object.process_files('Generator', args, self.interpreter, + preserve_path_from, extra_args=extras) return GeneratedListHolder(gl) @@ -1347,7 +1358,7 @@ build_target_common_kwargs = ( rust_kwargs | cs_kwargs) -exe_kwargs = (build_target_common_kwargs) | {'implib'} +exe_kwargs = (build_target_common_kwargs) | {'implib', 'export_dynamic'} shlib_kwargs = (build_target_common_kwargs) | {'version', 'soversion'} shmod_kwargs = shlib_kwargs stlib_kwargs = shlib_kwargs @@ -1372,7 +1383,7 @@ permitted_kwargs = {'add_global_arguments': {'language'}, 'declare_dependency': {'include_directories', 'link_with', 'sources', 'dependencies', 'compile_args', 'link_args', 'version'}, 'executable': exe_kwargs, 'find_program': {'required', 'native'}, - 'generator': {'arguments', 'output', 'depfile', 'capture'}, + 'generator': {'arguments', 'output', 'depfile', 'capture', 'preserve_path_from'}, 'include_directories': {'is_system'}, 'install_data': {'install_dir', 'install_mode', 'sources'}, 'install_headers': {'install_dir', 'subdir'}, @@ -1883,10 +1894,14 @@ to directly access options of other subprojects.''') raise InvalidCode('Second call to project().') if not self.is_subproject() and 'subproject_dir' in kwargs: spdirname = kwargs['subproject_dir'] - if '/' in spdirname or '\\' in spdirname: - raise InterpreterException('Subproject_dir must not contain a path segment.') + if not isinstance(spdirname, str): + raise InterpreterException('Subproject_dir must be a string') + if os.path.isabs(spdirname): + raise InterpreterException('Subproject_dir must not be an absolute path.') if spdirname.startswith('.'): raise InterpreterException('Subproject_dir must not begin with a period.') + if '..' in spdirname: + raise InterpreterException('Subproject_dir must not contain a ".." segment.') self.subproject_dir = spdirname if 'meson_version' in kwargs: @@ -2119,7 +2134,7 @@ to directly access options of other subprojects.''') if required and (progobj is None or not progobj.found()): raise InvalidArguments('Program "%s" not found or not executable' % args[0]) if progobj is None: - return ExternalProgramHolder(dependencies.ExternalProgram('nonexistingprogram')) + return ExternalProgramHolder(dependencies.NonExistingExternalProgram()) return progobj def func_find_library(self, node, args, kwargs): diff --git a/mesonbuild/mesonlib.py b/mesonbuild/mesonlib.py index 3b32996..4871bf7 100644 --- a/mesonbuild/mesonlib.py +++ b/mesonbuild/mesonlib.py @@ -25,29 +25,40 @@ from glob import glob def detect_meson_py_location(): c = sys.argv[0] - c_fname = os.path.split(c)[1] - if c_fname == 'meson' or c_fname == 'meson.py': - # $ /foo/meson.py <args> - if os.path.isabs(c): - return c - # $ meson <args> (gets run from /usr/bin/meson) + c_dir, c_fname = os.path.split(c) + + # get the absolute path to the <mesontool> folder + m_dir = None + if os.path.isabs(c): + # $ /foo/<mesontool>.py <args> + m_dir = c_dir + elif c_dir == '': + # $ <mesontool> <args> (gets run from /usr/bin/<mesontool>) in_path_exe = shutil.which(c_fname) if in_path_exe: - # Special case: when run like "./meson.py <opts>" and user has - # period in PATH, we need to expand it out, because, for example, + m_dir, c_fname = os.path.split(in_path_exe) + # Special case: when run like "./meson.py <opts>", + # we need to expand it out, because, for example, # "ninja test" will be run from a different directory. - if '.' in os.environ['PATH'].split(':'): - p, f = os.path.split(in_path_exe) - if p == '' or p == '.': - return os.path.join(os.getcwd(), f) - return in_path_exe - # $ python3 ./meson.py <args> - if os.path.exists(c): - return os.path.join(os.getcwd(), c) - + if m_dir == '.': + m_dir = os.getcwd() + else: + m_dir = os.path.abspath(c_dir) + + # find meson in m_dir + if m_dir is not None: + for fname in ['meson', 'meson.py']: + m_path = os.path.join(m_dir, fname) + if os.path.exists(m_path): + return m_path + + # No meson found, which means that either: + # a) meson is not installed + # b) meson is installed to a non-standard location + # c) the script that invoked mesonlib is not the one of meson tools (e.g. run_unittests.py) # The only thing remaining is to try to find the bundled executable and # pray distro packagers have not moved it. - fname = os.path.join(os.path.dirname(__file__), '..', 'meson.py') + fname = os.path.normpath(os.path.join(os.path.dirname(__file__), '..', 'meson.py')) if not os.path.exists(fname): raise RuntimeError('Could not determine how to run Meson. Please file a bug with details.') return fname @@ -285,6 +296,12 @@ def is_cygwin(): def is_debianlike(): return os.path.isfile('/etc/debian_version') +def is_dragonflybsd(): + return platform.system().lower() == 'dragonfly' + +def is_freebsd(): + return platform.system().lower() == 'freebsd' + def for_windows(is_cross, env): """ Host machine is windows? diff --git a/run_project_tests.py b/run_project_tests.py index 0bf5f31..d191e28 100755 --- a/run_project_tests.py +++ b/run_project_tests.py @@ -185,6 +185,7 @@ def get_relative_files_list_from_dir(fromdir): def platform_fix_name(fname, compiler): if '?lib' in fname: if mesonlib.is_cygwin(): + fname = re.sub(r'lib/\?lib(.*)\.so$', r'bin/cyg\1.dll', fname) fname = re.sub(r'\?lib(.*)\.dll$', r'cyg\1.dll', fname) else: fname = re.sub(r'\?lib', 'lib', fname) @@ -447,20 +448,28 @@ def have_objc_compiler(): env = environment.Environment(None, build_dir, None, get_fake_options('/'), []) try: objc_comp = env.detect_objc_compiler(False) - except: + except mesonlib.MesonException: return False if not objc_comp: return False try: objc_comp.sanity_check(env.get_scratch_dir(), env) - objcpp_comp = env.detect_objc_compiler(False) - except: + except mesonlib.MesonException: + return False + return True + +def have_objcpp_compiler(): + with AutoDeletedDir(tempfile.mkdtemp(prefix='b ', dir='.')) as build_dir: + env = environment.Environment(None, build_dir, None, get_fake_options('/'), []) + try: + objcpp_comp = env.detect_objcpp_compiler(False) + except mesonlib.MesonException: return False if not objcpp_comp: return False try: objcpp_comp.sanity_check(env.get_scratch_dir(), env) - except: + except mesonlib.MesonException: return False return True @@ -487,6 +496,7 @@ def detect_tests_to_run(): ('rust', 'rust', backend is not Backend.ninja or not shutil.which('rustc')), ('d', 'd', backend is not Backend.ninja or not have_d_compiler()), ('objective c', 'objc', backend not in (Backend.ninja, Backend.xcode) or mesonlib.is_windows() or not have_objc_compiler()), + ('objective c++', 'objcpp', backend not in (Backend.ninja, Backend.xcode) or mesonlib.is_windows() or not have_objcpp_compiler()), ('fortran', 'fortran', backend is not Backend.ninja or not shutil.which('gfortran')), ('swift', 'swift', backend not in (Backend.ninja, Backend.xcode) or not shutil.which('swiftc')), ('python3', 'python3', backend is not Backend.ninja), @@ -495,7 +505,11 @@ def detect_tests_to_run(): if mesonlib.is_windows(): # TODO: Set BOOST_ROOT in .appveyor.yml gathered_tests += [('framework', ['test cases/frameworks/1 boost'], 'BOOST_ROOT' not in os.environ)] - elif mesonlib.is_osx() or mesonlib.is_cygwin(): + elif mesonlib.is_osx(): + if os.path.exists('/usr/local/include/boost'): + # Just do the BOOST test + gathered_tests += [('framework', ['test cases/frameworks/1 boost'], False)] + elif mesonlib.is_cygwin(): # Just do the BOOST test gathered_tests += [('framework', ['test cases/frameworks/1 boost'], False)] else: diff --git a/run_unittests.py b/run_unittests.py index 08ad632..f61544f 100755 --- a/run_unittests.py +++ b/run_unittests.py @@ -34,8 +34,10 @@ import mesonbuild.environment import mesonbuild.mesonlib import mesonbuild.coredata from mesonbuild.interpreter import ObjectHolder -from mesonbuild.mesonlib import is_linux, is_windows, is_osx, is_cygwin, windows_proof_rmtree -from mesonbuild.mesonlib import python_command, meson_command, version_compare +from mesonbuild.mesonlib import ( + is_linux, is_windows, is_osx, is_cygwin, is_dragonflybsd, + windows_proof_rmtree, python_command, meson_command, version_compare, +) from mesonbuild.environment import Environment, detect_ninja from mesonbuild.mesonlib import MesonException, EnvironmentException from mesonbuild.dependencies import PkgConfigDependency, ExternalProgram @@ -1386,12 +1388,24 @@ int main(int argc, char **argv) { for each in ('prog', 'subdir/liblib1.so', ): rpath = get_rpath(os.path.join(self.builddir, each)) self.assertTrue(rpath) - for path in rpath.split(':'): + if is_dragonflybsd(): + # DragonflyBSD will prepend /usr/lib/gccVERSION to the rpath, + # so ignore that. + self.assertTrue(rpath.startswith('/usr/lib/gcc')) + rpaths = rpath.split(':')[1:] + else: + rpaths = rpath.split(':') + for path in rpaths: self.assertTrue(path.startswith('$ORIGIN'), msg=(each, path)) # These two don't link to anything else, so they do not need an rpath entry. for each in ('subdir/subdir2/liblib2.so', 'subdir/subdir3/liblib3.so'): rpath = get_rpath(os.path.join(self.builddir, each)) - self.assertTrue(rpath is None) + if is_dragonflybsd(): + # The rpath should be equal to /usr/lib/gccVERSION + self.assertTrue(rpath.startswith('/usr/lib/gcc')) + self.assertEqual(len(rpath.split(':')), 1) + else: + self.assertTrue(rpath is None) def test_dash_d_dedup(self): testdir = os.path.join(self.unit_test_dir, '10 d dedup') diff --git a/test cases/common/125 shared module/meson.build b/test cases/common/125 shared module/meson.build index 29277e9..08a284d 100644 --- a/test cases/common/125 shared module/meson.build +++ b/test cases/common/125 shared module/meson.build @@ -8,6 +8,6 @@ l = shared_library('runtime', 'runtime.c') # at runtime. This requires extra help on Windows, so # should be avoided unless really necessary. m = shared_module('mymodule', 'module.c') -e = executable('prog', 'prog.c', link_with : l, dependencies : dl) +e = executable('prog', 'prog.c', + link_with : l, export_dynamic : true, dependencies : dl) test('import test', e, args : m) - diff --git a/test cases/common/135 generated assembly/square-arm.S.in b/test cases/common/135 generated assembly/square-arm.S.in index 168c980..d2fb7ac 100644 --- a/test cases/common/135 generated assembly/square-arm.S.in +++ b/test cases/common/135 generated assembly/square-arm.S.in @@ -2,8 +2,8 @@ .text .globl SYMBOL_NAME(square_unsigned) -/* Only supported on Linux with GAS */ -# ifdef __linux__ +/* Only supported with GAS */ +# if defined(__linux__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) .type square_unsigned,%function #endif diff --git a/test cases/common/135 generated assembly/square-x86.S.in b/test cases/common/135 generated assembly/square-x86.S.in index 19dd9f5..ee77b81 100644 --- a/test cases/common/135 generated assembly/square-x86.S.in +++ b/test cases/common/135 generated assembly/square-x86.S.in @@ -21,8 +21,8 @@ END .text .globl SYMBOL_NAME(square_unsigned) -/* Only supported on Linux with GAS */ -# ifdef __linux__ +/* Only supported with GAS */ +# if defined(__linux__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) .type square_unsigned,@function # endif diff --git a/test cases/common/135 generated assembly/square-x86_64.S.in b/test cases/common/135 generated assembly/square-x86_64.S.in index 0834f16..856af13 100644 --- a/test cases/common/135 generated assembly/square-x86_64.S.in +++ b/test cases/common/135 generated assembly/square-x86_64.S.in @@ -18,8 +18,8 @@ END .text .globl SYMBOL_NAME(square_unsigned) -/* Only supported on Linux with GAS */ -# ifdef __linux__ +/* Only supported with GAS */ +# if defined(__linux__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) .type square_unsigned,@function # endif diff --git a/test cases/common/140 get define/meson.build b/test cases/common/140 get define/meson.build index e23b7de..fd87177 100644 --- a/test cases/common/140 get define/meson.build +++ b/test cases/common/140 get define/meson.build @@ -19,6 +19,19 @@ foreach lang : ['c', 'cpp'] elif host_system == 'haiku' d = cc.get_define('__HAIKU__') assert(d == '1', '__HAIKU__ value is @0@ instead of 1'.format(d)) + elif host_system == 'freebsd' + # the __FreeBSD__ define will be equal to the major version of the release + # (ex, in FreeBSD 11.x, __FreeBSD__ == 11). To make the test robust when + # being run on various versions of FreeBSD, just test that the define is + # set. + d = cc.get_define('__FreeBSD__') + assert(d != '', '__FreeBSD__ value is unset') + elif host_system == 'dragonfly' + d = cc.get_define('__DragonFly__') + assert(d == '1', '__DragonFly__ value is @0@ instead of 1'.format(d)) + elif host_system == 'netbsd' + d = cc.get_define('__NetBSD__') + assert(d == '1', '__NetBSD__ value is @0@ instead of 1'.format(d)) else error('Please report a bug and help us improve support for this platform') endif @@ -28,8 +41,16 @@ foreach lang : ['c', 'cpp'] # found in the compiler's default search path, GCC inserts an extra comment # between the delimiter and the define which causes a parsing error. # https://github.com/mesonbuild/meson/issues/1726 - ver = cc.get_define('ZLIB_VER_MAJOR', prefix : '#include <zlib.h>') - assert(ver == '1', 'ZLIB_VER_MAJOR value is "@0@" instead of "1"'.format(ver)) + if host_machine.system() == 'netbsd' + # NetBSD's zlib doesn't is version 1.2.3 and doesn't have a + # ZLIB_VER_MAJOR, but it does have a ZLIB_VERSION (which is a string), so + # check the first non-quote character of that. + ver = cc.get_define('ZLIB_VERSION', prefix : '#include <zlib.h>')[1] + assert(ver == '1', 'ZLIB_VERSION (major) value is "@0@" instead of "1"'.format(ver)) + else + ver = cc.get_define('ZLIB_VER_MAJOR', prefix : '#include <zlib.h>') + assert(ver == '1', 'ZLIB_VER_MAJOR value is "@0@" instead of "1"'.format(ver)) + endif endif # Check that an undefined value is empty. diff --git a/test cases/common/156 shared module resolving symbol in executable/meson.build b/test cases/common/156 shared module resolving symbol in executable/meson.build index 34a75f1..282a4d2 100644 --- a/test cases/common/156 shared module resolving symbol in executable/meson.build +++ b/test cases/common/156 shared module resolving symbol in executable/meson.build @@ -9,13 +9,7 @@ project('shared module resolving symbol in executable', 'c') # See testcase 125 for an example of the more complex portability gymnastics # required if we do not know (at link-time) what provides the symbol. -link_flags = [] -if host_machine.system() != 'windows' - # Needed to export dynamic symbols from the executable - link_flags += ['-rdynamic'] -endif - dl = meson.get_compiler('c').find_library('dl', required: false) -e = executable('prog', 'prog.c', dependencies: dl, implib: true, link_args: link_flags) +e = executable('prog', 'prog.c', dependencies: dl, export_dynamic: true) m = shared_module('module', 'module.c', link_with: e) test('test', e, args: m.full_path()) diff --git a/test cases/common/173 preserve gendir/base.inp b/test cases/common/173 preserve gendir/base.inp new file mode 100644 index 0000000..df967b9 --- /dev/null +++ b/test cases/common/173 preserve gendir/base.inp @@ -0,0 +1 @@ +base diff --git a/test cases/common/173 preserve gendir/com/mesonbuild/subbie.inp b/test cases/common/173 preserve gendir/com/mesonbuild/subbie.inp new file mode 100644 index 0000000..df0f4e9 --- /dev/null +++ b/test cases/common/173 preserve gendir/com/mesonbuild/subbie.inp @@ -0,0 +1 @@ +subbie diff --git a/test cases/common/173 preserve gendir/genprog.py b/test cases/common/173 preserve gendir/genprog.py new file mode 100755 index 0000000..8bd2b9d --- /dev/null +++ b/test cases/common/173 preserve gendir/genprog.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python3 + +import os, sys, argparse +import pathlib + +h_templ = '''#pragma once + +int %s(); +''' + +c_templ = '''#include"%s.h" + +int %s() { + return 0; +} +''' + +parser = argparse.ArgumentParser() +parser.add_argument('--searchdir', required=True) +parser.add_argument('--outdir', required=True) +parser.add_argument('ifiles', nargs='+') + +options = parser.parse_args() + +searchdir = options.searchdir +outdir = options.outdir +ifiles = options.ifiles + +rel_ofiles = [] + +for ifile in ifiles: + if not ifile.startswith(options.searchdir): + sys.exit('Input file %s does not start with search dir %s.' % (ifile, searchdir)) + rel_ofile = ifile[len(searchdir):] + if rel_ofile[0] == '/' or rel_ofile[0] == '\\': + rel_ofile = rel_ofile[1:] + rel_ofiles.append(os.path.splitext(rel_ofile)[0]) + +ofile_bases = [os.path.join(outdir, i) for i in rel_ofiles] + +for i, ifile_name in enumerate(ifiles): + proto_name = open(ifile_name).readline().strip() + h_out = ofile_bases[i] + '.h' + c_out = ofile_bases[i] + '.c' + os.makedirs(os.path.split(ofile_bases[i])[0], exist_ok=True) + open(h_out, 'w').write(h_templ % (proto_name)) + open(c_out, 'w').write(c_templ % (proto_name, proto_name)) diff --git a/test cases/common/173 preserve gendir/meson.build b/test cases/common/173 preserve gendir/meson.build new file mode 100644 index 0000000..ce219f0 --- /dev/null +++ b/test cases/common/173 preserve gendir/meson.build @@ -0,0 +1,13 @@ +project('preserve subdir', 'c') + +gprog = find_program('genprog.py') + +gen = generator(gprog, \ + output : ['@BASENAME@.c', '@BASENAME@.h'], + arguments : ['--searchdir=@CURRENT_SOURCE_DIR@', '--outdir=@BUILD_DIR@', '@INPUT@']) + +generated = gen.process('base.inp', 'com/mesonbuild/subbie.inp', + preserve_path_from : meson.current_source_dir()) + +e = executable('testprog', 'testprog.c', generated) +test('testprog', e) diff --git a/test cases/common/173 preserve gendir/testprog.c b/test cases/common/173 preserve gendir/testprog.c new file mode 100644 index 0000000..46b4602 --- /dev/null +++ b/test cases/common/173 preserve gendir/testprog.c @@ -0,0 +1,6 @@ +#include"base.h" +#include"com/mesonbuild/subbie.h" + +int main(int argc, char **argv) { + return base() + subbie(); +} diff --git a/test cases/frameworks/11 gir subproject/gir/meson.build b/test cases/frameworks/11 gir subproject/gir/meson.build index 48e0a47..fe40dc6 100644 --- a/test cases/frameworks/11 gir subproject/gir/meson.build +++ b/test cases/frameworks/11 gir subproject/gir/meson.build @@ -31,6 +31,9 @@ message('TEST: ' + girsubproject.outdir()) envdata = environment() envdata.append('GI_TYPELIB_PATH', girsubproject.outdir(), 'subprojects/mesongir', separator : ':') envdata.append('LD_LIBRARY_PATH', girsubproject.outdir(), 'subprojects/mesongir') +if ['windows', 'cygwin'].contains(host_machine.system()) + envdata.append('PATH', girsubproject.outdir(), 'subprojects/mesongir') +endif test('gobject introspection/subproject/c', girexe) test('gobject introspection/subproject/py', find_program('prog.py'), diff --git a/test cases/frameworks/11 gir subproject/installed_files.txt b/test cases/frameworks/11 gir subproject/installed_files.txt index 434481e..87d49a1 100644 --- a/test cases/frameworks/11 gir subproject/installed_files.txt +++ b/test cases/frameworks/11 gir subproject/installed_files.txt @@ -2,5 +2,5 @@ usr/lib/girepository-1.0/Meson-1.0.typelib usr/lib/girepository-1.0/MesonSub-1.0.typelib usr/share/gir-1.0/Meson-1.0.gir usr/share/gir-1.0/MesonSub-1.0.gir -usr/lib/libgirsubproject.so -usr/lib/libgirlib.so +usr/lib/?libgirsubproject.so +usr/lib/?libgirlib.so diff --git a/test cases/frameworks/12 multiple gir/installed_files.txt b/test cases/frameworks/12 multiple gir/installed_files.txt index 9fb51bf..a5d16bc 100644 --- a/test cases/frameworks/12 multiple gir/installed_files.txt +++ b/test cases/frameworks/12 multiple gir/installed_files.txt @@ -1,6 +1,6 @@ usr/lib/girepository-1.0/Meson-1.0.typelib usr/lib/girepository-1.0/MesonSub-1.0.typelib -usr/lib/libgirlib.so -usr/lib/libgirsubproject.so +usr/lib/?libgirlib.so +usr/lib/?libgirsubproject.so usr/share/gir-1.0/Meson-1.0.gir usr/share/gir-1.0/MesonSub-1.0.gir diff --git a/test cases/frameworks/15 llvm/meson.build b/test cases/frameworks/15 llvm/meson.build index 5211006..549adce 100644 --- a/test cases/frameworks/15 llvm/meson.build +++ b/test cases/frameworks/15 llvm/meson.build @@ -20,17 +20,19 @@ foreach static : [true, false] 'llvm', modules : ['bitwriter', 'asmprinter', 'executionengine', 'target', 'mcjit', 'nativecodegen'], - required : true, + required : false, static : static, ) - name = static ? 'static' : 'dynamic' - executable( - 'sum-@0@'.format(name), - 'sum.c', - dependencies : [ - llvm_dep, dep_tinfo, - dependency('zlib'), - meson.get_compiler('c').find_library('dl', required : false), - ] - ) + if llvm_dep.found() + name = static ? 'static' : 'dynamic' + executable( + 'sum-@0@'.format(name), + 'sum.c', + dependencies : [ + llvm_dep, dep_tinfo, + dependency('zlib'), + meson.get_compiler('c').find_library('dl', required : false), + ] + ) + endif endforeach diff --git a/test cases/frameworks/17 mpi/meson.build b/test cases/frameworks/17 mpi/meson.build index 17acd71..01ad61d 100644 --- a/test cases/frameworks/17 mpi/meson.build +++ b/test cases/frameworks/17 mpi/meson.build @@ -6,7 +6,10 @@ if build_machine.system() == 'windows' and cc.get_id() != 'msvc' error('MESON_SKIP_TEST: MPI not available on Windows without MSVC.') endif -mpic = dependency('mpi', language : 'c') +mpic = dependency('mpi', language : 'c', required : false) +if not mpic.found() + error('MESON_SKIP_TEST: MPI not found, skipping.') +endif exec = executable('exec', 'main.c', dependencies : [mpic]) diff --git a/test cases/frameworks/18 vulkan/meson.build b/test cases/frameworks/18 vulkan/meson.build index 54f1d47..e98854e 100644 --- a/test cases/frameworks/18 vulkan/meson.build +++ b/test cases/frameworks/18 vulkan/meson.build @@ -1,6 +1,9 @@ project('vulkan test', 'c') -vulkan_dep = dependency('vulkan') +vulkan_dep = dependency('vulkan', required : false) +if not vulkan_dep.found() + error('MESON_SKIP_TEST: vulkan not found.') +endif e = executable('vulkanprog', 'vulkanprog.c', dependencies : vulkan_dep) diff --git a/test cases/frameworks/2 gtest/meson.build b/test cases/frameworks/2 gtest/meson.build index 419f451..e5418e9 100644 --- a/test cases/frameworks/2 gtest/meson.build +++ b/test cases/frameworks/2 gtest/meson.build @@ -1,6 +1,9 @@ project('gtest', 'cpp') -gtest = dependency('gtest', main : true) +gtest = dependency('gtest', main : true, required : false) +if not gtest.found() + error('MESON_SKIP_TEST: gtest not installed.') +endif gtest_nomain = dependency('gtest', main : false) e = executable('testprog', 'test.cc', dependencies : gtest) diff --git a/test cases/frameworks/3 gmock/meson.build b/test cases/frameworks/3 gmock/meson.build index 341f9d7..516547f 100644 --- a/test cases/frameworks/3 gmock/meson.build +++ b/test cases/frameworks/3 gmock/meson.build @@ -3,8 +3,14 @@ project('gmock test', 'cpp') # Using gmock without gtest is a pain so just # don't support that then. -gtest = dependency('gtest', main : true) -gmock = dependency('gmock') +gtest = dependency('gtest', main : true, required : false) +if not gtest.found() + error('MESON_SKIP_TEST: gtest not installed.') +endif +gmock = dependency('gmock', required : false) +if not gmock.found() + error('MESON_SKIP_TEST: gmock not installed.') +endif e = executable('gmocktest', 'gmocktest.cc', dependencies : [gtest, gmock]) test('gmock test', e) diff --git a/test cases/frameworks/5 protocol buffers/asubdir/defs.proto b/test cases/frameworks/5 protocol buffers/asubdir/defs.proto index f795651..dad5754 100644 --- a/test cases/frameworks/5 protocol buffers/asubdir/defs.proto +++ b/test cases/frameworks/5 protocol buffers/asubdir/defs.proto @@ -1,3 +1,5 @@ +syntax = "proto3"; + message Dummy { - required string text = 1; + string text = 1; } diff --git a/test cases/frameworks/5 protocol buffers/defs.proto b/test cases/frameworks/5 protocol buffers/defs.proto index f795651..dad5754 100644 --- a/test cases/frameworks/5 protocol buffers/defs.proto +++ b/test cases/frameworks/5 protocol buffers/defs.proto @@ -1,3 +1,5 @@ +syntax = "proto3"; + message Dummy { - required string text = 1; + string text = 1; } diff --git a/test cases/frameworks/5 protocol buffers/meson.build b/test cases/frameworks/5 protocol buffers/meson.build index 58666f9..94fa980 100644 --- a/test cases/frameworks/5 protocol buffers/meson.build +++ b/test cases/frameworks/5 protocol buffers/meson.build @@ -10,7 +10,7 @@ endif gen = generator(protoc, \ output : ['@BASENAME@.pb.cc', '@BASENAME@.pb.h'], - arguments : ['--proto_path=@SOURCE_DIR@', '--cpp_out=@BUILD_DIR@', '@INPUT@']) + arguments : ['--proto_path=@CURRENT_SOURCE_DIR@', '--cpp_out=@BUILD_DIR@', '@INPUT@']) generated = gen.process('defs.proto') e = executable('prog', 'main.cpp', generated, @@ -18,3 +18,5 @@ e = executable('prog', 'main.cpp', generated, test('prototest', e) subdir('asubdir') +subdir('withpath') +subdir('sidedir') diff --git a/test cases/frameworks/5 protocol buffers/sidedir/meson.build b/test cases/frameworks/5 protocol buffers/sidedir/meson.build new file mode 100644 index 0000000..ce9b7be --- /dev/null +++ b/test cases/frameworks/5 protocol buffers/sidedir/meson.build @@ -0,0 +1,7 @@ +# Generated source defined in one directory but +# used in another. + +e = executable('sideprog', 'sideprog.cpp', generated, + override_options : ['unity=off'], + dependencies : dep) +test('sideprog', e) diff --git a/test cases/frameworks/5 protocol buffers/sidedir/sideprog.cpp b/test cases/frameworks/5 protocol buffers/sidedir/sideprog.cpp new file mode 100644 index 0000000..83af4b2 --- /dev/null +++ b/test cases/frameworks/5 protocol buffers/sidedir/sideprog.cpp @@ -0,0 +1,16 @@ +#include"com/mesonbuild/simple.pb.h" +#include"com/mesonbuild/subsite/complex.pb.h" + +#include<memory> + +int main(int argc, char **argv) { + GOOGLE_PROTOBUF_VERIFY_VERSION; + { + subdirectorial::SimpleMessage *s = new subdirectorial::SimpleMessage(); + s->set_the_integer(3); + subdirectorial::ComplexMessage c; + c.set_allocated_sm(s); + } + google::protobuf::ShutdownProtobufLibrary(); + return 0; +} diff --git a/test cases/frameworks/5 protocol buffers/withpath/com/mesonbuild/simple.proto b/test cases/frameworks/5 protocol buffers/withpath/com/mesonbuild/simple.proto new file mode 100644 index 0000000..336779f --- /dev/null +++ b/test cases/frameworks/5 protocol buffers/withpath/com/mesonbuild/simple.proto @@ -0,0 +1,7 @@ +syntax = "proto3"; + +package subdirectorial; + +message SimpleMessage { + int32 the_integer = 1; +} diff --git a/test cases/frameworks/5 protocol buffers/withpath/com/mesonbuild/subsite/complex.proto b/test cases/frameworks/5 protocol buffers/withpath/com/mesonbuild/subsite/complex.proto new file mode 100644 index 0000000..8dc32c2 --- /dev/null +++ b/test cases/frameworks/5 protocol buffers/withpath/com/mesonbuild/subsite/complex.proto @@ -0,0 +1,10 @@ +syntax = "proto3"; + +package subdirectorial; + +import "com/mesonbuild/simple.proto"; + +message ComplexMessage { + string a_message = 1; + SimpleMessage sm = 2; +} diff --git a/test cases/frameworks/5 protocol buffers/withpath/meson.build b/test cases/frameworks/5 protocol buffers/withpath/meson.build new file mode 100644 index 0000000..68a7381 --- /dev/null +++ b/test cases/frameworks/5 protocol buffers/withpath/meson.build @@ -0,0 +1,13 @@ +# Testing protobuf files that are deeply hierarchical +# and must preserve their path segments in output files +# because protoc will always put it in there. + +generated = gen.process('com/mesonbuild/simple.proto', + 'com/mesonbuild/subsite/complex.proto', + preserve_path_from : meson.current_source_dir(), + ) + +e = executable('pathprog', 'pathprog.cpp', generated, + override_options : ['unity=off'], + dependencies : dep) +test('pathprog', e) diff --git a/test cases/frameworks/5 protocol buffers/withpath/pathprog.cpp b/test cases/frameworks/5 protocol buffers/withpath/pathprog.cpp new file mode 100644 index 0000000..83af4b2 --- /dev/null +++ b/test cases/frameworks/5 protocol buffers/withpath/pathprog.cpp @@ -0,0 +1,16 @@ +#include"com/mesonbuild/simple.pb.h" +#include"com/mesonbuild/subsite/complex.pb.h" + +#include<memory> + +int main(int argc, char **argv) { + GOOGLE_PROTOBUF_VERIFY_VERSION; + { + subdirectorial::SimpleMessage *s = new subdirectorial::SimpleMessage(); + s->set_the_integer(3); + subdirectorial::ComplexMessage c; + c.set_allocated_sm(s); + } + google::protobuf::ShutdownProtobufLibrary(); + return 0; +} diff --git a/test cases/frameworks/7 gnome/gir/meson.build b/test cases/frameworks/7 gnome/gir/meson.build index a91cb97..1771548 100644 --- a/test cases/frameworks/7 gnome/gir/meson.build +++ b/test cases/frameworks/7 gnome/gir/meson.build @@ -41,5 +41,8 @@ gir_paths = ':'.join([girlib.outdir(), dep1lib.outdir(), dep2lib.outdir()]) envdata = environment() envdata.append('GI_TYPELIB_PATH', gir_paths, separator : ':') envdata.append('LD_LIBRARY_PATH', gir_paths) +if ['windows', 'cygwin'].contains(host_machine.system()) + envdata.append('PATH', gir_paths) +endif test('gobject introspection/py', find_program('prog.py'), env : envdata) diff --git a/test cases/frameworks/7 gnome/installed_files.txt b/test cases/frameworks/7 gnome/installed_files.txt index d0d51d5..c7c704f 100644 --- a/test cases/frameworks/7 gnome/installed_files.txt +++ b/test cases/frameworks/7 gnome/installed_files.txt @@ -2,9 +2,9 @@ usr/include/enums.h usr/include/enums2.h usr/include/enums3.h usr/include/marshaller.h -usr/lib/libgir_lib.so -usr/lib/libdep1lib.so -usr/lib/libdep2lib.so +usr/lib/?libgir_lib.so +usr/lib/?libdep1lib.so +usr/lib/?libdep2lib.so usr/lib/girepository-1.0/Meson-1.0.typelib usr/lib/girepository-1.0/MesonDep1-1.0.typelib usr/lib/girepository-1.0/MesonDep2-1.0.typelib diff --git a/test cases/objc/2 nsstring/meson.build b/test cases/objc/2 nsstring/meson.build index a877d74..7f2483f 100644 --- a/test cases/objc/2 nsstring/meson.build +++ b/test cases/objc/2 nsstring/meson.build @@ -5,7 +5,10 @@ if host_machine.system() == 'darwin' elif host_machine.system() == 'cygwin' error('MESON_SKIP_TEST GNUstep is not packaged for Cygwin.') else - dep = dependency('gnustep') + dep = dependency('gnustep', required : false) + if not dep.found() + error('MESON_SKIP_TEST: GNUstep is not installed') + endif if host_machine.system() == 'linux' and meson.get_compiler('objc').get_id() == 'clang' error('MESON_SKIP_TEST: GNUstep is broken on Linux with Clang') endif diff --git a/test cases/objc/4 objc args/meson.build b/test cases/objc/3 objc args/meson.build index 8887d96..8887d96 100644 --- a/test cases/objc/4 objc args/meson.build +++ b/test cases/objc/3 objc args/meson.build diff --git a/test cases/objc/4 objc args/prog.m b/test cases/objc/3 objc args/prog.m index bfd686a..bfd686a 100644 --- a/test cases/objc/4 objc args/prog.m +++ b/test cases/objc/3 objc args/prog.m diff --git a/test cases/objc/3 objc++/meson.build b/test cases/objcpp/1 simple/meson.build index 7d91884..7d91884 100644 --- a/test cases/objc/3 objc++/meson.build +++ b/test cases/objcpp/1 simple/meson.build diff --git a/test cases/objc/3 objc++/prog.mm b/test cases/objcpp/1 simple/prog.mm index 927e810..927e810 100644 --- a/test cases/objc/3 objc++/prog.mm +++ b/test cases/objcpp/1 simple/prog.mm diff --git a/test cases/objc/5 objc++ args/meson.build b/test cases/objcpp/2 objc++ args/meson.build index e0e34b0..e0e34b0 100644 --- a/test cases/objc/5 objc++ args/meson.build +++ b/test cases/objcpp/2 objc++ args/meson.build diff --git a/test cases/objc/5 objc++ args/prog.mm b/test cases/objcpp/2 objc++ args/prog.mm index 3decaf2..3decaf2 100644 --- a/test cases/objc/5 objc++ args/prog.mm +++ b/test cases/objcpp/2 objc++ args/prog.mm diff --git a/test cases/vala/11 generated vapi/installed_files.txt b/test cases/vala/11 generated vapi/installed_files.txt index 5993d01..aeaf2da 100644 --- a/test cases/vala/11 generated vapi/installed_files.txt +++ b/test cases/vala/11 generated vapi/installed_files.txt @@ -1,6 +1,6 @@ usr/bin/vapigen-test -usr/lib/libfoo.so -usr/lib/libbar.so +usr/lib/?libfoo.so +usr/lib/?libbar.so usr/share/vala/vapi/foo-1.0.vapi usr/share/vala/vapi/foo-1.0.deps usr/share/vala/vapi/bar-1.0.vapi diff --git a/test cases/vala/11 generated vapi/libbar/bar.c b/test cases/vala/11 generated vapi/libbar/bar.c index f0f5cb8..3037141 100644 --- a/test cases/vala/11 generated vapi/libbar/bar.c +++ b/test cases/vala/11 generated vapi/libbar/bar.c @@ -1,12 +1,29 @@ #include "bar.h" #include "foo.h" +struct _BarBar +{ + GObject parent_instance; +}; + +G_DEFINE_TYPE (BarBar, bar_bar, G_TYPE_OBJECT) + +static void +bar_bar_class_init (BarBarClass *klass) +{ +} + +static void +bar_bar_init (BarBar *self) +{ +} + /** - * bar_return_success: + * bar_bar_return_success: * * Returns 0 */ -int bar_return_success(void) +int bar_bar_return_success(void) { - return foo_return_success(); + return foo_foo_return_success(); } diff --git a/test cases/vala/11 generated vapi/libbar/bar.h b/test cases/vala/11 generated vapi/libbar/bar.h index 165b104..4ca7270 100644 --- a/test cases/vala/11 generated vapi/libbar/bar.h +++ b/test cases/vala/11 generated vapi/libbar/bar.h @@ -2,4 +2,8 @@ #pragma once -int bar_return_success(void); +#define BAR_TYPE_BAR (bar_bar_get_type()) + +G_DECLARE_FINAL_TYPE (BarBar, bar_bar, BAR, BAR, GObject) + +int bar_bar_return_success(void); diff --git a/test cases/vala/11 generated vapi/libfoo/foo.c b/test cases/vala/11 generated vapi/libfoo/foo.c index 0413ac5..dd2b891 100644 --- a/test cases/vala/11 generated vapi/libfoo/foo.c +++ b/test cases/vala/11 generated vapi/libfoo/foo.c @@ -1,11 +1,28 @@ #include "foo.h" +struct _FooFoo +{ + GObject parent_instance; +}; + +G_DEFINE_TYPE (FooFoo, foo_foo, G_TYPE_OBJECT) + +static void +foo_foo_class_init (FooFooClass *klass) +{ +} + +static void +foo_foo_init (FooFoo *self) +{ +} + /** - * foo_return_success: + * foo_foo_return_success: * * Returns 0 */ -int foo_return_success(void) +int foo_foo_return_success(void) { - return 0; + return 0; } diff --git a/test cases/vala/11 generated vapi/libfoo/foo.h b/test cases/vala/11 generated vapi/libfoo/foo.h index f09256d..e1887d8 100644 --- a/test cases/vala/11 generated vapi/libfoo/foo.h +++ b/test cases/vala/11 generated vapi/libfoo/foo.h @@ -2,4 +2,8 @@ #pragma once -int foo_return_success(void); +#define FOO_TYPE_FOO (foo_foo_get_type()) + +G_DECLARE_FINAL_TYPE (FooFoo, foo_foo, Foo, FOO, GObject) + +int foo_foo_return_success(void); diff --git a/test cases/vala/11 generated vapi/main.vala b/test cases/vala/11 generated vapi/main.vala index 303ab33..d61fba0 100644 --- a/test cases/vala/11 generated vapi/main.vala +++ b/test cases/vala/11 generated vapi/main.vala @@ -3,7 +3,7 @@ using Bar; class Main : GLib.Object { public static int main(string[] args) { - var ignore = Foo.return_success(); - return Bar.return_success(); + var ignore = Foo.Foo.return_success(); + return Bar.Bar.return_success(); } } diff --git a/test cases/vala/7 shared library/installed_files.txt b/test cases/vala/7 shared library/installed_files.txt index f70e439..012b107 100644 --- a/test cases/vala/7 shared library/installed_files.txt +++ b/test cases/vala/7 shared library/installed_files.txt @@ -1,5 +1,5 @@ -usr/lib/libinstalled_vala_lib.so -usr/lib/libinstalled_vala_all.so +usr/lib/?libinstalled_vala_lib.so +usr/lib/?libinstalled_vala_all.so usr/include/installed_vala_all.h usr/include/valah/installed_vala_all_nolib.h usr/include/installed_vala_onlyh.h diff --git a/test cases/vala/9 gir/installed_files.txt b/test cases/vala/9 gir/installed_files.txt index 7a0e055..64bddee 100644 --- a/test cases/vala/9 gir/installed_files.txt +++ b/test cases/vala/9 gir/installed_files.txt @@ -1,2 +1,2 @@ -usr/lib/libfoo.so +usr/lib/?libfoo.so usr/share/gir-1.0/Foo-1.0.gir diff --git a/wraptool.py b/wraptool.py index 5e03efd..a5ee9ef 100755 --- a/wraptool.py +++ b/wraptool.py @@ -17,4 +17,7 @@ from mesonbuild.wrap import wraptool import sys -sys.exit(wraptool.run(sys.argv[1:])) +if __name__ == '__main__': + print('Warning: This executable is deprecated. Use "meson wrap" instead.', + file=sys.stderr) + sys.exit(wraptool.run(sys.argv[1:])) |