diff options
24 files changed, 359 insertions, 102 deletions
diff --git a/authors.txt b/authors.txt index 229a2ff..a51badd 100644 --- a/authors.txt +++ b/authors.txt @@ -47,3 +47,6 @@ Iain Lane Daniel Brendle Franz Zapata Emanuele Aina +Guillaume Poirier-Morency +Scott D Phillips +Gautier Pelloux-Prayer diff --git a/mesonbuild/dependencies.py b/mesonbuild/dependencies.py index 6a4c32c..d0c7663 100644 --- a/mesonbuild/dependencies.py +++ b/mesonbuild/dependencies.py @@ -32,9 +32,10 @@ class DependencyException(MesonException): MesonException.__init__(self, *args, **kwargs) class Dependency(): - def __init__(self): + def __init__(self, type_name='unknown'): self.name = "null" self.is_found = False + self.type_name = type_name def get_compile_args(self): return [] @@ -59,9 +60,12 @@ class Dependency(): def need_threads(self): return False + def type_name(self): + return self.type_name + class InternalDependency(Dependency): def __init__(self, version, incdirs, compile_args, link_args, libraries, sources, ext_deps): - super().__init__() + super().__init__('internal') self.version = version self.include_directories = incdirs self.compile_args = compile_args @@ -83,7 +87,7 @@ class PkgConfigDependency(Dependency): pkgconfig_found = None def __init__(self, name, environment, kwargs): - Dependency.__init__(self) + Dependency.__init__(self, 'pkgconfig') self.is_libtool = False self.required = kwargs.get('required', True) self.static = kwargs.get('static', False) @@ -270,7 +274,7 @@ class WxDependency(Dependency): wx_found = None def __init__(self, environment, kwargs): - Dependency.__init__(self) + Dependency.__init__(self, 'wx') self.is_found = False if WxDependency.wx_found is None: self.check_wxconfig() @@ -445,7 +449,7 @@ class ExternalProgram(): class ExternalLibrary(Dependency): def __init__(self, name, link_args=None, silent=False): - super().__init__() + super().__init__('external') self.name = name # Rename fullpath to link_args once standalone find_library() gets removed. if link_args is not None: @@ -476,7 +480,7 @@ class BoostDependency(Dependency): name2lib = {'test' : 'unit_test_framework'} def __init__(self, environment, kwargs): - Dependency.__init__(self) + Dependency.__init__(self, 'boost') self.name = 'boost' self.environment = environment self.libdir = '' @@ -677,7 +681,7 @@ class BoostDependency(Dependency): class GTestDependency(Dependency): def __init__(self, environment, kwargs): - Dependency.__init__(self) + Dependency.__init__(self, 'gtest') self.main = kwargs.get('main', False) self.name = 'gtest' self.libname = 'libgtest.so' @@ -744,7 +748,7 @@ class GTestDependency(Dependency): class GMockDependency(Dependency): def __init__(self, environment, kwargs): - Dependency.__init__(self) + Dependency.__init__(self, 'gmock') # GMock may be a library or just source. # Work with both. self.name = 'gmock' @@ -798,7 +802,7 @@ class GMockDependency(Dependency): class Qt5Dependency(Dependency): def __init__(self, environment, kwargs): - Dependency.__init__(self) + Dependency.__init__(self, 'qt5') self.name = 'qt5' self.root = '/usr' mods = kwargs.get('modules', []) @@ -909,7 +913,7 @@ class Qt5Dependency(Dependency): class Qt4Dependency(Dependency): def __init__(self, environment, kwargs): - Dependency.__init__(self) + Dependency.__init__(self, 'qt4') self.name = 'qt4' self.root = '/usr' self.modules = [] @@ -947,7 +951,7 @@ class Qt4Dependency(Dependency): class GnuStepDependency(Dependency): def __init__(self, environment, kwargs): - Dependency.__init__(self) + Dependency.__init__(self, 'gnustep') self.modules = kwargs.get('modules', []) self.detect() @@ -1019,7 +1023,7 @@ why. As a hack filter out everything that is not a flag.""" class AppleFrameworks(Dependency): def __init__(self, environment, kwargs): - Dependency.__init__(self) + Dependency.__init__(self, 'appleframeworks') modules = kwargs.get('modules', []) if isinstance(modules, str): modules = [modules] @@ -1039,13 +1043,14 @@ class AppleFrameworks(Dependency): class GLDependency(Dependency): def __init__(self, environment, kwargs): - Dependency.__init__(self) + Dependency.__init__(self, 'gl') self.is_found = False self.cargs = [] self.linkargs = [] try: pcdep = PkgConfigDependency('gl', environment, kwargs) if pcdep.found(): + self.type_name = 'pkgconfig' self.is_found = True self.cargs = pcdep.get_compile_args() self.linkargs = pcdep.get_link_args() @@ -1068,13 +1073,14 @@ class GLDependency(Dependency): # sdl2-config, pkg-config and OSX framework class SDL2Dependency(Dependency): def __init__(self, environment, kwargs): - Dependency.__init__(self) + Dependency.__init__(self, 'sdl2') self.is_found = False self.cargs = [] self.linkargs = [] try: pcdep = PkgConfigDependency('sdl2', environment, kwargs) if pcdep.found(): + self.type_name = 'pkgconfig' self.is_found = True self.cargs = pcdep.get_compile_args() self.linkargs = pcdep.get_link_args() @@ -1124,7 +1130,7 @@ class SDL2Dependency(Dependency): class ExtraFrameworkDependency(Dependency): def __init__(self, name, required, path=None): - Dependency.__init__(self) + Dependency.__init__(self, 'extraframeworks') self.name = None self.detect(name, path) if self.found(): @@ -1165,7 +1171,7 @@ class ExtraFrameworkDependency(Dependency): class ThreadDependency(Dependency): def __init__(self, environment, kwargs): - super().__init__() + super().__init__('threads') self.name = 'threads' self.is_found = True mlog.log('Dependency', mlog.bold(self.name), 'found:', mlog.green('YES')) @@ -1175,7 +1181,7 @@ class ThreadDependency(Dependency): class Python3Dependency(Dependency): def __init__(self, environment, kwargs): - super().__init__() + super().__init__('python3') self.name = 'python3' self.is_found = False self.version = "3.something_maybe" diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index e486ee9..6e57107 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -27,6 +27,7 @@ import os, sys, subprocess, shutil, uuid, re from functools import wraps import importlib +import copy run_depr_printed = False @@ -188,6 +189,7 @@ class EnvironmentVariablesHolder(InterpreterObject): self.methods.update({'set': self.set_method, 'append': self.append_method, 'prepend' : self.prepend_method, + 'copy' : self.copy_method, }) @stringArgs @@ -210,6 +212,9 @@ class EnvironmentVariablesHolder(InterpreterObject): def prepend_method(self, args, kwargs): self.add_var(self.held_object.prepend, args, kwargs) + def copy_method(self, args, kwargs): + return copy.deepcopy(self) + class ConfigurationDataHolder(InterpreterObject): def __init__(self): @@ -278,27 +283,21 @@ class DependencyHolder(InterpreterObject): InterpreterObject.__init__(self) self.held_object = dep self.methods.update({'found' : self.found_method, + 'type_name': self.type_name_method, 'version': self.version_method}) + def type_name_method(self, args, kwargs): + return self.held_object.type_name + def found_method(self, args, kwargs): + if self.held_object.type_name == 'internal': + return True + return self.held_object.found() def version_method(self, args, kwargs): return self.held_object.get_version() -class InternalDependencyHolder(InterpreterObject): - def __init__(self, dep): - InterpreterObject.__init__(self) - self.held_object = dep - self.methods.update({'found' : self.found_method, - 'version': self.version_method, - }) - - def found_method(self, args, kwargs): - return True - - def version_method(self, args, kwargs): - return self.held_object.get_version() class ExternalProgramHolder(InterpreterObject): def __init__(self, ep): @@ -1394,7 +1393,7 @@ class Interpreter(): raise InterpreterException('Dependencies must be external deps') final_deps.append(d) dep = dependencies.InternalDependency(version, incs, compile_args, link_args, libs, sources, final_deps) - return InternalDependencyHolder(dep) + return DependencyHolder(dep) @noKwargs def func_assert(self, node, args, kwargs): @@ -1835,11 +1834,23 @@ class Interpreter(): # We need to actually search for this dep exception = None dep = None - try: - dep = dependencies.find_external_dependency(name, self.environment, kwargs) - except dependencies.DependencyException as e: - exception = e - pass + # If the fallback has already been configured (possibly by a higher level project) + # try to use it before using the native version + if 'fallback' in kwargs: + dirname, varname = self.get_subproject_infos(kwargs) + if dirname in self.subprojects: + try: + dep = self.subprojects[dirname].get_variable_method([varname], {}) + dep = dep.held_object + except KeyError: + pass + + if not dep: + try: + dep = dependencies.find_external_dependency(name, self.environment, kwargs) + except dependencies.DependencyException as e: + exception = e + pass if not dep or not dep.found(): if 'fallback' in kwargs: @@ -1853,35 +1864,42 @@ class Interpreter(): self.coredata.deps[identifier] = dep return DependencyHolder(dep) - def dependency_fallback(self, name, kwargs): + def get_subproject_infos(self, kwargs): fbinfo = kwargs['fallback'] check_stringlist(fbinfo) if len(fbinfo) != 2: raise InterpreterException('Fallback info must have exactly two items.') - dirname, varname = fbinfo + return fbinfo + + def dependency_fallback(self, name, kwargs): + dirname, varname = self.get_subproject_infos(kwargs) try: self.do_subproject(dirname, {}) except: mlog.log('Also couldn\'t find a fallback subproject in', mlog.bold(os.path.join(self.subproject_dir, dirname)), 'for the dependency', mlog.bold(name)) - if kwargs.get('required', True): - raise - else: - return None + return None try: dep = self.subprojects[dirname].get_variable_method([varname], {}) except KeyError: - raise InterpreterException('Fallback variable {!r} in the subproject {!r} does not exist'.format(varname, dirname)) - if not isinstance(dep, (DependencyHolder, InternalDependencyHolder)): - raise InterpreterException('Fallback variable {!r} in the subproject {!r} is not a dependency object.'.format(varname, dirname)) + mlog.log('Fallback variable', mlog.bold(varname), + 'in the subproject', mlog.bold(dirname), 'does not exist') + return None + if not isinstance(dep, DependencyHolder): + mlog.log('Fallback variable', mlog.bold(varname), + 'in the subproject', mlog.bold(dirname), + 'is not a dependency object.') + return None # Check if the version of the declared dependency matches what we want if 'version' in kwargs: wanted = kwargs['version'] found = dep.version_method([], {}) if found == 'undefined' or not mesonlib.version_compare(found, wanted): - m = 'Subproject "{0}" dependency "{1}" version is "{2}" but "{3}" is required.' - raise InterpreterException(m.format(dirname, varname, found, wanted)) + mlog.log('Subproject', mlog.bold(dirname), 'dependency', + mlog.bold(varname), 'version is', mlog.bold(found), + 'but', mlog.bold(wanted), 'is required.') + return None mlog.log('Found a', mlog.green('fallback'), 'subproject', mlog.bold(os.path.join(self.subproject_dir, dirname)), 'for', mlog.bold(name)) diff --git a/mesonbuild/modules/gnome.py b/mesonbuild/modules/gnome.py index be111ea..678ae82 100644 --- a/mesonbuild/modules/gnome.py +++ b/mesonbuild/modules/gnome.py @@ -22,22 +22,36 @@ from ..mesonlib import MesonException from .. import dependencies from .. import mlog from .. import mesonlib +from .. import interpreter +native_glib_version = None girwarning_printed = False gresource_warning_printed = False class GnomeModule: + def get_native_glib_version(self, state): + global native_glib_version + if native_glib_version is None: + glib_dep = dependencies.PkgConfigDependency( + 'glib-2.0', state.environment, {'native': True}) + native_glib_version = glib_dep.get_modversion() + return native_glib_version + def __print_gresources_warning(self): global gresource_warning_printed if not gresource_warning_printed: - mlog.log('Warning, glib compiled dependencies will not work reliably until this upstream issue is fixed:', + mlog.log('Warning, GLib compiled dependencies do not work fully ' + 'with versions of GLib older than 2.50.0.\n' + 'See the following upstream issue:', mlog.bold('https://bugzilla.gnome.org/show_bug.cgi?id=745754')) gresource_warning_printed = True return [] def compile_resources(self, state, args, kwargs): - self.__print_gresources_warning() + if mesonlib.version_compare(self.get_native_glib_version(state), + '< 2.50.0'): + self.__print_gresources_warning() cmd = ['glib-compile-resources', '@INPUT@'] @@ -51,6 +65,19 @@ class GnomeModule: if len(args) < 2: raise MesonException('Not enough arguments; The name of the resource and the path to the XML file are required') + dependencies = kwargs.pop('dependencies', []) + if not isinstance(dependencies, list): + dependencies = [dependencies] + + if mesonlib.version_compare(self.get_native_glib_version(state), + '< 2.48.2'): + if len(dependencies) > 0: + raise MesonException( + 'The "dependencies" argument of gnome.compile_resources() ' + 'can only be used with glib-compile-resources version ' + '2.48.2 or newer, due to ' + '<https://bugzilla.gnome.org/show_bug.cgi?id=673101>') + ifile = args[1] if isinstance(ifile, mesonlib.File): ifile = os.path.join(ifile.subdir, ifile.fname) @@ -58,12 +85,20 @@ class GnomeModule: ifile = os.path.join(state.subdir, ifile) else: raise RuntimeError('Unreachable code.') - kwargs['depend_files'] = self.get_gresource_dependencies(state, ifile, source_dirs) + + kwargs['depend_files'] = self.get_gresource_dependencies( + state, ifile, source_dirs, dependencies) for source_dir in source_dirs: sourcedir = os.path.join(state.build_to_src, state.subdir, source_dir) cmd += ['--sourcedir', sourcedir] + if len(dependencies) > 0: + # Add the build variant of each sourcedir if we have any + # generated dependencies. + sourcedir = os.path.join(state.subdir, source_dir) + cmd += ['--sourcedir', sourcedir] + if 'c_name' in kwargs: cmd += ['--c-name', kwargs.pop('c_name')] cmd += ['--generate', '--target', '@OUTPUT@'] @@ -78,9 +113,17 @@ class GnomeModule: target_h = build.CustomTarget(args[0] + '_h', state.subdir, kwargs) return [target_c, target_h] - def get_gresource_dependencies(self, state, input_file, source_dirs): + def get_gresource_dependencies(self, state, input_file, source_dirs, dependencies): self.__print_gresources_warning() + for dep in dependencies: + if not isinstance(dep, interpreter.CustomTargetHolder) and not \ + isinstance(dep, mesonlib.File): + raise MesonException( + 'Unexpected dependency type for gnome.compile_resources() ' + '"dependencies" argument. Please pass the output of ' + 'custom_target() or configure_file().') + cmd = ['glib-compile-resources', input_file, '--generate-dependencies'] @@ -95,7 +138,51 @@ class GnomeModule: mlog.log(mlog.bold('Warning:'), 'glib-compile-resources has failed to get the dependencies for {}'.format(cmd[1])) raise subprocess.CalledProcessError(pc.returncode, cmd) - return stdout.split('\n')[:-1] + dep_files = stdout.split('\n')[:-1] + + # In generate-dependencies mode, glib-compile-resources doesn't raise + # an error for missing resources but instead prints whatever filename + # was listed in the input file. That's good because it means we can + # handle resource files that get generated as part of the build, as + # follows. + # + # If there are multiple generated resource files with the same basename + # then this code will get confused. + + def exists_in_srcdir(f): + return os.path.exists(os.path.join(state.environment.get_source_dir(), f)) + missing_dep_files = [f for f in dep_files if not exists_in_srcdir(f)] + + for missing in missing_dep_files: + found = False + missing_basename = os.path.basename(missing) + + for dep in dependencies: + if isinstance(dep, mesonlib.File): + if dep.fname == missing_basename: + found = True + dep_files.remove(missing) + dep_files.append(dep) + break + elif isinstance(dep, interpreter.CustomTargetHolder): + if dep.held_object.get_basename() == missing_basename: + found = True + dep_files.remove(missing) + dep_files.append( + mesonlib.File( + is_built=True, + subdir=dep.held_object.get_subdir(), + fname=dep.held_object.get_basename())) + break + + if not found: + raise MesonException( + 'Resource "%s" listed in "%s" was not found. If this is a ' + 'generated file, pass the target that generates it to ' + 'gnome.compile_resources() using the "dependencies" ' + 'keyword argument.' % (missing, input_file)) + + return dep_files def get_link_args(self, state, lib, depends=None): link_command = ['-l%s' % lib.name] @@ -158,7 +245,7 @@ class GnomeModule: ldflags.update(extdepflags[1]) gi_includes.update(extdepflags[2]) for source in dep.sources: - if isinstance(source.held_object, GirTarget): + if hasattr(source, 'held_object') and isinstance(source.held_object, GirTarget): gi_includes.update([os.path.join(state.environment.get_build_dir(), source.held_object.get_subdir())]) # This should be any dependency other than an internal one. diff --git a/mesonbuild/modules/i18n.py b/mesonbuild/modules/i18n.py index 33874fa..00787f8 100644 --- a/mesonbuild/modules/i18n.py +++ b/mesonbuild/modules/i18n.py @@ -24,8 +24,12 @@ class I18nModule: languages = mesonlib.stringlistify(kwargs.get('languages', [])) if len(languages) == 0: raise coredata.MesonException('List of languages empty.') + datadirs = mesonlib.stringlistify(kwargs.get('data_dirs', [])) extra_args = mesonlib.stringlistify(kwargs.get('args', [])) - potargs = [state.environment.get_build_command(), '--internal', 'gettext', 'pot', packagename] + extra_args + potargs = [state.environment.get_build_command(), '--internal', 'gettext', 'pot', packagename] + if datadirs: + potargs.append('--datadirs=' + ':'.join(datadirs)) + potargs += extra_args pottarget = build.RunTarget(packagename + '-pot', sys.executable, potargs, [], state.subdir) gmoargs = [state.environment.get_build_command(), '--internal', 'gettext', 'gen_gmo'] + languages gmotarget = build.RunTarget(packagename + '-gmo', sys.executable, gmoargs, [], state.subdir) diff --git a/mesonbuild/modules/pkgconfig.py b/mesonbuild/modules/pkgconfig.py index 9c235b5..0cfd309 100644 --- a/mesonbuild/modules/pkgconfig.py +++ b/mesonbuild/modules/pkgconfig.py @@ -37,8 +37,9 @@ class PkgConfigModule: mlog.log(mlog.red('WARNING:'), msg.format(l.name, 'name_prefix', l.name, pcfile)) return l.name - def generate_pkgconfig_file(self, state, libraries, subdirs, name, description, version, pcfile, - pub_reqs, priv_reqs, priv_libs): + def generate_pkgconfig_file(self, state, libraries, subdirs, name, description, + url, version, pcfile, pub_reqs, priv_reqs, + conflicts, priv_libs): coredata = state.environment.get_coredata() outdir = state.environment.scratch_dir fname = os.path.join(outdir, pcfile) @@ -51,6 +52,8 @@ class PkgConfigModule: ofile.write('Name: %s\n' % name) if len(description) > 0: ofile.write('Description: %s\n' % description) + if len(url) > 0: + ofile.write('URL: %s\n' % url) if len(version) > 0: ofile.write('Version: %s\n' % version) if len(pub_reqs) > 0: @@ -58,45 +61,55 @@ class PkgConfigModule: if len(priv_reqs) > 0: ofile.write( 'Requires.private: {}\n'.format(' '.join(priv_reqs))) + if len(conflicts) > 0: + ofile.write('Conflicts: {}\n'.format(' '.join(conflicts))) + def generate_libs_flags(libs): + msg = 'Library target {0!r} has {1!r} set. Compilers ' \ + 'may not find it from its \'-l{2}\' linker flag in the ' \ + '{3!r} pkg-config file.' + for l in libs: + if isinstance(l, str): + yield l + else: + if l.custom_install_dir: + yield '-L${prefix}/%s ' % l.custom_install_dir + else: + yield '-L${libdir}' + lname = self._get_lname(l, msg, pcfile) + # If using a custom suffix, the compiler may not be able to + # find the library + if l.name_suffix_set: + mlog.log(mlog.red('WARNING:'), msg.format(l.name, 'name_suffix', lname, pcfile)) + yield '-l%s' % lname + if len(libraries) > 0: + ofile.write('Libs: {}\n'.format(' '.join(generate_libs_flags(libraries)))) if len(priv_libs) > 0: - ofile.write( - 'Libraries.private: {}\n'.format(' '.join(priv_libs))) - ofile.write('Libs: -L${libdir} ') - msg = 'Library target {0!r} has {1!r} set. Compilers ' \ - 'may not find it from its \'-l{2}\' linker flag in the ' \ - '{3!r} pkg-config file.' - for l in libraries: - if l.custom_install_dir: - ofile.write('-L${prefix}/%s ' % l.custom_install_dir) - lname = self._get_lname(l, msg, pcfile) - # If using a custom suffix, the compiler may not be able to - # find the library - if l.name_suffix_set: - mlog.log(mlog.red('WARNING:'), msg.format(l.name, 'name_suffix', lname, pcfile)) - ofile.write('-l{} '.format(lname)) - ofile.write('\n') - ofile.write('CFlags: ') + ofile.write('Libs.private: {}\n'.format(' '.join(generate_libs_flags(priv_libs)))) + ofile.write('Cflags:') for h in subdirs: if h == '.': h = '' - ofile.write(os.path.join('-I${includedir}', h)) ofile.write(' ') + ofile.write(os.path.join('-I${includedir}', h)) ofile.write('\n') - def generate(self, state, args, kwargs): - if len(args) > 0: - raise mesonlib.MesonException('Pkgconfig_gen takes no positional arguments.') - libs = kwargs.get('libraries', []) + def process_libs(self, libs): if not isinstance(libs, list): libs = [libs] processed_libs = [] for l in libs: if hasattr(l, 'held_object'): l = l.held_object - if not isinstance(l, (build.SharedLibrary, build.StaticLibrary)): - raise mesonlib.MesonException('Library argument not a library object.') + if not isinstance(l, (build.SharedLibrary, build.StaticLibrary, str)): + raise mesonlib.MesonException('Library argument not a library object nor a string.') processed_libs.append(l) - libs = processed_libs + return processed_libs + + def generate(self, state, args, kwargs): + if len(args) > 0: + raise mesonlib.MesonException('Pkgconfig_gen takes no positional arguments.') + libs = self.process_libs(kwargs.get('libraries', [])) + priv_libs = self.process_libs(kwargs.get('libraries_private', [])) subdirs = mesonlib.stringlistify(kwargs.get('subdirs', ['.'])) version = kwargs.get('version', '') if not isinstance(version, str): @@ -110,17 +123,21 @@ class PkgConfigModule: description = kwargs.get('description', None) if not isinstance(description, str): raise mesonlib.MesonException('Description is not a string.') + url = kwargs.get('url', '') + if not isinstance(url, str): + raise mesonlib.MesonException('URL is not a string.') pub_reqs = mesonlib.stringlistify(kwargs.get('requires', [])) priv_reqs = mesonlib.stringlistify(kwargs.get('requires_private', [])) - priv_libs = mesonlib.stringlistify(kwargs.get('libraries_private', [])) + conflicts = mesonlib.stringlistify(kwargs.get('conflicts', [])) pcfile = filebase + '.pc' pkgroot = kwargs.get('install_dir',None) if pkgroot is None: pkgroot = os.path.join(state.environment.coredata.get_builtin_option('libdir'), 'pkgconfig') if not isinstance(pkgroot, str): raise mesonlib.MesonException('Install_dir must be a string.') - self.generate_pkgconfig_file(state, libs, subdirs, name, description, version, pcfile, - pub_reqs, priv_reqs, priv_libs) + self.generate_pkgconfig_file(state, libs, subdirs, name, description, url, + version, pcfile, pub_reqs, priv_reqs, + conflicts, priv_libs) return build.Data(False, state.environment.get_scratch_dir(), [pcfile], pkgroot) def initialize(): diff --git a/mesonbuild/scripts/gettext.py b/mesonbuild/scripts/gettext.py index ba6b242..95fd45a 100644 --- a/mesonbuild/scripts/gettext.py +++ b/mesonbuild/scripts/gettext.py @@ -15,7 +15,7 @@ import os, subprocess, shutil from mesonbuild.scripts import destdir_join -def run_potgen(src_sub, pkgname, args): +def run_potgen(src_sub, pkgname, datadirs, args): listfile = os.path.join(src_sub, 'POTFILES') if not os.path.exists(listfile): listfile = os.path.join(src_sub, 'POTFILES.in') @@ -23,9 +23,14 @@ def run_potgen(src_sub, pkgname, args): print('Could not find file POTFILES in %s' % src_sub) return 1 + child_env = os.environ.copy() + if datadirs: + child_env['GETTEXTDATADIRS'] = datadirs + ofile = os.path.join(src_sub, pkgname + '.pot') return subprocess.call(['xgettext', '--package-name=' + pkgname, '-p', src_sub, '-f', listfile, - '-D', os.environ['MESON_SOURCE_ROOT'], '-k_', '-o', ofile] + args) + '-D', os.environ['MESON_SOURCE_ROOT'], '-k_', '-o', ofile] + args, + env=child_env) def gen_gmo(src_sub, bld_sub, langs): for l in langs: @@ -47,9 +52,12 @@ def do_install(src_sub, bld_sub, dest, pkgname, langs): def run(args): subcmd = args[0] if subcmd == 'pot': + pkgname = args[1] + datadirs = args[2][11:] if args[2].startswith('--datadirs=') else None + extra_args = args[3:] if datadirs is not None else args[2:] src_sub = os.path.join(os.environ['MESON_SOURCE_ROOT'], os.environ['MESON_SUBDIR']) bld_sub = os.path.join(os.environ['MESON_BUILD_ROOT'], os.environ['MESON_SUBDIR']) - return run_potgen(src_sub, args[1], args[2:]) + return run_potgen(src_sub, pkgname, datadirs, extra_args) elif subcmd == 'gen_gmo': src_sub = os.path.join(os.environ['MESON_SOURCE_ROOT'], os.environ['MESON_SUBDIR']) bld_sub = os.path.join(os.environ['MESON_BUILD_ROOT'], os.environ['MESON_SUBDIR']) diff --git a/test cases/common/51 pkgconfig-gen/meson.build b/test cases/common/51 pkgconfig-gen/meson.build index e31bfe6..fa9439c 100644 --- a/test cases/common/51 pkgconfig-gen/meson.build +++ b/test cases/common/51 pkgconfig-gen/meson.build @@ -7,7 +7,7 @@ libver = '1.0' h = install_headers('simple.h') pkgg.generate( - libraries : lib, + libraries : [lib, '-lz'], subdirs : '.', version : libver, name : 'libsimple', @@ -15,7 +15,16 @@ pkgg.generate( description : 'A simple demo library.', requires : 'glib-2.0', # Not really, but only here to test that this works. requires_private : ['gio-2.0', 'gobject-2.0'], - libraries_private : '-lz') + libraries_private : [lib, '-lz'], +) + +pkgconfig = find_program('pkg-config', required: false) +if pkgconfig.found() + test('pkgconfig-validation', pkgconfig, + args: ['--validate', 'simple'], + env: ['PKG_CONFIG_PATH=' + meson.current_build_dir() + '/meson-private' ], + ) +endif # Test that name_prefix='' and name='libfoo' results in '-lfoo' lib2 = shared_library('libfoo', 'simple.c', diff --git a/test cases/frameworks/7 gnome/meson.build b/test cases/frameworks/7 gnome/meson.build index 2c2e953..a771e71 100644 --- a/test cases/frameworks/7 gnome/meson.build +++ b/test cases/frameworks/7 gnome/meson.build @@ -9,6 +9,7 @@ gir = dependency('gobject-introspection-1.0') gmod = dependency('gmodule-2.0') add_global_arguments('-DMESON_TEST', language : 'c') +subdir('resources-data') subdir('resources') subdir('gir') subdir('schemas') diff --git a/test cases/frameworks/7 gnome/resources-data/meson.build b/test cases/frameworks/7 gnome/resources-data/meson.build new file mode 100644 index 0000000..6343c0e --- /dev/null +++ b/test cases/frameworks/7 gnome/resources-data/meson.build @@ -0,0 +1,16 @@ +subdir('subdir') + +fake_generator_script = ''' +import os, sys +assert os.path.exists(sys.argv[1]), "File %s not found" % sys.argv[1] +print("This is a generated resource") +''' + +# Generate file res3.txt from file res3.txt.in. This is then included +# in a GResource file, driven by resources/meson.build. +res3_txt = custom_target('res3.txt', + input: 'res3.txt.in', + output: 'res3.txt', + command: ['python3', '-c', fake_generator_script, '@INPUT@'], + capture: true, +) diff --git a/test cases/frameworks/7 gnome/resources/data/res1.txt b/test cases/frameworks/7 gnome/resources-data/res1.txt index e10afea..e10afea 100644 --- a/test cases/frameworks/7 gnome/resources/data/res1.txt +++ b/test cases/frameworks/7 gnome/resources-data/res1.txt diff --git a/test cases/frameworks/7 gnome/resources-data/res3.txt.in b/test cases/frameworks/7 gnome/resources-data/res3.txt.in new file mode 100644 index 0000000..077a8e3 --- /dev/null +++ b/test cases/frameworks/7 gnome/resources-data/res3.txt.in @@ -0,0 +1 @@ +This content is ignored, but Meson doesn't need to know that. diff --git a/test cases/frameworks/7 gnome/resources-data/subdir/meson.build b/test cases/frameworks/7 gnome/resources-data/subdir/meson.build new file mode 100644 index 0000000..b41300f --- /dev/null +++ b/test cases/frameworks/7 gnome/resources-data/subdir/meson.build @@ -0,0 +1,8 @@ +cdata = configuration_data() +cdata.set('NOISE', 'BARK') + +res4_txt = configure_file( + input: 'res4.txt.in', + output: 'res4.txt', + configuration: cdata +) diff --git a/test cases/frameworks/7 gnome/resources-data/subdir/res2.txt b/test cases/frameworks/7 gnome/resources-data/subdir/res2.txt new file mode 100644 index 0000000..d297899 --- /dev/null +++ b/test cases/frameworks/7 gnome/resources-data/subdir/res2.txt @@ -0,0 +1 @@ +This is a resource in a subdirectory. diff --git a/test cases/frameworks/7 gnome/resources-data/subdir/res4.txt.in b/test cases/frameworks/7 gnome/resources-data/subdir/res4.txt.in new file mode 100644 index 0000000..c0ec6f2 --- /dev/null +++ b/test cases/frameworks/7 gnome/resources-data/subdir/res4.txt.in @@ -0,0 +1 @@ +@NOISE@ @NOISE@ @NOISE@ diff --git a/test cases/frameworks/7 gnome/resources/generated-main.c b/test cases/frameworks/7 gnome/resources/generated-main.c new file mode 100644 index 0000000..fc9efbd --- /dev/null +++ b/test cases/frameworks/7 gnome/resources/generated-main.c @@ -0,0 +1,27 @@ +#include<stdio.h> +#include<string.h> +#include<gio/gio.h> +#include"generated-resources.h" + +#define EXPECTED "This is a generated resource.\n" + +int main(int argc, char **argv) { + GResource *res = generated_resources_get_resource(); + GError *err = NULL; + GBytes *data = g_resources_lookup_data("/com/example/myprog/res3.txt", + G_RESOURCE_LOOKUP_FLAGS_NONE, &err); + + if(data == NULL) { + fprintf(stderr, "Data lookup failed: %s\n", err->message); + return 1; + } + if(strcmp(g_bytes_get_data(data, NULL), EXPECTED) != 0) { + fprintf(stderr, "Resource contents are wrong:\n %s\n", + (const char*)g_bytes_get_data(data, NULL)); + return 1; + } + fprintf(stdout, "All ok.\n"); + g_bytes_unref(data); + g_resource_unref(res); + return 0; +} diff --git a/test cases/frameworks/7 gnome/resources/generated.gresource.xml b/test cases/frameworks/7 gnome/resources/generated.gresource.xml new file mode 100644 index 0000000..7a242d7 --- /dev/null +++ b/test cases/frameworks/7 gnome/resources/generated.gresource.xml @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="UTF-8"?> +<gresources> + <gresource prefix="/com/example/myprog"> + <file>res1.txt</file> + <file>subdir/res2.txt</file> + <file>res3.txt</file> + <file>subdir/res4.txt</file> + </gresource> +</gresources> diff --git a/test cases/frameworks/7 gnome/resources/meson.build b/test cases/frameworks/7 gnome/resources/meson.build index 937dc47..5762a8c 100644 --- a/test cases/frameworks/7 gnome/resources/meson.build +++ b/test cases/frameworks/7 gnome/resources/meson.build @@ -1,7 +1,29 @@ -myres = gnome.compile_resources('myresources', 'myresource.gresource.xml', -source_dir : 'data', -c_name : 'myres') +# There are two tests here, because the 2nd one depends on a version of +# GLib (2.48.2) that is very recent at the time of writing. -resexe = executable('resprog', 'main.c', myres, -dependencies : gio) -test('resource test', resexe) +simple_resources = gnome.compile_resources('simple-resources', + 'simple.gresource.xml', + source_dir : '../resources-data', + c_name : 'simple_resources') + +simple_res_exe = executable('simple-resources-test', + 'simple-main.c', simple_resources, + dependencies: gio) +test('simple resource test', simple_res_exe) + +if glib.version() >= '2.48.2' + # This test cannot pass if GLib version is older than 2.48.2. + # Meson will raise an error if the user tries to use the 'dependencies' + # argument and the version of GLib is too old for generated resource + # dependencies to work correctly. + generated_resources = gnome.compile_resources('generated-resources', + 'generated.gresource.xml', + source_dir : '../resources-data', + c_name : 'generated_resources', + dependencies : [res3_txt, res4_txt]) + + generated_res_exe = executable('generated-resources-test', + 'generated-main.c', generated_resources, + dependencies: gio) + test('generated resource test', generated_res_exe) +endif diff --git a/test cases/frameworks/7 gnome/resources/myresource.gresource.xml b/test cases/frameworks/7 gnome/resources/myresource.gresource.xml index b44c879..7a242d7 100644 --- a/test cases/frameworks/7 gnome/resources/myresource.gresource.xml +++ b/test cases/frameworks/7 gnome/resources/myresource.gresource.xml @@ -2,5 +2,8 @@ <gresources> <gresource prefix="/com/example/myprog"> <file>res1.txt</file> + <file>subdir/res2.txt</file> + <file>res3.txt</file> + <file>subdir/res4.txt</file> </gresource> </gresources> diff --git a/test cases/frameworks/7 gnome/resources/main.c b/test cases/frameworks/7 gnome/resources/simple-main.c index 471f07e..3569901 100644 --- a/test cases/frameworks/7 gnome/resources/main.c +++ b/test cases/frameworks/7 gnome/resources/simple-main.c @@ -1,12 +1,12 @@ #include<stdio.h> #include<string.h> #include<gio/gio.h> -#include"myresources.h" +#include"simple-resources.h" #define EXPECTED "This is a resource.\n" int main(int argc, char **argv) { - GResource *res = myres_get_resource(); + GResource *res = simple_resources_get_resource(); GError *err = NULL; GBytes *data = g_resources_lookup_data("/com/example/myprog/res1.txt", G_RESOURCE_LOOKUP_FLAGS_NONE, &err); @@ -20,7 +20,7 @@ int main(int argc, char **argv) { (const char*)g_bytes_get_data(data, NULL)); return 1; } - fprintf(stderr, "All ok.\n"); + fprintf(stdout, "All ok.\n"); g_bytes_unref(data); g_resource_unref(res); return 0; diff --git a/test cases/frameworks/7 gnome/resources/simple.gresource.xml b/test cases/frameworks/7 gnome/resources/simple.gresource.xml new file mode 100644 index 0000000..6e55910 --- /dev/null +++ b/test cases/frameworks/7 gnome/resources/simple.gresource.xml @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8"?> +<gresources> + <gresource prefix="/com/example/myprog"> + <file>res1.txt</file> + <file>subdir/res2.txt</file> + </gresource> +</gresources> diff --git a/test cases/linuxlike/5 dependency versions/meson.build b/test cases/linuxlike/5 dependency versions/meson.build index a3ee335..1de87c8 100644 --- a/test cases/linuxlike/5 dependency versions/meson.build +++ b/test cases/linuxlike/5 dependency versions/meson.build @@ -6,6 +6,7 @@ zlib = dependency('zlib') zlibver = dependency('zlib', version : '>1.0') assert(zlib.version() == zlibver.version(), 'zlib versions did not match!') # Find external dependency with conflicting version +assert(zlib.type_name() == 'pkgconfig', 'zlib should be of type "pkgconfig" not ' + zlib.type_name()) zlibver = dependency('zlib', version : '<1.0', required : false) assert(zlibver.found() == false, 'zlib <1.0 should not be found!') @@ -16,6 +17,7 @@ dependency('somebrokenlib', version : '>=1.0', required : false) # Find internal dependency without version somelibver = dependency('somelib', fallback : ['somelibnover', 'some_dep']) +assert(somelibver.type_name() == 'internal', 'somelibver should be of type "internal", not ' + somelibver.type_name()) # Find an internal dependency again with the same name and a specific version somelib = dependency('somelib', version : '== 0.1', @@ -30,3 +32,7 @@ somelibfail = dependency('somelib', required : false, fallback : ['somelibfail', 'some_dep']) assert(somelibfail.found() == false, 'somelibfail found via wrong fallback') + +fakezlib_dep = dependency('zlib', + fallback : ['somelib', 'fakezlib_dep']) +assert(fakezlib_dep.type_name() == 'internal', 'fakezlib_dep should be of type "internal", not ' + fakezlib_dep.type_name()) diff --git a/test cases/linuxlike/5 dependency versions/subprojects/somelib/meson.build b/test cases/linuxlike/5 dependency versions/subprojects/somelib/meson.build index 049c58b..086e514 100644 --- a/test cases/linuxlike/5 dependency versions/subprojects/somelib/meson.build +++ b/test cases/linuxlike/5 dependency versions/subprojects/somelib/meson.build @@ -6,3 +6,6 @@ someinc = include_directories('.') some_dep = declare_dependency(link_with : somelib, include_directories : someinc) + +fakezlib_dep = declare_dependency(link_with : somelib, + include_directories : someinc) diff --git a/tools/cmake2meson.py b/tools/cmake2meson.py index 7465d45..a99ea50 100755 --- a/tools/cmake2meson.py +++ b/tools/cmake2meson.py @@ -279,15 +279,15 @@ class Converter: defaultstr = '' else: if default == 'OFF': - typestr = ' type : boolean,' + typestr = ' type : \'boolean\',' default = 'false' elif default == 'ON': default = 'true' - typestr = ' type : boolean,' + typestr = ' type : \'boolean\',' else: - typestr = ' type : string,' + typestr = ' type : \'string\',' defaultstr = ' value : %s,' % default - line = "option(%s,%s%s description : '%s')\n" % (optname, + line = "option(%r,%s%s description : '%s')\n" % (optname, typestr, defaultstr, description) |