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"
32 def _overlay_directories(repository_ctx):
33 src_path = repository_ctx.path(Label("@llvm-raw//:WORKSPACE")).dirname
34 bazel_path = src_path.get_child("utils").get_child("bazel")
35 overlay_path = bazel_path.get_child("llvm-project-overlay")
36 script_path = bazel_path.get_child("overlay_directories.py")
38 python_bin = repository_ctx.which("python3")
40 # Windows typically just defines "python" as python3. The script itself
41 # contains a check to ensure python3.
42 python_bin = repository_ctx.which("python")
45 fail("Failed to find python3 binary")
57 exec_result = repository_ctx.execute(cmd, timeout = 20)
59 if exec_result.return_code != 0:
60 fail(("Failed to execute overlay script: '{cmd}'\n" +
61 "Exited with code {return_code}\n" +
62 "stdout:\n{stdout}\n" +
63 "stderr:\n{stderr}\n").format(
64 cmd = " ".join([str(arg) for arg in cmd]),
65 return_code = exec_result.return_code,
66 stdout = exec_result.stdout,
67 stderr = exec_result.stderr,
70 def _extract_cmake_settings(repository_ctx, llvm_cmake):
71 # The list to be written to vars.bzl
72 # `CMAKE_CXX_STANDARD` may be used from WORKSPACE for the toolchain.
74 "CMAKE_CXX_STANDARD": None,
75 "LLVM_VERSION_MAJOR": None,
76 "LLVM_VERSION_MINOR": None,
77 "LLVM_VERSION_PATCH": None,
78 "LLVM_VERSION_SUFFIX": None,
81 # It would be easier to use external commands like sed(1) and python.
82 # For portability, the parser should run on Starlark.
83 llvm_cmake_path = repository_ctx.path(Label("//:" + llvm_cmake))
84 for line in repository_ctx.read(llvm_cmake_path).splitlines():
85 # Extract "set ( FOO bar ... "
86 setfoo = line.partition("(")
89 if setfoo[0].strip().lower() != "set":
92 # `kv` is assumed as \s*KEY\s+VAL\s*\).*
93 # Typical case is like
94 # LLVM_REQUIRED_CXX_STANDARD 17)
95 # Possible case -- It should be ignored.
96 # CMAKE_CXX_STANDARD ${...} CACHE STRING "...")
97 kv = setfoo[2].strip()
103 # Prefer LLVM_REQUIRED_CXX_STANDARD instead of CMAKE_CXX_STANDARD
104 if k == "LLVM_REQUIRED_CXX_STANDARD":
105 k = "CMAKE_CXX_STANDARD"
110 # Skip if `CMAKE_CXX_STANDARD` is set with
111 # `LLVM_REQUIRED_CXX_STANDARD`.
112 # Then `v` will not be desired form, like "${...} CACHE"
116 # Pick up 1st word as the value.
117 # Note: It assumes unquoted word.
118 v = kv[i:].strip().partition(")")[0].partition(" ")[0]
121 # Synthesize `LLVM_VERSION` for convenience.
122 c["LLVM_VERSION"] = "{}.{}.{}".format(
123 c["LLVM_VERSION_MAJOR"],
124 c["LLVM_VERSION_MINOR"],
125 c["LLVM_VERSION_PATCH"],
128 c["PACKAGE_VERSION"] = "{}.{}.{}{}".format(
129 c["LLVM_VERSION_MAJOR"],
130 c["LLVM_VERSION_MINOR"],
131 c["LLVM_VERSION_PATCH"],
132 c["LLVM_VERSION_SUFFIX"],
137 def _write_dict_to_file(repository_ctx, filepath, header, vars):
138 # (fci + individual vars) + (fcd + dict items) + (fct)
140 fcd = "\nllvm_vars={\n"
143 for k, v in vars.items():
144 fci += '{} = "{}"\n'.format(k, v)
145 fcd += ' "{}": "{}",\n'.format(k, v)
147 repository_ctx.file(filepath, content = fci + fcd + fct)
149 def _llvm_configure_impl(repository_ctx):
150 _overlay_directories(repository_ctx)
152 llvm_cmake = "llvm/CMakeLists.txt"
153 vars = _extract_cmake_settings(
158 # Grab version info and merge it with the other vars
159 version = _extract_cmake_settings(
161 "cmake/Modules/LLVMVersion.cmake",
163 version = {k: v for k, v in version.items() if v != None}
168 filepath = "vars.bzl",
169 header = "# Generated from {}\n\n".format(llvm_cmake),
173 # Create a starlark file with the requested LLVM targets.
174 targets = repository_ctx.attr.targets
177 content = "llvm_targets = " + str(targets),
181 llvm_configure = repository_rule(
182 implementation = _llvm_configure_impl,
186 "targets": attr.string_list(default = DEFAULT_TARGETS),