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 15"""Rule used to import artifacts prebuilt by Soong into the Bazel workspace. 16 17The rule returns a DefaultInfo provider with all artifacts and runtime dependencies, 18and a SoongPrebuiltInfo provider with the original Soong module name and artifacts. 19""" 20 21SoongPrebuiltInfo = provider( 22 doc = "Info about a prebuilt Soong build module", 23 fields = { 24 "files": "Files imported from Soong outputs", 25 "module_name": "Name of the original Soong build module", 26 }, 27) 28 29def _soong_prebuilt_impl(ctx): 30 31 files = ctx.files.files 32 33 # Ensure that soong_prebuilt targets always have at least one file to avoid 34 # evaluation errors when running Bazel cquery on a clean tree to find 35 # dependencies. 36 # 37 # This happens because soong_prebuilt dependency target globs don't match 38 # any files when the workspace symlinks are broken and point to build 39 # artifacts that still don't exist. This in turn causes errors in rules 40 # that reference these targets via attributes with allow_single_file=True 41 # and which expect a file to be present. 42 # 43 # Note that the below action is never really executed during cquery 44 # evaluation but fails when run as part of a test execution to signal that 45 # prebuilts were not correctly imported. 46 if not files: 47 placeholder_file = ctx.actions.declare_file(ctx.label.name + ".missing") 48 49 progress_message = ( 50 "Attempting to import missing artifacts for Soong module '%s'; " + 51 "please make sure that the module is built with Soong before " + 52 "running Bazel" 53 ) % ctx.attr.module_name 54 55 # Note that we don't write the file for the action to always be 56 # executed and display the warning message. 57 ctx.actions.run_shell( 58 outputs=[placeholder_file], 59 command="/bin/false", 60 progress_message=progress_message 61 ) 62 files = [placeholder_file] 63 64 deps = [] 65 deps.extend(ctx.attr.runtime_deps) 66 deps.extend(ctx.attr.data) 67 runfiles = ctx.runfiles(files = files).merge_all([ 68 dep[DefaultInfo].default_runfiles 69 for dep in deps 70 ]) 71 72 return [ 73 SoongPrebuiltInfo( 74 files = depset(files), 75 module_name = ctx.attr.module_name, 76 ), 77 DefaultInfo( 78 files = depset(files), 79 runfiles = runfiles, 80 ), 81 ] 82 83soong_prebuilt = rule( 84 attrs = { 85 "module_name": attr.string(), 86 # Artifacts prebuilt by Soong. 87 "files": attr.label_list(allow_files = True), 88 # Targets that are needed by this target during runtime. 89 "runtime_deps": attr.label_list(), 90 "data": attr.label_list(), 91 }, 92 implementation = _soong_prebuilt_impl, 93 doc = "A rule that imports artifacts prebuilt by Soong into the Bazel workspace", 94) 95 96def _soong_uninstalled_prebuilt_impl(ctx): 97 98 runfiles = ctx.runfiles().merge_all([ 99 dep[DefaultInfo].default_runfiles 100 for dep in ctx.attr.runtime_deps 101 ]) 102 103 return [ 104 SoongPrebuiltInfo( 105 module_name = ctx.attr.module_name, 106 ), 107 DefaultInfo( 108 runfiles = runfiles, 109 ), 110 ] 111 112soong_uninstalled_prebuilt = rule( 113 attrs = { 114 "module_name": attr.string(), 115 "runtime_deps": attr.label_list(), 116 }, 117 implementation = _soong_uninstalled_prebuilt_impl, 118 doc = "A rule for targets with no runtime outputs", 119) 120