blob: 025c532d5154d399034f7a1763f8a25d191eecad [file] [log] [blame]
Christian Blichmann74bb2c32022-04-01 00:54:51 -07001# 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
17load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe")
18
Christian Blichmanne98133c2022-04-04 01:00:12 -070019SYSTEM_LLVM_BAZEL_TEMPLATE = """package(default_visibility = ["//visibility:public"])
Christian Blichmann74bb2c32022-04-01 00:54:51 -070020# 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.
23cc_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 Blichmann74bb2c32022-04-01 00:54:51 -070035 includes = ["llvm-project-include"],
Christian Blichmanne98133c2022-04-04 01:00:12 -070036 linkopts = [
37 "-lncurses",
38 "-lz",
39 "-L%{llvm_lib_dir}",
40 "-Wl,--start-group",
41 %{llvm_libs}
42 "-Wl,--end-group",
43 ],
Christian Blichmann74bb2c32022-04-01 00:54:51 -070044 visibility = ["@llvm-project//clang:__pkg__"],
45)
46# Fake support library
47cc_library(name = "Support", deps = ["@llvm-project//llvm:llvm"])
48"""
49
50SYSTEM_CLANG_BAZEL = """package(default_visibility = ["//visibility:public"])
51# Fake libraries that just depend on a big library with all files.
52cc_library(name = "ast", deps = ["@llvm-project//llvm:llvm"])
53cc_library(name = "basic", deps = ["@llvm-project//llvm:llvm"])
54cc_library(name = "driver", deps = ["@llvm-project//llvm:llvm"])
55cc_library(name = "format", deps = ["@llvm-project//llvm:llvm"])
56cc_library(name = "frontend", deps = ["@llvm-project//llvm:llvm"])
57cc_library(name = "lex", deps = ["@llvm-project//llvm:llvm"])
58cc_library(name = "tooling", deps = ["@llvm-project//llvm:llvm"])
59"""
60
61def _use_system_llvm(ctx):
62 found = False
63
64 # Look for LLVM in known places
65 llvm_dirs = ctx.execute(
Christian Blichmanne98133c2022-04-04 01:00:12 -070066 ["ls", "-1f"] +
Christian Blichmann74bb2c32022-04-01 00:54:51 -070067 [
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 Blichmanne98133c2022-04-04 01:00:12 -070073 ).stdout.splitlines()
Christian Blichmann74bb2c32022-04-01 00:54:51 -070074 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 Blichmanne98133c2022-04-04 01:00:12 -070084 ["ls", "-d1f"] +
Christian Blichmann74bb2c32022-04-01 00:54:51 -070085 [llvm_dir + "/lib64", llvm_dir + "/lib"],
Christian Blichmanne98133c2022-04-04 01:00:12 -070086 ).stdout.splitlines()
Christian Blichmann74bb2c32022-04-01 00:54:51 -070087 if lib_dirs:
Christian Blichmann74bb2c32022-04-01 00:54:51 -070088 found = True
89
90 if found:
91 # Create stub targets in sub-packages
Christian Blichmanne98133c2022-04-04 01:00:12 -070092 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 Blichmann74bb2c32022-04-01 00:54:51 -0700106 ctx.file("clang/BUILD.bazel", SYSTEM_CLANG_BAZEL)
107 return found
108
109def _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
144DEFAULT_LLVM_COMMIT = "2c494f094123562275ae688bd9e946ae2a0b4f8b" # 2022-03-31
145DEFAULT_LLVM_SHA256 = "59b9431ae22f0ea5f2ce880925c0242b32a9e4f1ae8147deb2bb0fc19b53fa0d"
146
147def _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
191DEFAULT_TARGETS = ["AArch64", "ARM", "PowerPC", "X86"]
192
193llvm_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
205def _llvm_zlib_disable_impl(ctx):
206 ctx.file(
207 "BUILD.bazel",
208 """cc_library(name = "zlib", visibility = ["//visibility:public"])""",
209 executable = False,
210 )
211
212llvm_zlib_disable = repository_rule(
213 implementation = _llvm_zlib_disable_impl,
214)
215
216def _llvm_terminfo_disable(ctx):
217 ctx.file(
218 "BUILD.bazel",
219 """cc_library(name = "terminfo", visibility = ["//visibility:public"])""",
220 executable = False,
221 )
222
223llvm_terminfo_disable = repository_rule(
224 implementation = _llvm_terminfo_disable,
225)
226
227def llvm_disable_optional_support_deps():
228 maybe(llvm_zlib_disable, name = "llvm_zlib")
229 maybe(llvm_terminfo_disable, name = "llvm_terminfo")