1# Copyright (C) 2023 The Android Open Source Project 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15"""Defines a repository that provides all clang toolchains.""" 16 17# General comment on toolchain registration orders: 18# 19# "When using target patterns to register toolchains, the order in which 20# the individual toolchains are registered is determined by the following rules: 21# [...] 22# Within a package, toolchains are registered in the lexicographical order of their names." 23# 24# Toolchains in this repository is prefixed with numbers to show their ordering. 25# 26# See 27# https://bazel.build/extending/toolchains#registering-building-toolchains 28 29def _clang_toolchain_repository_impl(repository_ctx): 30 repository_ctx.file("WORKSPACE.bazel", """\ 31workspace(name = "{}") 32""".format(repository_ctx.attr.name)) 33 34 build_file_content = '''\ 35""" 36All clang toolchains used by Kleaf. 37""" 38load("@kernel_toolchain_info//:dict.bzl","VARS") 39load("{architecture_constants}", "SUPPORTED_ARCHITECTURES") 40load("{clang_toolchain}", "clang_toolchain") 41load("{versions}", "VERSIONS") 42'''.format( 43 architecture_constants = Label(":architecture_constants.bzl"), 44 clang_toolchain = Label(":clang_toolchain.bzl"), 45 versions = Label(":versions.bzl"), 46 ) 47 48 if "KLEAF_USER_CLANG_TOOLCHAIN_PATH" not in repository_ctx.os.environ: 49 build_file_content += _empty_clang_toolchain_build_file() 50 else: 51 build_file_content += _real_clang_toolchain_build_file(repository_ctx) 52 53 build_file_content += _common_aliases_build_file() 54 55 repository_ctx.file("BUILD.bazel", build_file_content) 56 57def _empty_clang_toolchain_build_file(): 58 build_file_content = '''\ 59 60load("{empty_toolchain}", "empty_toolchain") 61 62toolchain_type( 63 name = "empty_toolchain_type", 64 visibility = ["//visibility:private"], 65) 66 67[empty_toolchain( 68 name = "1_user_{{}}_clang_toolchain".format(arch.name), 69 toolchain_type = ":empty_toolchain_type", 70 visibility = ["//visibility:private"], 71) for arch in SUPPORTED_ARCHITECTURES] 72'''.format( 73 empty_toolchain = Label(":empty_toolchain.bzl"), 74 ) 75 return build_file_content 76 77def _real_clang_toolchain_build_file(repository_ctx): 78 user_clang_toolchain_path = repository_ctx.os.environ["KLEAF_USER_CLANG_TOOLCHAIN_PATH"] 79 user_clang_toolchain_path = repository_ctx.path(user_clang_toolchain_path) 80 81 # Symlink contents of user_clang_toolchain_path to the top of the repository 82 for subpath in user_clang_toolchain_path.readdir(): 83 if subpath.basename in ("BUILD.bazel", "BUILD", "WORKSPACE.bazel", "WORKSPACE"): 84 continue 85 86 subpath_s = str(subpath) 87 user_clang_toolchain_path_s = str(user_clang_toolchain_path) 88 if not subpath_s.startswith(user_clang_toolchain_path_s + "/"): 89 fail("FATAL: {} does not start with {}/".format( 90 subpath_s, 91 user_clang_toolchain_path_s, 92 )) 93 94 repository_ctx.symlink( 95 subpath, 96 subpath_s.removeprefix(user_clang_toolchain_path_s + "/"), 97 ) 98 99 build_file_content = '''\ 100 101package(default_visibility = ["//visibility:public"]) 102 103filegroup( 104 name = "binaries", 105 srcs = glob([ 106 "bin/*", 107 "lib/*", 108 "lib/x86_64-unknown-linux-gnu/*", 109 ]), 110) 111 112filegroup( 113 name = "includes", 114 srcs = glob([ 115 "lib/clang/*/include/**", 116 "include/c++/**", 117 "include/x86_64-unknown-linux-gnu/c++/**", 118 ]), 119) 120 121[clang_toolchain( 122 name = "1_user_{{}}_clang_toolchain".format(arch.name), 123 arch = arch, 124 clang_pkg = ":fake_anchor_target", 125 clang_version = "kleaf_user_clang_toolchain_skip_version_check", 126) for arch in SUPPORTED_ARCHITECTURES] 127'''.format( 128 architecture_constants = Label(":architecture_constants.bzl"), 129 clang_toolchain = Label(":clang_toolchain.bzl"), 130 versions = Label(":versions.bzl"), 131 ) 132 133 return build_file_content 134 135def _common_aliases_build_file(): 136 # Label(): Resolve the label against this extension (clang_toolchain_repository.bzl) so the 137 # workspace name is injected properly when //prebuilts is in a subworkspace. 138 # @<kleaf tooling workspace>//prebuilts/clang/host/linux-x86/kleaf 139 this_pkg = str(Label(":x")).removesuffix(":x") 140 141 # @<kleaf tooling workspace>//prebuilts/clang/host/linux-x86 142 linux_x86_pkg = this_pkg.removesuffix("/kleaf") 143 144 build_file_content = """ 145 146# Default toolchains. 147 148[clang_toolchain( 149 name = "2_versioned_{{}}_{{}}_clang_toolchain".format(version, arch.name), 150 clang_pkg = "{linux_x86_pkg}/clang-{{}}".format(version), 151 clang_version = version, 152 extra_compatible_with = ["{this_pkg}:{{}}".format(version)], 153 arch = arch, 154) for version in VERSIONS for arch in SUPPORTED_ARCHITECTURES] 155 156[clang_toolchain( 157 name = "3_default_{{}}_clang_toolchain".format(arch.name), 158 clang_pkg = "{linux_x86_pkg}/clang-{{}}".format(VARS["CLANG_VERSION"]), 159 clang_version = VARS["CLANG_VERSION"], 160 arch = arch, 161) for arch in SUPPORTED_ARCHITECTURES] 162 163""".format( 164 this_pkg = this_pkg, 165 linux_x86_pkg = linux_x86_pkg, 166 ) 167 168 return build_file_content 169 170clang_toolchain_repository = repository_rule( 171 doc = """Defines a repository that provides all clang toolchains Kleaf uses. 172 173 Register them as follows: 174 175 ``` 176 register_toolchains("@kleaf_clang_toolchain//:all") 177 ``` 178 179 The user clang toolchain is expected from the path defined in the 180 `KLEAF_USER_CLANG_TOOLCHAIN_PATH` environment variable, if set. 181""", 182 implementation = _clang_toolchain_repository_impl, 183 environ = [ 184 "KLEAF_USER_CLANG_TOOLCHAIN_PATH", 185 ], 186 local = True, 187) 188