diff options
-rw-r--r-- | docs/markdown/Reference-manual.md | 5 | ||||
-rw-r--r-- | docs/markdown/snippets/custom-target-index.md | 21 | ||||
-rw-r--r-- | mesonbuild/backend/backends.py | 2 | ||||
-rw-r--r-- | mesonbuild/backend/ninjabackend.py | 11 | ||||
-rw-r--r-- | mesonbuild/backend/vs2010backend.py | 4 | ||||
-rw-r--r-- | mesonbuild/build.py | 34 | ||||
-rw-r--r-- | mesonbuild/interpreter.py | 16 | ||||
-rw-r--r-- | mesonbuild/interpreterbase.py | 10 | ||||
-rw-r--r-- | mesonbuild/modules/gnome.py | 9 | ||||
-rw-r--r-- | test cases/common/161 index customtarget/gen_sources.py | 49 | ||||
-rw-r--r-- | test cases/common/161 index customtarget/lib.c | 20 | ||||
-rw-r--r-- | test cases/common/161 index customtarget/meson.build | 32 | ||||
-rw-r--r-- | test cases/common/161 index customtarget/subdir/foo.c | 22 | ||||
-rw-r--r-- | test cases/common/161 index customtarget/subdir/meson.build | 19 | ||||
-rw-r--r-- | test cases/failing/60 assign custom target index/meson.build | 24 |
15 files changed, 261 insertions, 17 deletions
diff --git a/docs/markdown/Reference-manual.md b/docs/markdown/Reference-manual.md index 7aa4bca..c3636b8 100644 --- a/docs/markdown/Reference-manual.md +++ b/docs/markdown/Reference-manual.md @@ -1567,6 +1567,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/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 97959b6..12fb3eb 100644 --- a/mesonbuild/backend/backends.py +++ b/mesonbuild/backend/backends.py @@ -174,7 +174,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 41b93cb..d2ba49f 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -245,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): @@ -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) @@ -2013,7 +2014,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: diff --git a/mesonbuild/backend/vs2010backend.py b/mesonbuild/backend/vs2010backend.py index 22c1779..cb8dad6 100644 --- a/mesonbuild/backend/vs2010backend.py +++ b/mesonbuild/backend/vs2010backend.py @@ -91,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) @@ -201,6 +201,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): diff --git a/mesonbuild/build.py b/mesonbuild/build.py index c54abbd..d3c0b54 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) @@ -1676,6 +1676,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 +1744,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/interpreter.py b/mesonbuild/interpreter.py index 2148bed..012370d 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__() @@ -2774,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 1dd2f02..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 diff --git a/mesonbuild/modules/gnome.py b/mesonbuild/modules/gnome.py index 1ab075b..d1d7013 100644 --- a/mesonbuild/modules/gnome.py +++ b/mesonbuild/modules/gnome.py @@ -107,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' \ @@ -131,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 ' \ @@ -261,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: @@ -443,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') 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/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' |