xref: /aosp_15_r20/external/sandboxed-api/sandboxed_api/bazel/llvm_config.bzl (revision ec63e07ab9515d95e79c211197c445ef84cefa6a)
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