1""" 2This file specifies a clang toolchain that can run on a Linux host which does depend on any 3installed packages from the host machine. 4 5See build_toolchain.bzl for more details on the creation of the toolchain. 6 7It uses the usr subfolder of the built toolchain as a sysroot 8 9It follows the example of: 10 - https://docs.bazel.build/versions/4.2.1/tutorial/cc-toolchain-config.html 11 - https://github.com/emscripten-core/emsdk/blob/7f39d100d8cd207094decea907121df72065517e/bazel/emscripten_toolchain/crosstool.bzl 12""" 13 14load( 15 "@bazel_tools//tools/cpp:cc_toolchain_config_lib.bzl", 16 "action_config", 17 "feature", 18 "flag_group", 19 "flag_set", 20 "tool", 21 "variable_with_value", 22) 23load("@bazel_tools//tools/build_defs/cc:action_names.bzl", "ACTION_NAMES") 24 25# The location of the created clang toolchain. 26EXTERNAL_TOOLCHAIN = "external/clang_linux_amd64_musl" 27 28def _clang_impl(ctx): 29 action_configs = _make_action_configs() 30 features = [] 31 features += _make_default_flags() 32 features += _make_diagnostic_flags() 33 34 # https://docs.bazel.build/versions/main/skylark/lib/cc_common.html#create_cc_toolchain_config_info 35 # Note, this rule is defined in Java code, not Starlark 36 # https://cs.opensource.google/bazel/bazel/+/master:src/main/java/com/google/devtools/build/lib/starlarkbuildapi/cpp/CcModuleApi.java 37 return cc_common.create_cc_toolchain_config_info( 38 ctx = ctx, 39 features = features, 40 abi_libc_version = "unknown", 41 abi_version = "unknown", 42 action_configs = action_configs, 43 builtin_sysroot = EXTERNAL_TOOLCHAIN + "/usr", 44 compiler = "clang", 45 host_system_name = "local", 46 target_cpu = "k8", 47 target_libc = "musl", 48 target_system_name = "local", 49 toolchain_identifier = "clang-toolchain", 50 ) 51 52provide_clang_toolchain_config = rule( 53 attrs = {}, 54 provides = [CcToolchainConfigInfo], 55 implementation = _clang_impl, 56) 57 58def _make_action_configs(): 59 """ 60 This function sets up the tools needed to perform the various compile/link actions. 61 62 Bazel normally restricts us to referring to (and therefore running) executables/scripts 63 that are in this directory (That is EXEC_ROOT/toolchain). However, the executables we want 64 to run are brought in via WORKSPACE.bazel and are located in EXEC_ROOT/external/clang.... 65 Therefore, we make use of "trampoline scripts" that will call the binaries from the 66 toolchain directory. 67 68 These action_configs also let us dynamically specify arguments from the Bazel 69 environment if necessary (see cpp_link_static_library_action). 70 """ 71 72 # https://cs.opensource.google/bazel/bazel/+/master:tools/cpp/cc_toolchain_config_lib.bzl;l=435;drc=3b9e6f201a9a3465720aad8712ab7bcdeaf2e5da 73 clang_tool = tool(path = "clang_trampoline.sh") 74 lld_tool = tool(path = "lld_trampoline.sh") 75 ar_tool = tool(path = "ar_trampoline.sh") 76 77 # https://cs.opensource.google/bazel/bazel/+/master:tools/cpp/cc_toolchain_config_lib.bzl;l=488;drc=3b9e6f201a9a3465720aad8712ab7bcdeaf2e5da 78 assemble_action = action_config( 79 action_name = ACTION_NAMES.assemble, 80 tools = [clang_tool], 81 ) 82 c_compile_action = action_config( 83 action_name = ACTION_NAMES.c_compile, 84 tools = [clang_tool], 85 ) 86 cpp_compile_action = action_config( 87 action_name = ACTION_NAMES.cpp_compile, 88 tools = [clang_tool], 89 ) 90 linkstamp_compile_action = action_config( 91 action_name = ACTION_NAMES.linkstamp_compile, 92 tools = [clang_tool], 93 ) 94 preprocess_assemble_action = action_config( 95 action_name = ACTION_NAMES.preprocess_assemble, 96 tools = [clang_tool], 97 ) 98 99 cpp_link_dynamic_library_action = action_config( 100 action_name = ACTION_NAMES.cpp_link_dynamic_library, 101 tools = [lld_tool], 102 ) 103 cpp_link_executable_action = action_config( 104 action_name = ACTION_NAMES.cpp_link_executable, 105 # Bazel assumes it is talking to clang when building an executable. There are 106 # "-Wl" flags on the command: https://releases.llvm.org/6.0.1/tools/clang/docs/ClangCommandLineReference.html#cmdoption-clang-Wl 107 tools = [clang_tool], 108 ) 109 cpp_link_nodeps_dynamic_library_action = action_config( 110 action_name = ACTION_NAMES.cpp_link_nodeps_dynamic_library, 111 tools = [lld_tool], 112 ) 113 114 # This is the same rule as 115 # https://github.com/emscripten-core/emsdk/blob/7f39d100d8cd207094decea907121df72065517e/bazel/emscripten_toolchain/crosstool.bzl#L143 116 # By default, there are no flags or libraries passed to the llvm-ar tool, so 117 # we need to specify them. The variables mentioned by expand_if_available are defined 118 # https://docs.bazel.build/versions/main/cc-toolchain-config-reference.html#cctoolchainconfiginfo-build-variables 119 cpp_link_static_library_action = action_config( 120 action_name = ACTION_NAMES.cpp_link_static_library, 121 flag_sets = [ 122 flag_set( 123 flag_groups = [ 124 flag_group( 125 # https://llvm.org/docs/CommandGuide/llvm-ar.html 126 # replace existing files or insert them if they already exist, 127 # create the file if it doesn't already exist 128 # symbol table should be added 129 # Deterministic timestamps should be used 130 flags = ["rcsD", "%{output_execpath}"], 131 # Despite the name, output_execpath just refers to linker output, 132 # e.g. libFoo.a 133 expand_if_available = "output_execpath", 134 ), 135 ], 136 ), 137 flag_set( 138 flag_groups = [ 139 flag_group( 140 iterate_over = "libraries_to_link", 141 flag_groups = [ 142 flag_group( 143 flags = ["%{libraries_to_link.name}"], 144 expand_if_equal = variable_with_value( 145 name = "libraries_to_link.type", 146 value = "object_file", 147 ), 148 ), 149 flag_group( 150 flags = ["%{libraries_to_link.object_files}"], 151 iterate_over = "libraries_to_link.object_files", 152 expand_if_equal = variable_with_value( 153 name = "libraries_to_link.type", 154 value = "object_file_group", 155 ), 156 ), 157 ], 158 expand_if_available = "libraries_to_link", 159 ), 160 ], 161 ), 162 flag_set( 163 flag_groups = [ 164 flag_group( 165 flags = ["@%{linker_param_file}"], 166 expand_if_available = "linker_param_file", 167 ), 168 ], 169 ), 170 ], 171 tools = [ar_tool], 172 ) 173 174 action_configs = [ 175 assemble_action, 176 c_compile_action, 177 cpp_compile_action, 178 cpp_link_dynamic_library_action, 179 cpp_link_executable_action, 180 cpp_link_nodeps_dynamic_library_action, 181 cpp_link_static_library_action, 182 linkstamp_compile_action, 183 preprocess_assemble_action, 184 ] 185 return action_configs 186 187def _make_default_flags(): 188 """Here we define the flags for certain actions that are always applied.""" 189 cxx_compile_includes = flag_set( 190 actions = [ 191 ACTION_NAMES.c_compile, 192 ACTION_NAMES.cpp_compile, 193 ], 194 flag_groups = [ 195 flag_group( 196 flags = [ 197 # THIS ORDER MATTERS GREATLY. If these are in the wrong order, the 198 # #include_next directives will walk off the end of the specified system 199 # folders here and look in the absolute path that happens to contain 200 # the clang executable. Because that looks like an absolute path to 201 # Bazel, it will declare the Build is not properly specified (that is, 202 # it appears to use headers outside of Bazel's control/view) and fail. 203 "-isystem", 204 EXTERNAL_TOOLCHAIN + "/include/c++/v1", 205 "-isystem", 206 EXTERNAL_TOOLCHAIN + "/lib/clang/13.0.0/include", 207 "-isystem", 208 EXTERNAL_TOOLCHAIN + "/usr/include/x86_64-linux-musl", 209 ], 210 ), 211 ], 212 ) 213 214 cpp_compile_includes = flag_set( 215 actions = [ 216 ACTION_NAMES.cpp_compile, 217 ], 218 flag_groups = [ 219 flag_group( 220 flags = [ 221 # http://g/skia-staff/bhPPBV4YdeU/5oyG5GRgBQAJ 222 "-std=c++14", 223 "-Wno-c++17-extensions", 224 "-Wno-psabi", # noisy 225 # This define allows libc++ to work with musl. They were discovered by 226 # trying to compile without them, reading errors and source code, e.g. 227 # https://github.com/llvm/llvm-project/blob/f4c1258d5633fcf06385ff3fd1f4bf57ab971964/libcxx/include/__locale#L513 228 # https://github.com/llvm/llvm-project/blob/f4c1258d5633fcf06385ff3fd1f4bf57ab971964/libcxx/include/__config#L1155 229 # https://github.com/llvm/llvm-project/blob/f4c1258d5633fcf06385ff3fd1f4bf57ab971964/libcxx/include/__support/musl/xlocale.h 230 "-D_LIBCPP_HAS_MUSL_LIBC", 231 ], 232 ), 233 ], 234 ) 235 236 link_exe_flags = flag_set( 237 actions = [ACTION_NAMES.cpp_link_executable], 238 flag_groups = [ 239 flag_group( 240 flags = [ 241 "-fuse-ld=lld", 242 # This is the path to libc.a and other libraries. 243 "-L" + EXTERNAL_TOOLCHAIN + "/usr/lib/x86_64-linux-musl", 244 "-L" + EXTERNAL_TOOLCHAIN + "/lib", 245 # We chose to use the llvm runtime, not the gcc one because it is already 246 # included in the clang binary 247 "--rtlib=compiler-rt", 248 # In order to run our executables, they need to be statically linked, 249 # otherwise, the libc++.so and friends will not be found if they are 250 # not installed on the user's machine. 251 "-static", 252 "-std=c++14", 253 "-lc++abi", 254 "-lunwind", 255 "-lc++", 256 ], 257 ), 258 ], 259 ) 260 return [feature( 261 "default_flags", 262 enabled = True, 263 flag_sets = [ 264 cxx_compile_includes, 265 cpp_compile_includes, 266 link_exe_flags, 267 ], 268 )] 269 270def _make_diagnostic_flags(): 271 """Here we define the flags that can be turned on via features to yield debug info.""" 272 cxx_diagnostic = flag_set( 273 actions = [ 274 ACTION_NAMES.c_compile, 275 ACTION_NAMES.cpp_compile, 276 ], 277 flag_groups = [ 278 flag_group( 279 flags = [ 280 "--trace-includes", 281 "-v", 282 ], 283 ), 284 ], 285 ) 286 287 link_diagnostic = flag_set( 288 actions = [ACTION_NAMES.cpp_link_executable], 289 flag_groups = [ 290 flag_group( 291 flags = [ 292 "-Wl,--verbose", 293 "-v", 294 ], 295 ), 296 ], 297 ) 298 299 link_search_dirs = flag_set( 300 actions = [ACTION_NAMES.cpp_link_executable], 301 flag_groups = [ 302 flag_group( 303 flags = [ 304 "--print-search-dirs", 305 ], 306 ), 307 ], 308 ) 309 return [ 310 # Running a Bazel command with --features diagnostic will cause the compilation and 311 # link steps to be more verbose. 312 feature( 313 "diagnostic", 314 enabled = False, 315 flag_sets = [ 316 cxx_diagnostic, 317 link_diagnostic, 318 ], 319 ), 320 # Running a Bazel command with --features print_search_dirs will cause the link to fail 321 # but directories searched for libraries, etc will be displayed. 322 feature( 323 "print_search_dirs", 324 enabled = False, 325 flag_sets = [ 326 link_search_dirs, 327 ], 328 ), 329 ] 330