|
| 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 |
| 4 | + |
| 5 | +"""Configuration for the llvm-driver tool.""" |
| 6 | + |
| 7 | +load("@bazel_skylib//rules:common_settings.bzl", "BuildSettingInfo") |
| 8 | +load("@bazel_skylib//rules:expand_template.bzl", "expand_template") |
| 9 | + |
| 10 | +# Mapping from every tool to the cc_library that implements the tool's entrypoint. |
| 11 | +# TODO: uncomment the remaining targets after splitting them |
| 12 | +# into separate library/binary targets. |
| 13 | +_TOOLS = { |
| 14 | + # "clang-scan-deps": "//clang:clang-scan-deps-lib", |
| 15 | + # "clang": "//clang:clang-driver", |
| 16 | + # "dsymutil": "//llvm:dsymutil-lib", |
| 17 | + # "lld": "//lld:lld-lib", |
| 18 | + "llvm-ar": "//llvm:llvm-ar-lib", |
| 19 | + # "llvm-cxxfilt": "//llvm:llvm-cxxfilt-lib", |
| 20 | + # "llvm-dwp": "//llvm:llvm-dwp-lib", |
| 21 | + # "llvm-gsymutil": "//llvm:llvm-gsymutil-lib", |
| 22 | + # "llvm-ifs": "//llvm:llvm-ifs-lib", |
| 23 | + # "llvm-libtool-darwin": "//llvm:llvm-libtool-darwin-lib", |
| 24 | + # "llvm-lipo": "//llvm:llvm-lipo-lib", |
| 25 | + # "llvm-ml": "//llvm:llvm-ml-lib", |
| 26 | + # "llvm-mt": "//llvm:llvm-mt-lib", |
| 27 | + "llvm-nm": "//llvm:llvm-nm-lib", |
| 28 | + # "llvm-objcopy": "//llvm:llvm-objcopy-lib", |
| 29 | + # "llvm-objdump": "//llvm:llvm-objdump-lib", |
| 30 | + # "llvm-profdata": "//llvm:llvm-profdata-lib", |
| 31 | + # "llvm-rc": "//llvm:llvm-rc-lib", |
| 32 | + # "llvm-readobj": "//llvm:llvm-readobj-lib", |
| 33 | + "llvm-size": "//llvm:llvm-size-lib", |
| 34 | + # "llvm-symbolizer": "//llvm:llvm-symbolizer-lib", |
| 35 | + # "sancov": "//llvm:sancov-lib", |
| 36 | +} |
| 37 | + |
| 38 | +# Tools automatically get their own name as an alias, but there may be additional |
| 39 | +# aliases for a given tool. |
| 40 | +_EXTRA_ALIASES = { |
| 41 | + "clang": ["clang++", "clang-cl", "clang-cpp"], |
| 42 | + "lld": ["lld-link", "ld.lld", "ld64.lld", "wasm-ld"], |
| 43 | + "llvm-ar": ["ranlib", "lib", "dlltool"], |
| 44 | + "llvm-objcopy": ["bitcode-strip", "install-name-tool", "strip"], |
| 45 | + "llvm-objdump": ["otool"], |
| 46 | + "llvm-rc": ["windres"], |
| 47 | + "llvm-readobj": ["readelf"], |
| 48 | + "llvm-symbolizer": ["addr2line"], |
| 49 | +} |
| 50 | + |
| 51 | +def _validated_string_list_flag_impl(ctx): |
| 52 | + invalid_values = [v for v in ctx.build_setting_value if v not in ctx.attr.values] |
| 53 | + if invalid_values: |
| 54 | + fail("Tool(s) [{}] are not in the known list of tools: {}".format( |
| 55 | + ", ".join(invalid_values), |
| 56 | + ", ".join(ctx.attr.values), |
| 57 | + )) |
| 58 | + return BuildSettingInfo(value = ctx.build_setting_value) |
| 59 | + |
| 60 | +# Like string_list_flag, but with the validation that string_flag provides. |
| 61 | +_validated_string_list_flag = rule( |
| 62 | + implementation = _validated_string_list_flag_impl, |
| 63 | + build_setting = config.string_list(flag = True), |
| 64 | + attrs = { |
| 65 | + "values": attr.string_list( |
| 66 | + doc = "The list of allowed values for this setting. An error is raised if any other value is given.", |
| 67 | + ), |
| 68 | + }, |
| 69 | + doc = "A string list-typed build setting that can be set on the command line", |
| 70 | +) |
| 71 | + |
| 72 | +def generate_driver_selects(name): |
| 73 | + """Generates flags and config settings to configure the tool list. |
| 74 | +
|
| 75 | + By default, all supported tools are included in the "llvm" driver binary. |
| 76 | + To build only a subset, specify just the subset you want as the flag. |
| 77 | + For example, to produce a binary with just llvm-nm and llvm-size, run: |
| 78 | +
|
| 79 | + $ bazel build \ |
| 80 | + --@llvm-project//llvm:driver-tools=llvm-nm,llvm-size \ |
| 81 | + @llvm-project//llvm:llvm |
| 82 | +
|
| 83 | + Note: this assumes the flag name is "driver-tools" by being invoked as: |
| 84 | + generate_driver_selects(name = "driver-tools") |
| 85 | +
|
| 86 | + Args: |
| 87 | + name: the name of the flag that configures which tools are included. |
| 88 | + """ |
| 89 | + |
| 90 | + _validated_string_list_flag( |
| 91 | + name = name, |
| 92 | + build_setting_default = _TOOLS.keys(), |
| 93 | + values = _TOOLS.keys(), |
| 94 | + ) |
| 95 | + for tool in _TOOLS.keys(): |
| 96 | + native.config_setting( |
| 97 | + name = "{}-include-{}".format(name, tool), |
| 98 | + flag_values = {name: tool}, |
| 99 | + ) |
| 100 | + |
| 101 | +def select_driver_tools(flag): |
| 102 | + """Produce a list of tool deps based on generate_driver_selects(). |
| 103 | +
|
| 104 | + Args: |
| 105 | + flag: name that was used for generate_driver_selects(). |
| 106 | + Returns: |
| 107 | + List of tool deps based on generate_driver_selects(). |
| 108 | + """ |
| 109 | + tools = [] |
| 110 | + for tool, target in _TOOLS.items(): |
| 111 | + tools += select({ |
| 112 | + "{}-include-{}".format(flag, tool): [target], |
| 113 | + "//conditions:default": [], |
| 114 | + }) |
| 115 | + return tools |
| 116 | + |
| 117 | +def _generate_driver_tools_def_impl(ctx): |
| 118 | + # Depending on how the LLVM build files are included, |
| 119 | + # it may or may not have the @llvm-project repo prefix. |
| 120 | + # Compare just on the name. We could also include the package, |
| 121 | + # but the name itself is unique in practice. |
| 122 | + label_to_name = {Label(v).name: k for k, v in _TOOLS.items()} |
| 123 | + |
| 124 | + # Reverse sort by the *main* tool name, but keep aliases together. |
| 125 | + # This is consistent with how tools/llvm-driver/CMakeLists.txt does it, |
| 126 | + # and this makes sure that more specific tools are checked first. |
| 127 | + # For example, "clang-scan-deps" should not match "clang". |
| 128 | + tools = [label_to_name[tool.label.name] for tool in ctx.attr.driver_tools] |
| 129 | + tool_alias_pairs = [] |
| 130 | + for tool_name in reversed(tools): |
| 131 | + tool_alias_pairs.append((tool_name, tool_name)) |
| 132 | + for extra_alias in _EXTRA_ALIASES.get(tool_name, []): |
| 133 | + tool_alias_pairs.append((tool_name, extra_alias)) |
| 134 | + |
| 135 | + lines = [ |
| 136 | + 'LLVM_DRIVER_TOOL("{alias}", {tool})'.format( |
| 137 | + tool = tool_name.replace("-", "_"), |
| 138 | + alias = alias.removeprefix("llvm-"), |
| 139 | + ) |
| 140 | + for (tool_name, alias) in tool_alias_pairs |
| 141 | + ] |
| 142 | + lines.append("#undef LLVM_DRIVER_TOOL") |
| 143 | + |
| 144 | + ctx.actions.write( |
| 145 | + output = ctx.outputs.out, |
| 146 | + content = "\n".join(lines), |
| 147 | + ) |
| 148 | + |
| 149 | +generate_driver_tools_def = rule( |
| 150 | + implementation = _generate_driver_tools_def_impl, |
| 151 | + doc = """Generate a list of LLVM_DRIVER_TOOL macros. |
| 152 | +See tools/llvm-driver/CMakeLists.txt for the reference implementation.""", |
| 153 | + attrs = { |
| 154 | + "driver_tools": attr.label_list( |
| 155 | + doc = "List of tools to include in the generated header. Use select_driver_tools() to provide this.", |
| 156 | + providers = [CcInfo], |
| 157 | + ), |
| 158 | + "out": attr.output( |
| 159 | + doc = "Name of the generated .def output file.", |
| 160 | + mandatory = True, |
| 161 | + ), |
| 162 | + }, |
| 163 | +) |
| 164 | + |
| 165 | +def llvm_driver_cc_binary( |
| 166 | + name, |
| 167 | + deps = None, |
| 168 | + **kwargs): |
| 169 | + """cc_binary wrapper for binaries using the llvm-driver template.""" |
| 170 | + expand_template( |
| 171 | + name = "_gen_" + name, |
| 172 | + out = name + "-driver.cpp", |
| 173 | + substitutions = {"@TOOL_NAME@": name.replace("-", "_")}, |
| 174 | + template = "//llvm:cmake/modules/llvm-driver-template.cpp.in", |
| 175 | + ) |
| 176 | + deps = deps or [] |
| 177 | + native.cc_binary( |
| 178 | + name = name, |
| 179 | + srcs = [name + "-driver.cpp"], |
| 180 | + deps = deps + ["//llvm:Support"], |
| 181 | + **kwargs |
| 182 | + ) |
0 commit comments