diff --git a/tools-webrtc/ios/build_ios_libs.py b/tools-webrtc/ios/build_ios_libs.py new file mode 100755 index 0000000000..550c7a1b70 --- /dev/null +++ b/tools-webrtc/ios/build_ios_libs.py @@ -0,0 +1,221 @@ +#!/usr/bin/env python + +# Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. +# +# Use of this source code is governed by a BSD-style license +# that can be found in the LICENSE file in the root of the source +# tree. An additional intellectual property rights grant can be found +# in the file PATENTS. All contributing project authors may +# be found in the AUTHORS file in the root of the source tree. + +"""WebRTC iOS FAT libraries build script. +Each architecture is compiled separately before being merged together. +By default, the library is created in out_ios_libs/. (Change with -o.) +The headers will be copied to out_ios_libs/include. +""" + +import argparse +import distutils.dir_util +import logging +import os +import shutil +import subprocess +import sys + + +os.environ['PATH'] = '/usr/libexec' + os.pathsep + os.environ['PATH'] + +SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) +WEBRTC_BASE_DIR = os.path.abspath(os.path.join(SCRIPT_DIR, '..', '..')) +SDK_OUTPUT_DIR = os.path.join(WEBRTC_BASE_DIR, 'out_ios_libs') +SDK_LIB_NAME = 'librtc_sdk_objc.a' +SDK_FRAMEWORK_NAME = 'WebRTC.framework' + +ENABLED_ARCHITECTURES = ['arm', 'arm64', 'x64'] +IOS_DEPLOYMENT_TARGET = '8.0' +LIBVPX_BUILD_VP9 = False +CUSTOM_GN_OPTS = [] # example: ['some_option=foo bar', 'other_option=true'] + + +def _ParseArgs(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument('-b', '--build_type', default='framework', + choices=['framework', 'static_only'], + help='The build type. Can be "framework" or "static_only". ' + 'Defaults to "framework".') + parser.add_argument('--build_config', default='release', + choices=['debug', 'release'], + help='The build config. Can be "debug" or "release". ' + 'Defaults to "release".') + parser.add_argument('-c', '--clean', action='store_true', default=False, + help='Removes the previously generated build output, if any.') + parser.add_argument('-o', '--output-dir', default=SDK_OUTPUT_DIR, + help='Specifies a directory to output the build artifacts to. ' + 'If specified together with -c, deletes the dir.') + parser.add_argument('-r', '--revision', type=int, default=0, + help='Specifies a revision number to embed if building the framework.') + parser.add_argument('-e', '--bitcode', action='store_true', default=False, + help='Compile with bitcode.') + parser.add_argument('--verbose', action='store_true', default=False, + help='Debug logging.') + return parser.parse_args() + + +def _RunCommand(cmd): + logging.debug('Running: %r', cmd) + subprocess.check_call(cmd) + + +def _CleanArtifacts(output_dir): + if os.path.isdir(output_dir): + logging.info('Deleting %s', output_dir) + shutil.rmtree(output_dir) + + +def BuildWebRTC(output_dir, target_arch, flavor, build_type, + ios_deployment_target, libvpx_build_vp9, use_bitcode, + custom_gn_options=()): + output_dir = os.path.join(output_dir, target_arch + '_libs') + gn_args = ['target_os="ios"', 'ios_enable_code_signing=false', + 'use_xcode_clang=true', 'is_component_build=false'] + + # Add flavor option. + if flavor == 'debug': + gn_args.append('is_debug=true') + elif flavor == 'release': + gn_args.append('is_debug=false') + else: + raise ValueError('Unexpected flavor type: %s' % flavor) + + gn_args.append('target_cpu="%s"' % target_arch) + + gn_args.append('ios_deployment_target="%s"' % ios_deployment_target) + + gn_args.append('rtc_libvpx_build_vp9=' + + ('true' if libvpx_build_vp9 else 'false')) + + gn_args.append('enable_ios_bitcode=' + + ('true' if use_bitcode else 'false')) + + gn_args.extend(custom_gn_options) + + # Generate static or dynamic. + if build_type == 'static_only': + gn_target_name = 'rtc_sdk_objc' + elif build_type == 'framework': + gn_target_name = 'rtc_sdk_framework_objc' + gn_args.append('enable_dsyms=true') + gn_args.append('enable_stripping=true') + else: + raise ValueError('Build type "%s" is not supported.' % build_type) + + logging.info('Building WebRTC with args: %s', ' '.join(gn_args)) + cmd = ['gn', 'gen', output_dir, + '--args=' + ' '.join(gn_args)] + _RunCommand(cmd) + logging.info('Building target: %s', gn_target_name) + cmd = ['ninja', '-C', output_dir, gn_target_name] + _RunCommand(cmd) + + # Strip debug symbols to reduce size. + if build_type == 'static_only': + gn_target_path = os.path.join(output_dir, 'obj', 'webrtc', 'sdk', + 'lib%s.a' % gn_target_name) + cmd = ['strip', '-S', gn_target_path, '-o', + os.path.join(output_dir, 'lib%s.a' % gn_target_name)] + _RunCommand(cmd) + + +def main(): + args = _ParseArgs() + + logging.basicConfig(level=logging.DEBUG if args.verbose else logging.INFO) + + if args.clean: + _CleanArtifacts(args.output_dir) + return 0 + + # Build all architectures. + for arch in ENABLED_ARCHITECTURES: + BuildWebRTC(args.output_dir, arch, args.build_config, args.build_type, + IOS_DEPLOYMENT_TARGET, LIBVPX_BUILD_VP9, args.bitcode, + CUSTOM_GN_OPTS) + + # Ignoring x86 except for static libraries for now because of a GN build issue + # where the generated dynamic framework has the wrong architectures. + + # Create FAT archive. + if args.build_type == 'static_only': + BuildWebRTC(args.output_dir, 'x86', args.build_config, args.build_type, + IOS_DEPLOYMENT_TARGET, LIBVPX_BUILD_VP9, args.bitcode, + CUSTOM_GN_OPTS) + + arm_lib_path = os.path.join(args.output_dir, 'arm_libs', SDK_LIB_NAME) + arm64_lib_path = os.path.join(args.output_dir, 'arm64_libs', SDK_LIB_NAME) + x64_lib_path = os.path.join(args.output_dir, 'x64_libs', SDK_LIB_NAME) + x86_lib_path = os.path.join(args.output_dir, 'x86_libs', SDK_LIB_NAME) + + # Combine the slices. + cmd = ['lipo', arm_lib_path, arm64_lib_path, x64_lib_path, x86_lib_path, + '-create', '-output', os.path.join(args.output_dir, SDK_LIB_NAME)] + _RunCommand(cmd) + + elif args.build_type == 'framework': + arm_lib_path = os.path.join(args.output_dir, 'arm_libs') + arm64_lib_path = os.path.join(args.output_dir, 'arm64_libs') + x64_lib_path = os.path.join(args.output_dir, 'x64_libs') + + # Combine the slices. + dylib_path = os.path.join(SDK_FRAMEWORK_NAME, 'WebRTC') + # Use distutils instead of shutil to support merging folders. + distutils.dir_util.copy_tree( + os.path.join(arm64_lib_path, SDK_FRAMEWORK_NAME), + os.path.join(args.output_dir, SDK_FRAMEWORK_NAME)) + try: + os.remove(os.path.join(args.output_dir, dylib_path)) + except OSError: + pass + logging.info('Merging framework slices.') + cmd = ['lipo', os.path.join(arm_lib_path, dylib_path), + os.path.join(arm64_lib_path, dylib_path), + os.path.join(x64_lib_path, dylib_path), + '-create', '-output', os.path.join(args.output_dir, dylib_path)] + _RunCommand(cmd) + + # Merge the dSYM slices. + dsym_path = os.path.join('WebRTC.dSYM', 'Contents', 'Resources', 'DWARF', + 'WebRTC') + distutils.dir_util.copy_tree(os.path.join(arm64_lib_path, 'WebRTC.dSYM'), + os.path.join(args.output_dir, 'WebRTC.dSYM')) + try: + os.remove(os.path.join(args.output_dir, dsym_path)) + except OSError: + pass + logging.info('Merging dSYM slices.') + cmd = ['lipo', os.path.join(arm_lib_path, dsym_path), + os.path.join(arm64_lib_path, dsym_path), + os.path.join(x64_lib_path, dsym_path), + '-create', '-output', os.path.join(args.output_dir, dsym_path)] + _RunCommand(cmd) + + # Modify the version number. + # Format should be ... + # e.g. 55.0.14986 means branch cut 55, no hotfixes, and revision 14986. + infoplist_path = os.path.join(args.output_dir, SDK_FRAMEWORK_NAME, + 'Info.plist') + cmd = ['PlistBuddy', '-c', + 'Print :CFBundleShortVersionString', infoplist_path] + major_minor = subprocess.check_output(cmd).strip() + version_number = '%s.%s' % (major_minor, args.revision) + logging.info('Substituting revision number: %s', version_number) + cmd = ['PlistBuddy', '-c', + 'Set :CFBundleVersion ' + version_number, infoplist_path] + _RunCommand(cmd) + _RunCommand(['plutil', '-convert', 'binary1', infoplist_path]) + + logging.info('Done.') + return 0 + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/tools-webrtc/ios/build_ios_libs.sh b/tools-webrtc/ios/build_ios_libs.sh index 144152750a..c8d659c7e6 100755 --- a/tools-webrtc/ios/build_ios_libs.sh +++ b/tools-webrtc/ios/build_ios_libs.sh @@ -1,6 +1,6 @@ #!/bin/bash -# Copyright 2015 The WebRTC project authors. All Rights Reserved. +# Copyright 2017 The WebRTC project authors. All Rights Reserved. # # Use of this source code is governed by a BSD-style license # that can be found in the LICENSE file in the root of the source @@ -8,202 +8,8 @@ # in the file PATENTS. All contributing project authors may # be found in the AUTHORS file in the root of the source tree. -# Generates static FAT libraries for ios in out_ios_libs. +# This script has been rewritten in Python. Temporary "redirect": -# Exit on errors. -set -e +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" -# Environment -export PATH=/usr/libexec:$PATH - -SCRIPT_DIR=$(cd $(dirname $0) && pwd) -WEBRTC_BASE_DIR=${SCRIPT_DIR}/../.. - -function clean_artifacts { - local output_dir=$1 - if [[ -d ${output_dir} ]]; then - echo "Deleting ${output_dir}" - rm -r ${output_dir} - fi -} - -function build_webrtc { - local target_arch=$1 - local flavor=$2 - local build_type=$3 - local ios_deployment_target=$4 - local libvpx_build_vp9=$5 - local use_bitcode=$6 - local custom_gn_options=$7 - - OUTPUT_DIR=${SDK_OUTPUT_DIR}/${target_arch}_libs - GN_ARGS="target_os=\"ios\" ios_enable_code_signing=false \ -use_xcode_clang=true is_component_build=false" - - # Add flavor option. - if [[ ${flavor} = "debug" ]]; then - GN_ARGS="${GN_ARGS} is_debug=true" - elif [[ ${flavor} = "release" ]]; then - GN_ARGS="${GN_ARGS} is_debug=false" - else - echo "Unexpected flavor type: ${flavor}" - exit 1 - fi - - # Add the specified architecture. - GN_ARGS="${GN_ARGS} target_cpu=\"${target_arch}\"" - - # Add deployment target. - GN_ARGS="${GN_ARGS} ios_deployment_target=\"${ios_deployment_target}\"" - - # Add vp9 option. - GN_ARGS="${GN_ARGS} rtc_libvpx_build_vp9=${libvpx_build_vp9}" - - # Add bitcode option. - GN_ARGS="${GN_ARGS} enable_ios_bitcode=${use_bitcode}" - - # Add custom options. - if [[ -n "${custom_gn_options}" ]]; then - GN_ARGS="${GN_ARGS} ${custom_gn_options}" - fi - - # Generate static or dynamic. - if [[ ${build_type} = "static_only" ]]; then - GN_TARGET_NAME="rtc_sdk_objc" - elif [[ ${build_type} == "framework" ]]; then - GN_TARGET_NAME="rtc_sdk_framework_objc" - GN_ARGS="${GN_ARGS} enable_dsyms=true enable_stripping=true" - else - echo "Build type \"${build_type}\" is not supported." - exit 1 - fi - - echo "Building WebRTC with args: ${GN_ARGS}" - gn gen ${OUTPUT_DIR} --args="${GN_ARGS}" - echo "Building target: ${GN_TARGET_NAME}" - ninja -C ${OUTPUT_DIR} ${GN_TARGET_NAME} - - # Strip debug symbols to reduce size. - if [[ ${build_type} = "static_only" ]]; then - strip -S ${OUTPUT_DIR}/obj/webrtc/sdk/lib${GN_TARGET_NAME}.a -o \ - ${OUTPUT_DIR}/lib${GN_TARGET_NAME}.a - fi -} - -function usage { - echo "WebRTC iOS FAT libraries build script." - echo "Each architecture is compiled separately before being merged together." - echo "By default, the library is created in out_ios_libs/. (Change with -o.)" - echo "The headers will be copied to out_ios_libs/include." - echo "Usage: $0 [-h] [-b build_type] [-c] [-o output_dir] [-r rev_num] [-e]" - echo " -h Print this help." - echo " -b The build type. Can be \"framework\" or \"static_only\"." - echo " Defaults to \"framework\"." - echo " -c Removes the previously generated build output, if any." - echo " -o Specifies a directory to output the build artifacts to." - echo " If specified together with -c, deletes the dir." - echo " -r Specifies a revision number to embed if building the framework." - echo " -e Compile with bitcode." - exit 0 -} - -SDK_OUTPUT_DIR=${WEBRTC_BASE_DIR}/out_ios_libs -SDK_LIB_NAME="librtc_sdk_objc.a" -SDK_FRAMEWORK_NAME="WebRTC.framework" - -BUILD_FLAVOR="release" -BUILD_TYPE="framework" -ENABLED_ARCHITECTURES=("arm" "arm64" "x64") -IOS_DEPLOYMENT_TARGET="8.0" -LIBVPX_BUILD_VP9="false" -USE_BITCODE="false" -CUSTOM_GN_OPTS="" -WEBRTC_REVISION="0" - -# Parse arguments. -while getopts "hb:co:r:e" opt; do - case "${opt}" in - h) usage;; - b) BUILD_TYPE="${OPTARG}";; - c) PERFORM_CLEAN=1;; - e) USE_BITCODE="true";; - o) SDK_OUTPUT_DIR="${OPTARG}";; - r) WEBRTC_REVISION="${OPTARG}";; - *) - usage - exit 1 - ;; - esac -done - -if [[ ${PERFORM_CLEAN} -ne 0 ]]; then - clean_artifacts ${SDK_OUTPUT_DIR} - exit 0 -fi - -# Build all architectures. -for arch in ${ENABLED_ARCHITECTURES[*]}; do - build_webrtc $arch ${BUILD_FLAVOR} ${BUILD_TYPE} \ - ${IOS_DEPLOYMENT_TARGET} ${LIBVPX_BUILD_VP9} ${USE_BITCODE} \ - ${CUSTOM_GN_OPTS} -done - -# Ignoring x86 except for static libraries for now because of a GN build issue -# where the generated dynamic framework has the wrong architectures. - -# Create FAT archive. -if [[ ${BUILD_TYPE} = "static_only" ]]; then - build_webrtc "x86" ${BUILD_FLAVOR} ${BUILD_TYPE} \ - ${IOS_DEPLOYMENT_TARGET} ${LIBVPX_BUILD_VP9} ${USE_BITCODE} \ - ${CUSTOM_GN_OPTS} - - ARM_LIB_PATH=${SDK_OUTPUT_DIR}/arm_libs/${SDK_LIB_NAME} - ARM64_LIB_PATH=${SDK_OUTPUT_DIR}/arm64_libs/${SDK_LIB_NAME} - X64_LIB_PATH=${SDK_OUTPUT_DIR}/x64_libs/${SDK_LIB_NAME} - X86_LIB_PATH=${SDK_OUTPUT_DIR}/x86_libs/${SDK_LIB_NAME} - - # Combine the slices. - lipo ${ARM_LIB_PATH} ${ARM64_LIB_PATH} ${X64_LIB_PATH} ${X86_LIB_PATH} \ - -create -output ${SDK_OUTPUT_DIR}/${SDK_LIB_NAME} -elif [[ ${BUILD_TYPE} = "framework" ]]; then - ARM_LIB_PATH=${SDK_OUTPUT_DIR}/arm_libs - ARM64_LIB_PATH=${SDK_OUTPUT_DIR}/arm64_libs - X64_LIB_PATH=${SDK_OUTPUT_DIR}/x64_libs - X86_LIB_PATH=${SDK_OUTPUT_DIR}/x86_libs - - # Combine the slices. - DYLIB_PATH="WebRTC.framework/WebRTC" - cp -R ${ARM64_LIB_PATH}/WebRTC.framework ${SDK_OUTPUT_DIR} - rm ${SDK_OUTPUT_DIR}/${DYLIB_PATH} - echo "Merging framework slices." - lipo ${ARM_LIB_PATH}/${DYLIB_PATH} \ - ${ARM64_LIB_PATH}/${DYLIB_PATH} \ - ${X64_LIB_PATH}/${DYLIB_PATH} \ - -create -output ${SDK_OUTPUT_DIR}/${DYLIB_PATH} - - # Merge the dSYM slices. - DSYM_PATH="WebRTC.dSYM/Contents/Resources/DWARF/WebRTC" - cp -R ${ARM64_LIB_PATH}/WebRTC.dSYM ${SDK_OUTPUT_DIR} - rm ${SDK_OUTPUT_DIR}/${DSYM_PATH} - echo "Merging dSYM slices." - lipo ${ARM_LIB_PATH}/${DSYM_PATH} \ - ${ARM64_LIB_PATH}/${DSYM_PATH} \ - ${X64_LIB_PATH}/${DSYM_PATH} \ - -create -output ${SDK_OUTPUT_DIR}/${DSYM_PATH} - - # Modify the version number. - # Format should be ... - # e.g. 55.0.14986 means branch cut 55, no hotfixes, and revision number 14986. - INFOPLIST_PATH=${SDK_OUTPUT_DIR}/WebRTC.framework/Info.plist - MAJOR_MINOR=$(PlistBuddy -c "Print :CFBundleShortVersionString" \ - ${INFOPLIST_PATH}) - VERSION_NUMBER="${MAJOR_MINOR}.${WEBRTC_REVISION}" - echo "Substituting revision number: ${VERSION_NUMBER}" - PlistBuddy -c "Set :CFBundleVersion ${VERSION_NUMBER}" ${INFOPLIST_PATH} - plutil -convert binary1 ${INFOPLIST_PATH} -else - echo "BUILD_TYPE ${BUILD_TYPE} not supported." - exit 1 -fi - -echo "Done." +exec "$SCRIPT_DIR/build_ios_libs.py" "$@"