blob: 859ef89226ceefa90f94c946be79faed898f31fc [file] [log] [blame]
# This source file is part of the Swift.org open source project
#
# Copyright (c) 2014 - 2015 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 .config import Configuration
from .target import TargetConditional
from .path import Path
import os
class BuildAction:
input = None
output = None
_product = None
dependencies = None
skipRule = False
def __init__(self, input=None, output=None):
self.input = input
self.output = output
@property
def product(self):
return self._product
def set_product(self, product):
self._product = product
def generate_dependencies(self, extra = None):
if self.dependencies is not None and len(self.dependencies) > 0:
rule = " |"
for dep in self.dependencies:
rule += " " + dep.name
if extra is not None:
rule += " " + extra
return rule
else:
if extra is not None:
return " | " + extra
return ""
def add_dependency(self, phase):
if self.dependencies is None:
self.dependencies = [phase]
else:
self.dependencies.append(phase)
class Cp(BuildAction):
def __init__(self, source, destination):
BuildAction.__init__(self, input=source, output=destination)
def generate(self):
return """
build """ + self.output.relative() + """: Cp """ + self.input.relative() + self.generate_dependencies() + """
"""
class CompileSource(BuildAction):
path = None
def __init__(self, path, product):
BuildAction.__init__(self, input=path, output=Configuration.current.build_directory.path_by_appending(product.name).path_by_appending(path.relative() + ".o"))
self.path = path
@staticmethod
def compile(source, phase):
ext = source.extension()
if ext == ".c" or ext == ".m":
return CompileC(source, phase.product)
elif ext == ".mm" or ext == ".cpp" or ext == ".CC":
return CompileCxx(source, phase.product)
elif ext == ".S" or ext == ".s":
return Assemble(source, phase.product)
elif ext == ".swift":
return CompileSwift(source, phase.product, phase)
else:
return None
class CompileC(CompileSource):
def __init__(self, path, product):
CompileSource.__init__(self, path, product)
def generate(self):
generated = """
build """ + self.output.relative() + """: CompileC """ + self.path.relative() + self.generate_dependencies() + """
flags = """
generated += " -I" + Configuration.current.build_directory.path_by_appending(self.product.name).relative()
generated += " -I" + Configuration.current.build_directory.relative()
generated += " -I" + Configuration.current.build_directory.path_by_appending(self.product.name).relative() + self.product.ROOT_HEADERS_FOLDER_PATH
generated += " -I" + Configuration.current.build_directory.path_by_appending(self.product.name).relative() + self.product.PUBLIC_HEADERS_FOLDER_PATH
generated += " -I" + Configuration.current.build_directory.path_by_appending(self.product.name).relative() + self.product.PRIVATE_HEADERS_FOLDER_PATH
generated += " -I" + Configuration.current.build_directory.path_by_appending(self.product.name).relative() + self.product.PROJECT_HEADERS_FOLDER_PATH
cflags = TargetConditional.value(self.product.CFLAGS)
if cflags is not None:
generated += " " + cflags
prefix = TargetConditional.value(self.product.GCC_PREFIX_HEADER)
if prefix is not None:
generated += " -include " + prefix
generated += "\n"
if self.path.extension() == ".m" or "-x objective-c" in generated:
self.product.needs_objc = True
return generated
class CompileCxx(CompileSource):
def __init__(self, path, product):
CompileSource.__init__(self, path, product)
def generate(self):
generated = """
build """ + self.output.relative() + """: CompileCxx """ + self.path.relative() + self.generate_dependencies() + """
flags = """
generated += " -I" + Configuration.current.build_directory.path_by_appending(self.product.name).relative()
generated += " -I" + Configuration.current.build_directory.relative()
generated += " -I" + Configuration.current.build_directory.path_by_appending(self.product.name).relative() + self.product.ROOT_HEADERS_FOLDER_PATH
generated += " -I" + Configuration.current.build_directory.path_by_appending(self.product.name).relative() + self.product.PUBLIC_HEADERS_FOLDER_PATH
generated += " -I" + Configuration.current.build_directory.path_by_appending(self.product.name).relative() + self.product.PRIVATE_HEADERS_FOLDER_PATH
generated += " -I" + Configuration.current.build_directory.path_by_appending(self.product.name).relative() + self.product.PROJECT_HEADERS_FOLDER_PATH
cflags = TargetConditional.value(self.product.CFLAGS)
if cflags is not None:
generated += " " + cflags
cxxflags = TargetConditional.value(self.product.CXXFLAGS)
if cxxflags is not None:
generated += " " + cxxflags
prefix = TargetConditional.value(self.product.GCC_PREFIX_HEADER)
if prefix is not None:
generated += " -include " + prefix
generated += "\n"
if self.path.extension() == ".mm" or "-x objective-c" in generated:
self.product.needs_objc = True
self.product.needs_stdcxx = True
return generated
class Assemble(CompileSource):
def __init__(self, path, product):
CompileSource.__init__(self, path, product)
def generate(self):
generated = """
build """ + self.output.relative() + """: Assemble """ + self.path.relative() + self.generate_dependencies() + """
flags = """
generated += " -I" + Configuration.current.build_directory.path_by_appending(self.product.name).relative()
generated += " -I" + Configuration.current.build_directory.relative()
generated += " -I" + Configuration.current.build_directory.path_by_appending(self.product.name).relative() + self.product.ROOT_HEADERS_FOLDER_PATH
generated += " -I" + Configuration.current.build_directory.path_by_appending(self.product.name).relative() + self.product.PUBLIC_HEADERS_FOLDER_PATH
generated += " -I" + Configuration.current.build_directory.path_by_appending(self.product.name).relative() + self.product.PRIVATE_HEADERS_FOLDER_PATH
generated += " -I" + Configuration.current.build_directory.path_by_appending(self.product.name).relative() + self.product.PROJECT_HEADERS_FOLDER_PATH
asflags = TargetConditional.value(self.product.ASFLAGS)
if asflags is not None:
generated += " " + asflags
return generated
class CompileSwift(CompileSource):
phase = None
def __init__(self, path, product, phase):
CompileSource.__init__(self, path, product)
self.phase = phase
def generate(self):
generated = """
build """ + self.output.relative() + """: CompileSwift """ + self.path.relative() + self.generate_dependencies() + """
module_sources = """ + self.module_sources + """
module_name = """ + self.product.name + """
flags = """
generated += " -I" + Configuration.current.build_directory.path_by_appending(self.product.name).relative()
generated += " -I" + Configuration.current.build_directory.path_by_appending(self.product.name).relative() + self.product.ROOT_HEADERS_FOLDER_PATH
generated += " -I" + Configuration.current.build_directory.relative()
swiftflags = TargetConditional.value(self.product.SWIFTCFLAGS)
# Force building in Swift 4 compatibility mode.
swiftflags += " -swift-version 4"
if swiftflags is not None:
generated += " " + swiftflags
return generated
@property
def module_sources(self):
sources = self.phase.module_sources(primary=self.path.absolute())
return " ".join(sources)
class BuildPhase(BuildAction):
previous = None
name = None
dependencies = None
actions = None
def __init__(self, name):
BuildAction.__init__(self)
self.dependencies = []
self.actions = []
self.name = name
def generate(self):
generated = ""
for action in self.actions:
action.dependencies = self.dependencies
generated += action.generate() + "\n"
rule = "build " + self.name + ": phony"
if self.previous is not None or len(self.actions) > 0:
rule += " |"
if self.previous is not None:
rule += " " + self.previous.name
for action in self.actions:
rule += " " + action.output.relative()
rule += "\n"
return generated + "\n" + rule
@property
def objects(self):
return []
class CopyHeaders(BuildPhase):
_public = []
_private = []
_project = []
_module = None
def __init__(self, public, private, project, module=None):
BuildPhase.__init__(self, "CopyHeaders")
if public is not None:
self._public = public
if private is not None:
self._private = private
if project is not None:
self._project = project
self._module = module
@property
def product(self):
return self._product
def set_product(self, product):
BuildAction.set_product(self, product)
self.actions = []
module = Path.path(TargetConditional.value(self._module))
if module is not None:
action = Cp(module, self.product.public_module_path.path_by_appending("module.modulemap"))
self.actions.append(action)
action.set_product(product)
for value in self._public:
header = Path.path(TargetConditional.value(value))
if header is None:
continue
action = Cp(header, self.product.public_headers_path.path_by_appending(header.basename()))
self.actions.append(action)
action.set_product(product)
for value in self._private:
header = Path.path(TargetConditional.value(value))
if header is None:
continue
action = Cp(header, self.product.private_headers_path.path_by_appending(header.basename()))
self.actions.append(action)
action.set_product(product)
for value in self._project:
header = Path.path(TargetConditional.value(value))
if header is None:
continue
action = Cp(header, self.product.project_headers_path.path_by_appending(header.basename()))
self.actions.append(action)
action.set_product(product)
class CopyResources(BuildPhase):
_resources = []
_resourcesDir = None
def __init__(self, outputDir, resources):
BuildPhase.__init__(self, "CopyResources")
if resources is not None:
self._resources = resources
self._resourcesDir = outputDir
@property
def product(self):
return self._product
def set_product(self, product):
BuildAction.set_product(self, product)
self.actions = []
for value in self._resources:
resource = Path.path(TargetConditional.value(value))
if resource is None:
continue
action = Cp(resource, Configuration.current.build_directory.path_by_appending(self._resourcesDir).path_by_appending(resource.basename()))
self.actions.append(action)
action.set_product(product)
class CompileSources(BuildPhase):
_sources = []
def __init__(self, sources):
BuildPhase.__init__(self, "CompileSources")
if sources is not None:
self._sources = sources
@property
def product(self):
return self._product
def set_product(self, product):
BuildAction.set_product(self, product)
self.actions = []
for value in self._sources:
source = Path.path(TargetConditional.value(value))
if source is None:
continue
action = CompileSource.compile(source, self)
if action is None:
print("Unable to compile source " + source.absolute())
assert action is not None
self.actions.append(action)
action.set_product(product)
@property
def objects(self):
objects = []
for action in self.actions:
objects.append(action.output.relative())
return objects
class MergeSwiftModule:
name = None
def __init__(self, module):
self.name = module\
@property
def output(self):
return Path.path(self.name)
class CompileSwiftSources(BuildPhase):
_sources = []
_module = None
def __init__(self, sources):
BuildPhase.__init__(self, "CompileSwiftSources")
if sources is not None:
self._sources = sources
@property
def product(self):
return self._product
def set_product(self, product):
BuildAction.set_product(self, product)
self.actions = []
for value in self._sources:
source = Path.path(TargetConditional.value(value))
if source is None:
continue
action = CompileSource.compile(source, self)
if action is None:
print("Unable to compile source " + source.absolute())
assert action is not None
self.actions.append(action)
action.set_product(product)
self._module = Configuration.current.build_directory.path_by_appending(self.product.name).path_by_appending(self.product.name + ".swiftmodule")
product.add_dependency(MergeSwiftModule(self._module.relative()))
def module_sources(self, primary):
modules = []
for value in self._sources:
source = Path.path(TargetConditional.value(value))
if source is None:
continue
if source.absolute() != primary:
modules.append(source.relative())
else:
modules.append("-primary-file")
modules.append(source.relative())
return modules
def generate(self):
generated = BuildPhase.generate(self)
generated += "\n\n"
objects = ""
partial_modules = ""
partial_docs = ""
for value in self._sources:
path = Path.path(value)
compiled = Configuration.current.build_directory.path_by_appending(self.product.name).path_by_appending(path.relative() + ".o")
objects += compiled.relative() + " "
partial_modules += compiled.relative() + ".~partial.swiftmodule "
partial_docs += compiled.relative() + ".~partial.swiftdoc "
generated += """
build """ + self._module.relative() + ": MergeSwiftModule " + objects + """
partials = """ + partial_modules + """
module_name = """ + self.product.name + """
flags = -I""" + self.product.public_module_path.relative() + """ """ + TargetConditional.value(self.product.SWIFTCFLAGS) + """ -emit-module-doc-path """ + self._module.parent().path_by_appending(self.product.name).relative() + """.swiftdoc
"""
return generated
@property
def objects(self):
objects = []
for action in self.actions:
objects.append(action.output.relative())
return objects
# This builds a Swift executable using one invocation of swiftc (no partial compilation)
class SwiftExecutable(BuildPhase):
executableName = None
sources = []
def __init__(self, executableName, sources):
BuildAction.__init__(self, output=executableName)
self.executableName = executableName
self.name = executableName
self.sources = sources
def generate(self):
appName = Configuration.current.build_directory.relative() + """/""" + self.executableName + """/""" + self.executableName
libDependencyName = self.product.product_name
swiftSources = ""
for value in self.sources:
resource = Path.path(TargetConditional.value(value))
if resource is None:
continue
swiftSources += " " + resource.relative()
# Note: Fix -swift-version 4 for now.
return """
build """ + appName + """: SwiftExecutable """ + swiftSources + self.generate_dependencies(libDependencyName) + """
flags = -swift-version 4 -I""" + Configuration.current.build_directory.path_by_appending(self.product.name).relative() + self.product.ROOT_HEADERS_FOLDER_PATH + " -I" + Configuration.current.build_directory.path_by_appending(self.product.name).relative() + " -L" + Configuration.current.build_directory.path_by_appending(self.product.name).relative() + " " + TargetConditional.value(self.product.SWIFTCFLAGS) + """
build """ + self.executableName + """: phony | """ + appName + """
"""