Add pw_input_group GN template
This change defines a template that allows listing input file
dependencies in a build target that does not output anything. This code
code was previously inlined in pw_docgen but is extracted into a general
template for use elsewhere.
The pw_build module docs are expanded to describe the GN templates
provided by the module.
Change-Id: I5f2624c792dccb47c379727285f22f05eb05dfdf
diff --git a/pw_build/docs.rst b/pw_build/docs.rst
index acea1c5..e25076a 100644
--- a/pw_build/docs.rst
+++ b/pw_build/docs.rst
@@ -20,9 +20,111 @@
It contains ``config`` declarations referenced by ``BUILD.gn`` files in other
modules.
-The ``pw_executable.gni`` file contains a wrapper to build a target for the
-globally-defined target type, and ``python_script.gni`` makes it easy to run
-Python scripts as part of build rules.
+The module also provides some useful GN templates for build targets.
+
+Templates
+---------
+
+pw_executable
+^^^^^^^^^^^^^
+.. code::
+
+ import("$dir_pw_build/pw_executable.gni")
+
+The ``pw_executable`` template is a wrapper around executable targets which
+builds for a globally-defined target type. This is controlled by the build
+variable ``pw_executable_config.target_type``. For example, setting this
+variable to ``stm32f429i_executable`` causes all executable targets to build
+using that template.
+
+.. tip::
+
+ Prefer to use ``pw_executable`` over plain ``executable`` targets to allow
+ cleanly building the same code for multiple target configs.
+
+**Arguments**
+
+``pw_executable`` accepts any arguments, as it simply forwards them through to
+the specified custom template.
+
+pw_python_script
+^^^^^^^^^^^^^^^^
+The ``pw_python_script`` template is a convenience wrapper around ``action`` for
+running Python scripts. The main benefit it provides is automatic resolution of
+GN paths to filesystem paths and GN target names to compiled binary files. This
+allows Python scripts to be written independent of GN, taking only filesystem as
+arguments.
+
+Another convenience provided by the template is to allow running scripts without
+any outputs. Sometimes scripts run in a build do not directly produce output
+files, but GN requires that all actions have an output. ``pw_python_script``
+solves this by accepting a boolean ``stamp`` argument which tells it to create a
+dummy output file for the action.
+
+**Arguments**
+
+``pw_python_script`` accepts all of the arguments of a regular ``action``
+target. Additionally, it has some of its own arguments:
+
+* ``stamp``: Optional boolean indicating whether to automatically create a dummy
+ output file for the script. This allows running scripts without specifying any
+ ``outputs``.
+
+**Example**
+
+.. code::
+
+ import("$dir_pw_build/python_script.gni")
+
+ python_script("hello_world") {
+ script = "py/say_hello.py"
+ args = [ "world" ]
+ stamp = true
+ }
+
+pw_input_group
+^^^^^^^^^^^^^^
+``pw_input_group`` defines a group of input files which are not directly
+processed by the build but are still important dependencies of later build
+steps. This is commonly used alongside metadata to propagate file dependencies
+through the build graph and force rebuilds on file modifications.
+
+For example ``pw_docgen`` defines a ``pw_doc_group`` template which outputs
+metadata from a list of input files. The metadata file is not actually part of
+the build, and so changes to any of the input files do not trigger a rebuild.
+This is problematic, as targets that depend on the metadata should rebuild when
+the inputs are modified but GN cannot express this dependency.
+
+``pw_input_group`` solves this problem by allowing a list of files to be listed
+in a target that does not output any build artifacts, causing all dependent
+targets to correctly rebuild.
+
+**Arguments**
+
+``pw_input_group`` accepts all arguments that can be passed to a ``group``
+target, as well as requiring one extra:
+
+* ``inputs``: List of input files.
+
+**Example**
+
+.. code::
+
+ import("$dir_pw_build/input_group.gni")
+
+ pw_input_group("foo_metadata") {
+ metadata = {
+ files = [
+ "x.foo",
+ "y.foo",
+ "z.foo",
+ ]
+ }
+ inputs = metadata.files
+ }
+
+Targets depending on ``foo_metadata`` will rebuild when any of the ``.foo``
+files are modified.
Bazel
=====
diff --git a/pw_build/input_group.gni b/pw_build/input_group.gni
new file mode 100644
index 0000000..b1cfd3f
--- /dev/null
+++ b/pw_build/input_group.gni
@@ -0,0 +1,36 @@
+# Copyright 2019 The Pigweed Authors
+#
+# 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
+#
+# https://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("python_script.gni")
+
+# Creates an action that doesn't do anything that depends on a list of input
+# files. This allows modifications to these files to trigger targets depending
+# on this group to rebuild.
+#
+# This is typically used for targets that don't output any artifacts (e.g.
+# metadata-only targets) which list input files relevant to the build.
+template("pw_input_group") {
+ assert(defined(invoker.inputs), "pw_input_group requires some inputs")
+
+ pw_python_script(target_name) {
+ ignore_vars = [
+ "args",
+ "script",
+ "stamp",
+ ]
+ forward_variables_from(invoker, "*", ignore_vars)
+ script = "$dir_pw_build/py/nop.py"
+ stamp = true
+ }
+}
diff --git a/pw_docgen/docs.gni b/pw_docgen/docs.gni
index 34af772..34a1a04 100644
--- a/pw_docgen/docs.gni
+++ b/pw_docgen/docs.gni
@@ -12,6 +12,7 @@
# License for the specific language governing permissions and limitations under
# the License.
+import("$dir_pw_build/input_group.gni")
import("$dir_pw_build/python_script.gni")
# Defines a group of documentation files and assets.
@@ -38,17 +39,15 @@
_all_deps += invoker.report_deps
}
- # Creates an action which depends on all of the source and input files so that
- # docs are rebuilt on file modifications. The action does not do anything.
- pw_python_script(target_name) {
+ # Create a group containing the source and input files so that docs are
+ # rebuilt on file modifications.
+ pw_input_group(target_name) {
metadata = {
pw_doc_sources = rebase_path(invoker.sources, root_build_dir)
pw_doc_inputs = rebase_path(_inputs, root_build_dir)
}
deps = _all_deps
- script = "$dir_pw_build/py/nop.py"
inputs = invoker.sources + _inputs
- stamp = true
}
}