diff options
Diffstat (limited to 'mesonbuild')
-rw-r--r-- | mesonbuild/backend/ninjabackend.py | 37 | ||||
-rw-r--r-- | mesonbuild/backend/vs2010backend.py | 9 | ||||
-rw-r--r-- | mesonbuild/build.py | 49 | ||||
-rw-r--r-- | mesonbuild/compilers/c.py | 33 | ||||
-rw-r--r-- | mesonbuild/compilers/compilers.py | 2 | ||||
-rw-r--r-- | mesonbuild/dependencies/misc.py | 19 | ||||
-rw-r--r-- | mesonbuild/interpreter.py | 87 | ||||
-rw-r--r-- | mesonbuild/interpreterbase.py | 27 | ||||
-rw-r--r-- | mesonbuild/mesonmain.py | 10 | ||||
-rw-r--r-- | mesonbuild/modules/__init__.py | 1 | ||||
-rw-r--r-- | mesonbuild/modules/gnome.py | 25 | ||||
-rw-r--r-- | mesonbuild/modules/i18n.py | 36 | ||||
-rw-r--r-- | mesonbuild/modules/modtest.py | 2 | ||||
-rw-r--r-- | mesonbuild/modules/pkgconfig.py | 2 | ||||
-rw-r--r-- | mesonbuild/modules/python3.py | 3 | ||||
-rw-r--r-- | mesonbuild/modules/qt4.py | 2 | ||||
-rw-r--r-- | mesonbuild/modules/qt5.py | 2 | ||||
-rw-r--r-- | mesonbuild/modules/rpm.py | 2 | ||||
-rw-r--r-- | mesonbuild/modules/windows.py | 2 | ||||
-rw-r--r--[-rwxr-xr-x] | mesonbuild/rewriter.py | 0 | ||||
-rw-r--r-- | mesonbuild/scripts/meson_install.py | 4 | ||||
-rw-r--r-- | mesonbuild/wrap/wrap.py | 74 |
22 files changed, 267 insertions, 161 deletions
diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index 7088c1e..41b93cb 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -import os, pickle, re, shlex, shutil, subprocess, sys +import os, pickle, re, shlex, subprocess, sys from collections import OrderedDict from . import backends @@ -83,10 +83,9 @@ class NinjaBuildElement: def write(self, outfile): self.check_outputs() - line = 'build %s: %s %s' % ( - ' '.join([ninja_quote(i) for i in self.outfilenames]), - self.rule, - ' '.join([ninja_quote(i) for i in self.infilenames])) + line = 'build %s: %s %s' % (' '.join([ninja_quote(i) for i in self.outfilenames]), + self.rule, + ' '.join([ninja_quote(i) for i in self.infilenames])) if len(self.deps) > 0: line += ' | ' + ' '.join([ninja_quote(x) for x in self.deps]) if len(self.orderdeps) > 0: @@ -721,8 +720,7 @@ int dummy; # On toolchains/platforms that use an import library for # linking (separate from the shared library with all the # code), we need to install that too (dll.a/.lib). - if (isinstance(t, build.SharedLibrary) or - isinstance(t, build.Executable)) and t.get_import_filename(): + if (isinstance(t, build.SharedLibrary) or isinstance(t, build.Executable)) and t.get_import_filename(): if custom_install_dir: # If the DLL is installed into a custom directory, # install the import library into the same place so @@ -856,8 +854,9 @@ int dummy; self.create_target_alias('meson-test', outfile) # And then benchmarks. - cmd = self.environment.get_build_command(True) + ['test', '--benchmark', '--logbase', - 'benchmarklog', '--num-processes=1', '--no-rebuild'] + cmd = self.environment.get_build_command(True) + [ + 'test', '--benchmark', '--logbase', + 'benchmarklog', '--num-processes=1', '--no-rebuild'] elem = NinjaBuildElement(self.all_outputs, 'meson-benchmark', 'CUSTOM_COMMAND', ['all', 'PHONY']) elem.add_item('COMMAND', cmd) elem.add_item('DESC', 'Running benchmark suite.') @@ -1576,9 +1575,10 @@ int dummy; def generate_swift_compile_rules(self, compiler, outfile): rule = 'rule %s_COMPILER\n' % compiler.get_language() full_exe = [ninja_quote(x) for x in self.environment.get_build_command()] + [ - '--internal', - 'dirchanger', - '$RUNDIR'] + '--internal', + 'dirchanger', + '$RUNDIR', + ] invoc = (' '.join(full_exe) + ' ' + ' '.join(ninja_quote(i) for i in compiler.get_exelist())) command = ' command = %s $ARGS $in\n' % invoc @@ -1784,7 +1784,6 @@ rule FORTRAN_DEP_HACK exe_arr = self.exe_object_to_cmd_array(exe) infilelist = genlist.get_inputs() outfilelist = genlist.get_outputs() - base_args = generator.get_arglist() extra_dependencies = [os.path.join(self.build_to_src, i) for i in genlist.extra_depends] source_target_dir = self.get_target_source_dir(target) for i in range(len(infilelist)): @@ -1794,6 +1793,7 @@ rule FORTRAN_DEP_HACK sole_output = '' curfile = infilelist[i] infilename = curfile.rel_to_builddir(self.build_to_src) + base_args = generator.get_arglist(infilename) outfiles = genlist.get_outputs_for(curfile) outfiles = [os.path.join(self.get_target_private_dir(target), of) for of in outfiles] if generator.depfile is None: @@ -1818,7 +1818,7 @@ rule FORTRAN_DEP_HACK elem.add_item('DEPFILE', depfile) if len(extra_dependencies) > 0: elem.add_dep(extra_dependencies) - elem.add_item('DESC', 'Generating $out') + elem.add_item('DESC', 'Generating {!r}.'.format(sole_output)) if isinstance(exe, build.BuildTarget): elem.add_dep(self.get_target_filename(exe)) elem.add_item('COMMAND', cmdlist) @@ -2527,10 +2527,11 @@ rule FORTRAN_DEP_HACK def generate_dist(self, outfile): elem = NinjaBuildElement(self.all_outputs, 'meson-dist', 'CUSTOM_COMMAND', 'PHONY') elem.add_item('DESC', 'Creating source packages') - elem.add_item('COMMAND', self.environment.get_build_command() + - ['--internal', 'dist', - self.environment.source_dir, - self.environment.build_dir] + self.environment.get_build_command()) + elem.add_item('COMMAND', self.environment.get_build_command() + [ + '--internal', 'dist', + self.environment.source_dir, + self.environment.build_dir, + ] + self.environment.get_build_command()) elem.add_item('pool', 'console') elem.write(outfile) # Alias that runs the target defined above diff --git a/mesonbuild/backend/vs2010backend.py b/mesonbuild/backend/vs2010backend.py index 0bbc17c..22c1779 100644 --- a/mesonbuild/backend/vs2010backend.py +++ b/mesonbuild/backend/vs2010backend.py @@ -22,7 +22,6 @@ from .. import build from .. import dependencies from .. import mlog from .. import compilers -from ..build import BuildTarget from ..compilers import CompilerArgs from ..mesonlib import MesonException, File from ..environment import Environment @@ -106,7 +105,6 @@ class Vs2010Backend(backends.Backend): infilelist = genlist.get_inputs() outfilelist = genlist.get_outputs() exe_arr = self.exe_object_to_cmd_array(exe) - base_args = generator.get_arglist() idgroup = ET.SubElement(parent_node, 'ItemGroup') for i in range(len(infilelist)): if len(infilelist) == len(outfilelist): @@ -115,6 +113,7 @@ class Vs2010Backend(backends.Backend): sole_output = '' curfile = infilelist[i] infilename = os.path.join(down, curfile.rel_to_builddir(self.build_to_src)) + base_args = generator.get_arglist(infilename) outfiles_rel = genlist.get_outputs_for(curfile) outfiles = [os.path.join(target_private_dir, of) for of in outfiles_rel] generator_output_files += outfiles @@ -383,8 +382,7 @@ class Vs2010Backend(backends.Backend): cmd = [sys.executable, os.path.join(self.environment.get_script_dir(), 'commandrunner.py'), self.environment.get_build_dir(), self.environment.get_source_dir(), - self.get_target_dir(target)] + \ - self.environment.get_build_command() + self.get_target_dir(target)] + self.environment.get_build_command() for i in cmd_raw: if isinstance(i, build.BuildTarget): cmd.append(os.path.join(self.environment.get_build_dir(), self.get_target_filename(i))) @@ -926,8 +924,7 @@ class Vs2010Backend(backends.Backend): ofile.text = '$(OutDir)%s' % target.get_filename() subsys = ET.SubElement(link, 'SubSystem') subsys.text = subsystem - if (isinstance(target, build.SharedLibrary) or - isinstance(target, build.Executable)) and target.get_import_filename(): + if (isinstance(target, build.SharedLibrary) or isinstance(target, build.Executable)) and target.get_import_filename(): # DLLs built with MSVC always have an import library except when # they're data-only DLLs, but we don't support those yet. ET.SubElement(link, 'ImportLibrary').text = target.get_import_filename() diff --git a/mesonbuild/build.py b/mesonbuild/build.py index 281b060..c54abbd 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -359,6 +359,7 @@ class BuildTarget(Target): self.check_unknown_kwargs(kwargs) if not self.sources and not self.generated and not self.objects: raise InvalidArguments('Build target %s has no sources.' % name) + self.process_compilers_late() self.validate_sources() self.validate_cross_install(environment) @@ -439,6 +440,39 @@ class BuildTarget(Target): removed = True return removed + def process_compilers_late(self): + """Processes additional compilers after kwargs have been evaluated. + + This can add extra compilers that might be required by keyword + arguments, such as link_with or dependencies. It will also try to guess + which compiler to use if one hasn't been selected already. + """ + # Populate list of compilers + if self.is_cross: + compilers = self.environment.coredata.cross_compilers + else: + compilers = self.environment.coredata.compilers + + # If this library is linked against another library we need to consider + # the languages of those libraries as well. + if self.link_targets or self.link_whole_targets: + extra = set() + for t in itertools.chain(self.link_targets, self.link_whole_targets): + for name, compiler in t.compilers.items(): + if name in clike_langs: + extra.add((name, compiler)) + for name, compiler in sorted(extra, key=lambda p: sort_clike(p[0])): + self.compilers[name] = compiler + + if not self.compilers: + # No source files or parent targets, target consists of only object + # files of unknown origin. Just add the first clike compiler + # that we have and hope that it can link these objects + for lang in clike_langs: + if lang in compilers: + self.compilers[lang] = compilers[lang] + break + def process_compilers(self): ''' Populate self.compilers, which is the list of compilers that this @@ -487,14 +521,7 @@ class BuildTarget(Target): # Re-sort according to clike_langs self.compilers = OrderedDict(sorted(self.compilers.items(), key=lambda t: sort_clike(t[0]))) - else: - # No source files, target consists of only object files of unknown - # origin. Just add the first clike compiler that we have and hope - # that it can link these objects - for lang in clike_langs: - if lang in compilers: - self.compilers[lang] = compilers[lang] - break + # If all our sources are Vala, our target also needs the C compiler but # it won't get added above. if 'vala' in self.compilers and 'c' not in self.compilers: @@ -1048,8 +1075,10 @@ class Generator: basename = os.path.splitext(plainname)[0] return self.depfile.replace('@BASENAME@', basename).replace('@PLAINNAME@', plainname) - def get_arglist(self): - return self.arglist + def get_arglist(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.arglist] def process_files(self, name, files, state, extra_args=[]): output = GeneratedList(self, extra_args=extra_args) diff --git a/mesonbuild/compilers/c.py b/mesonbuild/compilers/c.py index 255a506..82b1ef0 100644 --- a/mesonbuild/compilers/c.py +++ b/mesonbuild/compilers/c.py @@ -482,6 +482,34 @@ class CCompiler(Compiler): # minus the extra newline at the end return p.stdo.split(delim + '\n')[-1][:-1] + def get_return_value(self, fname, rtype, prefix, env, extra_args, dependencies): + if rtype == 'string': + fmt = '%s' + cast = '(char*)' + elif rtype == 'int': + fmt = '%lli' + cast = '(long long int)' + else: + raise AssertionError('BUG: Unknown return type {!r}'.format(rtype)) + fargs = {'prefix': prefix, 'f': fname, 'cast': cast, 'fmt': fmt} + code = '''{prefix} + #include <stdio.h> + int main(int argc, char *argv[]) {{ + printf ("{fmt}", {cast} {f}()); + }}'''.format(**fargs) + res = self.run(code, env, extra_args, dependencies) + if not res.compiled: + m = 'Could not get return value of {}()' + raise EnvironmentException(m.format(fname)) + if rtype == 'string': + return res.stdout + elif rtype == 'int': + try: + return int(res.stdout.strip()) + except: + m = 'Return value of {}() is not an int' + raise EnvironmentException(m.format(fname)) + @staticmethod def _no_prototype_templ(): """ @@ -896,6 +924,9 @@ class VisualStudioCCompiler(CCompiler): def get_linker_search_args(self, dirname): return ['/LIBPATH:' + dirname] + def get_gui_app_args(self): + return ['/SUBSYSTEM:WINDOWS'] + def get_pic_args(self): return [] # PIC is handled by the loader on Windows @@ -1025,5 +1056,3 @@ class VisualStudioCCompiler(CCompiler): # and the can not be called. return None return vs32_instruction_set_args.get(instruction_set, None) - - diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py index c431194..89208e0 100644 --- a/mesonbuild/compilers/compilers.py +++ b/mesonbuild/compilers/compilers.py @@ -252,7 +252,7 @@ vs32_instruction_set_args = {'mmx': ['/arch:SSE'], # There does not seem to be a 'avx': ['/arch:AVX'], 'avx2': ['/arch:AVX2'], 'neon': None, -} + } # The 64 bit compiler defaults to /arch:avx. vs64_instruction_set_args = {'mmx': ['/arch:AVX'], diff --git a/mesonbuild/dependencies/misc.py b/mesonbuild/dependencies/misc.py index c0ac5a8..c2b6dbd 100644 --- a/mesonbuild/dependencies/misc.py +++ b/mesonbuild/dependencies/misc.py @@ -575,6 +575,7 @@ class Python3Dependency(ExternalDependency): else: return [DependencyMethods.PKGCONFIG] + class PcapDependency(ExternalDependency): def __init__(self, environment, kwargs): super().__init__('pcap', environment, None, kwargs) @@ -598,23 +599,12 @@ class PcapDependency(ExternalDependency): self.compile_args = stdo.strip().split() stdo = Popen_safe(['pcap-config', '--libs'])[1] self.link_args = stdo.strip().split() - self.version = '0' + self.version = self.get_pcap_lib_version() self.is_found = True mlog.log('Dependency', mlog.bold('pcap'), 'found:', mlog.green('YES'), '(%s)' % pcapconf) return mlog.debug('Could not find pcap-config binary, trying next.') - if DependencyMethods.EXTRAFRAMEWORK in self.methods: - if mesonlib.is_osx(): - fwdep = ExtraFrameworkDependency('pcap', False, None, self.env, - self.language, kwargs) - if fwdep.found(): - self.is_found = True - self.compile_args = fwdep.get_compile_args() - self.link_args = fwdep.get_link_args() - self.version = '2' # FIXME - return - mlog.log('Dependency', mlog.bold('pcap'), 'found:', mlog.red('NO')) def get_methods(self): if mesonlib.is_osx(): @@ -622,6 +612,11 @@ class PcapDependency(ExternalDependency): else: return [DependencyMethods.PKGCONFIG, DependencyMethods.PCAPCONFIG] + def get_pcap_lib_version(self): + return self.compiler.get_return_value('pcap_lib_version', 'string', + '#include <pcap.h>', self.env, [], [self]) + + class CupsDependency(ExternalDependency): def __init__(self, environment, kwargs): super().__init__('cups', environment, None, kwargs) diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index 69c49c2..2148bed 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -881,7 +881,7 @@ class CompilerHolder(InterpreterObject): extra_args = self.determine_args(kwargs) deps = self.determine_dependencies(kwargs) value = self.compiler.get_define(element, prefix, self.environment, extra_args, deps) - mlog.log('Checking for value of define "%s": %s' % (element, value)) + mlog.log('Fetching value of define "%s": %s' % (element, value)) return value def compiles_method(self, args, kwargs): @@ -1028,7 +1028,6 @@ class CompilerHolder(InterpreterObject): h) return result - def first_supported_argument_method(self, args, kwargs): for i in mesonlib.stringlistify(args): if self.compiler.has_argument(i, self.environment): @@ -1245,48 +1244,50 @@ class MesonMain(InterpreterObject): pch_kwargs = set(['c_pch', 'cpp_pch']) -lang_arg_kwargs = set(['c_args', - 'cpp_args', - 'd_args', - 'd_import_dirs', - 'd_unittest', - 'd_module_versions', - 'fortran_args', - 'java_args', - 'objc_args', - 'objcpp_args', - 'rust_args', - 'vala_args', - 'cs_args', - ]) +lang_arg_kwargs = set([ + 'c_args', + 'cpp_args', + 'd_args', + 'd_import_dirs', + 'd_unittest', + 'd_module_versions', + 'fortran_args', + 'java_args', + 'objc_args', + 'objcpp_args', + 'rust_args', + 'vala_args', + 'cs_args', +]) vala_kwargs = set(['vala_header', 'vala_gir', 'vala_vapi']) rust_kwargs = set(['rust_crate_type']) -cs_kwargs = set(['resources']) - -buildtarget_kwargs = set(['build_by_default', - 'build_rpath', - 'dependencies', - 'extra_files', - 'gui_app', - 'link_with', - 'link_whole', - 'link_args', - 'link_depends', - 'implicit_include_directories', - 'include_directories', - 'install', - 'install_rpath', - 'install_dir', - 'name_prefix', - 'name_suffix', - 'native', - 'objects', - 'override_options', - 'pic', - 'sources', - 'vs_module_defs', - ]) +cs_kwargs = set(['resources', 'cs_args']) + +buildtarget_kwargs = set([ + 'build_by_default', + 'build_rpath', + 'dependencies', + 'extra_files', + 'gui_app', + 'link_with', + 'link_whole', + 'link_args', + 'link_depends', + 'implicit_include_directories', + 'include_directories', + 'install', + 'install_rpath', + 'install_dir', + 'name_prefix', + 'name_suffix', + 'native', + 'objects', + 'override_options', + 'pic', + 'sources', + 'vs_module_defs', +]) build_target_common_kwargs = ( buildtarget_kwargs | @@ -2013,11 +2014,11 @@ class Interpreter(InterpreterBase): if not isinstance(use_native, bool): raise InvalidArguments('Argument to "native" must be a boolean.') if not use_native: - progobj = self.program_from_cross_file(args) + progobj = self.program_from_cross_file(args) if progobj is None: progobj = self.program_from_system(args) if required and (progobj is None or not progobj.found()): - raise InvalidArguments('Program "%s" not found or not executable' % exename) + raise InvalidArguments('Program "%s" not found or not executable' % args[0]) if progobj is None: return ExternalProgramHolder(dependencies.ExternalProgram('nonexistingprogram')) return progobj diff --git a/mesonbuild/interpreterbase.py b/mesonbuild/interpreterbase.py index d2e2ab3..1dd2f02 100644 --- a/mesonbuild/interpreterbase.py +++ b/mesonbuild/interpreterbase.py @@ -450,9 +450,25 @@ class InterpreterBase: else: raise InterpreterException('Unknown method "%s" for an integer.' % method_name) + @staticmethod + def _get_one_string_posarg(posargs, method_name): + if len(posargs) > 1: + m = '{}() must have zero or one arguments' + raise InterpreterException(m.format(method_name)) + elif len(posargs) == 1: + s = posargs[0] + if not isinstance(s, str): + m = '{}() argument must be a string' + raise InterpreterException(m.format(method_name)) + return s + return None + def string_method_call(self, obj, method_name, args): (posargs, _) = self.reduce_arguments(args) if method_name == 'strip': + s = self._get_one_string_posarg(posargs, 'strip') + if s is not None: + return obj.strip(s) return obj.strip() elif method_name == 'format': return self.format_string(obj, args) @@ -463,15 +479,10 @@ class InterpreterBase: elif method_name == 'underscorify': return re.sub(r'[^a-zA-Z0-9]', '_', obj) elif method_name == 'split': - if len(posargs) > 1: - raise InterpreterException('Split() must have at most one argument.') - elif len(posargs) == 1: - s = posargs[0] - if not isinstance(s, str): - raise InterpreterException('Split() argument must be a string') + s = self._get_one_string_posarg(posargs, 'split') + if s is not None: return obj.split(s) - else: - return obj.split() + return obj.split() elif method_name == 'startswith' or method_name == 'contains' or method_name == 'endswith': s = posargs[0] if not isinstance(s, str): diff --git a/mesonbuild/mesonmain.py b/mesonbuild/mesonmain.py index 1657ddd..45e6026 100644 --- a/mesonbuild/mesonmain.py +++ b/mesonbuild/mesonmain.py @@ -122,11 +122,11 @@ class MesonApp: if os.path.exists(priv_dir): if not handshake: print('Directory already configured, exiting Meson. Just run your build command\n' - '(e.g. ninja) and Meson will regenerate as necessary. If ninja fails, run ninja\n' - 'reconfigure to force Meson to regenerate.\n' - '\nIf build failures persist, manually wipe your build directory to clear any\n' - 'stored system data.\n' - '\nTo change option values, run meson configure instead.') + '(e.g. ninja) and Meson will regenerate as necessary. If ninja fails, run ninja\n' + 'reconfigure to force Meson to regenerate.\n' + '\nIf build failures persist, manually wipe your build directory to clear any\n' + 'stored system data.\n' + '\nTo change option values, run meson configure instead.') sys.exit(0) else: if handshake: diff --git a/mesonbuild/modules/__init__.py b/mesonbuild/modules/__init__.py index 8b5b210..364bc45 100644 --- a/mesonbuild/modules/__init__.py +++ b/mesonbuild/modules/__init__.py @@ -4,7 +4,6 @@ from .. import build from .. import dependencies from .. import mlog from ..mesonlib import MesonException -from ..interpreterbase import permittedKwargs, noKwargs class permittedSnippetKwargs: diff --git a/mesonbuild/modules/gnome.py b/mesonbuild/modules/gnome.py index 137d380..1ab075b 100644 --- a/mesonbuild/modules/gnome.py +++ b/mesonbuild/modules/gnome.py @@ -17,7 +17,6 @@ functionality such as gobject-introspection, gresources and gtk-doc''' from .. import build import os -import sys import copy import subprocess from . import ModuleReturnValue @@ -30,7 +29,7 @@ from .. import interpreter from . import GResourceTarget, GResourceHeaderTarget, GirTarget, TypelibTarget, VapiTarget from . import find_program, get_include_args from . import ExtensionModule -from . import noKwargs, permittedKwargs +from ..interpreterbase import noKwargs, permittedKwargs # gresource compilation is broken due to the way # the resource compiler and Ninja clash about it @@ -697,18 +696,22 @@ This will become a hard error in the future.''') args.append('--langs=' + '@@'.join(langs)) inscript = build.RunScript(script, args) - potargs = state.environment.get_build_command() + ['--internal', 'yelphelper', 'pot', - '--subdir=' + state.subdir, - '--id=' + project_id, - '--sources=' + source_str] + potargs = state.environment.get_build_command() + [ + '--internal', 'yelphelper', 'pot', + '--subdir=' + state.subdir, + '--id=' + project_id, + '--sources=' + source_str, + ] pottarget = build.RunTarget('help-' + project_id + '-pot', potargs[0], potargs[1:], [], state.subdir) - poargs = state.environment.get_build_command() + ['--internal', 'yelphelper', 'update-po', - '--subdir=' + state.subdir, - '--id=' + project_id, - '--sources=' + source_str, - '--langs=' + '@@'.join(langs)] + poargs = state.environment.get_build_command() + [ + '--internal', 'yelphelper', 'update-po', + '--subdir=' + state.subdir, + '--id=' + project_id, + '--sources=' + source_str, + '--langs=' + '@@'.join(langs), + ] potarget = build.RunTarget('help-' + project_id + '-update-po', poargs[0], poargs[1:], [], state.subdir) diff --git a/mesonbuild/modules/i18n.py b/mesonbuild/modules/i18n.py index 2af09de..c1dd837 100644 --- a/mesonbuild/modules/i18n.py +++ b/mesonbuild/modules/i18n.py @@ -12,7 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -import sys import shutil from os import path @@ -20,7 +19,7 @@ from .. import coredata, mesonlib, build from ..mesonlib import MesonException from . import ModuleReturnValue from . import ExtensionModule -from . import permittedKwargs +from ..interpreterbase import permittedKwargs PRESET_ARGS = { 'glib': [ @@ -72,8 +71,10 @@ class I18nModule(ExtensionModule): datadirs = self._get_data_dirs(state, mesonlib.stringlistify(kwargs.pop('data_dirs', []))) datadirs = '--datadirs=' + ':'.join(datadirs) if datadirs else None - command = state.environment.get_build_command() + ['--internal', 'msgfmthelper', - '@INPUT@', '@OUTPUT@', file_type, podir] + command = state.environment.get_build_command() + [ + '--internal', 'msgfmthelper', + '@INPUT@', '@OUTPUT@', file_type, podir + ] if datadirs: command.append(datadirs) @@ -81,7 +82,7 @@ class I18nModule(ExtensionModule): ct = build.CustomTarget(kwargs['output'] + '_merge', state.subdir, kwargs) return ModuleReturnValue(ct, [ct]) - @permittedKwargs({'po_dir', 'data_dirs', 'type', 'languages', 'args', 'preset'}) + @permittedKwargs({'po_dir', 'data_dirs', 'type', 'languages', 'args', 'preset', 'install'}) def gettext(self, state, args, kwargs): if len(args) != 1: raise coredata.MesonException('Gettext requires one positional argument (package name).') @@ -126,16 +127,21 @@ class I18nModule(ExtensionModule): updatepoargs.append(extra_args) updatepotarget = build.RunTarget(packagename + '-update-po', updatepoargs[0], updatepoargs[1:], [], state.subdir) - script = state.environment.get_build_command() - args = ['--internal', 'gettext', 'install', - '--subdir=' + state.subdir, - '--localedir=' + state.environment.coredata.get_builtin_option('localedir'), - pkg_arg] - if lang_arg: - args.append(lang_arg) - iscript = build.RunScript(script, args) - - return ModuleReturnValue(None, [pottarget, gmotarget, iscript, updatepotarget]) + targets = [pottarget, gmotarget, updatepotarget] + + install = kwargs.get('install', True) + if install: + script = state.environment.get_build_command() + args = ['--internal', 'gettext', 'install', + '--subdir=' + state.subdir, + '--localedir=' + state.environment.coredata.get_builtin_option('localedir'), + pkg_arg] + if lang_arg: + args.append(lang_arg) + iscript = build.RunScript(script, args) + targets.append(iscript) + + return ModuleReturnValue(None, targets) def initialize(): return I18nModule() diff --git a/mesonbuild/modules/modtest.py b/mesonbuild/modules/modtest.py index dd2f215..758eeae 100644 --- a/mesonbuild/modules/modtest.py +++ b/mesonbuild/modules/modtest.py @@ -14,7 +14,7 @@ from . import ModuleReturnValue from . import ExtensionModule -from . import noKwargs +from ..interpreterbase import noKwargs class TestModule(ExtensionModule): diff --git a/mesonbuild/modules/pkgconfig.py b/mesonbuild/modules/pkgconfig.py index 824ba78..aaed820 100644 --- a/mesonbuild/modules/pkgconfig.py +++ b/mesonbuild/modules/pkgconfig.py @@ -19,7 +19,7 @@ from .. import mesonlib from .. import mlog from . import ModuleReturnValue from . import ExtensionModule -from . import permittedKwargs +from ..interpreterbase import permittedKwargs class PkgConfigModule(ExtensionModule): diff --git a/mesonbuild/modules/python3.py b/mesonbuild/modules/python3.py index 94db75c..4fae88b 100644 --- a/mesonbuild/modules/python3.py +++ b/mesonbuild/modules/python3.py @@ -18,7 +18,8 @@ from .. import mesonlib, dependencies from . import ExtensionModule from mesonbuild.modules import ModuleReturnValue -from . import noKwargs, permittedSnippetKwargs +from . import permittedSnippetKwargs +from ..interpreterbase import noKwargs from ..interpreter import shlib_kwargs mod_kwargs = set() diff --git a/mesonbuild/modules/qt4.py b/mesonbuild/modules/qt4.py index 37e630b..a63aff8 100644 --- a/mesonbuild/modules/qt4.py +++ b/mesonbuild/modules/qt4.py @@ -20,7 +20,7 @@ from ..dependencies import Qt4Dependency from . import ExtensionModule import xml.etree.ElementTree as ET from . import ModuleReturnValue -from . import permittedKwargs +from ..interpreterbase import permittedKwargs class Qt4Module(ExtensionModule): tools_detected = False diff --git a/mesonbuild/modules/qt5.py b/mesonbuild/modules/qt5.py index ef3d52f..08ce662 100644 --- a/mesonbuild/modules/qt5.py +++ b/mesonbuild/modules/qt5.py @@ -20,7 +20,7 @@ from ..dependencies import Qt5Dependency from . import ExtensionModule import xml.etree.ElementTree as ET from . import ModuleReturnValue -from . import permittedKwargs +from ..interpreterbase import permittedKwargs class Qt5Module(ExtensionModule): tools_detected = False diff --git a/mesonbuild/modules/rpm.py b/mesonbuild/modules/rpm.py index b0a8db9..dbb01f7 100644 --- a/mesonbuild/modules/rpm.py +++ b/mesonbuild/modules/rpm.py @@ -22,7 +22,7 @@ from .. import mlog from . import GirTarget, TypelibTarget from . import ModuleReturnValue from . import ExtensionModule -from . import noKwargs +from ..interpreterbase import noKwargs import os diff --git a/mesonbuild/modules/windows.py b/mesonbuild/modules/windows.py index ab215dc..c16d7a8 100644 --- a/mesonbuild/modules/windows.py +++ b/mesonbuild/modules/windows.py @@ -20,7 +20,7 @@ from ..mesonlib import MesonException, extract_as_list from . import get_include_args from . import ModuleReturnValue from . import ExtensionModule -from . import permittedKwargs +from ..interpreterbase import permittedKwargs class WindowsModule(ExtensionModule): diff --git a/mesonbuild/rewriter.py b/mesonbuild/rewriter.py index b88c5ef..b88c5ef 100755..100644 --- a/mesonbuild/rewriter.py +++ b/mesonbuild/rewriter.py diff --git a/mesonbuild/scripts/meson_install.py b/mesonbuild/scripts/meson_install.py index f978be4..985b0e9 100644 --- a/mesonbuild/scripts/meson_install.py +++ b/mesonbuild/scripts/meson_install.py @@ -227,7 +227,9 @@ def install_man(d): if outfilename.endswith('.gz') and not full_source_filename.endswith('.gz'): with open(outfilename, 'wb') as of: with open(full_source_filename, 'rb') as sf: - of.write(gzip.compress(sf.read())) + # Set mtime and filename for reproducibility. + with gzip.GzipFile(fileobj=of, mode='wb', filename='', mtime=0) as gz: + gz.write(sf.read()) shutil.copystat(full_source_filename, outfilename) append_to_log(outfilename) else: diff --git a/mesonbuild/wrap/wrap.py b/mesonbuild/wrap/wrap.py index ac84d0e..14529ab 100644 --- a/mesonbuild/wrap/wrap.py +++ b/mesonbuild/wrap/wrap.py @@ -14,7 +14,7 @@ from .. import mlog import contextlib -import urllib.request, os, hashlib, shutil +import urllib.request, os, hashlib, shutil, tempfile, stat import subprocess import sys from pathlib import Path @@ -230,6 +230,8 @@ class Resolver: def get_data(self, url): blocksize = 10 * 1024 + h = hashlib.sha256() + tmpfile = tempfile.NamedTemporaryFile(mode='wb', dir=self.cachedir, delete=False) if url.startswith('https://wrapdb.mesonbuild.com'): resp = open_wrapdburl(url) else: @@ -241,26 +243,34 @@ class Resolver: dlsize = None if dlsize is None: print('Downloading file of unknown size.') - return resp.read() + while True: + block = resp.read(blocksize) + if block == b'': + break + h.update(block) + tmpfile.write(block) + hashvalue = h.hexdigest() + return hashvalue, tmpfile.name print('Download size:', dlsize) print('Downloading: ', end='') sys.stdout.flush() printed_dots = 0 - blocks = [] downloaded = 0 while True: block = resp.read(blocksize) if block == b'': break downloaded += len(block) - blocks.append(block) + h.update(block) + tmpfile.write(block) ratio = int(downloaded / dlsize * 10) while printed_dots < ratio: print('.', end='') sys.stdout.flush() printed_dots += 1 print('') - return b''.join(blocks) + hashvalue = h.hexdigest() + return hashvalue, tmpfile.name def get_hash(self, data): h = hashlib.sha256() @@ -272,34 +282,51 @@ class Resolver: ofname = os.path.join(self.cachedir, p.get('source_filename')) if os.path.exists(ofname): mlog.log('Using', mlog.bold(packagename), 'from cache.') - return - srcurl = p.get('source_url') - mlog.log('Downloading', mlog.bold(packagename), 'from', mlog.bold(srcurl)) - srcdata = self.get_data(srcurl) - dhash = self.get_hash(srcdata) - expected = p.get('source_hash') - if dhash != expected: - raise RuntimeError('Incorrect hash for source %s:\n %s expected\n %s actual.' % (packagename, expected, dhash)) - with open(ofname, 'wb') as f: - f.write(srcdata) + else: + srcurl = p.get('source_url') + mlog.log('Downloading', mlog.bold(packagename), 'from', mlog.bold(srcurl)) + dhash, tmpfile = self.get_data(srcurl) + expected = p.get('source_hash') + if dhash != expected: + os.remove(tmpfile) + raise RuntimeError('Incorrect hash for source %s:\n %s expected\n %s actual.' % (packagename, expected, dhash)) + os.rename(tmpfile, ofname) if p.has_patch(): purl = p.get('patch_url') mlog.log('Downloading patch from', mlog.bold(purl)) - pdata = self.get_data(purl) - phash = self.get_hash(pdata) + phash, tmpfile = self.get_data(purl) expected = p.get('patch_hash') if phash != expected: + os.remove(tmpfile) raise RuntimeError('Incorrect hash for patch %s:\n %s expected\n %s actual' % (packagename, expected, phash)) filename = os.path.join(self.cachedir, p.get('patch_filename')) - with open(filename, 'wb') as f: - f.write(pdata) + os.rename(tmpfile, filename) else: mlog.log('Package does not require patch.') + def copy_tree(self, root_src_dir, root_dst_dir): + """ + Copy directory tree. Overwrites also read only files. + """ + for src_dir, dirs, files in os.walk(root_src_dir): + dst_dir = src_dir.replace(root_src_dir, root_dst_dir, 1) + if not os.path.exists(dst_dir): + os.makedirs(dst_dir) + for file_ in files: + src_file = os.path.join(src_dir, file_) + dst_file = os.path.join(dst_dir, file_) + if os.path.exists(dst_file): + try: + os.remove(dst_file) + except PermissionError as exc: + os.chmod(dst_file, stat.S_IWUSR) + os.remove(dst_file) + shutil.copy2(src_file, dst_dir) + def extract_package(self, package): if sys.version_info < (3, 5): try: - import lzma + import lzma # noqa: F401 del lzma except ImportError: pass @@ -322,4 +349,9 @@ class Resolver: pass shutil.unpack_archive(os.path.join(self.cachedir, package.get('source_filename')), extract_dir) if package.has_patch(): - shutil.unpack_archive(os.path.join(self.cachedir, package.get('patch_filename')), self.subdir_root) + try: + shutil.unpack_archive(os.path.join(self.cachedir, package.get('patch_filename')), self.subdir_root) + except Exception: + with tempfile.TemporaryDirectory() as workdir: + shutil.unpack_archive(os.path.join(self.cachedir, package.get('patch_filename')), workdir) + self.copy_tree(workdir, self.subdir_root) |