partitioned_shared_library.gni 5.6 KB

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