summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/tools_webrtc/ios
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/libwebrtc/tools_webrtc/ios')
-rw-r--r--third_party/libwebrtc/tools_webrtc/ios/OWNERS1
-rwxr-xr-xthird_party/libwebrtc/tools_webrtc/ios/build_ios_libs.py340
-rwxr-xr-xthird_party/libwebrtc/tools_webrtc/ios/build_ios_libs.sh15
-rw-r--r--third_party/libwebrtc/tools_webrtc/ios/generate_modulemap.py34
-rw-r--r--third_party/libwebrtc/tools_webrtc/ios/generate_umbrella_header.py50
-rwxr-xr-xthird_party/libwebrtc/tools_webrtc/ios/merge_ios_libs.py126
-rw-r--r--third_party/libwebrtc/tools_webrtc/ios/no_op.cc14
-rw-r--r--third_party/libwebrtc/tools_webrtc/ios/objc_app.plist24
8 files changed, 604 insertions, 0 deletions
diff --git a/third_party/libwebrtc/tools_webrtc/ios/OWNERS b/third_party/libwebrtc/tools_webrtc/ios/OWNERS
new file mode 100644
index 0000000000..cd06158b7f
--- /dev/null
+++ b/third_party/libwebrtc/tools_webrtc/ios/OWNERS
@@ -0,0 +1 @@
+tkchin@webrtc.org
diff --git a/third_party/libwebrtc/tools_webrtc/ios/build_ios_libs.py b/third_party/libwebrtc/tools_webrtc/ios/build_ios_libs.py
new file mode 100755
index 0000000000..01a95b08c4
--- /dev/null
+++ b/third_party/libwebrtc/tools_webrtc/ios/build_ios_libs.py
@@ -0,0 +1,340 @@
+#!/usr/bin/env vpython3
+
+# 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 XCFramework build script.
+Each architecture is compiled separately before being merged together.
+By default, the library is created in out_ios_libs/. (Change with -o.)
+"""
+
+import argparse
+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__))
+SRC_DIR = os.path.abspath(os.path.join(SCRIPT_DIR, '..', '..'))
+sys.path.append(os.path.join(SRC_DIR, 'build'))
+import find_depot_tools
+
+SDK_OUTPUT_DIR = os.path.join(SRC_DIR, 'out_ios_libs')
+SDK_FRAMEWORK_NAME = 'WebRTC.framework'
+SDK_DSYM_NAME = 'WebRTC.dSYM'
+SDK_XCFRAMEWORK_NAME = 'WebRTC.xcframework'
+
+ENABLED_ARCHS = [
+ 'device:arm64', 'simulator:arm64', 'simulator:x64',
+ 'catalyst:arm64', 'catalyst:x64',
+ 'arm64', 'x64'
+]
+DEFAULT_ARCHS = [
+ 'device:arm64', 'simulator:arm64', 'simulator:x64'
+]
+IOS_DEPLOYMENT_TARGET = {
+ 'device': '12.0',
+ 'simulator': '12.0',
+ 'catalyst': '14.0'
+}
+LIBVPX_BUILD_VP9 = False
+
+sys.path.append(os.path.join(SCRIPT_DIR, '..', 'libs'))
+from generate_licenses import LicenseBuilder
+
+
+def _ParseArgs():
+ parser = argparse.ArgumentParser(description=__doc__)
+ 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('--arch',
+ nargs='+',
+ default=DEFAULT_ARCHS,
+ choices=ENABLED_ARCHS,
+ help='Architectures to build. Defaults to %(default)s.')
+ parser.add_argument(
+ '-c',
+ '--clean',
+ action='store_true',
+ default=False,
+ help='Removes the previously generated build output, if any.')
+ parser.add_argument('-p',
+ '--purify',
+ action='store_true',
+ default=False,
+ help='Purifies the previously generated build output by '
+ 'removing the temporary results used when (re)building.')
+ parser.add_argument(
+ '-o',
+ '--output-dir',
+ type=os.path.abspath,
+ 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('--verbose',
+ action='store_true',
+ default=False,
+ help='Debug logging.')
+ parser.add_argument('--use-goma',
+ action='store_true',
+ default=False,
+ help='Use goma to build.')
+ parser.add_argument(
+ '--extra-gn-args',
+ default=[],
+ nargs='*',
+ help='Additional GN args to be used during Ninja generation.')
+
+ return parser.parse_args()
+
+
+def _RunCommand(cmd):
+ logging.debug('Running: %r', cmd)
+ subprocess.check_call(cmd, cwd=SRC_DIR)
+
+
+def _CleanArtifacts(output_dir):
+ if os.path.isdir(output_dir):
+ logging.info('Deleting %s', output_dir)
+ shutil.rmtree(output_dir)
+
+
+def _CleanTemporary(output_dir, architectures):
+ if os.path.isdir(output_dir):
+ logging.info('Removing temporary build files.')
+ for arch in architectures:
+ arch_lib_path = os.path.join(output_dir, arch)
+ if os.path.isdir(arch_lib_path):
+ shutil.rmtree(arch_lib_path)
+
+
+def _ParseArchitecture(architectures):
+ result = dict()
+ for arch in architectures:
+ if ":" in arch:
+ target_environment, target_cpu = arch.split(":")
+ else:
+ logging.warning('The environment for build is not specified.')
+ logging.warning('It is assumed based on cpu type.')
+ logging.warning('See crbug.com/1138425 for more details.')
+ if arch == "x64":
+ target_environment = "simulator"
+ else:
+ target_environment = "device"
+ target_cpu = arch
+ archs = result.get(target_environment)
+ if archs is None:
+ result[target_environment] = {target_cpu}
+ else:
+ archs.add(target_cpu)
+
+ return result
+
+
+def BuildWebRTC(output_dir, target_environment, target_arch, flavor,
+ gn_target_name, ios_deployment_target, libvpx_build_vp9,
+ use_goma, extra_gn_args):
+ gn_args = [
+ 'target_os="ios"',
+ 'ios_enable_code_signing=false',
+ 'is_component_build=false',
+ 'rtc_include_tests=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_environment="%s"' % target_environment)
+
+ 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('use_lld=true')
+ gn_args.append('use_goma=' + ('true' if use_goma else 'false'))
+ gn_args.append('rtc_enable_objc_symbol_export=true')
+
+ args_string = ' '.join(gn_args + extra_gn_args)
+ logging.info('Building WebRTC with args: %s', args_string)
+
+ cmd = [
+ sys.executable,
+ os.path.join(find_depot_tools.DEPOT_TOOLS_PATH, 'gn.py'),
+ 'gen',
+ output_dir,
+ '--args=' + args_string,
+ ]
+ _RunCommand(cmd)
+ logging.info('Building target: %s', gn_target_name)
+
+ cmd = [
+ os.path.join(find_depot_tools.DEPOT_TOOLS_PATH, 'ninja'),
+ '-C',
+ output_dir,
+ gn_target_name,
+ ]
+ if use_goma:
+ cmd.extend(['-j', '200'])
+ _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
+
+ # architectures is typed as Dict[str, Set[str]],
+ # where key is for the environment (device or simulator)
+ # and value is for the cpu type.
+ architectures = _ParseArchitecture(args.arch)
+ gn_args = args.extra_gn_args
+
+ if args.purify:
+ _CleanTemporary(args.output_dir, list(architectures.keys()))
+ return 0
+
+ gn_target_name = 'framework_objc'
+ gn_args.append('enable_dsyms=true')
+ gn_args.append('enable_stripping=true')
+
+ # Build all architectures.
+ framework_paths = []
+ all_lib_paths = []
+ for (environment, archs) in list(architectures.items()):
+ framework_path = os.path.join(args.output_dir, environment)
+ framework_paths.append(framework_path)
+ lib_paths = []
+ for arch in archs:
+ lib_path = os.path.join(framework_path, arch + '_libs')
+ lib_paths.append(lib_path)
+ BuildWebRTC(lib_path, environment, arch, args.build_config,
+ gn_target_name, IOS_DEPLOYMENT_TARGET[environment],
+ LIBVPX_BUILD_VP9, args.use_goma, gn_args)
+ all_lib_paths.extend(lib_paths)
+
+ # Combine the slices.
+ dylib_path = os.path.join(SDK_FRAMEWORK_NAME, 'WebRTC')
+ # Dylibs will be combined, all other files are the same across archs.
+ shutil.rmtree(os.path.join(framework_path, SDK_FRAMEWORK_NAME),
+ ignore_errors=True)
+ shutil.copytree(os.path.join(lib_paths[0], SDK_FRAMEWORK_NAME),
+ os.path.join(framework_path, SDK_FRAMEWORK_NAME),
+ symlinks=True)
+ logging.info('Merging framework slices for %s.', environment)
+ dylib_paths = [os.path.join(path, dylib_path) for path in lib_paths]
+ out_dylib_path = os.path.join(framework_path, dylib_path)
+ if os.path.islink(out_dylib_path):
+ out_dylib_path = os.path.join(os.path.dirname(out_dylib_path),
+ os.readlink(out_dylib_path))
+ try:
+ os.remove(out_dylib_path)
+ except OSError:
+ pass
+ cmd = ['lipo'] + dylib_paths + ['-create', '-output', out_dylib_path]
+ _RunCommand(cmd)
+
+ # Merge the dSYM slices.
+ lib_dsym_dir_path = os.path.join(lib_paths[0], SDK_DSYM_NAME)
+ if os.path.isdir(lib_dsym_dir_path):
+ shutil.rmtree(os.path.join(framework_path, SDK_DSYM_NAME),
+ ignore_errors=True)
+ shutil.copytree(lib_dsym_dir_path,
+ os.path.join(framework_path, SDK_DSYM_NAME))
+ logging.info('Merging dSYM slices.')
+ dsym_path = os.path.join(SDK_DSYM_NAME, 'Contents', 'Resources', 'DWARF',
+ 'WebRTC')
+ lib_dsym_paths = [os.path.join(path, dsym_path) for path in lib_paths]
+ out_dsym_path = os.path.join(framework_path, dsym_path)
+ try:
+ os.remove(out_dsym_path)
+ except OSError:
+ pass
+ cmd = ['lipo'] + lib_dsym_paths + ['-create', '-output', out_dsym_path]
+ _RunCommand(cmd)
+
+ # Check for Mac-style WebRTC.framework/Resources/ (for Catalyst)...
+ resources_dir = os.path.join(framework_path, SDK_FRAMEWORK_NAME,
+ 'Resources')
+ if not os.path.exists(resources_dir):
+ # ...then fall back to iOS-style WebRTC.framework/
+ resources_dir = os.path.dirname(resources_dir)
+
+ # Modify the version number.
+ # Format should be <Branch cut MXX>.<Hotfix #>.<Rev #>.
+ # e.g. 55.0.14986 means
+ # branch cut 55, no hotfixes, and revision 14986.
+ infoplist_path = os.path.join(resources_dir, 'Info.plist')
+ cmd = [
+ 'PlistBuddy', '-c', 'Print :CFBundleShortVersionString',
+ infoplist_path
+ ]
+ major_minor = subprocess.check_output(cmd).decode('utf-8').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])
+
+ xcframework_dir = os.path.join(args.output_dir, SDK_XCFRAMEWORK_NAME)
+ if os.path.isdir(xcframework_dir):
+ shutil.rmtree(xcframework_dir)
+
+ logging.info('Creating xcframework.')
+ cmd = ['xcodebuild', '-create-xcframework', '-output', xcframework_dir]
+
+ # Apparently, xcodebuild needs absolute paths for input arguments
+ for framework_path in framework_paths:
+ cmd += [
+ '-framework',
+ os.path.abspath(os.path.join(framework_path, SDK_FRAMEWORK_NAME)),
+ ]
+ dsym_full_path = os.path.join(framework_path, SDK_DSYM_NAME)
+ if os.path.exists(dsym_full_path):
+ cmd += ['-debug-symbols', os.path.abspath(dsym_full_path)]
+
+ _RunCommand(cmd)
+
+ # Generate the license file.
+ logging.info('Generate license file.')
+ gn_target_full_name = '//sdk:' + gn_target_name
+ builder = LicenseBuilder(all_lib_paths, [gn_target_full_name])
+ builder.GenerateLicenseText(
+ os.path.join(args.output_dir, SDK_XCFRAMEWORK_NAME))
+
+ logging.info('Done.')
+ return 0
+
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/third_party/libwebrtc/tools_webrtc/ios/build_ios_libs.sh b/third_party/libwebrtc/tools_webrtc/ios/build_ios_libs.sh
new file mode 100755
index 0000000000..c8d659c7e6
--- /dev/null
+++ b/third_party/libwebrtc/tools_webrtc/ios/build_ios_libs.sh
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+# 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
+# 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.
+
+# This script has been rewritten in Python. Temporary "redirect":
+
+SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
+
+exec "$SCRIPT_DIR/build_ios_libs.py" "$@"
diff --git a/third_party/libwebrtc/tools_webrtc/ios/generate_modulemap.py b/third_party/libwebrtc/tools_webrtc/ios/generate_modulemap.py
new file mode 100644
index 0000000000..1b61b8e3d1
--- /dev/null
+++ b/third_party/libwebrtc/tools_webrtc/ios/generate_modulemap.py
@@ -0,0 +1,34 @@
+#!/usr/bin/env vpython3
+
+# Copyright (c) 2018 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.
+
+import argparse
+import sys
+
+
+def GenerateModulemap():
+ parser = argparse.ArgumentParser(description='Generate modulemap')
+ parser.add_argument("-o", "--out", type=str, help="Output file.")
+ parser.add_argument("-n", "--name", type=str, help="Name of binary.")
+
+ args = parser.parse_args()
+
+ with open(args.out, "w") as outfile:
+ module_template = 'framework module %s {\n' \
+ ' umbrella header "%s.h"\n' \
+ '\n' \
+ ' export *\n' \
+ ' module * { export * }\n' \
+ '}\n' % (args.name, args.name)
+ outfile.write(module_template)
+ return 0
+
+
+if __name__ == '__main__':
+ sys.exit(GenerateModulemap())
diff --git a/third_party/libwebrtc/tools_webrtc/ios/generate_umbrella_header.py b/third_party/libwebrtc/tools_webrtc/ios/generate_umbrella_header.py
new file mode 100644
index 0000000000..1fd1eed38e
--- /dev/null
+++ b/third_party/libwebrtc/tools_webrtc/ios/generate_umbrella_header.py
@@ -0,0 +1,50 @@
+#!/usr/bin/env vpython3
+
+# Copyright (c) 2018 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.
+
+import argparse
+import datetime
+import os
+import sys
+import textwrap
+
+
+def GenerateUmbrellaHeader():
+ parser = argparse.ArgumentParser(description='Generate umbrella header')
+ parser.add_argument("-o", "--out", type=str, help="Output file.")
+ parser.add_argument("-s",
+ "--sources",
+ default=[],
+ type=str,
+ nargs='+',
+ help="Headers to include.")
+
+ args = parser.parse_args()
+
+ with open(args.out, "w") as outfile:
+ outfile.write(
+ textwrap.dedent("""\
+ /*
+ * Copyright %d 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.
+ */\n\n""" % datetime.datetime.now().year))
+
+ for s in args.sources:
+ outfile.write("#import <WebRTC/{}>\n".format(os.path.basename(s)))
+
+ return 0
+
+
+if __name__ == '__main__':
+ sys.exit(GenerateUmbrellaHeader())
diff --git a/third_party/libwebrtc/tools_webrtc/ios/merge_ios_libs.py b/third_party/libwebrtc/tools_webrtc/ios/merge_ios_libs.py
new file mode 100755
index 0000000000..111825155e
--- /dev/null
+++ b/third_party/libwebrtc/tools_webrtc/ios/merge_ios_libs.py
@@ -0,0 +1,126 @@
+#!/usr/bin/env vpython3
+
+# Copyright 2016 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.
+"""Script for merging generated iOS libraries."""
+
+import sys
+import argparse
+import os
+import re
+import subprocess
+from six.moves import range
+
+
+# Valid arch subdir names.
+VALID_ARCHS = ['arm_libs', 'arm64_libs', 'ia32_libs', 'x64_libs']
+
+
+def MergeLibs(lib_base_dir):
+ """Merges generated iOS libraries for different archs.
+
+ Uses libtool to generate FAT archive files for each generated library.
+
+ Args:
+ lib_base_dir: directory whose subdirectories are named by architecture and
+ contain the built libraries for that architecture
+
+ Returns:
+ Exit code of libtool.
+ """
+ output_dir_name = 'fat_libs'
+ archs = [arch for arch in os.listdir(lib_base_dir) if arch in VALID_ARCHS]
+ # For each arch, find (library name, libary path) for arch. We will merge
+ # all libraries with the same name.
+ libs = {}
+ for lib_dir in [os.path.join(lib_base_dir, arch) for arch in VALID_ARCHS]:
+ if not os.path.exists(lib_dir):
+ continue
+ for dirpath, _, filenames in os.walk(lib_dir):
+ for filename in filenames:
+ if not filename.endswith('.a'):
+ continue
+ entry = libs.get(filename, [])
+ entry.append(os.path.join(dirpath, filename))
+ libs[filename] = entry
+ orphaned_libs = {}
+ valid_libs = {}
+ for library, paths in list(libs.items()):
+ if len(paths) < len(archs):
+ orphaned_libs[library] = paths
+ else:
+ valid_libs[library] = paths
+ for library, paths in list(orphaned_libs.items()):
+ components = library[:-2].split('_')[:-1]
+ found = False
+ # Find directly matching parent libs by stripping suffix.
+ while components and not found:
+ parent_library = '_'.join(components) + '.a'
+ if parent_library in valid_libs:
+ valid_libs[parent_library].extend(paths)
+ found = True
+ break
+ components = components[:-1]
+ # Find next best match by finding parent libs with the same prefix.
+ if not found:
+ base_prefix = library[:-2].split('_')[0]
+ for valid_lib, valid_paths in list(valid_libs.items()):
+ if valid_lib[:len(base_prefix)] == base_prefix:
+ valid_paths.extend(paths)
+ found = True
+ break
+ assert found
+
+ # Create output directory.
+ output_dir_path = os.path.join(lib_base_dir, output_dir_name)
+ if not os.path.exists(output_dir_path):
+ os.mkdir(output_dir_path)
+
+ # Use this so libtool merged binaries are always the same.
+ env = os.environ.copy()
+ env['ZERO_AR_DATE'] = '1'
+
+ # Ignore certain errors.
+ libtool_re = re.compile(r'^.*libtool:.*file: .* has no symbols$')
+
+ # Merge libraries using libtool.
+ libtool_returncode = 0
+ for library, paths in list(valid_libs.items()):
+ cmd_list = [
+ 'libtool', '-static', '-v', '-o',
+ os.path.join(output_dir_path, library)
+ ] + paths
+ libtoolout = subprocess.Popen(cmd_list, stderr=subprocess.PIPE, env=env)
+ _, err = libtoolout.communicate()
+ for line in err.splitlines():
+ if not libtool_re.match(line):
+ print(line, file=sys.stderr)
+ # Unconditionally touch the output .a file on the command line if present
+ # and the command succeeded. A bit hacky.
+ libtool_returncode = libtoolout.returncode
+ if not libtool_returncode:
+ for i in range(len(cmd_list) - 1):
+ if cmd_list[i] == '-o' and cmd_list[i + 1].endswith('.a'):
+ os.utime(cmd_list[i + 1], None)
+ break
+ return libtool_returncode
+
+
+def main():
+ parser_description = 'Merge WebRTC libraries.'
+ parser = argparse.ArgumentParser(description=parser_description)
+ parser.add_argument('lib_base_dir',
+ help='Directory with built libraries. ',
+ type=str)
+ args = parser.parse_args()
+ lib_base_dir = args.lib_base_dir
+ MergeLibs(lib_base_dir)
+
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/third_party/libwebrtc/tools_webrtc/ios/no_op.cc b/third_party/libwebrtc/tools_webrtc/ios/no_op.cc
new file mode 100644
index 0000000000..7508b9dbb4
--- /dev/null
+++ b/third_party/libwebrtc/tools_webrtc/ios/no_op.cc
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2012 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.
+ */
+
+// No-op main() to provide a dummy executable target.
+int main() {
+ return 0;
+}
diff --git a/third_party/libwebrtc/tools_webrtc/ios/objc_app.plist b/third_party/libwebrtc/tools_webrtc/ios/objc_app.plist
new file mode 100644
index 0000000000..c2fb0617f3
--- /dev/null
+++ b/third_party/libwebrtc/tools_webrtc/ios/objc_app.plist
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>en</string>
+ <key>CFBundleDisplayName</key>
+ <string>${PRODUCT_NAME}</string>
+ <key>CFBundleExecutable</key>
+ <string>${EXECUTABLE_NAME}</string>
+ <key>CFBundleIdentifier</key>
+ <string>com.Google.${PRODUCT_NAME:rfc1034identifier}</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>${PRODUCT_NAME}</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleVersion</key>
+ <string>1.0</string>
+</dict>
+</plist>