blob: 8842b10148d26507c1f7099e68cb8fbf11f8c4f0 [file] [log] [blame]
# 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:
import ConfigParser # Python 2
except ImportError:
import configparser as ConfigParser # Python 3
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:
if verbose:
print_with_argv0(e.strerror)
else:
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:
if verbose:
print_with_argv0(e.strerror)
else:
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)