blob: 2893df1df974f6f5560a75b1253d0aea71a953da [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.)
14The headers will be copied to out_ios_libs/include.
15"""
16
17import argparse
18import distutils.dir_util
19import logging
20import os
21import shutil
22import subprocess
23import sys
24
25
26os.environ['PATH'] = '/usr/libexec' + os.pathsep + os.environ['PATH']
27
28SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
29WEBRTC_BASE_DIR = os.path.abspath(os.path.join(SCRIPT_DIR, '..', '..'))
30SDK_OUTPUT_DIR = os.path.join(WEBRTC_BASE_DIR, 'out_ios_libs')
31SDK_LIB_NAME = 'librtc_sdk_objc.a'
32SDK_FRAMEWORK_NAME = 'WebRTC.framework'
33
34ENABLED_ARCHITECTURES = ['arm', 'arm64', 'x64']
35IOS_DEPLOYMENT_TARGET = '8.0'
36LIBVPX_BUILD_VP9 = False
oprypin7a2d8ca2017-02-06 07:53:41 -080037
38
39def _ParseArgs():
40 parser = argparse.ArgumentParser(description=__doc__)
41 parser.add_argument('-b', '--build_type', default='framework',
42 choices=['framework', 'static_only'],
43 help='The build type. Can be "framework" or "static_only". '
44 'Defaults to "framework".')
45 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".')
49 parser.add_argument('-c', '--clean', action='store_true', default=False,
50 help='Removes the previously generated build output, if any.')
51 parser.add_argument('-o', '--output-dir', default=SDK_OUTPUT_DIR,
52 help='Specifies a directory to output the build artifacts to. '
53 'If specified together with -c, deletes the dir.')
54 parser.add_argument('-r', '--revision', type=int, default=0,
55 help='Specifies a revision number to embed if building the framework.')
56 parser.add_argument('-e', '--bitcode', action='store_true', default=False,
57 help='Compile with bitcode.')
58 parser.add_argument('--verbose', action='store_true', default=False,
59 help='Debug logging.')
mbonadei585209b2017-02-13 04:59:27 -080060 parser.add_argument('--use-goma', action='store_true', default=False,
61 help='Use goma to build.')
62 parser.add_argument('--extra-gn-args', default=[], nargs='*',
63 help='Additional GN args to be used during Ninja generation.')
64
oprypin7a2d8ca2017-02-06 07:53:41 -080065 return parser.parse_args()
66
67
68def _RunCommand(cmd):
69 logging.debug('Running: %r', cmd)
70 subprocess.check_call(cmd)
71
72
73def _CleanArtifacts(output_dir):
74 if os.path.isdir(output_dir):
75 logging.info('Deleting %s', output_dir)
76 shutil.rmtree(output_dir)
77
78
79def BuildWebRTC(output_dir, target_arch, flavor, build_type,
80 ios_deployment_target, libvpx_build_vp9, use_bitcode,
mbonadei585209b2017-02-13 04:59:27 -080081 use_goma, extra_gn_args):
oprypin7a2d8ca2017-02-06 07:53:41 -080082 output_dir = os.path.join(output_dir, target_arch + '_libs')
83 gn_args = ['target_os="ios"', 'ios_enable_code_signing=false',
84 'use_xcode_clang=true', 'is_component_build=false']
85
86 # Add flavor option.
87 if flavor == 'debug':
88 gn_args.append('is_debug=true')
89 elif flavor == 'release':
90 gn_args.append('is_debug=false')
91 else:
92 raise ValueError('Unexpected flavor type: %s' % flavor)
93
94 gn_args.append('target_cpu="%s"' % target_arch)
95
96 gn_args.append('ios_deployment_target="%s"' % ios_deployment_target)
97
98 gn_args.append('rtc_libvpx_build_vp9=' +
99 ('true' if libvpx_build_vp9 else 'false'))
100
101 gn_args.append('enable_ios_bitcode=' +
102 ('true' if use_bitcode else 'false'))
mbonadei585209b2017-02-13 04:59:27 -0800103 gn_args.append('use_goma=' + ('true' if use_goma else 'false'))
oprypin7a2d8ca2017-02-06 07:53:41 -0800104
105 # Generate static or dynamic.
106 if build_type == 'static_only':
107 gn_target_name = 'rtc_sdk_objc'
108 elif build_type == 'framework':
109 gn_target_name = 'rtc_sdk_framework_objc'
110 gn_args.append('enable_dsyms=true')
111 gn_args.append('enable_stripping=true')
112 else:
113 raise ValueError('Build type "%s" is not supported.' % build_type)
114
115 logging.info('Building WebRTC with args: %s', ' '.join(gn_args))
116 cmd = ['gn', 'gen', output_dir,
mbonadei585209b2017-02-13 04:59:27 -0800117 '--args=' + ' '.join(gn_args + extra_gn_args)]
oprypin7a2d8ca2017-02-06 07:53:41 -0800118 _RunCommand(cmd)
119 logging.info('Building target: %s', gn_target_name)
120 cmd = ['ninja', '-C', output_dir, gn_target_name]
121 _RunCommand(cmd)
122
123 # Strip debug symbols to reduce size.
124 if build_type == 'static_only':
125 gn_target_path = os.path.join(output_dir, 'obj', 'webrtc', 'sdk',
126 'lib%s.a' % gn_target_name)
127 cmd = ['strip', '-S', gn_target_path, '-o',
128 os.path.join(output_dir, 'lib%s.a' % gn_target_name)]
129 _RunCommand(cmd)
130
131
132def main():
133 args = _ParseArgs()
134
135 logging.basicConfig(level=logging.DEBUG if args.verbose else logging.INFO)
136
137 if args.clean:
138 _CleanArtifacts(args.output_dir)
139 return 0
140
141 # Build all architectures.
142 for arch in ENABLED_ARCHITECTURES:
143 BuildWebRTC(args.output_dir, arch, args.build_config, args.build_type,
144 IOS_DEPLOYMENT_TARGET, LIBVPX_BUILD_VP9, args.bitcode,
mbonadei585209b2017-02-13 04:59:27 -0800145 args.use_goma, args.extra_gn_args)
oprypin7a2d8ca2017-02-06 07:53:41 -0800146
147 # Ignoring x86 except for static libraries for now because of a GN build issue
148 # where the generated dynamic framework has the wrong architectures.
149
150 # Create FAT archive.
151 if args.build_type == 'static_only':
152 BuildWebRTC(args.output_dir, 'x86', args.build_config, args.build_type,
153 IOS_DEPLOYMENT_TARGET, LIBVPX_BUILD_VP9, args.bitcode,
mbonadei585209b2017-02-13 04:59:27 -0800154 args.use_goma, args.extra_gn_args)
oprypin7a2d8ca2017-02-06 07:53:41 -0800155
156 arm_lib_path = os.path.join(args.output_dir, 'arm_libs', SDK_LIB_NAME)
157 arm64_lib_path = os.path.join(args.output_dir, 'arm64_libs', SDK_LIB_NAME)
158 x64_lib_path = os.path.join(args.output_dir, 'x64_libs', SDK_LIB_NAME)
159 x86_lib_path = os.path.join(args.output_dir, 'x86_libs', SDK_LIB_NAME)
160
161 # Combine the slices.
162 cmd = ['lipo', arm_lib_path, arm64_lib_path, x64_lib_path, x86_lib_path,
163 '-create', '-output', os.path.join(args.output_dir, SDK_LIB_NAME)]
164 _RunCommand(cmd)
165
166 elif args.build_type == 'framework':
167 arm_lib_path = os.path.join(args.output_dir, 'arm_libs')
168 arm64_lib_path = os.path.join(args.output_dir, 'arm64_libs')
169 x64_lib_path = os.path.join(args.output_dir, 'x64_libs')
170
171 # Combine the slices.
172 dylib_path = os.path.join(SDK_FRAMEWORK_NAME, 'WebRTC')
173 # Use distutils instead of shutil to support merging folders.
174 distutils.dir_util.copy_tree(
175 os.path.join(arm64_lib_path, SDK_FRAMEWORK_NAME),
176 os.path.join(args.output_dir, SDK_FRAMEWORK_NAME))
177 try:
178 os.remove(os.path.join(args.output_dir, dylib_path))
179 except OSError:
180 pass
181 logging.info('Merging framework slices.')
182 cmd = ['lipo', os.path.join(arm_lib_path, dylib_path),
183 os.path.join(arm64_lib_path, dylib_path),
184 os.path.join(x64_lib_path, dylib_path),
185 '-create', '-output', os.path.join(args.output_dir, dylib_path)]
186 _RunCommand(cmd)
187
188 # Merge the dSYM slices.
189 dsym_path = os.path.join('WebRTC.dSYM', 'Contents', 'Resources', 'DWARF',
190 'WebRTC')
191 distutils.dir_util.copy_tree(os.path.join(arm64_lib_path, 'WebRTC.dSYM'),
192 os.path.join(args.output_dir, 'WebRTC.dSYM'))
193 try:
194 os.remove(os.path.join(args.output_dir, dsym_path))
195 except OSError:
196 pass
197 logging.info('Merging dSYM slices.')
198 cmd = ['lipo', os.path.join(arm_lib_path, dsym_path),
199 os.path.join(arm64_lib_path, dsym_path),
200 os.path.join(x64_lib_path, dsym_path),
201 '-create', '-output', os.path.join(args.output_dir, dsym_path)]
202 _RunCommand(cmd)
203
204 # Modify the version number.
205 # Format should be <Branch cut MXX>.<Hotfix #>.<Rev #>.
206 # e.g. 55.0.14986 means branch cut 55, no hotfixes, and revision 14986.
207 infoplist_path = os.path.join(args.output_dir, SDK_FRAMEWORK_NAME,
208 'Info.plist')
209 cmd = ['PlistBuddy', '-c',
210 'Print :CFBundleShortVersionString', infoplist_path]
211 major_minor = subprocess.check_output(cmd).strip()
212 version_number = '%s.%s' % (major_minor, args.revision)
213 logging.info('Substituting revision number: %s', version_number)
214 cmd = ['PlistBuddy', '-c',
215 'Set :CFBundleVersion ' + version_number, infoplist_path]
216 _RunCommand(cmd)
217 _RunCommand(['plutil', '-convert', 'binary1', infoplist_path])
218
219 logging.info('Done.')
220 return 0
221
222
223if __name__ == '__main__':
224 sys.exit(main())