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""" 16This file contains rules and logic to initialize GBL workspace. 17""" 18 19def _abs_path(repo_ctx, path): 20 return repo_ctx.execute(["readlink", "-f", path]).stdout.strip("\n") 21 22def _dir_of(repo_ctx, path): 23 return repo_ctx.execute(["dirname", _abs_path(repo_ctx, path)]).stdout.strip("\n") 24 25def _gbl_llvm_prebuilts_impl(repo_ctx): 26 """Implementation for gbl_llvm_prebuilts 27 28 The repository rule sets up a repo for hosting LLVM distribution and Linux sysroot. They can 29 be provided manually via the `GBL_LLVM_PREBUILTS` and `GBL_LINUX_SYSROOT` environment 30 variables. If they don't exist, the top-level workspace needs to define them in repo 31 `@llvm_linux_x86_64_prebuilts` and `@linux_x86_64_sysroot` respectively. 32 33 Only Linux x86_64 platform is supported. 34 """ 35 prebuilts = repo_ctx.os.environ.get("GBL_LLVM_PREBUILTS") 36 if prebuilts: 37 repo_ctx.symlink(prebuilts, "llvm-linux-x86") 38 else: 39 path = _dir_of(repo_ctx, repo_ctx.path(Label("@llvm_linux_x86_64_prebuilts//:BUILD.bazel"))) 40 repo_ctx.symlink(path, "llvm-linux-x86") 41 42 # Linux host toolchain additionally needs a sysroot 43 linux_glibc = repo_ctx.os.environ.get("GBL_LINUX_SYSROOT") 44 if linux_glibc: 45 repo_ctx.symlink(linux_glibc, "linux_glibc") 46 else: 47 path = _dir_of(repo_ctx, repo_ctx.path(Label("@linux_x86_64_sysroot//:BUILD.bazel"))) 48 repo_ctx.symlink(path, "linux_glibc") 49 50 # Get the bin directory so that we can access other LLVM tools by path. 51 gbl_llvm_bin_dir = _abs_path(repo_ctx, "llvm-linux-x86/bin") 52 53 # Create a info.bzl file in the assembled repo to export header/library/tool paths. 54 info_bzl_content = """ 55def gbl_llvm_tool_path(tool_name): 56 return "{}/" + tool_name 57""".format(gbl_llvm_bin_dir) 58 59 # Get the builtin include directories. 60 clang = _abs_path(repo_ctx, "llvm-linux-x86/bin/clang") 61 llvm_resource_dir = repo_ctx.execute([clang, "--print-resource-dir"]).stdout.strip("\n") 62 info_bzl_content += """ 63LLVM_PREBUILTS_C_INCLUDE = "{}" 64LLVM_PREBUILTS_CPP_INCLUDE = "{}" 65""".format( 66 "{}/include".format(llvm_resource_dir), 67 _abs_path(repo_ctx, "llvm-linux-x86/include/c++/v1"), 68 ) 69 70 # Linux sysroot headers 71 sysroot_includes = [ 72 _abs_path(repo_ctx, "linux_glibc/sysroot/usr/include"), 73 _abs_path(repo_ctx, "linux_glibc/sysroot/usr/include/x86_64-linux-gnu"), 74 ] 75 info_bzl_content += """ 76LINUX_SYSROOT_INCLUDES = [{}] 77""".format(",".join(["\"{}\"".format(inc) for inc in sysroot_includes])) 78 79 repo_ctx.file("info.bzl", info_bzl_content) 80 81 # The following files are needed for defining bindgen toolchain, we symlink them out to the 82 # top level directory in case the the distribution repo has its own BUILD file which blocks 83 # direct access. 84 repo_ctx.symlink("llvm-linux-x86/bin/clang", "clang") 85 86 # In some prebuilt versions, "libc++.so" is a symlink to "libc++.so.1" etc. We need to use the 87 # same name as the actual library file name in cc_import(). Otherwise it complains it can't 88 # find the shared object. 89 libcpp_sharelib_path = _abs_path(repo_ctx, "llvm-linux-x86/lib/libc++.so") 90 libcpp_base_name = repo_ctx.execute(["basename", libcpp_sharelib_path]).stdout.strip("\n") 91 repo_ctx.symlink(libcpp_sharelib_path, libcpp_base_name) 92 93 # Do the same for libclang.so in case it's a symlink. 94 libclang_sharelib_path = _abs_path(repo_ctx, "llvm-linux-x86/lib/libclang.so") 95 libclang_basename = repo_ctx.execute(["basename", libclang_sharelib_path]).stdout.strip("\n") 96 repo_ctx.symlink(libclang_sharelib_path, libclang_basename) 97 98 # Add a BUILD file to make it a package 99 repo_ctx.file("BUILD", """ 100package( 101 default_visibility = ["//visibility:public"], 102) 103 104exports_files(glob(["**/*"])) 105 106sh_binary( 107 name = "clang-bin", 108 srcs = [":clang"], 109) 110 111cc_import( 112 name = "libc++", 113 shared_library = ":{}", 114) 115 116cc_import( 117 name = "libclang", 118 shared_library = ":{}", 119) 120""".format(libcpp_base_name, libclang_basename)) 121 122gbl_llvm_prebuilts = repository_rule( 123 implementation = _gbl_llvm_prebuilts_impl, 124 local = True, 125 environ = ["GBL_LLVM_PREBUILTS", "GBL_LINUX_SYSROOT"], 126) 127 128# The current rust version used by GBL. This needs to be manually udpated when new version of 129# prebuilts is uploaded to https://android.googlesource.com/platform/prebuilts/rust/ 130GBL_RUST_VERSION = "1.77.1.p1" 131 132def _android_rust_prebuilts_impl(repo_ctx): 133 """Assemble a rust toolchain repo from the Android rust prebuilts repo. 134 135 The Android rust prebuilts repo is expected to be from 136 https://android.googlesource.com/platform/prebuilts/rust/. 137 138 Attributes: 139 path (String): Relative path to the Android rust prebuilts repo. 140 build_file (Label): Label of the build file to use. 141 """ 142 143 # We only support linux x86 platform. 144 path = repo_ctx.workspace_root.get_child(repo_ctx.attr.path).get_child("linux-x86") 145 146 # Symlink everything into the assembled repo. 147 path = path.get_child(GBL_RUST_VERSION) 148 for entry in path.readdir(): 149 # Ignore native BUILD file as we'll use override from `ctx.attr.build_file` instead. 150 if entry.basename == "BUILD" or entry.basename == "BUILD.bazel": 151 continue 152 repo_ctx.symlink(entry.realpath, entry.basename) 153 154 # Symlink the provided build file 155 repo_ctx.symlink(repo_ctx.attr.build_file, "BUILD") 156 157android_rust_prebuilts = repository_rule( 158 implementation = _android_rust_prebuilts_impl, 159 attrs = { 160 "path": attr.string(mandatory = True), 161 "build_file": attr.label(mandatory = True), 162 }, 163) 164