1#!/usr/bin/env python
2#
3# Copyright 2014 The Chromium Authors. All rights reserved.
4# Use of this source code is governed by a BSD-style license that can be
5# found in the LICENSE file.
6
7"""Pack ARM relative relocations in a library (or copy unchanged).
8
9If --enable-packing and --configuration-name=='Release', invoke the
10relocation_packer tool to pack the .rel.dyn section in the given library
11files.  This step is inserted after the libraries are stripped.  Packing
12adds a new .android.rel.dyn section to the file and reduces the size of
13.rel.dyn accordingly.
14
15Currently packing only understands ARM32 shared libraries.  For all other
16architectures --enable-packing should be set to zero.  In this case the
17script copies files verbatim, with no attempt to pack relative relocations.
18
19Any library listed in --exclude-packing-list is also copied verbatim,
20irrespective of any --enable-packing setting.  Typically this would be
21'libchromium_android_linker.so'.
22"""
23
24import optparse
25import os
26import shlex
27import shutil
28import sys
29import tempfile
30
31from util import build_utils
32
33def PackArmLibraryRelocations(android_pack_relocations,
34                              android_objcopy,
35                              library_path,
36                              output_path):
37  if not build_utils.IsTimeStale(output_path, [library_path]):
38    return
39
40  # Copy and add a 'NULL' .android.rel.dyn section for the packing tool.
41  with tempfile.NamedTemporaryFile() as stream:
42    stream.write('NULL')
43    stream.flush()
44    objcopy_command = [android_objcopy,
45                       '--add-section', '.android.rel.dyn=%s' % stream.name,
46                       library_path, output_path]
47    build_utils.CheckOutput(objcopy_command)
48
49  # Pack R_ARM_RELATIVE relocations.
50  pack_command = [android_pack_relocations, output_path]
51  build_utils.CheckOutput(pack_command)
52
53
54def CopyArmLibraryUnchanged(library_path, output_path):
55  if not build_utils.IsTimeStale(output_path, [library_path]):
56    return
57
58  shutil.copy(library_path, output_path)
59
60
61def main(args):
62  args = build_utils.ExpandFileArgs(args)
63  parser = optparse.OptionParser()
64
65  parser.add_option('--configuration-name',
66      default='Release',
67      help='Gyp configuration name (i.e. Debug, Release)')
68  parser.add_option('--enable-packing',
69      choices=['0', '1'],
70      help=('Pack relocations if 1 and configuration name is \'Release\','
71            ' otherwise plain file copy'))
72  parser.add_option('--exclude-packing-list',
73      default='',
74      help='Names of any libraries explicitly not packed')
75  parser.add_option('--android-pack-relocations',
76      help='Path to the ARM relocations packer binary')
77  parser.add_option('--android-objcopy',
78      help='Path to the toolchain\'s objcopy binary')
79  parser.add_option('--stripped-libraries-dir',
80      help='Directory for stripped libraries')
81  parser.add_option('--packed-libraries-dir',
82      help='Directory for packed libraries')
83  parser.add_option('--libraries',
84      help='List of libraries')
85  parser.add_option('--stamp', help='Path to touch on success')
86
87  options, _ = parser.parse_args(args)
88  enable_packing = (options.enable_packing == '1' and
89                    options.configuration_name == 'Release')
90  exclude_packing_set = set(shlex.split(options.exclude_packing_list))
91
92  libraries = build_utils.ParseGypList(options.libraries)
93
94  build_utils.MakeDirectory(options.packed_libraries_dir)
95
96  for library in libraries:
97    library_path = os.path.join(options.stripped_libraries_dir, library)
98    output_path = os.path.join(options.packed_libraries_dir, library)
99
100    if enable_packing and library not in exclude_packing_set:
101      PackArmLibraryRelocations(options.android_pack_relocations,
102                                options.android_objcopy,
103                                library_path,
104                                output_path)
105    else:
106      CopyArmLibraryUnchanged(library_path, output_path)
107
108  if options.stamp:
109    build_utils.Touch(options.stamp)
110
111  return 0
112
113
114if __name__ == '__main__':
115  sys.exit(main(sys.argv[1:]))
116