blob: 50f1ff4e7cd24f28a8412e82a8b49a64d1f028a1 [file] [log] [blame]
sakala4a75382017-01-24 01:25:50 -08001#!/usr/bin/env python
2
3# Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
4#
5# Use of this source code is governed by a BSD-style license
6# that can be found in the LICENSE file in the root of the source
7# tree. An additional intellectual property rights grant can be found
8# in the file PATENTS. All contributing project authors may
9# be found in the AUTHORS file in the root of the source tree.
10
11"""Script to generate libwebrtc.aar for distribution.
12
13The script has to be run from the root src folder.
Henrik Kjellander90fd7d82017-05-09 08:30:10 +020014./tools_webrtc/android/build_aar.py
sakala4a75382017-01-24 01:25:50 -080015
16.aar-file is just a zip-archive containing the files of the library. The file
17structure generated by this script looks like this:
18 - AndroidManifest.xml
19 - classes.jar
20 - libs/
21 - armeabi-v7a/
22 - libjingle_peerconnection_so.so
23 - x86/
24 - libjingle_peerconnection_so.so
25"""
26
27import argparse
28import logging
29import os
30import shutil
31import subprocess
32import sys
33import tempfile
34import zipfile
35
36
sakal67e414c2017-09-05 00:16:15 -070037SCRIPT_DIR = os.path.dirname(os.path.realpath(sys.argv[0]))
sakal423f1062017-04-07 05:10:15 -070038DEFAULT_ARCHS = ['armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64']
sakala4a75382017-01-24 01:25:50 -080039NEEDED_SO_FILES = ['libjingle_peerconnection_so.so']
40JAR_FILE = 'lib.java/webrtc/sdk/android/libwebrtc.jar'
41MANIFEST_FILE = 'webrtc/sdk/android/AndroidManifest.xml'
42TARGETS = [
43 'webrtc/sdk/android:libwebrtc',
44 'webrtc/sdk/android:libjingle_peerconnection_so',
45]
46
sakal67e414c2017-09-05 00:16:15 -070047sys.path.append(os.path.join(SCRIPT_DIR, '..', 'libs'))
48from generate_licenses import LicenseBuilder
49
sakala4a75382017-01-24 01:25:50 -080050
51def _ParseArgs():
52 parser = argparse.ArgumentParser(description='libwebrtc.aar generator.')
53 parser.add_argument('--output', default='libwebrtc.aar',
54 help='Output file of the script.')
kjellander6b3fcfd2017-02-07 01:11:06 -080055 parser.add_argument('--arch', default=DEFAULT_ARCHS, nargs='*',
56 help='Architectures to build. Defaults to %(default)s.')
sakala4a75382017-01-24 01:25:50 -080057 parser.add_argument('--use-goma', action='store_true', default=False,
58 help='Use goma.')
59 parser.add_argument('--verbose', action='store_true', default=False,
60 help='Debug logging.')
kjellander6b3fcfd2017-02-07 01:11:06 -080061 parser.add_argument('--extra-gn-args', default=[], nargs='*',
62 help='Additional GN args to be used during Ninja generation.')
sakala4a75382017-01-24 01:25:50 -080063 return parser.parse_args()
64
65
66def _RunGN(args):
67 cmd = ['gn']
68 cmd.extend(args)
69 logging.debug('Running: %r', cmd)
70 subprocess.check_call(cmd)
71
72
73def _RunNinja(output_directory, args):
74 cmd = ['ninja', '-C', output_directory]
75 cmd.extend(args)
76 logging.debug('Running: %r', cmd)
77 subprocess.check_call(cmd)
78
79
80def _EncodeForGN(value):
81 """Encodes value as a GN literal."""
82 if type(value) is str:
83 return '"' + value + '"'
84 elif type(value) is bool:
85 return repr(value).lower()
86 else:
87 return repr(value)
88
89
90def _GetOutputDirectory(tmp_dir, arch):
91 """Returns the GN output directory for the target architecture."""
92 return os.path.join(tmp_dir, arch)
93
94
95def _GetTargetCpu(arch):
96 """Returns target_cpu for the GN build with the given architecture."""
97 if arch in ['armeabi', 'armeabi-v7a']:
98 return 'arm'
sakal423f1062017-04-07 05:10:15 -070099 elif arch == 'arm64-v8a':
100 return 'arm64'
sakala4a75382017-01-24 01:25:50 -0800101 elif arch == 'x86':
102 return 'x86'
sakal423f1062017-04-07 05:10:15 -0700103 elif arch == 'x86_64':
104 return 'x64'
sakala4a75382017-01-24 01:25:50 -0800105 else:
106 raise Exception('Unknown arch: ' + arch)
107
108
109def _GetArmVersion(arch):
110 """Returns arm_version for the GN build with the given architecture."""
111 if arch == 'armeabi':
112 return 6
113 elif arch == 'armeabi-v7a':
114 return 7
sakal423f1062017-04-07 05:10:15 -0700115 elif arch in ['arm64-v8a', 'x86', 'x86_64']:
sakala4a75382017-01-24 01:25:50 -0800116 return None
117 else:
118 raise Exception('Unknown arch: ' + arch)
119
120
kjellander6b3fcfd2017-02-07 01:11:06 -0800121def Build(tmp_dir, arch, use_goma, extra_gn_args):
sakala4a75382017-01-24 01:25:50 -0800122 """Generates target architecture using GN and builds it using ninja."""
123 logging.info('Building: %s', arch)
124 output_directory = _GetOutputDirectory(tmp_dir, arch)
125 gn_args = {
126 'target_os': 'android',
127 'is_debug': False,
128 'is_component_build': False,
sakal67e414c2017-09-05 00:16:15 -0700129 'rtc_include_tests': False,
sakala4a75382017-01-24 01:25:50 -0800130 'target_cpu': _GetTargetCpu(arch),
131 'use_goma': use_goma
132 }
133 arm_version = _GetArmVersion(arch)
134 if arm_version:
135 gn_args['arm_version'] = arm_version
136 gn_args_str = '--args=' + ' '.join([
kjellander6b3fcfd2017-02-07 01:11:06 -0800137 k + '=' + _EncodeForGN(v) for k, v in gn_args.items()] + extra_gn_args)
sakala4a75382017-01-24 01:25:50 -0800138
139 _RunGN(['gen', output_directory, gn_args_str])
140
sakal67e414c2017-09-05 00:16:15 -0700141 ninja_args = TARGETS[:]
sakala4a75382017-01-24 01:25:50 -0800142 if use_goma:
sakala53d4e72017-02-07 06:19:20 -0800143 ninja_args.extend(['-j', '200'])
sakala4a75382017-01-24 01:25:50 -0800144 _RunNinja(output_directory, ninja_args)
145
146
147def CollectCommon(aar_file, tmp_dir, arch):
148 """Collects architecture independent files into the .aar-archive."""
149 logging.info('Collecting common files.')
150 output_directory = _GetOutputDirectory(tmp_dir, arch)
151 aar_file.write(MANIFEST_FILE, 'AndroidManifest.xml')
152 aar_file.write(os.path.join(output_directory, JAR_FILE), 'classes.jar')
153
154
155def Collect(aar_file, tmp_dir, arch):
156 """Collects architecture specific files into the .aar-archive."""
157 logging.info('Collecting: %s', arch)
158 output_directory = _GetOutputDirectory(tmp_dir, arch)
159
160 abi_dir = os.path.join('jni', arch)
161 for so_file in NEEDED_SO_FILES:
162 aar_file.write(os.path.join(output_directory, so_file),
163 os.path.join(abi_dir, so_file))
164
165
sakal67e414c2017-09-05 00:16:15 -0700166def GenerateLicenses(output_dir, tmp_dir, archs):
167 builder = LicenseBuilder(
168 [_GetOutputDirectory(tmp_dir, arch) for arch in archs], TARGETS)
169 builder.GenerateLicenseText(output_dir)
170
171
sakala4a75382017-01-24 01:25:50 -0800172def main():
173 args = _ParseArgs()
sakala4a75382017-01-24 01:25:50 -0800174 logging.basicConfig(level=logging.DEBUG if args.verbose else logging.INFO)
175
176 tmp_dir = tempfile.mkdtemp()
177
178 for arch in args.arch:
kjellander6b3fcfd2017-02-07 01:11:06 -0800179 Build(tmp_dir, arch, args.use_goma, args.extra_gn_args)
sakala4a75382017-01-24 01:25:50 -0800180
181 with zipfile.ZipFile(args.output, 'w') as aar_file:
182 # Architecture doesn't matter here, arbitrarily using the first one.
183 CollectCommon(aar_file, tmp_dir, args.arch[0])
184 for arch in args.arch:
185 Collect(aar_file, tmp_dir, arch)
186
sakal67e414c2017-09-05 00:16:15 -0700187 license_dir = os.path.dirname(os.path.realpath(args.output))
188 GenerateLicenses(license_dir, tmp_dir, args.arch)
189
sakala4a75382017-01-24 01:25:50 -0800190 shutil.rmtree(tmp_dir, True)
191
192
193if __name__ == '__main__':
194 sys.exit(main())