# Copyright (C) 2023 The Android Open Source Project # # 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. """ This file contains rules and logic to initialize GBL workspace. """ def _abs_path(repo_ctx, path): return repo_ctx.execute(["readlink", "-f", path]).stdout.strip("\n") def _dir_of(repo_ctx, path): return repo_ctx.execute(["dirname", _abs_path(repo_ctx, path)]).stdout.strip("\n") def _gbl_llvm_prebuilts_impl(repo_ctx): """Implementation for gbl_llvm_prebuilts The repository rule sets up a repo for hosting LLVM distribution and Linux sysroot. They can be provided manually via the `GBL_LLVM_PREBUILTS` and `GBL_LINUX_SYSROOT` environment variables. If they don't exist, the top-level workspace needs to define them in repo `@llvm_linux_x86_64_prebuilts` and `@linux_x86_64_sysroot` respectively. Only Linux x86_64 platform is supported. """ prebuilts = repo_ctx.os.environ.get("GBL_LLVM_PREBUILTS") if prebuilts: repo_ctx.symlink(prebuilts, "llvm-linux-x86") else: path = _dir_of(repo_ctx, repo_ctx.path(Label("@llvm_linux_x86_64_prebuilts//:BUILD.bazel"))) repo_ctx.symlink(path, "llvm-linux-x86") # Linux host toolchain additionally needs a sysroot linux_glibc = repo_ctx.os.environ.get("GBL_LINUX_SYSROOT") if linux_glibc: repo_ctx.symlink(linux_glibc, "linux_glibc") else: path = _dir_of(repo_ctx, repo_ctx.path(Label("@linux_x86_64_sysroot//:BUILD.bazel"))) repo_ctx.symlink(path, "linux_glibc") # Get the bin directory so that we can access other LLVM tools by path. gbl_llvm_bin_dir = _abs_path(repo_ctx, "llvm-linux-x86/bin") # Create a info.bzl file in the assembled repo to export header/library/tool paths. info_bzl_content = """ def gbl_llvm_tool_path(tool_name): return "{}/" + tool_name """.format(gbl_llvm_bin_dir) # Get the builtin include directories. clang = _abs_path(repo_ctx, "llvm-linux-x86/bin/clang") llvm_resource_dir = repo_ctx.execute([clang, "--print-resource-dir"]).stdout.strip("\n") info_bzl_content += """ LLVM_PREBUILTS_C_INCLUDE = "{}" LLVM_PREBUILTS_CPP_INCLUDE = "{}" """.format( "{}/include".format(llvm_resource_dir), _abs_path(repo_ctx, "llvm-linux-x86/include/c++/v1"), ) # Linux sysroot headers sysroot_includes = [ _abs_path(repo_ctx, "linux_glibc/sysroot/usr/include"), _abs_path(repo_ctx, "linux_glibc/sysroot/usr/include/x86_64-linux-gnu"), ] info_bzl_content += """ LINUX_SYSROOT_INCLUDES = [{}] """.format(",".join(["\"{}\"".format(inc) for inc in sysroot_includes])) repo_ctx.file("info.bzl", info_bzl_content) # The following files are needed for defining bindgen toolchain, we symlink them out to the # top level directory in case the the distribution repo has its own BUILD file which blocks # direct access. repo_ctx.symlink("llvm-linux-x86/bin/clang", "clang") # In some prebuilt versions, "libc++.so" is a symlink to "libc++.so.1" etc. We need to use the # same name as the actual library file name in cc_import(). Otherwise it complains it can't # find the shared object. libcpp_sharelib_path = _abs_path(repo_ctx, "llvm-linux-x86/lib/libc++.so") libcpp_base_name = repo_ctx.execute(["basename", libcpp_sharelib_path]).stdout.strip("\n") repo_ctx.symlink(libcpp_sharelib_path, libcpp_base_name) # Do the same for libclang.so in case it's a symlink. libclang_sharelib_path = _abs_path(repo_ctx, "llvm-linux-x86/lib/libclang.so") libclang_basename = repo_ctx.execute(["basename", libclang_sharelib_path]).stdout.strip("\n") repo_ctx.symlink(libclang_sharelib_path, libclang_basename) # Add a BUILD file to make it a package repo_ctx.file("BUILD", """ package( default_visibility = ["//visibility:public"], ) exports_files(glob(["**/*"])) sh_binary( name = "clang-bin", srcs = [":clang"], ) cc_import( name = "libc++", shared_library = ":{}", ) cc_import( name = "libclang", shared_library = ":{}", ) """.format(libcpp_base_name, libclang_basename)) gbl_llvm_prebuilts = repository_rule( implementation = _gbl_llvm_prebuilts_impl, local = True, environ = ["GBL_LLVM_PREBUILTS", "GBL_LINUX_SYSROOT"], ) # The current rust version used by GBL. This needs to be manually udpated when new version of # prebuilts is uploaded to https://android.googlesource.com/platform/prebuilts/rust/ GBL_RUST_VERSION = "1.77.1.p1" def _android_rust_prebuilts_impl(repo_ctx): """Assemble a rust toolchain repo from the Android rust prebuilts repo. The Android rust prebuilts repo is expected to be from https://android.googlesource.com/platform/prebuilts/rust/. Attributes: path (String): Relative path to the Android rust prebuilts repo. build_file (Label): Label of the build file to use. """ # We only support linux x86 platform. path = repo_ctx.workspace_root.get_child(repo_ctx.attr.path).get_child("linux-x86") # Symlink everything into the assembled repo. path = path.get_child(GBL_RUST_VERSION) for entry in path.readdir(): # Ignore native BUILD file as we'll use override from `ctx.attr.build_file` instead. if entry.basename == "BUILD" or entry.basename == "BUILD.bazel": continue repo_ctx.symlink(entry.realpath, entry.basename) # Symlink the provided build file repo_ctx.symlink(repo_ctx.attr.build_file, "BUILD") android_rust_prebuilts = repository_rule( implementation = _android_rust_prebuilts_impl, attrs = { "path": attr.string(mandatory = True), "build_file": attr.label(mandatory = True), }, )