blob: 4e2585cc8a7e05b0ee0075aa794d2194fe61af07 [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 Kjellander368b5ff2017-02-15 20:51:26 +010028WEBRTC_SRC_DIR = os.path.abspath(os.path.join(SCRIPT_DIR, '..', '..'))
29SDK_OUTPUT_DIR = os.path.join(WEBRTC_SRC_DIR, 'out_ios_libs')
oprypin7a2d8ca2017-02-06 07:53:41 -080030SDK_LIB_NAME = 'librtc_sdk_objc.a'
31SDK_FRAMEWORK_NAME = 'WebRTC.framework'
32
oprypin9b0dbd42017-02-13 08:30:01 -080033DEFAULT_ARCHS = ENABLED_ARCHS = ['arm64', 'arm', 'x64', 'x86']
oprypin7a2d8ca2017-02-06 07:53:41 -080034IOS_DEPLOYMENT_TARGET = '8.0'
35LIBVPX_BUILD_VP9 = False
oprypin7a2d8ca2017-02-06 07:53:41 -080036
37
38def _ParseArgs():
39 parser = argparse.ArgumentParser(description=__doc__)
40 parser.add_argument('-b', '--build_type', default='framework',
41 choices=['framework', 'static_only'],
42 help='The build type. Can be "framework" or "static_only". '
43 'Defaults to "framework".')
44 parser.add_argument('--build_config', default='release',
45 choices=['debug', 'release'],
46 help='The build config. Can be "debug" or "release". '
47 'Defaults to "release".')
oprypin9b0dbd42017-02-13 08:30:01 -080048 parser.add_argument('--arch', nargs='+', default=DEFAULT_ARCHS,
49 choices=ENABLED_ARCHS,
50 help='Architectures to build. Defaults to %(default)s.')
oprypin7a2d8ca2017-02-06 07:53:41 -080051 parser.add_argument('-c', '--clean', action='store_true', default=False,
52 help='Removes the previously generated build output, if any.')
53 parser.add_argument('-o', '--output-dir', default=SDK_OUTPUT_DIR,
54 help='Specifies a directory to output the build artifacts to. '
55 'If specified together with -c, deletes the dir.')
56 parser.add_argument('-r', '--revision', type=int, default=0,
57 help='Specifies a revision number to embed if building the framework.')
58 parser.add_argument('-e', '--bitcode', action='store_true', default=False,
59 help='Compile with bitcode.')
60 parser.add_argument('--verbose', action='store_true', default=False,
61 help='Debug logging.')
mbonadei585209b2017-02-13 04:59:27 -080062 parser.add_argument('--use-goma', action='store_true', default=False,
63 help='Use goma to build.')
64 parser.add_argument('--extra-gn-args', default=[], nargs='*',
65 help='Additional GN args to be used during Ninja generation.')
66
oprypin7a2d8ca2017-02-06 07:53:41 -080067 return parser.parse_args()
68
69
70def _RunCommand(cmd):
71 logging.debug('Running: %r', cmd)
Henrik Kjellander368b5ff2017-02-15 20:51:26 +010072 subprocess.check_call(cmd, cwd=WEBRTC_SRC_DIR)
oprypin7a2d8ca2017-02-06 07:53:41 -080073
74
75def _CleanArtifacts(output_dir):
76 if os.path.isdir(output_dir):
77 logging.info('Deleting %s', output_dir)
78 shutil.rmtree(output_dir)
79
80
81def BuildWebRTC(output_dir, target_arch, flavor, build_type,
82 ios_deployment_target, libvpx_build_vp9, use_bitcode,
mbonadei585209b2017-02-13 04:59:27 -080083 use_goma, extra_gn_args):
oprypin7a2d8ca2017-02-06 07:53:41 -080084 output_dir = os.path.join(output_dir, target_arch + '_libs')
85 gn_args = ['target_os="ios"', 'ios_enable_code_signing=false',
86 'use_xcode_clang=true', 'is_component_build=false']
87
88 # Add flavor option.
89 if flavor == 'debug':
90 gn_args.append('is_debug=true')
91 elif flavor == 'release':
92 gn_args.append('is_debug=false')
93 else:
94 raise ValueError('Unexpected flavor type: %s' % flavor)
95
96 gn_args.append('target_cpu="%s"' % target_arch)
97
98 gn_args.append('ios_deployment_target="%s"' % ios_deployment_target)
99
100 gn_args.append('rtc_libvpx_build_vp9=' +
101 ('true' if libvpx_build_vp9 else 'false'))
102
103 gn_args.append('enable_ios_bitcode=' +
104 ('true' if use_bitcode else 'false'))
mbonadei585209b2017-02-13 04:59:27 -0800105 gn_args.append('use_goma=' + ('true' if use_goma else 'false'))
oprypin7a2d8ca2017-02-06 07:53:41 -0800106
107 # Generate static or dynamic.
108 if build_type == 'static_only':
109 gn_target_name = 'rtc_sdk_objc'
110 elif build_type == 'framework':
111 gn_target_name = 'rtc_sdk_framework_objc'
kthelgason28922442017-02-28 15:33:26 -0800112 if not use_bitcode:
113 gn_args.append('enable_dsyms=true')
oprypin7a2d8ca2017-02-06 07:53:41 -0800114 gn_args.append('enable_stripping=true')
115 else:
116 raise ValueError('Build type "%s" is not supported.' % build_type)
117
mbonadei7b2797e2017-02-16 01:40:59 -0800118 args_string = ' '.join(gn_args + extra_gn_args)
119 logging.info('Building WebRTC with args: %s', args_string)
mbonadei8714b8f2017-02-15 13:18:57 -0800120
mbonadei7b2797e2017-02-16 01:40:59 -0800121 cmd = ['gn', 'gen', output_dir, '--args=' + args_string]
oprypin7a2d8ca2017-02-06 07:53:41 -0800122 _RunCommand(cmd)
123 logging.info('Building target: %s', gn_target_name)
mbonadei8714b8f2017-02-15 13:18:57 -0800124
oprypin7a2d8ca2017-02-06 07:53:41 -0800125 cmd = ['ninja', '-C', output_dir, gn_target_name]
mbonadei8714b8f2017-02-15 13:18:57 -0800126 if use_goma:
127 cmd.extend(['-j', '200'])
oprypin7a2d8ca2017-02-06 07:53:41 -0800128 _RunCommand(cmd)
129
130 # Strip debug symbols to reduce size.
131 if build_type == 'static_only':
132 gn_target_path = os.path.join(output_dir, 'obj', 'webrtc', 'sdk',
133 'lib%s.a' % gn_target_name)
134 cmd = ['strip', '-S', gn_target_path, '-o',
135 os.path.join(output_dir, 'lib%s.a' % gn_target_name)]
136 _RunCommand(cmd)
137
138
139def main():
140 args = _ParseArgs()
141
142 logging.basicConfig(level=logging.DEBUG if args.verbose else logging.INFO)
143
144 if args.clean:
145 _CleanArtifacts(args.output_dir)
146 return 0
147
oprypin9b0dbd42017-02-13 08:30:01 -0800148 architectures = list(args.arch)
149 # Ignoring x86 except for static libraries for now because of a GN build issue
150 # where the generated dynamic framework has the wrong architectures.
151 if 'x86' in architectures and args.build_type != 'static_only':
152 architectures.remove('x86')
153
oprypin7a2d8ca2017-02-06 07:53:41 -0800154 # Build all architectures.
oprypin9b0dbd42017-02-13 08:30:01 -0800155 for arch in architectures:
oprypin7a2d8ca2017-02-06 07:53:41 -0800156 BuildWebRTC(args.output_dir, arch, args.build_config, args.build_type,
157 IOS_DEPLOYMENT_TARGET, LIBVPX_BUILD_VP9, args.bitcode,
mbonadei585209b2017-02-13 04:59:27 -0800158 args.use_goma, args.extra_gn_args)
oprypin7a2d8ca2017-02-06 07:53:41 -0800159
oprypin7a2d8ca2017-02-06 07:53:41 -0800160 # Create FAT archive.
161 if args.build_type == 'static_only':
oprypin9b0dbd42017-02-13 08:30:01 -0800162 lib_paths = [os.path.join(args.output_dir, arch + '_libs', SDK_LIB_NAME)
163 for arch in architectures]
164 out_lib_path = os.path.join(args.output_dir, SDK_LIB_NAME)
oprypin7a2d8ca2017-02-06 07:53:41 -0800165 # Combine the slices.
oprypin9b0dbd42017-02-13 08:30:01 -0800166 cmd = ['lipo'] + lib_paths + ['-create', '-output', out_lib_path]
oprypin7a2d8ca2017-02-06 07:53:41 -0800167 _RunCommand(cmd)
168
169 elif args.build_type == 'framework':
oprypin9b0dbd42017-02-13 08:30:01 -0800170 lib_paths = [os.path.join(args.output_dir, arch + '_libs')
171 for arch in architectures]
oprypin7a2d8ca2017-02-06 07:53:41 -0800172
173 # Combine the slices.
174 dylib_path = os.path.join(SDK_FRAMEWORK_NAME, 'WebRTC')
oprypin9b0dbd42017-02-13 08:30:01 -0800175 # Dylibs will be combined, all other files are the same across archs.
oprypin7a2d8ca2017-02-06 07:53:41 -0800176 # Use distutils instead of shutil to support merging folders.
177 distutils.dir_util.copy_tree(
oprypin9b0dbd42017-02-13 08:30:01 -0800178 os.path.join(lib_paths[0], SDK_FRAMEWORK_NAME),
oprypin7a2d8ca2017-02-06 07:53:41 -0800179 os.path.join(args.output_dir, SDK_FRAMEWORK_NAME))
oprypin7a2d8ca2017-02-06 07:53:41 -0800180 logging.info('Merging framework slices.')
oprypin9b0dbd42017-02-13 08:30:01 -0800181 dylib_paths = [os.path.join(path, dylib_path) for path in lib_paths]
182 out_dylib_path = os.path.join(args.output_dir, dylib_path)
kthelgason28922442017-02-28 15:33:26 -0800183 try:
184 os.remove(out_dylib_path)
185 except OSError:
186 pass
oprypin9b0dbd42017-02-13 08:30:01 -0800187 cmd = ['lipo'] + dylib_paths + ['-create', '-output', out_dylib_path]
oprypin7a2d8ca2017-02-06 07:53:41 -0800188 _RunCommand(cmd)
189
190 # Merge the dSYM slices.
kthelgason28922442017-02-28 15:33:26 -0800191 lib_dsym_dir_path = os.path.join(lib_paths[0], 'WebRTC.dSYM')
192 if os.path.isdir(lib_dsym_dir_path):
193 distutils.dir_util.copy_tree(lib_dsym_dir_path,
194 os.path.join(args.output_dir, 'WebRTC.dSYM'))
195 logging.info('Merging dSYM slices.')
196 dsym_path = os.path.join('WebRTC.dSYM', 'Contents', 'Resources', 'DWARF',
197 'WebRTC')
198 lib_dsym_paths = [os.path.join(path, dsym_path) for path in lib_paths]
199 out_dsym_path = os.path.join(args.output_dir, dsym_path)
200 try:
201 os.remove(out_dsym_path)
202 except OSError:
203 pass
204 cmd = ['lipo'] + lib_dsym_paths + ['-create', '-output', out_dsym_path]
205 _RunCommand(cmd)
oprypin7a2d8ca2017-02-06 07:53:41 -0800206
207 # Modify the version number.
208 # Format should be <Branch cut MXX>.<Hotfix #>.<Rev #>.
209 # e.g. 55.0.14986 means branch cut 55, no hotfixes, and revision 14986.
210 infoplist_path = os.path.join(args.output_dir, SDK_FRAMEWORK_NAME,
211 'Info.plist')
212 cmd = ['PlistBuddy', '-c',
213 'Print :CFBundleShortVersionString', infoplist_path]
214 major_minor = subprocess.check_output(cmd).strip()
215 version_number = '%s.%s' % (major_minor, args.revision)
216 logging.info('Substituting revision number: %s', version_number)
217 cmd = ['PlistBuddy', '-c',
218 'Set :CFBundleVersion ' + version_number, infoplist_path]
219 _RunCommand(cmd)
220 _RunCommand(['plutil', '-convert', 'binary1', infoplist_path])
221
222 logging.info('Done.')
223 return 0
224
225
226if __name__ == '__main__':
227 sys.exit(main())