Commit d8dec3b0 authored by Sylvain Defresne's avatar Sylvain Defresne Committed by Commit Bot

[ios] Add support for building .swift files

Add compiler wrapper script at build/apple/swiftc.py, define
the necessary tool in the toolchain and pass the -target and
-sdk through the configuration.

Bug: none
Change-Id: I177b8a6acf169b5c1d2399b625bdc0a82083b6a5
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2341135Reviewed-by: default avatarMike Pinkerton <pinkerton@chromium.org>
Commit-Queue: Sylvain Defresne <sdefresne@chromium.org>
Cr-Commit-Position: refs/heads/master@{#800939}
parent 2b9b3924
#!/usr/bin/python3
# Copyright 2020 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.
import argparse
import collections
import json
import os
import subprocess
import sys
import tempfile
class OrderedSet(collections.OrderedDict):
def add(self, value):
self[value] = True
def compile_module(module, sources, settings, extras, tmpdir):
output_file_map = {}
if settings.whole_module_optimization:
output_file_map[''] = {
'object': os.path.join(settings.object_dir, module + '.o'),
'dependencies': os.path.join(tmpdir, module + '.d'),
}
else:
for source in sources:
name, _ = os.path.splitext(os.path.basename(source))
output_file_map[source] = {
'object': os.path.join(settings.object_dir, name + '.o'),
'dependencies': os.path.join(tmpdir, name + '.d'),
}
for key in ('module_path', 'header_path', 'depfile'):
path = getattr(settings, key)
if os.path.exists(path):
os.unlink(path)
if key == 'module_path':
for ext in '.swiftdoc', '.swiftsourceinfo':
path = os.path.splitext(getattr(settings, key))[0] + ext
if os.path.exists(path):
os.unlink(path)
directory = os.path.dirname(path)
if not os.path.exists(directory):
os.makedirs(directory)
if not os.path.exists(settings.object_dir):
os.makedirs(settings.object_dir)
for key in output_file_map:
path = output_file_map[key]['object']
if os.path.exists(path):
os.unlink(path)
output_file_map_path = os.path.join(tmpdir, module + '.json')
with open(output_file_map_path, 'w') as output_file_map_file:
output_file_map_file.write(json.dumps(output_file_map))
output_file_map_file.flush()
extra_args = []
if settings.bridge_header:
extra_args.extend([
'-import-objc-header',
os.path.abspath(settings.bridge_header),
])
if settings.whole_module_optimization:
extra_args.append('-whole-module-optimization')
if settings.target:
extra_args.extend([
'-target',
settings.target,
])
if settings.sdk:
extra_args.extend([
'-sdk',
os.path.abspath(settings.sdk),
])
if settings.swift_version:
extra_args.extend([
'-swift-version',
settings.swift_version,
])
if settings.include_dirs:
for include_dir in settings.include_dirs:
extra_args.append('-I' + include_dir)
process = subprocess.Popen([
'swiftc',
'-parse-as-library',
'-module-name',
module,
'-emit-object',
'-emit-dependencies',
'-emit-module',
'-emit-module-path',
settings.module_path,
'-emit-objc-header',
'-emit-objc-header-path',
settings.header_path,
'-output-file-map',
output_file_map_path,
] + extra_args + extras + sources,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
universal_newlines=True)
stdout, stderr = process.communicate()
if process.returncode:
sys.stdout.write(stdout)
sys.stderr.write(stderr)
sys.exit(process.returncode)
depfile_content = collections.OrderedDict()
for key in output_file_map:
for line in open(output_file_map[key]['dependencies']):
output, inputs = line.split(' : ', 2)
_, ext = os.path.splitext(output)
if ext == '.o':
key = output
else:
key = os.path.splitext(settings.module_path)[0] + ext
if key not in depfile_content:
depfile_content[key] = OrderedSet()
for path in inputs.split():
depfile_content[key].add(path)
with open(settings.depfile, 'w') as depfile:
for key in depfile_content:
if not settings.depfile_filter or key in settings.depfile_filter:
inputs = depfile_content[key]
depfile.write('%s : %s\n' % (key, ' '.join(inputs)))
def main(args):
parser = argparse.ArgumentParser(add_help=False)
parser.add_argument('-module-name', help='name of the Swift module')
parser.add_argument('-include',
'-I',
action='append',
dest='include_dirs',
help='add directory to header search path')
parser.add_argument('sources', nargs='+', help='Swift source file to compile')
parser.add_argument('-whole-module-optimization',
action='store_true',
help='enable whole module optimization')
parser.add_argument('-object-dir',
help='path to the generated object files directory')
parser.add_argument('-module-path', help='path to the generated module file')
parser.add_argument('-header-path', help='path to the generated header file')
parser.add_argument('-bridge-header',
help='path to the Objective-C bridge header')
parser.add_argument('-depfile', help='path to the generated depfile')
parser.add_argument('-swift-version',
help='version of Swift language to support')
parser.add_argument('-depfile-filter',
action='append',
help='limit depfile to those files')
parser.add_argument('-target',
action='store',
help='generate code for the given target <triple>')
parser.add_argument('-sdk', action='store', help='compile against sdk')
parsed, extras = parser.parse_known_args(args)
with tempfile.TemporaryDirectory() as tmpdir:
compile_module(parsed.module_name, parsed.sources, parsed, extras, tmpdir)
if __name__ == '__main__':
sys.exit(main(sys.argv[1:]))
...@@ -2313,6 +2313,10 @@ config("symbols") { ...@@ -2313,6 +2313,10 @@ config("symbols") {
] ]
} }
if (is_apple) {
swiftflags = [ "-g" ]
}
if (use_debug_fission && !is_nacl && !is_android) { if (use_debug_fission && !is_nacl && !is_android) {
# NOTE: Some Chrome OS builds globally set |use_debug_fission| to true, # NOTE: Some Chrome OS builds globally set |use_debug_fission| to true,
# but they also build some targets against Android toolchains which aren't # but they also build some targets against Android toolchains which aren't
......
...@@ -36,23 +36,44 @@ config("compiler") { ...@@ -36,23 +36,44 @@ config("compiler") {
"-arch", "-arch",
"x86_64", "x86_64",
] ]
swiftflags = [
"-target",
"x86_64-apple-ios$ios_deployment_target-simulator",
]
} else if (current_cpu == "x86") { } else if (current_cpu == "x86") {
common_ios_flags += [ common_ios_flags += [
"-arch", "-arch",
"i386", "i386",
] ]
swiftflags = [
"-target",
"i386-apple-ios$ios_deployment_target-simulator",
]
} else if (current_cpu == "armv7" || current_cpu == "arm") { } else if (current_cpu == "armv7" || current_cpu == "arm") {
common_ios_flags += [ common_ios_flags += [
"-arch", "-arch",
"armv7", "armv7",
] ]
swiftflags = [
"-target",
"armv7-apple-ios$ios_deployment_target",
]
} else if (current_cpu == "arm64") { } else if (current_cpu == "arm64") {
common_ios_flags += [ common_ios_flags += [
"-arch", "-arch",
"arm64", "arm64",
] ]
swiftflags = [
"-target",
"arm64-apple-ios$ios_deployment_target",
]
} }
swiftflags += [
"-swift-version",
"5",
]
# This is here so that all files get recompiled after an Xcode update. # This is here so that all files get recompiled after an Xcode update.
# (defines are passed via the command line, and build system rebuild things # (defines are passed via the command line, and build system rebuild things
# when their commandline changes). Nothing should ever read this define. # when their commandline changes). Nothing should ever read this define.
...@@ -78,11 +99,19 @@ config("runtime_library") { ...@@ -78,11 +99,19 @@ config("runtime_library") {
"-isysroot", "-isysroot",
rebase_path(sysroot, root_build_dir), rebase_path(sysroot, root_build_dir),
] ]
swiftflags = [
"-sdk",
rebase_path(sysroot, root_build_dir),
]
} else { } else {
common_flags = [ common_flags = [
"-isysroot", "-isysroot",
sysroot, sysroot,
] ]
swiftflags = [
"-sdk",
sysroot,
]
} }
if (use_ios_simulator) { if (use_ios_simulator) {
...@@ -113,6 +142,7 @@ config("ios_executable_flags") { ...@@ -113,6 +142,7 @@ config("ios_executable_flags") {
config("ios_dynamic_flags") { config("ios_dynamic_flags") {
ldflags = [ "-Wl,-ObjC" ] # Always load Objective-C categories and class. ldflags = [ "-Wl,-ObjC" ] # Always load Objective-C categories and class.
lib_dirs = [ "$sysroot/usr/lib/swift" ]
} }
config("xctest_config") { config("xctest_config") {
......
...@@ -33,6 +33,17 @@ declare_args() { ...@@ -33,6 +33,17 @@ declare_args() {
# https://reviews.llvm.org/rL368199 but that has not yet made it into a public # https://reviews.llvm.org/rL368199 but that has not yet made it into a public
# lldb release. # lldb release.
mac_deterministic_build = false mac_deterministic_build = false
# This controls whether whole module optimization is enabled when building
# Swift modules. If enabled, the compiler will compile the module as one
# unit, generating just one single object file. Otherwise, it will generate
# one object file per .swift file. If unspecified, will default to "true"
# for official builds, and "false" for all other builds.
swift_whole_module_optimization = -1
}
if (swift_whole_module_optimization == -1) {
swift_whole_module_optimization = is_official_build
} }
if (current_toolchain == default_toolchain) { if (current_toolchain == default_toolchain) {
...@@ -95,6 +106,8 @@ template("mac_toolchain") { ...@@ -95,6 +106,8 @@ template("mac_toolchain") {
_cc = "${prefix}clang" _cc = "${prefix}clang"
_cxx = "${prefix}clang++" _cxx = "${prefix}clang++"
swiftmodule_switch = "-Wl,-add_ast_path,"
# When the invoker has explicitly overridden use_goma or cc_wrapper in the # When the invoker has explicitly overridden use_goma or cc_wrapper in the
# toolchain args, use those values, otherwise default to the global one. # toolchain args, use those values, otherwise default to the global one.
# This works because the only reasonable override that toolchains might # This works because the only reasonable override that toolchains might
...@@ -304,7 +317,7 @@ template("mac_toolchain") { ...@@ -304,7 +317,7 @@ template("mac_toolchain") {
link_command += " -Wl,-install_name,@rpath/\"{{target_output_name}}{{output_extension}}\" " link_command += " -Wl,-install_name,@rpath/\"{{target_output_name}}{{output_extension}}\" "
} }
link_command += dsym_switch link_command += dsym_switch
link_command += "{{ldflags}} -o \"$dylib\" -Wl,-filelist,\"$rspfile\" {{frameworks}} {{solibs}} {{libs}}" link_command += "{{ldflags}} -o \"$dylib\" -Wl,-filelist,\"$rspfile\" {{frameworks}} {{swiftmodules}} {{solibs}} {{libs}}"
replace_command = "if ! cmp -s \"$temporary_tocname\" \"$tocname\"; then mv \"$temporary_tocname\" \"$tocname\"" replace_command = "if ! cmp -s \"$temporary_tocname\" \"$tocname\"; then mv \"$temporary_tocname\" \"$tocname\""
extract_toc_command = "{ $otool -l \"$dylib\" | grep LC_ID_DYLIB -A 5; $nm -gPp \"$dylib\" | cut -f1-2 -d' ' | grep -v U\$\$; true; }" extract_toc_command = "{ $otool -l \"$dylib\" | grep LC_ID_DYLIB -A 5; $nm -gPp \"$dylib\" | cut -f1-2 -d' ' | grep -v U\$\$; true; }"
...@@ -356,7 +369,7 @@ template("mac_toolchain") { ...@@ -356,7 +369,7 @@ template("mac_toolchain") {
link_command += " -Wl,-install_name,@rpath/{{target_output_name}}{{output_extension}}" link_command += " -Wl,-install_name,@rpath/{{target_output_name}}{{output_extension}}"
} }
link_command += dsym_switch link_command += dsym_switch
link_command += " {{frameworks}} {{solibs}} {{libs}}" link_command += " {{frameworks}} {{swiftmodules}} {{solibs}} {{libs}}"
command = link_command command = link_command
rspfile_content = "{{inputs_newline}}" rspfile_content = "{{inputs_newline}}"
...@@ -392,7 +405,7 @@ template("mac_toolchain") { ...@@ -392,7 +405,7 @@ template("mac_toolchain") {
# do for command-line arguments. Thus any source names with spaces, or # do for command-line arguments. Thus any source names with spaces, or
# label names with spaces (which GN bases the output paths on) will be # label names with spaces (which GN bases the output paths on) will be
# corrupted by this process. Don't use spaces for source files or labels. # corrupted by this process. Don't use spaces for source files or labels.
command = "$linker_driver $ld $dsym_switch {{ldflags}} -o \"$outfile\" -Wl,-filelist,\"$rspfile\" {{frameworks}} {{solibs}} {{libs}}" command = "$linker_driver $ld $dsym_switch {{ldflags}} -o \"$outfile\" -Wl,-filelist,\"$rspfile\" {{frameworks}} {{swiftmodules}} {{solibs}} {{libs}}"
description = "LINK $outfile" description = "LINK $outfile"
rspfile_content = "{{inputs_newline}}" rspfile_content = "{{inputs_newline}}"
outputs = [ outfile ] outputs = [ outfile ]
...@@ -436,6 +449,46 @@ template("mac_toolchain") { ...@@ -436,6 +449,46 @@ template("mac_toolchain") {
pool = ":bundle_pool($default_toolchain)" pool = ":bundle_pool($default_toolchain)"
} }
tool("swift") {
_tool = rebase_path("//build/apple/swiftc.py", root_build_dir)
depfile = "{{target_out_dir}}/{{module_name}}.d"
depsformat = "gcc"
outputs = [
# The module needs to be the first output listed. The blank line after
# the module is required to prevent `gn format` from changing the file
# order.
"{{target_gen_dir}}/{{module_name}}.swiftmodule",
"{{target_gen_dir}}/{{module_name}}.h",
"{{target_gen_dir}}/{{module_name}}.swiftdoc",
"{{target_gen_dir}}/{{module_name}}.swiftsourceinfo",
]
if (swift_whole_module_optimization) {
_extra_flags = "-whole-module-optimization"
_objects_dir = "{{target_out_dir}}"
outputs += [ "$_objects_dir/{{module_name}}.o" ]
} else {
_extra_flags = ""
_objects_dir = "{{target_out_dir}}/{{label_name}}"
partial_outputs = [ "$_objects_dir/{{source_name_part}}.o" ]
}
command =
"$_tool -module-name {{module_name}} " +
"-object-dir $_objects_dir " +
"-module-path {{target_gen_dir}}/{{module_name}}.swiftmodule " +
"-header-path {{target_gen_dir}}/{{module_name}}.h " +
"-depfile {{target_out_dir}}/{{module_name}}.d " +
"-depfile-filter {{target_gen_dir}}/{{module_name}}.swiftmodule " +
"-bridge-header {{bridge_header}} $_extra_flags " +
"{{swiftflags}} {{include_dirs}} {{module_dirs}} {{inputs}}"
}
# xcassets are only used on iOS, not macOS. We want to minimize the number # xcassets are only used on iOS, not macOS. We want to minimize the number
# of Xcode-based tools used by the macOS toolchain, so we intentionally # of Xcode-based tools used by the macOS toolchain, so we intentionally
# disallow future uses of xcassets on macOS. https://crbug.com/965663. # disallow future uses of xcassets on macOS. https://crbug.com/965663.
......
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