1 # Copyright 2019 The Chromium Authors
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
6 import("//build/config/android/config.gni")
7 import("//build/config/clang/clang.gni")
8 import("//build/config/compiler/compiler.gni")
9 if (build_with_chromium) {
10 import("//third_party/jni_zero/jni_zero.gni")
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
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).
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.
33 # The template instantiates targets for the base library, as well as each
34 # specified partition, based on the root target name. Example:
36 # - libmonochrome (base library)
37 # - libmonochrome_foo (partition library for feature 'foo')
38 # - libmonochrome_bar (partition library for feature 'bar')
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.
46 # This template uses shared_library's default configurations.
49 # partitions: A list of library partition names to extract, in addition to
52 template("partitioned_shared_library") {
54 forward_variables_from(invoker, [ "testonly" ])
56 _combined_library_target = "${target_name}__combined"
58 # Strip "lib" from target names; it will be re-added to output libraries.
59 _output_name = string_replace(target_name, "lib", "")
61 shared_library(_combined_library_target) {
62 forward_variables_from(invoker, "*", [ "partitions" ])
63 if (!defined(ldflags)) {
67 "-Wl,-soname,lib${_output_name}.so",
68 "--partitioned-library",
71 # This shared library is an intermediate artifact that should not packaged
72 # into the final build. Therefore, reset metadata.
77 template("partition_action") {
79 deps = [ ":$_combined_library_target" ]
80 script = "//build/extract_partition.py"
82 [ "$root_out_dir/lib.unstripped/lib${_output_name}__combined.so" ]
84 invoker.unstripped_output,
85 invoker.stripped_output,
87 data = [ invoker.unstripped_output ]
89 shared_libraries = [ invoker.stripped_output ]
93 rebase_path("$clang_base_path/bin/llvm-objcopy", root_build_dir),
94 "--unstripped-output",
95 rebase_path(invoker.unstripped_output, root_build_dir),
97 rebase_path(invoker.stripped_output, root_build_dir),
99 if (defined(invoker.partition) && invoker.partition != "") {
102 "${invoker.partition}",
106 if (use_debug_fission) {
107 args += [ "--split-dwarf" ]
108 outputs += [ invoker.unstripped_output + ".dwp" ]
110 args += [ rebase_path(sources[0], root_build_dir) ]
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"
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.
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
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"
138 "$root_out_dir/lib.unstripped/lib${_output_name}_${partition}.so"
143 set_defaults("partitioned_shared_library") {
144 configs = default_shared_library_configs
147 # native_with_jni for partitioned shared libraries - see native_with_jni for
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 = "//build/partitioned_shared_library.gni"
157 set_defaults("partitioned_shared_library_with_jni") {
158 configs = default_shared_library_configs