blob: c86d266f9b6affdc5102860c0529cb4b96e2dfad [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']
Henrik Kjellander03ec4f82017-09-27 16:07:40 +020040JAR_FILE = 'lib.java/sdk/android/libwebrtc.jar'
41MANIFEST_FILE = 'sdk/android/AndroidManifest.xml'
sakala4a75382017-01-24 01:25:50 -080042TARGETS = [
Henrik Kjellander03ec4f82017-09-27 16:07:40 +020043 'sdk/android:libwebrtc',
44 'sdk/android:libjingle_peerconnection_so',
sakala4a75382017-01-24 01:25:50 -080045]
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.')
korniltsev.anatoly0b510a92017-09-05 08:12:30 -070053 parser.add_argument('--build-dir',
54 help='Build dir. By default will create and use temporary dir.')
sakala4a75382017-01-24 01:25:50 -080055 parser.add_argument('--output', default='libwebrtc.aar',
56 help='Output file of the script.')
kjellander6b3fcfd2017-02-07 01:11:06 -080057 parser.add_argument('--arch', default=DEFAULT_ARCHS, nargs='*',
58 help='Architectures to build. Defaults to %(default)s.')
sakala4a75382017-01-24 01:25:50 -080059 parser.add_argument('--use-goma', action='store_true', default=False,
60 help='Use goma.')
61 parser.add_argument('--verbose', action='store_true', default=False,
62 help='Debug logging.')
kjellander6b3fcfd2017-02-07 01:11:06 -080063 parser.add_argument('--extra-gn-args', default=[], nargs='*',
64 help='Additional GN args to be used during Ninja generation.')
sakala4a75382017-01-24 01:25:50 -080065 return parser.parse_args()
66
67
68def _RunGN(args):
69 cmd = ['gn']
70 cmd.extend(args)
71 logging.debug('Running: %r', cmd)
72 subprocess.check_call(cmd)
73
74
75def _RunNinja(output_directory, args):
76 cmd = ['ninja', '-C', output_directory]
77 cmd.extend(args)
78 logging.debug('Running: %r', cmd)
79 subprocess.check_call(cmd)
80
81
82def _EncodeForGN(value):
83 """Encodes value as a GN literal."""
84 if type(value) is str:
85 return '"' + value + '"'
86 elif type(value) is bool:
87 return repr(value).lower()
88 else:
89 return repr(value)
90
91
korniltsev.anatoly0b510a92017-09-05 08:12:30 -070092def _GetOutputDirectory(build_dir, arch):
sakala4a75382017-01-24 01:25:50 -080093 """Returns the GN output directory for the target architecture."""
korniltsev.anatoly0b510a92017-09-05 08:12:30 -070094 return os.path.join(build_dir, arch)
sakala4a75382017-01-24 01:25:50 -080095
96
97def _GetTargetCpu(arch):
98 """Returns target_cpu for the GN build with the given architecture."""
99 if arch in ['armeabi', 'armeabi-v7a']:
100 return 'arm'
sakal423f1062017-04-07 05:10:15 -0700101 elif arch == 'arm64-v8a':
102 return 'arm64'
sakala4a75382017-01-24 01:25:50 -0800103 elif arch == 'x86':
104 return 'x86'
sakal423f1062017-04-07 05:10:15 -0700105 elif arch == 'x86_64':
106 return 'x64'
sakala4a75382017-01-24 01:25:50 -0800107 else:
108 raise Exception('Unknown arch: ' + arch)
109
110
111def _GetArmVersion(arch):
112 """Returns arm_version for the GN build with the given architecture."""
113 if arch == 'armeabi':
114 return 6
115 elif arch == 'armeabi-v7a':
116 return 7
sakal423f1062017-04-07 05:10:15 -0700117 elif arch in ['arm64-v8a', 'x86', 'x86_64']:
sakala4a75382017-01-24 01:25:50 -0800118 return None
119 else:
120 raise Exception('Unknown arch: ' + arch)
121
122
korniltsev.anatoly0b510a92017-09-05 08:12:30 -0700123def Build(build_dir, arch, use_goma, extra_gn_args):
sakala4a75382017-01-24 01:25:50 -0800124 """Generates target architecture using GN and builds it using ninja."""
125 logging.info('Building: %s', arch)
korniltsev.anatoly0b510a92017-09-05 08:12:30 -0700126 output_directory = _GetOutputDirectory(build_dir, arch)
sakala4a75382017-01-24 01:25:50 -0800127 gn_args = {
128 'target_os': 'android',
129 'is_debug': False,
130 'is_component_build': False,
sakal67e414c2017-09-05 00:16:15 -0700131 'rtc_include_tests': False,
sakala4a75382017-01-24 01:25:50 -0800132 'target_cpu': _GetTargetCpu(arch),
133 'use_goma': use_goma
134 }
135 arm_version = _GetArmVersion(arch)
136 if arm_version:
137 gn_args['arm_version'] = arm_version
138 gn_args_str = '--args=' + ' '.join([
kjellander6b3fcfd2017-02-07 01:11:06 -0800139 k + '=' + _EncodeForGN(v) for k, v in gn_args.items()] + extra_gn_args)
sakala4a75382017-01-24 01:25:50 -0800140
141 _RunGN(['gen', output_directory, gn_args_str])
142
sakal67e414c2017-09-05 00:16:15 -0700143 ninja_args = TARGETS[:]
sakala4a75382017-01-24 01:25:50 -0800144 if use_goma:
sakala53d4e72017-02-07 06:19:20 -0800145 ninja_args.extend(['-j', '200'])
sakala4a75382017-01-24 01:25:50 -0800146 _RunNinja(output_directory, ninja_args)
147
148
korniltsev.anatoly0b510a92017-09-05 08:12:30 -0700149def CollectCommon(aar_file, build_dir, arch):
sakala4a75382017-01-24 01:25:50 -0800150 """Collects architecture independent files into the .aar-archive."""
151 logging.info('Collecting common files.')
korniltsev.anatoly0b510a92017-09-05 08:12:30 -0700152 output_directory = _GetOutputDirectory(build_dir, arch)
sakala4a75382017-01-24 01:25:50 -0800153 aar_file.write(MANIFEST_FILE, 'AndroidManifest.xml')
154 aar_file.write(os.path.join(output_directory, JAR_FILE), 'classes.jar')
155
156
korniltsev.anatoly0b510a92017-09-05 08:12:30 -0700157def Collect(aar_file, build_dir, arch):
sakala4a75382017-01-24 01:25:50 -0800158 """Collects architecture specific files into the .aar-archive."""
159 logging.info('Collecting: %s', arch)
korniltsev.anatoly0b510a92017-09-05 08:12:30 -0700160 output_directory = _GetOutputDirectory(build_dir, arch)
sakala4a75382017-01-24 01:25:50 -0800161
162 abi_dir = os.path.join('jni', arch)
163 for so_file in NEEDED_SO_FILES:
164 aar_file.write(os.path.join(output_directory, so_file),
165 os.path.join(abi_dir, so_file))
166
167
korniltsev.anatoly0b510a92017-09-05 08:12:30 -0700168def GenerateLicenses(output_dir, build_dir, archs):
sakal67e414c2017-09-05 00:16:15 -0700169 builder = LicenseBuilder(
korniltsev.anatoly0b510a92017-09-05 08:12:30 -0700170 [_GetOutputDirectory(build_dir, arch) for arch in archs], TARGETS)
sakal67e414c2017-09-05 00:16:15 -0700171 builder.GenerateLicenseText(output_dir)
172
173
Sami Kalliomäkidbb15a72017-10-05 16:15:02 +0200174def BuildAar(archs, output_file, use_goma=False, extra_gn_args=None,
175 ext_build_dir=None):
176 extra_gn_args = extra_gn_args or []
177 build_dir = ext_build_dir if ext_build_dir else tempfile.mkdtemp()
178
179 for arch in archs:
180 Build(build_dir, arch, use_goma, extra_gn_args)
181
182 with zipfile.ZipFile(output_file, 'w') as aar_file:
183 # Architecture doesn't matter here, arbitrarily using the first one.
184 CollectCommon(aar_file, build_dir, archs[0])
185 for arch in archs:
186 Collect(aar_file, build_dir, arch)
187
188 license_dir = os.path.dirname(os.path.realpath(output_file))
189 GenerateLicenses(license_dir, build_dir, archs)
190
191 if not ext_build_dir:
192 shutil.rmtree(build_dir, True)
193
194
sakala4a75382017-01-24 01:25:50 -0800195def main():
196 args = _ParseArgs()
sakala4a75382017-01-24 01:25:50 -0800197 logging.basicConfig(level=logging.DEBUG if args.verbose else logging.INFO)
198
Sami Kalliomäkidbb15a72017-10-05 16:15:02 +0200199 BuildAar(args.arch, args.output, args.use_goma, args.extra_gn_args,
200 args.build_dir)
sakala4a75382017-01-24 01:25:50 -0800201
202
203if __name__ == '__main__':
204 sys.exit(main())