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