blob: ba6f673bb6c99a59f56a479655dafcd996090590 [file] [log] [blame]
# swift_build_support/products/product.py -----------------------*- python -*-
#
# This source file is part of the Swift.org open source project
#
# Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
# Licensed under Apache License v2.0 with Runtime Library Exception
#
# See https://swift.org/LICENSE.txt for license information
# See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
#
# ----------------------------------------------------------------------------
import abc
import os
from .. import cmake
from .. import targets
def is_release_variant(build_variant):
return build_variant in ['Release', 'RelWithDebInfo']
class Product(object):
@classmethod
def product_name(cls):
"""product_name() -> str
The identifier-style name to use for this product.
"""
return cls.__name__.lower()
@classmethod
def product_source_name(cls):
"""product_source_name() -> str
The name of the source code directory of this product.
It provides a customization point for Product subclasses. It is set to
the value of product_name() by default for this reason.
"""
llvm_projects = ['clang',
'clang-tools-extra',
'compiler-rt',
'libcxx',
'lldb',
'llvm']
if cls.product_name() in llvm_projects:
return "llvm-project/{}".format(cls.product_name())
return cls.product_name()
@classmethod
def is_build_script_impl_product(cls):
"""is_build_script_impl_product -> bool
Whether this product is produced by build-script-impl.
"""
raise NotImplementedError
@classmethod
def is_swiftpm_unified_build_product(cls):
"""is_swiftpm_unified_build_product -> bool
Whether this product should be built in the unified build of SwiftPM
products.
"""
return False
@classmethod
def is_nondarwin_only_build_product(cls):
"""Returns true if this target should be skipped in darwin builds when
inferring dependencies.
"""
return False
@classmethod
def get_dependencies(cls):
"""Return a list of products that this product depends upon"""
raise NotImplementedError
def should_clean(self, host_target):
"""should_clean() -> Bool
Whether or not this product should be cleaned before being built
"""
return False
def clean(self, host_target):
"""clean() -> void
Perform the clean, for a non-build-script-impl product.
"""
raise NotImplementedError
def should_build(self, host_target):
"""should_build() -> Bool
Whether or not this product should be built with the given arguments.
"""
raise NotImplementedError
def build(self, host_target):
"""build() -> void
Perform the build, for a non-build-script-impl product.
"""
raise NotImplementedError
def should_test(self, host_target):
"""should_test() -> Bool
Whether or not this product should be tested with the given arguments.
"""
raise NotImplementedError
def test(self, host_target):
"""test() -> void
Run the tests, for a non-build-script-impl product.
"""
raise NotImplementedError
def should_install(self, host_target):
"""should_install() -> Bool
Whether or not this product should be installed with the given
arguments.
"""
raise NotImplementedError
def install(self, host_target):
"""install() -> void
Install to the toolchain, for a non-build-script-impl product.
"""
raise NotImplementedError
def __init__(self, args, toolchain, source_dir, build_dir):
"""
Parameters
----------
args : `argparse.Namespace`
The arguments passed by the user to the invocation of the script.
toolchain : `swift_build_support.toolchain.Toolchain`
The toolchain being used to build the product. The toolchain will
point to the tools that the builder should use to build (like the
compiler or the linker).
build_dir: string
The directory in which the product should put all of its build
products.
"""
self.args = args
self.toolchain = toolchain
self.source_dir = source_dir
self.build_dir = build_dir
self.cmake_options = cmake.CMakeOptions()
def is_release(self):
"""is_release() -> Bool
Whether or not this target is built as a release variant
"""
return is_release_variant(self.args.build_variant)
def install_toolchain_path(self, host_target):
"""toolchain_path() -> string
Returns the path to the toolchain that is being created as part of this
build.
"""
install_destdir = self.args.install_destdir
if self.args.cross_compile_hosts:
build_root = os.path.dirname(self.build_dir)
install_destdir = '%s/intermediate-install/%s' % (build_root, host_target)
return targets.toolchain_path(install_destdir,
self.args.install_prefix)
class ProductBuilder(object):
"""
Abstract base class for all ProductBuilders.
An specific ProductBuilder will implement the interface methods depending
how the product want to be build. Multiple products can use the same
product builder if parametrized right (for example all the products build
using CMake).
Ideally a ProductBuilder will be initialized with references to the
invocation arguments, the calculated toolchain, the calculated workspace,
and the target host, but the base class doesn't impose those requirements
in order to be flexible.
NOTE: Python doesn't need an explicit abstract base class, but it helps
documenting the interface.
"""
@abc.abstractmethod
def __init__(self, product_class, args, toolchain, workspace):
"""
Create a product builder for the given product class.
Parameters
----------
product_class : class
A subtype of `Product` which describes the product being built by
this builder.
args : `argparse.Namespace`
The arguments passed by the user to the invocation of the script. A
builder should consider this argument read-only.
toolchain : `swift_build_support.toolchain.Toolchain`
The toolchain being used to build the product. The toolchain will
point to the tools that the builder should use to build (like the
compiler or the linker).
workspace : `swift_build_support.workspace.Workspace`
The workspace where the source code and the build directories have
to be located. A builder should use the workspace to access its own
source/build directory, as well as other products source/build
directories.
"""
pass
@abc.abstractmethod
def build(self):
"""
Perform the build phase for the product.
This phase might also imply a configuration phase, but each product
builder is free to determine how to do it.
"""
pass
@abc.abstractmethod
def test(self):
"""
Perform the test phase for the product.
This phase might build and execute the product tests.
"""
pass
@abc.abstractmethod
def install(self):
"""
Perform the install phase for the product.
This phase might copy the artifacts from the previous phases into a
destination directory.
"""
pass