blob: fc6e88b65dca76e3e7aa1b271cbe49834c329c52 [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__))
Henrik Kjellander368b5ff2017-02-15 20:51:26 +010029WEBRTC_SRC_DIR = os.path.abspath(os.path.join(SCRIPT_DIR, '..', '..'))
30SDK_OUTPUT_DIR = os.path.join(WEBRTC_SRC_DIR, 'out_ios_libs')
oprypin7a2d8ca2017-02-06 07:53:41 -080031SDK_LIB_NAME = 'librtc_sdk_objc.a'
32SDK_FRAMEWORK_NAME = 'WebRTC.framework'
33
oprypin9b0dbd42017-02-13 08:30:01 -080034DEFAULT_ARCHS = ENABLED_ARCHS = ['arm64', 'arm', 'x64', 'x86']
oprypin7a2d8ca2017-02-06 07:53:41 -080035IOS_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".')
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.')
54 parser.add_argument('-o', '--output-dir', default=SDK_OUTPUT_DIR,
55 help='Specifies a directory to output the build artifacts to. '
56 'If specified together with -c, deletes the dir.')
57 parser.add_argument('-r', '--revision', type=int, default=0,
58 help='Specifies a revision number to embed if building the framework.')
59 parser.add_argument('-e', '--bitcode', action='store_true', default=False,
60 help='Compile with bitcode.')
61 parser.add_argument('--verbose', action='store_true', default=False,
62 help='Debug logging.')
mbonadei585209b2017-02-13 04:59:27 -080063 parser.add_argument('--use-goma', action='store_true', default=False,
64 help='Use goma to build.')
65 parser.add_argument('--extra-gn-args', default=[], nargs='*',
66 help='Additional GN args to be used during Ninja generation.')
67
oprypin7a2d8ca2017-02-06 07:53:41 -080068 return parser.parse_args()
69
70
71def _RunCommand(cmd):
72 logging.debug('Running: %r', cmd)
Henrik Kjellander368b5ff2017-02-15 20:51:26 +010073 subprocess.check_call(cmd, cwd=WEBRTC_SRC_DIR)
oprypin7a2d8ca2017-02-06 07:53:41 -080074
75
76def _CleanArtifacts(output_dir):
77 if os.path.isdir(output_dir):
78 logging.info('Deleting %s', output_dir)
79 shutil.rmtree(output_dir)
80
81
82def BuildWebRTC(output_dir, target_arch, flavor, build_type,
83 ios_deployment_target, libvpx_build_vp9, use_bitcode,
mbonadei585209b2017-02-13 04:59:27 -080084 use_goma, extra_gn_args):
oprypin7a2d8ca2017-02-06 07:53:41 -080085 output_dir = os.path.join(output_dir, target_arch + '_libs')
86 gn_args = ['target_os="ios"', 'ios_enable_code_signing=false',
87 'use_xcode_clang=true', 'is_component_build=false']
88
89 # Add flavor option.
90 if flavor == 'debug':
91 gn_args.append('is_debug=true')
92 elif flavor == 'release':
93 gn_args.append('is_debug=false')
94 else:
95 raise ValueError('Unexpected flavor type: %s' % flavor)
96
97 gn_args.append('target_cpu="%s"' % target_arch)
98
99 gn_args.append('ios_deployment_target="%s"' % ios_deployment_target)
100
101 gn_args.append('rtc_libvpx_build_vp9=' +
102 ('true' if libvpx_build_vp9 else 'false'))
103
104 gn_args.append('enable_ios_bitcode=' +
105 ('true' if use_bitcode else 'false'))
mbonadei585209b2017-02-13 04:59:27 -0800106 gn_args.append('use_goma=' + ('true' if use_goma else 'false'))
oprypin7a2d8ca2017-02-06 07:53:41 -0800107
108 # Generate static or dynamic.
109 if build_type == 'static_only':
110 gn_target_name = 'rtc_sdk_objc'
111 elif build_type == 'framework':
112 gn_target_name = 'rtc_sdk_framework_objc'
113 gn_args.append('enable_dsyms=true')
114 gn_args.append('enable_stripping=true')
115 else:
116 raise ValueError('Build type "%s" is not supported.' % build_type)
117
118 logging.info('Building WebRTC with args: %s', ' '.join(gn_args))
119 cmd = ['gn', 'gen', output_dir,
mbonadei585209b2017-02-13 04:59:27 -0800120 '--args=' + ' '.join(gn_args + extra_gn_args)]
oprypin7a2d8ca2017-02-06 07:53:41 -0800121 _RunCommand(cmd)
122 logging.info('Building target: %s', gn_target_name)
123 cmd = ['ninja', '-C', output_dir, gn_target_name]
124 _RunCommand(cmd)
125
126 # Strip debug symbols to reduce size.
127 if build_type == 'static_only':
128 gn_target_path = os.path.join(output_dir, 'obj', 'webrtc', 'sdk',
129 'lib%s.a' % gn_target_name)
130 cmd = ['strip', '-S', gn_target_path, '-o',
131 os.path.join(output_dir, 'lib%s.a' % gn_target_name)]
132 _RunCommand(cmd)
133
134
135def main():
136 args = _ParseArgs()
137
138 logging.basicConfig(level=logging.DEBUG if args.verbose else logging.INFO)
139
140 if args.clean:
141 _CleanArtifacts(args.output_dir)
142 return 0
143
oprypin9b0dbd42017-02-13 08:30:01 -0800144 architectures = list(args.arch)
145 # Ignoring x86 except for static libraries for now because of a GN build issue
146 # where the generated dynamic framework has the wrong architectures.
147 if 'x86' in architectures and args.build_type != 'static_only':
148 architectures.remove('x86')
149
oprypin7a2d8ca2017-02-06 07:53:41 -0800150 # Build all architectures.
oprypin9b0dbd42017-02-13 08:30:01 -0800151 for arch in architectures:
oprypin7a2d8ca2017-02-06 07:53:41 -0800152 BuildWebRTC(args.output_dir, arch, 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
oprypin7a2d8ca2017-02-06 07:53:41 -0800156 # Create FAT archive.
157 if args.build_type == 'static_only':
oprypin9b0dbd42017-02-13 08:30:01 -0800158 lib_paths = [os.path.join(args.output_dir, arch + '_libs', SDK_LIB_NAME)
159 for arch in architectures]
160 out_lib_path = os.path.join(args.output_dir, SDK_LIB_NAME)
oprypin7a2d8ca2017-02-06 07:53:41 -0800161 # Combine the slices.
oprypin9b0dbd42017-02-13 08:30:01 -0800162 cmd = ['lipo'] + lib_paths + ['-create', '-output', out_lib_path]
oprypin7a2d8ca2017-02-06 07:53:41 -0800163 _RunCommand(cmd)
164
165 elif args.build_type == 'framework':
oprypin9b0dbd42017-02-13 08:30:01 -0800166 lib_paths = [os.path.join(args.output_dir, arch + '_libs')
167 for arch in architectures]
oprypin7a2d8ca2017-02-06 07:53:41 -0800168
169 # Combine the slices.
170 dylib_path = os.path.join(SDK_FRAMEWORK_NAME, 'WebRTC')
oprypin9b0dbd42017-02-13 08:30:01 -0800171 # Dylibs will be combined, all other files are the same across archs.
oprypin7a2d8ca2017-02-06 07:53:41 -0800172 # Use distutils instead of shutil to support merging folders.
173 distutils.dir_util.copy_tree(
oprypin9b0dbd42017-02-13 08:30:01 -0800174 os.path.join(lib_paths[0], SDK_FRAMEWORK_NAME),
oprypin7a2d8ca2017-02-06 07:53:41 -0800175 os.path.join(args.output_dir, SDK_FRAMEWORK_NAME))
176 try:
177 os.remove(os.path.join(args.output_dir, dylib_path))
178 except OSError:
179 pass
180 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)
183 cmd = ['lipo'] + dylib_paths + ['-create', '-output', out_dylib_path]
oprypin7a2d8ca2017-02-06 07:53:41 -0800184 _RunCommand(cmd)
185
186 # Merge the dSYM slices.
187 dsym_path = os.path.join('WebRTC.dSYM', 'Contents', 'Resources', 'DWARF',
188 'WebRTC')
oprypin9b0dbd42017-02-13 08:30:01 -0800189 distutils.dir_util.copy_tree(os.path.join(lib_paths[0], 'WebRTC.dSYM'),
oprypin7a2d8ca2017-02-06 07:53:41 -0800190 os.path.join(args.output_dir, 'WebRTC.dSYM'))
191 try:
192 os.remove(os.path.join(args.output_dir, dsym_path))
193 except OSError:
194 pass
195 logging.info('Merging dSYM slices.')
oprypin9b0dbd42017-02-13 08:30:01 -0800196 dsym_paths = [os.path.join(path, dsym_path) for path in lib_paths]
197 out_dsym_path = os.path.join(args.output_dir, dsym_path)
198 cmd = ['lipo'] + dsym_paths + ['-create', '-output', out_dsym_path]
oprypin7a2d8ca2017-02-06 07:53:41 -0800199 _RunCommand(cmd)
200
201 # Modify the version number.
202 # Format should be <Branch cut MXX>.<Hotfix #>.<Rev #>.
203 # e.g. 55.0.14986 means branch cut 55, no hotfixes, and revision 14986.
204 infoplist_path = os.path.join(args.output_dir, SDK_FRAMEWORK_NAME,
205 'Info.plist')
206 cmd = ['PlistBuddy', '-c',
207 'Print :CFBundleShortVersionString', infoplist_path]
208 major_minor = subprocess.check_output(cmd).strip()
209 version_number = '%s.%s' % (major_minor, args.revision)
210 logging.info('Substituting revision number: %s', version_number)
211 cmd = ['PlistBuddy', '-c',
212 'Set :CFBundleVersion ' + version_number, infoplist_path]
213 _RunCommand(cmd)
214 _RunCommand(['plutil', '-convert', 'binary1', infoplist_path])
215
216 logging.info('Done.')
217 return 0
218
219
220if __name__ == '__main__':
221 sys.exit(main())