| # Copyright 2022 The Fuchsia Authors | 
 | # | 
 | # Use of this source code is governed by a MIT-style | 
 | # license that can be found in the LICENSE file or at | 
 | # https://opensource.org/licenses/MIT | 
 |  | 
 | import("//build/zircon/c_utils.gni") | 
 |  | 
 | # Provide an ELF executable() or loadable_module() target with a PT_INTERP | 
 | # string based on the build ID of another linking target. | 
 | # | 
 | # This defines a link-input target (as in source_set() et al) that can | 
 | # be included in $deps of executable() and similar targets.  Doing so | 
 | # gives that executable a PT_INTERP value of the build ID, in canonical | 
 | # hex textual form, of whatever executable-like target was reached by | 
 | # this target's $deps. | 
 | # | 
 | # Parameters | 
 | # | 
 | #   * deps | 
 | #     - Required: Must reach exactly one linking target (executable, etc.) as | 
 | #       per link_output_rspfile(), which see.  That executable's build ID | 
 | #       rendered as hex text will become the PT_INTERP string used if an | 
 | #       executable links in $target_name via its transitive $deps. | 
 | #     - Type: list(label) | 
 | # | 
 | #   * data_deps, metadata, visibility, testonly | 
 | #     - Optional: As for source_set(). | 
 | # | 
 | template("kernel_elf_interp") { | 
 |   main_target = target_name | 
 |   inc_target = "$target_name.incbin.inc" | 
 |   inc_label = ":$inc_target" | 
 |   gen_dir = get_label_info(inc_label, "target_gen_dir") | 
 |   elf_interp_inc_file = "$target_name.elf-interp.inc" | 
 |   elf_interp_inc = "$gen_dir/$elf_interp_inc_file" | 
 |  | 
 |   # Assemble a tiny file that defines an allocated `.interp` section. | 
 |   source_set(main_target) { | 
 |     forward_variables_from(invoker, | 
 |                            [ | 
 |                              "data_deps", | 
 |                              "metadata", | 
 |                              "visibility", | 
 |                              "testonly", | 
 |                            ]) | 
 |     sources = [ "//zircon/kernel/phys/elf-interp.S" ] | 
 |     defines = [ "ELF_INTERP_INC=\"$elf_interp_inc_file\"" ] | 
 |     include_dirs = [ gen_dir ] | 
 |     inputs = [ elf_interp_inc ] | 
 |     deps = [ inc_label ] | 
 |   } | 
 |  | 
 |   # Generate a file containing `.incbin "FILENAME"` to be used in the assembly. | 
 |   # The source_set() depends on this so that elf-interp.S can #include the file | 
 |   # in a fresh build, though since it's an #include the depfiles from the doing | 
 |   # the assembly will track that (redundantly).  However, those depfiles are | 
 |   # only from the compiler driver doing the preprocessing; the assembler itself | 
 |   # doesn't emit any depfile information about the `.incbin` use of the input | 
 |   # file.  So to ensure that the assembler step is repeated when *that* file | 
 |   # changes, we unconditionally update this generated one-liner file whenever | 
 |   # the file `.incbin` will make the assembler read was touched.  This happens | 
 |   # only implicitly via the depfile that the script writes, since we don't know | 
 |   # what that actual file name is until we derive it from the rspfile below. | 
 |   # What we use is the .stamp file that buildidtool writes.  This has a name | 
 |   # that's the same as the link_ouptut_path plus ".build-id.stamp" and is an | 
 |   # implicit output of the linking step.  GN doesn't really care that this | 
 |   # output file exists, but GN tells Ninja about it being an output of the link | 
 |   # step.  That's enough for Ninja to ingest a depfile that refers to it and | 
 |   # ensure that the next incremental build will regenerate $elf_interp_inc when | 
 |   # and only when the $deps linking target was actually relinked. | 
 |   # | 
 |   # **NOTE:** This generation has to be evaluated separately in each toolchain | 
 |   # because there's no other way to be sure that the `deps` list is resolved to | 
 |   # the intended toolchain.  Even if it used explicit toolchain labels, then | 
 |   # those would be generated using `$current_cpu` and the like, which gets | 
 |   # re-evaluated in a toolchain redirect and e.g. in $default_toolchain might | 
 |   # not be the same CPU that a particular kernel or phys toolchain is using. | 
 |  | 
 |   rspfile_target = "$target_name.interp.rspfile" | 
 |   interp_rspfile = "$target_gen_dir/$target_name.elf-interp.rspfile" | 
 |  | 
 |   action(inc_target) { | 
 |     visibility = [ ":$main_target" ] | 
 |     forward_variables_from(invoker, [ "testonly" ]) | 
 |  | 
 |     script = "//zircon/kernel/phys/kernel-elf-interp.sh" | 
 |     sources = [ interp_rspfile ] | 
 |     deps = [ ":$rspfile_target" ] | 
 |     outputs = [ elf_interp_inc ] | 
 |     depfile = "$elf_interp_inc.d" | 
 |     args = rebase_path(sources + outputs + [ depfile ], root_build_dir) | 
 |  | 
 |     metadata = { | 
 |       # Don't propagate from zbi_input()-compatible or resource() targets. | 
 |       zbi_input_barrier = [] | 
 |       distribution_entries_barrier = [] | 
 |     } | 
 |   } | 
 |  | 
 |   # Before all else, we need an rspfile that shows the file name that the | 
 |   # link step wrote.  The handy template generates an rspfile that contains | 
 |   # the name of the main output file.  The buildidtool file we need has a | 
 |   # name that can be derived from this file name. | 
 |   link_output_rspfile(rspfile_target) { | 
 |     visibility = [ ":$inc_target" ] | 
 |     forward_variables_from(invoker, | 
 |                            [ | 
 |                              "deps", | 
 |                              "testonly", | 
 |                            ]) | 
 |     outputs = [ interp_rspfile ] | 
 |   } | 
 | } |