1# Copyright (C) 2021 The Android Open Source Project 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15load("@bazel_skylib//lib:paths.bzl", "paths") 16 17# A rule to generate files based on provided srcs and tools 18def _gensrcs_impl(ctx): 19 # The next two assignments can be created by using ctx.resolve_command 20 # TODO: Switch to using ctx.resolve_command when it is out of experimental 21 command = ctx.expand_location(ctx.attr.cmd, targets = ctx.attr.data) 22 tools = [ 23 tool[DefaultInfo].files_to_run 24 for tool in ctx.attr.tools 25 ] 26 27 command = command.replace( 28 "$(RULEDIR)", 29 paths.join( 30 ctx.var["GENDIR"], 31 ctx.label.package, 32 ), 33 ) 34 35 in_files = ctx.files.srcs 36 out_files = [] 37 for in_file in in_files: 38 # <path-to-in_file>/out_file 39 # where path-to-in_file is relative to the workspace 40 out_file_path = paths.join( 41 paths.dirname(in_file.short_path), 42 paths.replace_extension( 43 in_file.basename, 44 "." + ctx.attr.output_extension, 45 ), 46 ) 47 48 # out_file is at output_file_path that is relative to <GENDIR>/<package-dir> 49 # Hence, the fullpath to out_file is 50 # <GENDIR>/<package-dir>/<path-to-in_file>/out_file 51 out_file = ctx.actions.declare_file(out_file_path) 52 shell_command = command \ 53 .replace("$(SRC)", in_file.path) \ 54 .replace("$(OUT)", out_file.path) 55 ctx.actions.run_shell( 56 tools = tools, 57 outputs = [out_file], 58 inputs = in_files + ctx.files.data, 59 command = shell_command, 60 progress_message = "Generating %s from %s" % ( 61 out_file.path, 62 in_file.path, 63 ), 64 ) 65 out_files.append(out_file) 66 67 return [DefaultInfo( 68 files = depset(out_files), 69 )] 70 71gensrcs = rule( 72 implementation = _gensrcs_impl, 73 doc = "This rule generates files, where each of the `srcs` files is " + 74 "passed into the custom shell command`", 75 attrs = { 76 "srcs": attr.label_list( 77 allow_files = True, 78 mandatory = True, 79 doc = "A list of inputs such as source files to process", 80 ), 81 "output_extension": attr.string( 82 doc = "The extension that will be substituted for output files", 83 ), 84 "cmd": attr.string( 85 mandatory = True, 86 doc = "The command to run. Subject to $(location) expansion. " + 87 "$(IN) represents each input file provided in `srcs` " + 88 "while $(OUT) reprensents corresponding output file " + 89 "generated by the rule. $(RULEDIR) is intepreted the same " + 90 "as it is in genrule.", 91 ), 92 "tools": attr.label_list( 93 allow_files = True, 94 doc = "A list of tool dependencies for this rule. " + 95 "The path of an individual `tools` target //x:y can be " + 96 "obtained using `$(location //x:y)`", 97 cfg = "exec", 98 ), 99 "data": attr.label_list( 100 allow_files = True, 101 doc = "Additional files needed for build that are not tooling " + 102 "related.", 103 ), 104 }, 105) 106