Commit 7f4c25f2 authored by sdefresne's avatar sdefresne Committed by Commit bot

Upstream helper script to build Chromium on iOS and update instructions.

Upstream some scripts used to simplify the setup of a new Chromium on iOS
checkout and update the instruction to remove obsolete informations, and
add recommendation to use the script.

BUG=None

Review-Url: https://codereview.chromium.org/2343853002
Cr-Commit-Position: refs/heads/master@{#419422}
parent 59a29f5a
...@@ -7,97 +7,72 @@ the web layer), and various unit tests. ...@@ -7,97 +7,72 @@ the web layer), and various unit tests.
## Prerequisites ## Prerequisites
* A Mac with a version of OS X capable of running the latest version * A Mac running 10.11+.
of Xcode. * [Xcode] 8.0+.
* The latest version of [Xcode](https://developer.apple.com/xcode/), * [depot\_tools].
including the current iOS SDK.
* The current version of the JDK (required for the closure compiler). * The current version of the JDK (required for the closure compiler).
* [depot\_tools](http://dev.chromium.org/developers/how-tos/install-depot-tools).
## Setting Up ## Getting the source
### With GYP To checkout the source, use `fetch ios` command from [depot\_tools] in a new
empty directory.
In the directory where you are going to check out the code, create a
`chromium.gyp_env` to set the build to use iOS targets (and to use
hybrid builds; see [Building](#Building) below):
```shell ```shell
cat > chromium.gyp_env <<EOF # You can use a different location for your checkout of Chromium on iOS
{ # by updating this variable. All shell snippets will refer to it.
"GYP_DEFINES": "OS=ios", CHROMIUM_IOS="$HOME/chromium_ios"
"GYP_GENERATORS": "ninja,xcode-ninja", mkdir "$CHROMIUM_IOS"
} cd "$CHROMIUM_IOS"
EOF fetch ios
``` ```
If you aren't set up to sign iOS build products via a developer account, ## Setting up
you should instead use:
```shell Chromium on iOS is built using the [Ninja](ninja_build.md) tool and
cat > chromium.gyp_env <<EOF the [Clang](clang.md) compiler. See both of those pages for further details on
{ how to tune the build.
"GYP_DEFINES": "OS=ios chromium_ios_signing=0",
"GYP_GENERATORS": "ninja,xcode-ninja",
}
EOF
```
### With GN Before you build, you may want to [install API keys](api-keys) so that
Chrome-integrated Google services work. This step is optional if you aren't
testing those features.
Use `gn args out/Debug-iphonesimulator` (or replace ### Quick setup
`out/Debug-iphonesimulator` with your chosen `out/` directory) to open up an
editor to set the following gn variables and regenerate:
``` To setup the repository for building Chromium on iOS code, it is recommended
# Set to true if you have a valid code signing key. to use the `src/ios/build/tools/setup-gn.py` script that creates a Xcode
ios_enable_code_signing = false workspace configured to build the different targets for device and simulator.
target_os = "ios"
# Set to "x86", "x64", "arm", "armv7", "arm64". "x86" and "x64" will create a
# build to run on the iOS simulator (and set use_ios_simulator = true), all
# others are for an iOS device.
target_cpu = "x64"
# Release vs debug build.
is_debug = true
```
### API Keys
Before you build, you may want to
[install API keys](https://sites.google.com/a/chromium.org/dev/developers/how-tos/api-keys)
so that Chrome-integrated Google services work. This step is optional if you
aren't testing those features.
## Getting the Code
Next, [check out the
code](https://www.chromium.org/developers/how-tos/get-the-code), with:
```shell ```shell
fetch ios cd "$CHROMIUM_IOS/src"
ios/build/tools/setup-gn.py
open out/build/all.xcworkspace
``` ```
## Building You can customize the build by editing the file `$HOME/.setup-gn` (create it
if it does not exists). Look at `src/ios/build/tools/setup-gn.config` for
available configuration options.
Build the target you are interested in. The instructions above select From this point, you can either build from Xcode or from the command-line
the ninja/Xcode hybrid mode, which uses ninja to do the actual build, using `ninja`. The script `setup-gn.py` creates sub-directories named
but provides a wrapper Xcode project that can be used to build targets `out/${configuration}-${platform}`, so for a `Debug` build for simulator
and navigate the source. (The Xcode project just shells out to ninja to use:
do the builds, so you can't actually inspect/change target-level
settings from within Xcode; this mode avoids generating a large tree of
Xcode projects, which leads to performance issues in Xcode). To build
with ninja (simulator and device, respectively):
```shell ```shell
ninja -C out/Debug-iphonesimulator All ninja -C out/Debug-iphonesimulator gn_all
ninja -C out/Debug-iphoneos All
``` ```
To build with Xcode, open `build/all.ninja.xcworkspace`, and choose the Note: you need to run `setup-gn.py` script every time one of the `BUILD.gn`
target you want to build. file is updated (either by you or after rebasing). If you forget to run it,
the list of targets and files in the Xcode solution may be stale.
You should always be able to build All, since targets are added there for iOS ### Advanced setup
only when they compile.
You can run `gn` manually to configure the build yourself. In that case,
refer to [mac build instructions] for help on how to do that.
To build for iOS, you have to set `target_os` to `"ios"`. Please also note
that `is_component_build` is not supported when building for iOS and must
be set to `false`.
## Running ## Running
...@@ -114,37 +89,16 @@ example, to run a debug build of ios\_web\_shell: ...@@ -114,37 +89,16 @@ example, to run a debug build of ios\_web\_shell:
out/Debug-iphonesimulator/iossim out/Debug-iphonesimulator/ios_web_shell.app out/Debug-iphonesimulator/iossim out/Debug-iphonesimulator/ios_web_shell.app
``` ```
## Converting an existing Mac checkout into an iOS checkout
If you want to convert your Mac checkout into an iOS checkout, follow the steps
below:
1. Add `target_os = [ "ios" ]` to the bottom of your `chromium/.gclient`
file.
2. For gyp, make sure you have the following in your
`chromium/chromium.gyp_env` file (removing the `chromium_ios_signing=0` if you
want to make developer-signed builds):
```json
{
"GYP_DEFINES" : "OS=ios chromium_ios_signing=0",
"GYP_GENERATORS" : "ninja,xcode-ninja",
}
```
For gn, add the arguments specified [above](#With-GN) to your gn setup.
3. Make sure to sync again to fetch the iOS specific dependencies and
regenerate build rules using:
```shell
gclient sync
```
## Troubleshooting ## Troubleshooting
If your build fails, check the iOS columns of [the Mac If your build fails, check the iOS columns of [the Mac
waterfall](http://build.chromium.org/p/chromium.mac/console) (the last two) to waterfall](http://build.chromium.org/p/chromium.mac/console) (the last two) to
see if the bots are green. In general they should be, since failures on those see if the bots are green. In general they should be, since failures on those
bots will close the tree. bots will close the tree.
[Xcode]: https://developer.apple.com/xcode
[depot\_tools]: https://dev.chromium.org/developers/how-tos/depottools
[Ninja]: ninja.md
[Clang]: clang.md
[api-keys]: https://sites.google.com/a/chromium.org/dev/developers/how-tos/api-keys
[mac build instructions]: mac_build_instructions.md
#!/usr/bin/python
# Copyright 2016 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Convert GN Xcode projects to platform and configuration independent targets.
GN generates Xcode projects that build one configuration only. However, typical
iOS development involves using the Xcode IDE to toggle the platform and
configuration. This script replaces the 'gn' configuration with 'Debug',
'Release' and 'Profile', and changes the ninja invokation to honor these
configurations.
"""
import argparse
import collections
import copy
import filecmp
import json
import hashlib
import os
import plistlib
import random
import shutil
import subprocess
import sys
import tempfile
XCTEST_PRODUCT_TYPE = 'com.apple.product-type.bundle.unit-test'
class XcodeProject(object):
def __init__(self, objects, counter = 0):
self.objects = objects
self.counter = 0
def AddObject(self, parent_name, obj):
while True:
self.counter += 1
str_id = "%s %s %d" % (parent_name, obj['isa'], self.counter)
new_id = hashlib.sha1(str_id).hexdigest()[:24].upper()
# Make sure ID is unique. It's possible there could be an id conflict
# since this is run after GN runs.
if new_id not in self.objects:
self.objects[new_id] = obj
return new_id
def CopyFileIfChanged(source_path, target_path):
"""Copy |source_path| to |target_path| is different."""
target_dir = os.path.dirname(target_path)
if not os.path.isdir(target_dir):
os.makedirs(target_dir)
if not os.path.exists(target_path) or \
not filecmp.cmp(source_path, target_path):
shutil.copyfile(source_path, target_path)
def LoadXcodeProjectAsJSON(path):
"""Return Xcode project at |path| as a JSON string."""
return subprocess.check_output([
'plutil', '-convert', 'json', '-o', '-', path])
def WriteXcodeProject(output_path, json_string):
"""Save Xcode project to |output_path| as XML."""
with tempfile.NamedTemporaryFile() as temp_file:
temp_file.write(json_string)
temp_file.flush()
subprocess.check_call(['plutil', '-convert', 'xml1', temp_file.name])
CopyFileIfChanged(temp_file.name, output_path)
def UpdateProductsProject(file_input, file_output, configurations):
"""Update Xcode project to support multiple configurations.
Args:
file_input: path to the input Xcode project
file_output: path to the output file
configurations: list of string corresponding to the configurations that
need to be supported by the tweaked Xcode projects, must contains at
least one value.
"""
json_data = json.loads(LoadXcodeProjectAsJSON(file_input))
project = XcodeProject(json_data['objects'])
objects_to_remove = []
for value in project.objects.values():
isa = value['isa']
# TODO(crbug.com/619072): gn does not write the min deployment target in the
# generated Xcode project, so add it while doing the conversion, only if it
# is not present. Remove this code and comment once the bug is fixed and gn
# has rolled past it.
if isa == 'XCBuildConfiguration':
build_settings = value['buildSettings']
if 'IPHONEOS_DEPLOYMENT_TARGET' not in build_settings:
build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '9.0'
# Remove path name key and change path to basename.
if isa == 'PBXFileReference':
if 'name' in value:
del value['name']
value['path'] = os.path.basename(value['path'])
# Teach build shell script to look for the configuration and platform.
if isa == 'PBXShellScriptBuildPhase':
value['shellScript'] = value['shellScript'].replace(
'ninja -C .',
'ninja -C "../${CONFIGURATION}${EFFECTIVE_PLATFORM_NAME}"')
# Configure BUNDLE_LOADER and TEST_HOST for xctest target (assuming that
# the host is named "${target}_host") unless gn has already configured
# them.
if isa == 'PBXNativeTarget' and value['productType'] == XCTEST_PRODUCT_TYPE:
configuration_list = project.objects[value['buildConfigurationList']]
for config_name in configuration_list['buildConfigurations']:
config = project.objects[config_name]
if not config['buildSettings'].get('BUNDLE_LOADER'):
config['buildSettings']['BUNDLE_LOADER'] = '$(TEST_HOST)'
config['buildSettings']['TEST_HOST'] = \
'${BUILT_PRODUCTS_DIR}/%(name)s_host.app/%(name)s' % value
# Add new configuration, using the first one as default.
if isa == 'XCConfigurationList':
value['defaultConfigurationName'] = configurations[0]
objects_to_remove.extend(value['buildConfigurations'])
build_config_template = project.objects[value['buildConfigurations'][0]]
build_config_template['buildSettings']['CONFIGURATION_BUILD_DIR'] = \
'../$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)'
value['buildConfigurations'] = []
for configuration in configurations:
new_build_config = copy.copy(build_config_template)
new_build_config['name'] = configuration
value['buildConfigurations'].append(
project.AddObject('products', new_build_config))
for object_id in objects_to_remove:
del project.objects[object_id]
objects = collections.OrderedDict(sorted(project.objects.iteritems()))
WriteXcodeProject(file_output, json.dumps(json_data))
def ConvertGnXcodeProject(input_dir, output_dir, configurations):
'''Tweak the Xcode project generated by gn to support multiple configurations.
The Xcode projects generated by "gn gen --ide" only supports a single
platform and configuration (as the platform and configuration are set
per output directory). This method takes as input such projects and
add support for multiple configurations and platforms (to allow devs
to select them in Xcode).
Args:
input_dir: directory containing the XCode projects created by "gn gen --ide"
output_dir: directory where the tweaked Xcode projects will be saved
configurations: list of string corresponding to the configurations that
need to be supported by the tweaked Xcode projects, must contains at
least one value.
'''
# Update products project.
products = os.path.join('products.xcodeproj', 'project.pbxproj')
product_input = os.path.join(input_dir, products)
product_output = os.path.join(output_dir, products)
UpdateProductsProject(product_input, product_output, configurations)
# Copy sources project and all workspace.
sources = os.path.join('sources.xcodeproj', 'project.pbxproj')
CopyFileIfChanged(os.path.join(input_dir, sources),
os.path.join(output_dir, sources))
xcwspace = os.path.join('all.xcworkspace', 'contents.xcworkspacedata')
CopyFileIfChanged(os.path.join(input_dir, xcwspace),
os.path.join(output_dir, xcwspace))
def Main(args):
parser = argparse.ArgumentParser(
description='Convert GN Xcode projects for iOS.')
parser.add_argument(
'input',
help='directory containing [product|sources|all] Xcode projects.')
parser.add_argument(
'output',
help='directory where to generate the iOS configuration.')
parser.add_argument(
'--add-config', dest='configurations', default=[], action='append',
help='configuration to add to the Xcode project')
args = parser.parse_args(args)
if not os.path.isdir(args.input):
sys.stderr.write('Input directory does not exists.\n')
return 1
required = set(['products.xcodeproj', 'sources.xcodeproj', 'all.xcworkspace'])
if not required.issubset(os.listdir(args.input)):
sys.stderr.write(
'Input directory does not contain all necessary Xcode projects.\n')
return 1
if not args.configurations:
sys.stderr.write('At least one configuration required, see --add-config.\n')
return 1
ConvertGnXcodeProject(args.input, args.output, args.configurations)
if __name__ == '__main__':
sys.exit(Main(sys.argv[1:]))
[goma]
# Controls whether goma is enabled or not. If you generally use goma but
# want to disable goma for a single build, consider using the environment
# variable GOMA_DISABLED.
enabled = False
install = "$GOMA_DIR"
[xcode]
# Controls settings for the generated Xcode project. If jobs is non-zero
# it will be passed to the ninja invocation in Xcode project.
jobs = 0
[build]
# Controls the build output. The only supported values are "64-bit", "32-bit"
# and "multi" (for a fat binary supporting both "32-bit" and "64-bit" cpus).
arch = "64-bit"
[gn_args]
# Values in that section will be copied verbatim in the generated args.gn file.
target_os = "ios"
[filters]
# List of target files to pass to --filters argument of gn gen when generating
# the Xcode project. By default, list all targets from ios/ and ios_internal/
# and the targets corresponding to the unit tests run on the bots.
filter_0 = "//base:base_unittests"
filter_1 = "//components:components_unittests"
filter_2 = "//crypto:crypto_unittests"
filter_3 = "//google_apis:google_apis_unittests"
filter_4 = "//ios/*"
filter_5 = "//ios_internal/*"
filter_6 = "//net:net_unittests"
filter_7 = "//skia:skia_unittests"
filter_8 = "//sql:sql_unittests"
filter_9 = "//ui/base:ui_base_unittests"
filter_a = "//ui/gfx:gfx_unittests"
filter_b = "//url:url_unittests"
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment