diff options
51 files changed, 693 insertions, 274 deletions
diff --git a/ci/appveyor-install.bat b/ci/appveyor-install.bat index 9eddeac..becc80a 100644 --- a/ci/appveyor-install.bat +++ b/ci/appveyor-install.bat @@ -1,7 +1,5 @@ set CACHE=C:\cache set CYGWIN_MIRROR="http://cygwin.mirror.constant.com" -set CYGWIN_ADDITIONAL_REPO="http://www.dronecode.org.uk/cygwin/" -set CYGWIN_ADDITIONAL_REPO_KEY="http://www.dronecode.org.uk/cygwin/dronecode.gpg" if _%arch%_ == _x64_ set SETUP=setup-x86_64.exe && set CYGWIN_ROOT=C:\cygwin64 if _%arch%_ == _x86_ set SETUP=setup-x86.exe && set CYGWIN_ROOT=C:\cygwin @@ -9,5 +7,5 @@ if _%arch%_ == _x86_ set SETUP=setup-x86.exe && set CYGWIN_ROOT=C:\cygwin if not exist %CACHE% mkdir %CACHE% echo Updating Cygwin and installing ninja and test prerequisites -%CYGWIN_ROOT%\%SETUP% -qnNdO -R "%CYGWIN_ROOT%" -s "%CYGWIN_MIRROR%" -s "%CYGWIN_ADDITIONAL_REPO%" -K "%CYGWIN_ADDITIONAL_REPO_KEY%" -l "%CACHE%" -g -P "ninja,gcc-objc,gcc-objc++,libglib2.0-devel,zlib-devel,python3-pip" +%CYGWIN_ROOT%\%SETUP% -qnNdO -R "%CYGWIN_ROOT%" -s "%CYGWIN_MIRROR%" -l "%CACHE%" -g -P "ninja,gcc-objc,gcc-objc++,libglib2.0-devel,zlib-devel,python3-pip" echo Install done diff --git a/docs/markdown/Build-options.md b/docs/markdown/Build-options.md index 54905d5..cb7b19e 100644 --- a/docs/markdown/Build-options.md +++ b/docs/markdown/Build-options.md @@ -42,11 +42,16 @@ prefix = get_option('prefix') ``` It should be noted that you can not set option values in your Meson -scripts. They have to be set externally with the `mesonconf` command -line tool. Running `mesonconf` without arguments in a build dir shows -you all options you can set. To change their values use the `-D` +scripts. They have to be set externally with the `meson configure` command +line tool. Running `meson configure` without arguments in a build dir shows +you all options you can set. + +To change their values use the `-D` option: ```console -$ mesonconf -Doption=newvalue +$ meson configure -Doption=newvalue ``` + + +**NOTE:** If you cannot call `meson configure` you likely have a old version of Meson. In that case you can call `mesonconf` instead, but that is deprecated in newer versions diff --git a/docs/markdown/Generating-sources.md b/docs/markdown/Generating-sources.md index c251805..c5e338d 100644 --- a/docs/markdown/Generating-sources.md +++ b/docs/markdown/Generating-sources.md @@ -31,7 +31,7 @@ gen_src = custom_target('gen-output', '--h-out', '@OUTPUT1@']) ``` -The `@INPUT@` there will be transformed to `'out.c' 'out.h'`. Just like the output, you can also refer to each input file individually by index. +The `@INPUT@` there will be transformed to `'somefile1.c' 'file2.c'`. Just like the output, you can also refer to each input file individually by index. Then you just put that in your program and you're done. diff --git a/docs/markdown/Reference-manual.md b/docs/markdown/Reference-manual.md index de51479..f37fb34 100644 --- a/docs/markdown/Reference-manual.md +++ b/docs/markdown/Reference-manual.md @@ -554,6 +554,9 @@ following: - `output` a template string (or list of template strings) defining how an output file name is (or multiple output names are) generated from a single source file name +- `capture` when this argument is set to true, Meson captures `stdout` + of the `executable` and writes it to the target file specified as + `output`. Available since v0.43.0. The returned object also has methods that are documented in the [object methods section](#generator-object) below. @@ -1309,9 +1312,9 @@ the following methods: - `get_id()` returns a string identifying the compiler. For example, `gcc`, `msvc`, [and more](Compiler-properties.md#compiler-id). -- `get_supported_arguments(list_of_string)` returns an array - containing only the arguments supported by the compiler, as if - `has_argument` were called on them individually. +- `get_supported_arguments(list_of_string)` *(added 0.43.0)* returns + an array containing only the arguments supported by the compiler, + as if `has_argument` were called on them individually. - `has_argument(argument_name)` returns true if the compiler accepts the specified command line argument, that is, can compile code @@ -1440,7 +1443,9 @@ are immutable, all operations return their results as a new string. - `startswith(string)` returns true if string starts with the string specified as the argument -- `strip()` removes whitespace at the beginning and end of the string +- `strip()` removes whitespace at the beginning and end of the string + *(added 0.43.0)* optionally can take one positional string argument, + and all characters in that string will be stripped - `to_int` returns the string converted to an integer (error if string is not a number) @@ -1565,6 +1570,11 @@ contains a target with the following methods: this and will also allow Meson to setup inter-target dependencies correctly. Please file a bug if that doesn't work for you. +- `[index]` returns an opaque object that references this target, and can be + used as a source in other targets. When it is used as such it will make that + target depend on this custom target, but the only source added will be the + one that corresponds to the index of the custom target's output argument. + ### `dependency` object This object is returned by [`dependency()`](#dependency) and contains diff --git a/docs/markdown/Release-notes-for-0.43.0/001-generator-capture.md b/docs/markdown/Release-notes-for-0.43.0/001-generator-capture.md new file mode 100644 index 0000000..4eb7fc0 --- /dev/null +++ b/docs/markdown/Release-notes-for-0.43.0/001-generator-capture.md @@ -0,0 +1,4 @@ +## Generator learned capture + +Generators can now be configured to capture the standard output. See +`test cases/common/98 gen extra/meson.build` for an example. diff --git a/docs/markdown/Unit-tests.md b/docs/markdown/Unit-tests.md index 7949522..6ded714 100644 --- a/docs/markdown/Unit-tests.md +++ b/docs/markdown/Unit-tests.md @@ -57,42 +57,42 @@ Sometimes a test can only determine at runtime that it can not be run. The GNU s ## Testing tool -In version 0.37.0 a new tool called `mesontest` was added. The goal of this tool is to provide a simple way to run tests in a variety of different ways. The tool is designed to be run in the build directory. +The goal of the meson test tool is to provide a simple way to run tests in a variety of different ways. The tool is designed to be run in the build directory. The simplest thing to do is just to run all tests, which is equivalent to running `ninja test`. ```console -$ mesontest +$ meson test ``` You can also run only a single test by giving its name: ```console -$ mesontest testname +$ meson test testname ``` Sometimes you need to run the tests multiple times, which is done like this: ```console -$ mesontest --repeat=10 +$ meson test --repeat=10 ``` Invoking tests via a helper executable such as Valgrind can be done with the `--wrap` argument ```console -$ mesontest --wrap=valgrind testname +$ meson test --wrap=valgrind testname ``` Arguments to the wrapper binary can be given like this: ```console -$ mesontest --wrap='valgrind --tool=helgrind' testname +$ meson test --wrap='valgrind --tool=helgrind' testname ``` Meson also supports running the tests under GDB. Just doing this: ```console -$ mesontest --gdb testname +$ meson test --gdb testname ``` Mesontest will launch `gdb` all set up to run the test. Just type `run` in the GDB command prompt to start the program. @@ -100,9 +100,11 @@ Mesontest will launch `gdb` all set up to run the test. Just type `run` in the G The second use case is a test that segfaults only rarely. In this case you can invoke the following command: ```console -$ mesontest --gdb --repeat=10000 testname +$ meson test --gdb --repeat=10000 testname ``` This runs the test up to 10 000 times under GDB automatically. If the program crashes, GDB will halt and the user can debug the application. Note that testing timeouts are disabled in this case so mesontest will not kill `gdb` while the developer is still debugging it. The downside is that if the test binary freezes, the test runner will wait forever. For further information see the command line help of Mesontest by running `mesontest -h`. + +**NOTE:** If `meson test` does not work for you, you likely have a old version of Meson. In that case you should call `mesontest` instead. If `mesontest` doesn't work either you have a very old version prior to 0.37.0 and should upgrade. diff --git a/docs/markdown/i18n-module.md b/docs/markdown/i18n-module.md index 5e6004a..1144e29 100644 --- a/docs/markdown/i18n-module.md +++ b/docs/markdown/i18n-module.md @@ -32,6 +32,8 @@ argument which is the name of the gettext module. [source](https://github.com/mesonbuild/meson/blob/master/mesonbuild/modules/i18n.py) for for their value +* `install`: (*Added 0.43.0*) if false, do not install the built translations. + This function also defines targets for maintainers to use: **Note**: These output to the source directory diff --git a/docs/markdown/snippets/custom-target-index.md b/docs/markdown/snippets/custom-target-index.md new file mode 100644 index 0000000..10d7cf1 --- /dev/null +++ b/docs/markdown/snippets/custom-target-index.md @@ -0,0 +1,21 @@ +# Can index CustomTaget objects + +The `CustomTarget` object can now be indexed like an array. The resulting +object can be used as a source file for other Targets, this will create a +dependency on the original `CustomTarget`, but will only insert the generated +file corresponding to the index value of the `CustomTarget`'s `output` keyword. + + c = CustomTarget( + ... + output : ['out.h', 'out.c'], + ) + lib1 = static_library( + 'lib1', + [lib1_sources, c[0]], + ... + ) + exec = executable( + 'executable', + c[1], + link_with : lib1, + ) diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py index 9f2092b..960f2e2 100644 --- a/mesonbuild/backend/backends.py +++ b/mesonbuild/backend/backends.py @@ -180,7 +180,7 @@ class Backend: Returns the full path of the generated source relative to the build root """ # CustomTarget generators output to the build dir of the CustomTarget - if isinstance(gensrc, build.CustomTarget): + if isinstance(gensrc, (build.CustomTarget, build.CustomTargetIndex)): return os.path.join(self.get_target_dir(gensrc), src) # GeneratedList generators output to the private build directory of the # target that the GeneratedList is used in diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index f67e412..2e6e351 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: @@ -246,7 +245,7 @@ int dummy; header_deps = [] # XXX: Why don't we add deps to CustomTarget headers here? for genlist in target.get_generated_sources(): - if isinstance(genlist, build.CustomTarget): + if isinstance(genlist, (build.CustomTarget, build.CustomTargetIndex)): continue for src in genlist.get_outputs(): if self.environment.is_header(src): @@ -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 @@ -1761,10 +1761,11 @@ rule FORTRAN_DEP_HACK outfile.write('\n') def generate_generator_list_rules(self, target, outfile): - # CustomTargets have already written their rules, - # so write rules for GeneratedLists here + # CustomTargets have already written their rules and + # CustomTargetIndexes don't actually get generated, so write rules for + # GeneratedLists here for genlist in target.get_generated_sources(): - if isinstance(genlist, build.CustomTarget): + if isinstance(genlist, (build.CustomTarget, build.CustomTargetIndex)): continue self.generate_genlist_for_target(genlist, target, outfile) @@ -1813,6 +1814,19 @@ rule FORTRAN_DEP_HACK relout = self.get_target_private_dir(target) args = self.replace_paths(target, args) cmdlist = exe_arr + self.replace_extra_args(args, genlist) + if generator.capture: + exe_data = self.serialize_executable( + cmdlist[0], + cmdlist[1:], + self.environment.get_build_dir(), + capture=outfiles[0] + ) + cmd = self.environment.get_build_command() + ['--internal', 'exe', exe_data] + abs_pdir = os.path.join(self.environment.get_build_dir(), self.get_target_dir(target)) + os.makedirs(abs_pdir, exist_ok=True) + else: + cmd = cmdlist + elem = NinjaBuildElement(self.all_outputs, outfiles, rulename, infilename) if generator.depfile is not None: elem.add_item('DEPFILE', depfile) @@ -1821,7 +1835,7 @@ rule FORTRAN_DEP_HACK 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) + elem.add_item('COMMAND', cmd) elem.write(outfile) def scan_fortran_module_outputs(self, target): @@ -2013,7 +2027,7 @@ rule FORTRAN_DEP_HACK # Generator output goes into the target private dir which is # already in the include paths list. Only custom targets have their # own target build dir. - if not isinstance(i, build.CustomTarget): + if not isinstance(i, (build.CustomTarget, build.CustomTargetIndex)): continue idir = self.get_target_dir(i) if idir not in custom_target_include_dirs: @@ -2527,10 +2541,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 758be79..e4e9696 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 @@ -92,7 +91,7 @@ class Vs2010Backend(backends.Backend): 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): + if isinstance(genlist, (build.CustomTarget, build.CustomTargetIndex)): for i in genlist.get_outputs(): # Path to the generated source from the current vcxproj dir via the build root ipath = os.path.join(down, self.get_target_dir(genlist), i) @@ -129,6 +128,16 @@ class Vs2010Backend(backends.Backend): .replace("@BUILD_ROOT@", self.environment.get_build_dir()) for x in args] cmd = exe_arr + self.replace_extra_args(args, genlist) + if generator.capture: + exe_data = self.serialize_executable( + cmd[0], + cmd[1:], + self.environment.get_build_dir(), + capture=outfiles[0] + ) + cmd = self.environment.get_build_command() + ['--internal', 'exe', exe_data] + abs_pdir = os.path.join(self.environment.get_build_dir(), self.get_target_dir(target)) + os.makedirs(abs_pdir, exist_ok=True) cbs = ET.SubElement(idgroup, 'CustomBuild', Include=infilename) ET.SubElement(cbs, 'Command').text = ' '.join(self.quote_arguments(cmd)) ET.SubElement(cbs, 'Outputs').text = ';'.join(outfiles) @@ -202,6 +211,8 @@ class Vs2010Backend(backends.Backend): for gendep in target.get_generated_sources(): if isinstance(gendep, build.CustomTarget): all_deps[gendep.get_id()] = gendep + elif isinstance(gendep, build.CustomTargetIndex): + all_deps[gendep.target.get_id()] = gendep.target else: gen_exe = gendep.generator.get_exe() if isinstance(gen_exe, build.Executable): @@ -388,8 +399,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))) @@ -946,8 +956,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 5740fbb..5f5dd6b 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -425,7 +425,7 @@ class BuildTarget(Target): if s not in added_sources: self.sources.append(s) added_sources[s] = True - elif isinstance(s, (GeneratedList, CustomTarget)): + elif isinstance(s, (GeneratedList, CustomTarget, CustomTargetIndex)): self.generated.append(s) else: msg = 'Bad source of type {!r} in target {!r}.'.format(type(s).__name__, self.name) @@ -1019,6 +1019,7 @@ class Generator: raise InvalidArguments('First generator argument must be an executable.') self.exe = exe self.depfile = None + self.capture = False self.process_kwargs(kwargs) def __repr__(self): @@ -1062,6 +1063,11 @@ class Generator: if os.path.split(depfile)[1] != depfile: raise InvalidArguments('Depfile must be a plain filename without a subdirectory.') self.depfile = depfile + if 'capture' in kwargs: + capture = kwargs['capture'] + if not isinstance(capture, bool): + raise InvalidArguments('Capture must be boolean.') + self.capture = capture def get_base_outnames(self, inname): plainname = os.path.split(inname)[1] @@ -1676,6 +1682,15 @@ class CustomTarget(Target): def type_suffix(self): return "@cus" + def __getitem__(self, index): + return CustomTargetIndex(self, self.outputs[index]) + + def __setitem__(self, index, value): + raise NotImplementedError + + def __delitem__(self, index): + raise NotImplementedError + class RunTarget(Target): def __init__(self, name, command, args, dependencies, subdir): super().__init__(name, subdir, False) @@ -1735,6 +1750,29 @@ class Jar(BuildTarget): pass +class CustomTargetIndex: + + """A special opaque object returned by indexing a CustomTaget. This object + exists in meson, but acts as a proxy in the backends, making targets depend + on the CustomTarget it's derived from, but only adding one source file to + the sources. + """ + + def __init__(self, target, output): + self.target = target + self.output = output + + def __repr__(self): + return '<CustomTargetIndex: {!r}[{}]>'.format( + self.target, self.target.output.index(self.output)) + + def get_outputs(self): + return [self.output] + + def get_subdir(self): + return self.target.get_subdir() + + class ConfigureFile: def __init__(self, subdir, sourcename, targetname, configuration_data): 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/dev.py b/mesonbuild/dependencies/dev.py index f991d3c..d2dd107 100644 --- a/mesonbuild/dependencies/dev.py +++ b/mesonbuild/dependencies/dev.py @@ -129,9 +129,6 @@ class LLVMDependency(ExternalDependency): 'llvm-config-3.5', 'llvm-config35', 'llvm-config-5.0', 'llvm-config-devel', # development snapshot ] - llvmconfig = None - _llvmconfig_found = False - __best_found = None __cpp_blacklist = {'-DNDEBUG'} def __init__(self, environment, kwargs): @@ -139,11 +136,12 @@ class LLVMDependency(ExternalDependency): # the C linker works fine if only using the C API. super().__init__('llvm-config', environment, 'cpp', kwargs) self.modules = [] + self.llvmconfig = None + self.__best_found = None # FIXME: Support multiple version requirements ala PkgConfigDependency req_version = kwargs.get('version', None) + self.check_llvmconfig(req_version) if self.llvmconfig is None: - self.check_llvmconfig(req_version) - if not self._llvmconfig_found: if self.__best_found is not None: mlog.log('found {!r} but need:'.format(self.__best_found), req_version) @@ -159,31 +157,36 @@ class LLVMDependency(ExternalDependency): mlog.debug('stdout: {}\nstderr: {}'.format(out, err)) if self.required: raise DependencyException('Dependency LLVM not found') + mlog.log('Dependency LLVM found:', mlog.red('NO')) return - else: - self.version = out.strip() - mlog.log('Dependency LLVM found:', mlog.green('YES')) - self.is_found = True - p, out = Popen_safe( - [self.llvmconfig, '--libs', '--ldflags', '--system-libs'])[:2] - if p.returncode != 0: - raise DependencyException('Could not generate libs for LLVM.') - self.link_args = shlex.split(out) - - p, out = Popen_safe([self.llvmconfig, '--cppflags'])[:2] - if p.returncode != 0: - raise DependencyException('Could not generate includedir for LLVM.') - cargs = mesonlib.OrderedSet(shlex.split(out)) - self.compile_args = list(cargs.difference(self.__cpp_blacklist)) - - p, out = Popen_safe([self.llvmconfig, '--components'])[:2] - if p.returncode != 0: - raise DependencyException('Could not generate modules for LLVM.') - self.modules = shlex.split(out) - - modules = mesonlib.stringlistify(kwargs.get('modules', [])) - for mod in modules: + mlog.log('Dependency LLVM found:', mlog.green('YES')) + self.is_found = True + + # Currently meson doesn't really atempt to handle pre-release versions, + # so strip the 'svn' off the end, since it will probably cuase problems + # for users who want the patch version. + self.version = out.strip().rstrip('svn') + + p, out = Popen_safe( + [self.llvmconfig, '--libs', '--ldflags', '--system-libs'])[:2] + if p.returncode != 0: + raise DependencyException('Could not generate libs for LLVM.') + self.link_args = shlex.split(out) + + p, out = Popen_safe([self.llvmconfig, '--cppflags'])[:2] + if p.returncode != 0: + raise DependencyException('Could not generate includedir for LLVM.') + cargs = mesonlib.OrderedSet(shlex.split(out)) + self.compile_args = list(cargs.difference(self.__cpp_blacklist)) + + p, out = Popen_safe([self.llvmconfig, '--components'])[:2] + if p.returncode != 0: + raise DependencyException('Could not generate modules for LLVM.') + self.modules = shlex.split(out) + + modules = mesonlib.stringlistify(mesonlib.flatten(kwargs.get('modules', []))) + for mod in sorted(set(modules)): if mod not in self.modules: mlog.log('LLVM module', mod, 'found:', mlog.red('NO')) self.is_found = False @@ -193,38 +196,33 @@ class LLVMDependency(ExternalDependency): else: mlog.log('LLVM module', mod, 'found:', mlog.green('YES')) - @classmethod - def check_llvmconfig(cls, version_req): + def check_llvmconfig(self, version_req): """Try to find the highest version of llvm-config.""" - for llvmconfig in cls.llvm_config_bins: + for llvmconfig in self.llvm_config_bins: try: p, out = Popen_safe([llvmconfig, '--version'])[0:2] out = out.strip() if p.returncode != 0: continue - # FIXME: As soon as some llvm-config is found, version checks - # in further dependnecy() calls will be ignored if version_req: if version_compare(out, version_req, strict=True): - if cls.__best_found and version_compare(out, '<={}'.format(cls.__best_found), strict=True): + if self.__best_found and version_compare( + out, '<={}'.format(self.__best_found), strict=True): continue - cls.__best_found = out - cls.llvmconfig = llvmconfig + self.__best_found = out + self.llvmconfig = llvmconfig else: # If no specific version is requested use the first version # found, since that should be the best. - cls.__best_found = out - cls.llvmconfig = llvmconfig + self.__best_found = out + self.llvmconfig = llvmconfig break except (FileNotFoundError, PermissionError): pass - if cls.__best_found: + if self.__best_found: mlog.log('Found llvm-config:', - mlog.bold(shutil.which(cls.llvmconfig)), + mlog.bold(shutil.which(self.llvmconfig)), '({})'.format(out.strip())) - cls._llvmconfig_found = True - else: - cls.llvmconfig = False def need_threads(self): return True 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 6658c26..8197b5e 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -566,6 +566,11 @@ class JarHolder(BuildTargetHolder): def __init__(self, target, interp): super().__init__(target, interp) +class CustomTargetIndexHolder(InterpreterObject): + def __init__(self, object_to_hold): + super().__init__() + self.held_object = object_to_hold + class CustomTargetHolder(TargetHolder): def __init__(self, object_to_hold, interp): super().__init__() @@ -582,6 +587,15 @@ class CustomTargetHolder(TargetHolder): def full_path_method(self, args, kwargs): return self.interpreter.backend.get_target_filename_abs(self.held_object) + def __getitem__(self, index): + return CustomTargetIndexHolder(self.held_object[index]) + + def __setitem__(self, index, value): + raise InterpreterException('Cannot set a member of a CustomTarget') + + def __delitem__(self, index): + raise InterpreterException('Cannot delete a member of a CustomTarget') + class RunTargetHolder(InterpreterObject): def __init__(self, name, command, args, dependencies, subdir): super().__init__() @@ -881,7 +895,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 +1042,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 +1258,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', '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', - ]) +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 | @@ -1320,7 +1335,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'}, + 'generator': {'arguments', 'output', 'depfile', 'capture'}, 'include_directories': {'is_system'}, 'install_data': {'install_dir', 'install_mode', 'sources'}, 'install_headers': {'install_dir', 'subdir'}, @@ -2013,7 +2028,7 @@ 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()): @@ -2549,12 +2564,10 @@ class Interpreter(InterpreterBase): if not isinstance(inputfile, (str, mesonlib.File)): raise InterpreterException('Input must be a string or a file') if isinstance(inputfile, str): - inputfile = os.path.join(self.subdir, inputfile) - ifile_abs = os.path.join(self.environment.source_dir, inputfile) - else: - ifile_abs = inputfile.absolute_path(self.environment.source_dir, - self.environment.build_dir) - inputfile = inputfile.relative_name() + inputfile = mesonlib.File.from_source_file(self.environment.source_dir, + self.subdir, inputfile) + ifile_abs = inputfile.absolute_path(self.environment.source_dir, + self.environment.build_dir) elif 'command' in kwargs and '@INPUT@' in kwargs['command']: raise InterpreterException('@INPUT@ used as command argument, but no input file specified.') # Validate output @@ -2575,18 +2588,13 @@ class Interpreter(InterpreterBase): raise InterpreterException('Argument "configuration" is not of type configuration_data') mlog.log('Configuring', mlog.bold(output), 'using configuration') if inputfile is not None: - # Normalize the path of the conffile to avoid duplicates - # This is especially important to convert '/' to '\' on Windows - conffile = os.path.normpath(inputfile) - if conffile not in self.build_def_files: - self.build_def_files.append(conffile) os.makedirs(os.path.join(self.environment.build_dir, self.subdir), exist_ok=True) missing_variables = mesonlib.do_conf_file(ifile_abs, ofile_abs, conf.held_object) if missing_variables: var_list = ", ".join(map(repr, sorted(missing_variables))) mlog.warning( - "The variable(s) %s in the input file %r are not " + "The variable(s) %s in the input file %s are not " "present in the given configuration data" % ( var_list, inputfile)) else: @@ -2616,6 +2624,17 @@ class Interpreter(InterpreterBase): mesonlib.replace_if_different(ofile_abs, dst_tmp) else: raise InterpreterException('Configure_file must have either "configuration" or "command".') + # If the input is a source file, add it to the list of files that we + # need to reconfigure on when they change. FIXME: Do the same for + # files() objects in the command: kwarg. + if inputfile and not inputfile.is_built: + # Normalize the path of the conffile (relative to the + # source root) to avoid duplicates. This is especially + # important to convert '/' to '\' on Windows + conffile = os.path.normpath(inputfile.relative_name()) + if conffile not in self.build_def_files: + self.build_def_files.append(conffile) + # Install file if requested idir = kwargs.get('install_dir', None) if isinstance(idir, str): cfile = mesonlib.File.from_built_file(ofile_path, ofile_fname) @@ -2769,7 +2788,7 @@ different subdirectory. results = [] for s in sources: if isinstance(s, (mesonlib.File, GeneratedListHolder, - CustomTargetHolder)): + CustomTargetHolder, CustomTargetIndexHolder)): pass elif isinstance(s, str): s = mesonlib.File.from_source_file(self.environment.source_dir, self.subdir, s) diff --git a/mesonbuild/interpreterbase.py b/mesonbuild/interpreterbase.py index d2e2ab3..cb82e56 100644 --- a/mesonbuild/interpreterbase.py +++ b/mesonbuild/interpreterbase.py @@ -369,14 +369,16 @@ class InterpreterBase: def evaluate_indexing(self, node): assert(isinstance(node, mparser.IndexNode)) iobject = self.evaluate_statement(node.iobject) - if not isinstance(iobject, list): - raise InterpreterException('Tried to index a non-array object.') + if not hasattr(iobject, '__getitem__'): + raise InterpreterException( + 'Tried to index an object that doesn\'t support indexing.') index = self.evaluate_statement(node.index) if not isinstance(index, int): raise InterpreterException('Index value is not an integer.') - if index < -len(iobject) or index >= len(iobject): + try: + return iobject[index] + except IndexError: raise InterpreterException('Index %d out of bounds of array of size %d.' % (index, len(iobject))) - return iobject[index] def function_call(self, node): func_name = node.func_name @@ -450,9 +452,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 +481,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..d1d7013 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 @@ -108,12 +107,12 @@ class GnomeModule(ExtensionModule): for (ii, dep) in enumerate(dependencies): if hasattr(dep, 'held_object'): dependencies[ii] = dep = dep.held_object - if not isinstance(dep, (mesonlib.File, build.CustomTarget)): + if not isinstance(dep, (mesonlib.File, build.CustomTarget, build.CustomTargetIndex)): m = 'Unexpected dependency type {!r} for gnome.compile_resources() ' \ '"dependencies" argument.\nPlease pass the return value of ' \ 'custom_target() or configure_file()' raise MesonException(m.format(dep)) - if isinstance(dep, build.CustomTarget): + if isinstance(dep, (build.CustomTarget, build.CustomTargetIndex)): if not mesonlib.version_compare(glib_version, gresource_dep_needed_version): m = 'The "dependencies" argument of gnome.compile_resources() can not\n' \ 'be used with the current version of glib-compile-resources due to\n' \ @@ -132,6 +131,7 @@ class GnomeModule(ExtensionModule): elif isinstance(ifile, str): ifile = os.path.join(state.subdir, ifile) elif isinstance(ifile, (interpreter.CustomTargetHolder, + interpreter.CustomTargetIndexHolder, interpreter.GeneratedObjectsHolder)): m = 'Resource xml files generated at build-time cannot be used ' \ 'with gnome.compile_resources() because we need to scan ' \ @@ -262,7 +262,7 @@ class GnomeModule(ExtensionModule): dep_files.append(dep) subdirs.append(dep.subdir) break - elif isinstance(dep, build.CustomTarget): + elif isinstance(dep, (build.CustomTarget, build.CustomTargetIndex)): fname = None outputs = {(o, os.path.basename(o)) for o in dep.get_outputs()} for o, baseo in outputs: @@ -444,7 +444,7 @@ class GnomeModule(ExtensionModule): for s in libsources: if hasattr(s, 'held_object'): s = s.held_object - if isinstance(s, build.CustomTarget): + if isinstance(s, (build.CustomTarget, build.CustomTargetIndex)): gir_filelist.write(os.path.join(state.environment.get_build_dir(), state.backend.get_target_dir(s), s.get_outputs()[0]) + '\n') @@ -697,18 +697,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/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..81a2f88 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,55 @@ 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) - expected = p.get('patch_hash') - if phash != expected: - 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) + patch_filename = p.get('patch_filename') + filename = os.path.join(self.cachedir, patch_filename) + if os.path.exists(filename): + mlog.log('Using', mlog.bold(patch_filename), 'from cache.') + else: + purl = p.get('patch_url') + mlog.log('Downloading patch from', mlog.bold(purl)) + 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)) + 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 +353,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) diff --git a/mesonrewriter.py b/mesonrewriter.py index 426d878..e6f2637 100755 --- a/mesonrewriter.py +++ b/mesonrewriter.py @@ -23,11 +23,10 @@ # - move targets # - reindent? -from mesonbuild import mesonmain, mlog +from mesonbuild import mesonmain import sys if __name__ == '__main__': print('Warning: This executable is deprecated. Use "meson rewrite" instead.', file=sys.stderr) sys.exit(mesonmain.run(['rewrite'] + sys.argv[1:])) - diff --git a/msi/createmsi.py b/msi/createmsi.py index 13b4081..dd92e50 100755 --- a/msi/createmsi.py +++ b/msi/createmsi.py @@ -56,7 +56,7 @@ class PackageGenerator: 'Title': 'Meson', 'Description': 'Meson executables', 'Level': '1', - 'Absent': 'disallow', + 'Absent': 'disallow', }, self.staging_dirs[1]: { 'Id': 'NinjaProgram', @@ -109,7 +109,7 @@ class PackageGenerator: 'Language': '1033', 'Codepage': '1252', 'Version': self.version, - }) + }) package = ET.SubElement(product, 'Package', { 'Id': '*', @@ -121,7 +121,7 @@ class PackageGenerator: 'Languages': '1033', 'Compressed': 'yes', 'SummaryCodepage': '1252', - }) + }) if self.bytesize == 64: package.set('Platform', 'x64') @@ -129,25 +129,26 @@ class PackageGenerator: 'Id': '1', 'Cabinet': 'meson.cab', 'EmbedCab': 'yes', - }) + }) targetdir = ET.SubElement(product, 'Directory', { 'Id': 'TARGETDIR', 'Name': 'SourceDir', - }) + }) progfiledir = ET.SubElement(targetdir, 'Directory', { - 'Id' : self.progfile_dir, - }) + 'Id': self.progfile_dir, + }) installdir = ET.SubElement(progfiledir, 'Directory', { 'Id': 'INSTALLDIR', - 'Name': 'Meson'}) + 'Name': 'Meson', + }) ET.SubElement(product, 'Property', { 'Id': 'WIXUI_INSTALLDIR', 'Value': 'INSTALLDIR', - }) + }) ET.SubElement(product, 'UIRef', { 'Id': 'WixUI_FeatureTree', - }) + }) for sd in self.staging_dirs: assert(os.path.isdir(sd)) top_feature = ET.SubElement(product, 'Feature', { @@ -157,7 +158,7 @@ class PackageGenerator: 'Display': 'expand', 'Level': '1', 'ConfigurableDirectory': 'INSTALLDIR', - }) + }) for sd in self.staging_dirs: nodes = {} for root, dirs, files in os.walk(sd): @@ -165,7 +166,7 @@ class PackageGenerator: nodes[root] = cur_node self.create_xml(nodes, sd, installdir, sd) self.build_features(nodes, top_feature, sd) - ET.ElementTree(self.root).write(self.main_xml, encoding='utf-8',xml_declaration=True) + ET.ElementTree(self.root).write(self.main_xml, encoding='utf-8', xml_declaration=True) # ElementTree can not do prettyprinting so do it manually import xml.dom.minidom doc = xml.dom.minidom.parse(self.main_xml) @@ -177,8 +178,7 @@ class PackageGenerator: for component_id in self.feature_components[staging_dir]: ET.SubElement(feature, 'ComponentRef', { 'Id': component_id, - }) - + }) def create_xml(self, nodes, current_dir, parent_xml_node, staging_dir): cur_node = nodes[current_dir] @@ -187,7 +187,7 @@ class PackageGenerator: comp_xml_node = ET.SubElement(parent_xml_node, 'Component', { 'Id': component_id, 'Guid': gen_guid(), - }) + }) self.feature_components[staging_dir].append(component_id) if self.bytesize == 64: comp_xml_node.set('Win64', 'yes') @@ -208,14 +208,14 @@ class PackageGenerator: 'Id': file_id, 'Name': f, 'Source': os.path.join(current_dir, f), - }) + }) for dirname in cur_node.dirs: dir_id = os.path.join(current_dir, dirname).replace('\\', '_').replace('/', '_') dir_node = ET.SubElement(parent_xml_node, 'Directory', { 'Id': dir_id, 'Name': dirname, - }) + }) self.create_xml(nodes, os.path.join(current_dir, dirname), dir_node, staging_dir) def build_package(self): diff --git a/run_project_tests.py b/run_project_tests.py index 71770f3..426e2c7 100755 --- a/run_project_tests.py +++ b/run_project_tests.py @@ -585,7 +585,7 @@ def check_file(fname): with open(fname, 'rb') as f: lines = f.readlines() for line in lines: - if b'\t' in line: + if line.startswith(b'\t'): print("File %s contains a literal tab on line %d. Only spaces are permitted." % (fname, linenum)) sys.exit(1) if b'\r' in line: diff --git a/run_unittests.py b/run_unittests.py index 2626931..b217714 100755 --- a/run_unittests.py +++ b/run_unittests.py @@ -1946,7 +1946,7 @@ cpu = 'armv7' # Not sure if correct. endian = 'little' ''' % os.path.join(testdir, 'some_cross_tool.py')) crossfile.flush() - self.init(testdir, ['--cross-file='+crossfile.name]) + self.init(testdir, ['--cross-file=' + crossfile.name]) def test_reconfigure(self): testdir = os.path.join(self.unit_test_dir, '13 reconfigure') @@ -14,8 +14,10 @@ ignore = E305, # E401: multiple imports on one line E401, - # too many leading '#' for block comment + # E266: too many leading '#' for block comment E266, - # module level import not at top of file - E402 + # E402: module level import not at top of file + E402, + # E731: do not assign a lambda expression, use a def (too many false positives) + E731 max-line-length = 120 diff --git a/test cases/common/114 multiple dir configure file/meson.build b/test cases/common/114 multiple dir configure file/meson.build index 180227c..c76c6b4 100644 --- a/test cases/common/114 multiple dir configure file/meson.build +++ b/test cases/common/114 multiple dir configure file/meson.build @@ -5,3 +5,7 @@ subdir('subdir') configure_file(input : 'subdir/someinput.in', output : 'outputhere', configuration : configuration_data()) + +configure_file(input : cfile1, + output : '@BASENAME@', + configuration : configuration_data()) diff --git a/test cases/common/114 multiple dir configure file/subdir/foo.txt b/test cases/common/114 multiple dir configure file/subdir/foo.txt new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test cases/common/114 multiple dir configure file/subdir/foo.txt diff --git a/test cases/common/114 multiple dir configure file/subdir/meson.build b/test cases/common/114 multiple dir configure file/subdir/meson.build index a8f731d..9c72bf9 100644 --- a/test cases/common/114 multiple dir configure file/subdir/meson.build +++ b/test cases/common/114 multiple dir configure file/subdir/meson.build @@ -2,3 +2,10 @@ configure_file(input : 'someinput.in', output : 'outputsubdir', install : false, configuration : configuration_data()) + +py3 = import('python3').find_python() + +cfile1 = configure_file(input : 'foo.txt', + output : 'foo.h.in', + capture : true, + command : [py3, '-c', 'print("#mesondefine FOO_BAR")']) diff --git a/test cases/common/147 mesonintrospect from scripts/check_env.py b/test cases/common/147 mesonintrospect from scripts/check_env.py index 9bd64d7..2d46d88 100644 --- a/test cases/common/147 mesonintrospect from scripts/check_env.py +++ b/test cases/common/147 mesonintrospect from scripts/check_env.py @@ -16,8 +16,8 @@ mesonintrospect = os.environ['MESONINTROSPECT'] introspect_arr = shlex.split(mesonintrospect) -#print(mesonintrospect) -#print(introspect_arr) +# print(mesonintrospect) +# print(introspect_arr) some_executable = introspect_arr[0] diff --git a/test cases/common/161 index customtarget/gen_sources.py b/test cases/common/161 index customtarget/gen_sources.py new file mode 100644 index 0000000..0bdb529 --- /dev/null +++ b/test cases/common/161 index customtarget/gen_sources.py @@ -0,0 +1,49 @@ +# Copyright © 2017 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import argparse +import textwrap + +HEADER = textwrap.dedent('''\ + void stringify(int foo, char * buffer); + ''') + +CODE = textwrap.dedent('''\ + #include <stdio.h> + + #ifndef WORKS + # error "This shouldn't have been included" + #endif + + void stringify(int foo, char * buffer) { + sprintf(buffer, "%i", foo); + } + ''') + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument('--header') + parser.add_argument('--code') + args = parser.parse_args() + + with open(args.header, 'w') as f: + f.write(HEADER) + + with open(args.code, 'w') as f: + f.write(CODE) + + +if __name__ == '__main__': + main() diff --git a/test cases/common/161 index customtarget/lib.c b/test cases/common/161 index customtarget/lib.c new file mode 100644 index 0000000..17117d5 --- /dev/null +++ b/test cases/common/161 index customtarget/lib.c @@ -0,0 +1,20 @@ +/* Copyright © 2017 Intel Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "gen.h" + +void func(char * buffer) { + stringify(1, buffer); +} diff --git a/test cases/common/161 index customtarget/meson.build b/test cases/common/161 index customtarget/meson.build new file mode 100644 index 0000000..11cb214 --- /dev/null +++ b/test cases/common/161 index customtarget/meson.build @@ -0,0 +1,32 @@ +# Copyright © 2017 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +project('custom_target_index', 'c', default_options : 'c_std=c89') + +py_mod = import('python3') +prog_python = py_mod.find_python() + +gen = custom_target( + 'gen.[ch]', + input : 'gen_sources.py', + output : ['gen.c', 'gen.h'], + command : [prog_python, '@INPUT@', '--header', '@OUTPUT1@', '--code', '@OUTPUT0@'], +) + +lib = static_library( + 'libfoo', + ['lib.c', gen[1]], +) + +subdir('subdir') diff --git a/test cases/common/161 index customtarget/subdir/foo.c b/test cases/common/161 index customtarget/subdir/foo.c new file mode 100644 index 0000000..c620a11 --- /dev/null +++ b/test cases/common/161 index customtarget/subdir/foo.c @@ -0,0 +1,22 @@ +/* Copyright © 2017 Intel Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "gen.h" + +int main(void) { + char buf[50]; + stringify(10, buf); + return 0; +} diff --git a/test cases/common/161 index customtarget/subdir/meson.build b/test cases/common/161 index customtarget/subdir/meson.build new file mode 100644 index 0000000..47bcd32 --- /dev/null +++ b/test cases/common/161 index customtarget/subdir/meson.build @@ -0,0 +1,19 @@ +# Copyright © 2017 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +foo = executable( + 'foo', + ['foo.c', gen[0], gen[1]], + c_args : '-DWORKS', +) diff --git a/test cases/common/42 string operations/meson.build b/test cases/common/42 string operations/meson.build index 5d7a73d..d9f8130 100644 --- a/test cases/common/42 string operations/meson.build +++ b/test cases/common/42 string operations/meson.build @@ -67,3 +67,10 @@ assert(not version_number.version_compare('!=1.2.8'), 'Version_compare neq broke assert(version_number.version_compare('<2.0'), 'Version_compare major less broken') assert(version_number.version_compare('>0.9'), 'Version_compare major greater broken') + +assert(' spaces tabs '.strip() == 'spaces tabs', 'Spaces and tabs badly stripped') +assert(''' +multiline string '''.strip() == '''multiline string''', 'Newlines badly stripped') +assert('"1.1.20"'.strip('"') == '1.1.20', '" badly stripped') +assert('"1.1.20"'.strip('".') == '1.1.20', '". badly stripped') +assert('"1.1.20" '.strip('" ') == '1.1.20', '". badly stripped') diff --git a/test cases/common/98 gen extra/meson.build b/test cases/common/98 gen extra/meson.build index 772f52e..cbbdceb 100644 --- a/test cases/common/98 gen extra/meson.build +++ b/test cases/common/98 gen extra/meson.build @@ -28,3 +28,13 @@ plainname_gen = generator(prog2, plainname_src = plainname_gen.process('name.l') test('plainname', executable('plainname', plainname_src)) + +prog3 = find_program('srcgen3.py') +capture_gen = generator(prog3, + output : ['@BASENAME@.yy.c'], + arguments : ['@INPUT@'], + capture : true) + +capture_src = capture_gen.process('name.l') + +test('capture', executable('capture', capture_src)) diff --git a/test cases/common/98 gen extra/srcgen3.py b/test cases/common/98 gen extra/srcgen3.py new file mode 100644 index 0000000..ad0a5cb --- /dev/null +++ b/test cases/common/98 gen extra/srcgen3.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python3 + +import os +import sys +import argparse + +parser = argparse.ArgumentParser() +parser.add_argument('input', + help='the input file') + +options = parser.parse_args(sys.argv[1:]) + +with open(options.input) as f: + content = f.read().strip() + +print(content) diff --git a/test cases/failing/60 assign custom target index/meson.build b/test cases/failing/60 assign custom target index/meson.build new file mode 100644 index 0000000..7f2a820 --- /dev/null +++ b/test cases/failing/60 assign custom target index/meson.build @@ -0,0 +1,24 @@ +# Copyright © 2017 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +prog_python = import('python3').find_python() + +target = custom_target( + 'target', + output : ['1', '2'], + command : [prog_python, '-c', + 'with open("1", "w") as f: f.write("foo"); with open("2", "w") as f: f.write("foo")'], +) + +target[0] = 'foo' diff --git a/test cases/frameworks/15 llvm/meson.build b/test cases/frameworks/15 llvm/meson.build index af7f8c6..e1d97cb 100644 --- a/test cases/frameworks/15 llvm/meson.build +++ b/test cases/frameworks/15 llvm/meson.build @@ -10,8 +10,7 @@ llvm_dep = dependency( d = dependency('llvm', modules : 'not-found', required : false) assert(d.found() == false, 'not-found llvm module found') -# XXX: Version checks are broken, see FIXME in LLVMDependency -#d = dependency('llvm', version : '<0.1', required : false) -#assert(d.found() == false, 'ancient llvm module found') +d = dependency('llvm', version : '<0.1', required : false) +assert(d.found() == false, 'ancient llvm module found') executable('sum', 'sum.c', dependencies : llvm_dep) diff --git a/test cases/frameworks/19 pcap/meson.build b/test cases/frameworks/19 pcap/meson.build index 909d7cd..c505960 100644 --- a/test cases/frameworks/19 pcap/meson.build +++ b/test cases/frameworks/19 pcap/meson.build @@ -2,6 +2,9 @@ project('pcap test', 'c') pcap_dep = dependency('pcap', version : '>=1.0') +pcap_ver = pcap_dep.version() +assert(pcap_ver.split('.').length() > 1, 'pcap version is "@0@"'.format(pcap_ver)) + e = executable('pcap_prog', 'pcap_prog.c', dependencies : pcap_dep) test('pcaptest', e) |