| # Copyright 2016 The Bazel Authors. All rights reserved. | |
| # | |
| # Licensed under the Apache License, Version 2.0 (the "License"); | |
| # you may not use this file except in compliance with the License. | |
| # You may obtain a copy of the License at | |
| # | |
| # http://www.apache.org/licenses/LICENSE-2.0 | |
| # | |
| # Unless required by applicable law or agreed to in writing, software | |
| # distributed under the License is distributed on an "AS IS" BASIS, | |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| # See the License for the specific language governing permissions and | |
| # limitations under the License. | |
| """Module to add METADATA and cc toolchain targets to BUILD for all configs.""" | |
| import imp | |
| import os | |
| import shlex | |
| import shutil | |
| from string import Template | |
| import subprocess | |
| from util import get_autoconfig_target_name | |
| from util import get_date | |
| from util import get_git_root | |
| BUILD_EXTRA_LICENCE = """ | |
| licenses(["notice"]) # Apache 2.0 | |
| package(default_visibility = ["//visibility:public"]) | |
| """ | |
| GIT_ROOT = get_git_root() | |
| LICENCE_TPL = os.path.join(GIT_ROOT, "release", "license.tpl") | |
| CPP_TPL = os.path.join(GIT_ROOT, "release", "cc", "cpp.tpl") | |
| LATEST_TPL = os.path.join(GIT_ROOT, "release", "cc", "latest.tpl") | |
| SHA_MAP_FILE = os.path.join(GIT_ROOT, "rules/toolchain_containers.bzl") | |
| CLANG_REVISION_FILE = os.path.join(GIT_ROOT, "third_party/clang/revision.bzl") | |
| def create_targets(container_configs_list, bazel_version): | |
| """Creates the new docker_toolchain_autoconfig target if not exists. | |
| An example target located in configs/ubuntu16_04_clang/BUILD is: | |
| //configs/ubuntu16_04_clang:msan-ubuntu16_04-clang-1.0-bazel_0.15.0-autoconfig | |
| There is one target per container per Bazel version per config type. | |
| The script only creates new targets in the BUILD file if they do not exist, | |
| i.e. if a target for the given version of Bazel, type and config version | |
| already exists, then the script does not re-create it. | |
| Args: | |
| container_configs_list: list of ContainerConfigs, the list of | |
| ContainerConfigs to generate configs for. | |
| bazel_version: string, the version of Bazel used to generate the configs. | |
| """ | |
| container_sha_map = imp.load_source("toolchain_containers", SHA_MAP_FILE) | |
| clang_revision_map = imp.load_source("clang_revision", CLANG_REVISION_FILE) | |
| clang_revision = clang_revision_map.CLANG_REVISION | |
| for container_configs in container_configs_list: | |
| # Get the sha256 value of the container used to generate the configs. | |
| sha = container_sha_map.toolchain_container_sha256s()[ | |
| "%s_clang" % container_configs.distro] | |
| for config in container_configs.configs: | |
| # Get target basename from config definitions. | |
| target = get_autoconfig_target_name( | |
| config_type=config.config_type, | |
| distro=container_configs.distro, | |
| config_version=container_configs.version, | |
| bazel_version=bazel_version) | |
| with open(container_configs.get_target_build_path(), "a+") as build_file: | |
| if target not in build_file.read(): | |
| tpl_file_path = os.path.join(GIT_ROOT, "release", "cc", | |
| "%s.tpl" % config.config_type) | |
| with open(tpl_file_path, "r") as tpl_file: | |
| tpl = Template(tpl_file.read()).substitute( | |
| DATE=get_date(), | |
| DISTRO=container_configs.distro, | |
| CONFIG_VERSION=container_configs.version, | |
| BAZEL_VERSION=bazel_version, | |
| NAME=container_configs.image, | |
| SHA=sha, | |
| CLANG_REVISION=clang_revision) | |
| build_file.write(tpl) | |
| def update_latest_target_aliases(container_configs_list, bazel_version): | |
| """Updates the alias targets pointing to latest toolchain targets. | |
| Example latest aliases clang-ubuntu container are located in | |
| configs/ubuntu16_04_clang/latest/BUILD. | |
| There is one BUILD file to contain all aliases for a container_config. | |
| Args: | |
| container_configs_list: list of ContainerConfigs, the list of | |
| ContainerConfigs to generate configs for. | |
| bazel_version: string, the version of Bazel used to generate the configs. | |
| """ | |
| for container_configs in container_configs_list: | |
| constraints = list(container_configs.constraints) | |
| with open(container_configs.get_latest_aliases_build_path(), | |
| "w") as build_file: | |
| # Update the BUILD file with aliases for latest toolchain targets. | |
| with open(LATEST_TPL, "r") as tpl_file: | |
| tpl = Template(tpl_file.read()).substitute( | |
| CONFIG_VERSION=container_configs.version, | |
| BAZEL_VERSION=bazel_version, | |
| PACKAGE=container_configs.package, | |
| PLATFORM=container_configs.platform_target, | |
| CONFIG_TYPES=", ".join( | |
| [("\"%s\"" % config_type) | |
| for config_type in container_configs.config_types]), | |
| EXTRA_CONSTRAINTS="\n".join( | |
| [("\"%s\"," % constraint) for constraint in constraints]) | |
| ) | |
| build_file.write(tpl) | |
| def generate_toolchain_definition(container_configs_list, bazel_version): | |
| """Generates new cpp toolchain definitions. | |
| Example cpp toolchain definitions for clang-ubuntu container are located in | |
| configs/ubuntu16_04_clang/1.0/bazel_0.15.0/cpp/. | |
| There is one BUILD file to contain all cpp toolchain definitions for each | |
| config type (e.g. default, msan) per container per Bazel version. | |
| If the file already exists in this repo, the script will delete it and | |
| generate new one. | |
| Args: | |
| container_configs_list: list of ContainerConfigs, the list of | |
| ContainerConfigs to generate configs for. | |
| bazel_version: string, the version of Bazel used to generate the configs. | |
| """ | |
| for container_configs in container_configs_list: | |
| cpp_dir = os.path.dirname(container_configs.get_cpp_build_path()) | |
| # Remove old cpp directory if exists. | |
| if os.path.exists(cpp_dir): | |
| print("\nOld version of cpp toolchain definition already exists. " | |
| "Deleting and generating again.") | |
| shutil.rmtree(cpp_dir) | |
| os.makedirs(cpp_dir) | |
| with open(container_configs.get_cpp_build_path(), "w") as build_file: | |
| # Write license header. | |
| with open(LICENCE_TPL, "r") as license_header: | |
| build_file.write(license_header.read()) | |
| # Write extra license string required for BUILD file. | |
| build_file.write(BUILD_EXTRA_LICENCE) | |
| for config in container_configs.configs: | |
| with open(container_configs.get_cpp_build_path(), "a") as build_file: | |
| with open(CPP_TPL, "r") as tpl_file: | |
| # Merge constraint lists. Remove duplicates while perserving order. | |
| constraints = list(container_configs.constraints) | |
| for constraint in config.constraints: | |
| if constraint not in constraints: | |
| constraints.append(constraint) | |
| tpl = Template(tpl_file.read()).substitute( | |
| TYPE=config.config_type, | |
| CONFIG_VERSION=container_configs.version, | |
| BAZEL_VERSION=bazel_version, | |
| PACKAGE=container_configs.package, | |
| EXTRA_CONSTRAINTS="\n".join( | |
| [("\"%s\"," % constraint) for constraint in constraints])) | |
| build_file.write(tpl) | |
| subprocess.check_call( | |
| shlex.split("buildifier %s" % container_configs.get_cpp_build_path())) | |
| def generate_metadata(container_configs_list): | |
| """Creates the METADATA file with the container register path. | |
| Example METADATA file can be found at | |
| configs/ubuntu16_04_clang/1.0/bazel_0.15.0/default/METADATA. | |
| There is one METADATA file per container per Bazel version per config type. | |
| If the file already exists in this repo, the script will delete it and | |
| generate new one. | |
| Args: | |
| container_configs_list: list of ContainerConfigs, the list of | |
| ContainerConfigs to generate configs for. | |
| """ | |
| container_sha_map = imp.load_source("toolchain_containers", SHA_MAP_FILE) | |
| for container_configs in container_configs_list: | |
| # Get the sha256 value of the container used to generate the configs. | |
| sha = container_sha_map.toolchain_container_sha256s()[ | |
| "%s_clang" % container_configs.distro] | |
| for config in container_configs.configs: | |
| with open(config.get_metadata_path(), "w") as metadata_file: | |
| metadata_file.write("{image}@{sha}\n".format( | |
| image=container_configs.image, sha=sha)) |