blob: b0d28c015143e54591156c5926e13c87c3e023c2 [file] [log] [blame]
oprypin7a2d8ca2017-02-06 07:53:41 -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"""WebRTC iOS FAT libraries build script.
12Each architecture is compiled separately before being merged together.
13By default, the library is created in out_ios_libs/. (Change with -o.)
oprypin7a2d8ca2017-02-06 07:53:41 -080014"""
15
16import argparse
17import distutils.dir_util
18import logging
19import os
20import shutil
21import subprocess
22import sys
23
24
25os.environ['PATH'] = '/usr/libexec' + os.pathsep + os.environ['PATH']
26
27SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
Henrik Kjellanderec57e052017-10-17 21:36:01 +020028SRC_DIR = os.path.abspath(os.path.join(SCRIPT_DIR, '..', '..'))
29sys.path.append(os.path.join(SRC_DIR, 'build'))
30import find_depot_tools
31
32SDK_OUTPUT_DIR = os.path.join(SRC_DIR, 'out_ios_libs')
oprypin7a2d8ca2017-02-06 07:53:41 -080033SDK_FRAMEWORK_NAME = 'WebRTC.framework'
34
oprypin9b0dbd42017-02-13 08:30:01 -080035DEFAULT_ARCHS = ENABLED_ARCHS = ['arm64', 'arm', 'x64', 'x86']
Kári Tristan Helgasonffe93762019-03-07 13:14:32 +010036IOS_DEPLOYMENT_TARGET = '10.0'
oprypin7a2d8ca2017-02-06 07:53:41 -080037LIBVPX_BUILD_VP9 = False
oprypin7a2d8ca2017-02-06 07:53:41 -080038
sakal67e414c2017-09-05 00:16:15 -070039sys.path.append(os.path.join(SCRIPT_DIR, '..', 'libs'))
40from generate_licenses import LicenseBuilder
41
oprypin7a2d8ca2017-02-06 07:53:41 -080042
43def _ParseArgs():
44 parser = argparse.ArgumentParser(description=__doc__)
oprypin7a2d8ca2017-02-06 07:53:41 -080045 parser.add_argument('--build_config', default='release',
46 choices=['debug', 'release'],
47 help='The build config. Can be "debug" or "release". '
48 'Defaults to "release".')
oprypin9b0dbd42017-02-13 08:30:01 -080049 parser.add_argument('--arch', nargs='+', default=DEFAULT_ARCHS,
50 choices=ENABLED_ARCHS,
51 help='Architectures to build. Defaults to %(default)s.')
oprypin7a2d8ca2017-02-06 07:53:41 -080052 parser.add_argument('-c', '--clean', action='store_true', default=False,
53 help='Removes the previously generated build output, if any.')
VladimirTechMan7b188e82017-03-14 03:12:35 -070054 parser.add_argument('-p', '--purify', action='store_true', default=False,
55 help='Purifies the previously generated build output by '
56 'removing the temporary results used when (re)building.')
oprypin7a2d8ca2017-02-06 07:53:41 -080057 parser.add_argument('-o', '--output-dir', default=SDK_OUTPUT_DIR,
58 help='Specifies a directory to output the build artifacts to. '
59 'If specified together with -c, deletes the dir.')
60 parser.add_argument('-r', '--revision', type=int, default=0,
61 help='Specifies a revision number to embed if building the framework.')
62 parser.add_argument('-e', '--bitcode', action='store_true', default=False,
63 help='Compile with bitcode.')
64 parser.add_argument('--verbose', action='store_true', default=False,
65 help='Debug logging.')
mbonadei585209b2017-02-13 04:59:27 -080066 parser.add_argument('--use-goma', action='store_true', default=False,
67 help='Use goma to build.')
68 parser.add_argument('--extra-gn-args', default=[], nargs='*',
69 help='Additional GN args to be used during Ninja generation.')
70
oprypin7a2d8ca2017-02-06 07:53:41 -080071 return parser.parse_args()
72
73
74def _RunCommand(cmd):
75 logging.debug('Running: %r', cmd)
Henrik Kjellanderec57e052017-10-17 21:36:01 +020076 subprocess.check_call(cmd, cwd=SRC_DIR)
oprypin7a2d8ca2017-02-06 07:53:41 -080077
78
79def _CleanArtifacts(output_dir):
80 if os.path.isdir(output_dir):
81 logging.info('Deleting %s', output_dir)
82 shutil.rmtree(output_dir)
83
84
VladimirTechMan7b188e82017-03-14 03:12:35 -070085def _CleanTemporary(output_dir, architectures):
86 if os.path.isdir(output_dir):
87 logging.info('Removing temporary build files.')
88 for arch in architectures:
89 arch_lib_path = os.path.join(output_dir, arch + '_libs')
90 if os.path.isdir(arch_lib_path):
91 shutil.rmtree(arch_lib_path)
92
93
Kári Tristan Helgason1edbda02017-06-13 10:45:42 +020094def BuildWebRTC(output_dir, target_arch, flavor, gn_target_name,
oprypin7a2d8ca2017-02-06 07:53:41 -080095 ios_deployment_target, libvpx_build_vp9, use_bitcode,
Kári Tristan Helgasona2d89fc2018-03-06 10:18:43 +010096 use_goma, extra_gn_args):
oprypin7a2d8ca2017-02-06 07:53:41 -080097 output_dir = os.path.join(output_dir, target_arch + '_libs')
98 gn_args = ['target_os="ios"', 'ios_enable_code_signing=false',
99 'use_xcode_clang=true', 'is_component_build=false']
100
101 # Add flavor option.
102 if flavor == 'debug':
103 gn_args.append('is_debug=true')
104 elif flavor == 'release':
105 gn_args.append('is_debug=false')
106 else:
107 raise ValueError('Unexpected flavor type: %s' % flavor)
108
109 gn_args.append('target_cpu="%s"' % target_arch)
110
111 gn_args.append('ios_deployment_target="%s"' % ios_deployment_target)
112
113 gn_args.append('rtc_libvpx_build_vp9=' +
114 ('true' if libvpx_build_vp9 else 'false'))
115
116 gn_args.append('enable_ios_bitcode=' +
117 ('true' if use_bitcode else 'false'))
mbonadei585209b2017-02-13 04:59:27 -0800118 gn_args.append('use_goma=' + ('true' if use_goma else 'false'))
oprypin7a2d8ca2017-02-06 07:53:41 -0800119
mbonadei7b2797e2017-02-16 01:40:59 -0800120 args_string = ' '.join(gn_args + extra_gn_args)
121 logging.info('Building WebRTC with args: %s', args_string)
mbonadei8714b8f2017-02-15 13:18:57 -0800122
Henrik Kjellanderec57e052017-10-17 21:36:01 +0200123 cmd = [
124 sys.executable,
125 os.path.join(find_depot_tools.DEPOT_TOOLS_PATH, 'gn.py'),
126 'gen',
127 output_dir,
128 '--args=' + args_string,
129 ]
oprypin7a2d8ca2017-02-06 07:53:41 -0800130 _RunCommand(cmd)
131 logging.info('Building target: %s', gn_target_name)
mbonadei8714b8f2017-02-15 13:18:57 -0800132
Henrik Kjellanderec57e052017-10-17 21:36:01 +0200133 cmd = [
134 os.path.join(find_depot_tools.DEPOT_TOOLS_PATH, 'ninja'),
135 '-C',
136 output_dir,
137 gn_target_name,
138 ]
mbonadei8714b8f2017-02-15 13:18:57 -0800139 if use_goma:
140 cmd.extend(['-j', '200'])
oprypin7a2d8ca2017-02-06 07:53:41 -0800141 _RunCommand(cmd)
142
oprypin7a2d8ca2017-02-06 07:53:41 -0800143def main():
144 args = _ParseArgs()
145
146 logging.basicConfig(level=logging.DEBUG if args.verbose else logging.INFO)
147
148 if args.clean:
149 _CleanArtifacts(args.output_dir)
150 return 0
151
oprypin9b0dbd42017-02-13 08:30:01 -0800152 architectures = list(args.arch)
Kári Tristan Helgason1edbda02017-06-13 10:45:42 +0200153 gn_args = args.extra_gn_args
VladimirTechMan7b188e82017-03-14 03:12:35 -0700154
155 if args.purify:
156 _CleanTemporary(args.output_dir, architectures)
157 return 0
158
Kári Tristan Helgasona2d89fc2018-03-06 10:18:43 +0100159 gn_target_name = 'framework_objc'
160 if not args.bitcode:
161 gn_args.append('enable_dsyms=true')
162 gn_args.append('enable_stripping=true')
Kári Tristan Helgason1edbda02017-06-13 10:45:42 +0200163
164
oprypin7a2d8ca2017-02-06 07:53:41 -0800165 # Build all architectures.
oprypin9b0dbd42017-02-13 08:30:01 -0800166 for arch in architectures:
Kári Tristan Helgason1edbda02017-06-13 10:45:42 +0200167 BuildWebRTC(args.output_dir, arch, args.build_config, gn_target_name,
oprypin7a2d8ca2017-02-06 07:53:41 -0800168 IOS_DEPLOYMENT_TARGET, LIBVPX_BUILD_VP9, args.bitcode,
Kári Tristan Helgasona2d89fc2018-03-06 10:18:43 +0100169 args.use_goma, gn_args)
oprypin7a2d8ca2017-02-06 07:53:41 -0800170
oprypin7a2d8ca2017-02-06 07:53:41 -0800171 # Create FAT archive.
Kári Tristan Helgasona2d89fc2018-03-06 10:18:43 +0100172 lib_paths = [os.path.join(args.output_dir, arch + '_libs')
173 for arch in architectures]
oprypin7a2d8ca2017-02-06 07:53:41 -0800174
Kári Tristan Helgasona2d89fc2018-03-06 10:18:43 +0100175 # Combine the slices.
176 dylib_path = os.path.join(SDK_FRAMEWORK_NAME, 'WebRTC')
177 # Dylibs will be combined, all other files are the same across archs.
178 # Use distutils instead of shutil to support merging folders.
179 distutils.dir_util.copy_tree(
180 os.path.join(lib_paths[0], SDK_FRAMEWORK_NAME),
181 os.path.join(args.output_dir, SDK_FRAMEWORK_NAME))
182 logging.info('Merging framework slices.')
183 dylib_paths = [os.path.join(path, dylib_path) for path in lib_paths]
184 out_dylib_path = os.path.join(args.output_dir, dylib_path)
185 try:
186 os.remove(out_dylib_path)
187 except OSError:
188 pass
189 cmd = ['lipo'] + dylib_paths + ['-create', '-output', out_dylib_path]
190 _RunCommand(cmd)
oprypin7a2d8ca2017-02-06 07:53:41 -0800191
Kári Tristan Helgasona2d89fc2018-03-06 10:18:43 +0100192 # Merge the dSYM slices.
193 lib_dsym_dir_path = os.path.join(lib_paths[0], 'WebRTC.dSYM')
194 if os.path.isdir(lib_dsym_dir_path):
195 distutils.dir_util.copy_tree(lib_dsym_dir_path,
196 os.path.join(args.output_dir, 'WebRTC.dSYM'))
197 logging.info('Merging dSYM slices.')
198 dsym_path = os.path.join('WebRTC.dSYM', 'Contents', 'Resources', 'DWARF',
199 'WebRTC')
200 lib_dsym_paths = [os.path.join(path, dsym_path) for path in lib_paths]
201 out_dsym_path = os.path.join(args.output_dir, dsym_path)
kthelgason28922442017-02-28 15:33:26 -0800202 try:
Kári Tristan Helgasona2d89fc2018-03-06 10:18:43 +0100203 os.remove(out_dsym_path)
kthelgason28922442017-02-28 15:33:26 -0800204 except OSError:
205 pass
Kári Tristan Helgasona2d89fc2018-03-06 10:18:43 +0100206 cmd = ['lipo'] + lib_dsym_paths + ['-create', '-output', out_dsym_path]
oprypin7a2d8ca2017-02-06 07:53:41 -0800207 _RunCommand(cmd)
208
kthelgason96feb2a2017-03-13 08:05:59 -0700209 # Generate the license file.
kthelgason96feb2a2017-03-13 08:05:59 -0700210 ninja_dirs = [os.path.join(args.output_dir, arch + '_libs')
211 for arch in architectures]
Mirko Bonadei92ea95e2017-09-15 06:47:31 +0200212 gn_target_full_name = '//sdk:' + gn_target_name
sakal67e414c2017-09-05 00:16:15 -0700213 builder = LicenseBuilder(ninja_dirs, [gn_target_full_name])
214 builder.GenerateLicenseText(
215 os.path.join(args.output_dir, SDK_FRAMEWORK_NAME))
216
kthelgason96feb2a2017-03-13 08:05:59 -0700217
oprypin7a2d8ca2017-02-06 07:53:41 -0800218 # Modify the version number.
219 # Format should be <Branch cut MXX>.<Hotfix #>.<Rev #>.
220 # e.g. 55.0.14986 means branch cut 55, no hotfixes, and revision 14986.
221 infoplist_path = os.path.join(args.output_dir, SDK_FRAMEWORK_NAME,
222 'Info.plist')
223 cmd = ['PlistBuddy', '-c',
224 'Print :CFBundleShortVersionString', infoplist_path]
225 major_minor = subprocess.check_output(cmd).strip()
226 version_number = '%s.%s' % (major_minor, args.revision)
227 logging.info('Substituting revision number: %s', version_number)
228 cmd = ['PlistBuddy', '-c',
229 'Set :CFBundleVersion ' + version_number, infoplist_path]
230 _RunCommand(cmd)
231 _RunCommand(['plutil', '-convert', 'binary1', infoplist_path])
232
233 logging.info('Done.')
234 return 0
235
236
237if __name__ == '__main__':
238 sys.exit(main())