blob: 5a7b56e53f81d0797959611e54d03f5da3a2ea9c [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]))
Henrik Kjellanderec57e052017-10-17 21:36:01 +020038SRC_DIR = os.path.normpath(os.path.join(SCRIPT_DIR, os.pardir, os.pardir))
sakal423f1062017-04-07 05:10:15 -070039DEFAULT_ARCHS = ['armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64']
sakala4a75382017-01-24 01:25:50 -080040NEEDED_SO_FILES = ['libjingle_peerconnection_so.so']
Henrik Kjellander03ec4f82017-09-27 16:07:40 +020041JAR_FILE = 'lib.java/sdk/android/libwebrtc.jar'
42MANIFEST_FILE = 'sdk/android/AndroidManifest.xml'
sakala4a75382017-01-24 01:25:50 -080043TARGETS = [
Henrik Kjellander03ec4f82017-09-27 16:07:40 +020044 'sdk/android:libwebrtc',
45 'sdk/android:libjingle_peerconnection_so',
sakala4a75382017-01-24 01:25:50 -080046]
47
sakal67e414c2017-09-05 00:16:15 -070048sys.path.append(os.path.join(SCRIPT_DIR, '..', 'libs'))
49from generate_licenses import LicenseBuilder
50
Henrik Kjellanderec57e052017-10-17 21:36:01 +020051sys.path.append(os.path.join(SRC_DIR, 'build'))
52import find_depot_tools
53
54
sakala4a75382017-01-24 01:25:50 -080055
56def _ParseArgs():
57 parser = argparse.ArgumentParser(description='libwebrtc.aar generator.')
korniltsev.anatoly0b510a92017-09-05 08:12:30 -070058 parser.add_argument('--build-dir',
59 help='Build dir. By default will create and use temporary dir.')
sakala4a75382017-01-24 01:25:50 -080060 parser.add_argument('--output', default='libwebrtc.aar',
61 help='Output file of the script.')
kjellander6b3fcfd2017-02-07 01:11:06 -080062 parser.add_argument('--arch', default=DEFAULT_ARCHS, nargs='*',
63 help='Architectures to build. Defaults to %(default)s.')
sakala4a75382017-01-24 01:25:50 -080064 parser.add_argument('--use-goma', action='store_true', default=False,
65 help='Use goma.')
66 parser.add_argument('--verbose', action='store_true', default=False,
67 help='Debug logging.')
kjellander6b3fcfd2017-02-07 01:11:06 -080068 parser.add_argument('--extra-gn-args', default=[], nargs='*',
Yura Yaroshevichbe7b88c2018-03-13 13:12:56 +030069 help="""Additional GN arguments to be used during Ninja generation.
70 These are applied after any other arguments and will
71 override any values defined by the script.""")
sakala4a75382017-01-24 01:25:50 -080072 return parser.parse_args()
73
74
75def _RunGN(args):
Henrik Kjellanderec57e052017-10-17 21:36:01 +020076 cmd = [sys.executable,
77 os.path.join(find_depot_tools.DEPOT_TOOLS_PATH, 'gn.py')]
sakala4a75382017-01-24 01:25:50 -080078 cmd.extend(args)
79 logging.debug('Running: %r', cmd)
80 subprocess.check_call(cmd)
81
82
83def _RunNinja(output_directory, args):
Henrik Kjellanderec57e052017-10-17 21:36:01 +020084 cmd = [os.path.join(find_depot_tools.DEPOT_TOOLS_PATH, 'ninja'),
85 '-C', output_directory]
sakala4a75382017-01-24 01:25:50 -080086 cmd.extend(args)
87 logging.debug('Running: %r', cmd)
88 subprocess.check_call(cmd)
89
90
91def _EncodeForGN(value):
92 """Encodes value as a GN literal."""
93 if type(value) is str:
94 return '"' + value + '"'
95 elif type(value) is bool:
96 return repr(value).lower()
97 else:
98 return repr(value)
99
100
korniltsev.anatoly0b510a92017-09-05 08:12:30 -0700101def _GetOutputDirectory(build_dir, arch):
sakala4a75382017-01-24 01:25:50 -0800102 """Returns the GN output directory for the target architecture."""
korniltsev.anatoly0b510a92017-09-05 08:12:30 -0700103 return os.path.join(build_dir, arch)
sakala4a75382017-01-24 01:25:50 -0800104
105
106def _GetTargetCpu(arch):
107 """Returns target_cpu for the GN build with the given architecture."""
108 if arch in ['armeabi', 'armeabi-v7a']:
109 return 'arm'
sakal423f1062017-04-07 05:10:15 -0700110 elif arch == 'arm64-v8a':
111 return 'arm64'
sakala4a75382017-01-24 01:25:50 -0800112 elif arch == 'x86':
113 return 'x86'
sakal423f1062017-04-07 05:10:15 -0700114 elif arch == 'x86_64':
115 return 'x64'
sakala4a75382017-01-24 01:25:50 -0800116 else:
117 raise Exception('Unknown arch: ' + arch)
118
119
120def _GetArmVersion(arch):
121 """Returns arm_version for the GN build with the given architecture."""
122 if arch == 'armeabi':
123 return 6
124 elif arch == 'armeabi-v7a':
125 return 7
sakal423f1062017-04-07 05:10:15 -0700126 elif arch in ['arm64-v8a', 'x86', 'x86_64']:
sakala4a75382017-01-24 01:25:50 -0800127 return None
128 else:
129 raise Exception('Unknown arch: ' + arch)
130
131
korniltsev.anatoly0b510a92017-09-05 08:12:30 -0700132def Build(build_dir, arch, use_goma, extra_gn_args):
sakala4a75382017-01-24 01:25:50 -0800133 """Generates target architecture using GN and builds it using ninja."""
134 logging.info('Building: %s', arch)
korniltsev.anatoly0b510a92017-09-05 08:12:30 -0700135 output_directory = _GetOutputDirectory(build_dir, arch)
sakala4a75382017-01-24 01:25:50 -0800136 gn_args = {
137 'target_os': 'android',
138 'is_debug': False,
139 'is_component_build': False,
sakal67e414c2017-09-05 00:16:15 -0700140 'rtc_include_tests': False,
sakala4a75382017-01-24 01:25:50 -0800141 'target_cpu': _GetTargetCpu(arch),
142 'use_goma': use_goma
143 }
144 arm_version = _GetArmVersion(arch)
145 if arm_version:
146 gn_args['arm_version'] = arm_version
147 gn_args_str = '--args=' + ' '.join([
kjellander6b3fcfd2017-02-07 01:11:06 -0800148 k + '=' + _EncodeForGN(v) for k, v in gn_args.items()] + extra_gn_args)
sakala4a75382017-01-24 01:25:50 -0800149
150 _RunGN(['gen', output_directory, gn_args_str])
151
sakal67e414c2017-09-05 00:16:15 -0700152 ninja_args = TARGETS[:]
sakala4a75382017-01-24 01:25:50 -0800153 if use_goma:
sakala53d4e72017-02-07 06:19:20 -0800154 ninja_args.extend(['-j', '200'])
sakala4a75382017-01-24 01:25:50 -0800155 _RunNinja(output_directory, ninja_args)
156
157
korniltsev.anatoly0b510a92017-09-05 08:12:30 -0700158def CollectCommon(aar_file, build_dir, arch):
sakala4a75382017-01-24 01:25:50 -0800159 """Collects architecture independent files into the .aar-archive."""
160 logging.info('Collecting common files.')
korniltsev.anatoly0b510a92017-09-05 08:12:30 -0700161 output_directory = _GetOutputDirectory(build_dir, arch)
sakala4a75382017-01-24 01:25:50 -0800162 aar_file.write(MANIFEST_FILE, 'AndroidManifest.xml')
163 aar_file.write(os.path.join(output_directory, JAR_FILE), 'classes.jar')
164
165
korniltsev.anatoly0b510a92017-09-05 08:12:30 -0700166def Collect(aar_file, build_dir, arch):
sakala4a75382017-01-24 01:25:50 -0800167 """Collects architecture specific files into the .aar-archive."""
168 logging.info('Collecting: %s', arch)
korniltsev.anatoly0b510a92017-09-05 08:12:30 -0700169 output_directory = _GetOutputDirectory(build_dir, arch)
sakala4a75382017-01-24 01:25:50 -0800170
171 abi_dir = os.path.join('jni', arch)
172 for so_file in NEEDED_SO_FILES:
173 aar_file.write(os.path.join(output_directory, so_file),
174 os.path.join(abi_dir, so_file))
175
176
korniltsev.anatoly0b510a92017-09-05 08:12:30 -0700177def GenerateLicenses(output_dir, build_dir, archs):
sakal67e414c2017-09-05 00:16:15 -0700178 builder = LicenseBuilder(
korniltsev.anatoly0b510a92017-09-05 08:12:30 -0700179 [_GetOutputDirectory(build_dir, arch) for arch in archs], TARGETS)
sakal67e414c2017-09-05 00:16:15 -0700180 builder.GenerateLicenseText(output_dir)
181
182
Sami Kalliomäkidbb15a72017-10-05 16:15:02 +0200183def BuildAar(archs, output_file, use_goma=False, extra_gn_args=None,
184 ext_build_dir=None):
185 extra_gn_args = extra_gn_args or []
186 build_dir = ext_build_dir if ext_build_dir else tempfile.mkdtemp()
187
188 for arch in archs:
189 Build(build_dir, arch, use_goma, extra_gn_args)
190
191 with zipfile.ZipFile(output_file, 'w') as aar_file:
192 # Architecture doesn't matter here, arbitrarily using the first one.
193 CollectCommon(aar_file, build_dir, archs[0])
194 for arch in archs:
195 Collect(aar_file, build_dir, arch)
196
197 license_dir = os.path.dirname(os.path.realpath(output_file))
198 GenerateLicenses(license_dir, build_dir, archs)
199
200 if not ext_build_dir:
201 shutil.rmtree(build_dir, True)
202
203
sakala4a75382017-01-24 01:25:50 -0800204def main():
205 args = _ParseArgs()
sakala4a75382017-01-24 01:25:50 -0800206 logging.basicConfig(level=logging.DEBUG if args.verbose else logging.INFO)
207
Sami Kalliomäkidbb15a72017-10-05 16:15:02 +0200208 BuildAar(args.arch, args.output, args.use_goma, args.extra_gn_args,
209 args.build_dir)
sakala4a75382017-01-24 01:25:50 -0800210
211
212if __name__ == '__main__':
213 sys.exit(main())