[msan][NFCI] Add tests for Arm NEON saturating extract narrow (#125331)
[llvm-project.git] / utils / bazel / configure.bzl
blobc5da28845eccf2363517da57e59ad3d3627692c6
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 # Directory of overlay files relative to WORKSPACE
8 DEFAULT_OVERLAY_PATH = "llvm-project-overlay"
10 DEFAULT_TARGETS = [
11     "AArch64",
12     "AMDGPU",
13     "ARM",
14     "AVR",
15     "BPF",
16     "Hexagon",
17     "Lanai",
18     "LoongArch",
19     "Mips",
20     "MSP430",
21     "NVPTX",
22     "PowerPC",
23     "RISCV",
24     "Sparc",
25     "SPIRV",
26     "SystemZ",
27     "VE",
28     "WebAssembly",
29     "X86",
30     "XCore",
33 def _overlay_directories(repository_ctx):
34     src_path = repository_ctx.path(Label("@llvm-raw//:WORKSPACE")).dirname
35     bazel_path = src_path.get_child("utils").get_child("bazel")
36     overlay_path = bazel_path.get_child("llvm-project-overlay")
37     script_path = bazel_path.get_child("overlay_directories.py")
39     python_bin = repository_ctx.which("python3")
40     if not python_bin:
41         # Windows typically just defines "python" as python3. The script itself
42         # contains a check to ensure python3.
43         python_bin = repository_ctx.which("python")
45     if not python_bin:
46         fail("Failed to find python3 binary")
48     cmd = [
49         python_bin,
50         script_path,
51         "--src",
52         src_path,
53         "--overlay",
54         overlay_path,
55         "--target",
56         ".",
57     ]
58     exec_result = repository_ctx.execute(cmd, timeout = 20)
60     if exec_result.return_code != 0:
61         fail(("Failed to execute overlay script: '{cmd}'\n" +
62               "Exited with code {return_code}\n" +
63               "stdout:\n{stdout}\n" +
64               "stderr:\n{stderr}\n").format(
65             cmd = " ".join([str(arg) for arg in cmd]),
66             return_code = exec_result.return_code,
67             stdout = exec_result.stdout,
68             stderr = exec_result.stderr,
69         ))
71 def _extract_cmake_settings(repository_ctx, llvm_cmake):
72     # The list to be written to vars.bzl
73     # `CMAKE_CXX_STANDARD` may be used from WORKSPACE for the toolchain.
74     c = {
75         "CMAKE_CXX_STANDARD": None,
76         "LLVM_VERSION_MAJOR": None,
77         "LLVM_VERSION_MINOR": None,
78         "LLVM_VERSION_PATCH": None,
79         "LLVM_VERSION_SUFFIX": 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     c["PACKAGE_VERSION"] = "{}.{}.{}{}".format(
130         c["LLVM_VERSION_MAJOR"],
131         c["LLVM_VERSION_MINOR"],
132         c["LLVM_VERSION_PATCH"],
133         c["LLVM_VERSION_SUFFIX"],
134     )
136     return c
138 def _write_dict_to_file(repository_ctx, filepath, header, vars):
139     # (fci + individual vars) + (fcd + dict items) + (fct)
140     fci = header
141     fcd = "\nllvm_vars={\n"
142     fct = "}\n"
144     for k, v in vars.items():
145         fci += '{} = "{}"\n'.format(k, v)
146         fcd += '    "{}": "{}",\n'.format(k, v)
148     repository_ctx.file(filepath, content = fci + fcd + fct)
150 def _llvm_configure_impl(repository_ctx):
151     _overlay_directories(repository_ctx)
153     llvm_cmake = "llvm/CMakeLists.txt"
154     vars = _extract_cmake_settings(
155         repository_ctx,
156         llvm_cmake,
157     )
159     # Grab version info and merge it with the other vars
160     version = _extract_cmake_settings(
161         repository_ctx,
162         "cmake/Modules/LLVMVersion.cmake",
163     )
164     version = {k: v for k, v in version.items() if v != None}
165     vars.update(version)
167     _write_dict_to_file(
168         repository_ctx,
169         filepath = "vars.bzl",
170         header = "# Generated from {}\n\n".format(llvm_cmake),
171         vars = vars,
172     )
174     # Create a starlark file with the requested LLVM targets.
175     targets = repository_ctx.attr.targets
176     repository_ctx.file(
177         "llvm/targets.bzl",
178         content = "llvm_targets = " + str(targets),
179         executable = False,
180     )
182 llvm_configure = repository_rule(
183     implementation = _llvm_configure_impl,
184     local = True,
185     configure = True,
186     attrs = {
187         "targets": attr.string_list(default = DEFAULT_TARGETS),
188     },