[clang][modules] Don't prevent translation of FW_Private includes when explicitly...
[llvm-project.git] / utils / bazel / configure.bzl
blob88a576548e169574b35fcb8ccb9e15cdd2c51e0e
1 # This file is licensed under the Apache License v2.0 with LLVM Exceptions.
2 # See https://llvm.org/LICENSE.txt for license information.
3 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5 """Helper macros to configure the LLVM overlay project."""
7 load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe")
9 # Directory of overlay files relative to WORKSPACE
10 DEFAULT_OVERLAY_PATH = "llvm-project-overlay"
12 DEFAULT_TARGETS = [
13     "AArch64",
14     "AMDGPU",
15     "ARM",
16     "AVR",
17     "BPF",
18     "Hexagon",
19     "Lanai",
20     "LoongArch",
21     "Mips",
22     "MSP430",
23     "NVPTX",
24     "PowerPC",
25     "RISCV",
26     "Sparc",
27     "SystemZ",
28     "VE",
29     "WebAssembly",
30     "X86",
31     "XCore",
34 def _overlay_directories(repository_ctx):
35     src_path = repository_ctx.path(Label("@llvm-raw//:WORKSPACE")).dirname
36     bazel_path = src_path.get_child("utils").get_child("bazel")
37     overlay_path = bazel_path.get_child("llvm-project-overlay")
38     script_path = bazel_path.get_child("overlay_directories.py")
40     python_bin = repository_ctx.which("python3")
41     if not python_bin:
42         # Windows typically just defines "python" as python3. The script itself
43         # contains a check to ensure python3.
44         python_bin = repository_ctx.which("python")
46     if not python_bin:
47         fail("Failed to find python3 binary")
49     cmd = [
50         python_bin,
51         script_path,
52         "--src",
53         src_path,
54         "--overlay",
55         overlay_path,
56         "--target",
57         ".",
58     ]
59     exec_result = repository_ctx.execute(cmd, timeout = 20)
61     if exec_result.return_code != 0:
62         fail(("Failed to execute overlay script: '{cmd}'\n" +
63               "Exited with code {return_code}\n" +
64               "stdout:\n{stdout}\n" +
65               "stderr:\n{stderr}\n").format(
66             cmd = " ".join([str(arg) for arg in cmd]),
67             return_code = exec_result.return_code,
68             stdout = exec_result.stdout,
69             stderr = exec_result.stderr,
70         ))
72 def _extract_cmake_settings(repository_ctx, llvm_cmake):
73     # The list to be written to vars.bzl
74     # `CMAKE_CXX_STANDARD` may be used from WORKSPACE for the toolchain.
75     c = {
76         "CMAKE_CXX_STANDARD": None,
77         "LLVM_VERSION_MAJOR": None,
78         "LLVM_VERSION_MINOR": None,
79         "LLVM_VERSION_PATCH": None,
80     }
82     # It would be easier to use external commands like sed(1) and python.
83     # For portability, the parser should run on Starlark.
84     llvm_cmake_path = repository_ctx.path(Label("//:" + llvm_cmake))
85     for line in repository_ctx.read(llvm_cmake_path).splitlines():
86         # Extract "set ( FOO bar ... "
87         setfoo = line.partition("(")
88         if setfoo[1] != "(":
89             continue
90         if setfoo[0].strip().lower() != "set":
91             continue
93         # `kv` is assumed as \s*KEY\s+VAL\s*\).*
94         # Typical case is like
95         #   LLVM_REQUIRED_CXX_STANDARD 17)
96         # Possible case -- It should be ignored.
97         #   CMAKE_CXX_STANDARD ${...} CACHE STRING "...")
98         kv = setfoo[2].strip()
99         i = kv.find(" ")
100         if i < 0:
101             continue
102         k = kv[:i]
104         # Prefer LLVM_REQUIRED_CXX_STANDARD instead of CMAKE_CXX_STANDARD
105         if k == "LLVM_REQUIRED_CXX_STANDARD":
106             k = "CMAKE_CXX_STANDARD"
107             c[k] = None
108         if k not in c:
109             continue
111         # Skip if `CMAKE_CXX_STANDARD` is set with
112         # `LLVM_REQUIRED_CXX_STANDARD`.
113         # Then `v` will not be desired form, like "${...} CACHE"
114         if c[k] != None:
115             continue
117         # Pick up 1st word as the value.
118         # Note: It assumes unquoted word.
119         v = kv[i:].strip().partition(")")[0].partition(" ")[0]
120         c[k] = v
122     # Synthesize `LLVM_VERSION` for convenience.
123     c["LLVM_VERSION"] = "{}.{}.{}".format(
124         c["LLVM_VERSION_MAJOR"],
125         c["LLVM_VERSION_MINOR"],
126         c["LLVM_VERSION_PATCH"],
127     )
129     return c
131 def _write_dict_to_file(repository_ctx, filepath, header, vars):
132     # (fci + individual vars) + (fcd + dict items) + (fct)
133     fci = header
134     fcd = "\nllvm_vars={\n"
135     fct = "}\n"
137     for k, v in vars.items():
138         fci += '{} = "{}"\n'.format(k, v)
139         fcd += '    "{}": "{}",\n'.format(k, v)
141     repository_ctx.file(filepath, content = fci + fcd + fct)
143 def _llvm_configure_impl(repository_ctx):
144     _overlay_directories(repository_ctx)
146     llvm_cmake = "llvm/CMakeLists.txt"
147     vars = _extract_cmake_settings(
148         repository_ctx,
149         llvm_cmake,
150     )
152     _write_dict_to_file(
153         repository_ctx,
154         filepath = "vars.bzl",
155         header = "# Generated from {}\n\n".format(llvm_cmake),
156         vars = vars,
157     )
159     # Create a starlark file with the requested LLVM targets.
160     targets = repository_ctx.attr.targets
161     repository_ctx.file(
162         "llvm/targets.bzl",
163         content = "llvm_targets = " + str(targets),
164         executable = False,
165     )
167 llvm_configure = repository_rule(
168     implementation = _llvm_configure_impl,
169     local = True,
170     configure = True,
171     attrs = {
172         "targets": attr.string_list(default = DEFAULT_TARGETS),
173     },