blob: 0520317b2b55c3c223e49e112e78eca9e44ab6e9 [file] [log] [blame]
#!/usr/bin/env python
# utils/build-script - The ultimate tool for building Swift -*- python -*-
#
# This source file is part of the Swift.org open source project
#
# Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
# Licensed under Apache License v2.0 with Runtime Library Exception
#
# See https://swift.org/LICENSE.txt for license information
# See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
from __future__ import print_function
import argparse
import multiprocessing
import os
import pipes
import platform
import sys
# FIXME: Instead of modifying the system path in order to enable imports from
# other directories, all Python modules related to the build script
# should be moved to the `swift_build_support` module. Remove "noqa"
# markers when this is fixed.
# For additional information, see: https://bugs.swift.org/browse/SR-237.
sys.path.append(os.path.dirname(__file__))
from SwiftBuildSupport import (
HOME,
SWIFT_BUILD_ROOT,
SWIFT_SOURCE_ROOT,
get_all_preset_names,
get_preset_options,
) # noqa (E402 module level import not at top of file)
sys.path.append(os.path.join(os.path.dirname(__file__), 'swift_build_support'))
# E402 means module level import not at top of file
from swift_build_support import arguments # noqa (E402)
from swift_build_support import diagnostics # noqa (E402)
from swift_build_support import host # noqa (E402)
from swift_build_support.toolchain import host_toolchain # noqa (E402)
import swift_build_support.debug # noqa (E402)
from swift_build_support import migration # noqa (E402)
from swift_build_support import products # noqa (E402)
from swift_build_support import shell # noqa (E402)
import swift_build_support.tar # noqa (E402)
import swift_build_support.targets # noqa (E402)
from swift_build_support.targets import StdlibDeploymentTarget # noqa (E402)
from swift_build_support.cmake import CMake # noqa (E402)
import swift_build_support.workspace # noqa (E402)
sys.path.append(os.path.join(os.path.dirname(__file__), 'android'))
import adb.commands # noqa (E402)
build_script_impl = os.path.join(
SWIFT_SOURCE_ROOT, "swift", "utils", "build-script-impl")
def call_without_sleeping(command, env=None, dry_run=False, echo=False):
"""
Execute a command during which system sleep is disabled.
By default, this ignores the state of the `shell.dry_run` flag.
"""
# Disable system sleep, if possible.
if platform.system() == 'Darwin':
# Don't mutate the caller's copy of the arguments.
command = ["caffeinate"] + list(command)
shell.call(command, env=env, dry_run=dry_run, echo=echo)
class HostSpecificConfiguration(object):
"""Configuration information for an individual host."""
def __init__(self, host_target, invocation):
"""Initialize for the given `host_target`."""
# Compute the set of deployment targets to configure/build.
args = invocation.args
if host_target == args.host_target:
# This host is the user's desired product, so honor the requested
# set of targets to configure/build.
stdlib_targets_to_configure = args.stdlib_deployment_targets
if "all" in args.build_stdlib_deployment_targets:
stdlib_targets_to_build = set(stdlib_targets_to_configure)
else:
stdlib_targets_to_build = set(
args.build_stdlib_deployment_targets).intersection(
set(args.stdlib_deployment_targets))
else:
# Otherwise, this is a host we are building as part of
# cross-compiling, so we only need the target itself.
stdlib_targets_to_configure = [host_target]
stdlib_targets_to_build = set(stdlib_targets_to_configure)
# Compute the lists of **CMake** targets for each use case (configure
# vs. build vs. run) and the SDKs to configure with.
self.sdks_to_configure = set()
self.swift_stdlib_build_targets = []
self.swift_test_run_targets = []
self.swift_benchmark_build_targets = []
self.swift_benchmark_run_targets = []
for deployment_target_name in stdlib_targets_to_configure:
# Get the target object.
deployment_target = StdlibDeploymentTarget.get_target_for_name(
deployment_target_name)
if deployment_target is None:
diagnostics.fatal("unknown target: %r" % (
deployment_target_name,))
# Add the SDK to use.
deployment_platform = deployment_target.platform
self.sdks_to_configure.add(deployment_platform.sdk_name)
# If we aren't actually building this target (only configuring
# it), do nothing else.
if deployment_target_name not in stdlib_targets_to_build:
continue
# Compute which actions are desired.
build = (
deployment_platform not in invocation.platforms_to_skip_build)
test = (
deployment_platform not in invocation.platforms_to_skip_test)
test_host_only = None
build_benchmark = build and deployment_target.supports_benchmark
# FIXME: Note, `build-script-impl` computed a property here
# w.r.t. testing, but it was actually unused.
# For platforms which normally require a connected device to
# test, the default behavior is to run tests that only require
# the host (i.e., they do not attempt to execute).
if deployment_platform.is_darwin and \
deployment_platform.is_embedded and \
not deployment_platform.is_simulator:
if deployment_platform not in \
invocation.platforms_to_skip_test_host:
test_host_only = True
test = True
else:
test = False
name = deployment_target.name
if build:
# Validation and long tests require building the full standard
# library, whereas the other targets can build a slightly
# smaller subset which is faster to build.
if args.build_swift_stdlib_unittest_extra or \
args.validation_test or args.long_test:
self.swift_stdlib_build_targets.append(
"swift-stdlib-" + name)
else:
self.swift_stdlib_build_targets.append(
"swift-test-stdlib-" + name)
if build_benchmark:
self.swift_benchmark_build_targets.append(
"swift-benchmark-" + name)
# FIXME: This probably should respect `args.benchmark`, but
# a typo in build-script-impl meant we always would do this.
self.swift_benchmark_run_targets.append(
"check-swift-benchmark-" + name)
if test:
if test_host_only:
suffix = "-non-executable"
else:
suffix = ""
subset_suffix = ""
if args.validation_test and args.long_test:
subset_suffix = "-all"
elif args.validation_test:
subset_suffix = "-validation"
elif args.long_test:
subset_suffix = "-only_long"
else:
subset_suffix = ""
self.swift_test_run_targets.append("check-swift{}{}-{}".format(
subset_suffix, suffix, name))
if args.test_optimized and not test_host_only:
self.swift_test_run_targets.append(
"check-swift{}-optimize-{}".format(
subset_suffix, name))
class BuildScriptInvocation(object):
"""Represent a single build script invocation."""
@staticmethod
def validate_arguments(toolchain, args):
if toolchain.cc is None or toolchain.cxx is None:
diagnostics.fatal(
"can't find clang (please install clang-3.5 or a "
"later version)")
if toolchain.cmake is None:
diagnostics.fatal("can't find CMake (please install CMake)")
if args.distcc:
if toolchain.distcc is None:
diagnostics.fatal(
"can't find distcc (please install distcc)")
if toolchain.distcc_pump is None:
diagnostics.fatal(
"can't find distcc-pump (please install distcc-pump)")
if args.host_target is None or args.stdlib_deployment_targets is None:
diagnostics.fatal("unknown operating system")
if args.symbols_package:
if not os.path.isabs(args.symbols_package):
print(
'--symbols-package must be an absolute path '
'(was \'{}\')'.format(args.symbols_package))
return 1
if not args.install_symroot:
diagnostics.fatal(
"--install-symroot is required when specifying "
"--symbols-package.")
if args.android:
if args.android_ndk is None or \
args.android_api_level is None or \
args.android_icu_uc is None or \
args.android_icu_uc_include is None or \
args.android_icu_i18n is None or \
args.android_icu_i18n_include is None:
diagnostics.fatal(
"when building for Android, --android-ndk, "
"--android-ndk-version, --android-icu-uc, "
"--android-icu-uc-include, --android-icu-i18n, "
"and --android-icu-i18n-include must be specified")
@staticmethod
def apply_default_arguments(toolchain, args):
"""Preprocess an argument set to apply default behaviors."""
# Build cmark if any cmark-related options were specified.
if (args.cmark_build_variant is not None):
args.build_cmark = True
# Build LLDB if any LLDB-related options were specified.
if args.lldb_build_variant is not None or \
args.lldb_assertions is not None:
args.build_lldb = True
# Set the default build variant.
if args.build_variant is None:
args.build_variant = "Debug"
# Set the default stdlib-deployment-targets, if none were provided.
if args.stdlib_deployment_targets is None:
stdlib_targets = \
StdlibDeploymentTarget.default_stdlib_deployment_targets()
args.stdlib_deployment_targets = [
target.name for target in stdlib_targets]
# Propagate the default build variant.
if args.cmark_build_variant is None:
args.cmark_build_variant = args.build_variant
if args.llvm_build_variant is None:
args.llvm_build_variant = args.build_variant
if args.swift_build_variant is None:
args.swift_build_variant = args.build_variant
if args.swift_stdlib_build_variant is None:
args.swift_stdlib_build_variant = args.build_variant
if args.lldb_build_variant is None:
args.lldb_build_variant = args.build_variant
if args.foundation_build_variant is None:
args.foundation_build_variant = args.build_variant
if args.libdispatch_build_variant is None:
args.libdispatch_build_variant = args.build_variant
if args.libicu_build_variant is None:
args.libicu_build_variant = args.build_variant
# Assertions are enabled by default.
if args.assertions is None:
args.assertions = True
# Propagate the default assertions setting.
if args.cmark_assertions is None:
args.cmark_assertions = args.assertions
if args.llvm_assertions is None:
args.llvm_assertions = args.assertions
if args.swift_assertions is None:
args.swift_assertions = args.assertions
if args.swift_stdlib_assertions is None:
args.swift_stdlib_assertions = args.assertions
# Set the default CMake generator.
if args.cmake_generator is None:
args.cmake_generator = "Ninja"
ninja_required = (
args.cmake_generator == 'Ninja' or args.build_foundation)
if ninja_required and toolchain.ninja is None:
args.build_ninja = True
# SwiftPM and XCTest have a dependency on Foundation.
# On OS X, Foundation is built automatically using xcodebuild.
# On Linux, we must ensure that it is built manually.
if ((args.build_swiftpm or args.build_xctest) and
platform.system() != "Darwin"):
args.build_foundation = True
# Foundation has a dependency on libdispatch.
# On OS X, libdispatch is provided by the OS.
# On Linux, we must ensure that it is built manually.
if (args.build_foundation and
platform.system() != "Darwin"):
args.build_libdispatch = True
# Propagate global --skip-build
if args.skip_build:
args.skip_build_linux = True
args.skip_build_freebsd = True
args.skip_build_cygwin = True
args.skip_build_osx = True
args.skip_build_ios = True
args.skip_build_tvos = True
args.skip_build_watchos = True
args.skip_build_android = True
args.skip_build_benchmarks = True
args.build_lldb = False
args.build_llbuild = False
args.build_swiftpm = False
args.build_xctest = False
args.build_foundation = False
args.build_libdispatch = False
args.build_libicu = False
args.build_playgroundlogger = False
args.build_playgroundsupport = False
# --skip-{ios,tvos,watchos} or --skip-build-{ios,tvos,watchos} are
# merely shorthands for --skip-build-{**os}-{device,simulator}
if not args.ios or args.skip_build_ios:
args.skip_build_ios_device = True
args.skip_build_ios_simulator = True
if not args.tvos or args.skip_build_tvos:
args.skip_build_tvos_device = True
args.skip_build_tvos_simulator = True
if not args.watchos or args.skip_build_watchos:
args.skip_build_watchos_device = True
args.skip_build_watchos_simulator = True
if not args.android or args.skip_build_android:
args.skip_build_android = True
# --validation-test implies --test.
if args.validation_test:
args.test = True
# --test-optimized implies --test.
if args.test_optimized:
args.test = True
# If none of tests specified skip swift stdlib test on all platforms
if not args.test and not args.validation_test and not args.long_test:
args.skip_test_linux = True
args.skip_test_freebsd = True
args.skip_test_cygwin = True
args.skip_test_osx = True
args.skip_test_ios = True
args.skip_test_tvos = True
args.skip_test_watchos = True
# --skip-test-ios is merely a shorthand for host and simulator tests.
if args.skip_test_ios:
args.skip_test_ios_host = True
args.skip_test_ios_simulator = True
# --skip-test-tvos is merely a shorthand for host and simulator tests.
if args.skip_test_tvos:
args.skip_test_tvos_host = True
args.skip_test_tvos_simulator = True
# --skip-test-watchos is merely a shorthand for host and simulator
# --tests.
if args.skip_test_watchos:
args.skip_test_watchos_host = True
args.skip_test_watchos_simulator = True
# --skip-build-{ios,tvos,watchos}-{device,simulator} implies
# --skip-test-{ios,tvos,watchos}-{host,simulator}
if args.skip_build_ios_device:
args.skip_test_ios_host = True
if args.skip_build_ios_simulator:
args.skip_test_ios_simulator = True
if args.skip_build_tvos_device:
args.skip_test_tvos_host = True
if args.skip_build_tvos_simulator:
args.skip_test_tvos_simulator = True
if args.skip_build_watchos_device:
args.skip_test_watchos_host = True
if args.skip_build_watchos_simulator:
args.skip_test_watchos_simulator = True
if args.skip_build_android:
args.skip_test_android_host = True
if not args.host_test:
args.skip_test_ios_host = True
args.skip_test_tvos_host = True
args.skip_test_watchos_host = True
args.skip_test_android_host = True
if args.build_subdir is None:
args.build_subdir = \
swift_build_support.workspace.compute_build_subdir(args)
# Add optional stdlib-deployment-targets
if args.android:
args.stdlib_deployment_targets.append(
StdlibDeploymentTarget.Android.armv7.name)
# Infer platform flags from manually-specified configure targets.
# This doesn't apply to Darwin platforms, as they are
# already configured. No building without the platform flag, though.
android_tgts = [tgt for tgt in args.stdlib_deployment_targets
if StdlibDeploymentTarget.Android.contains(tgt)]
if not args.android and len(android_tgts) > 0:
args.android = True
args.skip_build_android = True
# ---
def __init__(self, toolchain, args):
self.toolchain = toolchain
self.args = args
self.workspace = swift_build_support.workspace.Workspace(
source_root=SWIFT_SOURCE_ROOT,
build_root=os.path.join(SWIFT_BUILD_ROOT, args.build_subdir))
# Compute derived information from the arguments.
#
# FIXME: We should move the platform-derived arguments to be entirely
# data driven, so that we can eliminate this code duplication and just
# iterate over all supported platforms.
self.platforms_to_skip_build = set()
if args.skip_build_linux:
self.platforms_to_skip_build.add(StdlibDeploymentTarget.Linux)
if args.skip_build_freebsd:
self.platforms_to_skip_build.add(StdlibDeploymentTarget.FreeBSD)
if args.skip_build_cygwin:
self.platforms_to_skip_build.add(StdlibDeploymentTarget.Cygwin)
if args.skip_build_osx:
self.platforms_to_skip_build.add(StdlibDeploymentTarget.OSX)
if args.skip_build_ios_device:
self.platforms_to_skip_build.add(StdlibDeploymentTarget.iOS)
if args.skip_build_ios_simulator:
self.platforms_to_skip_build.add(
StdlibDeploymentTarget.iOSSimulator)
if args.skip_build_tvos_device:
self.platforms_to_skip_build.add(StdlibDeploymentTarget.AppleTV)
if args.skip_build_tvos_simulator:
self.platforms_to_skip_build.add(
StdlibDeploymentTarget.AppleTVSimulator)
if args.skip_build_watchos_device:
self.platforms_to_skip_build.add(StdlibDeploymentTarget.AppleWatch)
if args.skip_build_watchos_simulator:
self.platforms_to_skip_build.add(
StdlibDeploymentTarget.AppleWatchSimulator)
if args.skip_build_android:
self.platforms_to_skip_build.add(StdlibDeploymentTarget.Android)
self.platforms_to_skip_test = set()
if args.skip_test_linux:
self.platforms_to_skip_test.add(StdlibDeploymentTarget.Linux)
if args.skip_test_freebsd:
self.platforms_to_skip_test.add(StdlibDeploymentTarget.FreeBSD)
if args.skip_test_cygwin:
self.platforms_to_skip_test.add(StdlibDeploymentTarget.Cygwin)
if args.skip_test_osx:
self.platforms_to_skip_test.add(StdlibDeploymentTarget.OSX)
# iOS device tests are not supported.
self.platforms_to_skip_test.add(StdlibDeploymentTarget.iOS)
if args.skip_test_ios_simulator:
self.platforms_to_skip_test.add(
StdlibDeploymentTarget.iOSSimulator)
# tvOS device tests are not supported.
self.platforms_to_skip_test.add(StdlibDeploymentTarget.AppleTV)
if args.skip_test_tvos_simulator:
self.platforms_to_skip_test.add(
StdlibDeploymentTarget.AppleTVSimulator)
# watchOS device tests are not supported.
self.platforms_to_skip_test.add(StdlibDeploymentTarget.AppleWatch)
if args.skip_test_watchos_simulator:
self.platforms_to_skip_test.add(
StdlibDeploymentTarget.AppleWatchSimulator)
if args.skip_test_android_host:
self.platforms_to_skip_test.add(StdlibDeploymentTarget.Android)
self.platforms_to_skip_test_host = set()
if args.skip_test_ios_host:
self.platforms_to_skip_test_host.add(StdlibDeploymentTarget.iOS)
if args.skip_test_tvos_host:
self.platforms_to_skip_test_host.add(
StdlibDeploymentTarget.AppleTV)
if args.skip_test_watchos_host:
self.platforms_to_skip_test_host.add(
StdlibDeploymentTarget.AppleWatch)
def initialize_runtime_environment(self):
"""Change the program environment for building."""
# Set an appropriate default umask.
os.umask(0o022)
# Unset environment variables that might affect how tools behave.
for v in [
'MAKEFLAGS',
'SDKROOT',
'MACOSX_DEPLOYMENT_TARGET',
'IPHONEOS_DEPLOYMENT_TARGET',
'TVOS_DEPLOYMENT_TARGET',
'WATCHOS_DEPLOYMENT_TARGET']:
os.environ.pop(v, None)
def build_ninja(self):
if not os.path.exists(self.workspace.source_dir("ninja")):
diagnostics.fatal(
"can't find source directory for ninja "
"(tried %s)" % (self.workspace.source_dir("ninja")))
ninja_build = products.Ninja(
args=self.args,
toolchain=self.toolchain,
source_dir=self.workspace.source_dir("ninja"),
build_dir=self.workspace.build_dir("build", "ninja"))
ninja_build.do_build()
self.toolchain.ninja = ninja_build.ninja_bin_path
def convert_to_impl_arguments(self):
"""convert_to_impl_arguments() -> (env, args)
Convert the invocation to an environment and list of arguments suitable
for invoking `build-script-impl`.
"""
# Create local shadows, for convenience.
args = self.args
toolchain = self.toolchain
cmake = CMake(args=args,
toolchain=self.toolchain)
impl_args = [
"--workspace", self.workspace.source_root,
"--build-dir", self.workspace.build_root,
"--install-prefix", args.install_prefix,
"--host-target", args.host_target,
"--stdlib-deployment-targets",
" ".join(args.stdlib_deployment_targets),
"--host-cc", toolchain.cc,
"--host-cxx", toolchain.cxx,
"--darwin-xcrun-toolchain", args.darwin_xcrun_toolchain,
"--darwin-deployment-version-osx=%s" % (
args.darwin_deployment_version_osx),
"--darwin-deployment-version-ios=%s" % (
args.darwin_deployment_version_ios),
"--darwin-deployment-version-tvos=%s" % (
args.darwin_deployment_version_tvos),
"--darwin-deployment-version-watchos=%s" % (
args.darwin_deployment_version_watchos),
"--cmake", toolchain.cmake,
"--cmark-build-type", args.cmark_build_variant,
"--llvm-build-type", args.llvm_build_variant,
"--swift-build-type", args.swift_build_variant,
"--swift-stdlib-build-type", args.swift_stdlib_build_variant,
"--lldb-build-type", args.lldb_build_variant,
"--foundation-build-type", args.foundation_build_variant,
"--libdispatch-build-type", args.libdispatch_build_variant,
"--libicu-build-type", args.libicu_build_variant,
"--xctest-build-type", args.build_variant,
"--swift-enable-assertions", str(args.swift_assertions).lower(),
"--swift-stdlib-enable-assertions", str(
args.swift_stdlib_assertions).lower(),
"--swift-analyze-code-coverage", str(
args.swift_analyze_code_coverage).lower(),
"--cmake-generator", args.cmake_generator,
"--build-jobs", str(args.build_jobs),
"--common-cmake-options=%s" % ' '.join(
pipes.quote(opt) for opt in cmake.common_options()),
"--build-args=%s" % ' '.join(
pipes.quote(arg) for arg in cmake.build_args()),
]
# Compute any product specific cmake arguments.
for product_class in self.compute_product_classes():
product_name = product_class.product_name()
product = product_class(
args=args,
toolchain=self.toolchain,
source_dir=self.workspace.source_dir(product_name),
# FIXME: This is incorrect since it always assumes the host
# target I think?
build_dir=self.workspace.build_dir(
args.host_target, product_name))
cmake_opts = product.cmake_options
# FIXME: We should be using pipes.quote here but we run into issues
# with build-script-impl/cmake not being happy with all of the
# extra "'" in the strings. To fix this easily, we really need to
# just invoke cmake from build-script directly rather than futzing
# with build-script-impl. This makes even more sense since there
# really isn't a security issue here.
impl_args += [
"--%s-cmake-options=%s" % (product_name, ' '.join(cmake_opts))
]
if args.build_stdlib_deployment_targets:
impl_args += [
"--build-stdlib-deployment-targets", " ".join(
args.build_stdlib_deployment_targets)]
if args.cross_compile_hosts:
impl_args += [
"--cross-compile-hosts", " ".join(args.cross_compile_hosts)]
if toolchain.ninja:
impl_args += ["--ninja-bin=%s" % toolchain.ninja]
if args.distcc:
impl_args += [
"--distcc",
"--distcc-pump=%s" % toolchain.distcc_pump
]
if args.enable_asan:
impl_args += ["--enable-asan"]
if args.enable_ubsan:
impl_args += ["--enable-ubsan"]
if args.verbose_build:
impl_args += ["--verbose-build"]
if args.install_symroot:
impl_args += [
"--install-symroot", os.path.abspath(args.install_symroot)
]
if args.skip_build:
impl_args += ["--skip-build-cmark",
"--skip-build-llvm",
"--skip-build-swift"]
if args.skip_build_benchmarks:
impl_args += ["--skip-build-benchmarks"]
if not args.build_foundation:
impl_args += ["--skip-build-foundation"]
if not args.build_xctest:
impl_args += ["--skip-build-xctest"]
if not args.build_lldb:
impl_args += ["--skip-build-lldb"]
if not args.build_llbuild:
impl_args += ["--skip-build-llbuild"]
if not args.build_libdispatch:
impl_args += ["--skip-build-libdispatch"]
if not args.build_libicu:
impl_args += ["--skip-build-libicu"]
if not args.build_swiftpm:
impl_args += ["--skip-build-swiftpm"]
if not args.build_playgroundlogger:
impl_args += ["--skip-build-playgroundlogger"]
if not args.build_playgroundsupport:
impl_args += ["--skip-build-playgroundsupport"]
if args.build_swift_dynamic_stdlib:
impl_args += ["--build-swift-dynamic-stdlib"]
if args.build_swift_static_stdlib:
impl_args += ["--build-swift-static-stdlib"]
if args.build_swift_stdlib_unittest_extra:
impl_args += ["--build-swift-stdlib-unittest-extra"]
if args.build_swift_dynamic_sdk_overlay:
impl_args += ["--build-swift-dynamic-sdk-overlay"]
if args.build_swift_static_sdk_overlay:
impl_args += ["--build-swift-static-sdk-overlay"]
if args.skip_build_linux:
impl_args += ["--skip-build-linux"]
if args.skip_build_freebsd:
impl_args += ["--skip-build-freebsd"]
if args.skip_build_cygwin:
impl_args += ["--skip-build-cygwin"]
if args.skip_build_osx:
impl_args += ["--skip-build-osx"]
if args.skip_build_ios_device:
impl_args += ["--skip-build-ios-device"]
if args.skip_build_ios_simulator:
impl_args += ["--skip-build-ios-simulator"]
if args.skip_build_tvos_device:
impl_args += ["--skip-build-tvos-device"]
if args.skip_build_tvos_simulator:
impl_args += ["--skip-build-tvos-simulator"]
if args.skip_build_watchos_device:
impl_args += ["--skip-build-watchos-device"]
if args.skip_build_watchos_simulator:
impl_args += ["--skip-build-watchos-simulator"]
if args.skip_build_android:
impl_args += ["--skip-build-android"]
if not args.test and not args.long_test:
impl_args += ["--skip-test-swift"]
if not args.test:
impl_args += ["--skip-test-cmark",
"--skip-test-lldb",
"--skip-test-llbuild",
"--skip-test-swiftpm",
"--skip-test-xctest",
"--skip-test-foundation",
"--skip-test-libdispatch",
"--skip-test-libicu",
"--skip-test-playgroundlogger",
"--skip-test-playgroundsupport"]
if args.skip_test_linux:
impl_args += ["--skip-test-linux"]
if args.skip_test_freebsd:
impl_args += ["--skip-test-freebsd"]
if args.skip_test_cygwin:
impl_args += ["--skip-test-cygwin"]
if args.skip_test_osx:
impl_args += ["--skip-test-osx"]
if args.skip_test_ios_host:
impl_args += ["--skip-test-ios-host"]
if args.skip_test_ios_simulator:
impl_args += ["--skip-test-ios-simulator"]
if args.skip_test_tvos_host:
impl_args += ["--skip-test-tvos-host"]
if args.skip_test_tvos_simulator:
impl_args += ["--skip-test-tvos-simulator"]
if args.skip_test_watchos_host:
impl_args += ["--skip-test-watchos-host"]
if args.skip_test_watchos_simulator:
impl_args += ["--skip-test-watchos-simulator"]
if args.skip_test_android_host:
impl_args += ["--skip-test-android-host"]
if args.build_runtime_with_host_compiler:
impl_args += ["--build-runtime-with-host-compiler"]
if args.validation_test:
impl_args += ["--validation-test"]
if args.long_test:
impl_args += ["--long-test"]
if not args.benchmark:
impl_args += ["--skip-test-benchmarks"]
if not args.test_optimized:
impl_args += ["--skip-test-optimized"]
if args.android:
impl_args += [
"--android-ndk", args.android_ndk,
"--android-api-level", args.android_api_level,
"--android-ndk-gcc-version",
args.android_ndk_gcc_version,
"--android-icu-uc", args.android_icu_uc,
"--android-icu-uc-include", args.android_icu_uc_include,
"--android-icu-i18n", args.android_icu_i18n,
"--android-icu-i18n-include", args.android_icu_i18n_include,
]
if args.android_deploy_device_path:
impl_args += [
"--android-deploy-device-path",
args.android_deploy_device_path,
]
if platform.system() == 'Darwin':
impl_args += [
"--toolchain-prefix",
swift_build_support.targets.darwin_toolchain_prefix(
args.install_prefix),
]
# If we have extra_swift_args, combine all of them together and then
# add them as one command.
if args.extra_swift_args:
impl_args += [
"--extra-swift-args",
";".join(args.extra_swift_args)]
# If we have extra_cmake_options, combine all of them together and then
# add them as one command.
if args.extra_cmake_options:
impl_args += [
"--extra-cmake-options=%s" % ' '.join(
pipes.quote(opt) for opt in args.extra_cmake_options)
]
if args.lto_type is not None:
impl_args += [
"--llvm-enable-lto=%s" % args.lto_type,
"--swift-tools-enable-lto=%s" % args.lto_type
]
if args.llvm_max_parallel_lto_link_jobs is not None:
impl_args += [
"--llvm-num-parallel-lto-link-jobs=%s" %
min(args.llvm_max_parallel_lto_link_jobs, args.build_jobs)
]
if args.swift_tools_max_parallel_lto_link_jobs is not None:
impl_args += [
"--swift-tools-num-parallel-lto-link-jobs=%s" %
min(args.swift_tools_max_parallel_lto_link_jobs,
args.build_jobs)
]
impl_args += args.build_script_impl_args
if args.dry_run:
impl_args += ["--dry-run"]
if args.clang_profile_instr_use:
impl_args += [
"--clang-profile-instr-use=%s" %
os.path.abspath(args.clang_profile_instr_use)
]
if args.lit_args:
impl_args += ["--llvm-lit-args=%s" % args.lit_args]
if args.coverage_db:
impl_args += [
"--coverage-db=%s" %
os.path.abspath(args.coverage_db)
]
# Compute the set of host-specific variables, which we pass through to
# the build script via environment variables.
host_specific_variables = self.compute_host_specific_variables()
impl_env = {}
for (host_target, options) in host_specific_variables.items():
for (name, value) in options.items():
# We mangle into an environment variable we can easily evaluate
# from the `build-script-impl`.
impl_env["HOST_VARIABLE_{}__{}".format(
host_target.replace("-", "_"), name)] = value
return (impl_env, impl_args)
def compute_host_specific_variables(self):
"""compute_host_specific_variables(args) -> dict
Compute the host-specific options, organized as a dictionary keyed by
host of options.
"""
args = self.args
options = {}
for host_target in [args.host_target] + args.cross_compile_hosts:
# Compute the host specific configuration.
config = HostSpecificConfiguration(host_target, self)
# Convert into `build-script-impl` style variables.
options[host_target] = {
"SWIFT_SDKS": " ".join(sorted(
config.sdks_to_configure)),
"SWIFT_STDLIB_TARGETS": " ".join(
config.swift_stdlib_build_targets),
"SWIFT_BENCHMARK_TARGETS": " ".join(
config.swift_benchmark_build_targets),
"SWIFT_RUN_BENCHMARK_TARGETS": " ".join(
config.swift_benchmark_run_targets),
"SWIFT_TEST_TARGETS": " ".join(
config.swift_test_run_targets),
}
return options
def compute_product_classes(self):
"""compute_product_classes() -> list
Compute the list of all Product classes used in this build. This list
is constructed in dependency order.
"""
# FIXME: This is a weird division (returning a list of class objects),
# but it matches the existing structure of the `build-script-impl`.
product_classes = []
product_classes.append(products.CMark)
product_classes.append(products.LLVM)
if self.args.build_libicu:
product_classes.append(products.LibICU)
product_classes.append(products.Swift)
if self.args.build_lldb:
product_classes.append(products.LLDB)
if self.args.build_llbuild:
product_classes.append(products.LLBuild)
if self.args.build_libdispatch:
product_classes.append(products.LibDispatch)
if self.args.build_foundation:
product_classes.append(products.Foundation)
if self.args.build_xctest:
product_classes.append(products.XCTest)
if self.args.build_swiftpm:
product_classes.append(products.SwiftPM)
return product_classes
def execute(self):
"""Execute the invocation with the configured arguments."""
# Convert to a build-script-impl invocation.
(impl_env, impl_args) = self.convert_to_impl_arguments()
# If using the legacy implementation, delegate all behavior to
# `build-script-impl`.
if self.args.legacy_impl:
# Execute the underlying build script implementation.
call_without_sleeping([build_script_impl] + impl_args,
env=impl_env, echo=True)
return
# Otherwise, we compute and execute the individual actions ourselves.
def execute_one_impl_action(host=None, product_class=None, name=None):
if host is None:
assert (product_class is None and
name == "merged-hosts-lipo"), "invalid action"
action_name = name
elif product_class is None:
assert name == "package", "invalid action"
action_name = "{}-{}".format(host.name, name)
else:
assert name is not None, "invalid action"
action_name = "{}-{}-{}".format(
host.name, product_class.product_name(), name)
call_without_sleeping(
[build_script_impl] + impl_args + [
"--only-execute", action_name],
env=impl_env, echo=self.args.verbose_build)
# Compute the list of hosts to operate on.
all_host_names = [
self.args.host_target] + self.args.cross_compile_hosts
all_hosts = [StdlibDeploymentTarget.get_target_for_name(name)
for name in all_host_names]
# Compute the list of product classes to operate on.
#
# FIXME: This should really be per-host, but the current structure
# matches that of `build-script-impl`.
product_classes = self.compute_product_classes()
# Execute each "pass".
# Build...
for host_target in all_hosts:
# FIXME: We should only compute these once.
config = HostSpecificConfiguration(host_target.name, self)
print("Building the standard library for: {}".format(
" ".join(config.swift_stdlib_build_targets)))
if config.swift_test_run_targets and (
self.args.test or self.args.long_test):
print("Running Swift tests for: {}".format(
" ".join(config.swift_test_run_targets)))
if config.swift_benchmark_run_targets and self.args.benchmark:
print("Running Swift benchmarks for: {}".format(
" ".join(config.swift_benchmark_run_targets)))
for product_class in product_classes:
execute_one_impl_action(host_target, product_class, "build")
# Test...
for host_target in all_hosts:
for product_class in product_classes:
execute_one_impl_action(host_target, product_class, "test")
# Install...
for host_target in all_hosts:
for product_class in product_classes:
execute_one_impl_action(host_target, product_class, "install")
# Package...
for host_target in all_hosts:
execute_one_impl_action(host_target, name="package")
# Lipo...
execute_one_impl_action(name="merged-hosts-lipo")
# Main entry point for the preset mode.
def main_preset():
parser = argparse.ArgumentParser(
formatter_class=argparse.RawDescriptionHelpFormatter,
description="""Builds Swift using a preset.""")
parser.add_argument(
"-n", "--dry-run",
help="print the commands that would be executed, but do not execute "
"them",
action="store_true",
default=False)
parser.add_argument(
"--preset-file",
help="load presets from the specified file",
metavar="PATH",
action="append",
dest="preset_file_names",
default=[])
parser.add_argument(
"--preset",
help="use the specified option preset",
metavar="NAME")
parser.add_argument(
"--show-presets",
help="list all presets and exit",
action=arguments.action.optional_bool)
parser.add_argument(
"--distcc",
help="use distcc",
action=arguments.action.optional_bool)
parser.add_argument(
"-j", "--jobs",
help="the number of parallel build jobs to use",
type=int,
dest="build_jobs")
parser.add_argument(
"preset_substitutions_raw",
help="'name=value' pairs that are substituted in the preset",
nargs="*",
metavar="SUBSTITUTION")
parser.add_argument(
"--expand-build-script-invocation",
help="Print the expanded build-script invocation generated "
"by the preset, but do not run the preset",
action=arguments.action.optional_bool)
args = parser.parse_args()
if len(args.preset_file_names) == 0:
args.preset_file_names = [
os.path.join(HOME, ".swift-build-presets"),
os.path.join(
SWIFT_SOURCE_ROOT, "swift", "utils", "build-presets.ini")
]
if args.show_presets:
for name in sorted(get_all_preset_names(args.preset_file_names),
key=str.lower):
print(name)
return 0
if not args.preset:
diagnostics.fatal("missing --preset option")
args.preset_substitutions = {}
for arg in args.preset_substitutions_raw:
name, value = arg.split("=", 1)
args.preset_substitutions[name] = value
preset_args = get_preset_options(
args.preset_substitutions, args.preset_file_names, args.preset)
build_script_args = [sys.argv[0]]
if args.dry_run:
build_script_args += ["--dry-run"]
build_script_args += preset_args
if args.distcc:
build_script_args += ["--distcc"]
if args.build_jobs:
build_script_args += ["--jobs", str(args.build_jobs)]
diagnostics.note(
"using preset '" + args.preset + "', which expands to \n\n" +
shell.quote_command(build_script_args) + "\n")
if args.expand_build_script_invocation:
return 0
call_without_sleeping(build_script_args)
return 0
# Main entry point for the normal mode.
def main_normal():
parser = argparse.ArgumentParser(
formatter_class=argparse.RawDescriptionHelpFormatter,
usage="""
%(prog)s [-h | --help] [OPTION ...]
%(prog)s --preset=NAME [SUBSTITUTION ...]
""",
description="""
Use this tool to build, test, and prepare binary distribution archives of Swift
and related tools.
Builds Swift (and, optionally, LLDB), incrementally, optionally
testing it thereafter. Different build configurations are maintained in
parallel.""",
epilog="""
Using option presets:
--preset-file=PATH load presets from the specified file
--preset=NAME use the specified option preset
The preset mode is mutually exclusive with other options. It is not
possible to add ad-hoc customizations to a preset. This is a deliberate
design decision. (Rationale: a preset is a certain important set of
options that we want to keep in a centralized location. If you need to
customize it, you should create another preset in a centralized location,
rather than scattering the knowledge about the build across the system.)
Presets support substitutions for controlled customizations. Substitutions
are defined in the preset file. Values for substitutions are supplied
using the name=value syntax on the command line.
Any arguments not listed are forwarded directly to Swift's
'build-script-impl'. See that script's help for details.
Environment variables
---------------------
This script respects a few environment variables, should you
choose to set them:
SWIFT_SOURCE_ROOT: a directory containing the source for LLVM, Clang, Swift.
If this script is located in a Swift
source directory, the location of SWIFT_SOURCE_ROOT will be
inferred if the variable is not set.
'build-script' expects the sources to be laid out in the following way:
$SWIFT_SOURCE_ROOT/llvm
/clang
/swift
/lldb (optional)
/llbuild (optional)
/swiftpm (optional, requires llbuild)
/compiler-rt (optional)
/swift-corelibs-xctest (optional)
/swift-corelibs-foundation (optional)
/swift-corelibs-libdispatch (optional)
/icu (optional)
SWIFT_BUILD_ROOT: a directory in which to create out-of-tree builds.
Defaults to "$SWIFT_SOURCE_ROOT/build/".
Preparing to run this script
----------------------------
See README.md for instructions on cloning Swift subprojects.
If you intend to use the -l, -L, --lldb, or --debug-lldb options.
That's it; you're ready to go!
Examples
--------
Given the above layout of sources, the simplest invocation of 'build-script' is
just:
[~/src/s]$ ./swift/utils/build-script
This builds LLVM, Clang, Swift and Swift standard library in debug mode.
All builds are incremental. To incrementally build changed files, repeat the
same 'build-script' command.
Typical uses of 'build-script'
------------------------------
To build everything with optimization without debug information:
[~/src/s]$ ./swift/utils/build-script -R
To run tests, add '-t':
[~/src/s]$ ./swift/utils/build-script -R -t
To run normal tests and validation tests, add '-T':
[~/src/s]$ ./swift/utils/build-script -R -T
To build LLVM+Clang with optimization without debug information, and a
debuggable Swift compiler:
[~/src/s]$ ./swift/utils/build-script -R --debug-swift
To build a debuggable Swift standard library:
[~/src/s]$ ./swift/utils/build-script -R --debug-swift-stdlib
iOS build targets are always configured and present, but are not built by
default. To build the standard library for OS X, iOS simulator and iOS device:
[~/src/s]$ ./swift/utils/build-script -R -i
To run OS X and iOS tests that don't require a device:
[~/src/s]$ ./swift/utils/build-script -R -i -t
To use 'make' instead of 'ninja', use '-m':
[~/src/s]$ ./swift/utils/build-script -m -R
To create Xcode projects that can build Swift, use '-x':
[~/src/s]$ ./swift/utils/build-script -x -R
Preset mode in build-script
---------------------------
All buildbots and automated environments use 'build-script' in *preset mode*.
In preset mode, the command line only specifies the preset name and allows
limited customization (extra output paths). The actual options come from
the selected preset in 'utils/build-presets.ini'. For example, to build like
the incremental buildbot, run:
[~/src/s]$ ./swift/utils/build-script --preset=buildbot_incremental
To build with AddressSanitizer:
[~/src/s]$ ./swift/utils/build-script --preset=asan
To build a root for Xcode XYZ, '/tmp/xcode-xyz-root.tar.gz':
[~/src/s]$ ./swift/utils/build-script --preset=buildbot_BNI_internal_XYZ \\
install_destdir="/tmp/install"
install_symroot="/tmp/symroot"
installable_package="/tmp/xcode-xyz-root.tar.gz"
If you have your own favorite set of options, you can create your own, local,
preset. For example, let's create a preset called 'ds' (which stands for
Debug Swift):
$ cat > ~/.swift-build-presets
[preset: ds]
release
debug-swift
debug-swift-stdlib
test
build-subdir=ds
To use it, specify the '--preset=' argument:
[~/src/s]$ ./swift/utils/build-script --preset=ds
./swift/utils/build-script: using preset 'ds', which expands to
./swift/utils/build-script --release --debug-swift --debug-swift-stdlib \
--test
--build-subdir=ds --
...
Philosophy
----------
While you can invoke CMake directly to build Swift, this tool will save you
time by taking away the mechanical parts of the process, providing you controls
for the important options.
For all automated build environments, this tool is regarded as *the* *only* way
to build Swift. This is not a technical limitation of the Swift build system.
It is a policy decision aimed at making the builds uniform across all
environments and easily reproducible by engineers who are not familiar with the
details of the setups of other systems or automated environments.""")
parser.add_argument(
"-n", "--dry-run",
help="print the commands that would be executed, but do not execute "
"them",
action="store_true",
default=False)
parser.add_argument(
"--no-legacy-impl", dest="legacy_impl",
help="avoid legacy implementation",
action="store_false",
default=True)
targets_group = parser.add_argument_group(
title="Host and cross-compilation targets")
targets_group.add_argument(
"--host-target",
help="The host target. LLVM, Clang, and Swift will be built for this "
"target. The built LLVM and Clang will be used to compile Swift "
"for the cross-compilation targets.",
default=StdlibDeploymentTarget.host_target().name)
targets_group.add_argument(
"--cross-compile-hosts",
help="A space separated list of targets to cross-compile host Swift "
"tools for. Can be used multiple times.",
action=arguments.action.concat, type=arguments.type.shell_split,
default=[])
targets_group.add_argument(
"--stdlib-deployment-targets",
help="list of targets to compile or cross-compile the Swift standard "
"library for. %(default)s by default.",
action=arguments.action.concat, type=arguments.type.shell_split,
default=None)
targets_group.add_argument(
"--build-stdlib-deployment-targets",
help="A space-separated list that filters which of the configured "
"targets to build the Swift standard library for, or 'all'.",
type=arguments.type.shell_split, default=["all"])
projects_group = parser.add_argument_group(
title="Options to select projects")
projects_group.add_argument(
"-l", "--lldb",
help="build LLDB",
action="store_true",
dest="build_lldb")
projects_group.add_argument(
"-b", "--llbuild",
help="build llbuild",
action="store_true",
dest="build_llbuild")
projects_group.add_argument(
"-p", "--swiftpm",
help="build swiftpm",
action="store_true",
dest="build_swiftpm")
projects_group.add_argument(
"--xctest",
help="build xctest",
action=arguments.action.optional_bool,
dest="build_xctest")
projects_group.add_argument(
"--foundation",
help="build foundation",
action=arguments.action.optional_bool,
dest="build_foundation")
projects_group.add_argument(
"--libdispatch",
help="build libdispatch",
action=arguments.action.optional_bool,
dest="build_libdispatch")
projects_group.add_argument(
"--libicu",
help="build libicu",
action=arguments.action.optional_bool,
dest="build_libicu")
projects_group.add_argument(
"--playgroundlogger",
help="build playgroundlogger",
action="store_true",
dest="build_playgroundlogger")
projects_group.add_argument(
"--playgroundsupport",
help="build PlaygroundSupport",
action="store_true",
dest="build_playgroundsupport")
projects_group.add_argument(
"--build-ninja",
help="build the Ninja tool",
action=arguments.action.optional_bool)
extra_actions_group = parser.add_argument_group(
title="Extra actions to perform before or in addition to building")
extra_actions_group.add_argument(
"-c", "--clean",
help="do a clean build",
action="store_true")
extra_actions_group.add_argument(
"--export-compile-commands",
help="generate compilation databases in addition to building",
action=arguments.action.optional_bool)
extra_actions_group.add_argument(
"--symbols-package",
metavar="PATH",
help="if provided, an archive of the symbols directory will be "
"generated at this path")
build_variant_group = parser.add_mutually_exclusive_group(required=False)
build_variant_group.add_argument(
"-d", "--debug",
help="build the Debug variant of everything (LLVM, Clang, Swift host "
"tools, target Swift standard libraries, LLDB (if enabled) "
"(default)",
action="store_const",
const="Debug",
dest="build_variant")
build_variant_group.add_argument(
"-r", "--release-debuginfo",
help="build the RelWithDebInfo variant of everything (default is "
"Debug)",
action="store_const",
const="RelWithDebInfo",
dest="build_variant")
build_variant_group.add_argument(
"-R", "--release",
help="build the Release variant of everything (default is Debug)",
action="store_const",
const="Release",
dest="build_variant")
build_variant_override_group = parser.add_argument_group(
title="Override build variant for a specific project")
build_variant_override_group.add_argument(
"--debug-llvm",
help="build the Debug variant of LLVM",
action="store_const",
const="Debug",
dest="llvm_build_variant")
build_variant_override_group.add_argument(
"--debug-swift",
help="build the Debug variant of Swift host tools",
action="store_const",
const="Debug",
dest="swift_build_variant")
build_variant_override_group.add_argument(
"--debug-swift-stdlib",
help="build the Debug variant of the Swift standard library and SDK "
"overlay",
action="store_const",
const="Debug",
dest="swift_stdlib_build_variant")
build_variant_override_group.add_argument(
"--debug-lldb",
help="build the Debug variant of LLDB",
action="store_const",
const="Debug",
dest="lldb_build_variant")
build_variant_override_group.add_argument(
"--debug-cmark",
help="build the Debug variant of CommonMark",
action="store_const",
const="Debug",
dest="cmark_build_variant")
build_variant_override_group.add_argument(
"--debug-foundation",
help="build the Debug variant of Foundation",
action="store_const",
const="Debug",
dest="foundation_build_variant")
build_variant_override_group.add_argument(
"--debug-libdispatch",
help="build the Debug variant of libdispatch",
action="store_const",
const="Debug",
dest="libdispatch_build_variant")
build_variant_override_group.add_argument(
"--debug-libicu",
help="build the Debug variant of libicu",
action="store_const",
const="Debug",
dest="libicu_build_variant")
assertions_group = parser.add_mutually_exclusive_group(required=False)
assertions_group.add_argument(
"--assertions",
help="enable assertions in all projects",
action="store_const",
const=True,
dest="assertions")
assertions_group.add_argument(
"--no-assertions",
help="disable assertions in all projects",
action="store_const",
const=False,
dest="assertions")
assertions_override_group = parser.add_argument_group(
title="Control assertions in a specific project")
assertions_override_group.add_argument(
"--cmark-assertions",
help="enable assertions in CommonMark",
action="store_const",
const=True,
dest="cmark_assertions")
assertions_override_group.add_argument(
"--llvm-assertions",
help="enable assertions in LLVM",
action="store_const",
const=True,
dest="llvm_assertions")
assertions_override_group.add_argument(
"--no-llvm-assertions",
help="disable assertions in LLVM",
action="store_const",
const=False,
dest="llvm_assertions")
assertions_override_group.add_argument(
"--swift-assertions",
help="enable assertions in Swift",
action="store_const",
const=True,
dest="swift_assertions")
assertions_override_group.add_argument(
"--no-swift-assertions",
help="disable assertions in Swift",
action="store_const",
const=False,
dest="swift_assertions")
assertions_override_group.add_argument(
"--swift-stdlib-assertions",
help="enable assertions in the Swift standard library",
action="store_const",
const=True,
dest="swift_stdlib_assertions")
assertions_override_group.add_argument(
"--no-swift-stdlib-assertions",
help="disable assertions in the Swift standard library",
action="store_const",
const=False,
dest="swift_stdlib_assertions")
assertions_override_group.add_argument(
"--lldb-assertions",
help="enable assertions in LLDB",
action="store_const",
const=True,
dest="lldb_assertions")
assertions_override_group.add_argument(
"--no-lldb-assertions",
help="disable assertions in LLDB",
action="store_const",
const=False,
dest="lldb_assertions")
# FIXME: This should be one option using choices=[...]
cmake_generator_group = parser.add_argument_group(
title="Select the CMake generator")
cmake_generator_group.add_argument(
"-x", "--xcode",
help="use CMake's Xcode generator (default is Ninja)",
action="store_const",
const="Xcode",
dest="cmake_generator")
cmake_generator_group.add_argument(
"-m", "--make",
help="use CMake's Makefile generator (default is Ninja)",
action="store_const",
const="Unix Makefiles",
dest="cmake_generator")
cmake_generator_group.add_argument(
"-e", "--eclipse",
help="use CMake's Eclipse generator (default is Ninja)",
action="store_const",
const="Eclipse CDT4 - Ninja",
dest="cmake_generator")
run_tests_group = parser.add_argument_group(
title="Run tests")
# NOTE: We can't merge -t and --test, because nargs='?' makes
# `-ti` to be treated as `-t=i`.
run_tests_group.add_argument(
"-t",
help="test Swift after building",
action="store_const",
const=True,
dest="test")
run_tests_group.add_argument(
"--test",
help="test Swift after building",
action=arguments.action.optional_bool)
run_tests_group.add_argument(
"-T",
help="run the validation test suite (implies --test)",
action="store_const",
const=True,
dest="validation_test")
run_tests_group.add_argument(
"--validation-test",
help="run the validation test suite (implies --test)",
action=arguments.action.optional_bool)
run_tests_group.add_argument(
"-o",
help="run the test suite in optimized mode too (implies --test)",
action="store_const",
const=True,
dest="test_optimized")
run_tests_group.add_argument(
"--test-optimized",
help="run the test suite in optimized mode too (implies --test)",
action=arguments.action.optional_bool)
run_tests_group.add_argument(
"--long-test",
help="run the long test suite",
action=arguments.action.optional_bool)
run_tests_group.add_argument(
"--host-test",
help="run executable tests on host devices (such as iOS or tvOS)",
action=arguments.action.optional_bool)
run_tests_group.add_argument(
"-B", "--benchmark",
help="run the Swift Benchmark Suite after building",
action="store_true")
run_tests_group.add_argument(
"--benchmark-num-o-iterations",
help="if the Swift Benchmark Suite is run after building, run N \
iterations with -O",
metavar='N', type=int, default=3)
run_tests_group.add_argument(
"--benchmark-num-onone-iterations",
help="if the Swift Benchmark Suite is run after building, run N \
iterations with -Onone", metavar='N', type=int, default=3)
run_tests_group.add_argument(
"--skip-test-osx",
help="skip testing Swift stdlibs for Mac OS X",
action=arguments.action.optional_bool)
run_tests_group.add_argument(
"--skip-test-linux",
help="skip testing Swift stdlibs for Linux",
action=arguments.action.optional_bool)
run_tests_group.add_argument(
"--skip-test-freebsd",
help="skip testing Swift stdlibs for FreeBSD",
action=arguments.action.optional_bool)
run_tests_group.add_argument(
"--skip-test-cygwin",
help="skip testing Swift stdlibs for Cygwin",
action=arguments.action.optional_bool)
parser.add_argument(
"--build-runtime-with-host-compiler",
help="Use the host compiler, not the self-built one to compile the "
"Swift runtime",
action=arguments.action.optional_bool)
run_build_group = parser.add_argument_group(
title="Run build")
run_build_group.add_argument(
"--build-swift-dynamic-stdlib",
help="build dynamic variants of the Swift standard library",
action=arguments.action.optional_bool,
default=True)
run_build_group.add_argument(
"--build-swift-static-stdlib",
help="build static variants of the Swift standard library",
action=arguments.action.optional_bool)
run_build_group.add_argument(
"--build-swift-dynamic-sdk-overlay",
help="build dynamic variants of the Swift SDK overlay",
action=arguments.action.optional_bool,
default=True)
run_build_group.add_argument(
"--build-swift-static-sdk-overlay",
help="build static variants of the Swift SDK overlay",
action=arguments.action.optional_bool)
run_build_group.add_argument(
"--build-swift-stdlib-unittest-extra",
help="Build optional StdlibUnittest components",
action=arguments.action.optional_bool)
run_build_group.add_argument(
"-S", "--skip-build",
help="generate build directory only without building",
action="store_true")
run_build_group.add_argument(
"--skip-build-linux",
help="skip building Swift stdlibs for Linux",
action=arguments.action.optional_bool)
run_build_group.add_argument(
"--skip-build-freebsd",
help="skip building Swift stdlibs for FreeBSD",
action=arguments.action.optional_bool)
run_build_group.add_argument(
"--skip-build-cygwin",
help="skip building Swift stdlibs for Cygwin",
action=arguments.action.optional_bool)
run_build_group.add_argument(
"--skip-build-osx",
help="skip building Swift stdlibs for MacOSX",
action=arguments.action.optional_bool)
run_build_group.add_argument(
"--skip-build-ios",
help="skip building Swift stdlibs for iOS",
action=arguments.action.optional_bool)
run_build_group.add_argument(
"--skip-build-ios-device",
help="skip building Swift stdlibs for iOS devices "
"(i.e. build simulators only)",
action=arguments.action.optional_bool)
run_build_group.add_argument(
"--skip-build-ios-simulator",
help="skip building Swift stdlibs for iOS simulator "
"(i.e. build devices only)",
action=arguments.action.optional_bool)
run_build_group.add_argument(
"--skip-build-tvos",
help="skip building Swift stdlibs for tvOS",
action=arguments.action.optional_bool)
run_build_group.add_argument(
"--skip-build-tvos-device",
help="skip building Swift stdlibs for tvOS devices "
"(i.e. build simulators only)",
action=arguments.action.optional_bool)
run_build_group.add_argument(
"--skip-build-tvos-simulator",
help="skip building Swift stdlibs for tvOS simulator "
"(i.e. build devices only)",
action=arguments.action.optional_bool)
run_build_group.add_argument(
"--skip-build-watchos",
help="skip building Swift stdlibs for watchOS",
action=arguments.action.optional_bool)
run_build_group.add_argument(
"--skip-build-watchos-device",
help="skip building Swift stdlibs for watchOS devices "
"(i.e. build simulators only)",
action=arguments.action.optional_bool)
run_build_group.add_argument(
"--skip-build-watchos-simulator",
help="skip building Swift stdlibs for watchOS simulator "
"(i.e. build devices only)",
action=arguments.action.optional_bool)
run_build_group.add_argument(
"--skip-build-android",
help="skip building Swift stdlibs for Android",
action=arguments.action.optional_bool)
run_build_group.add_argument(
"--skip-build-benchmarks",
help="skip building Swift Benchmark Suite",
action=arguments.action.optional_bool)
skip_test_group = parser.add_argument_group(
title="Skip testing specified targets")
skip_test_group.add_argument(
"--skip-test-ios",
help="skip testing all iOS targets. Equivalent to specifying both "
"--skip-test-ios-simulator and --skip-test-ios-host",
action=arguments.action.optional_bool)
skip_test_group.add_argument(
"--skip-test-ios-simulator",
help="skip testing iOS simulator targets",
action=arguments.action.optional_bool)
skip_test_group.add_argument(
"--skip-test-ios-host",
help="skip testing iOS device targets on the host machine (the phone "
"itself)",
action=arguments.action.optional_bool)
skip_test_group.add_argument(
"--skip-test-tvos",
help="skip testing all tvOS targets. Equivalent to specifying both "
"--skip-test-tvos-simulator and --skip-test-tvos-host",
action=arguments.action.optional_bool)
skip_test_group.add_argument(
"--skip-test-tvos-simulator",
help="skip testing tvOS simulator targets",
action=arguments.action.optional_bool)
skip_test_group.add_argument(
"--skip-test-tvos-host",
help="skip testing tvOS device targets on the host machine (the TV "
"itself)",
action=arguments.action.optional_bool)
skip_test_group.add_argument(
"--skip-test-watchos",
help="skip testing all tvOS targets. Equivalent to specifying both "
"--skip-test-watchos-simulator and --skip-test-watchos-host",
action=arguments.action.optional_bool)
skip_test_group.add_argument(
"--skip-test-watchos-simulator",
help="skip testing watchOS simulator targets",
action=arguments.action.optional_bool)
skip_test_group.add_argument(
"--skip-test-watchos-host",
help="skip testing watchOS device targets on the host machine (the "
"watch itself)",
action=arguments.action.optional_bool)
skip_test_group.add_argument(
"--skip-test-android-host",
help="skip testing Android device targets on the host machine (the "
"phone itself)",
action=arguments.action.optional_bool)
parser.add_argument(
"-i", "--ios",
help="also build for iOS, but disallow tests that require an iOS "
"device",
action="store_true")
parser.add_argument(
"--skip-ios",
help="set to skip everything iOS-related",
dest="ios",
action="store_false")
parser.add_argument(
"--tvos",
help="also build for tvOS, but disallow tests that require a tvos "
"device",
action=arguments.action.optional_bool)
parser.add_argument(
"--skip-tvos",
help="set to skip everything tvOS-related",
dest="tvos",
action="store_false")
parser.add_argument(
"--watchos",
help="also build for watchOS, but disallow tests that require an "
"watchOS device",
action=arguments.action.optional_bool)
parser.add_argument(
"--skip-watchos",
help="set to skip everything watchOS-related",
dest="watchos",
action="store_false")
parser.add_argument(
"--android",
help="also build for Android",
action=arguments.action.optional_bool)
parser.add_argument(
"--swift-analyze-code-coverage",
help="enable code coverage analysis in Swift (false, not-merged, "
"merged).",
choices=["false", "not-merged", "merged"],
default="false", # so CMake can see the inert mode as a false value
dest="swift_analyze_code_coverage")
parser.add_argument(
"--build-subdir",
help="name of the directory under $SWIFT_BUILD_ROOT where the build "
"products will be placed",
metavar="PATH")
parser.add_argument(
"--install-prefix",
help="The installation prefix. This is where built Swift products "
"(like bin, lib, and include) will be installed.",
metavar="PATH",
default=swift_build_support.targets.install_prefix())
parser.add_argument(
"--install-symroot",
help="the path to install debug symbols into",
metavar="PATH")
parser.add_argument(
"-j", "--jobs",
help="the number of parallel build jobs to use",
type=int,
dest="build_jobs",
default=multiprocessing.cpu_count())
parser.add_argument(
"--darwin-xcrun-toolchain",
help="the name of the toolchain to use on Darwin",
default="default")
parser.add_argument(
"--cmake",
help="the path to a CMake executable that will be used to build "
"Swift",
type=arguments.type.executable,
metavar="PATH")
parser.add_argument(
"--show-sdks",
help="print installed Xcode and SDK versions",
action=arguments.action.optional_bool)
parser.add_argument(
"--extra-swift-args",
help="Pass through extra flags to swift in the form of a cmake list "
"'module_regexp;flag'. Can be called multiple times to add "
"multiple such module_regexp flag pairs. All semicolons in flags "
"must be escaped with a '\\'",
action="append", dest="extra_swift_args", default=[])
llvm_group = parser.add_argument_group(
title="Build settings specific for LLVM")
llvm_group.add_argument(
'--llvm-targets-to-build',
help='LLVM target generators to build',
default="X86;ARM;AArch64;PowerPC;SystemZ")
android_group = parser.add_argument_group(
title="Build settings for Android")
android_group.add_argument(
"--android-ndk",
help="An absolute path to the NDK that will be used as a libc "
"implementation for Android builds",
metavar="PATH")
android_group.add_argument(
"--android-api-level",
help="The Android API level to target when building for Android. "
"Currently only 21 or above is supported",
default="21")
android_group.add_argument(
"--android-ndk-gcc-version",
help="The GCC version to use when building for Android. Currently "
"only 4.9 is supported. %(default)s is also the default value. "
"This option may be used when experimenting with versions "
"of the Android NDK not officially supported by Swift",
choices=["4.8", "4.9"],
default="4.9")
android_group.add_argument(
"--android-icu-uc",
help="Path to a directory containing libicuuc.so",
metavar="PATH")
android_group.add_argument(
"--android-icu-uc-include",
help="Path to a directory containing headers for libicuuc",
metavar="PATH")
android_group.add_argument(
"--android-icu-i18n",
help="Path to a directory containing libicui18n.so",
metavar="PATH")
android_group.add_argument(
"--android-icu-i18n-include",
help="Path to a directory containing headers libicui18n",
metavar="PATH")
android_group.add_argument(
"--android-deploy-device-path",
help="Path on an Android device to which built Swift stdlib products "
"will be deployed. If running host tests, specify the '{}' "
"directory.".format(adb.commands.DEVICE_TEMP_DIR),
default=adb.commands.DEVICE_TEMP_DIR,
metavar="PATH")
parser.add_argument(
"--host-cc",
help="the absolute path to CC, the 'clang' compiler for the host "
"platform. Default is auto detected.",
type=arguments.type.executable,
metavar="PATH")
parser.add_argument(
"--host-cxx",
help="the absolute path to CXX, the 'clang++' compiler for the host "
"platform. Default is auto detected.",
type=arguments.type.executable,
metavar="PATH")
parser.add_argument(
"--distcc",
help="use distcc in pump mode",
action=arguments.action.optional_bool)
parser.add_argument(
"--enable-asan",
help="enable Address Sanitizer",
action=arguments.action.optional_bool)
parser.add_argument(
"--enable-ubsan",
help="enable Undefined Behavior Sanitizer",
action=arguments.action.optional_bool)
parser.add_argument(
"--enable-tsan",
help="enable Thread Sanitizer for swift tools",
action=arguments.action.optional_bool)
parser.add_argument(
"--enable-tsan-runtime",
help="enable Thread Sanitizer on the swift runtime")
parser.add_argument(
"--compiler-vendor",
choices=["none", "apple"],
default="none",
help="Compiler vendor name")
parser.add_argument(
"--clang-compiler-version",
help="string that indicates a compiler version for Clang",
type=arguments.type.clang_compiler_version,
metavar="MAJOR.MINOR.PATCH")
parser.add_argument(
"--clang-user-visible-version",
help="User-visible version of the embedded Clang and LLVM compilers",
type=arguments.type.clang_compiler_version,
default="3.8.0",
metavar="MAJOR.MINOR.PATCH")
parser.add_argument(
"--swift-compiler-version",
help="string that indicates a compiler version for Swift",
type=arguments.type.swift_compiler_version,
metavar="MAJOR.MINOR")
parser.add_argument(
"--swift-user-visible-version",
help="User-visible version of the embedded Swift compiler",
type=arguments.type.swift_compiler_version,
default="3.0",
metavar="MAJOR.MINOR")
parser.add_argument(
"--darwin-deployment-version-osx",
help="minimum deployment target version for OS X",
metavar="MAJOR.MINOR",
default="10.9")
parser.add_argument(
"--darwin-deployment-version-ios",
help="minimum deployment target version for iOS",
metavar="MAJOR.MINOR",
default="7.0")
parser.add_argument(
"--darwin-deployment-version-tvos",
help="minimum deployment target version for tvOS",
metavar="MAJOR.MINOR",
default="9.0")
parser.add_argument(
"--darwin-deployment-version-watchos",
help="minimum deployment target version for watchOS",
metavar="MAJOR.MINOR",
default="2.0")
parser.add_argument(
"--extra-cmake-options",
help="Pass through extra options to CMake in the form of comma "
"separated options '-DCMAKE_VAR1=YES,-DCMAKE_VAR2=/tmp'. Can be "
"called multiple times to add multiple such options.",
action=arguments.action.concat,
type=arguments.type.shell_split,
default=[])
parser.add_argument(
"--build-args",
help="arguments to the build tool. This would be prepended to the "
"default argument that is '-j8' when CMake generator is "
"\"Ninja\".",
type=arguments.type.shell_split,
default=[])
parser.add_argument(
"--verbose-build",
help="print the commands executed during the build",
action=arguments.action.optional_bool)
parser.add_argument(
"--lto",
help="use lto optimization on llvm/swift tools. This does not "
"imply using lto on the swift standard library or runtime. "
"Options: thin, full. If no optional arg is provided, full is "
"chosen by default",
metavar="LTO_TYPE",
nargs='?',
choices=['thin', 'full'],
default=None,
const='full',
dest='lto_type')
parser.add_argument(
"--clang-profile-instr-use",
help="profile file to use for clang PGO",
metavar="PATH")
default_max_lto_link_job_counts = host.max_lto_link_job_counts()
parser.add_argument(
"--llvm-max-parallel-lto-link-jobs",
help="the maximum number of parallel link jobs to use when compiling "
"llvm",
metavar="COUNT",
default=default_max_lto_link_job_counts['llvm'])
parser.add_argument(
"--swift-tools-max-parallel-lto-link-jobs",
help="the maximum number of parallel link jobs to use when compiling "
"swift tools.",
metavar="COUNT",
default=default_max_lto_link_job_counts['swift'])
parser.add_argument("--enable-sil-ownership",
help="Enable the SIL ownership model",
action='store_true')
parser.add_argument(
# Explicitly unavailable options here.
"--build-jobs",
"--common-cmake-options",
"--only-execute",
"--skip-test-optimized",
action=arguments.action.unavailable)
parser.add_argument(
"--lit-args",
help="lit args to use when testing",
metavar="LITARGS",
default="-sv")
parser.add_argument(
"--coverage-db",
help="coverage database to use when prioritizing testing",
metavar="PATH")
args = migration.parse_args(parser, sys.argv[1:])
if args.build_script_impl_args:
# If we received any impl args, check if `build-script-impl` would
# accept them or not before any further processing.
try:
migration.check_impl_args(build_script_impl,
args.build_script_impl_args)
except ValueError as e:
parser.print_usage(sys.stderr)
print(e, file=sys.stderr)
sys.exit(2) # 2 is the same as `argparse` error exit code.
if '--check-args-only' in args.build_script_impl_args:
return 0
shell.dry_run = args.dry_run
# Prepare and validate toolchain
toolchain = host_toolchain(xcrun_toolchain=args.darwin_xcrun_toolchain)
if args.host_cc is not None:
toolchain.cc = args.host_cc
if args.host_cxx is not None:
toolchain.cxx = args.host_cxx
if args.cmake is not None:
toolchain.cmake = args.cmake
# Preprocess the arguments to apply defaults.
BuildScriptInvocation.apply_default_arguments(toolchain, args)
# Validate the arguments.
BuildScriptInvocation.validate_arguments(toolchain, args)
# Create the build script invocation.
invocation = BuildScriptInvocation(toolchain, args)
# Sanitize the runtime environment.
invocation.initialize_runtime_environment()
# Show SDKs, if requested.
if args.show_sdks:
swift_build_support.debug.print_xcodebuild_versions()
# Clean build directory if requested.
if args.clean:
shell.rmtree(invocation.workspace.build_root)
# Create build directory.
shell.makedirs(invocation.workspace.build_root)
# Build ninja if required, which will update the toolchain.
if args.build_ninja:
invocation.build_ninja()
# Execute the underlying build script implementation.
invocation.execute()
if args.symbols_package:
print('--- Creating symbols package ---')
print('-- Package file: {} --'.format(args.symbols_package))
if platform.system() == 'Darwin':
prefix = swift_build_support.targets.darwin_toolchain_prefix(
args.install_prefix)
else:
prefix = args.install_prefix
# As a security measure, `tar` normally strips leading '/' from paths
# it is archiving. To stay safe, we change working directories, then
# run `tar` without the leading '/' (we remove it ourselves to keep
# `tar` from emitting a warning).
with shell.pushd(args.install_symroot):
swift_build_support.tar.tar(source=prefix.lstrip('/'),
destination=args.symbols_package)
return 0
def main():
if not SWIFT_SOURCE_ROOT:
diagnostics.fatal(
"could not infer source root directory " +
"(forgot to set $SWIFT_SOURCE_ROOT environment variable?)")
if not os.path.isdir(SWIFT_SOURCE_ROOT):
diagnostics.fatal(
"source root directory \'" + SWIFT_SOURCE_ROOT +
"\' does not exist " +
"(forgot to set $SWIFT_SOURCE_ROOT environment variable?)")
# Determine if we are invoked in the preset mode and dispatch accordingly.
if any([(opt.startswith("--preset") or opt == "--show-presets")
for opt in sys.argv[1:]]):
return main_preset()
else:
return main_normal()
if __name__ == "__main__":
sys.exit(main())