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