1# Copyright (C) 2022 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. 14load("@bazel_skylib//lib:paths.bzl", "paths") 15 16SystemInfo = provider(fields = ["system"]) 17 18def _gen_module_info_java(ctx, jars_to_module_info, jars, module_info): 19 ctx.actions.run_shell( 20 inputs = jars, 21 outputs = [module_info], 22 command = "{} java.base {} > {}".format( 23 jars_to_module_info.path, 24 " ".join([jar.path for jar in jars]), 25 module_info.path, 26 ), 27 tools = [jars_to_module_info], 28 ) 29 30def _gen_module_info_class(ctx, java_runtime, module_info, java_base_patch_jars, module_info_class): 31 ctx.actions.run_shell( 32 inputs = depset([module_info], transitive = [java_base_patch_jars]), 33 outputs = [module_info_class], 34 tools = java_runtime.files, 35 command = "{} -d {} --system=none --patch-module=java.base={} {}".format( 36 paths.join(java_runtime.java_home, "bin", "javac"), 37 module_info_class.dirname, 38 ":".join([jar.path for jar in java_base_patch_jars.to_list()]), 39 module_info.path, 40 ), 41 ) 42 43def _gen_module_info_jar(ctx, soong_zip, module_info_class, module_info_jar): 44 args = ctx.actions.args() 45 args.add("-jar") 46 args.add("--symlinks=false") 47 args.add("-o", module_info_jar) 48 args.add("-C", module_info_class.dirname) 49 args.add("-f", module_info_class) 50 ctx.actions.run( 51 inputs = [module_info_class], 52 outputs = [module_info_jar], 53 arguments = [args], 54 executable = soong_zip, 55 ) 56 57def _gen_merged_module_jar(ctx, merge_zips, module_info_jar, jars, merged_module_jar): 58 args = ctx.actions.args() 59 args.add("-j", merged_module_jar) 60 args.add_all(depset([module_info_jar], transitive = [jars])) 61 ctx.actions.run( 62 inputs = depset([module_info_jar], transitive = [jars]), 63 outputs = [merged_module_jar], 64 arguments = [args], 65 executable = merge_zips, 66 ) 67 68def _gen_jmod(ctx, java_runtime, merged_module_jar, jmod): 69 ctx.actions.run_shell( 70 inputs = [merged_module_jar], 71 outputs = [jmod], 72 tools = java_runtime.files, 73 command = ( 74 "{} create --module-version $({} --version) " + 75 "--target-platform android --class-path {} {}" 76 ).format( 77 paths.join(java_runtime.java_home, "bin", "jmod"), 78 paths.join(java_runtime.java_home, "bin", "jlink"), 79 merged_module_jar.path, 80 jmod.path, 81 ), 82 ) 83 84def _gen_system(ctx, java_runtime, jmod, system): 85 ctx.actions.run_shell( 86 inputs = depset([jmod], transitive = [java_runtime.files]), 87 outputs = [system], 88 tools = java_runtime.files, 89 command = ( 90 "rm -rf {} && " + 91 "{} --module-path {} --add-modules java.base --output {} " + 92 "--disable-plugin system-modules && " + 93 "cp {} {}/lib/" 94 ).format( 95 system.path, 96 paths.join(java_runtime.java_home, "bin", "jlink"), 97 jmod.dirname, 98 system.path, 99 paths.join(java_runtime.java_home, "lib", "jrt-fs.jar"), 100 system.path, 101 ), 102 ) 103 104def _java_system_modules_impl(ctx): 105 java_info = java_common.merge([d[JavaInfo] for d in ctx.attr.deps]) 106 module_info = ctx.actions.declare_file("%s/src/module-info.java" % ctx.label.name) 107 _gen_module_info_java(ctx, ctx.executable._jars_to_module_info, java_info.compile_jars.to_list(), module_info) 108 109 java_runtime = ctx.attr._runtime[java_common.JavaRuntimeInfo] 110 module_info_class = ctx.actions.declare_file("%s/class/module-info.class" % ctx.label.name) 111 _gen_module_info_class(ctx, java_runtime, module_info, java_info.compile_jars, module_info_class) 112 113 module_info_jar = ctx.actions.declare_file("%s/jar/classes.jar" % ctx.label.name) 114 _gen_module_info_jar(ctx, ctx.executable._soong_zip, module_info_class, module_info_jar) 115 116 merged_module_jar = ctx.actions.declare_file("%s/merged/module.jar" % ctx.label.name) 117 _gen_merged_module_jar( 118 ctx, 119 ctx.executable._merge_zips, 120 module_info_jar, 121 java_info.full_compile_jars, 122 merged_module_jar, 123 ) 124 125 jmod = ctx.actions.declare_file("%s/jmod/java.base.jmod" % ctx.label.name) 126 _gen_jmod(ctx, java_runtime, merged_module_jar, jmod) 127 128 system = ctx.actions.declare_directory("%s/system" % ctx.label.name) 129 _gen_system(ctx, java_runtime, jmod, system) 130 131 return [ 132 SystemInfo( 133 system = system, 134 ), 135 DefaultInfo(files = depset([system])), 136 ] 137 138java_system_modules = rule( 139 implementation = _java_system_modules_impl, 140 attrs = { 141 "_jars_to_module_info": attr.label( 142 allow_files = True, 143 executable = True, 144 cfg = "exec", 145 default = "//build/soong/scripts:jars-to-module-info-java", 146 ), 147 "_soong_zip": attr.label( 148 cfg = "exec", 149 allow_single_file = True, 150 doc = "The tool soong_zip", 151 default = "//build/soong/zip/cmd:soong_zip", 152 executable = True, 153 ), 154 "_merge_zips": attr.label( 155 cfg = "exec", 156 allow_single_file = True, 157 doc = "The tool merge_zips.", 158 default = "//prebuilts/build-tools:linux-x86/bin/merge_zips", 159 executable = True, 160 ), 161 "_runtime": attr.label( 162 default = Label("@bazel_tools//tools/jdk:current_java_runtime"), 163 cfg = "exec", 164 providers = [java_common.JavaRuntimeInfo], 165 ), 166 "deps": attr.label_list( 167 providers = [JavaInfo], 168 doc = "Libraries to be converted into a system module directory structure.", 169 ), 170 }, 171 doc = """Generates a system module directory from Java libraries. 172 173Starting from version 1.9, Java requires a subset of java.* classes to be 174provided via system modules. This rule encapsulates the set of steps necessary 175to convert a jar file into the directory structure of system modules. 176""", 177) 178