summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDylan Baker <dylan@pnwbakers.com>2017-09-25 13:46:07 -0700
committerJussi Pakkanen <jpakkane@gmail.com>2017-09-27 22:01:24 +0300
commitdda5e8cadbfdeee3267b1a0943c014e06bcd0100 (patch)
tree049a70c550729d722e23c67d8312c2eaa820da6f
parentdfc2b75ee2dba3245ac23bb3d7f0156e47773ed5 (diff)
downloadmeson-dda5e8cadbfdeee3267b1a0943c014e06bcd0100.tar.gz
Allow CustomTarget's to be indexed
This allows a CustomTarget to be indexed, and the resulting indexed value (a CustomTargetIndex type), to be used as a source in other targets. This will confer a dependency on the original target, but only inserts the source file returning by index the original target's outputs. This can allow a CustomTarget that creates both a header and a code file to have it's outputs split, for example. Fixes #1470
-rw-r--r--docs/markdown/Reference-manual.md5
-rw-r--r--docs/markdown/snippets/custom-target-index.md21
-rw-r--r--mesonbuild/backend/backends.py2
-rw-r--r--mesonbuild/backend/ninjabackend.py11
-rw-r--r--mesonbuild/backend/vs2010backend.py4
-rw-r--r--mesonbuild/build.py34
-rw-r--r--mesonbuild/interpreter.py16
-rw-r--r--mesonbuild/interpreterbase.py10
-rw-r--r--mesonbuild/modules/gnome.py9
-rw-r--r--test cases/common/161 index customtarget/gen_sources.py49
-rw-r--r--test cases/common/161 index customtarget/lib.c20
-rw-r--r--test cases/common/161 index customtarget/meson.build32
-rw-r--r--test cases/common/161 index customtarget/subdir/foo.c22
-rw-r--r--test cases/common/161 index customtarget/subdir/meson.build19
-rw-r--r--test cases/failing/60 assign custom target index/meson.build24
15 files changed, 261 insertions, 17 deletions
diff --git a/docs/markdown/Reference-manual.md b/docs/markdown/Reference-manual.md
index 7aa4bcad8..c3636b89a 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 000000000..10d7cf155
--- /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 97959b603..12fb3ebf7 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 41b93cbf7..d2ba49f9e 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 22c1779f6..cb8dad612 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 c54abbd42..d3c0b54df 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 2148bedb7..012370de2 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 1dd2f0212..cb82e5604 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 1ab075bd2..d1d7013d3 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 000000000..0bdb529cd
--- /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 000000000..17117d54c
--- /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 000000000..11cb214b2
--- /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 000000000..c620a1183
--- /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 000000000..47bcd322a
--- /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 000000000..7f2a820b8
--- /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'