xref: /aosp_15_r20/external/sandboxed-api/sandboxed_api/bazel/llvm_config.bzl (revision ec63e07ab9515d95e79c211197c445ef84cefa6a)
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
17load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe")
18
19SYSTEM_LLVM_BAZEL_TEMPLATE = """package(default_visibility = ["//visibility:public"])
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.
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    ]),
35    includes = ["llvm-project-include"],
36    linkopts = [
37        "-lncurses",
38        "-lz",
39        "-L%{llvm_lib_dir}",
40        "-Wl,--start-group",
41        %{llvm_libs}
42        "-Wl,--end-group",
43    ],
44    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(
66        ["ls", "-1f"] +
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        ],
73    ).stdout.splitlines()
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(
84            ["ls", "-d1f"] +
85            [llvm_dir + "/lib64", llvm_dir + "/lib"],
86        ).stdout.splitlines()
87        if lib_dirs:
88            found = True
89
90    if found:
91        # Create stub targets in sub-packages
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        )
106        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")
230