1*ec63e07aSXin Li# Copyright 2022 Google LLC 2*ec63e07aSXin Li# 3*ec63e07aSXin Li# Licensed under the Apache License, Version 2.0 (the "License"); 4*ec63e07aSXin Li# you may not use this file except in compliance with the License. 5*ec63e07aSXin Li# You may obtain a copy of the License at 6*ec63e07aSXin Li# 7*ec63e07aSXin Li# https://www.apache.org/licenses/LICENSE-2.0 8*ec63e07aSXin Li# 9*ec63e07aSXin Li# Unless required by applicable law or agreed to in writing, software 10*ec63e07aSXin Li# distributed under the License is distributed on an "AS IS" BASIS, 11*ec63e07aSXin Li# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*ec63e07aSXin Li# See the License for the specific language governing permissions and 13*ec63e07aSXin Li# limitations under the License. 14*ec63e07aSXin Li 15*ec63e07aSXin Li"""Repository rule that tries to find system provided LLVM packages.""" 16*ec63e07aSXin Li 17*ec63e07aSXin Liload("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe") 18*ec63e07aSXin Li 19*ec63e07aSXin LiSYSTEM_LLVM_BAZEL_TEMPLATE = """package(default_visibility = ["//visibility:public"]) 20*ec63e07aSXin Li# Create one hidden library with all LLVM headers that depends on all its 21*ec63e07aSXin Li# static library archives. This will be used to provide individual library 22*ec63e07aSXin Li# targets named the same as the upstream Bazel files. 23*ec63e07aSXin Licc_library( 24*ec63e07aSXin Li name = "llvm", 25*ec63e07aSXin Li hdrs = glob([ 26*ec63e07aSXin Li "llvm-project-include/clang-c/**/*.h", 27*ec63e07aSXin Li "llvm-project-include/clang/**/*.def", 28*ec63e07aSXin Li "llvm-project-include/clang/**/*.h", 29*ec63e07aSXin Li "llvm-project-include/clang/**/*.inc", 30*ec63e07aSXin Li "llvm-project-include/llvm-c/**/*.h", 31*ec63e07aSXin Li "llvm-project-include/llvm/**/*.def", 32*ec63e07aSXin Li "llvm-project-include/llvm/**/*.h", 33*ec63e07aSXin Li "llvm-project-include/llvm/**/*.inc", 34*ec63e07aSXin Li ]), 35*ec63e07aSXin Li includes = ["llvm-project-include"], 36*ec63e07aSXin Li linkopts = [ 37*ec63e07aSXin Li "-lncurses", 38*ec63e07aSXin Li "-lz", 39*ec63e07aSXin Li "-L%{llvm_lib_dir}", 40*ec63e07aSXin Li "-Wl,--start-group", 41*ec63e07aSXin Li %{llvm_libs} 42*ec63e07aSXin Li "-Wl,--end-group", 43*ec63e07aSXin Li ], 44*ec63e07aSXin Li visibility = ["@llvm-project//clang:__pkg__"], 45*ec63e07aSXin Li) 46*ec63e07aSXin Li# Fake support library 47*ec63e07aSXin Licc_library(name = "Support", deps = ["@llvm-project//llvm:llvm"]) 48*ec63e07aSXin Li""" 49*ec63e07aSXin Li 50*ec63e07aSXin LiSYSTEM_CLANG_BAZEL = """package(default_visibility = ["//visibility:public"]) 51*ec63e07aSXin Li# Fake libraries that just depend on a big library with all files. 52*ec63e07aSXin Licc_library(name = "ast", deps = ["@llvm-project//llvm:llvm"]) 53*ec63e07aSXin Licc_library(name = "basic", deps = ["@llvm-project//llvm:llvm"]) 54*ec63e07aSXin Licc_library(name = "driver", deps = ["@llvm-project//llvm:llvm"]) 55*ec63e07aSXin Licc_library(name = "format", deps = ["@llvm-project//llvm:llvm"]) 56*ec63e07aSXin Licc_library(name = "frontend", deps = ["@llvm-project//llvm:llvm"]) 57*ec63e07aSXin Licc_library(name = "lex", deps = ["@llvm-project//llvm:llvm"]) 58*ec63e07aSXin Licc_library(name = "tooling", deps = ["@llvm-project//llvm:llvm"]) 59*ec63e07aSXin Li""" 60*ec63e07aSXin Li 61*ec63e07aSXin Lidef _use_system_llvm(ctx): 62*ec63e07aSXin Li found = False 63*ec63e07aSXin Li 64*ec63e07aSXin Li # Look for LLVM in known places 65*ec63e07aSXin Li llvm_dirs = ctx.execute( 66*ec63e07aSXin Li ["ls", "-1f"] + 67*ec63e07aSXin Li [ 68*ec63e07aSXin Li "/usr/lib/llvm-{}/include/llvm/Support/InitLLVM.h".format(ver) 69*ec63e07aSXin Li for ver in [16, 15, 14, 13, 12, 11] # Debian 70*ec63e07aSXin Li ] + [ 71*ec63e07aSXin Li "/usr/include/llvm/Support/InitLLVM.h", # Fedora and others 72*ec63e07aSXin Li ], 73*ec63e07aSXin Li ).stdout.splitlines() 74*ec63e07aSXin Li if llvm_dirs: 75*ec63e07aSXin Li llvm_dir = llvm_dirs[0].split("/include/llvm/")[0] 76*ec63e07aSXin Li for suffix in ["llvm", "llvm-c", "clang", "clang-c"]: 77*ec63e07aSXin Li ctx.symlink( 78*ec63e07aSXin Li llvm_dir + "/include/" + suffix, 79*ec63e07aSXin Li "llvm/llvm-project-include/" + suffix, 80*ec63e07aSXin Li ) 81*ec63e07aSXin Li 82*ec63e07aSXin Li # Try to find the lib directory 83*ec63e07aSXin Li lib_dirs = ctx.execute( 84*ec63e07aSXin Li ["ls", "-d1f"] + 85*ec63e07aSXin Li [llvm_dir + "/lib64", llvm_dir + "/lib"], 86*ec63e07aSXin Li ).stdout.splitlines() 87*ec63e07aSXin Li if lib_dirs: 88*ec63e07aSXin Li found = True 89*ec63e07aSXin Li 90*ec63e07aSXin Li if found: 91*ec63e07aSXin Li # Create stub targets in sub-packages 92*ec63e07aSXin Li lib_dir = lib_dirs[0] # buildifier: disable=uninitialized 93*ec63e07aSXin Li archives = ctx.execute( 94*ec63e07aSXin Li ["find", ".", "-maxdepth", "1"] + 95*ec63e07aSXin Li ["(", "-name", "libLLVM*.a", "-o", "-name", "libclang*.a", ")"], 96*ec63e07aSXin Li working_directory = lib_dir, 97*ec63e07aSXin Li ).stdout.splitlines() 98*ec63e07aSXin Li lib_strs = sorted(["\"-l{}\",".format(a[5:-2]) for a in archives]) 99*ec63e07aSXin Li 100*ec63e07aSXin Li ctx.file( 101*ec63e07aSXin Li "llvm/BUILD.bazel", 102*ec63e07aSXin Li SYSTEM_LLVM_BAZEL_TEMPLATE 103*ec63e07aSXin Li .replace("%{llvm_lib_dir}", lib_dir) 104*ec63e07aSXin Li .replace("%{llvm_libs}", "\n".join(lib_strs)), 105*ec63e07aSXin Li ) 106*ec63e07aSXin Li ctx.file("clang/BUILD.bazel", SYSTEM_CLANG_BAZEL) 107*ec63e07aSXin Li return found 108*ec63e07aSXin Li 109*ec63e07aSXin Lidef _overlay_directories(ctx, src_path, target_path): 110*ec63e07aSXin Li bazel_path = src_path.get_child("utils").get_child("bazel") 111*ec63e07aSXin Li overlay_path = bazel_path.get_child("llvm-project-overlay") 112*ec63e07aSXin Li script_path = bazel_path.get_child("overlay_directories.py") 113*ec63e07aSXin Li 114*ec63e07aSXin Li python_bin = ctx.which("python3") 115*ec63e07aSXin Li if not python_bin: 116*ec63e07aSXin Li python_bin = ctx.which("python") 117*ec63e07aSXin Li 118*ec63e07aSXin Li if not python_bin: 119*ec63e07aSXin Li fail("Failed to find python3 binary") 120*ec63e07aSXin Li 121*ec63e07aSXin Li cmd = [ 122*ec63e07aSXin Li python_bin, 123*ec63e07aSXin Li script_path, 124*ec63e07aSXin Li "--src", 125*ec63e07aSXin Li src_path, 126*ec63e07aSXin Li "--overlay", 127*ec63e07aSXin Li overlay_path, 128*ec63e07aSXin Li "--target", 129*ec63e07aSXin Li target_path, 130*ec63e07aSXin Li ] 131*ec63e07aSXin Li exec_result = ctx.execute(cmd, timeout = 20) 132*ec63e07aSXin Li 133*ec63e07aSXin Li if exec_result.return_code != 0: 134*ec63e07aSXin Li fail(("Failed to execute overlay script: '{cmd}'\n" + 135*ec63e07aSXin Li "Exited with code {return_code}\n" + 136*ec63e07aSXin Li "stdout:\n{stdout}\n" + 137*ec63e07aSXin Li "stderr:\n{stderr}\n").format( 138*ec63e07aSXin Li cmd = " ".join([str(arg) for arg in cmd]), 139*ec63e07aSXin Li return_code = exec_result.return_code, 140*ec63e07aSXin Li stdout = exec_result.stdout, 141*ec63e07aSXin Li stderr = exec_result.stderr, 142*ec63e07aSXin Li )) 143*ec63e07aSXin Li 144*ec63e07aSXin LiDEFAULT_LLVM_COMMIT = "2c494f094123562275ae688bd9e946ae2a0b4f8b" # 2022-03-31 145*ec63e07aSXin LiDEFAULT_LLVM_SHA256 = "59b9431ae22f0ea5f2ce880925c0242b32a9e4f1ae8147deb2bb0fc19b53fa0d" 146*ec63e07aSXin Li 147*ec63e07aSXin Lidef _llvm_configure_impl(ctx): 148*ec63e07aSXin Li commit = ctx.attr.commit 149*ec63e07aSXin Li sha256 = ctx.attr.sha256 150*ec63e07aSXin Li 151*ec63e07aSXin Li if ctx.attr.system_libraries: 152*ec63e07aSXin Li if _use_system_llvm(ctx): 153*ec63e07aSXin Li return 154*ec63e07aSXin Li if not commit: 155*ec63e07aSXin Li fail(( 156*ec63e07aSXin Li "Failed to find LLVM and clang system libraries\n\n" + 157*ec63e07aSXin Li "Note: You may have to install llvm-13-dev and libclang-13-dev\n" + 158*ec63e07aSXin Li " packages (or later versions) first.\n" 159*ec63e07aSXin Li )) 160*ec63e07aSXin Li 161*ec63e07aSXin Li if not commit: 162*ec63e07aSXin Li commit = DEFAULT_LLVM_COMMIT 163*ec63e07aSXin Li sha256 = DEFAULT_LLVM_SHA256 164*ec63e07aSXin Li 165*ec63e07aSXin Li ctx.download_and_extract( 166*ec63e07aSXin Li ["https://github.com/llvm/llvm-project/archive/{commit}.tar.gz".format(commit = commit)], 167*ec63e07aSXin Li "llvm-raw", 168*ec63e07aSXin Li sha256, 169*ec63e07aSXin Li "", 170*ec63e07aSXin Li "llvm-project-" + commit, 171*ec63e07aSXin Li ) 172*ec63e07aSXin Li 173*ec63e07aSXin Li target_path = ctx.path("llvm-raw").dirname 174*ec63e07aSXin Li src_path = target_path.get_child("llvm-raw") 175*ec63e07aSXin Li _overlay_directories(ctx, src_path, target_path) 176*ec63e07aSXin Li 177*ec63e07aSXin Li # Create a starlark file with the requested LLVM targets 178*ec63e07aSXin Li ctx.file( 179*ec63e07aSXin Li "llvm/targets.bzl", 180*ec63e07aSXin Li "llvm_targets = " + str(ctx.attr.targets), 181*ec63e07aSXin Li executable = False, 182*ec63e07aSXin Li ) 183*ec63e07aSXin Li 184*ec63e07aSXin Li # Set up C++ toolchain options. LLVM requires at least C++ 14. 185*ec63e07aSXin Li ctx.file( 186*ec63e07aSXin Li ".bazelrc", 187*ec63e07aSXin Li "build --cxxopt=-std=c++17 --host_cxxopt=-std=c++17", 188*ec63e07aSXin Li executable = False, 189*ec63e07aSXin Li ) 190*ec63e07aSXin Li 191*ec63e07aSXin LiDEFAULT_TARGETS = ["AArch64", "ARM", "PowerPC", "X86"] 192*ec63e07aSXin Li 193*ec63e07aSXin Lillvm_configure = repository_rule( 194*ec63e07aSXin Li implementation = _llvm_configure_impl, 195*ec63e07aSXin Li local = True, 196*ec63e07aSXin Li configure = True, 197*ec63e07aSXin Li attrs = { 198*ec63e07aSXin Li "system_libraries": attr.bool(default = True), 199*ec63e07aSXin Li "commit": attr.string(), 200*ec63e07aSXin Li "sha256": attr.string(), 201*ec63e07aSXin Li "targets": attr.string_list(default = DEFAULT_TARGETS), 202*ec63e07aSXin Li }, 203*ec63e07aSXin Li) 204*ec63e07aSXin Li 205*ec63e07aSXin Lidef _llvm_zlib_disable_impl(ctx): 206*ec63e07aSXin Li ctx.file( 207*ec63e07aSXin Li "BUILD.bazel", 208*ec63e07aSXin Li """cc_library(name = "zlib", visibility = ["//visibility:public"])""", 209*ec63e07aSXin Li executable = False, 210*ec63e07aSXin Li ) 211*ec63e07aSXin Li 212*ec63e07aSXin Lillvm_zlib_disable = repository_rule( 213*ec63e07aSXin Li implementation = _llvm_zlib_disable_impl, 214*ec63e07aSXin Li) 215*ec63e07aSXin Li 216*ec63e07aSXin Lidef _llvm_terminfo_disable(ctx): 217*ec63e07aSXin Li ctx.file( 218*ec63e07aSXin Li "BUILD.bazel", 219*ec63e07aSXin Li """cc_library(name = "terminfo", visibility = ["//visibility:public"])""", 220*ec63e07aSXin Li executable = False, 221*ec63e07aSXin Li ) 222*ec63e07aSXin Li 223*ec63e07aSXin Lillvm_terminfo_disable = repository_rule( 224*ec63e07aSXin Li implementation = _llvm_terminfo_disable, 225*ec63e07aSXin Li) 226*ec63e07aSXin Li 227*ec63e07aSXin Lidef llvm_disable_optional_support_deps(): 228*ec63e07aSXin Li maybe(llvm_zlib_disable, name = "llvm_zlib") 229*ec63e07aSXin Li maybe(llvm_terminfo_disable, name = "llvm_terminfo") 230