partitioned_shared_library.gni (6324B)
1 # Copyright 2019 The Chromium Authors 2 3 # Use of this source code is governed by a BSD-style license that can be 4 # found in the LICENSE file. 5 6 import("//chromium/build/config/android/config.gni") 7 import("//chromium/build/config/clang/clang.gni") 8 import("//chromium/build/config/compiler/compiler.gni") 9 if (build_with_chromium) { 10 import("//third_party/jni_zero/jni_zero.gni") 11 } 12 13 # This template creates a set of shared libraries, by linking a single 14 # "partitioned" shared library, then splitting it into multiple pieces. 15 # The intention is to facilitate code-splitting between a base library and 16 # additional feature-specific libraries that may be obtained and loaded at a 17 # later time. 18 # 19 # The combined library is an intermediate product made by leveraging the LLVM 20 # toolchain. Code modules may be labeled via compiler flag as belonging to a 21 # particular partition. At link time, any symbols reachable by only a single 22 # partition's entrypoints will be located in a partition-specific library 23 # segment. After linking, the segments are split apart using objcopy into 24 # separate libraries. The main library is then packaged with the application 25 # as usual, while feature libraries may be packaged, delivered and loaded 26 # separately (via an Android Dynamic Feature Module). 27 # 28 # When loading a feature library, the intended address of the library must be 29 # supplied to the loader, so that it can be mapped to the memory location. The 30 # address offsets of the feature libraries are stored in the base library and 31 # accessed through special symbols named according to the partitions. 32 # 33 # The template instantiates targets for the base library, as well as each 34 # specified partition, based on the root target name. Example: 35 # 36 # - libmonochrome (base library) 37 # - libmonochrome_foo (partition library for feature 'foo') 38 # - libmonochrome_bar (partition library for feature 'bar') 39 # 40 # Note that the feature library filenames are chosen based on the main 41 # library's name (eg. libmonochrome_foo.so), but the soname of the feature 42 # library is based on the feature name (eg. "foo"). This should generally be 43 # okay, with the caveat that loading the library multiple times *might* cause 44 # problems in Android. 45 # 46 # This template uses shared_library's default configurations. 47 # 48 # Variables: 49 # partitions: A list of library partition names to extract, in addition to 50 # the base library. 51 52 template("partitioned_shared_library") { 53 assert(is_clang) 54 forward_variables_from(invoker, [ "testonly" ]) 55 56 _combined_library_target = "${target_name}__combined" 57 58 # Strip "lib" from target names; it will be re-added to output libraries. 59 _output_name = string_replace(target_name, "lib", "") 60 61 shared_library(_combined_library_target) { 62 forward_variables_from(invoker, "*", [ "partitions" ]) 63 if (!defined(ldflags)) { 64 ldflags = [] 65 } 66 ldflags += [ 67 "-Wl,-soname,lib${_output_name}.so", 68 "--partitioned-library", 69 ] 70 71 # This shared library is an intermediate artifact that should not packaged 72 # into the final build. Therefore, reset metadata. 73 metadata = { 74 } 75 } 76 77 template("partition_action") { 78 action(target_name) { 79 deps = [ ":$_combined_library_target" ] 80 script = "//chromium/build/extract_partition.py" 81 sources = 82 [ "$root_out_dir/lib.unstripped/lib${_output_name}__combined.so" ] 83 outputs = [ 84 invoker.unstripped_output, 85 invoker.stripped_output, 86 ] 87 data = [ invoker.unstripped_output ] 88 metadata = { 89 shared_libraries = [ invoker.stripped_output ] 90 } 91 args = [ 92 "--objcopy", 93 rebase_path("$clang_base_path/bin/llvm-objcopy", root_build_dir), 94 "--unstripped-output", 95 rebase_path(invoker.unstripped_output, root_build_dir), 96 "--stripped-output", 97 rebase_path(invoker.stripped_output, root_build_dir), 98 ] 99 if (defined(invoker.partition) && invoker.partition != "") { 100 args += [ 101 "--partition", 102 "${invoker.partition}", 103 ] 104 } 105 106 if (use_debug_fission) { 107 args += [ "--split-dwarf" ] 108 outputs += [ invoker.unstripped_output + ".dwp" ] 109 } 110 args += [ rebase_path(sources[0], root_build_dir) ] 111 } 112 } 113 114 partition_action(target_name) { 115 stripped_output = "$root_out_dir/lib${_output_name}.so" 116 unstripped_output = "$root_out_dir/lib.unstripped/lib${_output_name}.so" 117 } 118 119 # Note that as of now, non-base partition libraries are placed in a 120 # subdirectory of the root output directory. This is because partition 121 # sonames are not sensitive to the filename of the base library, and as such, 122 # their corresponding file names may be generated multiple times by different 123 # base libraries. To avoid collisions, each base library target has a 124 # corresponding subdir for its extra partitions. 125 # 126 # If this proves problematic to various pieces of infrastructure, a proposed 127 # alternative is allowing the linker to rename partitions. For example, 128 # feature "foo" may be a partition. If two different base libraries both 129 # define "foo" partitions, the linker may be made to accept an extra command 130 # to rename the partition's soname to "foo1" or "foo2". Other build config 131 # can name the libraries foo1.so and foo2.so, allowing them to reside in the 132 # same directory. 133 foreach(_partition, invoker.partitions) { 134 partition_action("${target_name}_${_partition}") { 135 partition = "${_partition}_partition" 136 stripped_output = "$root_out_dir/lib${_output_name}_${partition}.so" 137 unstripped_output = 138 "$root_out_dir/lib.unstripped/lib${_output_name}_${partition}.so" 139 } 140 } 141 } 142 143 set_defaults("partitioned_shared_library") { 144 configs = default_shared_library_configs 145 } 146 147 # native_with_jni for partitioned shared libraries - see native_with_jni for 148 # details. 149 template("partitioned_shared_library_with_jni") { 150 native_with_jni(target_name) { 151 forward_variables_from(invoker, "*", TESTONLY_AND_VISIBILITY) 152 forward_variables_from(invoker, TESTONLY_AND_VISIBILITY) 153 target_type = "partitioned_shared_library" 154 target_type_import = "//chromium/build/partitioned_shared_library.gni" 155 } 156 } 157 set_defaults("partitioned_shared_library_with_jni") { 158 configs = default_shared_library_configs 159 }