diff --git a/utils-experimental/build-script b/utils-experimental/build-script new file mode 100755 index 0000000000000..16c744d015511 --- /dev/null +++ b/utils-experimental/build-script @@ -0,0 +1,27 @@ +#!/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 http://swift.org/LICENSE.txt for license information +# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +# +# ---------------------------------------------------------------------------- + +import os +import sys + + +PYTHONPATH = os.path.join(os.path.dirname(__file__), 'build-script-impl') +if "PYTHONPATH" in os.environ: + PYTHONPATH += os.pathsep + os.environ["PYTHONPATH"] + +env = dict(os.environ) +env.update(PYTHONPATH=PYTHONPATH) + +os.execve(sys.executable, + [sys.executable, '-m', 'build_script'] + sys.argv, + env) diff --git a/utils-experimental/build-script-impl/.gitignore b/utils-experimental/build-script-impl/.gitignore new file mode 100644 index 0000000000000..fc2af77fe3caf --- /dev/null +++ b/utils-experimental/build-script-impl/.gitignore @@ -0,0 +1,5 @@ +#==============================================================================# +# Ignore coverage report files +#==============================================================================# +/.coverage +/htmlcov diff --git a/utils-experimental/build-script-impl/README.md b/utils-experimental/build-script-impl/README.md new file mode 100644 index 0000000000000..e1282ffa8242c --- /dev/null +++ b/utils-experimental/build-script-impl/README.md @@ -0,0 +1,29 @@ +# build_script_impl + +`build_script_impl` holds implementation of Swift build script. + +## Tests + +You may run unit tests for `build-script` from the command line: + +```sh +apple/swift $ python -m unittest discover utils/build-script-impl +``` + +## Developer notes + +- `build-script` : the launcher +- `build-script-impl/` + - `build_script/` : package + - `__main__.py` : main entry point + - `main_normal.py` : the main work flow + - `workspace.py` : `workspace` represents whole source tree. + - `host/` : `host` represents running machine itself. Subclassed depends on + the machine. + - `cmake.py` : represents cmake command. + - `products/` : represents each product to be built. + - `shell.py` : every shell command invocation must be done via this module. + - `utils/` : some utility functions + - `main_preset.py` : sub entry point when `__main__.py` is called with + `--preset` + - `tests/` : TESTS diff --git a/utils-experimental/build-script-impl/build_script/__init__.py b/utils-experimental/build-script-impl/build_script/__init__.py new file mode 100644 index 0000000000000..cb231ffd117f8 --- /dev/null +++ b/utils-experimental/build-script-impl/build_script/__init__.py @@ -0,0 +1,15 @@ +# build_script/__init__.py -------------------------------------*- 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 http://swift.org/LICENSE.txt for license information +# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +# +# ---------------------------------------------------------------------------- +''' +build-script implementation detail +''' +# ---------------------------------------------------------------------------- diff --git a/utils-experimental/build-script-impl/build_script/__main__.py b/utils-experimental/build-script-impl/build_script/__main__.py new file mode 100644 index 0000000000000..3c83345d02064 --- /dev/null +++ b/utils-experimental/build-script-impl/build_script/__main__.py @@ -0,0 +1,66 @@ +# build_script/__main__.py --------------------------------------*- 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 http://swift.org/LICENSE.txt for license information +# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +# +# ---------------------------------------------------------------------------- +""" +The entry point for Swift build script +""" +# ---------------------------------------------------------------------------- + +from __future__ import absolute_import + +import sys +import os.path + +from . import env +from .utils import printf_with_argv0 +from .exceptions import BuildError, CalledProcessError + + +def main(): + + if not env.SWIFT_SOURCE_ROOT: + printf_with_argv0( + "Could not infer source root directory. " + "Forgot to set $SWIFT_SOURCE_ROOT environment variable?") + return 1 + + if not os.path.isdir(env.SWIFT_SOURCE_ROOT): + printf_with_argv0( + "Source root directory '{0}' does not exists. " + "Forgot to set $SWIFT_SOURCE_ROOT environment variable?", + env.SWIFT_SOURCE_ROOT) + return 1 + + # 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:]]): + from .main_preset import main as impl_main + else: + from .main_driver import main as impl_main + + try: + return impl_main(sys.argv) + except (OSError, CalledProcessError, BuildError) as e: + printf_with_argv0("Error: {0}", e) + return 1 + + return 0 + + +if __name__ == "__main__": + # Since this script is invoked from ./utils/build-script like: + # + # python -m build_script ./utils/build-script --options ... + # + # argv[0] is "path/to/build_script/__main__.py". + # Shift sys.argv so that we can process it normally. + sys.argv = sys.argv[1:] + sys.exit(main()) diff --git a/utils-experimental/build-script-impl/build_script/_shell.py b/utils-experimental/build-script-impl/build_script/_shell.py new file mode 100644 index 0000000000000..212ad063a73c4 --- /dev/null +++ b/utils-experimental/build-script-impl/build_script/_shell.py @@ -0,0 +1,194 @@ +# build_script/shell.py -----------------------------------------*- 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 http://swift.org/LICENSE.txt for license information +# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +# +# ---------------------------------------------------------------------------- +""" +Implementaion detail of build_script.shell module. +""" +# ---------------------------------------------------------------------------- +from __future__ import print_function + +import os +import sys +import shutil +import pipes +import subprocess +from contextlib import contextmanager + + +def _print_line(line): + print(line) + # To prevent mixed output with executed command output. + sys.stdout.flush() + + +def _print_command(args, env=None, prompt="+ "): + output = [] + + def q(val): + return pipes.quote(str(val)) + + if env is not None: + output += ['env'] + [q("%s=%s" % (k, v)) for k, v in env] + output += [q(arg) for arg in args] + _print_line(prompt + ' '.join(output)) + + +@contextmanager +def pushd(path, echo=True, dry_run=False): + old_dir = os.getcwd() + if echo or dry_run: + _print_command(["pushd", path]) + if not dry_run: + os.chdir(path) + yield + if echo or dry_run: + _print_command(["popd"]) + if not dry_run: + os.chdir(old_dir) + + +def chdir(path, echo=True, dry_run=False): + if echo or dry_run: + _print_command(["cd", path]) + if dry_run: + return + + os.chdir(path) + + +def query(args, env=None, stderr=subprocess.PIPE, echo=False, strip=True): + ''' + Run command and returns its output. + ''' + if echo: + _print_command(args, env) + + if env is not None: + env = dict(os.environ.items() + env) + out = subprocess.check_output(args, stderr=stderr, env=env) + # Coerce to `str`. Not `bytes`(py3), not `unicode`(py2) + out = str(out.decode()) + if strip: + out = out.strip() + return out + + +def execv(args, echo=True, dry_run=False): + ''' + Execute given command, replacing current process. Never return. + ''' + if echo or dry_run: + _print_command(args) + if dry_run: + # FIXME: I'm not sure what to to for `execv` dry-run. + sys.exit(0) + + os.execv(args[0], args) + + +def invoke(args, env=None, echo=True, dry_run=False): + ''' + Invoke given command + ''' + if echo or dry_run: + _print_command(args, env) + if dry_run: + return + + if env is not None: + env = dict(os.environ.items() + env) + subprocess.check_call(args, env=env) + + +def runscript(script, env=None, ignore_errors=False, echo=True, dry_run=False): + prompt = '++ ' + if dry_run: + import shlex + for command in script.splitlines(): + _print_command(shlex.split(command), prompt=prompt) + return + + cmd = ['sh', ] + if not ignore_errors: + cmd += ['-e', ] + if echo: + cmd += ['-x', ] + + env = dict(os.environ) + env['PS4'] = prompt + if env is not None: + env.update(env) + + pipe = subprocess.Popen(cmd, env=env, stdin=subprocess.PIPE) + pipe.communicate(script.encode()) + if pipe.returncode != 0: + raise subprocess.CalledProcessError(pipe.returncode, script) + + +def copy(src, dst, echo=True, dry_run=False): + if echo or dry_run: + _print_command(['cp', src, dst]) + if dry_run: + return + + shutil.copy(src, dst) + + +def remove(path, echo=True, dry_run=False): + if echo or dry_run: + _print_command(['rm', path]) + if dry_run: + return + + os.remove(path) + + +def makedirs(directory, echo=True, dry_run=False): + if echo or dry_run: + _print_command(['mkdir', '-p', directory]) + if dry_run: + return + + os.makedirs(directory) + + +def rmtree(path, echo=True, dry_run=False): + if echo or dry_run: + _print_command(['rm', '-rf', path]) + if dry_run: + return + + shutil.rmtree(path) + + +def copytree(src, dst, symlinks=False, echo=True, dry_run=False): + if echo or dry_run: + _print_command(['cp', '-r', src, dst]) + if dry_run: + return + + shutil.copytree(src, dst, symlinks=symlinks) + + +def symlink(source, link_name, relative=False, echo=True, dry_run=False): + ''' + Create symbolic link + ''' + if relative: + target_dir = os.path.dirname(link_name) + source = os.path.relpath(source, target_dir) + + if echo or dry_run: + _print_command(['ln', '-s', source, link_name]) + if dry_run: + return + + os.symlink(source, link_name) diff --git a/utils-experimental/build-script-impl/build_script/cmake.py b/utils-experimental/build-script-impl/build_script/cmake.py new file mode 100644 index 0000000000000..c90b2388708e5 --- /dev/null +++ b/utils-experimental/build-script-impl/build_script/cmake.py @@ -0,0 +1,374 @@ +# build_script/cmake.py -----------------------------------------*- 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 http://swift.org/LICENSE.txt for license information +# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +# +# ---------------------------------------------------------------------------- +""" +Represent CMake command +""" +# ---------------------------------------------------------------------------- + +from __future__ import absolute_import + +import re +import os.path +import itertools +import subprocess +from numbers import Number + +from .utils import CachedProperty +from . import shell +from . import targets +from .host import host + + +class CMakeOptions(object): + def __init__(self, *args): + self._options = [] + for var, value in args: + self.define(var, value) + + def define(self, var, value): + if var.endswith(':BOOL'): + value = self.true_false(value) + elif value is None: + value = "" + elif (not isinstance(value, str) and + not isinstance(value, Number)): + raise ValueError('value must be string or number') + self._options.append('-D%s=%s' % (var, value)) + + def unset(self, var): + var = var.rsplit(':', 1)[0] # strip :BOOL etc + self._options.append('-U' + var) + + def true_false(self, value): + if value in [True, 1, 'true', 'True', 'TRUE', '1']: + return 'TRUE' + elif value in [False, 0, 'false', 'False', 'FALSE', '0']: + return 'FALSE' + else: + raise ValueError('true_false: unknown value: ' + str(value)) + + def __len__(self): + return self._options.__len__() + + def __iter__(self): + return self._options.__iter__() + + def __add__(self, other): + ret = CMakeOptions() + ret._options += self._options + ret._options += list(other) + return ret + + def __iadd__(self, other): + self._options += list(other) + return self + + +class CMake(object): + def __init__(self, path, + host_cc, host_cxx, + host_distcc, host_distcc_pump, + ninja_build, + args): + self.path = path + self.host_cc = host_cc + self.host_cxx = host_cxx + self.distcc = host_distcc + self.distcc_pump = host_distcc_pump + self.ninja_build = ninja_build + self.args = args + + self.generator = args.cmake_generator + + # static utility functions + + def is_release_build_type(self, build_type): + return build_type in ['Release', 'RelWithDebInfo'] + + def common_cross_c_flags(self, deployment_target): + sys, arch = targets.split(deployment_target) + if sys == 'iphonesimulator': + return ('-arch', arch, + '-mios-simulator-version-min=' + + self.args.darwin_deployment_version_ios) + if sys == 'iphoneos': + return ('-arch', arch, + '-miphoneos-version-min=' + + self.args.darwin_deployment_version_ios) + if sys == 'appletvsimulator': + return ('-arch', arch, + '-mtvos-simulator-version-min=' + + self.args.darwin_deployment_version_tvos) + if sys == 'appletvos': + return ('-arch', arch, + '-mtvos-version-min=' + + self.args.darwin_deployment_version_tvos) + if sys == 'watchsimulator': + return ('-arch', arch, + '-mwatchos-simulator-version-min=' + + self.args.darwin_deployment_version_watchos) + if sys == 'watchos': + return ('-arch', arch, + '-mwatchos-version-min=' + + self.args.darwin_deployment_version_watchos) + if sys == 'android': + return ('-arch', arch) + return [] + + def _parse_clang_compiler_version(self, value): + version_re = re.compile(r'([0-9]*)\.([0-9]*)\.([0-9]*)') + m = version_re.match(value) + if m is None: + return None + return (m.group(1), m.group(2), m.group(3),) + + # Property accessors + + @CachedProperty + def version(self): + import subprocess + try: + output = shell.query([self.path, '--version']) + version_re = re.compile(r'cmake_version ([0-9\.]+)') + m = version_re.match(output) + if m is not None: + return m[1] + else: + return None + except subprocess.CalledProcessError: + return None + + def needs_to_specify_standard_computed_defaults(self): + if self.version == '3.4.0': + return True + else: + return False + + @CachedProperty + def computed_jobs(self): + + jobs = self.args.build_jobs + if self.args.distcc: + # When we use distcc, query job count with distcc command + jobs = int(shell.query([self.distcc, '-j'])) + return jobs + + def num_parallel_lto_link_jobs(self, gb_per_job): + sys_memory_in_bytes = host.system_memory_in_bytes() + link_jobs = int(sys_memory_in_bytes / 1000000000 / gb_per_job) + link_jobs = min(self.computed_jobs, link_jobs) + return link_jobs + + def common_options(self): + '''\ + Return common CMake options. + ''' + args = self.args + + options = CMakeOptions() + define = options.define + + # If we use just built ninja, set the path of the exectable. + if self.generator == 'Ninja' and self.ninja_build is not None: + ninja_path = self.ninja_build.ninja_bin_path + define('CMAKE_MAKE_PROGRAM', ninja_path) + + sanitizers = [] + if args.enable_asan: + sanitizers.append('Address') + if args.enable_ubsan: + sanitizers.append('Undefined') + if len(sanitizers): + sanitizers_str = ';'.join(sanitizers) + define('LLVM_USE_SANITIZER', sanitizers_str) + + if args.export_compile_commands: + define('CMAKE_EXPORT_COMPILE_COMMANDS:BOOL', True) + + if args.distcc: + define('CMAKE_C_COMPILER:PATH', self.distcc) + define('CMAKE_CXX_COMPILER:PATH', self.distcc) + define('CMAKE_C_COMPILER_ARG1', self.host_cc) + define('CMAKE_CXX_COMPILER_ARG1', self.host_cxx) + else: + define('CMAKE_C_COMPILER:PATH', self.host_cc) + define('CMAKE_CXX_COMPILER:PATH', self.host_cxx) + + if self.generator == 'Xcode': + define('CMAKE_CONFIGURATION_TYPES', + 'Debug;Release;MinSizeRel;RelWithDebInfo') + + if args.clang_compiler_version is not None: + (major, minor, patch) = self._parse_clang_compiler_version( + args.clang_compiler_version) + define('LLVM_VERSION_MAJOR:STRING', major) + define('LLVM_VERSION_MINOR:STRING', minor) + define('LLVM_VERSION_PATCH:STRING', patch) + + if len(args.extra_cmake_options): + options += args.extra_cmake_options + + return options + + def is_configured(self, build_dir): + cmake_cache_path = os.path.join(build_dir, 'CMakeCache.txt') + if not os.path.exists(cmake_cache_path): + return False + + # Compute the generator output file to check for, to determine if we + # must reconfigure. We only handle Ninja for now. + # + # This is important for ensuring that if a CMake configuration fails in + # CI, that we will still be willing to rerun the configuration process. + generator_output_path = None + if self.generator == 'Ninja': + generator_output_path = os.path.join(build_dir, + 'build.ninja') + if generator_output_path is not None: + if not os.path.exists(generator_output_path): + return False + return True + + def configure(self, source_dir, build_dir, options, use_module_cache=True): + '''\ + Configure cmake project with given paramters. + ''' + + command = [self.path, '-G', self.generator] + command += self.common_options() + command += options + command += self.args.user_config_args + command += [source_dir, ] + + # Create build directory if not exists + if not os.path.exists(build_dir): + os.makedirs(build_dir) + + # Clean the product-local module cache. + if use_module_cache: + module_cache_dir = os.path.join(build_dir, 'module_cache') + if os.path.exists(module_cache_dir): + shell.rmtree(module_cache_dir) + shell.makedirs(module_cache_dir) + + # Do configure + with shell.pushd(build_dir): + shell.invoke(command) + + def _build_args(self): + result = list(self.args.build_args) + + # Parallel jobs + jobs = self.computed_jobs + + # Generator depend build arguments. + if self.generator == 'Ninja': + result += ['-j%d' % jobs, ] + if self.args.verbose_build: + result += ['-v', ] + elif self.generator == 'Unix Makefiles': + result += ['-j%d' % jobs, ] + if self.args.verbose_build: + result += ['VERBOSE=1', ] + elif self.generator == 'Xcode': + result += ['-parallelizeTargets', '-jobs', str(jobs), ] + + return result + + def build(self, build_dir, build_targets, config_opts=None): + '''\ + Invoke `cmake --build` + ''' + build_cmd = [self.path, ] + + if self.args.distcc: + # use distcc + build_cmd = [self.distcc_pump, ] + build_cmd + + build_cmd += ['--build', build_dir] + if self.generator == 'XCode': + # CMake automatically adds --target ALL_BUILD if we don't pass + # this. + build_cmd += ['--target', 'ZERO_CHECK'] + if config_opts is not None: + build_cmd += config_opts + build_cmd += ['--', ] # dash-dash + build_cmd += self._build_args() + + if self.generator == 'Xcode': + # Xcode can't restart itself if it turns out we need to + # reconfigure. Do an advance build to handle that. + shell.invoke(build_cmd) + + # Xcode generator uses "ALL_BUILD" instead of "all". + # Also, xcodebuild uses `-target {name}` instead of bare names. + build_targets = ( + 'ALL_BUILD' if t == 'all' else t for t in build_targets) + build_targets = itertools.chain.from_iterable( + ['-target', t] for t in build_targets) + + build_cmd += build_targets + + # Do build + shell.invoke(build_cmd) + + def test(self, build_dir, test_targets, config_opts=None): + build_cmd = [self.path, '--build', build_dir] + if self.generator == 'XCode': + build_cmd += ['--target', 'ZERO_CHECK'] + + if config_opts is not None: + build_cmd += config_opts + + build_cmd += ['--', ] # dash-dash + build_cmd += self._build_args() + + need_manual_invoke = False + if self.generator == "Ninja": + # NOTE: In dry_run mode, querying '--version' fails if + # it's not already configured. We treat it as no manual + # `cmake --build` invocation + if not shell.dry_run: + query_cmd = build_cmd + ["--version"] + result = shell.query(query_cmd, + stderr=subprocess.STDOUT, echo_=False) + result = result.lower() + if "llbuild" not in result: + need_manual_invoke = True + + for target in test_targets: + if need_manual_invoke: + # Ninja buffers command output to avoid scrambling the output + # of parallel jobs, which is awesome... except that it + # interferes with the progress meter when testing. Instead of + # executing ninja directly, have it dump the commands it would + # run, strip Ninja's progress prefix, and tell the shell to + # execute that. + test_cmds = shell.query(build_cmd + ["-n", "-v", target]) + test_cmds = re.sub(r"^[^]]*] ", "", test_cmds, + flags=re.MULTILINE) + # FIXME: ignore_errors=True is just a workaround for current + # Swift source tree + shell.runscript(test_cmds, ignore_errors=True) + else: + test_cmd = list(build_cmd) + if self.generator == 'Xcode': + test_cmd += ["-target", target, ] + else: + test_cmd += [target, ] + shell.invoke(test_cmd) + + def install(self, build_dir, dest_dir, install_targets=("install", )): + args = [self.path, '--build', build_dir, '--'] + args += install_targets + shell.invoke(args, + env=[("DESTDIR", dest_dir), ]) diff --git a/utils-experimental/build-script-impl/build_script/defaults.py b/utils-experimental/build-script-impl/build_script/defaults.py new file mode 100644 index 0000000000000..44b36f767a5e9 --- /dev/null +++ b/utils-experimental/build-script-impl/build_script/defaults.py @@ -0,0 +1,57 @@ +# build_script/defaults.py --------------------------------------*- 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 http://swift.org/LICENSE.txt for license information +# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +# +# ---------------------------------------------------------------------------- +""" +Default option value definitions. +""" +# ---------------------------------------------------------------------------- + +__all__ = [ + # Command line configuarable + 'SWIFT_USER_VISIBLE_VERSION', + 'CLANG_USER_VISIBLE_VERSION', + 'SWIFT_ANALYZE_CODE_COVERAGE', + 'DARWIN_XCRUN_TOOLCHAIN', + 'DARWIN_DEPLOYMENT_VERSION_OSX', + 'DARWIN_DEPLOYMENT_VERSION_IOS', + 'DARWIN_DEPLOYMENT_VERSION_TVOS', + 'DARWIN_DEPLOYMENT_VERSION_WATCHOS', + 'UNIX_INSTALL_PREFIX', + 'DARWIN_INSTALL_PREFIX', + + # Constants + 'LLVM_TARGETS_TO_BUILD', +] + +# Options that can be "configured" by command line options + +BUILD_TYPE = "Debug" +CMAKE_GENERATOR = "Ninja" +COMPILER_VENDOR = "none" +DARWIN_XCRUN_TOOLCHAIN = 'default' +SWIFT_USER_VISIBLE_VERSION = '3.0' +CLANG_USER_VISIBLE_VERSION = '3.8.0' +SWIFT_ANALYZE_CODE_COVERAGE = 'false' +DARWIN_DEPLOYMENT_VERSION_OSX = '10.9' +DARWIN_DEPLOYMENT_VERSION_IOS = '7.0' +DARWIN_DEPLOYMENT_VERSION_TVOS = '9.0' +DARWIN_DEPLOYMENT_VERSION_WATCHOS = '2.0' + +UNIX_INSTALL_PREFIX = '/usr' +DARWIN_INSTALL_PREFIX = ('/Applications/Xcode.app/Contents/Developer/' + 'Toolchains/XcodeDefault.xctoolchain/usr') + +# Options that can only be "configured" by editing this file. +# +# These options are not exposed as command line options on purpose. If you +# need to change any of these, you should do so on trunk or in a branch. + +LLVM_TARGETS_TO_BUILD = "X86;ARM;AArch64;PowerPC" diff --git a/utils-experimental/build-script-impl/build_script/driver_arguments.py b/utils-experimental/build-script-impl/build_script/driver_arguments.py new file mode 100644 index 0000000000000..9330fc536d9ae --- /dev/null +++ b/utils-experimental/build-script-impl/build_script/driver_arguments.py @@ -0,0 +1,1183 @@ +# build_script/driver_arguments.py ------------------------------*- 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 http://swift.org/LICENSE.txt for license information +# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +# +# ---------------------------------------------------------------------------- +""" +The build script command line arguments definitions, including parser factory. +""" +# ---------------------------------------------------------------------------- + +from __future__ import absolute_import + +import os.path +import argparse +import multiprocessing + +from .host import host +from . import defaults +from .utils import ArgParserBuilder + +__all__ = [ + 'create_argparser', + 'Args', +] + + +class Args(object): + ''' Simple object to store parsed arguments. + ''' + + @classmethod + def freeze(cls, obj): + ''' + Make given Args object immutable. After this, no one can set or delete + any attributes on this object. + ''' + obj.__dict__['@frozen@'] = True + + def __init__(self, **kwargs): + for name in kwargs: + setattr(self, name, kwargs[name]) + + def __setattr__(self, attr, value): + if self.__dict__.get('@frozen@'): + raise AttributeError("Can't set attribute on frozen object") + self.__dict__[attr] = value + + def __delattr__(self, attr): + if self.__dict__.get('@frozen@'): + raise AttributeError("Can't delete attribute on frozen object") + del self.__dict__[attr] + + +def create_argparser(): + '''Return configured argument parser. + ''' + + builder = ArgParserBuilder( + usage="%(prog)s [-h | --help] [OPTIONS...]", + formatter_class=argparse.RawDescriptionHelpFormatter, + description=DESCRIPTION, + epilog=EPILOG) + # Note: DESCRIPTION and EPLOG are defined at the bottom of this file. + + # Prepare DSL functions + in_group = builder.in_group + option = builder.add_option + set_defaults = builder.set_defaults + mutually_exclusive_group = builder.mutually_exclusive_group + set_ = builder.set_action + disable = builder.disable_action + enable = builder.enable_action + append = builder.append_action + + def realpath(path): + path = os.path.expanduser(path) + path = os.path.abspath(path) + path = os.path.realpath(path) + return path + + # ------------------------------------------------------------------------ + + option(["-n", "--dry-run"], enable, nargs=0, default=False, + help="Print the commands that would be executed, but do not " + "execute them") + + option("--show-sdks", enable, default=False, nargs=0, + help="print installed Xcode and SDK versions") + + # ------------------------------------------------------------------------ + in_group("Workspace settings") + + option("--build-dir", set_('build_root', type=realpath), + metavar="PATH", + help="out-of-tree build directory; default is in-tree.") + + option("--workspace", set_('source_root', type=realpath), + metavar="PATH", + help="source directory containing llvm, clang, swift, and other " + "optional products") + + option("--build-subdir", set_, + metavar="PATH", + help="name of the directory under $SWIFT_BUILD_ROOT where the " + "build products will be placed") + + option("--darwin-xcrun-toolchain", set_, default="default", + metavar="NAME", + help="the name of the toolchain to use on Darwin") + + option("--cmake", set_, + metavar="PATH", + help="the path to a CMake executable that will be " + "used to build Swift") + + option("--build-args", append(separator=" "), + help="arguments to the build tool") + + option(["-j", "--jobs", "--build-jobs"], set_("build_jobs", type=int), + default=multiprocessing.cpu_count(), + metavar="NUM", + help="the number of parallel build jobs to use") + + option("--native-llvm-tools-path", set_, + metavar="PATH", + help="directory that contains LLVM tools that are executable on " + "the build machine") + + option("--native-clang-tools-path", set_, + metavar="PATH", + help="directory that contains Clang tools that are executable on " + "the build machine") + + option("--native-swift-tools-path", set_, + metavar="PATH", + help="directory that contains Swift tools that are executable on " + "the build machine") + + option('--host-cc', set_, + metavar="PATH", + help="the path to CC, the 'clang' compiler for the host platform.") + + option('--host-cxx', set_, + metavar="PATH", + help="the path to CXX, the 'clang++' compiler for the host " + "platform.") + + option("--distcc", enable, + help="use distcc in pump mode") + + # ----------------------------------------------------------------------- + in_group("Select the CMake generator") + + with mutually_exclusive_group(): + set_defaults(cmake_generator=defaults.CMAKE_GENERATOR) + + option(["-x", "--xcode"], + set_("cmake_generator", const="Xcode"), + help="use CMake's Xcode generator (default is Ninja)") + + option(["-m", "--make"], + set_("cmake_generator", const="Unix Makefiles"), + help="use CMake's Makefile generator (default is Ninja)") + + option(["-e", "--eclipse"], + set_("cmake_generator", const="Eclipse CDT4 - Ninja"), + help="use CMake's Eclipse generator (default is Ninja)") + + option("--cmake-generator", set_, + help="kind of build system to generate; see output of 'cmake " + "--help' for choices") + + # ------------------------------------------------------------------------ + in_group("Extra actions to perform before or in addition to building") + + option(["-c", "--clean"], enable, default=False, nargs=0, + help="do a clean build") + + option("--export-compile-commands", enable, default=False, + help="generate compilation databases in addition to building") + + option("--reconfigure", enable, + help="force a CMake configuration run even if CMakeCache.txt " + "already exists") + + option("--verbose-build", enable, + help="print the commands executed during the build of each " + "products") + + # ------------------------------------------------------------------------ + in_group("Host and cross-compilation targets") + + option("--host-target", set_, default=host.deployment_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.") + + option("--stdlib-deployment-targets", set_, nargs="*", + help="list of targets to compile or cross-compile the Swift " + "standard library for.") + + all_skip_ios = [ + 'skip_build_ios', + 'skip_build_ios_simulator', + 'skip_build_ios_device', + 'skip_test_ios_simulator', + 'skip_test_ios_host'] + + all_skip_tvos = [ + 'skip_build_tvos', + 'skip_build_tvos_simulator', + 'skip_build_tvos_device', + 'skip_test_tvos_simulator', + 'skip_test_tvos_host'] + + all_skip_watchos = [ + 'skip_build_watchos', + 'skip_build_watchos_simulator', + 'skip_build_watchos_device', + 'skip_test_watchos_simulator', + 'skip_test_watchos_host'] + + set_defaults(all_skip_ios, True) + set_defaults(all_skip_tvos, True) + set_defaults(all_skip_watchos, True) + + with mutually_exclusive_group(): + option("--ios", disable(all_skip_ios), + help="also build for iOS, but disallow tests that require an " + "iOS device") + option(["--skip-ios", "--skip-build-ios"], enable(all_skip_ios), + help="set to skip everything iOS-related") + + option("--skip-build-ios-device", enable, + help="set to skip building Swift stdlibs for iOS devices (i.e. " + "build simulators only)") + option("--skip-build-ios-simulator", enable, + help="set to skip building Swift stdlibs for iOS simulators (i.e. " + "build devices only)") + + with mutually_exclusive_group(): + option("--tvos", disable(all_skip_tvos), + help="also build for tvOS, but disallow tests that require a " + "tvos device") + option(["--skip-tvos", "--skip-build-tvos"], enable(all_skip_tvos), + help="set to skip everything tvOS-related") + + option("--skip-build-tvos-device", enable, + help="set to skip building Swift stdlibs for tvOS devices (i.e. " + "build simulators only)") + option("--skip-build-tvos-simulator", enable, + help="set to skip building Swift stdlibs for tvOS simulators (i.e. " + "build devices only)") + + with mutually_exclusive_group(): + option("--watchos", disable(all_skip_watchos), + help="also build for watchOS, but disallow tests that require " + "an watchOS device") + option(["--skip-watchos", "--skip-build-watchos"], + disable(all_skip_watchos), + help="set to skip everything watchOS-related") + + option("--skip-build-watchos-device", enable, + help="set to skip building Swift stdlibs for Apple watchOS devices " + "(i.e. build simulators only)") + option("--skip-build-watchos-simulator", enable, + help="set to skip building Swift stdlibs for Apple watchOS " + "simulators (i.e. build devices only)") + + with mutually_exclusive_group(): + set_defaults(skip_build_android=True) + option("--android", disable("skip_build_android"), + help="also build for Android") + option("--skip-build-android", enable, + help="set to skip building Swift stdlibs for Android") + + option("--cross-compile-tools-deployment-targets", append(separator=" "), + metavar="TARGET", + help="space-separated list of targets to cross-compile host Swift " + "tools for") + + option("--darwin-deployment-version-osx", set_, + default=defaults.DARWIN_DEPLOYMENT_VERSION_OSX, + metavar="VERSION", + help="minimum deployment target version for OS X") + + option("--darwin-deployment-version-ios", set_, + default=defaults.DARWIN_DEPLOYMENT_VERSION_IOS, + metavar="VERSION", + help="minimum deployment target version for iOS") + + option("--darwin-deployment-version-tvos", set_, + default=defaults.DARWIN_DEPLOYMENT_VERSION_TVOS, + metavar="VERSION", + help="minimum deployment target version for tvOS") + + option("--darwin-deployment-version-watchos", set_, + default=defaults.DARWIN_DEPLOYMENT_VERSION_WATCHOS, + metavar="VERSION", + help="minimum deployment target version for watchOS") + + # ----------------------------------------------------------------------- + in_group("Options to select projects") + all_required_product_skip_builds = [ + "skip_build_cmark", + "skip_build_llvm", + "skip_build_swift"] + + all_optional_product_skip_builds = [ + "skip_build_lldb", + "skip_build_llbuild", + "skip_build_swiftpm", + "skip_build_xctest", + "skip_build_foundation", + "skip_build_libdispatch"] + + set_defaults(all_required_product_skip_builds, False) + set_defaults(all_optional_product_skip_builds, True) + + all_product_skip_builds = ( + all_required_product_skip_builds + + all_optional_product_skip_builds) + + option(["-S", "--skip-build"], enable(all_product_skip_builds), + help="generate build directory only without building") + + option("--skip-build-cmark", enable, + help="set to skip building CommonMark") + option("--skip-build-llvm", enable, + help="set to skip building LLVM/Clang") + option("--skip-build-swift", enable, + help="set to skip building Swift") + + with mutually_exclusive_group(): + option(["-l", "--lldb"], disable('skip_build_lldb'), + help="build LLDB") + option("--skip-build-lldb", enable, + help="set to skip building LLDB") + + with mutually_exclusive_group(): + option(["-b", "--llbuild"], disable('skip_build_llbuild'), + help="build llbuild") + option("--skip-build-llbuild", enable, + help="set to skip building llbuild") + + with mutually_exclusive_group(): + option(["-p", "--swiftpm"], disable('skip_build_swiftpm'), + help="build swiftpm") + option("--skip-build-swiftpm", enable, + help="set to skip building swiftpm") + + # XCTest has a dependency on Foundation. + # On OS X, Foundation is built automatically using xcodebuild. + # On Linux, we must ensure that it is built manually. + skip_build_xctest_dst = ['skip_build_xctest'] + if not host.is_darwin(): + skip_build_xctest_dst.append('skip_build_foundation') + + with mutually_exclusive_group(): + option("--xctest", disable(skip_build_xctest_dst), + help="build xctest") + option("--skip-build-xctest", enable, + help="set to skip building xctest") + + with mutually_exclusive_group(): + option("--foundation", disable("skip_build_foundation"), + help="build foundation") + option("--skip-build-foundation", enable, + help="set to skip building foundation") + + with mutually_exclusive_group(): + option("--libdispatch", disable("skip_build_libdispatch"), + help="build libdispatch") + option("--skip-build-libdispatch", enable, + help="set to skip building libdispatch") + + option("--build-ninja", enable(default=False), + help="build the Ninja tool") + + # ----------------------------------------------------------------------- + in_group("Build variant for projects") + + with mutually_exclusive_group(): + all_build_types = [ + 'cmark_build_type', 'llvm_build_type', + 'swift_build_type', 'swift_stdlib_build_type', + 'lldb_build_type', 'llbuild_build_type', + 'foundation_build_type'] + + set_defaults(all_build_types, defaults.BUILD_TYPE) + + option(["-d", "--debug"], + set_(all_build_types, const="Debug"), + help="build the Debug variant of everything (LLVM, Clang, " + "Swift host tools, target Swift standard libraries, LLDB " + "(if enabled) (default)") + + option(["-r", "--release-debuginfo"], + set_(all_build_types, const="RelWithDebInfo"), + help="build the RelWithDebInfo variant of everything (default " + "is Debug)") + + option(["-R", "--release"], + set_(all_build_types, const="Release"), + help="build the Release variant of everything (default is " + "Debug)") + + build_types = ['Debug', 'RelWithDebInfo', 'Release', 'MinSizeRel'] + + with mutually_exclusive_group(): + option("--debug-llvm", + set_("llvm_build_tyoe", const="Debug"), + help="build the Debug variant of LLVM") + option("--llvm-build-type", set_(choices=build_types), + help="the CMake build variant for LLVM and Clang") + + with mutually_exclusive_group(): + option("--debug-swift", + set_("swift_build_type", const="Debug"), + help="build the Debug variant of Swift host tools") + option("--swift-build-type", set_(choices=build_types), + help="the CMake build variant for Swift") + + with mutually_exclusive_group(): + option("--debug-swift-stdlib", + set_("swift_stdlib_build_type", const="Debug"), + help="build the Debug variant of the Swift standard library " + "and SDK overlay") + option("--swift-stdlib-build-type", set_(choices=build_types), + help="the CMake build variant for Swift standard library") + + with mutually_exclusive_group(): + option("--debug-cmark", set_("cmark_build_type", const="Debug"), + help="build the Debug variant of CommonMark") + option("--cmark-build-type", set_(choices=build_types), + help="the CMake build variant for CommonMark") + + with mutually_exclusive_group(): + option("--debug-lldb", + set_("lldb_build_type", const="Debug"), + disable("skip_build_lldb"), + help="build the Debug variant of LLDB") + option("--lldb-build-type", + set_("lldb_build_type", choices=build_types), + disable("skip_build_lldb"), + help="the CMake build variant for LLDB") + + with mutually_exclusive_group(): + option("--debug-foundation", + set_("foundation_build_type", const="Debug"), + disable("skip_build_foundation"), + help="build the Debug variant of Foundation") + option("--foundation-build-type", + set_(choices=build_types), + disable("skip_build_foundation"), + help="the build variant for Foundation") + + with mutually_exclusive_group(): + option("--debug-llbuild", + set_("llbuild_build_type", const="Debug"), + disable("skip-build-llbuild"), + help="build the Debug variant of Foundation") + option("--llbuild-build-type", + set_(choices=build_types), + disable("skip_build_llbuild"), + help="the build variant for Foundation") + + option("--debug-libdispatch", + # FIXME: Not used in build-script-impl + set_("libdispatch_build_type", const="Debug"), + disable("skip_build_libdispatch"), + help="build the Debug variant of libdispatch") + + # ----------------------------------------------------------------------- + in_group("Control assertions in each project") + + with mutually_exclusive_group(): + all_assertions = [ + "llvm_enable_assertions", + "swift_enable_assertions", + "swift_stdlib_enable_assertions", + "llbuild_enable_assertions", + + # FIXME: these values are not used in build-script-impl + "lldb_enable_assertions", + "cmark_enable_assertions", + ] + + set_defaults(all_assertions, True) + + option("--assertions", enable(all_assertions), + help="enable assertions in all projects") + option("--no-assertions", disable(all_assertions), + help="enable assertions in all projects") + + # FIXME: cmark_enable_assertions doesn't exists in build-script-impl + with mutually_exclusive_group(): + option("--cmark-assertions", enable("cmark_enable_assertions"), + help="enable assertions in CommonMark") + + # TODO: --{product}-enable-assertions are added just for old + # `build-script-impl` compatibility. Shoud remove them. + + with mutually_exclusive_group(): + option(["--llvm-assertions", "--llvm-enable-assertions"], + enable("llvm_enable_assertions"), + help="enable assertions in LLVM") + option("--no-llvm-assertions", + disable("llvm_enable_assertions"), + help="disable assertions in LLVM") + + # FIXME: Unused old build-script-impl option + option("--enable-llvm-assertions", enable, + help="set to enable llvm assertions") + + with mutually_exclusive_group(): + option(["--swift-assertions", "--swift-enable-assertions"], + enable("swift_enable_assertions"), + help="enable assertions in Swift") + option("--no-swift-assertions", + disable("swift_enable_assertions"), + help="disable assertions in Swift") + + with mutually_exclusive_group(): + option(["--swift-stdlib-assertions", + "--swift-stdlib-enable-assertions"], + enable("swift_stdlib_enable_assertions"), + help="enable assertions in the Swift standard library") + option("--no-swift-stdlib-assertions", + disable("swift_stdlib_enable_assertions"), + help="disable assertions in the Swift standard library") + + with mutually_exclusive_group(): + option(["--llbuild-assertions", "--llbuild-enable-assertions"], + enable("llbuild_enable_assertions"), + disable("skip_build_llbuild"), + help="enable assertions in LLBuild") + option("--no-llbuild-assertions", + disable("llbuild_enable_assertions"), + disable("skip_build_llbuild"), + help="disable assertions in LLBuild") + + with mutually_exclusive_group(): + option("--lldb-assertions", + # FIXME: lldb-enable-assertions is not used in lldb builder + enable("lldb_enable_assertions"), + disable("skip_build_lldb"), + help="enable assertions in LLDB") + option("--no-lldb-assertions", + disable("lldb_enable_assertions"), + disable("skip_build_lldb"), + help="disable assertions in LLDB") + + # ------------------------------------------------------------------------ + in_group("Sanitizers") + + option("--enable-asan", enable(), + help="enable Address Sanitizer") + + option("--enable-ubsan", enable(), + help="enable Undefined Behavior Sanitizer") + + # ------------------------------------------------------------------------ + in_group("Swift specific build options") + + option("--swift-sdks", set_, + help="build target binaries only for specified SDKs " + "(semicolon-separated list)") + + option("--swift-primary-variant-sdk", set_, + help="default SDK for target binaries") + + option("--swift-primary-variant-arch", set_, + help="default arch for target binaries") + + option("--swift-analyze-code-coverage", + set_(choices=["false", "not-merged", "merged"], default="false"), + # so CMake can see the inert mode as a false value + help="enable code coverage analysis in Swift") + + option("--swift-enable-ast-verifier", enable(default=True), + help="If enabled, and the assertions are enabled, the built Swift " + "compiler will run the AST verifier every time it is invoked") + + option("--build-runtime-with-host-compiler", enable(default=True), + help="Use the host compiler, not the self-built one to compile the " + "Swift runtime") + + option("--extra-swift-args", append(join=";"), + metavar="\"MODULE_REGEXP;FLAG\"", + 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."), + + option("--swift-enable-lto", enable, + help="enable LTO compilation of just Swift.") + + option("--swift-stdlib-enable-reflection-metadata", enable, + help="build the Swift stdlib and overlays with remote reflection " + "metadata") + + option("--swift-stdlib-enable-resilience", enable, + help="build the Swift stdlib and overlays with resilience enabled") + + option("--swift-stdlib-sil-serialize-all", enable(default=True), + help="build the Swift stdlib and overlays with all method bodies " + "serialized") + + option("--build-serialized-stdlib-unittest", enable, + help="set to 1 to build the StdlibUnittest module with " + "-sil-serialize-all") + + option("--build-sil-debugging-stdlib", enable, + help="set to 1 to build the Swift standard library with -gsil to " + "enable debugging and profiling on SIL leve'") + + option("--build-swift-tools", enable(default=True), + help="build Swift host tools") + + option("--build-swift-stdlib", enable(default=True), + help="build the Swift standard library") + + option("--build-swift-stdlib-unittest-extra", enable, # See tests sec. + help="build optional StdlibUnittest components") + + option("--build-swift-sdk-overlay", enable(default=True), + help="build the Swift SDK overlay") + + option("--build-swift-static-stdlib", enable, + help="build static versions of the Swift standard library and SDK " + "overlay") + + option("--build-swift-examples", enable(default=True), + help="build static versions of the Swift standard library and SDK " + "overlay") + + option("--embed-bitcode-section", enable, + help="embed an LLVM bitcode section in stdlib/overlay binaries " + "for supported platforms") + + option("--darwin-crash-reporter-client", enable, + help="whether to enable CrashReporter integration") + + option("--darwin-stdlib-install-name-dir", set_, + metavar="PATH", + help="the directory of the install_name for standard library " + "dylibs") + + option("--sil-verify-all", enable, + help="If enabled, run the SIL verifier after each transform when " + "building Swift files during this build process") + + option("--swift-runtime-enable-leak-checker", enable, + help="Enable leaks checking routines in the runtime") + + # ----------------------------------------------------------------------- + in_group("Other build options") + + option("--use-gold-linker", enable, + help="Enable using the gold linker") + + option("--source-tree-includes-tests", enable(default=True), + help="set to 0 to allow the build to proceed when 'test' directory " + "is missing (required for B&I builds)") + + option("--compiler-vendor", set_(choices=["none", "apple"]), + default=defaults.COMPILER_VENDOR, + help="compiler vendor name") + + option("--swift-compiler-version", set_, + metavar="VERSION", + help="string that indicates a compiler version for Swift") + + option("--clang-compiler-version", set_, + metavar="VERSION", + help="string that indicates a compiler version for Clang") + + option("--clang-user-visible-version", set_, + default=defaults.CLANG_USER_VISIBLE_VERSION, + metavar="VERSION", + help="user-visible version of the embedded Clang and LLVM " + "compilers") + + option("--swift-user-visible-version", set_, + default=defaults.SWIFT_USER_VISIBLE_VERSION, + metavar="VERSION", + help="user-visible version of the Swift language") + + option("--build-llvm", enable(default=True), + help="set to build LLVM and Clang (default: True)") + + option("--llvm-enable-lto", enable(default=False), + help="enable LTO compilation of LLVM/Clang.") + + option("--lldb-extra-cmake-args", append(separator=" "), + help="extra command line args to pass to lldb cmake") + + option("--lldb-extra-xcodebuild-args", set_, + help="extra command line args to pass to lldb xcodebuild") + + option("--lldb-test-cc", set_, + metavar="PATH", + help="CC to use for building LLDB testsuite test inferiors. " + "Defaults to just-built, in-tree clang. If set to " + "'host-toolchain', sets it to same as host-cc.") + + option("--lldb-test-with-curses", enable, + help="lldb-test-with-curses") + + option("--lldb-no-debugserver", enable, + help="delete debugserver after building it, and don't try to " + "codesign it") + + option("--lldb-use-system-debugserver", enable, + help="don't try to codesign debugserver, and use the system's " + "debugserver instead") + + option("--extra-cmake-options", append(separator=','), + 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.") + + option("--user-config-args", append(separator=" "), + help="User-supplied arguments to cmake when used to do " + "configuration") + + # ----------------------------------------------------------------------- + in_group("Build settings for Android") + + option("--android-ndk", set_, + metavar="PATH", + help="An absolute path to the NDK that will be used as a libc " + "implementation for Android builds") + + option("--android-ndk-version", set_, default="21", + help="A version of the NDK to use when building for Android. " + "Currently only 21 or above is supported") + + option("--android-ndk-toolchain-version", + set_(choices=["4.8", "4.9"]), default="4.8", + help="A version of the toolchain to use when building for Android. " + "Use 4.8 for 32-bit builds, 4.9 for 64-bit builds") + + option("--android-icu-uc", set_, + metavar="PATH", + help="Path to a directory containing libicuuc.so") + + option("--android-icu-uc-include", set_, + metavar="PATH", + help="Path to a directory containing headers for libicuuc") + + option("--android-icu-i18n", set_, + metavar="PATH", + help="Path to a directory containing libicui18n.so") + + option("--android-icu-i18n-include", set_, + metavar="PATH", + help="Path to a directory containing headers libicui18n") + + # ----------------------------------------------------------------------- + in_group("Run build") + + option("--skip-build-osx", enable, + help="skip building Swift stdlibs for OS X") + + option("--skip-build-linux", enable, + help="skip building Swift stdlibs for Linux") + + option("--skip-build-freebsd", enable, + help="skip building Swift stdlibs for FreeBSD") + + option("--skip-build-cygwin", enable, + help="skip building Swift stdlibs for Cygwin") + + option("--skip-build-benchmarks", enable, default=False, + help="skip building Swift Benchmark Suite") + + # ----------------------------------------------------------------------- + in_group("Run tests") + + all_product_skip_tests = [ + "skip_test_cmark", + "skip_test_swift", + "skip_test_lldb", + "skip_test_llbuild", + "skip_test_swiftpm", + "skip_test_xctest", + "skip_test_foundation", + "skip_test_libdispatch"] + + all_host_skip_tests = [ + "skip_test_linux", + "skip_test_freebsd", + "skip_test_cygwin", + "skip_test_osx"] + + all_normal_skip_tests = all_product_skip_tests + all_host_skip_tests + set_defaults(all_normal_skip_tests, True) + set_defaults(skip_test_validation=True) + set_defaults(skip_test_optimized=True) + + option(["-t", "--test"], disable(all_normal_skip_tests), + help="test Swift after building") + + option(["-T", "--validation-test"], + disable(all_normal_skip_tests + ['skip_test_validation']), + help="run the validation test suite (implies --test)") + + option("--skip-test-validation", enable, + help="set to skip validation test suite") + + option("--host-test", enable, + help="run executable tests on host devices (such as iOS or tvOS)") + + with mutually_exclusive_group(): + option(["-B", "--benchmark"], + disable("skip_test_benchmarks", default=True), + help="run the Swift Benchmark Suite after building") + option("--skip-test-benchmarks", enable, + help="set to skip running Swift Benchmark Suite") + + option("--stress-test-sourcekit", enable, default=False, + help="set to run the stress-SourceKit target") + + option("--skip-test-osx", enable, + help="skip testing Swift stdlibs for OS X") + option("--skip-test-linux", enable, + help="skip testing Swift stdlibs for Linux") + option("--skip-test-freebsd", enable, + help="skip testing Swift stdlibs for FreeBSD") + option("--skip-test-cygwin", enable, + help="skip testing Swift stdlibs for Cygwin") + + with mutually_exclusive_group(): + option(["-o", "--test-optimized"], + disable(all_normal_skip_tests + ['skip_test_optimized']), + help="run the test suite in optimized mode too (implies " + "--test)") + option("--skip-test-optimized", enable, + help="set to skip testing the test suite in optimized mode") + + # ------------------------------------------------------------------------ + in_group("Skip testing specified target") + + option("--skip-test-ios", + enable(["skip_test_ios_simulator", "skip_test_ios_host"]), + help="skip testing all iOS targets. Equivalent to specifying both " + "--skip-test-ios-simulator and --skip-test-ios-host") + option("--skip-test-ios-simulator", enable, + help="skip testing iOS simulator targets") + option("--skip-test-ios-host", enable, + help="skip testing iOS device targets on the host machine (the " + "phone itself)") + + option("--skip-test-tvos", + enable(["skip_test_tvos_simulator", "skip_test_tvos_host"]), + help="skip testing all tvOS targets. Equivalent to specifying both " + "--skip-test-tvos-simulator and --skip-test-tvos-host") + option("--skip-test-tvos-simulator", enable, + help="skip testing tvOS simulator targets") + option("--skip-test-tvos-host", enable, + help="skip testing tvOS device targets on the host machine (the TV " + "itself)") + + option("--skip-test-watchos", + enable(["skip_test_watchos_simulator", "skip_test_watchos_host"]), + help="skip testing all tvOS targets. Equivalent to specifying both " + "--skip-test-watchos-simulator and --skip-test-watchos-host") + option("--skip-test-watchos-simulator", enable, + help="skip testing watchOS simulator targets") + option("--skip-test-watchos-host", enable, + help="skip testing watchOS device targets on the host machine (the " + "watch itself)") + + # ------------------------------------------------------------------------ + in_group("Skip testing specified products") + + option("--skip-test-cmark", enable, + help="set to skip testing CommonMark") + + option("--skip-test-swift", enable, + help="set to skip testing Swift") + + option("--skip-test-lldb", enable, + help="set to skip testing lldb") + + option("--skip-test-llbuild", enable, + help="set to skip testing llbuild") + + option("--skip-test-swiftpm", enable, + help="set to skip testing swiftpm") + + option("--skip-test-xctest", enable, + help="set to skip testing xctest") + + option("--skip-test-foundation", enable, + help="set to skip testing foundation") + + option("--skip-test-libdispatch", enable, + help="set to skip testing libdispatch") + + # ------------------------------------------------------------------------ + in_group("Installation related options") + + option("--install-destdir", set_, type=realpath, + metavar="PATH", + help="the path to use as the filesystem root for the installation") + + if host.is_darwin(): + set_defaults(install_prefix=defaults.DARWIN_INSTALL_PREFIX) + else: + set_defaults(install_prefix=defaults.UNIX_INSTALL_PREFIX) + option("--install-prefix", set_, + metavar="PATH", + help="The installation prefix. This is where built Swift products " + "(like bin, lib, and include) will be installed.") + + option("--install-symroot", set_, + metavar="PATH", + help="the path to install debug symbols into") + + option("--swift-install-components", append(separator=";"), + metavar="COMPONENTS", + help="a semicolon-separated list of Swift components to install", + dest="swift_install_components") + + option("--llvm-install-components", append(separator=";"), + metavar="COMPONENTS", + help="a semicolon-separated list of LLVM components to install") + + option("--install-cmark", enable, + help="install cmark") + option("--install-swift", enable, + help="install Swift") + option("--install-lldb", enable, + help="install LLDB") + option("--install-llbuild", enable, + help="install llbuild") + option("--install-swiftpm", enable, + help="install swiftpm") + option("--install-xctest", enable, + help="install xctest") + option("--install-foundation", enable, + help="install foundation") + option("--install-libdispatch", enable, + help="install libdispatch") + + option("--toolchain-prefix", set_, + metavar="PATH", + help="the path to the .xctoolchain directory that houses the " + "install prefix path. (Default: auto determined from " + "install-prefix)") + + option("--darwin-install-extract-symbols", enable, + help="whether to extract symbols with dsymutil during " + "installations") + + # ------------------------------------------------------------------------ + in_group("Packaging options") + + option("--installable-package", set_(type=realpath), + metavar="PATH", + help="the path to the archive of the installation directory") + + option("--test-installable-package", enable, + help="whether to run post-packaging tests on the produced package") + + option("--symbols-package", set_(type=realpath), + metavar="PATH", + help="if provided, an archive of the symbols directory will be " + "generated at this path") + + option("--skip-merge-lipo-cross-compile-tools", enable, + help="set to skip running merge-lipo after installing " + "cross-compiled host Swift tools") + + option("--darwin-toolchain-bundle-identifier", set_, + help="CFBundleIdentifier for xctoolchain info plist") + + option("--darwin-toolchain-display-name", set_, + help="Display Name for xctoolcain info plist") + + option("--darwin-toolchain-name", set_, + help="Directory name for xctoolchain") + + option("--darwin-toolchain-version", set_, + metavar="VERSION", + help="Version for xctoolchain info plist and installer pkg") + + option("--darwin-toolchain-application-cert", set_, + help="Application Cert name to codesign xctoolchain") + + option("--darwin-toolchain-installer-cert", set_, + help="Installer Cert name to create installer pkg") + + option("--darwin-toolchain-installer-package", set_, + help="The path to installer pkg") + + option("--darwin-toolchain-alias", set_, + help="Swift alias for toolchain") + + return builder.build() + + +# ---------------------------------------------------------------------------- +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. + + +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) + +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 --lldb-debug 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.""" diff --git a/utils-experimental/build-script-impl/build_script/env.py b/utils-experimental/build-script-impl/build_script/env.py new file mode 100644 index 0000000000000..cdde89afaf5b5 --- /dev/null +++ b/utils-experimental/build-script-impl/build_script/env.py @@ -0,0 +1,63 @@ +# build_script/env.py -------------------------------------------*- 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 http://swift.org/LICENSE.txt for license information +# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +# +# ---------------------------------------------------------------------------- +""" +Environmental variables for the build script. +""" +# ---------------------------------------------------------------------------- + +from __future__ import absolute_import + +import os +import os.path +import sys + +__all__ = [ + 'HOME', + 'SWIFT_SOURCE_ROOT', + 'SWIFT_BUILD_ROOT', +] + + +def _get_default_source_root(): + '''Return auto detected SWIFT_SOURCE_ROOT directory path string. + + Assuming `build-script` is in a Swift checkout, traverse ancestor + directories and find SWIFT_SOURCE_ROOT that must contain `swift` directory + and `swift/CMakeLists.txt` avaiable. + + Return `None` if not found. + ''' + + def _is_source_root(directory): + swift_dir = os.path.join(directory, 'swift') + return (os.path.isdir(swift_dir) and + os.path.exists(os.path.join(swift_dir, 'CMakeLists.txt'))) + + directory = os.path.dirname(os.path.abspath(sys.argv[0])) + root = os.path.join(os.path.splitdrive(directory)[0], os.sep) + while directory != root: + if _is_source_root(directory): + return directory + directory = os.path.dirname(directory) + return None + +HOME = os.environ.get("HOME", "/") + +# Set SWIFT_SOURCE_ROOT in your environment to control where the sources +# are found. +SWIFT_SOURCE_ROOT = os.environ.get( + "SWIFT_SOURCE_ROOT", _get_default_source_root()) + +# Set SWIFT_BUILD_ROOT to a directory that will contain a subdirectory +# for each build configuration +SWIFT_BUILD_ROOT = os.environ.get( + "SWIFT_BUILD_ROOT", os.path.join(SWIFT_SOURCE_ROOT, "build")) diff --git a/utils-experimental/build-script-impl/build_script/exceptions.py b/utils-experimental/build-script-impl/build_script/exceptions.py new file mode 100644 index 0000000000000..37e6fe77e4f8b --- /dev/null +++ b/utils-experimental/build-script-impl/build_script/exceptions.py @@ -0,0 +1,28 @@ +# build_script/exceptions.py ------------------------------------*- 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 http://swift.org/LICENSE.txt for license information +# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +# +# ---------------------------------------------------------------------------- +""" +Exceptions raised in the build script +""" +# ---------------------------------------------------------------------------- + +from __future__ import absolute_import + +from subprocess import CalledProcessError + +__all__ = [ + 'CalledProcessError', + 'BuildError', +] + + +class BuildError(RuntimeError): + pass diff --git a/utils-experimental/build-script-impl/build_script/host/__init__.py b/utils-experimental/build-script-impl/build_script/host/__init__.py new file mode 100644 index 0000000000000..9372b0f385b86 --- /dev/null +++ b/utils-experimental/build-script-impl/build_script/host/__init__.py @@ -0,0 +1,42 @@ +# swift_build/host/__init__.py ----------------------------------*- 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 http://swift.org/LICENSE.txt for license information +# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +# +# ---------------------------------------------------------------------------- +""" +Provide singleton object that represents host machine +""" +# ---------------------------------------------------------------------------- + +from __future__ import absolute_import + +import platform + +from . import host_target + +__all__ = [ + 'host' +] + +_system = platform.system() +if _system == 'Darwin': + from .darwin import MacOSX as Host +elif _system == 'Linux': + from .unix import Linux as Host +elif _system == 'FreeBSD': + from .unix import FreeBSD as Host +elif _system.startswith('CYGWIN'): + from .unix import Cygwin as Host + +host = Host( + os_type=_system, + deployment_target=host_target.host_target()) +''' +Singleton Host +''' diff --git a/utils-experimental/build-script-impl/build_script/host/base.py b/utils-experimental/build-script-impl/build_script/host/base.py new file mode 100644 index 0000000000000..59b8958dd56f5 --- /dev/null +++ b/utils-experimental/build-script-impl/build_script/host/base.py @@ -0,0 +1,88 @@ +# build_script/host/base.py -------------------------------------*- 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 http://swift.org/LICENSE.txt for license information +# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +# +# ---------------------------------------------------------------------------- +""" +Host object base class +""" +# ---------------------------------------------------------------------------- + +from __future__ import absolute_import + +from ..utils import which + + +class Base(object): + """Represents native host system. + + Attributes: + install_prefix (str): The path at which built Swift products (like + bin, lib, and include) will be installed. The default value + depends on the host machine's operating system. + + deployment_target(str): LLVM, Clang, and Swift will be built for + this target. The default value is determined from machine's + operation system and CPU architecture. + """ + + def __init__(self, os_type, deployment_target): + self._os_type = os_type + self._deployment_target = deployment_target + + def deployment_target(self): + return self._deployment_target + + def os_type(self): + return self._os_type + + def is_darwin(self): + return self.os_type() == "Darwin" + + def is_freebsd(self): + return self.os_type() == "FreeBSD" + + def is_linux(self): + return self.os_type() == "Linux" + + def is_cygwin(self): + return self.os_type().startswith('CYGWIN') + + def find_clang_cc(self): + '''Return Clang host tool path if found. `None` otherwise. + ''' + raise NotImplementedError() + + def find_clang_cxx(self): + '''Return Clang host tool path if found. `None` otherwise. + ''' + raise NotImplementedError() + + def find_cmake(self): + '''Return CMake host tool path if found. `None` otherwise. + ''' + raise NotImplementedError() + + def find_ninja(self): + '''Return Ninja host tool path if found. `None` otherwise. + ''' + return which('ninja') or which('ninja-build') + + def find_distcc(self): + '''Return distcc host tool path if found. `None` otherwise. + ''' + return which('distcc') + + def find_distcc_pump(self): + '''Return distcc-pump host tool path if found. `None` otherwise. + ''' + return which('distcc-pump') or which('pump') + + def show_sdks(self): + raise NotImplementedError() diff --git a/utils-experimental/build-script-impl/build_script/host/darwin.py b/utils-experimental/build-script-impl/build_script/host/darwin.py new file mode 100644 index 0000000000000..3074d9aa7788d --- /dev/null +++ b/utils-experimental/build-script-impl/build_script/host/darwin.py @@ -0,0 +1,103 @@ +# build_script/host/darwin.py -----------------------------------*- 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 http://swift.org/LICENSE.txt for license information +# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +# +# ---------------------------------------------------------------------------- +""" +Darwin based host class +""" +# ---------------------------------------------------------------------------- + +from __future__ import absolute_import + +import os +import subprocess + +from .base import Base +from .. import shell +from ..utils import printf + +__all__ = [ + 'MacOSX', +] + + +class Darwin(Base): + def __init__(self, **kwargs): + super(Darwin, self).__init__(**kwargs) + self.xcrun_sdk = 'macosx' + self.xcrun_toolchain = None + + def is_darwin(self): + return True + + def system_memory_in_bytes(self): + ret = shell.query(['sysctl', 'hw.memsize']).rstrip().split(' ')[1] + return int(ret) + + def xcrun_find(self, tool): + """\ + Return the path for the given tool, according to `xcrun --find`. + If `xcrun --find` cannot find the tool, return None. + """ + command = ['xcrun', '--find', tool] + if self.xcrun_sdk is not None: + command += ['--sdk', self.xcrun_sdk] + if self.xcrun_toolchain is not None: + command += ['--toolchain', self.xcrun_toolchain] + + try: + # `xcrun --find` prints to stderr when it fails to find the + # given tool. We swallow that output with a pipe. + return shell.query(command, + stderr=subprocess.PIPE, + echo_=False).rstrip() + + except subprocess.CalledProcessError: + return None + + def sdk_path(self, sdk): + """\ + Return the SDK root path string for the given SDK name. + """ + command = ['xcrun', '--sdk', sdk, '--show-sdk-path'] + try: + # `xcrun --find` prints to stderr when it fails to find the + # given tool. We swallow that output with a pipe. + return shell.query(command, stderr=subprocess.PIPE).rstrip() + + except subprocess.CalledProcessError: + return None + + def find_clang_cc(self): + return self.xcrun_find('clang') + + def find_clang_cxx(self): + return self.xcrun_find('clang++') + + def find_cmake(self): + return self.xcrun_find('cmake') + + def toolchain_prefix(self, install_prefix): + return os.path.dirname(install_prefix) + + def show_sdks(self): + """ + Print the host machine's `xcodebuild` version, as well as version + information for all available SDKs. + """ + printf('{0}\n', shell.query(['xcodebuild', '-version'], + echo_=False)) + printf('--- SDK versions ---') + printf('{0}\n', shell.query(['xcodebuild', '-version', '-sdk'], + echo_=False)) + + +class MacOSX(Darwin): + pass diff --git a/utils-experimental/build-script-impl/build_script/host/host_target.py b/utils-experimental/build-script-impl/build_script/host/host_target.py new file mode 100644 index 0000000000000..3901bba509f82 --- /dev/null +++ b/utils-experimental/build-script-impl/build_script/host/host_target.py @@ -0,0 +1,56 @@ +# swift_build/host/host_target.py -------------------------------*- 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 http://swift.org/LICENSE.txt for license information +# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +# +# ---------------------------------------------------------------------------- +""" +Deployment target name for the host machine +""" +# ---------------------------------------------------------------------------- + +import platform + + +def host_target(): + """ + Return the deployment target name for the current host machine, if it is + one of the recognized targets. Otherwise, return None. + """ + system = platform.system() + machine = platform.machine() + + if system == 'Linux': + if machine == 'x86_64': + return 'linux-x86_64' + elif machine.startswith('armv7'): + # linux-armv7* is canonicalized to 'linux-armv7' + return 'linux-armv7' + elif machine.startswith('armv6'): + # linux-armv6* is canonicalized to 'linux-armv6' + return 'linux-armv6' + elif machine == 'aarch64': + return 'linux-aarch64' + elif machine == 'ppc64': + return 'linux-powerpc64' + elif machine == 'ppc64le': + return 'linux-powerpc64le' + + elif system == 'Darwin': + if machine == 'x86_64': + return 'macosx-x86_64' + + elif system == 'FreeBSD': + if machine == 'amd64': + return 'freebsd-x86_64' + + elif system == 'CYGWIN_NT-10.0': + if machine == 'x86_64': + return 'cygwin-x86_64' + + return None diff --git a/utils-experimental/build-script-impl/build_script/host/unix.py b/utils-experimental/build-script-impl/build_script/host/unix.py new file mode 100644 index 0000000000000..85b64a424f39d --- /dev/null +++ b/utils-experimental/build-script-impl/build_script/host/unix.py @@ -0,0 +1,110 @@ +# build_script/host/unix.py -------------------------------------*- 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 http://swift.org/LICENSE.txt for license information +# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +# +# ---------------------------------------------------------------------------- +""" +Unix like host class +""" +# ---------------------------------------------------------------------------- + +from __future__ import absolute_import + +import os.path +import re +import subprocess + +from .base import Base +from ..utils import which, CachedProperty, printf +from .. import shell + +__all__ = [ + 'Linux', + 'FreeBSD', + 'Cygwin', +] + + +class GenericUnix(Base): + + def _find_clang(self, tool): + for suffix in ['', '-3.8', '-3.7', '-3.6', '-3.5']: + found = which(tool + suffix) + if found: + return found + return None + + def find_clang_cc(self): + return self._find_clang('clang') + + def find_clang_cxx(self): + return self._find_clang('clang++') + + def find_cmake(self): + '''\ + Return `CMake` host tool object if found. `None` otherwise. + ''' + return which('cmake') + + def system_memory_in_bytes(self): + # Currently, not used + try: + from psutil import virtual_memory + return virtual_memory().total + except ImportError: + pass + + if not os.path.exists('/proc/meminfo'): + raise NotImplementedError() + + with open('/proc/meminfo') as f: + for line in f: + if "MemTotal" in line: + return int(re.finditer('\d+').next().group(0)) * 1024 + + def show_sdks(self): + """ + Print the host machine's `clang` version + """ + printf('{0}\n', shell.query(['clang', '--version'], echo_=False)) + + +class Linux(GenericUnix): + pass + + +class FreeBSD(GenericUnix): + + @CachedProperty + def _release_date(): + """ + Return the release date for FreeBSD operating system on this host. + If the release date cannot be ascertained, return None. + """ + try: + # For details on `sysctl`, see: + # http://www.freebsd.org/cgi/man.cgi?sysctl(8) + return int(shell.query(['sysctl', '-n', 'kern.osreldate'])) + except subprocess.CalledProcessError: + return None + + def _find_clang(self, tool): + rel_date = self._release_date + if rel_date is None or rel_date <= 1100000: + for suffix in ['38', '37', '36', '35']: + found = which(tool + suffix) + if found: + return found + return None + else: + return which(tool) + + +class Cygwin(GenericUnix): + pass diff --git a/utils-experimental/build-script-impl/build_script/main_driver.py b/utils-experimental/build-script-impl/build_script/main_driver.py new file mode 100644 index 0000000000000..512128fbb74a3 --- /dev/null +++ b/utils-experimental/build-script-impl/build_script/main_driver.py @@ -0,0 +1,720 @@ +# build_script/main_driver.py -----------------------------------*- 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 http://swift.org/LICENSE.txt for license information +# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +# +# ---------------------------------------------------------------------------- +""" +The main workflow of the build-script +""" +# ---------------------------------------------------------------------------- + +from __future__ import absolute_import + +import os +import os.path + +from . import env +from . import shell +from .host import host +from .workspace import Workspace +from .cmake import CMake +from .exceptions import BuildError +from .driver_arguments import create_argparser, Args +from . import products +from . import swift_utils +from .utils import printf + + +# Main entry point for the normal mode. +def main(argv): + # remove argv[0] and dash-dash ("--") + argv = [arg for arg in argv[1:] if arg != "--"] + + args = Args() + + # Temporary option default value because of some workarounds here. + + # FIXME: Make the option of building using the host clang the default + # as a workaround until we fix the ASAN bot. + # https://github.com/apple/swift/commit/0b1e858 + args.build_runtime_with_host_compiler = True + + # Parse arguments + parser = create_argparser() + args = parser.parse_args(argv, namespace=args) + + # Setup environment + shell.dry_run = args.dry_run + + if host.is_darwin(): + host.xcrun_toolchain = args.darwin_xcrun_toolchain + + # 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) + + # Check host environment + if args.host_target is None: + raise BuildError("Unsupported host operating system.") + + if not os.path.isdir(env.SWIFT_SOURCE_ROOT): + raise BuildError("Source root directory %s does not exist. " + "Forgot to set $SWIFT_SOURCE_ROOT environment " + "variable?" % env.SWIFT_SOURCE_ROOT) + + # check clang available + if args.host_cc is None: + args.host_cc = host.find_clang_cc() + if args.host_cxx is None: + args.host_cxx = host.find_clang_cxx() + is_host_clang_ok = ( + args.host_cc is not None and os.access(args.host_cc, os.X_OK) and + args.host_cxx is not None and os.access(args.host_cxx, os.X_OK)) + if not is_host_clang_ok: + raise BuildError("Can't find clang. Please install clang-3.5 or a " + "later version.") + # check cmake + if args.cmake is None: + args.cmake = host.find_cmake() + elif not os.access(args.cmake, os.X_OK): + args.cmake = None + if args.cmake is None: + raise BuildError("Can't find CMake. Please install CMake") + + # check distcc is requested + host_distcc = None + host_distcc_pump = None + if args.distcc: + host_distcc = host.find_distcc() + host_distcc_pump = host.find_distcc_pump() + if host_distcc is None or host_distcc_pump is None: + raise BuildError("Can't find distcc") + + # Sanitize arguments + if args.symbols_package: + if not os.path.isabs(args.symbols_package): + raise BuildError('--symbols-package must be an absolute path ' + '(was \'%s\')' % (args.symbols_package, )) + if not args.install_symroot: + raise BuildError("--install-symroot is required when specifying " + "--symbols-package.") + + install_something = any( + getattr(args, 'install_' + p) for p in [ + 'cmark', 'swift', 'llbuild', 'swiftpm', + 'libdispatch', 'foundation', 'xctest']) + if not install_something: + install_something = len(args.llvm_install_components) > 0 + if install_something and args.install_destdir is None: + raise BuildError("--install-destdir is required when install " + "something.") + + if not args.skip_build_android: + if None in [args.android_ndk, args.android_ndk_version, + args.android_icu_uc, args.android_icu_uc_include, + args.android_icu_i18n, args.android_icu_i18n_include]: + raise BuildError("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 speficied") + + # Tweaks + + if host.is_darwin(): + if args.toolchain_prefix is None: + args.toolchain_prefix = host.toolchain_prefix(args.install_prefix) + + # If not explictly set --host-test, disable them all. + if not args.host_test: + args.skip_test_ios_host = True + args.skip_test_tvos_host = True + args.skip_test_watchos_host = True + + # We need ninja even if cmake_generator is *not* `Ninja`, because some + # products use ninja directry. + if host.find_ninja() is None: + args.build_ninja = True + + # Linux ARM targets require the gold linker. + gold_linker_required_deployment_targets = [ + 'linux-armv6', + 'linux-armv7', + 'linux-aarch64'] + if args.host_target in gold_linker_required_deployment_targets: + args.use_gold_linker = True + + # Workarounds + + args.skip_compiler_rt = False # Temporary attribute for the workaround. + + # FIXME: We currently do not support building compiler-rt with the + # Xcode generator. + if args.cmake_generator == 'Xcode': + args.skip_compier_rt = True + + # FIXME: We currently do not support cross-compiling swift with + # compiler-rt. + if len(args.cross_compile_tools_deployment_targets): + args.skip_compiler_rt = True + + # Show SDKs if requested + if args.show_sdks: + host.show_sdks() + + # Make arguments object immutable. + + Args.freeze(args) + + # Initialize workspace + + def compute_build_root(): + + root_parent = env.SWIFT_BUILD_ROOT + # If --build-subdir is specified, use that. + if args.build_subdir is not None: + return os.path.join(root_parent, args.build_subdir) + + # Create a name for the build directory. + build_subdir = args.cmake_generator.replace(" ", "_") + + cmark_build_dir_label = args.cmark_build_type + if args.cmark_enable_assertions: + cmark_build_dir_label += "Assert" + + llvm_build_dir_label = args.llvm_build_type + if args.llvm_enable_assertions: + llvm_build_dir_label += "Assert" + + swift_build_dir_label = args.swift_build_type + if args.swift_enable_assertions: + swift_build_dir_label += "Assert" + if args.swift_analyze_code_coverage != "false": + swift_build_dir_label += "Coverage" + + swift_stdlib_build_dir_label = args.swift_stdlib_build_type + if args.swift_stdlib_enable_assertions: + swift_stdlib_build_dir_label += "Assert" + + if (llvm_build_dir_label == swift_build_dir_label and + llvm_build_dir_label == swift_stdlib_build_dir_label and + llvm_build_dir_label == cmark_build_dir_label): + # Use a simple directory name if all projects use the same build + # type. + build_subdir += "-" + llvm_build_dir_label + elif (llvm_build_dir_label != swift_build_dir_label and + llvm_build_dir_label == swift_stdlib_build_dir_label and + llvm_build_dir_label == cmark_build_dir_label): + # Swift build type differs. + build_subdir += "-" + llvm_build_dir_label + build_subdir += "+swift-" + swift_build_dir_label + elif (llvm_build_dir_label == swift_build_dir_label and + llvm_build_dir_label != swift_stdlib_build_dir_label and + llvm_build_dir_label == cmark_build_dir_label): + # Swift stdlib build type differs. + build_subdir += "-" + llvm_build_dir_label + build_subdir += "+stdlib-" + swift_stdlib_build_dir_label + elif (llvm_build_dir_label == swift_build_dir_label and + llvm_build_dir_label == swift_stdlib_build_dir_label and + llvm_build_dir_label != cmark_build_dir_label): + # cmark build type differs. + build_subdir += "-" + llvm_build_dir_label + build_subdir += "+cmark-" + cmark_build_dir_label + else: + # We don't know how to create a short name, so just mangle in all + # the information. + build_subdir += "+llvm-" + llvm_build_dir_label + build_subdir += "+swift-" + swift_build_dir_label + build_subdir += "+stdlib-" + swift_stdlib_build_dir_label + + return os.path.join(root_parent, build_subdir) + + build_root = args.build_root + if build_root is None: + build_root = compute_build_root() + + source_root = args.source_root + if source_root is None: + source_root = env.SWIFT_SOURCE_ROOT + + workspace = Workspace(source_root=source_root, + build_root=build_root) + + # Replace swift_utils base directory just in case `source_root` is not + # *this* source root. + swift_utils.basedir = os.path.join(source_root, 'swift', 'utils') + + # Potentionally file system mutating operations from here. + + if os.path.exists(build_root): + # Clean if requested + if args.clean: + printf("-- Clean previous build --") + shell.rmtree(build_root) + # FIXME: Souldn't we clean install_destdir also? + + if not os.path.exists(build_root): + # Create build directory if not exists + shell.makedirs(build_root) + else: + # TODO: Implement auto reconfigure. + # To do that, we should serialze `args` object, and store it in + # build_basedir. Then, at the next build, if saved args are + # different from this invocation, we should reconfigure. + pass + + # Prepare Product builder + products.CMark.prepare(workspace) + products.LLVM.prepare(workspace) + products.Swift.prepare(workspace) + if not args.skip_build_lldb: + products.LLDB.prepare(workspace) + if not args.skip_build_libdispatch: + products.Libdispatch.prepare(workspace) + if not args.skip_build_foundation: + products.Foundation.prepare(workspace) + if not args.skip_build_xctest: + products.XCTest.prepare(workspace) + if not args.skip_build_llbuild: + products.LLBuild.prepare(workspace) + if not args.skip_build_swiftpm: + products.SwiftPM.prepare(workspace) + + # Create cross tools compilation target list + # FIXME: We should emit warning or error if unsupported deployment + # targets are requested. + cross_tools_deployment_targets = [ + target for target in args.cross_compile_tools_deployment_targets if + target != args.host_target] + + all_deployment_targets = [args.host_target, ] + all_deployment_targets += cross_tools_deployment_targets + + # Initialize Builders list + + builds = [] + + # Instantiate all builders for each deployment targets for each products. + + # At first, build Ninja if needed + ninja_build = None + if args.build_ninja: + products.Ninja.prepare(workspace) + ninja_build = products.Ninja( + deployment_target=args.host_target, + target_build_dir=workspace.build_dir(args.host_target, 'ninja'), + args=args) + builds.append(ninja_build) + + # Prepare common CMake + cmake = CMake( + path=args.cmake, + host_cc=args.host_cc, + host_cxx=args.host_cxx, + host_distcc=host_distcc, + host_distcc_pump=host_distcc_pump, + ninja_build=ninja_build, + args=args) + + host_swift_build = None + host_llvm_build = None + need_merge_lipo = (args.cross_compile_tools_deployment_targets and + not args.skip_merge_lipo_cross_compile_tools) + + for deployment_target in all_deployment_targets: + + # Where to install + install_destdir = args.install_destdir + if install_destdir is None: + install_destdir = '/tmp' # dummy + if not args.cross_compile_tools_deployment_targets: + target_install_destdir = install_destdir + else: + # If cross compiling tools, install into a deployment target + # specific subdirectory. + if need_merge_lipo: + target_install_destdir = os.path.join( + workspace.build_root_dir(), + 'intermediate-install', + deployment_target) + else: + target_install_destdir = os.path.join( + install_destdir, + deployment_target) + + # Start to instantiate product builders. + + cmark_build_dir = workspace.build_dir(deployment_target, 'cmark') + cmark_build = products.CMark( + deployment_target=deployment_target, + target_build_dir=cmark_build_dir, + target_install_destdir=target_install_destdir, + cmake=cmake, + args=args) + builds.append(cmark_build) + + llvm_build_dir = workspace.build_dir(deployment_target, 'llvm') + llvm_build = products.LLVM( + deployment_target=deployment_target, + target_build_dir=llvm_build_dir, + target_install_destdir=target_install_destdir, + host_llvm_build=host_llvm_build, + cmake=cmake, + args=args) + builds.append(llvm_build) + + swift_build_dir = workspace.build_dir(deployment_target, 'swift') + swift_build = products.Swift( + deployment_target=deployment_target, + target_build_dir=swift_build_dir, + target_install_destdir=target_install_destdir, + cmake=cmake, + cmark_build=cmark_build, + llvm_build=llvm_build, + host_llvm_build=host_llvm_build, + host_swift_build=host_swift_build, + args=args) + builds.append(swift_build) + + if deployment_target == args.host_target: + host_llvm_build = llvm_build + host_swift_build = swift_build + + # Optional products. + + lldb_build = None + if not args.skip_build_lldb: + lldb_build_dir = workspace.build_dir(deployment_target, 'lldb') + lldb_build = products.LLDB( + deployment_target=deployment_target, + target_build_dir=lldb_build_dir, + target_install_destdir=target_install_destdir, + cmark_build=cmark_build, + llvm_build=llvm_build, + swift_build=swift_build, + cmake=cmake, + args=args) + builds.append(lldb_build) + + libdispatch_build = None + if not args.skip_build_libdispatch: + libdispatch_build_dir = workspace.build_dir(deployment_target, + 'libdispatch') + libdispatch_build = products.Libdispatch( + deployment_target=deployment_target, + target_build_dir=libdispatch_build_dir, + target_install_destdir=target_install_destdir, + swift_build=swift_build, + args=args) + builds.append(libdispatch_build) + + foundation_build = None + if not args.skip_build_foundation: + foundation_build_dir = workspace.build_dir(deployment_target, + 'foundation') + foundation_build = products.Foundation( + deployment_target=deployment_target, + target_build_dir=foundation_build_dir, + target_install_destdir=target_install_destdir, + llvm_build=llvm_build, + swift_build=swift_build, + libdispatch_build=libdispatch_build, + ninja_build=ninja_build, + args=args) + builds.append(foundation_build) + + xctest_build = None + if not args.skip_build_xctest: + xctest_build_dir = workspace.build_dir(deployment_target, + 'xctest') + xctest_build = products.XCTest( + deployment_target=deployment_target, + target_build_dir=xctest_build_dir, + target_install_destdir=target_install_destdir, + swift_build=swift_build, + foundation_build=foundation_build, + args=args) + builds.append(xctest_build) + + # FIXME: Foundation *tests* optionally depends on xctest build. + # XCTest *build* depends on foundation build. + # Is there a better way? + if foundation_build: + foundation_build.xctest_build = xctest_build + + llbuild_build = None + if not args.skip_build_llbuild: + llbuild_build_dir = workspace.build_dir(deployment_target, + 'llbuild') + llbuild_build = products.LLBuild( + deployment_target=deployment_target, + target_build_dir=llbuild_build_dir, + target_install_destdir=target_install_destdir, + llvm_build=llvm_build, + cmake=cmake, + args=args) + builds.append(llbuild_build) + + swiftpm_build = None + if not args.skip_build_swiftpm: + swiftpm_build_dir = workspace.build_dir(deployment_target, + 'swiftpm') + swiftpm_build = products.SwiftPM( + deployment_target=deployment_target, + target_build_dir=swiftpm_build_dir, + target_install_destdir=target_install_destdir, + swift_build=swift_build, + llbuild_build=llbuild_build, + foundation_build=foundation_build, + xctest_build=xctest_build, + args=args) + builds.append(swiftpm_build) + + # Print out some infomation + + (stdlib_targets, + benchmark_targets, + test_targets, + run_benchmarks_targets) = host_swift_build._stdlib_build_targets() + printf("Building the standard library for: {0}", + ", ".join(stdlib_targets)) + if len(test_targets): + printf("Running Swift tests for: {0}", + ", ".join(test_targets)) + if len(run_benchmarks_targets): + printf("Running Swift benchmarks for: {0}", + ", ".join(run_benchmarks_targets)) + + # Configure and Build + for build in builds: + build.configure() + build.build() + # FIXME: Since some products create intermediate files in its *source* + # directory, we have to configure and build in a row. + # *Except Ninja* because other configure requires pre-built ninja. + # This should be: + # + # if ninja_build is not None: + # ninja_build.configure() + # ninja_build.build() + # + # for build in builds: + # build.configre() + # for build in builds: + # build.build() + + # Test + for build in builds: + build.test() + + # Install + for build in builds: + build.install() + + # FIXME: Factor out below so that we can unit test them + + # Merge lipo if required + if need_merge_lipo and args.install_destdir: + printf("--- Merging and running lipo for {0} ---", + str(cross_tools_deployment_targets)) + recursive_lipo_cmd = [ + swift_utils('recursive-lipo'), + "--lipo=" + host.xcrun_find('lipo'), + "--copy-subdirs={0} {1}".format( + os.path.join(args.install_prefix, + 'lib', 'swift'), + os.path.join(args.install_prefix, + 'lib', 'swift_static')), + "--destination=" + args.install_destdir] + for deployment_target in cross_tools_deployment_targets: + recursive_lipo_cmd += [ + os.path.join(args.build_dir, + 'intermediate-install', + deployment_target)] + shell.invoke(recursive_lipo_cmd) + + # Install symbols + if args.darwin_install_extract_symbols: + printf('--- Installing symbols ---') + cmd = 'find ./{0} -perm -0111 -type f -print | cpio -pdm "{1}"'.format( + args.toolchain_prefix.lstrip('/'), + args.install_symroot) + with shell.pushd(args.install_destdir): + shell.invoke(["sh", "-c", cmd]) + + cmd = ("find ./{0} -perm -0111 -type f -print | " + "grep -v swift-stdlib-tool | " + "grep -v crashlog.py | " + "grep -v symbolication.py | " + "xargs -n 1 -P {1} {2}") + cmd = cmd.format(args.toolchain_prefix.lstrip('/'), + args.build_jobs, + host.xcrun_find('dsymutil')) + with shell.pushd(args.install_symroot): + shell.invoke(["sh", "-c", cmd]) + + cmd = ('find {0}/{1} ' + '"(" -perm -0111 -or -name "*.a" ")" -type f -print | ' + 'xargs -n 1 -P {2} {3} -S') + cmd = cmd.format(args.install_destdir, + args.toolchain_prefix.lstrip('/'), + args.build_jobs, + host.xcrun_find('strip')) + shell.invoke(["sh", "-c", cmd]) + + # Installable package + if args.installable_package: + printf("--- Creating installable package ---") + printf("-- Package file: {0} --", args.installable_package) + + if host.is_darwin(): + # Copy swift-stdlib-tool laucher if neccesary. + swift_stdlib_tool_bin_path = os.path.join( + args.install_destdir, + args.install_prefix.lstrip('/'), + 'bin', 'swift-stdlib-tool') + if not os.path.exists(swift_stdlib_tool_bin_path): + printf("--- Copy swift-stdlib-tool ---") + shell.copy( + swift_build.swift_stdlib_tool_source_path, + swift_stdlib_tool_bin_path) + + # Create plist for xctoolchain. + printf("-- Create Info.plist --") + darwin_toolchain_install_location = os.path.join( + '/Library/Developer/Toolchains', + '%s.xctoolchain' % args.darwin_toolchain_name) + darwin_toolchain_info_plist_path = os.path.join( + args.install_destdir, + args.toolchain_prefix.lstrip('/'), + "Info.plist") + darwin_toolchain_report_url = "https://bugs.swift.org/" + + if os.path.exists(darwin_toolchain_info_plist_path): + printf("-- Removing: {0}", darwin_toolchain_info_plist_path) + shell.remove(darwin_toolchain_info_plist_path) + + plist_buddy_bin = "/usr/libexec/PlistBuddy" + + def plist_buddy(name, ty, value=None): + val = 'Add {0} {1}'.format(name, ty) + if value is not None: + val += ' "{0}"'.format(value) + command = [plist_buddy_bin, '-c', val] + command += [darwin_toolchain_info_plist_path, ] + shell.invoke(command) + + plist_buddy('DisplayName', 'string', + args.darwin_toolchain_display_name) + plist_buddy('Version', 'string', + args.darwin_toolchain_version) + plist_buddy('CFBundleIdentifier', 'string', + args.darwin_toolchain_bundle_identifier) + plist_buddy('ReportProblemURL', 'string', + darwin_toolchain_report_url) + plist_buddy('Aliases', 'array') + plist_buddy('Aliases:0', 'string', + args.darwin_toolchain_alias) + + shell.invoke(['chmod', 'a+r', darwin_toolchain_info_plist_path]) + + # Codesign + if args.darwin_toolchain_application_cert is not None: + printf("-- Codesign xctoolchain --") + shell.invoke([ + swift_utils('toolchain-codesign'), + args.darwin_toolchain_application_cert, + os.path.join(args.install_destdir, + args.toolchain_prefix.lstrip('/'))]) + + # Installer + if args.darwin_toolchain_installer_package is not None: + printf("-- Create Installer --") + + shell.invoke([ + swift_utils('toolchain-installer'), + os.path.join(args.install_destdir, + args.toolchain_prefix.lstrip('/')), + args.darwin_toolchain_bundle_identifier, + args.darwin_toolchain_installer_cert, + args.darwin_toolchain_installer_package, + darwin_toolchain_install_location, + args.darwin_toolchain_version, + swift_utils('darwin-installer-scripts')]) + + # Create tarball + with shell.pushd(args.install_destdir): + shell.invoke(['tar', '-c', '-z', + '-f', args.installable_package, + args.install_prefix.lstrip('/')]) + else: + # Just create tarball + with shell.pushd(args.install_destdir): + shell.invoke(['tar', '-c', '-z', + '--owner=0', '--group=0', + '-f', args.installable_package, + args.install_prefix.lstrip('/')]) + + # Test Installable package + if args.installable_package and args.test_installable_package: + printf("-- Test Installable Package --") + + # Collect paths + pkg_tests_source_dir = workspace.subdir('swift-integration-tests') + pkg_tests_sandbox_parent = workspace.build_dir('none', + 'integration-tests') + if host.is_darwin(): + pkg_tests_sandbox = os.path.join( + pkg_tests_sandbox_parent, args.toolchain_prefix.lstrip('/')) + else: + pkg_tests_sandbox = pkg_tests_sandbox_parent + + # Clean up tests directory + if os.path.exists(pkg_tests_sandbox_parent): + shell.rmtree(pkg_tests_sandbox_parent) + shell.makedirs(pkg_tests_sandbox) + + # Install the package into sandbox and run tests + with shell.pushd(pkg_tests_sandbox_parent): + shell.invoke(['tar', '-x', '-z', + '-f', args.installable_package]) + + lit_bin_path = host_llvm_build.lit_bin_path + filecheck_bin_path = host_llvm_build.filecheck_bin_path + with shell.pushd(pkg_tests_source_dir): + shell.invoke(['python', lit_bin_path, '.', '-sv', + '--param', 'package-path=' + pkg_tests_sandbox, + '--param', 'filecheck=' + filecheck_bin_path]) + + # Symbols package + if args.symbols_package: + printf('--- Creating symbols package ---') + printf('-- Package file: {0} --', args.symbols_package) + + if host.is_darwin(): + prefix = host.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): + shell.invoke(['tar', '-c', '-z', '-f', + args.symbols_package, + prefix.lstrip('/')]) + + return 0 diff --git a/utils-experimental/build-script-impl/build_script/main_preset.py b/utils-experimental/build-script-impl/build_script/main_preset.py new file mode 100644 index 0000000000000..219bd2ac5a2a4 --- /dev/null +++ b/utils-experimental/build-script-impl/build_script/main_preset.py @@ -0,0 +1,112 @@ +# build_script/main_preset.py -----------------------------------*- 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 http://swift.org/LICENSE.txt for license information +# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +# +# ---------------------------------------------------------------------------- +""" +Preset mode entry point +""" +# ---------------------------------------------------------------------------- + +from __future__ import absolute_import +from __future__ import print_function + +import sys +import os.path +import argparse + +from . import env +from . import _shell +from .utils import printf_with_argv0 +from .presets import ( + get_all_preset_names, + get_preset_options, +) + + +def main(argv): + ''' + Main entry point for the preset mode. + ''' + + parser = argparse.ArgumentParser( + formatter_class=argparse.RawDescriptionHelpFormatter, + description="""Builds Swift using a preset.""") + 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="store_true") + parser.add_argument( + "--distcc", + help="use distcc", + action="store_true") + + parser.add_argument( + "-n", "--dry-run", + help="Print the commands that would be executed, but do not execute " + "them", + default=False, + action="store_true") + + parser.add_argument( + "preset_substitutions_raw", + help="'name=value' pairs that are substituted in the preset", + nargs="*", + metavar="SUBSTITUTION") + args = parser.parse_args() + + if len(args.preset_file_names) == 0: + args.preset_file_names = [ + os.path.join(env.HOME, ".swift-build-presets"), + os.path.join( + env.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: + printf_with_argv0("Missing --preset option") + return 1 + + 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 += ['-n'] + + build_script_args += preset_args + if args.distcc: + build_script_args += ["--distcc"] + + print( + "using preset '" + args.preset + "'") + + _shell.execv(build_script_args, echo=True) diff --git a/utils-experimental/build-script-impl/build_script/presets.py b/utils-experimental/build-script-impl/build_script/presets.py new file mode 100644 index 0000000000000..5bdc562e0d37e --- /dev/null +++ b/utils-experimental/build-script-impl/build_script/presets.py @@ -0,0 +1,110 @@ +# build_script/presets.py ---------------------------------------*- 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 http://swift.org/LICENSE.txt for license information +# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +# +# ---------------------------------------------------------------------------- +""" +build-presets.ini config loader +""" +# ---------------------------------------------------------------------------- + +from __future__ import absolute_import + +try: + # Python 2 + import ConfigParser +except ImportError: + # Python 3 + import configparser as ConfigParser + +from .exceptions import BuildError + + +def _load_preset_files_impl(preset_file_names, substitutions={}): + config = ConfigParser.SafeConfigParser(substitutions, allow_no_value=True) + if config.read(preset_file_names) == []: + raise BuildError( + "preset file not found (tried " + str(preset_file_names) + ")") + return config + + +_PRESET_PREFIX = "preset: " + + +def _get_preset_options_impl(config, substitutions, preset_name): + section_name = _PRESET_PREFIX + preset_name + if section_name not in config.sections(): + return (None, None, None) + + build_script_opts = [] + build_script_impl_opts = [] + missing_opts = [] + dash_dash_seen = False + + for o in config.options(section_name): + try: + a = config.get(section_name, o) + except ConfigParser.InterpolationMissingOptionError as e: + # e.reference contains the correctly formatted option + missing_opts.append(e.reference) + continue + + if not a: + a = "" + + if o in substitutions: + continue + + opt = None + if o == "mixin-preset": + # Split on newlines and filter out empty lines. + mixins = filter(None, [m.strip() for m in a.splitlines()]) + for mixin in mixins: + (base_build_script_opts, + base_build_script_impl_opts, + base_missing_opts) = \ + _get_preset_options_impl(config, substitutions, mixin) + build_script_opts += base_build_script_opts + build_script_impl_opts += base_build_script_impl_opts + missing_opts += base_missing_opts + elif o == "dash-dash": + dash_dash_seen = True + elif a == "": + opt = "--" + o + else: + opt = "--" + o + "=" + a + + if opt: + if not dash_dash_seen: + build_script_opts.append(opt) + else: + build_script_impl_opts.append(opt) + + return (build_script_opts, build_script_impl_opts, missing_opts) + + +def get_preset_options(substitutions, preset_file_names, preset_name): + config = _load_preset_files_impl(preset_file_names, substitutions) + + (build_script_opts, build_script_impl_opts, missing_opts) = \ + _get_preset_options_impl(config, substitutions, preset_name) + if not build_script_opts: + raise BuildError("preset '%s' not found" % preset_name) + if missing_opts: + raise BuildError("missing option(s) for preset '%s': %s" % ( + preset_name, + ", ".join(missing_opts))) + + return build_script_opts + ["--"] + build_script_impl_opts + + +def get_all_preset_names(preset_file_names): + config = _load_preset_files_impl(preset_file_names) + return [name[len(_PRESET_PREFIX):] for name in config.sections() + if name.startswith(_PRESET_PREFIX)] diff --git a/utils-experimental/build-script-impl/build_script/products/__init__.py b/utils-experimental/build-script-impl/build_script/products/__init__.py new file mode 100644 index 0000000000000..540f31d189a96 --- /dev/null +++ b/utils-experimental/build-script-impl/build_script/products/__init__.py @@ -0,0 +1,41 @@ +# build_script/products/__init__.py -----------------------------*- 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 http://swift.org/LICENSE.txt for license information +# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +# +# ---------------------------------------------------------------------------- +""" +Products package +""" +# ---------------------------------------------------------------------------- + +from __future__ import absolute_import + +from .ninja import Ninja +from .cmark import CMark +from .llvm import LLVM +from .lldb import LLDB +from .llbuild import LLBuild +from .swift import Swift +from .swiftpm import SwiftPM +from .libdispatch import Libdispatch +from .foundation import Foundation +from .xctest import XCTest + +__all__ = [ + 'Ninja', + 'CMark', + 'LLVM', + 'LLDB', + 'LLBuild', + 'Swift', + 'SwiftPM', + 'Libdispatch', + 'Foundation', + 'XCTest', +] diff --git a/utils-experimental/build-script-impl/build_script/products/cmark.py b/utils-experimental/build-script-impl/build_script/products/cmark.py new file mode 100644 index 0000000000000..fdb9589d9831c --- /dev/null +++ b/utils-experimental/build-script-impl/build_script/products/cmark.py @@ -0,0 +1,137 @@ +# build_script/products/cmark.py --------------------------------*- 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 http://swift.org/LICENSE.txt for license information +# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +# +# ---------------------------------------------------------------------------- +""" +CMark builder +""" +# ---------------------------------------------------------------------------- + +import os.path +from ..exceptions import BuildError +from .. import targets +from ..cmake import CMakeOptions +from ..utils import printf +from ..host import host + + +class CMark(object): + + source_dir = None + + @classmethod + def prepare(cls, workspace): + cls.source_dir = workspace.subdir('cmark') + if cls.source_dir is None: + raise BuildError("Couldn't find cmark source directory.") + + def __init__(self, + deployment_target, + target_build_dir, + target_install_destdir, + cmake, + args): + self.deployment_target = deployment_target + self.build_dir = target_build_dir + self.install_destdir = target_install_destdir + self.cmake = cmake + self.args = args + + @property + def library_dir(self): + if self.cmake.generator == "Xcode": + return os.path.join(self.build_dir, 'src', + self.args.cmark_build_type) + else: + return os.path.join(self.build_dir, 'src') + + def _c_flags(self): + cflags = [] + cflags += self.cmake.common_cross_c_flags(self.deployment_target) + if self.cmake.is_release_build_type(self.args.cmark_build_type): + cflags += ['-fno-stack-protector', ] + return cflags + + def configure(self): + if (not self.args.reconfigure and + self.cmake.is_configured(self.build_dir)): + return + + printf("--- Configuring CMark ---") + cmake_options = CMakeOptions() + define = cmake_options.define + + if self.args.use_gold_linker: + define('CMAKE_EXE_LINKER_FLAGS:STRING', "-fuse-ld=gold") + define('CMAKE_SHARED_LINKER_FLAGS:STRING', "-fuse-ld=gold") + + define('CMAKE_BUILD_TYPE:STRING', self.args.cmark_build_type) + + if targets.is_darwin_type(self.deployment_target): + c_flags = ' '.join(self._c_flags()) + xcrun_sdk_name = targets.xcrun_sdk_name(self.deployment_target) + xcrun_sdk_path = host.sdk_path(xcrun_sdk_name) + define('CMAKE_C_FLAGS', c_flags) + define('CMAKE_CXX_FLAGS', c_flags) + define('CMAKE_OSX_SYSROOT:PATH', xcrun_sdk_path) + if targets.is_osx(self.deployment_target): + define('CMAKE_OSX_DEPLOYMENT_TARGET', + self.args.darwin_deployment_version_osx) + + # Do configure + self.cmake.configure( + source_dir=self.source_dir, + build_dir=self.build_dir, + options=cmake_options) + + def _cmake_config_opts(self): + config_opts = [] + if self.args.cmake_generator == 'Xcode': + config_opts += [ + '--config', self.args.cmark_build_type] + return config_opts + + def build(self): + if self.args.skip_build_cmark: + return + + printf("--- Building CMark ---") + self.cmake.build( + build_targets=['all', ], + build_dir=self.build_dir, + config_opts=self._cmake_config_opts()) + + def test(self): + if (self.args.skip_test_cmark or + self.deployment_target != self.args.host_target): + return + + printf("--- Building tests for CMark ---") + self.cmake.build( + build_targets=["api_test", ], + build_dir=self.build_dir, + config_opts=self._cmake_config_opts()) + + printf("--- Running tests for CMark ---") + results_targets = ["test", ] + if self.args.cmake_generator == 'Xcode': + results_targets = ["RUN_TESTS", ] + self.cmake.test( + test_targets=results_targets, + build_dir=self.build_dir, + config_opts=self._cmake_config_opts()) + + def install(self): + if not self.args.install_cmark: + return + printf("--- Installing CMark ---") + self.cmake.install( + dest_dir=self.install_destdir, + build_dir=self.build_dir) diff --git a/utils-experimental/build-script-impl/build_script/products/foundation.py b/utils-experimental/build-script-impl/build_script/products/foundation.py new file mode 100644 index 0000000000000..c1b4588cb13bd --- /dev/null +++ b/utils-experimental/build-script-impl/build_script/products/foundation.py @@ -0,0 +1,134 @@ +# build_script/products/foundation.py ---------------------------*- 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 http://swift.org/LICENSE.txt for license information +# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +# +# ---------------------------------------------------------------------------- +""" +Foundation builder +""" +# ---------------------------------------------------------------------------- + +import os + +from .. import shell +from ..utils import printf +from ..exceptions import BuildError + + +class Foundation(object): + + source_dir = None + + @classmethod + def prepare(cls, workspace): + cls.source_dir = workspace.subdir('swift-corelibs-foundation') + if cls.source_dir is None: + raise BuildError("Couldn't find Foundation source directory.") + + def __init__(self, + deployment_target, + target_build_dir, + target_install_destdir, + llvm_build, + swift_build, + libdispatch_build, + ninja_build, + args): + self.deployment_target = deployment_target + self.build_dir = target_build_dir + self.install_destdir = target_install_destdir + + self.llvm_build = llvm_build + self.swift_build = swift_build + self.libdispatch_build = libdispatch_build + self.ninja_build = ninja_build + self.xctest_build = None # To be populated later. + + self.args = args + + @property + def foundation_path(self): + return os.path.join(self.build_dir, 'Foundation') + + def _ninja_bin(self): + ninja_bin = 'ninja' + if self.ninja_build is not None: + ninja_bin = self.ninja_build.ninja_bin_path + return ninja_bin + + def configure(self): + printf("--- Configuring Foundation ---") + + # FIXME: Foundation always require re-configuration because + # `configure` script pollutes it's source directory, that might + # cause cross compilation failure. + + env = [ + ('SWIFTC', self.swift_build.swiftc_bin_path), + ('CLANG', self.llvm_build.clang_bin_path), + ('SWIFT', self.swift_build.swift_bin_path), + ('SDKROOT', self.swift_build.build_dir), + ('BUILD_DIR', self.build_dir), + # FIXME: We should use self.install_destdir instead. + ('DSTROOT', (self.args.install_destdir or "")), + ('PREFIX', self.args.install_prefix)] + + command = ['./configure', self.args.foundation_build_type] + if self.xctest_build is not None: + command += [ + '-DXCTEST_BUILD_DIR=' + self.xctest_build.build_dir] + if self.libdispatch_build is not None: + libdispatch_source_dir = self.libdispatch_build.source_dir + libdispatch_build_dir = self.libdispatch_build.build_dir + command += [ + '-DLIBDISPATCH_SOURCE_DIR=' + libdispatch_source_dir, + '-DLIBDISPATCH_BUILD_DIR=%s' + libdispatch_build_dir] + + with shell.pushd(self.source_dir): + shell.invoke(command, env=env) + + def build(self): + printf("--- Building Foundation ---") + with shell.pushd(self.source_dir): + shell.invoke([self._ninja_bin(), ]) + + def test(self): + if self.deployment_target != self.args.host_target: + return + if self.args.skip_test_foundation: + return + + printf("--- Running tests for Foundation ---") + + def ld_library_path(): + libpath = [ + self.swift_build.swiftlib_path, + self.foundation_path] + if self.xctest_build is not None: + libpath += [self.xctest_build.build_dir, ] + if 'LD_LIBRARY_PATH' in os.environ: + libpath += [os.environ['LD_LIBRARY_PATH'], ] + return os.pathsep.join(libpath) + + env = [('LD_LIBRARY_PATH', ld_library_path()), ] + + test_executable = os.path.join( + self.build_dir, "TestFoundation", "TestFoundation") + + with shell.pushd(self.source_dir): + shell.invoke([self._ninja_bin(), "TestFoundation"]) + shell.invoke([test_executable, ], env=env) + + def install(self): + if not self.args.install_foundation: + return + + printf("--- Installing Foundation ---") + with shell.pushd(self.source_dir): + shell.invoke([self._ninja_bin(), 'install']) diff --git a/utils-experimental/build-script-impl/build_script/products/libdispatch.py b/utils-experimental/build-script-impl/build_script/products/libdispatch.py new file mode 100644 index 0000000000000..0269f0770f609 --- /dev/null +++ b/utils-experimental/build-script-impl/build_script/products/libdispatch.py @@ -0,0 +1,97 @@ +# build_script/products/libdispatch .py -------------------------*- 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 http://swift.org/LICENSE.txt for license information +# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +# +# ---------------------------------------------------------------------------- +""" +libdispatch builder +""" +# ---------------------------------------------------------------------------- + +import os + +from .. import shell +from ..utils import printf +from ..exceptions import BuildError + + +class Libdispatch(object): + + source_dir = None + + @classmethod + def prepare(cls, workspace): + cls.source_dir = workspace.subdir('swift-corelibs-libdispatch') + if cls.source_dir is None: + raise BuildError("Couldn't find libdipatch source directory.") + + if not os.path.exists(os.path.join(cls.source_dir, 'configure')): + # This is first time to build + with shell.pushd(cls.source_dir): + shell.invoke(['autoreconf', '-fvi']) + + def __init__(self, + deployment_target, + target_build_dir, + target_install_destdir, + swift_build, + args): + self.deployment_target = deployment_target + self.build_dir = target_build_dir + self.install_destdir = target_install_destdir + + self.swift_build = swift_build + + self.args = args + + def is_configured(self): + return os.path.exists(os.path.join(self.build_dir, 'config.status')) + + def configure(self): + if not self.args.reconfigure and self.is_configured(): + # Already configured. + return + + printf("--- Configuring libdispatch ---") + # Do configre + configure_command = [os.path.join(self.source_dir, 'configure')] + configure_command += ( + '--prefix=' + self.install_destdir, + '--with-swift-toolchain=' + self.swift_build.build_dir, + ) + # Prepare build directory + if not os.path.exists(self.build_dir): + shell.makedirs(self.build_dir) + # Do configure + with shell.pushd(self.build_dir): + shell.invoke(configure_command) + + def build(self): + printf("--- Building libdispatch ---") + with shell.pushd(self.build_dir): + shell.invoke(['make']) + shell.chdir('tests') + shell.invoke(['make', 'build-tests']) + + def test(self): + if self.deployment_target != self.args.host_target: + return + if self.args.skip_test_libdispatch: + return + printf("--- Running tests for libdispatch ---") + with shell.pushd(self.build_dir): + shell.invoke(["make", "test"]) + + def install(self): + if not self.args.install_libdispatch: + return + + printf("--- Installing libdispatch ---") + with shell.pushd(self.build_dir): + shell.invoke(["make", "install"]) diff --git a/utils-experimental/build-script-impl/build_script/products/llbuild.py b/utils-experimental/build-script-impl/build_script/products/llbuild.py new file mode 100644 index 0000000000000..cb09be356a0d5 --- /dev/null +++ b/utils-experimental/build-script-impl/build_script/products/llbuild.py @@ -0,0 +1,118 @@ +# build_script/products/llbuild.py ------------------------------*- 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 http://swift.org/LICENSE.txt for license information +# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +# +# ---------------------------------------------------------------------------- +""" +llbuild builder +""" +# ---------------------------------------------------------------------------- + +import os.path +from ..exceptions import BuildError +from ..cmake import CMakeOptions +from ..utils import printf + + +class LLBuild(object): + source_dir = None + + @classmethod + def prepare(cls, workspace): + cls.source_dir = workspace.subdir('llbuild') + if cls.source_dir is None: + raise BuildError("Couldn't find llbuild source directory.") + + def __init__(self, + deployment_target, + target_build_dir, + target_install_destdir, + llvm_build, + cmake, + args): + self.deployment_target = deployment_target + self.build_dir = target_build_dir + self.install_destdir = target_install_destdir + self.llvm_build = llvm_build + self.cmake = cmake + + self.args = args + + def _bin_dir(self): + if self.args.cmake_generator == 'Xcode': + return os.path.join(self.build_dir, + 'bin', self.llbuild_build_type) + else: + return os.path.join(self.build_dir, 'bin') + + @property + def swift_build_tool_bin_path(self): + return os.path.join(self._bin_dir(), 'swift-build-tool') + + def configure(self): + if (not self.args.reconfigure and + self.cmake.is_configured(self.build_dir)): + return + + printf("--- Configuring llbuild ---") + cmake_options = CMakeOptions() + define = cmake_options.define + + if self.args.use_gold_linker: + define('CMAKE_EXE_LINKER_FLAGS:STRING', "-fuse-ld=gold") + define('CMAKE_SHARED_LINKER_FLAGS:STRING', "-fuse-ld=gold") + + define('CMAKE_INSTALL_PREFIX:PATH', self.args.install_prefix) + define('CMAKE_BUILD_TYPE:STRING', self.args.llbuild_build_type) + define('LLVM_ENABLE_ASSERTIONS:BOOL', + self.args.llbuild_enable_assertions) + define('LIT_EXECUTABLE:PATH', self.llvm_build.lit_bin_path) + define('FILECHECK_EXECUTABLE:PATH', + self.llvm_build.filecheck_bin_path) + + self.cmake.configure( + source_dir=self.source_dir, + build_dir=self.build_dir, + options=cmake_options) + + def _cmake_config_opts(self): + config_opts = [] + if self.args.cmake_generator == 'Xcode': + config_opts += [ + '--config', self.args.cmark_build_type] + return config_opts + + def build(self): + printf("--- Building llbuild ---") + self.cmake.build( + build_dir=self.build_dir, + build_targets=['all', ], + config_opts=self._cmake_config_opts()) + + def test(self): + if self.deployment_target != self.args.host_target: + return + if self.args.skip_test_llbuild: + return + + printf("--- Running tests for llbuild ---") + self.cmake.test( + build_dir=self.build_dir, + test_targets=['test', ], + config_opts=self._cmake_config_opts()) + + def install(self): + if not self.args.install_llbuild: + return + + printf("--- Installing llbuild ---") + self.cmake.install( + build_dir=self.build_dir, + dest_dir=self.install_destdir, + install_targets=["install-swift-build-tool", ]) diff --git a/utils-experimental/build-script-impl/build_script/products/lldb.py b/utils-experimental/build-script-impl/build_script/products/lldb.py new file mode 100644 index 0000000000000..b8e8f1270fabe --- /dev/null +++ b/utils-experimental/build-script-impl/build_script/products/lldb.py @@ -0,0 +1,225 @@ +# build_script/products/lldb.py ---------------------------------*- 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 http://swift.org/LICENSE.txt for license information +# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +# +# ---------------------------------------------------------------------------- +""" +LLDB builder +""" +# ---------------------------------------------------------------------------- + +import os.path +import datetime + +from .. import shell +from ..xcodebuild import Xcodebuild, XcodebuildOptions +from ..cmake import CMakeOptions +from ..host import host +from ..exceptions import BuildError +from ..utils import printf + + +class LLDB(object): + source_dir = None + + @classmethod + def prepare(cls, workspace): + cls.source_dir = workspace.subdir('lldb') + if cls.source_dir is None: + raise BuildError("Couldn't find lldb source directory.") + + def __init__(self, + deployment_target, + target_build_dir, + target_install_destdir, + cmark_build, + llvm_build, + swift_build, + cmake, + args): + self.deployment_target = deployment_target + self.build_dir = target_build_dir + self.install_destdir = target_install_destdir + self.cmark_build = cmark_build + self.llvm_build = llvm_build + self.swift_build = swift_build + self.cmake = cmake + + self.args = args + + def configure(self): + is_buildbot_build = ( + ('JENKINS_HOME' in os.environ) and + ('JOB_NAME' in os.environ) and + ('BUILD_NUMBER' in os.environ)) + if is_buildbot_build: + is_buildbot_build = "1" + else: + is_buildbot_build = "0" + + build_date = datetime.date.today().strftime('"%Y-%m-%d"') + + options = None + if host.is_darwin(): + options = XcodebuildOptions() + else: + options = CMakeOptions() + define = options.define + + define('LLDB_PATH_TO_LLVM_SOURCE:PATH', + self.llvm_build.source_dir) + define('LLDB_PATH_TO_CLANG_SOURCE:PATH', + self.llvm_build.clang_source_dir) + define('LLDB_PATH_TO_SWIFT_SOURCE:PATH', self.swift_build.source_dir) + define('LLDB_PATH_TO_LLVM_BUILD:PATH', self.llvm_build.build_dir) + define('LLDB_PATH_TO_CLANG_BUILD:PATH', self.llvm_build.build_dir) + define('LLDB_PATH_TO_SWIFT_BUILD:PATH', self.swift_build.build_dir) + define('LLDB_PATH_TO_CMARK_BUILD:PATH', self.cmark_build.build_dir) + define('LLDB_IS_BUILDBOT_BUILD:BOOL', is_buildbot_build) + define('LLDB_BUILD_DATE:STRING', build_date) + + if host.is_darwin(): + # Set up flags to pass to xcodebuild + + if self.args.lldb_no_debugserver: + define('DEBUGSERVER_DISABLE_CODESIGN', "1") + define('DEBUGSERVER_DELETE_AFTER_BUILD', "1") + if self.args.lldb_use_system_debugserver: + define('DEBUGSERVER_USE_FROM_SYSTEM', "1") + + define('SYMROOT', self.build_dir) + define('OBJROOT', self.build_dir) + + # xcodebuild doesn't have separate configure and build phases. + # Store configuration options into myself. + self.xcodebuild_options = options + self.xcodebuild_config = "CustomSwift-" + self.args.lldb_build_type + else: + if (not self.args.reconfigure and + self.cmake.is_configured(self.build_dir)): + return + + printf('--- Configuring LLDB ---') + if self.args.use_gold_linker: + define('CMAKE_EXE_LINKER_FLAGS:STRING', "-fuse-ld=gold") + define('CMAKE_SHARED_LINKER_FLAGS:STRING', "-fuse-ld=gold") + + define('LLDB_ALLOW_STATIC_BINDINGS:BOOL', True) + define('CMAKE_BUILD_TYPE:STRING', self.args.lldb_build_type) + define('CMAKE_INSTALL_PREFIX:PATH', self.args.install_prefix) + + if len(self.args.lldb_extra_cmake_args) is not None: + options += self.args.lldb_extra_cmake_args + + self.cmake.configure( + source_dir=self.source_dir, + build_dir=self.build_dir, + options=options) + + def build(self): + printf('--- Building LLDB ---') + if host.is_darwin(): + xcodebuild = Xcodebuild() + xcodebuild.build( + project_dir=self.source_dir, + target="desktop", + configuration=self.xcodebuild_config, + action="build", + options=self.xcodebuild_options) + else: + self.cmake.build( + build_dir=self.build_dir, + build_targets=['all', ]) + + def test(self): + if self.deployment_target != self.args.host_target: + return + if self.args.skip_test_lldb: + return + printf('--- Running tests for LLDB ---') + if host.is_darwin(): + lldb_bin_path = os.path.join(self.build_dir, + self.args.lldb_build_type, + "lldb") + else: + lldb_bin_path = os.path.join(self.build_dir, "bin", "lldb") + + results_dir = os.path.join(self.build_dir, 'test-results') + if not os.path.exists(results_dir): + shell.makedirs(results_dir) + + # Handle test results formatter + if self.args.lldb_test_with_curses: + # Setup the curses results formatter. + lldb_formatter_opts = [ + '--results-formatter', + 'lldbsuite.test.curses_results.Curses', + '--results-file', + '/dev/stdout'] + else: + lldb_formatter_opts = [ + '--results-formatter', + 'lldbsuite.test.xunit_formatter.XunitFormatter', + '--results-file', + os.path.join(results_dir, 'results.xml'), + '-O--xpass=ignore'] + + # Setup the xUnit results formatter. + if not host.is_darwin(): + # On non-Darwin, we ignore skipped tests entirely + # so that they don't pollute our xUnit results with + # non-actionable content. + lldb_formatter_opts += [ + '-O-ndsym', '-O-rdebugserver', + r'-O-rlibc\\+\\+', '-O-rlong.running', + '-O-rbenchmarks', '-O-rrequires.one?.of.darwin'] + + # figure out which C/C++ compiler we should use for building test + # inferiors. + if self.args.lldb_test_cc == "host-toolchain": + do_test_cc = self.args.host_cc + elif self.args.lldb_test_cc is not None: + do_test_cc = self.args.lldb_test_cc + else: + do_test_cc = self.llvm_build.clang_bin_path + + test_cmd = [os.path.join(self.source_dir, 'test', 'dotest.py'), ] + test_cmd += ['--executable', lldb_bin_path] + test_cmd += ['--rerun-all-issues'] + test_cmd += ['-C', do_test_cc] + test_cmd += lldb_formatter_opts + + env = [ + ("SWIFTCC", self.swift_build.swiftc_bin_path), + ("SWIFTLIBS", self.swift_build.swiftlib_path)] + + with shell.pushd(results_dir): + shell.invoke(test_cmd, env=env) + + def install(self): + if not self.args.install_lldb: + return + + printf("--- Installing LLDB ---") + if host.is_darwin(): + xcodebuild = Xcodebuild() + install_options = XcodebuildOptions( + # FIXME: We should use self.install_destdir instead. + ("DSTROOT", self.args.install_destdir), + ("LLDB_TOOLCHAIN_PREFIX", self.args.toolchain_prefix)) + xcodebuild.build( + project_dir=self.source_dir, + target="toolchain", + configuration=self.xcodebuild_config, + action="install", + options=self.xcodebuild_options + install_options) + else: + self.cmake.install( + dest_dir=self.install_destdir, + build_dir=self.build_dir) diff --git a/utils-experimental/build-script-impl/build_script/products/llvm.py b/utils-experimental/build-script-impl/build_script/products/llvm.py new file mode 100644 index 0000000000000..1551244d70be6 --- /dev/null +++ b/utils-experimental/build-script-impl/build_script/products/llvm.py @@ -0,0 +1,336 @@ +# build_script/products/llvm.py ---------------------------------*- 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 http://swift.org/LICENSE.txt for license information +# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +# +# ---------------------------------------------------------------------------- +""" +LLVM builder +""" +# ---------------------------------------------------------------------------- + +import os.path + +from .. import targets +from ..host import host +from ..cmake import CMakeOptions +from ..defaults import LLVM_TARGETS_TO_BUILD +from .. import shell +from ..utils import printf +from ..exceptions import BuildError + + +class LLVM(object): + + source_dir = None + clang_source_dir = None + + @classmethod + def prepare(cls, workspace): + cls.source_dir = workspace.subdir('llvm') + if cls.source_dir is None: + raise BuildError("Couldn't find LLVM source directory.") + + # Symlink clang into the llvm tree. + cls.clang_source_dir = os.path.join(cls.source_dir, 'tools', 'clang') + clang_checkout_dir = workspace.subdir('clang', no_exist=True) + if not os.path.exists(cls.clang_source_dir): + if not os.path.exists(clang_checkout_dir): + raise BuildError("Couldn't find clang source directory." + "Tried (%s and %s)" % ( + clang_checkout_dir, + cls.clang_source_dir)) + + printf("Symlink clang source directory to %s", + cls.clang_source_dir) + try: + shell.symlink(clang_checkout_dir, + cls.clang_source_dir, + relative=True) + except Exception: + raise BuildError("Couldn't symlink clang source directory " + "into %s" % cls.clang_source_dir) + + # Symlink compiler-rt into llvm tree if exists + compiler_rt_source_dir = os.path.join( + cls.source_dir, 'projects', 'compiler-rt') + compiler_rt_checkout_dir = workspace.subdir('compiler-rt') + if not os.path.exists(compiler_rt_source_dir): + if compiler_rt_checkout_dir is not None: + try: + shell.symlink(compiler_rt_checkout_dir, + compiler_rt_source_dir, + relative=True) + except OSError: + raise BuildError("Couldn't symlink compiler-rt source " + "directory into %s" % ( + compiler_rt_source_dir)) + + def __init__(self, + deployment_target, + target_build_dir, + target_install_destdir, + host_llvm_build, + cmake, + args): + self.deployment_target = deployment_target + self.build_dir = target_build_dir + self.install_destdir = target_install_destdir + self.host_llvm_build = host_llvm_build + self.cmake = cmake + self.args = args + + @property + def bin_dir(self): + if self.args.cmake_generator == 'Xcode': + return os.path.join(self.build_dir, 'bin', self.llvm_build_type) + else: + return os.path.join(self.build_dir, 'bin') + + @property + def lib_dir(self): + return os.path.join(self.build_dir, 'lib') + + @property + def include_dir(self): + return os.path.join(self.build_dir, 'include') + + @property + def llvm_bin_path(self): + return os.path.join(self.bin_dir, 'llvm') + + @property + def clang_bin_path(self): + return os.path.join(self.bin_dir, 'clang') + + @property + def llvm_config_bin_path(self): + return os.path.join(self.bin_dir, 'llvm-config') + + @property + def llvm_tblgen_bin_path(self): + return os.path.join(self.bin_dir, 'llvm-tblgen') + + @property + def clang_tblgen_bin_path(self): + return os.path.join(self.bin_dir, 'clang-tblgen') + + @property + def filecheck_bin_path(self): + return os.path.join(self.bin_dir, 'FileCheck') + + @property + def lit_bin_path(self): + return os.path.join(self.source_dir, 'utils', 'lit', 'lit.py') + + def _host_triple_target_arch(self): + version_osx = self.args.darwin_deployment_version_osx + version_ios = self.args.darwin_deployment_version_ios + version_tvos = self.args.darwin_deployment_version_tvos + version_watchos = self.args.darwin_deployment_version_watchos + + t = self.deployment_target + if t == 'macosx-x86_64': + return ("x86_64-apple-macosx" + version_osx, None) + if t == 'iphonesimulator-i386': + return ("i386-apple-ios" + version_ios, "X86") + if t == 'iphonesimulator-x86_64': + return ("x86_64-apple-ios" + version_ios, "X86") + if t == 'iphoneos-armv7': + return ("armv7-apple-ios" + version_ios, "ARM") + if t == 'iphoneos-armv7s': + return ("armv7s-apple-ios" + version_ios, "ARM") + if t == 'iphoneos-arm64': + return ("arm64-apple-ios" + version_ios, "AArch64") + if t == 'appletvsimulator-x86_64': + return ("x86_64-apple-tvos" + version_tvos, "X86") + if t == 'appletvos-arm64': + return ("arm64-apple-tvos" + version_tvos, "AArch64") + if t == 'watchsimulator-i386': + return ("i386-apple-watchos" + version_watchos, "X86") + if t == 'watchos-armv7k': + return ("armv7k-apple-watchos" + version_watchos, "ARM") + + raise BuildError("Unknown deployment target") + + def _c_flags(self): + cflags = [] + cflags += self.cmake.common_cross_c_flags(self.deployment_target) + if self.cmake.is_release_build_type(self.args.llvm_build_type): + cflags += ['-fno-stack-protector', ] + return cflags + + def configure(self): + if (not self.args.reconfigure and + self.cmake.is_configured(self.build_dir)): + return + + printf("--- Configuring LLVM/Clang ---") + cmake_options = CMakeOptions() + define = cmake_options.define + + if self.args.use_gold_linker: + define('CMAKE_EXE_LINKER_FLAGS:STRING', "-fuse-ld=gold") + define('CMAKE_SHARED_LINKER_FLAGS:STRING', "-fuse-ld=gold") + + # Note: we set the variable: + # + # LLVM_TOOL_SWIFT_BUILD + # + # below because this script builds swift separately, and people + # often have reasons to symlink the swift directory into + # llvm/tools, e.g. to build LLDB. + cflags = " ".join(self._c_flags()) + define('CMAKE_C_FLAGS', cflags) + define('CMAKE_CXX_FLAGS', cflags) + define('CMAKE_BUILD_TYPE:STRING', self.args.llvm_build_type) + define('LLVM_ENABLE_ASSERTIONS:BOOL', self.args.llvm_enable_assertions) + define('LLVM_TOOL_SWIFT_BUILD:BOOL', False) + define('LLVM_TARGETS_TO_BUILD', LLVM_TARGETS_TO_BUILD) + define('LLVM_INCLUDE_TESTS:BOOL', self.args.source_tree_includes_tests) + define('LLVM_INCLUDE_DOCS:BOOL', True) + + # Darwin specific + if targets.is_darwin_type(self.deployment_target): + (sys, arch) = targets.split(self.deployment_target) + (host_triple, target_arch) = (self._host_triple_target_arch()) + sdk_path = host.sdk_path(sys) + + cmake_osx_deployment_target = ( + self.args.darwin_deployment_version_osx) + if sys != 'macosx': + cmake_osx_deployment_target = "" + + define('CMAKE_OSX_DEPLOYMENT_TARGET', cmake_osx_deployment_target) + define('CMAKE_OSX_SYSROOT:PATH', sdk_path) + define('LLVM_HOST_TRIPLE:STRING', host_triple) + define('LLVM_ENABLE_LIBCXX:BOOL', True) + define('LLVM_TOOL_COMPILER_RT_BUILD:BOOL', + not self.args.skip_compiler_rt) + define('COMPILER_RT_ENABLE_IOS:BOOL', + not self.args.skip_build_ios) + define('COMPILER_RT_ENABLE_WATCHOS:BOOL', False) + define('COMPILER_RT_ENABLE_TVOS:BOOL', False) + + if self.args.llvm_enable_lto: + if self.cmake.needs_to_specify_standard_computed_defaults(): + define('CMAKE_C_STANDARD_COMPUTED_DEFAULT', 'AppleClang') + define('CMAKE_CXX_STANDARD_COMPUTED_DEFAULT', 'AppleClang') + define('CMAKE_C_FLAGS', + '-O2 -gline-tables-only -fno-stack-protector') + define('CMAKE_CXX_FLAGS', + '-O2 -gline-tables-only -fno-stack-protector') + define('CMAKE_C_FLAGS_RELWITHDEBINFO', + '-O2 -gline-tables-only -fno-stack-protector') + define('CMAKE_CXX_FLAGS_RELWITHDEBINFO', + '-O2 -gline-tables-only -fno-stack-protector') + + # Currently with -gline-tables-only clang is ~3.5GB on Darwin. + # Use the formula GB Memory/3.5GB to get the number of parallel + # link threads we can support. + define('LLVM_PARALLEL_LINK_JOBS', + self.cmake.num_parallel_lto_link_jobs(3.5)) + + if target_arch is not None: + define('LLVM_TARGET_ARCH', target_arch) + + # Vender + if self.args.compiler_vendor == 'none': + pass + elif self.args.compiler_vendor == 'apple': + define('CLANG_VENDOR', 'Apple') + define('CLANG_VENDOR_UTI', 'com.apple.compilers.llvm.clang') + define('PACKAGE_VERSION', self.args.clang_user_visible_version) + else: + raise BuildError('unknown compiler vendor') + + # Install prefix + define('CMAKE_INSTALL_PREFIX:PATH', self.args.install_prefix) + define('INTERNAL_INSTALL_PREFIX', 'local') + + if self.args.clang_compiler_version is not None: + define('CLANG_REPOSITORY_STRING', + "clang-%s" % self.args.clang_compiler_version) + + if self.deployment_target != self.args.host_target: + llvm_tblgen = self.host_llvm_build.llvm_tblgen_bin_path + clang_tblgen = self.host_llvm_build.clang_tblgen_bin_path + define('LLVM_TABLEGEN', llvm_tblgen) + define('CLANG_TABLEGEN', clang_tblgen) + + # Do configure + self.cmake.configure( + source_dir=self.source_dir, + build_dir=self.build_dir, + options=cmake_options) + + def build(self): + build_targets = ['all', ] + + if not self.args.build_llvm: + # FIXME: I cannot imagine anyone using `--build-llvm=0` option. + build_targets = ['clean', ] + + if self.args.skip_build_llvm: + # We can't skip the build completely because the standalone + # build of Swift depend on these. + build_targets = ['llvm-config', 'llvm-tblgen', 'clang-headers'] + + config_opts = [] + if self.args.cmake_generator == 'Xcode': + config_opts += [ + '--config', self.args.cmark_build_type] + + # Do build + printf("--- Building LLVM/Clang ---") + self.cmake.build( + build_dir=self.build_dir, + build_targets=build_targets, + config_opts=config_opts) + + # Create symlinks to the c++ headers. + + built_cxx_include_link = os.path.join( + self.build_dir, 'include', 'c++') + + # Find the location of the c++ header dir. + if host.is_darwin(): + host_cxx_dir = os.path.dirname(self.cmake.host_cxx) + host_cxx_headers_dir = os.path.join( + host_cxx_dir, '..', '..', 'usr', 'include', 'c++') + else: + # Linux etc. + host_cxx_headers_dir = os.path.normpath('/usr/include/c++') + + printf("Symlinking the system headers ({0}) into the local " + "clang build directory ({1}).", + host_cxx_headers_dir, built_cxx_include_link) + + try: + if os.path.exists(built_cxx_include_link): + shell.remove(built_cxx_include_link) + shell.symlink(host_cxx_headers_dir, built_cxx_include_link) + except OSError: + raise BuildError("Couldn't symlink clang source " + "directory into %s" % ( + built_cxx_include_link)) + + def test(self): + pass # We don't test LLVM + + def install(self): + if not len(self.args.llvm_install_components): + return + + install_targets = ["install-" + component for component in + self.args.llvm_install_components] + printf("--- Installing LLVM/Clang ---") + self.cmake.install( + build_dir=self.build_dir, + dest_dir=self.install_destdir, + install_targets=install_targets) diff --git a/utils-experimental/build-script-impl/build_script/products/ninja.py b/utils-experimental/build-script-impl/build_script/products/ninja.py new file mode 100644 index 0000000000000..108b2318c3fea --- /dev/null +++ b/utils-experimental/build-script-impl/build_script/products/ninja.py @@ -0,0 +1,79 @@ +# build_script/products/ninja.py --------------------------------*- 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 http://swift.org/LICENSE.txt for license information +# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +# +# ---------------------------------------------------------------------------- +""" +Ninja builder +""" +# ---------------------------------------------------------------------------- + +import os.path + +from ..host import host +from ..exceptions import BuildError +from .. import shell +from ..utils import printf + + +class Ninja(object): + + source_dir = None + + @classmethod + def prepare(cls, workspace): + cls.source_dir = workspace.subdir('ninja') + if cls.source_dir is None: + raise BuildError("Can't find Ninja source directory") + + def __init__(self, deployment_target, target_build_dir, args): + self.deployment_target = deployment_target + self.build_dir = target_build_dir + self.args = args + + @property + def ninja_bin_path(self): + return os.path.join(self.build_dir, 'ninja') + + def configure(self): + if not self.args.reconfigure and os.path.exists(self.ninja_bin_path): + # If we already have a built ninja, we don't need to recompile it. + return + + printf('--- Configuring Ninja ---') + # Ninja can only be built in-tree. + # Copy the source tree to the build directory. + if os.path.exists(self.build_dir): + shell.rmtree(self.build_dir) + + shell.copytree(self.source_dir, self.build_dir, symlinks=True) + + def build(self): + + env = {} + if host.is_darwin(): + macosx_min = ('-mmacosx-version-min=%s' % + self.args.darwin_deployment_version_osx) + cflags = [ + '-isysroot', host.sdk_path('macosx'), macosx_min] + env = [ + ('CXX', host.find_clang_cxx()), + ('CFLAGS', ' '.join(cflags)), + ('LDFLAGS', macosx_min)] + + printf('--- Building Ninja ---') + with shell.pushd(self.build_dir): + shell.invoke(['python', './configure.py', '--bootstrap'], + env=env) + + def test(self): + pass # We don't test Ninja + + def install(self): + pass # We don't install Ninja diff --git a/utils-experimental/build-script-impl/build_script/products/swift.py b/utils-experimental/build-script-impl/build_script/products/swift.py new file mode 100644 index 0000000000000..ffef4787b10b1 --- /dev/null +++ b/utils-experimental/build-script-impl/build_script/products/swift.py @@ -0,0 +1,558 @@ +# build_script/products/swift.py --------------------------------*- 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 http://swift.org/LICENSE.txt for license information +# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +# +# ---------------------------------------------------------------------------- +""" +Swift builder +""" +# ---------------------------------------------------------------------------- + +from __future__ import absolute_import + +import os + +from ..host import host +from ..cmake import CMakeOptions +from .. import targets +from ..exceptions import BuildError +from ..utils import printf + + +class Swift(object): + + source_dir = None + + @classmethod + def prepare(cls, workspace): + cls.source_dir = workspace.subdir('swift') + if cls.source_dir is None: + raise BuildError("Couldn't find Swift source directory.") + + def __init__(self, + deployment_target, + target_build_dir, + target_install_destdir, + cmake, + cmark_build, + llvm_build, + host_llvm_build, + host_swift_build, + args): + self.deployment_target = deployment_target + self.build_dir = target_build_dir + self.install_destdir = target_install_destdir + self.cmake = cmake + self.cmark_build = cmark_build + self.llvm_build = llvm_build + self.host_llvm_build = host_llvm_build + self.host_swift_build = host_swift_build + self.args = args + + # Public property accessors + + @property + def bin_dir(self): + if self.args.cmake_generator == 'Xcode': + return os.path.join(self.build_dir, + 'bin', self.swift_build_type) + else: + return os.path.join(self.build_dir, 'bin') + + @property + def swiftc_bin_path(self): + return os.path.join(self.bin_dir, 'swiftc') + + @property + def swift_bin_path(self): + return os.path.join(self.bin_dir, 'swift') + + @property + def swift_stdlib_tool_source_path(self): + return os.path.join(self.source_dir, + 'utils', 'swift-stdlib-tool-substitute') + + @property + def swiftlib_path(self): + return os.path.join(self.build_dir, 'lib', 'swift') + + # Private utilities + + def stdlib_deployment_targets(self): + ''' + All possible deployment targets where this host can cross compile. + ''' + host_target = host.deployment_target() + sys, arch = targets.split(host_target) + + if sys == 'linux': + return (host_target, "android-armv7", ) + if sys == 'freebsd': + return (host_target, ) + if sys == 'cygwin': + return (host_target, ) + + if sys == 'macosx': + return ( + host_target, + "iphonesimulator-i386", + "iphonesimulator-x86_64", + "appletvsimulator-x86_64", + "watchsimulator-i386", + + # Put iOS native targets last so that we test them last + # (it takes a long time). + "iphoneos-arm64", + "iphoneos-armv7", + "appletvos-arm64", + "watchos-armv7k") + + raise BuildError("Unknown operating system") + + def _stdlib_build_targets(self): + stdlib_targets = [] + benchmark_targets = [] + run_benchmark_targets = [] + test_targets = [] + + stdlib_deployment_targets = self.args.stdlib_deployment_targets + if stdlib_deployment_targets is None: + stdlib_deployment_targets = self.stdlib_deployment_targets() + + for deployment_tgt in stdlib_deployment_targets: + build_for_this_target = True + test_this_target = True + test_host_only = False + build_benchmark_this_target = False + + sys, arch = targets.split(deployment_tgt) + if sys == 'linux': + build_for_this_target = not self.args.skip_build_linux + test_this_target = not self.args.skip_test_linux + elif sys == 'freebsd': + build_for_this_target = not self.args.skip_build_freebsd + test_this_target = not self.args.skip_test_freebsd + elif sys == 'cygwin': + build_for_this_target = not self.args.skip_build_cygwin + test_this_target = not self.args.skip_test_cygwin + elif sys == 'macosx': + build_for_this_target = not self.args.skip_build_osx + test_this_target = not self.args.skip_test_osx + build_benchmark_this_target = build_for_this_target + elif sys == 'iphoneos': + build_for_this_target = not self.args.skip_build_ios_device + if not self.args.skip_test_ios_host: + test_host_only = True + else: + test_this_target = False + build_benchmark_this_target = build_for_this_target + elif sys == 'iphonesimulator': + build_for_this_target = not self.args.skip_build_ios_simulator + test_this_target = not self.args.skip_test_ios_simulator + elif sys == 'appletvos': + build_for_this_target = not self.args.skip_build_tvos_device + if not self.args.skip_test_tvos_host: + test_host_only = True + else: + test_this_target = False + build_benchmark_this_target = build_for_this_target + elif sys == 'appletvsimulator': + build_for_this_target = not self.args.skip_build_tvos_simulator + test_this_target = not self.args.skip_test_tvos_simulator + elif sys == 'watchos': + build_for_this_target = not self.args.skip_build_watchos_device + if not self.args.skip_test_watchos_host: + test_host_only = True + else: + test_this_target = False + build_benchmark_this_target = build_for_this_target + elif sys == 'watchsimulator': + build_for_this_target = ( + not self.args.skip_build_watchos_simulator) + test_this_target = ( + not self.args.skip_test_watchos_simulator) + elif sys == 'android': + build_for_this_target = not self.args.skip_build_android + # FIXME: Allow Android host tests to be enabled/disabled by the + # build script. + test_this_target = False + else: + raise BuildError("Unknown compiler deployment target: " % + deployment_tgt) + + # Build + if build_for_this_target: + if self.args.build_swift_stdlib_unittest_extra: + stdlib_targets += [ + "swift-stdlib-" + deployment_tgt] + elif self.args.skip_test_validation: + stdlib_targets += [ + "swift-test-stdlib-" + deployment_tgt] + else: + stdlib_targets += [ + "swift-stdlib-" + deployment_tgt] + + # Benchmark + if build_benchmark_this_target: + benchmark_targets += ["swift-benchmark-" + deployment_tgt] + if not self.args.skip_test_benchmarks: + run_benchmark_targets += [ + "check-swift-benchmark-" + deployment_tgt] + + # Test + if test_this_target: + test_target_suffix = "" + if test_host_only: + test_target_suffix = "non-executable-" + + def should_optimzed_test(): + return (not self.args.skip_test_optimized and + not test_host_only) + + if self.args.skip_test_validation: + test_targets += [ + "check-swift-" + test_target_suffix + deployment_tgt] + if should_optimzed_test(): + test_targets += [ + "check-swift-optimize-" + deployment_tgt] + else: + test_targets += [ + "check-swift-all-" + + test_target_suffix + deployment_tgt] + if should_optimzed_test(): + test_targets += [ + "check-swift-all-optimize-" + deployment_tgt] + + return (stdlib_targets, + benchmark_targets, + test_targets, + run_benchmark_targets) + + def _host_variants(self, target): + sys, arch = targets.split(target) + if sys == 'iphonesimulator': + return (sys, 'IOS_SIMULATOR', arch) + if sys == 'iphoneos': + return (sys, 'IOS', arch) + if sys == 'appletvsimulator': + return (sys, 'TVOS_SIMULATOR', arch) + if sys == 'appletvos': + return (sys, 'TVOS', arch) + if sys == 'watchsimulator': + return (sys, 'WATCHOS_SIMULATOR', arch) + if sys == 'watchos': + return (sys, 'WATCHOS', arch) + return None + + def _c_flags(self): + cflags = [] + + # Don't pass common_cross_c_flags to Swift because CMake code in the + # Swift project is itself aware of cross-compilation for the host + # tools and standard library. + if self.cmake.is_release_build_type(self.args.llvm_build_type): + cflags += ['-fno-stack-protector', ] + return cflags + + def configure(self): + if (not self.args.reconfigure and + self.cmake.is_configured(self.build_dir)): + return + + printf("--- Configuring Swift ---") + # Configure cmake options + cmake_options = CMakeOptions() + define = cmake_options.define + + if self.args.use_gold_linker: + define('SWIFT_ENABLE_GOLD_LINKER:BOOL', True) + + if not self.args.skip_build_android: + define('SWIFT_ANDROID_NDK_PATH:STRING', + self.args.android_ndk) + define('SWIFT_ANDROID_NDK_TOOLCHAIN_VERSION:STRING', + self.args.android_ndk_toolchain_version) + define('SWIFT_ANDROID_SDK_PATH', + os.path.join(self.args.android_ndk, + 'platforms', + 'android-%s' % self.args.android_ndk_version, + 'arch-arm')) + define('SWIFT_ANDROID_ICU_UC:STRING', + self.args.android_icu_uc) + define('SWIFT_ANDROID_ICU_UC_INCLUDE:STRING', + self.args.android_icu_uc_include) + define('SWIFT_ANDROID_ICU_I18N:STRING', + self.args.android_icu_i18n) + define('SWIFT_ANDROID_ICU_I18N_INCLUDE:STRING', + self.args.android_icu_i18n_include) + + native_llvm_tools_path = None + native_clang_tools_path = None + native_swift_tools_path = None + if self.deployment_target != self.args.host_target: + # Cross tools target + build_benchmark_this_time = False + build_tests_this_time = False + + native_llvm_tools_path = self.host_llvm_build.bin_dir + native_clang_tools_path = self.host_llvm_build.bin_dir + native_swift_tools_path = self.host_swift_build.bin_dir + + define('LLVM_TOOLS_BINARY_DIR:PATH', self.llvm_build.bin_dir) + define('LLVM_LIBRARY_DIR:PATH', self.llvm_build.lib_dir) + define('LLVM_MAIN_INCLUDE_DIR:PATH', self.llvm_build.include_dir) + define('LLVM_BINARY_DIR:PATH', self.llvm_build.build_dir) + define('LLVM_MAIN_SRC_DIR:PATH', self.llvm_build.source_dir) + else: + # Host target + build_benchmark_this_time = not self.args.skip_build_benchmarks + build_tests_this_time = self.args.source_tree_includes_tests + + # Command-line parameters override any autodetection that we + # might have done. + if self.args.native_llvm_tools_path is not None: + native_llvm_tools_path = self.args.native_llvm_tools_path + if self.args.native_clang_tools_path is not None: + native_clang_tools_path = self.args.native_clang_tools_path + if self.args.native_swift_tools_path is not None: + native_swift_tools_path = self.args.native_swift_tools_path + + if not self.args.build_llvm: + define("LLVM_TOOLS_BINARY_DIR:PATH", "/tmp/dummy") + define("LLVM_LIBRARY_DIR:PATH", self.build_dir) + define("LLVM_MAIN_INCLUDE_DIR:PATH", "/tmp/dummy") + define("LLVM_BINARY_DIR:PATH", self.llvm_build.build_dir) + define("LLVM_MAIN_SRC_DIR:PATH", self.llvm_build.source_dir) + + define("CMAKE_C_FLAGS", " ".join(self._c_flags())) + define("CMAKE_CXX_FLAGS", " ".join(self._c_flags())) + define("CMAKE_BUILD_TYPE:STRING", self.args.llvm_build_type) + define("LLVM_ENABLE_ASSERTIONS:BOOL", + self.args.swift_enable_assertions) + define("SWIFT_ANALYZE_CODE_COVERAGE:STRING", + self.args.swift_analyze_code_coverage.upper()) + define("SWIFT_STDLIB_BUILD_TYPE:STRING", + self.args.swift_stdlib_build_type) + define("SWIFT_STDLIB_ASSERTIONS:BOOL", + self.args.swift_stdlib_enable_assertions) + define("SWIFT_STDLIB_ENABLE_REFLECTION_METADATA:BOOL", + self.args.swift_stdlib_enable_reflection_metadata) + define("SWIFT_STDLIB_ENABLE_RESILIENCE:BOOL", + self.args.swift_stdlib_enable_resilience) + define("SWIFT_STDLIB_SIL_SERIALIZE_ALL:BOOL", + self.args.swift_stdlib_sil_serialize_all) + define("SWIFT_NATIVE_LLVM_TOOLS_PATH:STRING", + native_llvm_tools_path) + define("SWIFT_NATIVE_CLANG_TOOLS_PATH:STRING", + native_clang_tools_path) + define("SWIFT_NATIVE_SWIFT_TOOLS_PATH:STRING", + native_swift_tools_path) + define("SWIFT_BUILD_TOOLS:BOOL", + self.args.build_swift_tools) + define("SWIFT_BUILD_STDLIB:BOOL", + self.args.build_swift_stdlib) + define("SWIFT_SERIALIZE_STDLIB_UNITTEST:BOOL", + self.args.build_serialized_stdlib_unittest) + define("SWIFT_STDLIB_SIL_DEBUGGING:BOOL", + self.args.build_sil_debugging_stdlib) + define("SWIFT_BUILD_SDK_OVERLAY:BOOL", + self.args.build_swift_sdk_overlay) + define("SWIFT_BUILD_STATIC_STDLIB:BOOL", + self.args.build_swift_static_stdlib) + define("SWIFT_BUILD_PERF_TESTSUITE:BOOL", + build_benchmark_this_time) + define("SWIFT_BUILD_EXAMPLES:BOOL", + self.args.build_swift_examples) + define("SWIFT_INCLUDE_TESTS:BOOL", + build_tests_this_time) + define("SWIFT_INSTALL_COMPONENTS:STRING", + ";".join(self.args.swift_install_components)) + define("SWIFT_EMBED_BITCODE_SECTION:BOOL", + self.args.embed_bitcode_section) + define("SWIFT_ENABLE_LTO:BOOL", + self.args.swift_enable_lto) + define("SWIFT_BUILD_RUNTIME_WITH_HOST_COMPILER:BOOL", + self.args.build_runtime_with_host_compiler) + + # deployment target based options + host_variant_opts = self._host_variants(self.deployment_target) + if host_variant_opts is not None: + (variant, variant_sdk, variant_arch) = host_variant_opts + define('SWIFT_HOST_VARIANT', variant) + define('SWIFT_HOST_VARIANT_SDK', variant_sdk) + define('SWIFT_HOST_VARIANT_ARCH', variant_arch) + + if targets.is_darwin_type(self.deployment_target): + if self.args.swift_enable_lto: + if self.cmake.needs_to_specify_standard_computed_defaults: + define("CMAKE_C_STANDARD_COMPUTED_DEFAULT", "AppleClang") + define("CMAKE_CXX_STANDARD_COMPUTED_DEFAULT", "AppleClang") + + # Currently with -gline-tables-only swift is ~5-6GB on + # Darwin. Use the formula GB Memory/6GB to get the number + # of parallel link threads we can support. + define("SWIFT_PARALLEL_LINK_JOBS", + self.cmake.num_parallel_lto_link_jobs(6.0)) + + define("SWIFT_DARWIN_DEPLOYMENT_VERSION_OSX", + self.args.darwin_deployment_version_osx) + define("SWIFT_DARWIN_DEPLOYMENT_VERSION_IOS", + self.args.darwin_deployment_version_ios) + define("SWIFT_DARWIN_DEPLOYMENT_VERSION_TVOS", + self.args.darwin_deployment_version_tvos) + define("SWIFT_DARWIN_DEPLOYMENT_VERSION_WATCHOS", + self.args.darwin_deployment_version_watchos) + define("LLVM_ENABLE_LIBCXX:BOOL", True) + + if self.args.compiler_vendor == "none": + pass + elif self.args.compiler_vendor == "apple": + define("SWIFT_VENDOR", "Apple") + define("SWIFT_VENDOR_UTI", "com.apple.compilers.llvm.swift") + define("SWIFT_VERSION", self.args.swift_user_visible_version) + define("SWIFT_COMPILER_VERSION", self.args.swift_compiler_version) + else: + raise BuildError("unknown compiler vendor") + + clang_compiler_version = self.args.clang_compiler_version + swift_compiler_version = self.args.swift_compiler_version + if swift_compiler_version is None: + swift_compiler_version = clang_compiler_version + if clang_compiler_version is not None: + define("CLANG_COMPILER_VERSION", clang_compiler_version) + define("SWIFT_COMPILER_VERSION", swift_compiler_version) + + if self.args.darwin_toolchain_version is not None: + define("DARWIN_TOOLCHAIN_VERSION", + self.args.darwin_toolchain_version), + + if self.args.enable_asan is not None: + define("SWIFT_SOURCEKIT_USE_INPROC_LIBRARY:BOOL", True) + + if self.args.darwin_crash_reporter_client: + define("SWIFT_RUNTIME_CRASH_REPORTER_CLIENT:BOOL", True) + + define("SWIFT_DARWIN_XCRUN_TOOLCHAIN:STRING", + self.args.darwin_xcrun_toolchain) + + if self.args.darwin_stdlib_install_name_dir: + define("SWIFT_DARWIN_STDLIB_INSTALL_NAME_DIR:STRING", + self.args.darwin_stdlib_install_name_dir) + + if len(self.args.extra_swift_args): + define('SWIFT_EXPERIMENTAL_EXTRA_REGEXP_FLAGS', + self.args.extra_swift_args) + + define("SWIFT_AST_VERIFIER:BOOL", self.args.swift_enable_ast_verifier) + define("SWIFT_SIL_VERIFY_ALL:BOOL", self.args.sil_verify_all) + define("SWIFT_RUNTIME_ENABLE_LEAK_CHECKER:BOOL", + self.args.swift_runtime_enable_leak_checker) + + define("CMAKE_INSTALL_PREFIX:PATH", self.args.install_prefix) + define("LLVM_CONFIG:PATH", self.llvm_build.llvm_config_bin_path) + define("SWIFT_PATH_TO_CLANG_SOURCE:PATH", + self.llvm_build.clang_source_dir) + define("SWIFT_PATH_TO_CLANG_BUILD:PATH", self.llvm_build.build_dir) + define("SWIFT_PATH_TO_LLVM_SOURCE:PATH", self.llvm_build.source_dir) + define("SWIFT_PATH_TO_LLVM_BUILD:PATH", self.llvm_build.build_dir) + define("SWIFT_PATH_TO_CMARK_SOURCE:PATH", self.cmark_build.source_dir) + define("SWIFT_PATH_TO_CMARK_BUILD:PATH", self.cmark_build.build_dir) + define('SWIFT_CMARK_LIBRARY_DIR:PATH', self.cmark_build.library_dir) + + if self.args.swift_sdks: + define("SWIFT_SDKS:STRING", self.args.swift_sdks) + + if self.args.swift_primary_variant_sdk: + define("SWIFT_PRIMARY_VARIANT_SDK:STRING", + self.args.swift_primary_variant_sdk) + define("SWIFT_PRIMARY_VARIANT_ARCH:STRING", + self.args.swift_primary_variant_arch) + + if build_benchmark_this_time: + define("SWIFT_EXEC:STRING", self.swiftc_bin_path) + + self.cmake.configure( + source_dir=self.source_dir, + build_dir=self.build_dir, + options=cmake_options) + + def _cmake_config_opts(self): + config_opts = [] + if self.args.cmake_generator == 'Xcode': + config_opts += [ + '--config', self.args.swift_build_type] + return config_opts + + def build(self): + if self.args.skip_build_swift: + return + + printf("--- Building Swift ---") + + (stdlib_build_targets, + benchmark_build_targets, + _, _) = self._stdlib_build_targets() + + build_targets = ["all", ] + build_targets += stdlib_build_targets + + build_benchmark_this_time = ( + self.deployment_target == self.args.host_target and + not self.args.skip_build_benchmarks) + if build_benchmark_this_time: + build_targets += benchmark_build_targets + + self.cmake.build( + build_targets=build_targets, + build_dir=self.build_dir, + config_opts=self._cmake_config_opts()) + + def test(self): + if self.deployment_target != self.args.host_target: + return + + (_, _, + test_targets, + run_benchmark_targets) = self._stdlib_build_targets() + + executable_targets = [] + results_targets = [] + + if not self.args.skip_test_swift: + executable_targets += ['SwiftUnitTests', ] + results_targets += test_targets + if self.args.stress_test_sourcekit: + results_targets += ['stress-SourceKit', ] + if not self.args.skip_test_benchmarks: + results_targets += run_benchmark_targets + + if not len(results_targets): + # Nothing to test + return + + printf("--- Building tests for Swift ---") + self.cmake.build( + build_targets=executable_targets, + build_dir=self.build_dir, + config_opts=self._cmake_config_opts()) + + printf("--- Running tests for Swift ---") + self.cmake.test( + test_targets=results_targets, + build_dir=self.build_dir, + config_opts=self._cmake_config_opts()) + + def install(self): + if not self.args.install_swift: + return + + printf("--- Installing Swift ---") + self.cmake.install( + dest_dir=self.install_destdir, + build_dir=self.build_dir) diff --git a/utils-experimental/build-script-impl/build_script/products/swiftpm.py b/utils-experimental/build-script-impl/build_script/products/swiftpm.py new file mode 100644 index 0000000000000..fad6301f0a6fe --- /dev/null +++ b/utils-experimental/build-script-impl/build_script/products/swiftpm.py @@ -0,0 +1,103 @@ +# build_script/products/swiftpm.py ------------------------------*- 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 http://swift.org/LICENSE.txt for license information +# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +# +# ---------------------------------------------------------------------------- +""" +Swift Package Manager builder +""" +# ---------------------------------------------------------------------------- + +from __future__ import absolute_import + +import os.path + +from .. import shell +from ..exceptions import BuildError +from ..host import host +from ..utils import printf + + +# FIXME: consider cross tools deployment targets +class SwiftPM(object): + source_dir = None + + @classmethod + def prepare(cls, workspace): + cls.source_dir = workspace.subdir('swiftpm') + if cls.source_dir is None: + raise BuildError("Couldn't find swiftpm source directory.") + + def __init__(self, + deployment_target, + target_build_dir, + target_install_destdir, + swift_build, + llbuild_build, + foundation_build, + xctest_build, + args): + self.deployment_target = deployment_target + self.build_dir = target_build_dir + self.install_destdir = target_install_destdir + + self.swift_build = swift_build + self.llbuild_build = llbuild_build + self.foundation_build = foundation_build + self.xctest_build = xctest_build + + self.args = args + + def configure(self): + printf("--- Configuring Swift Package Manager ---") + if self.llbuild_build is None: + raise RuntimeError( + "Error: Cannot build swiftpm without llbuild" + " (swift-build-tool).") + + def bootstrap_command(self): + build_cmd = [os.path.join(self.source_dir, 'Utilities', 'bootstrap')] + + if self.deployment_target == 'macosx-x86_64': + build_cmd += ['--sysroot=' + host.sdk_path("macosx"), ] + if self.args.verbose_build: + build_cmd += ["-v", ] + build_cmd += [ + "--swiftc=" + self.swift_build.swiftc_bin_path, + "--sbt=" + self.llbuild_build.swift_build_tool_bin_path, + "--build=" + self.build_dir] + + if self.foundation_build and self.xctest_build: + build_cmd += [ + "--foundation=" + self.foundation_build.foundation_path, + "--xctest=" + self.xctest_build.build_dir] + return build_cmd + + def build(self): + printf("--- Building Swift Package Manager ---") + shell.invoke(self.bootstrap_command()) + + def test(self): + if self.deployment_target != self.args.host_target: + return + if self.args.skip_test_swiftpm: + return + printf("--- Running tests for Swift Package Manager ---") + shell.invoke(self.bootstrap_command() + ["test", ]) + + def install(self): + if not self.args.install_swiftpm: + return + printf("--- Installing Swift Package Manager ---") + + # FIXME: We should use self.install_destdir instead. + prefix = os.path.join(self.args.install_destdir, + self.args.install_prefix.lstrip('/')) + shell.invoke(self.bootstrap_command() + ["--prefix=" + prefix, + "install"]) diff --git a/utils-experimental/build-script-impl/build_script/products/xctest.py b/utils-experimental/build-script-impl/build_script/products/xctest.py new file mode 100644 index 0000000000000..b685628f484a0 --- /dev/null +++ b/utils-experimental/build-script-impl/build_script/products/xctest.py @@ -0,0 +1,160 @@ +# build_script/products/xctest.py -------------------------------*- 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 http://swift.org/LICENSE.txt for license information +# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +# +# ---------------------------------------------------------------------------- +""" +XCTest builder +""" +# ---------------------------------------------------------------------------- + +from __future__ import absolute_import + +import os.path + +from .. import targets +from .. import shell +from .. import swift_utils +from ..host import host +from ..exceptions import BuildError +from ..xcodebuild import Xcodebuild, XcodebuildOptions +from ..utils import printf + + +class XCTest(object): + + source_dir = None + + @classmethod + def prepare(cls, workspace): + cls.source_dir = workspace.subdir('swift-corelibs-xctest') + if cls.source_dir is None: + raise BuildError("Couldn't find XCTest source directory.") + + def __init__(self, + deployment_target, + target_build_dir, + target_install_destdir, + swift_build, + foundation_build, + args): + self.deployment_target = deployment_target + self.build_dir = target_build_dir + self.install_destdir = target_install_destdir + + self.swift_build = swift_build + self.foundation_build = foundation_build + + self.args = args + + def configure(self): + pass # XCTest has no configuration + + def build(self): + printf("--- Building XCTest ---") + + if host.is_darwin(): + xcodebuild_options = XcodebuildOptions() + define = xcodebuild_options.define + define('SWIFT_EXEC', self.swift_build.swiftc_bin_path) + define('SWIFT_LINK_OBJC_RUNTIME', 'YES') + define('SYMROOT', self.build_dir) + define('OBJROOT', self.build_dir) + + # xcodebuild requires swift-stdlib-tool to build a Swift + # framework. This is normally present when building XCTest + # via a packaged .xctoolchain, but here we are using the + # swiftc that was just built--no toolchain exists yet. As a + # result, we must copy swift-stdlib-tool ourselves. + swift_stdlib_tool_path = os.path.join( + self.swift_build.bin_dir, 'swift-stdlib-tool') + if not os.path.exists(swift_stdlib_tool_path): + # FIXME: What if substitute source has changed? + shell.copy( + swift_utils('swift-stdlib-tool-substitute'), + swift_stdlib_tool_path) + + xcodebuild = Xcodebuild() + xcodebuild.build_workspace( + workspace=os.path.join(self.source_dir, 'XCTest.xcworkspace'), + scheme="SwiftXCTest", + options=xcodebuild_options) + else: + foundation_path = self.foundation_build.foundation_path + command = [os.path.join(self.source_dir, 'build_script.py')] + command += [ + '--swiftc=' + self.swift_build.swiftc_bin_path, + '--build-dir=' + self.build_dir, + '--foundation-build-dir=' + foundation_path] + shell.invoke(command) + + def test(self): + if self.deployment_target != self.args.host_target: + return + if self.args.skip_test_xctest: + return + + printf("--- Running tests for XCTest ---") + if host.is_darwin(): + xcodebuild_options = XcodebuildOptions() + define = xcodebuild_options.define + define('SWIFT_EXEC', self.swift_build.swiftc_bin_path) + define('SWIFT_LINK_OBJC_RUNTIME', 'YES') + define('SYMROOT', self.build_dir) + define('OBJROOT', self.build_dir) + + xcodebuild = Xcodebuild() + xcodebuild.build_workspace( + workspace=os.path.join(self.source_dir, 'XCTest.xcworkspace'), + scheme="SwiftXCTestFunctionalTests", + options=xcodebuild_options) + else: + foundation_path = self.foundation_build.foundation_path + command = [os.path.join(self.source_dir, 'build_script.py'), + "test"] + command += [ + '--swiftc=' + self.swift_build.swiftc_bin_path, + '--foundation-build-dir=' + foundation_path, + self.build_dir] + shell.invoke(command) + + def install(self): + if not self.args.install_xctest: + return + + printf("--- Installing XCTest ---") + if host.is_linux(): + lib_target = "linux" + elif host.is_freebsd(): + lib_target = "freebsd" + elif host.is_cygwin(): + lib_target = "windows" + else: + raise BuildError( + "--install-xctest is not supported on this platform") + + install_prefix = os.path.join( + # FIXME: We should use self.install_destdir instead. + self.args.install_destdir, + # strip leading '/' because join('/foo', '/bar') results '/bar' + self.args.install_prefix.lstrip('/'), + 'lib', 'swift', lib_target) + + module_install_prefix = os.path.join( + install_prefix, + targets.split(self.deployment_target)[1]) + + command = [os.path.join(self.source_dir, 'build_script.py'), + "install"] + command += [ + '--library-install-path=' + install_prefix, + '--module-install-path=' + module_install_prefix, + self.build_dir] + + shell.invoke(command) diff --git a/utils-experimental/build-script-impl/build_script/shell.py b/utils-experimental/build-script-impl/build_script/shell.py new file mode 100644 index 0000000000000..31b3b12d482d1 --- /dev/null +++ b/utils-experimental/build-script-impl/build_script/shell.py @@ -0,0 +1,92 @@ +# build_script/shell.py -----------------------------------------*- 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 http://swift.org/LICENSE.txt for license information +# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +# +# ---------------------------------------------------------------------------- +""" +Centralized command line and file system interface for the build script. +""" +# ---------------------------------------------------------------------------- + +from __future__ import absolute_import + +import os +import subprocess + +from . import _shell + +echo = True +dry_run = False + +# FIXME: I hate this kind of silent mode change. +os.umask(0o022) + + +def query(args, env=None, echo_=None, stderr=subprocess.PIPE): + if echo_ is not None: + do_echo = echo_ + else: + do_echo = echo + return _shell.query(args, env=env, stderr=stderr, + echo=do_echo) + + +def execv(args): + _shell.execv(args, + echo=echo, dry_run=dry_run) + + +def invoke(args, env=None): + _shell.invoke(args, env=env, + echo=echo, dry_run=dry_run) + + +def runscript(script, env=None, ignore_errors=False): + _shell.runscript(script, env=env, ignore_errors=ignore_errors, + echo=echo, dry_run=dry_run) + + +def copy(src, dst): + _shell.copy(src, dst, + echo=echo, dry_run=dry_run) + + +def symlink(source, link_name, relative=False): + _shell.symlink(source, link_name, relative=relative, + echo=echo, dry_run=dry_run) + + +def remove(path): + _shell.remove(path, + echo=echo, dry_run=dry_run) + + +def makedirs(directory): + _shell.makedirs(directory, + echo=echo, dry_run=dry_run) + + +def rmtree(path): + _shell.rmtree(path, + echo=echo, dry_run=dry_run) + + +def copytree(src, dst, symlinks=False): + _shell.copytree(src, dst, symlink, + echo=echo, dry_run=dry_run) + + +def pushd(path): + return _shell.pushd(path, + echo=echo, dry_run=dry_run) + + +def chdir(path): + _shell.chdir(path, + echo=echo, dry_run=dry_run) diff --git a/utils-experimental/build-script-impl/build_script/swift_utils.py b/utils-experimental/build-script-impl/build_script/swift_utils.py new file mode 100644 index 0000000000000..ad80f747196af --- /dev/null +++ b/utils-experimental/build-script-impl/build_script/swift_utils.py @@ -0,0 +1,35 @@ +# build_script/swift_utils.py -----------------------------------*- 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 http://swift.org/LICENSE.txt for license information +# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +# +# ---------------------------------------------------------------------------- +""" +Provides utility scripts path in swift/utils +""" +# ---------------------------------------------------------------------------- + +from __future__ import absolute_import + +import sys +import os.path + +from . import env + + +class SwiftUtils(object): + def __init__(self): + self.basedir = os.path.join(env.SWIFT_SOURCE_ROOT, 'swift', 'utils') + + def __call__(self, name): + import os.path # Because callable module hack hides module global. + return os.path.join(self.basedir, name) + +# This is a callable module. +# http://stackoverflow.com/a/1060872/3804019 +sys.modules[__name__] = SwiftUtils() diff --git a/utils-experimental/build-script-impl/build_script/targets.py b/utils-experimental/build-script-impl/build_script/targets.py new file mode 100644 index 0000000000000..cdb45fffc3992 --- /dev/null +++ b/utils-experimental/build-script-impl/build_script/targets.py @@ -0,0 +1,43 @@ +# build_script/targets.py ---------------------------------------*- 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 http://swift.org/LICENSE.txt for license information +# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +# +# ---------------------------------------------------------------------------- +""" +Utility functions for deployment targets +""" +# ---------------------------------------------------------------------------- + +from __future__ import absolute_import + + +def split(target): + res = target.split('-', 1) + if len(res) != 2: + res = (res[0], None) + return tuple(res) + + +def is_darwin_type(target): + sys, _ = split(target) + return sys in [ + 'macosx', + 'iphoneos', 'iphonesimulator', + 'appletvos', 'appletvsimulator', + 'watchos', 'watchsimulator'] + + +def is_osx(target): + sys, _ = split(target) + return sys == 'macosx' + + +def xcrun_sdk_name(target): + sys, _ = split(target) + return sys diff --git a/utils-experimental/build-script-impl/build_script/utils/__init__.py b/utils-experimental/build-script-impl/build_script/utils/__init__.py new file mode 100644 index 0000000000000..923d4770b9b73 --- /dev/null +++ b/utils-experimental/build-script-impl/build_script/utils/__init__.py @@ -0,0 +1,30 @@ +# build_script/utils/__init__.py --------------------------------*- 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 http://swift.org/LICENSE.txt for license information +# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +# +# ---------------------------------------------------------------------------- +""" +Utilities independent from Swift +""" +# ---------------------------------------------------------------------------- + +from __future__ import absolute_import + +from .which import which +from .cached_property import CachedProperty +from .printf import printf, printf_with_argv0 +from .argparser_builder import ArgParserBuilder + +__all__ = [ + "which", + "printf", + "printf_with_argv0", + "CachedProperty", + "ArgParserBuilder", +] diff --git a/utils-experimental/build-script-impl/build_script/utils/argparser_builder.py b/utils-experimental/build-script-impl/build_script/utils/argparser_builder.py new file mode 100644 index 0000000000000..39b070ed8683b --- /dev/null +++ b/utils-experimental/build-script-impl/build_script/utils/argparser_builder.py @@ -0,0 +1,250 @@ +# build_script/utils/argparser_builder.py -----------------------*- 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 http://swift.org/LICENSE.txt for license information +# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +# +# ---------------------------------------------------------------------------- +""" +DSL like argparse.ArgumentParser builder +""" +# ---------------------------------------------------------------------------- + +from __future__ import absolute_import + +from contextlib import contextmanager +import argparse + + +class _MultiDestinationAction(argparse.Action): + '''Action that can have multiple destinations. + ''' + def __init__(self, dests=None, **kwargs): + + if dests is None: + pass + elif isinstance(dests, str): + kwargs['dest'] = dests + dests = None + else: + # So that the default value not set to the inferred dest name. + kwargs['dest'] = argparse.SUPPRESS + + super(_MultiDestinationAction, self).__init__(**kwargs) + self.destgroup = dests + + def dests(self): + dests = self.destgroup + if dests is None: + dests = [self.dest, ] + return dests + + def __call__(self, parser, namespace, values, option_string=None): + for dest in self.dests(): + setattr(namespace, dest, values) + + +class _OnOffAction(_MultiDestinationAction): + def __init__(self, **kwargs): + assert 'choices' in kwargs + if 'metavar' not in kwargs: + kwargs['metavar'] = "BOOL" + self._vals = kwargs.pop('choices') + kwargs['nargs'] = '?' + super(_OnOffAction, self).__init__(**kwargs) + + def __call__(self, parser, namespace, values, option_string=None): + if values is None: + val = self._vals[0] + elif values not in ['0', 'FALSE', 'False', 'false', 0, False]: + val = self._vals[0] + else: + val = self._vals[1] + super(_OnOffAction, self).__call__( + parser, namespace, val, option_string=None) + + +class _EnableAction(_OnOffAction): + def __init__(self, **kwargs): + kwargs['choices'] = [True, False] + kwargs['default'] = kwargs.get('default', False) + super(_EnableAction, self).__init__(**kwargs) + + +class _DisableAction(_OnOffAction): + def __init__(self, **kwargs): + kwargs['choices'] = [False, True] + kwargs['default'] = kwargs.get('default', True) + super(_DisableAction, self).__init__(**kwargs) + + +class _AppendAction(_MultiDestinationAction): + '''Action that append specified string to a list. + ''' + + def __init__(self, join=None, separator=None, **kwargs): + kwargs['nargs'] = None + if kwargs.get('default', None) is None: + if join is not None: + kwargs['default'] = "" + else: + kwargs['default'] = () + super(_AppendAction, self).__init__(**kwargs) + + self.join = join + self.separator = separator + + def __call__(self, parser, namespace, values, option_string=None): + if self.separator is not None: + values = values.split(self.separator) + else: + values = [values, ] + + if self.join is not None: + append = (self.join).join(values) + else: + append = tuple(values) + + for dest in self.dests(): + value = getattr(namespace, dest) + if len(value) and self.join is not None: + value = value + self.join + value = value + append + setattr(namespace, dest, value) + + +class _SetAction(_MultiDestinationAction): + '''Action that set an string value, or arbitrary constant. + ''' + + def __init__(self, **kwargs): + kwargs['const'] = kwargs.get('as_', kwargs.get('const', None)) + super(_SetAction, self).__init__(**kwargs) + if kwargs['const'] is not None: + self.nargs = 0 + + def __call__(self, parser, namespace, value, option_string=None): + if self.const is not None: + value = self.const + super(_SetAction, self).__call__( + parser, namespace, value, option_string=None) + + +class _CompoundAction(argparse.Action): + '''Action containing multiple actions. + ''' + def __init__(self, actions, **kwargs): + _actions = [] + for a in actions: + _actions.append(a(**kwargs)) + + if 'nargs' not in kwargs: + kwargs['nargs'] = _actions[0].nargs + if 'metavar' not in kwargs: + kwargs['metavar'] = _actions[0].metavar + if 'choices' not in kwargs: + kwargs['choices'] = _actions[0].choices + + super(_CompoundAction, self).__init__(**kwargs) + self.actions = _actions + # Compound action should not have default inferred dest. + self.dest = argparse.SUPPRESS + + def __call__(self, *args): + for action in self.actions: + action(*args) + + +class _action_partial(object): + '''Partial to make option(flag, act) and option(flag, act()) equivalent. + ''' + def __init__(self, action): + self.action = action + + def __call__(self, dests=None, **kwargs): + def factory(*args, **argparse_kwargs): + argparse_kwargs.update(kwargs) # Innner kwargs are stronger. + return self.action(*args, dests=dests, **argparse_kwargs) + return factory + + +class ArgParserBuilder(object): + '''DSL like custom ArgParser builder. + ''' + + def __init__(self, **kwargs): + self._parser = argparse.ArgumentParser(**kwargs) + self._current_group = self._parser + self._defaults = {} + + self.enable_action = _action_partial(_EnableAction) + self.disable_action = _action_partial(_DisableAction) + self.set_action = _action_partial(_SetAction) + self.append_action = _action_partial(_AppendAction) + + def build(self): + self._parser.set_defaults(**self._defaults) + return self._parser + + def add_option(self, names, *actions, **kwargs): + + if isinstance(names, str): + names = [names, ] + + assert all(name.startswith("-") for name in names), ( + "add_option can't add positional arguments") + + # Unwrap partial actions. + _actions = [] + for act in actions: + if isinstance(act, _action_partial): + act = act() + _actions.append(act) + actions = _actions + + if len(actions) == 0: + # add_option(name) -- equivalents to option(name, set_()) + action = _SetAction + elif len(actions) == 1: + # option(name, action) + action = actions[0] + else: + def factory(*args, **kwargs): + kwargs['actions'] = actions + return _CompoundAction(*args, **kwargs) + action = factory + + self._current_group.add_argument(*names, action=action, **kwargs) + + def in_group(self, description): + self._current_group = self._parser.add_argument_group(description) + + def reset_group(self): + self._current_group = self._parser + + @contextmanager + def mutually_exclusive_group(self): + old = self._current_group + self._current_group = old.add_mutually_exclusive_group() + yield + self._current_group = old + + def set_defaults(self, *args, **kwargs): + if len(args): + assert len(args) == 2, "Invalid set_default argument." + (names, default_value) = args + if isinstance(names, str): + names = [names, ] + for name in names: + kwargs[name] = default_value + + # Defaults will be added to the parser at build() time. + self._defaults.update(kwargs) + + def add_positional_argument(self, dest, **kwargs): + self._current_group.add_argument( + dest, **kwargs) diff --git a/utils-experimental/build-script-impl/build_script/utils/cached_property.py b/utils-experimental/build-script-impl/build_script/utils/cached_property.py new file mode 100644 index 0000000000000..ced484355de8b --- /dev/null +++ b/utils-experimental/build-script-impl/build_script/utils/cached_property.py @@ -0,0 +1,42 @@ +# build_script/utils/cached_property.py -------------------------*- 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 http://swift.org/LICENSE.txt for license information +# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +# +# ---------------------------------------------------------------------------- +""" +Cached property decorator +""" +# ---------------------------------------------------------------------------- + +from __future__ import absolute_import + + +class CachedProperty(object): + """Decorator that lazy-loads the value of a property. + + The first time the property is accessed, the original property function is + executed. The value it returns is set as the new value of that instance's + property, replacing the original method. + """ + + def __init__(self, wrapped): + self.wrapped = wrapped + try: + self.__doc__ = wrapped.__doc__ + except AttributeError: + pass + + def __get__(self, instance, instance_type=None): + if instance is None: + return self + + value = self.wrapped(instance) + setattr(instance, self.wrapped.__name__, value) + + return value diff --git a/utils-experimental/build-script-impl/build_script/utils/printf.py b/utils-experimental/build-script-impl/build_script/utils/printf.py new file mode 100644 index 0000000000000..f5570b5560899 --- /dev/null +++ b/utils-experimental/build-script-impl/build_script/utils/printf.py @@ -0,0 +1,35 @@ +# build_script/utils/printf.py ----------------------------------*- 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 http://swift.org/LICENSE.txt for license information +# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +# +# ---------------------------------------------------------------------------- +""" +Rough printf. Flush immediately. +""" +# ---------------------------------------------------------------------------- + +from __future__ import absolute_import +from __future__ import print_function + +import sys + +__all__ = [ + 'printf', + 'printf_with_argv0', +] + + +def printf(message, *args, **kwargs): + print(message.format(*args, **kwargs)) + # Flush everytime to prevent mixed output with sub commands. + sys.stdout.flush() + + +def printf_with_argv0(message, *args, **kwargs): + printf(sys.argv[0] + ": " + message, *args, **kwargs) diff --git a/utils-experimental/build-script-impl/build_script/utils/which.py b/utils-experimental/build-script-impl/build_script/utils/which.py new file mode 100644 index 0000000000000..4b78db2894055 --- /dev/null +++ b/utils-experimental/build-script-impl/build_script/utils/which.py @@ -0,0 +1,73 @@ +# utils/which.py ------------------------------------------------*- 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 http://swift.org/LICENSE.txt for license information +# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +# +# ---------------------------------------------------------------------------- +""" +A rough implementation of shutil.which() for Python 2.7 + +This can be removed if the Swift build toolchain migrates completely to +Python 3.3+. +""" +# ---------------------------------------------------------------------------- + +from __future__ import absolute_import + +import sys +import os +import os.path + + +def _uniq_list(list_): + '''\ + Return a list of unique elements from given list. Unlike + `list(set(someList))`, this function keeps the order of original elements. + + >>> ary = [3,5,1,3,2,1,2] + >>> _uniq_list(ary) + [3,5,1,2] + >>> ary = _uniq_list(reverse(ary)) + [2,1,3,5] + ''' + output = [] + for item in list_: + if item not in output: + output.append(item) + return output + + +def which(cmd): + '''\ + Find and return the path to an executable from system executable paths. + If not found return `None`. + + >>> which('a-tool-that-doesnt-exist') + None + >>> lspath = which('ls') + >>> os.path.split(lspath)[0] == 'ls' + True + ''' + path = os.environ.get("PATH", os.defpath).split(os.pathsep) + path = _uniq_list(os.path.realpath(p) for p in path) + + if sys.platform == 'win32': + pathext = os.environ.get("PATHEXT", "").split(os.pathsep) + cmds = [cmd + ext for ext in pathext] + else: + cmds = [cmd] + + for dir in path: + for cmd in cmds: + cmdpath = os.path.join(dir, cmd) + is_executable = (os.path.exists(cmdpath) and + not os.path.isdir(cmdpath) and + os.access(cmdpath, os.X_OK)) + if is_executable: + return cmdpath + return None diff --git a/utils-experimental/build-script-impl/build_script/workspace.py b/utils-experimental/build-script-impl/build_script/workspace.py new file mode 100644 index 0000000000000..c58a6c7d0fec1 --- /dev/null +++ b/utils-experimental/build-script-impl/build_script/workspace.py @@ -0,0 +1,54 @@ +# build_script/workspace.py -------------------------------------*- 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 http://swift.org/LICENSE.txt for license information +# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +# +# ---------------------------------------------------------------------------- +""" +Represents whole source tree and the build directory. +""" +# ---------------------------------------------------------------------------- + +from __future__ import absolute_import + +import os.path + + +class Workspace(object): + def __init__(self, source_root, build_root): + self._source_root = source_root + self._build_root = build_root + + def source_root_dir(self): + """Return path string of the source root directory. + """ + return self._source_root + + def subdir(self, *components, **kwargs): + """Join one or more path components to source_root_dir of this + workspace. Return path string only if the composed path exists + and is really a directory. None otherwise. + """ + # FIXME: We should sanitize **kwargs. We only accepts `no_exist` only + path = os.path.join(self._source_root, *components) + if kwargs.get('no_exist', False) or os.path.isdir(path): + return path + return None + + def build_dir(self, deployment_target, product): + """Return path string of the build directory for given + deployment_target and product_name. The returned path may or may not + exist. + """ + return os.path.join(self._build_root, + product + '-' + deployment_target) + + def build_root_dir(self): + """Return path string of the build *root* directory. + """ + return self._build_root diff --git a/utils-experimental/build-script-impl/build_script/xcodebuild.py b/utils-experimental/build-script-impl/build_script/xcodebuild.py new file mode 100644 index 0000000000000..afdf974125797 --- /dev/null +++ b/utils-experimental/build-script-impl/build_script/xcodebuild.py @@ -0,0 +1,77 @@ +# build_script/xcodebuild.py ------------------------------------*- 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 http://swift.org/LICENSE.txt for license information +# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +# +# ---------------------------------------------------------------------------- +""" +Represent xcodebuild command +""" +# ---------------------------------------------------------------------------- + +from __future__ import absolute_import + +import re +from . import shell + + +class XcodebuildOptions(object): + def __init__(self, *args): + self._options = [] + for var, value in args: + self.define(var, value) + + def define(self, var, value): + # Strip type suffix. + var = re.sub(':[^:]*$', '', var) + self._options.append(var + "=" + value) + + def __len__(self): + return self._options.__len__() + + def __iter__(self): + return self._options.__iter__() + + def __add__(self, other): + ret = XcodebuildOptions() + ret._options += self._options + ret._options += list(other) + return ret + + def __iadd__(self, other): + self._options += list(other) + return self + + +class Xcodebuild(object): + + def configure(): + pass # no configure for xcodebuild projects + + def build(self, project_dir, target, configuration, action, options): + build_cmd = ['xcodebuild', + '-target', target, + '-configuration', configuration] + + if action != "build": + # We don't need to pass "build" action + build_cmd += [action, ] + + build_cmd += options + + # Do build + with shell.pushd(project_dir): + shell.invoke(build_cmd) + + def build_workspace(self, workspace, scheme, options): + build_cmd = ['xcodebuild', + '-workspace', workspace, + '-scheme', scheme] + build_cmd += options + + shell.invoke(build_cmd) diff --git a/utils-experimental/build-script-impl/tests/__init__.py b/utils-experimental/build-script-impl/tests/__init__.py new file mode 100644 index 0000000000000..c918eeb6284f7 --- /dev/null +++ b/utils-experimental/build-script-impl/tests/__init__.py @@ -0,0 +1,15 @@ +# tests/__init__.py ---------------------------------------------*- 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 http://swift.org/LICENSE.txt for license information +# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +# +# ---------------------------------------------------------------------------- +''' +build-script unit tests +''' +# ---------------------------------------------------------------------------- diff --git a/utils-experimental/build-script-impl/tests/products/__init__.py b/utils-experimental/build-script-impl/tests/products/__init__.py new file mode 100644 index 0000000000000..15c87d27b08a2 --- /dev/null +++ b/utils-experimental/build-script-impl/tests/products/__init__.py @@ -0,0 +1,11 @@ +# tests/products/__init__.py ------------------------------------*- 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 http://swift.org/LICENSE.txt for license information +# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +# +# ---------------------------------------------------------------------------- diff --git a/utils-experimental/build-script-impl/tests/products/test_libdispatch.py b/utils-experimental/build-script-impl/tests/products/test_libdispatch.py new file mode 100644 index 0000000000000..399e6c604344f --- /dev/null +++ b/utils-experimental/build-script-impl/tests/products/test_libdispatch.py @@ -0,0 +1,136 @@ +# tests/products/test_libdispatch.py ----------------------------*- 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 http://swift.org/LICENSE.txt for license information +# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +# +# ---------------------------------------------------------------------------- + +import unittest +import os +import sys +import shutil +import tempfile +try: + # py2 + from StringIO import StringIO +except ImportError: + # py3 + from io import StringIO + +from build_script.driver_arguments import Args +from build_script.workspace import Workspace +from build_script.products import Libdispatch +from build_script import shell + + +class MockSwift(object): + def __init__(self): + self.build_dir = '/path/to/swift/build' + + +class LibdispatchTest(unittest.TestCase): + @classmethod + def setUpClass(cls): + shell.dry_run = True + source_root = os.path.realpath(tempfile.mkdtemp()) + build_root = os.path.join(source_root, 'build') + os.makedirs(os.path.join(source_root, 'swift')) + os.makedirs(os.path.join(source_root, 'swift-corelibs-libdispatch')) + os.makedirs(build_root) + + cls.workspace = Workspace(source_root=source_root, + build_root=build_root) + + Libdispatch.prepare(cls.workspace) + + @classmethod + def tearDownClass(cls): + shutil.rmtree(cls.workspace.source_root_dir()) + shell.dry_run = False + + def setUp(self): + self._stdout = StringIO() + self.orig_stdout = sys.stdout + sys.stdout = self._stdout + + def tearDown(self): + sys.stdout = self.orig_stdout + + def test_configure(self): + args = Args(reconfigure=True, host_target='dummy') + build = Libdispatch( + deployment_target='dummy', + target_build_dir='/path/to/libdispatch/build', + target_install_destdir='/path/to/libdispatch/install', + swift_build=MockSwift(), + args=args) + + build.configure() + self.assertEqual(self._stdout.getvalue(), '''\ +--- Configuring libdispatch --- ++ mkdir -p /path/to/libdispatch/build ++ pushd /path/to/libdispatch/build ++ {source_dir}/configure \ +--prefix=/path/to/libdispatch/install \ +--with-swift-toolchain=/path/to/swift/build ++ popd +'''.format(source_dir=self.workspace.subdir('swift-corelibs-libdispatch'))) + + def test_build(self): + args = Args(reconfigure=True, host_target='dummy') + build = Libdispatch( + deployment_target='dummy', + target_build_dir='/path/to/libdispatch/build', + target_install_destdir='/path/to/libdispatch/install', + swift_build=MockSwift(), + args=args) + + build.build() + self.assertEqual(self._stdout.getvalue(), '''\ +--- Building libdispatch --- ++ pushd /path/to/libdispatch/build ++ make ++ cd tests ++ make build-tests ++ popd +''') + + def test_test(self): + args = Args(skip_test_libdispatch=False, host_target="dummy") + build = Libdispatch( + deployment_target='dummy', + target_build_dir='/path/to/libdispatch/build', + target_install_destdir='/path/to/libdispatch/install', + swift_build=MockSwift(), + args=args) + + build.test() + self.assertEqual(self._stdout.getvalue(), '''\ +--- Running tests for libdispatch --- ++ pushd /path/to/libdispatch/build ++ make test ++ popd +''') + + def test_install(self): + args = Args(install_libdispatch=True, + reconfigure=True, + host_target='dummy') + build = Libdispatch( + deployment_target='dummy', + target_build_dir='/path/to/libdispatch/build', + target_install_destdir='/path/to/libdispatch/install', + swift_build=MockSwift(), + args=args) + build.install() + self.assertEqual(self._stdout.getvalue(), '''\ +--- Installing libdispatch --- ++ pushd /path/to/libdispatch/build ++ make install ++ popd +''') diff --git a/utils-experimental/build-script-impl/tests/test_cmake.py b/utils-experimental/build-script-impl/tests/test_cmake.py new file mode 100644 index 0000000000000..eef22a3716db6 --- /dev/null +++ b/utils-experimental/build-script-impl/tests/test_cmake.py @@ -0,0 +1,94 @@ +# tests/test_cmake.py -------------------------------------------*- 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 http://swift.org/LICENSE.txt for license information +# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +# +# ---------------------------------------------------------------------------- + +import unittest + +from build_script.cmake import CMakeOptions + + +class CMakeTestCase(unittest.TestCase): + + def test_cmake(self): + pass + + def test_cmakeoptions(self): + options = CMakeOptions() + options.define('OPT1:STRING', 'foo') + options.define('OPT2:BOOL', 1) + options.define('OPT3:BOOL', '1') + options.define('OPT4:BOOL', 'true') + options.define('OPT5:BOOL', 'True') + options.define('OPT6:BOOL', True) + options.define('OPT7:BOOL', 0) + options.define('OPT8:BOOL', '0') + options.define('OPT9:BOOL', 'false') + options.define('OPT10:BOOL', 'False') + options.define('OPT11:BOOL', False) + options.define('OPT12', 12) + options.define('OPT13', '') + options.define('OPT14', None) + options.define('OPT15:PATH', 'foo') + + options.unset('OPT16:BOOL') + options.unset('OPT17:STRING') + options.unset('OPT18') + + self.assertRaises(ValueError, options.define, 'ERR', ["FOO"]) + self.assertRaises(ValueError, options.define, 'ERR', {"FOO": 1}) + + self.assertRaises(ValueError, options.define, 'ERR:BOOL', 3) + self.assertRaises(ValueError, options.define, 'ERR:BOOL', 'foo') + self.assertRaises(ValueError, options.define, 'ERR:BOOL', [1]) + self.assertRaises(ValueError, options.define, 'ERR:BOOL', 'YES') + self.assertRaises(ValueError, options.define, 'ERR:BOOL', 'NO') + + self.assertEqual(list(options), [ + '-DOPT1:STRING=foo', + '-DOPT2:BOOL=TRUE', + '-DOPT3:BOOL=TRUE', + '-DOPT4:BOOL=TRUE', + '-DOPT5:BOOL=TRUE', + '-DOPT6:BOOL=TRUE', + '-DOPT7:BOOL=FALSE', + '-DOPT8:BOOL=FALSE', + '-DOPT9:BOOL=FALSE', + '-DOPT10:BOOL=FALSE', + '-DOPT11:BOOL=FALSE', + '-DOPT12=12', + '-DOPT13=', + '-DOPT14=', + '-DOPT15:PATH=foo', + '-UOPT16', + '-UOPT17', + '-UOPT18']) + + def test_cmakeoptions_op(self): + + options1 = CMakeOptions() + options1.define("OPT1_1", 'VAL1') + options1.define("OPT1_2", 'VAL2') + + options2 = CMakeOptions() + options2.define("OPT2_1", 'VAL3') + + options = options1 + options2 + self.assertEqual(list(options), [ + "-DOPT1_1=VAL1", + "-DOPT1_2=VAL2", + "-DOPT2_1=VAL3"]) + + options += options2 + self.assertEqual(list(options), [ + "-DOPT1_1=VAL1", + "-DOPT1_2=VAL2", + "-DOPT2_1=VAL3", + "-DOPT2_1=VAL3"]) diff --git a/utils-experimental/build-script-impl/tests/test_defaults.py b/utils-experimental/build-script-impl/tests/test_defaults.py new file mode 100644 index 0000000000000..94fda4024c5f5 --- /dev/null +++ b/utils-experimental/build-script-impl/tests/test_defaults.py @@ -0,0 +1,36 @@ +# tests/test_defaults.py ----------------------------------------*- 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 http://swift.org/LICENSE.txt for license information +# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +# +# ---------------------------------------------------------------------------- + +import unittest + +from build_script import defaults + + +class ShellTestCase(unittest.TestCase): + def test_default_exists(self): + + assertTrue = self.assertTrue + + # Configurable + assertTrue(hasattr(defaults, 'SWIFT_USER_VISIBLE_VERSION')) + assertTrue(hasattr(defaults, 'CLANG_USER_VISIBLE_VERSION')) + assertTrue(hasattr(defaults, 'SWIFT_ANALYZE_CODE_COVERAGE')) + assertTrue(hasattr(defaults, 'DARWIN_XCRUN_TOOLCHAIN')) + assertTrue(hasattr(defaults, 'DARWIN_DEPLOYMENT_VERSION_OSX')) + assertTrue(hasattr(defaults, 'DARWIN_DEPLOYMENT_VERSION_IOS')) + assertTrue(hasattr(defaults, 'DARWIN_DEPLOYMENT_VERSION_TVOS')) + assertTrue(hasattr(defaults, 'DARWIN_DEPLOYMENT_VERSION_WATCHOS')) + assertTrue(hasattr(defaults, 'UNIX_INSTALL_PREFIX')) + assertTrue(hasattr(defaults, 'DARWIN_INSTALL_PREFIX')) + + # Constants + assertTrue(hasattr(defaults, 'LLVM_TARGETS_TO_BUILD')) diff --git a/utils-experimental/build-script-impl/tests/test_driver_arguments.py b/utils-experimental/build-script-impl/tests/test_driver_arguments.py new file mode 100644 index 0000000000000..ef91f1ba2baa7 --- /dev/null +++ b/utils-experimental/build-script-impl/tests/test_driver_arguments.py @@ -0,0 +1,240 @@ +# tests/test_cmake.py -------------------------------------------*- 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 http://swift.org/LICENSE.txt for license information +# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +# +# ---------------------------------------------------------------------------- + +import unittest +import sys +try: + # py2 + from StringIO import StringIO +except ImportError: + # py3 + from io import StringIO + +from build_script.driver_arguments import Args, create_argparser + + +class ArgsTestCase(unittest.TestCase): + + def test_args(self): + args = Args() + + args.foo = 42 + setattr(args, 'bar', 'Swift') + + self.assertEqual(args.foo, 42) + self.assertEqual(args.bar, 'Swift') + + del args.foo + self.assertFalse(hasattr(args, 'foo')) + + # Immutable after freeze() + Args.freeze(args) + + def _setattr1(): + args.foo = 42 + + def _setattr2(): + setattr(args, 'foo', 42) + + def _delattr1(): + del args.bar + + self.assertRaises(AttributeError, _setattr1) + self.assertRaises(AttributeError, _setattr2) + self.assertRaises(AttributeError, _delattr1) + self.assertEqual(args.bar, 'Swift') + self.assertFalse(hasattr(args, 'foo')) + + # TODO: This test should be removed if we are merged to master. + def test_parser_accepts_all_old_args(self): + # Tests that we migrated all `build-script-impl` options. + parser = create_argparser() + + orig_err = sys.stderr + + for arg in ALL_OLD_ARGS: + err = StringIO() + sys.stderr = err + try: + self.assertIsNotNone( + # ALL old args should accept one argument. + parser.parse_args(['--' + arg + "=1"])) + except SystemExit: + # invalid choice error. At least, we have declaration :) + self.assertIn('invalid choice', err.getvalue()) + + sys.stderr = orig_err + + +ALL_OLD_ARGS = [ + "build-args", + "build-dir", + "host-cc", + "host-cxx", + "darwin-xcrun-toolchain", + "build-ninja", + "cmark-build-type", + "lldb-extra-cmake-args", + "lldb-extra-xcodebuild-args", + "lldb-test-cc", + "lldb-test-with-curses", + "lldb-no-debugserver", + "lldb-use-system-debugserver", + "llvm-build-type", + "llvm-enable-assertions", + "swift-build-type", + "swift-enable-assertions", + "swift-analyze-code-coverage", + "swift-enable-lto", + "llvm-enable-lto", + "swift-stdlib-build-type", + "swift-stdlib-enable-assertions", + "swift-stdlib-enable-reflection-metadata", + "swift-stdlib-enable-resilience", + "swift-stdlib-sil-serialize-all", + "lldb-build-type", + "llbuild-build-type", + "foundation-build-type", + "llbuild-enable-assertions", + "enable-asan", + "enable-ubsan", + "cmake", + "distcc", + "build-runtime-with-host-compiler", + "user-config-args", + "cmake-generator", + "verbose-build", + "install-prefix", + "toolchain-prefix", + "install-destdir", + "install-symroot", + "swift-install-components", + "llvm-install-components", + "installable-package", + "test-installable-package", + "reconfigure", + "swift-sdks", + "swift-primary-variant-sdk", + "swift-primary-variant-arch", + "skip-ios", + "skip-tvos", + "skip-watchos", + "skip-build-cmark", + "skip-build-llvm", + "skip-build-swift", + "skip-build-linux", + "skip-build-freebsd", + "skip-build-cygwin", + "skip-build-osx", + "skip-build-ios", + "skip-build-ios-device", + "skip-build-ios-simulator", + "skip-build-tvos", + "skip-build-tvos-device", + "skip-build-tvos-simulator", + "skip-build-watchos", + "skip-build-watchos-device", + "skip-build-watchos-simulator", + "skip-build-android", + "skip-build-lldb", + "skip-build-llbuild", + "skip-build-swiftpm", + "skip-build-xctest", + "skip-build-foundation", + "skip-build-libdispatch", + "skip-build-benchmarks", + "skip-test-cmark", + "skip-test-lldb", + "skip-test-swift", + "skip-test-llbuild", + "skip-test-swiftpm", + "skip-test-xctest", + "skip-test-foundation", + "skip-test-libdispatch", + "skip-test-linux", + "skip-test-freebsd", + "skip-test-cygwin", + "skip-test-osx", + "skip-test-ios-simulator", + "skip-test-ios-host", + "skip-test-tvos-simulator", + "skip-test-tvos-host", + "skip-test-watchos-simulator", + "skip-test-watchos-host", + "skip-test-validation", + "skip-test-benchmarks", + "skip-test-optimized", + "stress-test-sourcekit", + "workspace", + "enable-llvm-assertions", + "build-llvm", + "build-swift-tools", + "build-swift-stdlib", + "build-swift-stdlib-unittest-extra", + "build-swift-sdk-overlay", + "build-swift-static-stdlib", + "build-swift-examples", + "build-serialized-stdlib-unittest", + "build-sil-debugging-stdlib", + "source-tree-includes-tests", + "native-llvm-tools-path", + "native-clang-tools-path", + "native-swift-tools-path", + "compiler-vendor", + "clang-user-visible-version", + "swift-user-visible-version", + "swift-compiler-version", + "clang-compiler-version", + "embed-bitcode-section", + "darwin-crash-reporter-client", + "darwin-stdlib-install-name-dir", + "install-cmark", + "install-swift", + "install-lldb", + "install-llbuild", + "install-swiftpm", + "install-xctest", + "install-foundation", + "install-libdispatch", + "darwin-install-extract-symbols", + "host-target", + "stdlib-deployment-targets", + "cross-compile-tools-deployment-targets", + "skip-merge-lipo-cross-compile-tools", + "darwin-deployment-version-osx", + "darwin-deployment-version-ios", + "darwin-deployment-version-tvos", + "darwin-deployment-version-watchos", + "extra-cmake-options", + "extra-swift-args", + "sil-verify-all", + "swift-enable-ast-verifier", + "swift-runtime-enable-leak-checker", + "use-gold-linker", + "darwin-toolchain-bundle-identifier", + "darwin-toolchain-display-name", + "darwin-toolchain-name", + "darwin-toolchain-version", + "darwin-toolchain-application-cert", + "darwin-toolchain-installer-cert", + "darwin-toolchain-installer-package", + "build-jobs", + "darwin-toolchain-alias", + "android-ndk", + "android-ndk-version", + "android-ndk-toolchain-version", + "android-icu-uc", + "android-icu-uc-include", + "android-icu-i18n", + "android-icu-i18n-include", + "export-compile-commands", +] diff --git a/utils-experimental/build-script-impl/tests/test_env.py b/utils-experimental/build-script-impl/tests/test_env.py new file mode 100644 index 0000000000000..9e48387929ebf --- /dev/null +++ b/utils-experimental/build-script-impl/tests/test_env.py @@ -0,0 +1,39 @@ +# tests/test_env.py ---------------------------------------------*- 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 http://swift.org/LICENSE.txt for license information +# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +# +# ---------------------------------------------------------------------------- + +import unittest +import os + +from build_script import env + + +class EnvTestCase(unittest.TestCase): + + def test_env_exists(self): + self.assertIsNotNone(env.HOME) + self.assertIsNotNone(env.SWIFT_SOURCE_ROOT) + self.assertIsNotNone(env.SWIFT_BUILD_ROOT) + + def test_env_var(self): + # Note: This test may fail if this script is moved + # from the swift source tree. + # Assuming : + # {SWIFT_SOURCE_ROOT}/swift/utils/build-script-impl/tests/test_env.py + + self.assertEqual( + os.path.realpath(env.SWIFT_SOURCE_ROOT), + os.path.realpath(os.path.join(os.path.dirname(__file__), + '..', '..', '..', '..'))) + self.assertEqual( + os.path.realpath(env.SWIFT_BUILD_ROOT), + os.path.realpath(os.path.join(os.path.dirname(__file__), + '..', '..', '..', '..', 'build'))) diff --git a/utils-experimental/build-script-impl/tests/test_host.py b/utils-experimental/build-script-impl/tests/test_host.py new file mode 100644 index 0000000000000..b2c62de8c0999 --- /dev/null +++ b/utils-experimental/build-script-impl/tests/test_host.py @@ -0,0 +1,97 @@ +# tests/test_host.py --------------------------------------------*- 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 http://swift.org/LICENSE.txt for license information +# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +# +# ---------------------------------------------------------------------------- + +import unittest +import os + +from build_script.host import host + + +class HostTestCase(unittest.TestCase): + + def test_is_xxx(self): + + result = [ + host.is_darwin(), + host.is_linux(), + host.is_freebsd(), + host.is_cygwin()] + + true_count = 0 + for x in result: + if x: + true_count += 1 + + self.assertEqual(true_count, 1) + + def test_find_xxx(self): + + if host.is_darwin(): + host.xcrun_toolchain = 'default' + + cc = host.find_clang_cc() + cxx = host.find_clang_cxx() + cmake = host.find_cmake() + ninja = host.find_ninja() + distcc = host.find_distcc() + pump = host.find_distcc_pump() + + self.assertIsNotNone(cc) + self.assertIsNotNone(cxx) + self.assertIsNotNone(cmake) + + self.assertTrue(os.path.basename(cc).startswith('clang')) + self.assertTrue(os.path.basename(cxx).startswith('clang++')) + self.assertTrue(os.path.basename(cmake) == 'cmake') + self.assertTrue(ninja is None or + os.path.basename(ninja) == 'ninja') + self.assertTrue(distcc is None or + os.path.basename(ninja) == 'distcc') + self.assertTrue(pump is None or + os.path.basename(pump) == 'pump' or + os.path.basename(pump) == 'distcc-pump') + + @unittest.skipUnless(host.is_darwin(), + 'xcrun_find is available in darwin only') + def test_xcrun_find(self): + host.xcrun_toolchain = 'default' + + self.assertIsNotNone(host.xcrun_find('strip')) + self.assertIsNotNone(host.xcrun_find('dsymutil')) + + lipo = host.xcrun_find('lipo') + self.assertIsInstance(lipo, str) + self.assertIsNotNone(lipo) + self.assertTrue(os.path.isabs(lipo)) + + self.assertIsNone(host.xcrun_find('invalid-tool-name-here')) + + @unittest.skipUnless(host.is_darwin(), + 'sdk_path is available in darwin only') + def test_sdk_path(self): + host.xcrun_toolchain = 'default' + + self.assertIsNotNone(host.sdk_path('macosx')) + self.assertIsNotNone(host.sdk_path('iphoneos')) + self.assertIsNotNone(host.sdk_path('iphonesimulator')) + self.assertIsNotNone(host.sdk_path('appletvos')) + self.assertIsNotNone(host.sdk_path('appletvsimulator')) + self.assertIsNotNone(host.sdk_path('watchos')) + self.assertIsNotNone(host.sdk_path('watchsimulator')) + + sdkpath = host.sdk_path('macosx') + self.assertIsInstance(sdkpath, str) + self.assertFalse(sdkpath.endswith('\n')) + self.assertTrue(os.path.isdir(sdkpath)) + self.assertTrue(os.path.isabs(sdkpath)) + + self.assertIsNone(host.sdk_path('does-not-exists')) diff --git a/utils-experimental/build-script-impl/tests/test_shell.py b/utils-experimental/build-script-impl/tests/test_shell.py new file mode 100644 index 0000000000000..5300e5c33031a --- /dev/null +++ b/utils-experimental/build-script-impl/tests/test_shell.py @@ -0,0 +1,332 @@ +# tests/test_shell.py -------------------------------------------*- 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 http://swift.org/LICENSE.txt for license information +# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +# +# ---------------------------------------------------------------------------- + +import unittest +import sys +import os +import os.path +import shutil +import tempfile +try: + # py2 + from StringIO import StringIO +except ImportError: + # py3 + from io import StringIO + +from build_script import shell + + +class ShellTestCase(unittest.TestCase): + + def setUp(self): + self.tmpdir = os.path.realpath(tempfile.mkdtemp()) + + def tearDown(self): + if os.path.exists(self.tmpdir): + shutil.rmtree(self.tmpdir) + + def test_query(self): + shell.echo = False + shell.dry_run = False + + foo_file = os.path.join(self.tmpdir, 'foo.txt') + with open(foo_file, 'w') as f: + f.write("Hello Swift") + + result = shell.query(['cat', foo_file]) + self.assertEqual(result, 'Hello Swift') + + def test_invoke(self): + shell.echo = False + shell.dry_run = False + + foo_file = os.path.join(self.tmpdir, 'foo.txt') + bar_file = os.path.join(self.tmpdir, 'bar.txt') + with open(foo_file, 'w') as f: + f.write("Hello Swift") + + shell.invoke(['cp', foo_file, bar_file]) + + with open(bar_file, 'r') as f: + self.assertEqual(f.read(), "Hello Swift") + + def test_runscript(self): + shell.echo = False + shell.dry_run = False + + foo_file = os.path.join(self.tmpdir, 'foo.txt') + bar_file = os.path.join(self.tmpdir, 'bar.txt') + script = '''\ +echo Hello Swift > {foo_file} +cat {foo_file} | tr '[A-Z]' '[a-z]' > {bar_file} +''' + script = script.format(foo_file=foo_file, bar_file=bar_file) + shell.runscript(script) + + with open(bar_file, 'r') as f: + self.assertEqual(f.read(), "hello swift\n") + + def test_copy(self): + shell.echo = False + shell.dry_run = False + + foo_file = os.path.join(self.tmpdir, 'foo.txt') + bar_file = os.path.join(self.tmpdir, 'bar.txt') + + with open(foo_file, 'w') as f: + f.write("Hello Swift") + shell.copy(foo_file, bar_file) + with open(bar_file, 'r') as f: + self.assertEqual(f.read(), "Hello Swift") + + def test_symlink(self): + shell.echo = False + shell.dry_run = False + + foo_file = os.path.join(self.tmpdir, 'foo.txt') + bar_file = os.path.join(self.tmpdir, 'bar.txt') + with open(foo_file, 'w') as f: + f.write("Hello Swift") + + # absolute + shell.symlink(foo_file, bar_file) + self.assertTrue(os.path.islink(bar_file)) + self.assertEqual(os.readlink(bar_file), foo_file) + with open(bar_file, 'r') as f: + self.assertEqual(f.read(), "Hello Swift") + os.remove(bar_file) + self.assertTrue(os.path.exists(foo_file)) + self.assertFalse(os.path.exists(bar_file)) + + # relative manually + rel_target = os.path.join('..', + os.path.basename(self.tmpdir), + 'foo.txt') + shell.symlink(rel_target, bar_file) + self.assertTrue(os.path.islink(bar_file)) + self.assertEqual(os.readlink(bar_file), rel_target) + os.remove(bar_file) + + # auto relative + shell.symlink(foo_file, bar_file, relative=True) + self.assertEqual(os.readlink(bar_file), 'foo.txt') + + def test_remove(self): + shell.echo = False + shell.dry_run = False + + foo_file = os.path.join(self.tmpdir, 'foo.txt') + + with open(foo_file, 'w') as f: + f.write("Hello Swift") + self.assertTrue(os.path.exists(foo_file)) + shell.remove(foo_file) + self.assertFalse(os.path.exists(foo_file)) + self.assertTrue(os.path.exists(self.tmpdir)) + + def test_makedirs(self): + shell.echo = False + shell.dry_run = False + + path = os.path.join(self.tmpdir, 'foo', 'bar', 'baz') + + shell.makedirs(path) + self.assertTrue(os.path.isdir(path)) + + def test_rmtree(self): + shell.echo = False + shell.dry_run = False + + path = os.path.join(self.tmpdir, 'foo', 'bar', 'baz') + os.makedirs(path) + + self.assertTrue(os.path.isdir(path)) + shell.rmtree(os.path.join(self.tmpdir, 'foo', 'bar')) + self.assertFalse( + os.path.exists(os.path.join(self.tmpdir, 'foo', 'bar'))) + self.assertTrue( + os.path.exists(os.path.join(self.tmpdir, 'foo'))) + + def test_copytree(self): + shell.echo = False + shell.dry_run = False + + path1 = os.path.join(self.tmpdir, 'path', 'to') + os.makedirs(path1) + open(os.path.join(path1, 'foo'), 'a').close() + os.symlink('foo', os.path.join(path1, 'bar')) + + shell.copytree(os.path.join(self.tmpdir, 'path'), + os.path.join(self.tmpdir, 'copy')) + + self.assertTrue(os.path.isdir(os.path.join(self.tmpdir, 'copy'))) + # symlink remains symlink + new_bar = os.path.join(self.tmpdir, 'copy', 'to', 'bar') + self.assertEqual(os.readlink(new_bar), 'foo') + + def test_chdir(self): + shell.echo = False + shell.dry_run = False + + basedir = os.getcwd() + + # Basic + shell.chdir(self.tmpdir) + self.assertEqual(os.getcwd(), self.tmpdir) + shell.chdir(basedir) + self.assertEqual(os.getcwd(), basedir) + + foo_dir = os.path.join(self.tmpdir, 'foo') + bar_dir = os.path.join(self.tmpdir, 'bar') + os.makedirs(foo_dir) + os.makedirs(bar_dir) + + # relative path + shell.chdir(foo_dir) + self.assertEqual(os.getcwd(), foo_dir) + shell.chdir(os.path.join('..', 'bar')) + self.assertEqual(os.getcwd(), bar_dir) + shell.chdir(os.path.join('..')) + self.assertEqual(os.getcwd(), self.tmpdir) + + shell.chdir(basedir) + self.assertEqual(os.getcwd(), basedir) + + def test_pushd(self): + + shell.echo = False + shell.dry_run = False + + basedir = os.getcwd() + with shell.pushd(self.tmpdir): + self.assertEqual(os.getcwd(), self.tmpdir) + self.assertEqual(os.getcwd(), basedir) + + # pushd inside pushd + with shell.pushd(self.tmpdir): + self.assertEqual(os.getcwd(), self.tmpdir) + os.makedirs('foo') + with shell.pushd('foo'): + self.assertEqual(os.getcwd(), + os.path.join(self.tmpdir, 'foo')) + self.assertEqual(os.getcwd(), self.tmpdir) + self.assertEqual(os.getcwd(), basedir) + + # cd inside pushd + with shell.pushd(self.tmpdir): + os.chdir('foo') + self.assertEqual(os.getcwd(), os.path.join(self.tmpdir, 'foo')) + os.chdir('..') + self.assertEqual(os.getcwd(), self.tmpdir) + os.rmdir('foo') + self.assertEqual(os.getcwd(), basedir) + + def test_echo(self): + + shell.echo = True + shell.dry_run = False + + out = StringIO() + _orig_stdout = sys.stdout + sys.stdout = out + + foobar_dir = os.path.join(self.tmpdir, 'foo', 'bar') + foobar2_dir = os.path.join(self.tmpdir, 'foo', 'bar2') + + shell.makedirs(foobar_dir) + with shell.pushd(foobar_dir): + shell.makedirs('subdir') + shell.chdir('subdir') + shell.invoke(['touch', 'testfile']) + shell.query(['date', '+%Y-%m-%d']) + shell.copy('testfile', 'testfile2') + shell.symlink('testfile', 'testlink') + shell.copytree(foobar_dir, foobar2_dir) + shell.rmtree(foobar_dir) + self.assertTrue( + os.path.exists(os.path.join(foobar2_dir, 'subdir', 'testfile'))) + self.assertEqual( + os.readlink(os.path.join(foobar2_dir, 'subdir', 'testlink')), + 'testfile') + self.assertEqual(out.getvalue(), '''\ ++ mkdir -p {foobar_dir} ++ pushd {foobar_dir} ++ mkdir -p subdir ++ cd subdir ++ touch testfile ++ date +%Y-%m-%d ++ cp testfile testfile2 ++ ln -s testfile testlink ++ popd ++ cp -r {foobar_dir} {foobar2_dir} ++ rm -rf {foobar_dir} +'''.format(foobar_dir=foobar_dir, + foobar2_dir=foobar2_dir)) + + sys.stdout = _orig_stdout + + def test_dryrun(self): + shell.echo = False + shell.dry_run = True + + out = StringIO() + _orig_stdout = sys.stdout + sys.stdout = out + + basedir = os.getcwd() + foobar_dir = os.path.join(self.tmpdir, 'foo', 'bar') + foobar2_dir = os.path.join(self.tmpdir, 'foo', 'bar2') + + shell.makedirs(foobar_dir) + self.assertFalse(os.path.exists(foobar_dir)) + with shell.pushd(foobar_dir): + self.assertEqual(os.getcwd(), basedir) + shell.makedirs('subdir') + shell.chdir('subdir') + self.assertEqual(os.getcwd(), basedir) + shell.invoke(['touch', 'testfile']) + self.assertFalse(os.path.exists(os.path.join(foobar_dir, + 'subdir', + 'testfile'))) + shell.query(['date', '+%Y-%m-%d']) + shell.copy('testfile', 'testfile2') + self.assertFalse(os.path.exists(os.path.join(foobar_dir, + 'subdir', + 'testfile2'))) + shell.symlink('testfile', 'testlink') + self.assertFalse(os.path.exists(os.path.join(foobar_dir, + 'subdir', + 'testlink'))) + shell.copytree(foobar_dir, foobar2_dir) + self.assertFalse(os.path.exists(foobar2_dir)) + shell.rmtree(self.tmpdir) + self.assertTrue(os.path.exists(self.tmpdir)) + + # dry_run always echo **except** query that doesn't have dry_run + # semantics + self.assertEqual(out.getvalue(), '''\ ++ mkdir -p {foobar_dir} ++ pushd {foobar_dir} ++ mkdir -p subdir ++ cd subdir ++ touch testfile ++ cp testfile testfile2 ++ ln -s testfile testlink ++ popd ++ cp -r {foobar_dir} {foobar2_dir} ++ rm -rf {tmpdir} +'''.format(foobar_dir=foobar_dir, + foobar2_dir=foobar2_dir, + tmpdir=self.tmpdir)) + + sys.stdout = _orig_stdout diff --git a/utils-experimental/build-script-impl/tests/test_swift_utils.py b/utils-experimental/build-script-impl/tests/test_swift_utils.py new file mode 100644 index 0000000000000..a9c2274ef2fce --- /dev/null +++ b/utils-experimental/build-script-impl/tests/test_swift_utils.py @@ -0,0 +1,30 @@ + +import unittest +import os +import os.path + +from build_script import swift_utils + + +class SwiftUtilsTestCase(unittest.TestCase): + + def test_swift_utils(self): + + def isexec(path): + return ( + os.path.exists(path) and + not os.path.isdir(path) and + os.access(path, os.X_OK)) + + def isdir(path): + return os.path.isdir(path) + + self.assertTrue(isexec(swift_utils('build-script'))) + self.assertTrue(isexec(swift_utils('recursive-lipo'))) + self.assertTrue(isexec(swift_utils('toolchain-codesign'))) + self.assertTrue(isexec(swift_utils('toolchain-installer'))) + self.assertTrue(isexec(swift_utils('swift-stdlib-tool-substitute'))) + self.assertTrue(isdir(swift_utils('darwin-installer-scripts'))) + + # Returns path even if the file does not exist + self.assertIsNotNone(swift_utils('not-exists-tool-name')) diff --git a/utils-experimental/build-script-impl/tests/test_targets.py b/utils-experimental/build-script-impl/tests/test_targets.py new file mode 100644 index 0000000000000..795bccacb8b50 --- /dev/null +++ b/utils-experimental/build-script-impl/tests/test_targets.py @@ -0,0 +1,42 @@ +# tests/test_targets.py -----------------------------------------*- 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 http://swift.org/LICENSE.txt for license information +# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +# +# ---------------------------------------------------------------------------- + +import unittest + +from build_script import targets + + +class TargetsTestCase(unittest.TestCase): + + def test_targets(self): + + self.assertEqual(targets.split('linux-x86_64'), + ('linux', 'x86_64')) + + self.assertEqual(targets.split('linux-x86_64-bar'), + ('linux', 'x86_64-bar')) + + self.assertEqual(targets.split('linux'), + ('linux', None)) + + self.assertTrue(targets.is_osx('macosx-x86_64')) + self.assertFalse(targets.is_osx('linux-armv7')) + self.assertFalse(targets.is_osx('iphoneos-arm64')) + + self.assertTrue(targets.is_darwin_type('macosx-x86_64')) + self.assertTrue(targets.is_darwin_type('iphonesimulator-i386')) + self.assertTrue(targets.is_darwin_type('iphoneos-armv7s')) + self.assertTrue(targets.is_darwin_type('appletvsimulator-x86_64')) + self.assertTrue(targets.is_darwin_type('appletvos-arm64')) + self.assertTrue(targets.is_darwin_type('watchsimulator-i386')) + self.assertTrue(targets.is_darwin_type('watchos-armv7k')) + self.assertFalse(targets.is_darwin_type('freebsd-x86_64')) diff --git a/utils-experimental/build-script-impl/tests/test_workspace.py b/utils-experimental/build-script-impl/tests/test_workspace.py new file mode 100644 index 0000000000000..e67714ed5ab1c --- /dev/null +++ b/utils-experimental/build-script-impl/tests/test_workspace.py @@ -0,0 +1,58 @@ +# tests/test_workspace.py ---------------------------------------*- 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 http://swift.org/LICENSE.txt for license information +# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +# +# ---------------------------------------------------------------------------- + +import unittest +import os +import shutil +import tempfile + +from build_script.workspace import Workspace + + +class WorkspaceTestCase(unittest.TestCase): + + def test_workspace(self): + + tmpdir1 = os.path.realpath(tempfile.mkdtemp()) + tmpdir2 = os.path.realpath(tempfile.mkdtemp()) + + os.makedirs(os.path.join(tmpdir1, 'foo')) + os.makedirs(os.path.join(tmpdir1, 'foo', 'src')) + + workspace = Workspace(source_root=tmpdir1, + build_root=tmpdir2) + + self.assertEqual(workspace.source_root_dir(), tmpdir1) + self.assertEqual(workspace.build_root_dir(), tmpdir2) + + # Return source directory if exists + self.assertEqual(workspace.subdir('foo'), + os.path.join(tmpdir1, 'foo')) + self.assertEqual(workspace.subdir('foo', 'src'), + os.path.join(tmpdir1, 'foo', 'src')) + + # Return None if not exists + self.assertIsNone(workspace.subdir('baz')) + self.assertIsNone(workspace.subdir('foo', 'not-exists')) + + # Return path even if not exists + self.assertEqual(workspace.subdir('baz', no_exist=True), + os.path.join(tmpdir1, 'baz')) + self.assertEqual(workspace.subdir('foo', 'not-exists', no_exist=True), + os.path.join(tmpdir1, 'foo', 'not-exists')) + + # build_dir() always return the path + self.assertEqual(workspace.build_dir('target', 'product'), + os.path.join(tmpdir2, 'product-target')) + + shutil.rmtree(tmpdir1) + shutil.rmtree(tmpdir2) diff --git a/utils-experimental/build-script-impl/tests/utils/__init__.py b/utils-experimental/build-script-impl/tests/utils/__init__.py new file mode 100644 index 0000000000000..0d2462c3f73ef --- /dev/null +++ b/utils-experimental/build-script-impl/tests/utils/__init__.py @@ -0,0 +1,11 @@ +# tests/utils/__init__.py ---------------------------------------*- 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 http://swift.org/LICENSE.txt for license information +# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +# +# ---------------------------------------------------------------------------- diff --git a/utils-experimental/build-script-impl/tests/utils/test_argparser_builder.py b/utils-experimental/build-script-impl/tests/utils/test_argparser_builder.py new file mode 100644 index 0000000000000..46f95b2ef4f46 --- /dev/null +++ b/utils-experimental/build-script-impl/tests/utils/test_argparser_builder.py @@ -0,0 +1,106 @@ +# tests/utils/test_argparser_builder.py -------------------------*- 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 http://swift.org/LICENSE.txt for license information +# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +# +# ---------------------------------------------------------------------------- + +import unittest +from build_script.utils import ArgParserBuilder + + +class ArgParserBuilderTestCase(unittest.TestCase): + + def test_argparser_builder(self): + builder = ArgParserBuilder() + in_group = builder.in_group + mutually_exclusive_group = builder.mutually_exclusive_group + + set_ = builder.set_action + enable = builder.enable_action + disable = builder.disable_action + append = builder.append_action + option = builder.add_option + + in_group("FooBar") + + option('--foo', set_(['foo1', 'foo2'])) + option(['-B', '--bar'], set_(const=True)) + option('--disable-baz', disable('baz', default=True)) + + with mutually_exclusive_group(): + option('--test', enable('test')) + option('--no-test', disable('test')) + + with mutually_exclusive_group(): + all_products = ['x_type', 'y_type'] + option('--typeA', set_(all_products, const="A")) + option('--typeB', set_(all_products, const="B")) + + option('--compound', + set_("compound_dest1", const="comp"), + enable("compound_dest2")) + + option('--enabler1', enable(default=True)) + option('--enabler2', enable(default=True)) + option('--enabler3', enable(default=True)) + option('--disabler1', disable(default=False)) + option('--disabler2', disable(default=False)) + option('--disabler3', disable(default=False)) + + option('--append1', append(separator=';')) + option('--append2', append(join='==')) + option('--append3', append(join=';', separator=",")) + + parser = builder.build() + args = parser.parse_args([ + '--foo', 'some', '--bar', '--disable-baz', + '--no-test', '--typeA', '--compound', + '--enabler2=0', '--enabler3=1', + '--disabler2', '0', '--disabler3', '1', + '--append1', 'foo;bar', '--append1', 'baz;qux', + '--append2', 'foo,bar', '--append2', 'baz', + '--append3', 'foo,bar', '--append3', 'baz', + ]) + + self.assertEqual(vars(args), { + 'foo1': 'some', + 'foo2': 'some', + 'bar': True, + 'baz': False, + 'test': False, + 'x_type': 'A', + 'y_type': 'A', + 'compound_dest1': "comp", + 'compound_dest2': True, + 'enabler1': True, + 'enabler2': False, + 'enabler3': True, + 'disabler1': False, + 'disabler2': True, + 'disabler3': False, + 'append1': ('foo', 'bar', 'baz', 'qux'), + 'append2': 'foo,bar==baz', + 'append3': 'foo;bar;baz' + }) + + def test_args(self): + builder = ArgParserBuilder() + + builder.set_defaults(baz=12) + builder.set_defaults(['test', 'test2'], 'swift') + + builder.add_option('--foo', builder.set_action) + builder.add_option('--bar', builder.set_action('baz_value')) + args = builder.build().parse_args(['--bar', 'Swift']) + + self.assertIs(args.baz, 12) + self.assertIs(args.test, 'swift') + self.assertIs(args.test2, 'swift') + self.assertIs(args.foo, None) + self.assertIs(args.baz_value, 'Swift') diff --git a/utils-experimental/build-script-impl/tests/utils/test_cached_property.py b/utils-experimental/build-script-impl/tests/utils/test_cached_property.py new file mode 100644 index 0000000000000..ec5cfd16dca7d --- /dev/null +++ b/utils-experimental/build-script-impl/tests/utils/test_cached_property.py @@ -0,0 +1,44 @@ +# tests/utils/test_cached_property.py ---------------------------*- 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 http://swift.org/LICENSE.txt for license information +# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +# +# ---------------------------------------------------------------------------- + +import unittest + +from build_script.utils import CachedProperty + + +i = 0 + + +class Foo(object): + @CachedProperty + def bar(self): + global i + i += 1 + return i + + +class CachedPropertyTestCase(unittest.TestCase): + + def test_cached_property(self): + global i + + foo = Foo() + ret = foo.bar + self.assertEqual(i, 1) + self.assertEqual(ret, 1) + ret = foo.bar + self.assertEqual(i, 1) + self.assertEqual(ret, 1) + + i = 42 + ret = foo.bar + self.assertEqual(ret, 1) diff --git a/utils-experimental/build-script-impl/tests/utils/test_printf.py b/utils-experimental/build-script-impl/tests/utils/test_printf.py new file mode 100644 index 0000000000000..19e862434f4f4 --- /dev/null +++ b/utils-experimental/build-script-impl/tests/utils/test_printf.py @@ -0,0 +1,48 @@ +# tests/utils/test_printf.py ------------------------------------*- 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 http://swift.org/LICENSE.txt for license information +# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +# +# ---------------------------------------------------------------------------- + +import unittest +import sys +try: + # py2 + from StringIO import StringIO +except ImportError: + # py3 + from io import StringIO + +from build_script.utils import printf, printf_with_argv0 + + +class PrintfTestCase(unittest.TestCase): + + def test_printf(self): + + out = StringIO() + sys.stdout = out + + printf("Hello {1} {0}", "build_script", "Swift") + + self.assertEqual(out.getvalue(), "Hello Swift build_script\n") + + sys.stdout = sys.__stdout__ + + def test_printf_with_argv0(self): + + out = StringIO() + sys.stdout = out + + printf_with_argv0("Hello {1} {0}", "build_script", "Swift") + + self.assertEqual(out.getvalue(), + sys.argv[0] + ": Hello Swift build_script\n") + + sys.stdout = sys.__stdout__ diff --git a/utils-experimental/build-script-impl/tests/utils/test_which.py b/utils-experimental/build-script-impl/tests/utils/test_which.py new file mode 100644 index 0000000000000..a6b7a91a29e7e --- /dev/null +++ b/utils-experimental/build-script-impl/tests/utils/test_which.py @@ -0,0 +1,30 @@ +# tests/utils/test_which.py -------------------------------------*- 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 http://swift.org/LICENSE.txt for license information +# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +# +# ---------------------------------------------------------------------------- + +import unittest +import os.path + +from build_script.utils import which + + +class WhichTestCase(unittest.TestCase): + + def test_when_cmd_not_found_returns_none(self): + result = which('a-tool-that-doesnt-exist') + self.assertIsNone(result) + + def test_when_cmd_found_returns_absolute_path(self): + result = which('ls') + self.assertIsNotNone(result) + self.assertTrue(os.path.isabs(result)) + path, name = os.path.split(result) + self.assertEqual(name, 'ls') diff --git a/utils-experimental/build-toolchain b/utils-experimental/build-toolchain new file mode 100755 index 0000000000000..b892cf1fdbce4 --- /dev/null +++ b/utils-experimental/build-toolchain @@ -0,0 +1,57 @@ +#!/usr/bin/env bash +# +# utils/build-toolchain - documents process for building a toolchain +# +# 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 http://swift.org/LICENSE.txt for license information +# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors + +SCRIPT_DIR=$(cd $(dirname ${BASH_SOURCE:-$0}); pwd) +cd "$(dirname ${BASH_SOURCE:-$0})/.." || exit +SRC_DIR=$PWD + +DRY_RUN= +if [[ "$1" == "-n" ]] ; then + DRY_RUN="-n" + shift +fi + +YEAR=$(date +"%Y") +MONTH=$(date +"%m") +DAY=$(date +"%d") +TOOLCHAIN_VERSION="swift-LOCAL-${YEAR}-${MONTH}-${DAY}-a" +ARCHIVE="${TOOLCHAIN_VERSION}-osx.tar.gz" +SYM_ARCHIVE="${TOOLCHAIN_VERSION}-osx-symbols.tar.gz" +BUNDLE_PREFIX=${1:?Please specify bundle prefix e.g. $0 local.swift} +BUNDLE_IDENTIFIER="${BUNDLE_PREFIX}.${YEAR}${MONTH}${DAY}" +DISPLAY_NAME="Local Swift Development Snapshot ${YEAR}-${MONTH}-${DAY}" +TOOLCHAIN_NAME="${TOOLCHAIN_VERSION}" + +SWIFT_INSTALLABLE_PACKAGE="${SRC_DIR}/${ARCHIVE}" +SWIFT_INSTALL_DIR="${SRC_DIR}/swift-nightly-install" +SWIFT_INSTALL_SYMROOT="${SRC_DIR}/swift-nightly-symroot" +SWIFT_TOOLCHAIN_DIR="/Library/Developer/Toolchains/${TOOLCHAIN_NAME}.xctoolchain" +SYMBOLS_PACKAGE="${SRC_DIR}/${SYM_ARCHIVE}" + +if [[ "$(uname -s)" == "Darwin" ]] ; then + SWIFT_PACKAGE=buildbot_osx_package +else + SWIFT_PACKAGE=buildbot_linux +fi + + +exec ${SCRIPT_DIR}/build-script ${DRY_RUN} --preset="${SWIFT_PACKAGE}" \ + install_destdir="${SWIFT_INSTALL_DIR}" \ + installable_package="${SWIFT_INSTALLABLE_PACKAGE}" \ + install_toolchain_dir="${SWIFT_TOOLCHAIN_DIR}" \ + install_symroot="${SWIFT_INSTALL_SYMROOT}" \ + symbols_package="${SYMBOLS_PACKAGE}" \ + darwin_toolchain_bundle_identifier="${BUNDLE_IDENTIFIER}" \ + darwin_toolchain_display_name="${DISPLAY_NAME}" \ + darwin_toolchain_xctoolchain_name="${TOOLCHAIN_NAME}" \ + darwin_toolchain_version="${TOOLCHAIN_VERSION}" \ + darwin_toolchain_alias="Local" \