Add support for building variants of app on iOS.
Chrome on iOS needs to build the same app (exact same binary) with different application icons (i.e. with different compiled asset catalogs). Add a "variants" property to "ios_app_bundle" template that contains a list of scope, each defining the variant "name" and the list of additional "bundle_deps". When the "variants" property is defined, the executable will be linked once, but n application bundles will be generated in $root_out_dir/variants/$variant_name and a copy of the first variant will be created in $root_out_dir. The hardlink.py script is used to copy the first variant (it tries to use hardlink if possible, but fallback to copy if it fails). Bug: 764286 Change-Id: I0ea18e757c891ae884ba22c07fe20946715d1d0a Reviewed-on: https://chromium-review.googlesource.com/677386 Commit-Queue: Sylvain Defresne <sdefresne@chromium.org> Reviewed-by: Olivier Robin <olivierrobin@chromium.org> Cr-Original-Commit-Position: refs/heads/master@{#503710} Cr-Mirrored-From: https://chromium.googlesource.com/chromium/src Cr-Mirrored-Commit: 7aac0a1de0b0c010efde682ad414770eb04eb4b0
This commit is contained in:
Родитель
2cf030dbbf
Коммит
aaf141004b
|
@ -0,0 +1,69 @@
|
|||
# Copyright 2017 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.
|
||||
|
||||
"""Recursively create hardlink to target named output."""
|
||||
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import shutil
|
||||
|
||||
|
||||
def CreateHardlinkHelper(target, output):
|
||||
"""Recursively create a hardlink named output pointing to target.
|
||||
|
||||
Args:
|
||||
target: path to an existing file or directory
|
||||
output: path to the newly created hardlink
|
||||
|
||||
This function assumes that output does not exists but that the parent
|
||||
directory containing output does. If those conditions are false, then
|
||||
the function will fails with an exception corresponding to an OS error.
|
||||
"""
|
||||
if os.path.islink(target):
|
||||
os.symlink(os.readlink(target), output)
|
||||
elif not os.path.isdir(target):
|
||||
try:
|
||||
os.link(target, output)
|
||||
except:
|
||||
shutil.copy(target, output)
|
||||
else:
|
||||
os.mkdir(output)
|
||||
for name in os.listdir(target):
|
||||
CreateHardlinkHelper(
|
||||
os.path.join(target, name),
|
||||
os.path.join(output, name))
|
||||
|
||||
|
||||
def CreateHardlink(target, output):
|
||||
"""Recursively create a hardlink named output pointing to target.
|
||||
|
||||
Args:
|
||||
target: path to an existing file or directory
|
||||
output: path to the newly created hardlink
|
||||
|
||||
If output already exists, it is first removed. In all cases, the
|
||||
parent directory containing output is created.
|
||||
"""
|
||||
if os.path.exists(output):
|
||||
shutil.rmtree(output)
|
||||
|
||||
parent_dir = os.path.dirname(os.path.abspath(output))
|
||||
if not os.path.isdir(parent_dir):
|
||||
os.makedirs(parent_dir)
|
||||
|
||||
CreateHardlinkHelper(target, output)
|
||||
|
||||
|
||||
def Main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('target', help='path to the file or directory to link to')
|
||||
parser.add_argument('output', help='name of the hardlink to create')
|
||||
args = parser.parse_args()
|
||||
|
||||
CreateHardlink(args.target, args.output)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
Main()
|
|
@ -122,12 +122,16 @@ template("lipo_binary") {
|
|||
# product_type
|
||||
# string, product type for the generated Xcode project.
|
||||
#
|
||||
# bundle_gen_dir
|
||||
# (optional) directory where the bundle is generated; must be below
|
||||
# root_out_dir and defaults to root_out_dir if omitted.
|
||||
#
|
||||
# bundle_deps
|
||||
# (optional) list of additional dependencies
|
||||
# (optional) list of additional dependencies.
|
||||
#
|
||||
# bundle_deps_filter
|
||||
# (optional) list of dependencies to filter (for more information
|
||||
# see "gn help bundle_deps_filter")
|
||||
# see "gn help bundle_deps_filter").
|
||||
#
|
||||
# bundle_extension
|
||||
# string, extension of the bundle, used to generate bundle name.
|
||||
|
@ -220,6 +224,11 @@ template("create_signed_bundle") {
|
|||
"/$_bundle_binary_output"
|
||||
}
|
||||
|
||||
_bundle_gen_dir = root_out_dir
|
||||
if (defined(invoker.bundle_gen_dir)) {
|
||||
_bundle_gen_dir = invoker.bundle_gen_dir
|
||||
}
|
||||
|
||||
_bundle_extension = invoker.bundle_extension
|
||||
|
||||
if (!defined(invoker.entitlements_target)) {
|
||||
|
@ -258,7 +267,7 @@ template("create_signed_bundle") {
|
|||
"xcode_test_application_name",
|
||||
])
|
||||
|
||||
bundle_root_dir = "$root_out_dir/$_output_name$_bundle_extension"
|
||||
bundle_root_dir = "$_bundle_gen_dir/$_output_name$_bundle_extension"
|
||||
bundle_contents_dir = bundle_root_dir
|
||||
bundle_resources_dir = bundle_contents_dir
|
||||
bundle_executable_dir = bundle_contents_dir
|
||||
|
@ -470,6 +479,13 @@ template("ios_info_plist") {
|
|||
# (optional) boolean, control whether code signing is enabled or not,
|
||||
# default to ios_enable_code_signing if not defined.
|
||||
#
|
||||
# variants
|
||||
# (optional) list of scopes, each scope needs to define the attributes
|
||||
# "name" and "bundle_deps"; if defined and non-empty, then one bundle
|
||||
# named $target_out_dir/$variant/$output_name will be created for each
|
||||
# variant with the same binary but the correct bundle_deps, the bundle
|
||||
# at $target_out_dir/$output_name will be a copy of the first variant.
|
||||
#
|
||||
# For more information, see "gn help executable".
|
||||
template("ios_app_bundle") {
|
||||
_output_name = target_name
|
||||
|
@ -482,6 +498,45 @@ template("ios_app_bundle") {
|
|||
_arch_executable_target = _target_name + "_arch_executable"
|
||||
_lipo_executable_target = _target_name + "_executable"
|
||||
|
||||
if (defined(invoker.variants) && invoker.variants != []) {
|
||||
_variants = []
|
||||
|
||||
foreach(_variant, invoker.variants) {
|
||||
assert(defined(_variant.name) && _variant.name != "",
|
||||
"name must be defined for all $target_name variants")
|
||||
|
||||
assert(defined(_variant.bundle_deps),
|
||||
"bundle_deps must be defined for all $target_name variants")
|
||||
|
||||
_variants += [ {
|
||||
name = _variant.name
|
||||
bundle_deps = _variant.bundle_deps
|
||||
target_name = "${_target_name}_variants_${_variant.name}"
|
||||
bundle_gen_dir = "$root_out_dir/variants/${_variant.name}"
|
||||
} ]
|
||||
}
|
||||
} else {
|
||||
# If no variants are passed to the template, use a fake variant with
|
||||
# no name to avoid duplicating code. As no variant can have an empty
|
||||
# name except this fake variant, it is possible to know if a variant
|
||||
# is fake or not.
|
||||
_variants = [ {
|
||||
name = ""
|
||||
bundle_deps = []
|
||||
target_name = _target_name
|
||||
bundle_gen_dir = root_out_dir
|
||||
} ]
|
||||
}
|
||||
|
||||
_default_variant = _variants[0]
|
||||
|
||||
if (current_toolchain != default_toolchain) {
|
||||
# For use of _variants and _default_variant for secondary toolchain to
|
||||
# avoid the "Assignment had no effect" error from gn.
|
||||
assert(_variants != [])
|
||||
assert(_default_variant.target_name != "")
|
||||
}
|
||||
|
||||
source_set(_arch_executable_source) {
|
||||
forward_variables_from(invoker,
|
||||
"*",
|
||||
|
@ -611,7 +666,11 @@ template("ios_app_bundle") {
|
|||
"testonly",
|
||||
])
|
||||
|
||||
visibility = [ ":$_target_name" ]
|
||||
visibility = []
|
||||
foreach(_variant, _variants) {
|
||||
visibility += [ ":${_variant.target_name}" ]
|
||||
}
|
||||
|
||||
output_name = _output_name
|
||||
arch_binary_target = ":$_arch_executable_target"
|
||||
arch_binary_output = _output_name
|
||||
|
@ -728,51 +787,79 @@ template("ios_app_bundle") {
|
|||
}
|
||||
}
|
||||
|
||||
create_signed_bundle(_target_name) {
|
||||
forward_variables_from(invoker,
|
||||
[
|
||||
"bundle_deps",
|
||||
"bundle_deps_filter",
|
||||
"data_deps",
|
||||
"deps",
|
||||
"enable_code_signing",
|
||||
"entitlements_path",
|
||||
"entitlements_target",
|
||||
"extra_system_frameworks",
|
||||
"public_configs",
|
||||
"public_deps",
|
||||
"testonly",
|
||||
"visibility",
|
||||
])
|
||||
foreach(_variant, _variants) {
|
||||
create_signed_bundle(_variant.target_name) {
|
||||
forward_variables_from(invoker,
|
||||
[
|
||||
"bundle_deps",
|
||||
"bundle_deps_filter",
|
||||
"data_deps",
|
||||
"deps",
|
||||
"enable_code_signing",
|
||||
"entitlements_path",
|
||||
"entitlements_target",
|
||||
"extra_system_frameworks",
|
||||
"public_configs",
|
||||
"public_deps",
|
||||
"testonly",
|
||||
"visibility",
|
||||
])
|
||||
|
||||
output_name = _output_name
|
||||
bundle_binary_target = ":$_lipo_executable_target"
|
||||
bundle_binary_output = _output_name
|
||||
bundle_extension = _bundle_extension
|
||||
product_type = _product_type
|
||||
output_name = _output_name
|
||||
bundle_gen_dir = _variant.bundle_gen_dir
|
||||
bundle_binary_target = ":$_lipo_executable_target"
|
||||
bundle_binary_output = _output_name
|
||||
bundle_extension = _bundle_extension
|
||||
product_type = _product_type
|
||||
|
||||
_generate_info_plist_outputs =
|
||||
get_target_outputs(":$_generate_info_plist")
|
||||
primary_info_plist = _generate_info_plist_outputs[0]
|
||||
partial_info_plist = "$target_gen_dir/${_target_name}_partial_info.plist"
|
||||
_generate_info_plist_outputs =
|
||||
get_target_outputs(":$_generate_info_plist")
|
||||
primary_info_plist = _generate_info_plist_outputs[0]
|
||||
partial_info_plist =
|
||||
"$target_gen_dir/${_variant.target_name}_partial_info.plist"
|
||||
|
||||
if (!defined(deps)) {
|
||||
deps = []
|
||||
}
|
||||
deps += [ ":$_generate_info_plist" ]
|
||||
if (!defined(deps)) {
|
||||
deps = []
|
||||
}
|
||||
deps += [ ":$_generate_info_plist" ]
|
||||
|
||||
if (_write_pkg_info) {
|
||||
if (!defined(bundle_deps)) {
|
||||
bundle_deps = []
|
||||
}
|
||||
bundle_deps += [ ":$_bundle_data_pkg_info" ]
|
||||
}
|
||||
|
||||
if (use_ios_simulator) {
|
||||
if (!defined(data_deps)) {
|
||||
data_deps = []
|
||||
if (_write_pkg_info) {
|
||||
bundle_deps += [ ":$_bundle_data_pkg_info" ]
|
||||
}
|
||||
data_deps += [ "//testing/iossim" ]
|
||||
bundle_deps += _variant.bundle_deps
|
||||
|
||||
if (use_ios_simulator) {
|
||||
if (!defined(data_deps)) {
|
||||
data_deps = []
|
||||
}
|
||||
data_deps += [ "//testing/iossim" ]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_default_variant.name != "") {
|
||||
_bundle_short_name = "$_output_name$_bundle_extension"
|
||||
action(_target_name) {
|
||||
forward_variables_from(invoker, [ "testonly" ])
|
||||
|
||||
script = "//build/config/ios/hardlink.py"
|
||||
public_deps = []
|
||||
foreach(_variant, _variants) {
|
||||
public_deps += [ ":${_variant.target_name}" ]
|
||||
}
|
||||
|
||||
sources = [
|
||||
"${_default_variant.bundle_gen_dir}/$_bundle_short_name",
|
||||
]
|
||||
outputs = [
|
||||
"$root_out_dir/$_bundle_short_name",
|
||||
]
|
||||
|
||||
args = rebase_path(sources, root_out_dir) +
|
||||
rebase_path(outputs, root_out_dir)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче