# utils/SwiftBuildSupport.py - Utilities for Swift build scripts -*- 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 from __future__ import print_function try: # Python 2 import ConfigParser except ImportError: # Python 3 import configparser as ConfigParser import os import pipes import subprocess import sys HOME = os.environ.get("HOME", "/") def _get_default_source_root(): result = "" # Are we in a Swift checkout? Start from this file and check its parent # directories. # # $SWIFT_SOURCE_ROOT/swift/utils/SwiftBuildSupport.py (swift_path, parent_dirname) = os.path.split(os.path.dirname(__file__)) if parent_dirname != "utils": return result if not os.path.exists(os.path.join(swift_path, 'CMakeLists.txt')): return result result = os.path.dirname(swift_path) # Are we in an LLVM checkout? Start from the Swift checkout and check /its/ # parent directories. # # $SWIFT_SOURCE_ROOT/llvm/tools/swift/utils/SwiftBuildSupport.py (llvm_path, parent_dirname) = os.path.split(result) if parent_dirname != "tools": return result if not os.path.exists(os.path.join(llvm_path, 'CMakeLists.txt')): return result result = os.path.dirname(llvm_path) return result # 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")) def print_with_argv0(message): print(sys.argv[0] + ": " + message) def quote_shell_command(args): return " ".join([pipes.quote(a) for a in args]) def check_call(args, print_command=False, verbose=False): if print_command: print(os.getcwd() + "$ " + quote_shell_command(args)) try: return subprocess.check_call(args) except subprocess.CalledProcessError as e: print_with_argv0( "command terminated with a non-zero exit status " + str(e.returncode) + ", aborting") sys.stdout.flush() sys.exit(1) except OSError as e: print_with_argv0( "could not execute '" + quote_shell_command(args) + "': " + e.strerror) sys.stdout.flush() sys.exit(1) def check_output(args, print_command=False, verbose=False): if print_command: print(os.getcwd() + "$ " + quote_shell_command(args)) try: return subprocess.check_output(args) except subprocess.CalledProcessError as e: print_with_argv0( "command terminated with a non-zero exit status " + str(e.returncode) + ", aborting") sys.stdout.flush() sys.exit(1) except OSError as e: print_with_argv0( "could not execute '" + quote_shell_command(args) + "': " + e.strerror) sys.stdout.flush() sys.exit(1) def _load_preset_files_impl(preset_file_names, substitutions={}): config = ConfigParser.SafeConfigParser(substitutions, allow_no_value=True) if config.read(preset_file_names) == []: print_with_argv0( "preset file not found (tried " + str(preset_file_names) + ")") sys.exit(1) 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: print_with_argv0("preset '" + preset_name + "' not found") sys.exit(1) if missing_opts: print_with_argv0("missing option(s) for preset '" + preset_name + "': " + ", ".join(missing_opts)) sys.exit(1) 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)] # A context manager for changing the current working directory. # # with WorkingDirectory('/tmp'): # ... do work in /tmp... class WorkingDirectory(object): def __init__(self, new_cwd): self.new_cwd = new_cwd def __enter__(self): self.old_cwd = os.getcwd() os.chdir(self.new_cwd) def __exit__(self, type, value, traceback): os.chdir(self.old_cwd)