1# pylint: disable=g-bad-file-header 2# Copyright 2016 The Bazel Authors. All rights reserved. 3# 4# Licensed under the Apache License, Version 2.0 (the "License"); 5# you may not use this file except in compliance with the License. 6# You may obtain a copy of the License at 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS IS" BASIS, 12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13# See the License for the specific language governing permissions and 14# limitations under the License. 15"""Configuring the C++ toolchain on Unix platforms.""" 16 17load( 18 ":lib_cc_configure.bzl", 19 "auto_configure_fail", 20 "auto_configure_warning", 21 "auto_configure_warning_maybe", 22 "escape_string", 23 "execute", 24 "get_env_var", 25 "get_starlark_list", 26 "resolve_labels", 27 "split_escaped", 28 "which", 29 "write_builtin_include_directory_paths", 30) 31 32def _uniq(iterable): 33 """Remove duplicates from a list.""" 34 35 unique_elements = {element: None for element in iterable} 36 return unique_elements.keys() 37 38def _generate_system_module_map(repository_ctx, dirs, script_path): 39 return execute(repository_ctx, [script_path] + dirs) 40 41def _prepare_include_path(repo_ctx, path): 42 """Resolve include path before outputting it into the crosstool. 43 44 Args: 45 repo_ctx: repository_ctx object. 46 path: an include path to be resolved. 47 48 Returns: 49 Resolved include path. Resulting path is absolute if it is outside the 50 repository and relative otherwise. 51 """ 52 53 repo_root = str(repo_ctx.path(".")) 54 55 # We're on UNIX, so the path delimiter is '/'. 56 repo_root += "/" 57 path = str(repo_ctx.path(path)) 58 if path.startswith(repo_root): 59 return path[len(repo_root):] 60 return path 61 62def _find_tool(repository_ctx, tool, overridden_tools): 63 """Find a tool for repository, taking overridden tools into account.""" 64 if tool in overridden_tools: 65 return overridden_tools[tool] 66 return which(repository_ctx, tool, "/usr/bin/" + tool) 67 68def _get_tool_paths(repository_ctx, overridden_tools): 69 """Compute the %-escaped path to the various tools""" 70 return dict({ 71 k: escape_string(_find_tool(repository_ctx, k, overridden_tools)) 72 for k in [ 73 "ar", 74 "ld", 75 "llvm-cov", 76 "llvm-profdata", 77 "cpp", 78 "gcc", 79 "dwp", 80 "gcov", 81 "nm", 82 "objcopy", 83 "objdump", 84 "strip", 85 "c++filt", 86 ] 87 }.items()) 88 89def _escaped_cplus_include_paths(repository_ctx): 90 """Use ${CPLUS_INCLUDE_PATH} to compute the %-escaped list of flags for cxxflag.""" 91 if "CPLUS_INCLUDE_PATH" in repository_ctx.os.environ: 92 result = [] 93 for p in repository_ctx.os.environ["CPLUS_INCLUDE_PATH"].split(":"): 94 p = escape_string(str(repository_ctx.path(p))) # Normalize the path 95 result.append("-I" + p) 96 return result 97 else: 98 return [] 99 100_INC_DIR_MARKER_BEGIN = "#include <...>" 101 102# OSX add " (framework directory)" at the end of line, strip it. 103_OSX_FRAMEWORK_SUFFIX = " (framework directory)" 104_OSX_FRAMEWORK_SUFFIX_LEN = len(_OSX_FRAMEWORK_SUFFIX) 105 106def _cxx_inc_convert(path): 107 """Convert path returned by cc -E xc++ in a complete path. Doesn't %-escape the path!""" 108 path = path.strip() 109 if path.endswith(_OSX_FRAMEWORK_SUFFIX): 110 path = path[:-_OSX_FRAMEWORK_SUFFIX_LEN].strip() 111 return path 112 113def _get_cxx_include_directories(repository_ctx, print_resource_dir_supported, cc, lang_flag, additional_flags = []): 114 """Compute the list of C++ include directories.""" 115 result = repository_ctx.execute([cc, "-E", lang_flag, "-", "-v"] + additional_flags) 116 index1 = result.stderr.find(_INC_DIR_MARKER_BEGIN) 117 if index1 == -1: 118 return [] 119 index1 = result.stderr.find("\n", index1) 120 if index1 == -1: 121 return [] 122 index2 = result.stderr.rfind("\n ") 123 if index2 == -1 or index2 < index1: 124 return [] 125 index2 = result.stderr.find("\n", index2 + 1) 126 if index2 == -1: 127 inc_dirs = result.stderr[index1 + 1:] 128 else: 129 inc_dirs = result.stderr[index1 + 1:index2].strip() 130 131 inc_directories = [ 132 _prepare_include_path(repository_ctx, _cxx_inc_convert(p)) 133 for p in inc_dirs.split("\n") 134 ] 135 136 if print_resource_dir_supported: 137 resource_dir = repository_ctx.execute( 138 [cc, "-print-resource-dir"] + additional_flags, 139 ).stdout.strip() + "/share" 140 inc_directories.append(_prepare_include_path(repository_ctx, resource_dir)) 141 142 return inc_directories 143 144def _is_compiler_option_supported(repository_ctx, cc, option): 145 """Checks that `option` is supported by the C compiler. Doesn't %-escape the option.""" 146 result = repository_ctx.execute([ 147 cc, 148 option, 149 "-o", 150 "/dev/null", 151 "-c", 152 str(repository_ctx.path("tools/cpp/empty.cc")), 153 ]) 154 return result.stderr.find(option) == -1 155 156def _is_linker_option_supported(repository_ctx, cc, force_linker_flags, option, pattern): 157 """Checks that `option` is supported by the C linker. Doesn't %-escape the option.""" 158 result = repository_ctx.execute([cc] + force_linker_flags + [ 159 option, 160 "-o", 161 "/dev/null", 162 str(repository_ctx.path("tools/cpp/empty.cc")), 163 ]) 164 return result.stderr.find(pattern) == -1 165 166def _find_linker_path(repository_ctx, cc, linker, is_clang): 167 """Checks if a given linker is supported by the C compiler. 168 169 Args: 170 repository_ctx: repository_ctx. 171 cc: path to the C compiler. 172 linker: linker to find 173 is_clang: whether the compiler is known to be clang 174 175 Returns: 176 String to put as value to -fuse-ld= flag, or None if linker couldn't be found. 177 """ 178 result = repository_ctx.execute([ 179 cc, 180 str(repository_ctx.path("tools/cpp/empty.cc")), 181 "-o", 182 "/dev/null", 183 # Some macOS clang versions don't fail when setting -fuse-ld=gold, adding 184 # these lines to force it to. This also means that we will not detect 185 # gold when only a very old (year 2010 and older) is present. 186 "-Wl,--start-lib", 187 "-Wl,--end-lib", 188 "-fuse-ld=" + linker, 189 "-v", 190 ]) 191 if result.return_code != 0: 192 return None 193 194 if not is_clang: 195 return linker 196 197 # Extract linker path from: 198 # /usr/bin/clang ... 199 # "/usr/bin/ld.lld" -pie -z ... 200 linker_command = result.stderr.splitlines()[-1] 201 return linker_command.strip().split(" ")[0].strip("\"'") 202 203def _add_compiler_option_if_supported(repository_ctx, cc, option): 204 """Returns `[option]` if supported, `[]` otherwise. Doesn't %-escape the option.""" 205 return [option] if _is_compiler_option_supported(repository_ctx, cc, option) else [] 206 207def _add_linker_option_if_supported(repository_ctx, cc, force_linker_flags, option, pattern): 208 """Returns `[option]` if supported, `[]` otherwise. Doesn't %-escape the option.""" 209 return [option] if _is_linker_option_supported(repository_ctx, cc, force_linker_flags, option, pattern) else [] 210 211def _get_no_canonical_prefixes_opt(repository_ctx, cc): 212 # If the compiler sometimes rewrites paths in the .d files without symlinks 213 # (ie when they're shorter), it confuses Bazel's logic for verifying all 214 # #included header files are listed as inputs to the action. 215 216 # The '-fno-canonical-system-headers' should be enough, but clang does not 217 # support it, so we also try '-no-canonical-prefixes' if first option does 218 # not work. 219 opt = _add_compiler_option_if_supported( 220 repository_ctx, 221 cc, 222 "-fno-canonical-system-headers", 223 ) 224 if len(opt) == 0: 225 return _add_compiler_option_if_supported( 226 repository_ctx, 227 cc, 228 "-no-canonical-prefixes", 229 ) 230 return opt 231 232def get_env(repository_ctx): 233 """Convert the environment in a list of export if in Homebrew. Doesn't %-escape the result! 234 235 Args: 236 repository_ctx: The repository context. 237 Returns: 238 empty string or a list of exports in case we're running with homebrew. Don't ask me why. 239 """ 240 env = repository_ctx.os.environ 241 if "HOMEBREW_RUBY_PATH" in env: 242 return "\n".join([ 243 "export %s='%s'" % (k, env[k].replace("'", "'\\''")) 244 for k in env 245 if k != "_" and k.find(".") == -1 246 ]) 247 else: 248 return "" 249 250def _coverage_flags(repository_ctx, darwin): 251 use_llvm_cov = "1" == get_env_var( 252 repository_ctx, 253 "BAZEL_USE_LLVM_NATIVE_COVERAGE", 254 default = "0", 255 enable_warning = False, 256 ) 257 if darwin or use_llvm_cov: 258 compile_flags = '"-fprofile-instr-generate", "-fcoverage-mapping"' 259 link_flags = '"-fprofile-instr-generate"' 260 else: 261 # gcc requires --coverage being passed for compilation and linking 262 # https://gcc.gnu.org/onlinedocs/gcc/Instrumentation-Options.html#Instrumentation-Options 263 compile_flags = '"--coverage"' 264 link_flags = '"--coverage"' 265 return compile_flags, link_flags 266 267def _is_clang(repository_ctx, cc): 268 return "clang" in repository_ctx.execute([cc, "-v"]).stderr 269 270def _is_gcc(repository_ctx, cc): 271 # GCC's version output uses the basename of argv[0] as the program name: 272 # https://gcc.gnu.org/git/?p=gcc.git;a=blob;f=gcc/gcc.cc;h=158461167951c1b9540322fb19be6a89d6da07fc;hb=HEAD#l8728 273 cc_stdout = repository_ctx.execute([cc, "--version"]).stdout 274 return cc_stdout.startswith("gcc ") or cc_stdout.startswith("gcc-") 275 276def _get_compiler_name(repository_ctx, cc): 277 if _is_clang(repository_ctx, cc): 278 return "clang" 279 if _is_gcc(repository_ctx, cc): 280 return "gcc" 281 return "compiler" 282 283def _find_generic(repository_ctx, name, env_name, overridden_tools, warn = False, silent = False): 284 """Find a generic C++ toolchain tool. Doesn't %-escape the result.""" 285 286 if name in overridden_tools: 287 return overridden_tools[name] 288 289 result = name 290 env_value = repository_ctx.os.environ.get(env_name) 291 env_value_with_paren = "" 292 if env_value != None: 293 env_value = env_value.strip() 294 if env_value: 295 result = env_value 296 env_value_with_paren = " (%s)" % env_value 297 if result.startswith("/"): 298 # Absolute path, maybe we should make this supported by our which function. 299 return result 300 result = repository_ctx.which(result) 301 if result == None: 302 msg = ("Cannot find %s or %s%s; either correct your path or set the %s" + 303 " environment variable") % (name, env_name, env_value_with_paren, env_name) 304 if warn: 305 if not silent: 306 auto_configure_warning(msg) 307 else: 308 auto_configure_fail(msg) 309 return result 310 311def find_cc(repository_ctx, overridden_tools): 312 """Find the C compiler (gcc or clang) for the repository, considering overridden tools. 313 314 Args: 315 repository_ctx: The repository context. 316 overridden_tools: A dictionary of overridden tools. 317 318 Returns: 319 The path to the C compiler. 320 """ 321 cc = _find_generic(repository_ctx, "gcc", "CC", overridden_tools) 322 if _is_clang(repository_ctx, cc): 323 # If clang is run through a symlink with -no-canonical-prefixes, it does 324 # not find its own include directory, which includes the headers for 325 # libc++. Resolving the potential symlink here prevents this. 326 result = repository_ctx.execute(["readlink", "-f", cc]) 327 if result.return_code == 0: 328 return result.stdout.strip() 329 return cc 330 331def configure_unix_toolchain(repository_ctx, cpu_value, overridden_tools): 332 """Configure C++ toolchain on Unix platforms. 333 334 Args: 335 repository_ctx: The repository context. 336 cpu_value: The CPU value. 337 overridden_tools: A dictionary of overridden tools. 338 """ 339 paths = resolve_labels(repository_ctx, [ 340 "@rules_cc//cc/private/toolchain:BUILD.tpl", 341 "@rules_cc//cc/private/toolchain:generate_system_module_map.sh", 342 "@rules_cc//cc/private/toolchain:armeabi_cc_toolchain_config.bzl", 343 "@rules_cc//cc/private/toolchain:unix_cc_toolchain_config.bzl", 344 "@rules_cc//cc/private/toolchain:linux_cc_wrapper.sh.tpl", 345 "@rules_cc//cc/private/toolchain:validate_static_library.sh.tpl", 346 "@rules_cc//cc/private/toolchain:osx_cc_wrapper.sh.tpl", 347 "@rules_cc//cc/private/toolchain:clang_deps_scanner_wrapper.sh.tpl", 348 "@rules_cc//cc/private/toolchain:gcc_deps_scanner_wrapper.sh.tpl", 349 ]) 350 351 repository_ctx.symlink( 352 paths["@rules_cc//cc/private/toolchain:unix_cc_toolchain_config.bzl"], 353 "cc_toolchain_config.bzl", 354 ) 355 356 repository_ctx.symlink( 357 paths["@rules_cc//cc/private/toolchain:armeabi_cc_toolchain_config.bzl"], 358 "armeabi_cc_toolchain_config.bzl", 359 ) 360 361 repository_ctx.file("tools/cpp/empty.cc", "int main() {}") 362 darwin = cpu_value.startswith("darwin") 363 bsd = cpu_value == "freebsd" or cpu_value == "openbsd" 364 365 cc = find_cc(repository_ctx, overridden_tools) 366 is_clang = _is_clang(repository_ctx, cc) 367 overridden_tools = dict(overridden_tools) 368 overridden_tools["gcc"] = cc 369 overridden_tools["gcov"] = _find_generic( 370 repository_ctx, 371 "gcov", 372 "GCOV", 373 overridden_tools, 374 warn = True, 375 silent = True, 376 ) 377 overridden_tools["llvm-cov"] = _find_generic( 378 repository_ctx, 379 "llvm-cov", 380 "BAZEL_LLVM_COV", 381 overridden_tools, 382 warn = True, 383 silent = True, 384 ) 385 overridden_tools["llvm-profdata"] = _find_generic( 386 repository_ctx, 387 "llvm-profdata", 388 "BAZEL_LLVM_PROFDATA", 389 overridden_tools, 390 warn = True, 391 silent = True, 392 ) 393 overridden_tools["ar"] = _find_generic( 394 repository_ctx, 395 "ar", 396 "AR", 397 overridden_tools, 398 warn = True, 399 silent = True, 400 ) 401 if darwin: 402 overridden_tools["gcc"] = "cc_wrapper.sh" 403 overridden_tools["ar"] = _find_generic(repository_ctx, "libtool", "LIBTOOL", overridden_tools) 404 405 auto_configure_warning_maybe(repository_ctx, "CC used: " + str(cc)) 406 tool_paths = _get_tool_paths(repository_ctx, overridden_tools) 407 tool_paths["cpp-module-deps-scanner"] = "deps_scanner_wrapper.sh" 408 409 # The parse_header tool needs to be a wrapper around the compiler as it has 410 # to touch the output file. 411 tool_paths["parse_headers"] = "cc_wrapper.sh" 412 cc_toolchain_identifier = escape_string(get_env_var( 413 repository_ctx, 414 "CC_TOOLCHAIN_NAME", 415 "local", 416 False, 417 )) 418 419 if "nm" in tool_paths and "c++filt" in tool_paths: 420 repository_ctx.template( 421 "validate_static_library.sh", 422 paths["@rules_cc//cc/private/toolchain:validate_static_library.sh.tpl"], 423 { 424 "%{c++filt}": escape_string(str(repository_ctx.path(tool_paths["c++filt"]))), 425 # Certain weak symbols are otherwise listed with type T in the output of nm on macOS. 426 "%{nm_extra_args}": "--no-weak" if darwin else "", 427 "%{nm}": escape_string(str(repository_ctx.path(tool_paths["nm"]))), 428 }, 429 ) 430 tool_paths["validate_static_library"] = "validate_static_library.sh" 431 432 cc_wrapper_src = ( 433 "@rules_cc//cc/private/toolchain:osx_cc_wrapper.sh.tpl" if darwin else "@rules_cc//cc/private/toolchain:linux_cc_wrapper.sh.tpl" 434 ) 435 repository_ctx.template( 436 "cc_wrapper.sh", 437 paths[cc_wrapper_src], 438 { 439 "%{cc}": escape_string(str(cc)), 440 "%{env}": escape_string(get_env(repository_ctx)), 441 }, 442 ) 443 deps_scanner_wrapper_src = ( 444 "@rules_cc//cc/private/toolchain:clang_deps_scanner_wrapper.sh.tpl" if is_clang else "@rules_cc//cc/private/toolchain:gcc_deps_scanner_wrapper.sh.tpl" 445 ) 446 deps_scanner = "cpp-module-deps-scanner_not_found" 447 if is_clang: 448 cc_str = str(cc) 449 path_arr = cc_str.split("/")[:-1] 450 path_arr.append("clang-scan-deps") 451 deps_scanner = "/".join(path_arr) 452 repository_ctx.template( 453 "deps_scanner_wrapper.sh", 454 paths[deps_scanner_wrapper_src], 455 { 456 "%{cc}": escape_string(str(cc)), 457 "%{deps_scanner}": escape_string(deps_scanner), 458 "%{env}": escape_string(get_env(repository_ctx)), 459 }, 460 ) 461 462 conly_opts = split_escaped(get_env_var( 463 repository_ctx, 464 "BAZEL_CONLYOPTS", 465 "", 466 False, 467 ), ":") 468 469 cxx_opts = split_escaped(get_env_var( 470 repository_ctx, 471 "BAZEL_CXXOPTS", 472 "-std=c++17", 473 False, 474 ), ":") 475 476 gold_or_lld_linker_path = ( 477 _find_linker_path(repository_ctx, cc, "lld", is_clang) or 478 _find_linker_path(repository_ctx, cc, "gold", is_clang) 479 ) 480 cc_path = repository_ctx.path(cc) 481 if not str(cc_path).startswith(str(repository_ctx.path(".")) + "/"): 482 # cc is outside the repository, set -B 483 bin_search_flags = ["-B" + escape_string(str(cc_path.dirname))] 484 else: 485 # cc is inside the repository, don't set -B. 486 bin_search_flags = [] 487 if not gold_or_lld_linker_path: 488 ld_path = repository_ctx.path(tool_paths["ld"]) 489 if ld_path.dirname != cc_path.dirname: 490 bin_search_flags.append("-B" + str(ld_path.dirname)) 491 force_linker_flags = [] 492 if gold_or_lld_linker_path: 493 force_linker_flags.append("-fuse-ld=" + gold_or_lld_linker_path) 494 495 # TODO: It's unclear why these flags aren't added on macOS. 496 if bin_search_flags and not darwin: 497 force_linker_flags.extend(bin_search_flags) 498 use_libcpp = darwin or bsd 499 is_as_needed_supported = _is_linker_option_supported( 500 repository_ctx, 501 cc, 502 force_linker_flags, 503 "-Wl,-no-as-needed", 504 "-no-as-needed", 505 ) 506 is_push_state_supported = _is_linker_option_supported( 507 repository_ctx, 508 cc, 509 force_linker_flags, 510 "-Wl,--push-state", 511 "--push-state", 512 ) 513 if use_libcpp: 514 bazel_default_libs = ["-lc++", "-lm"] 515 else: 516 bazel_default_libs = ["-lstdc++", "-lm"] 517 if is_as_needed_supported and is_push_state_supported: 518 # Do not link against C++ standard libraries unless they are actually 519 # used. 520 # We assume that --push-state support implies --pop-state support. 521 bazel_linklibs_elements = [ 522 arg 523 for lib in bazel_default_libs 524 for arg in ["-Wl,--push-state,-as-needed", lib, "-Wl,--pop-state"] 525 ] 526 else: 527 bazel_linklibs_elements = bazel_default_libs 528 bazel_linklibs = ":".join(bazel_linklibs_elements) 529 bazel_linkopts = "" 530 531 link_opts = split_escaped(get_env_var( 532 repository_ctx, 533 "BAZEL_LINKOPTS", 534 bazel_linkopts, 535 False, 536 ), ":") 537 link_libs = split_escaped(get_env_var( 538 repository_ctx, 539 "BAZEL_LINKLIBS", 540 bazel_linklibs, 541 False, 542 ), ":") 543 coverage_compile_flags, coverage_link_flags = _coverage_flags(repository_ctx, darwin) 544 print_resource_dir_supported = _is_compiler_option_supported( 545 repository_ctx, 546 cc, 547 "-print-resource-dir", 548 ) 549 no_canonical_prefixes_opt = _get_no_canonical_prefixes_opt(repository_ctx, cc) 550 builtin_include_directories = _uniq( 551 _get_cxx_include_directories(repository_ctx, print_resource_dir_supported, cc, "-xc", conly_opts) + 552 _get_cxx_include_directories(repository_ctx, print_resource_dir_supported, cc, "-xc++", cxx_opts) + 553 _get_cxx_include_directories( 554 repository_ctx, 555 print_resource_dir_supported, 556 cc, 557 "-xc++", 558 cxx_opts + ["-stdlib=libc++"], 559 ) + 560 _get_cxx_include_directories( 561 repository_ctx, 562 print_resource_dir_supported, 563 cc, 564 "-xc", 565 no_canonical_prefixes_opt, 566 ) + 567 _get_cxx_include_directories( 568 repository_ctx, 569 print_resource_dir_supported, 570 cc, 571 "-xc++", 572 cxx_opts + no_canonical_prefixes_opt, 573 ) + 574 _get_cxx_include_directories( 575 repository_ctx, 576 print_resource_dir_supported, 577 cc, 578 "-xc++", 579 cxx_opts + no_canonical_prefixes_opt + ["-stdlib=libc++"], 580 ) + 581 # Always included in case the user has Xcode + the CLT installed, both 582 # paths can be used interchangeably 583 ["/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk"], 584 ) 585 586 generate_modulemap = is_clang 587 if generate_modulemap: 588 repository_ctx.file("module.modulemap", _generate_system_module_map( 589 repository_ctx, 590 builtin_include_directories, 591 paths["@rules_cc//cc/private/toolchain:generate_system_module_map.sh"], 592 )) 593 extra_flags_per_feature = {} 594 if is_clang: 595 # Only supported by LLVM 14 and later, but required with C++20 and 596 # layering_check as C++ modules are the default. 597 # https://github.com/llvm/llvm-project/commit/0556138624edf48621dd49a463dbe12e7101f17d 598 result = repository_ctx.execute([ 599 cc, 600 "-Xclang", 601 "-fno-cxx-modules", 602 "-o", 603 "/dev/null", 604 "-c", 605 str(repository_ctx.path("tools/cpp/empty.cc")), 606 ]) 607 if "-fno-cxx-modules" not in result.stderr: 608 extra_flags_per_feature["use_module_maps"] = ["-Xclang", "-fno-cxx-modules"] 609 610 write_builtin_include_directory_paths(repository_ctx, cc, builtin_include_directories) 611 repository_ctx.template( 612 "BUILD", 613 paths["@rules_cc//cc/private/toolchain:BUILD.tpl"], 614 # @unsorted-dict-items 615 { 616 "%{abi_libc_version}": escape_string(get_env_var( 617 repository_ctx, 618 "ABI_LIBC_VERSION", 619 "local", 620 False, 621 )), 622 "%{abi_version}": escape_string(get_env_var( 623 repository_ctx, 624 "ABI_VERSION", 625 "local", 626 False, 627 )), 628 "%{cc_compiler_deps}": get_starlark_list([ 629 ":builtin_include_directory_paths", 630 ":cc_wrapper", 631 ":deps_scanner_wrapper", 632 ] + ( 633 [":validate_static_library"] if "validate_static_library" in tool_paths else [] 634 )), 635 "%{cc_toolchain_identifier}": cc_toolchain_identifier, 636 "%{compile_flags}": get_starlark_list( 637 [ 638 "-fstack-protector", 639 # All warnings are enabled. 640 "-Wall", 641 # Enable a few more warnings that aren't part of -Wall. 642 ] + (( 643 _add_compiler_option_if_supported(repository_ctx, cc, "-Wthread-safety") + 644 _add_compiler_option_if_supported(repository_ctx, cc, "-Wself-assign") 645 )) + ( 646 # Disable problematic warnings. 647 _add_compiler_option_if_supported(repository_ctx, cc, "-Wunused-but-set-parameter") + 648 # has false positives 649 _add_compiler_option_if_supported(repository_ctx, cc, "-Wno-free-nonheap-object") + 650 # Enable coloring even if there's no attached terminal. Bazel removes the 651 # escape sequences if --nocolor is specified. 652 _add_compiler_option_if_supported(repository_ctx, cc, "-fcolor-diagnostics") 653 ) + [ 654 # Keep stack frames for debugging, even in opt mode. 655 "-fno-omit-frame-pointer", 656 ], 657 ), 658 "%{compiler}": escape_string(get_env_var( 659 repository_ctx, 660 "BAZEL_COMPILER", 661 _get_compiler_name(repository_ctx, cc), 662 False, 663 )), 664 "%{conly_flags}": get_starlark_list(conly_opts), 665 "%{coverage_compile_flags}": coverage_compile_flags, 666 "%{coverage_link_flags}": coverage_link_flags, 667 "%{cxx_builtin_include_directories}": get_starlark_list(builtin_include_directories), 668 "%{cxx_flags}": get_starlark_list(cxx_opts + _escaped_cplus_include_paths(repository_ctx)), 669 "%{dbg_compile_flags}": get_starlark_list(["-g"]), 670 "%{extra_flags_per_feature}": repr(extra_flags_per_feature), 671 "%{host_system_name}": escape_string(get_env_var( 672 repository_ctx, 673 "BAZEL_HOST_SYSTEM", 674 "local", 675 False, 676 )), 677 "%{link_flags}": get_starlark_list(force_linker_flags + ( 678 ["-Wl,-no-as-needed"] if is_as_needed_supported else [] 679 ) + _add_linker_option_if_supported( 680 repository_ctx, 681 cc, 682 force_linker_flags, 683 "-Wl,-z,relro,-z,now", 684 "-z", 685 ) + ( 686 [ 687 "-headerpad_max_install_names", 688 ] if darwin else [ 689 # Gold linker only? Can we enable this by default? 690 # "-Wl,--warn-execstack", 691 # "-Wl,--detect-odr-violations" 692 ] + _add_compiler_option_if_supported( 693 # Have gcc return the exit code from ld. 694 repository_ctx, 695 cc, 696 "-pass-exit-codes", 697 ) 698 ) + link_opts), 699 "%{link_libs}": get_starlark_list(link_libs), 700 "%{modulemap}": ("\":module.modulemap\"" if generate_modulemap else "None"), 701 "%{name}": cpu_value, 702 "%{opt_compile_flags}": get_starlark_list( 703 [ 704 # No debug symbols. 705 # Maybe we should enable https://gcc.gnu.org/wiki/DebugFission for opt or 706 # even generally? However, that can't happen here, as it requires special 707 # handling in Bazel. 708 "-g0", 709 710 # Conservative choice for -O 711 # -O3 can increase binary size and even slow down the resulting binaries. 712 # Profile first and / or use FDO if you need better performance than this. 713 "-O2", 714 715 # Security hardening on by default. 716 # Conservative choice; -D_FORTIFY_SOURCE=2 may be unsafe in some cases. 717 "-D_FORTIFY_SOURCE=1", 718 719 # Disable assertions 720 "-DNDEBUG", 721 722 # Removal of unused code and data at link time (can this increase binary 723 # size in some cases?). 724 "-ffunction-sections", 725 "-fdata-sections", 726 ], 727 ), 728 "%{opt_link_flags}": get_starlark_list( 729 ["-Wl,-dead_strip"] if darwin else _add_linker_option_if_supported( 730 repository_ctx, 731 cc, 732 force_linker_flags, 733 "-Wl,--gc-sections", 734 "-gc-sections", 735 ), 736 ), 737 "%{supports_start_end_lib}": "True" if gold_or_lld_linker_path else "False", 738 "%{target_cpu}": escape_string(get_env_var( 739 repository_ctx, 740 "BAZEL_TARGET_CPU", 741 cpu_value, 742 False, 743 )), 744 "%{target_libc}": "macosx" if darwin else escape_string(get_env_var( 745 repository_ctx, 746 "BAZEL_TARGET_LIBC", 747 "local", 748 False, 749 )), 750 "%{target_system_name}": escape_string(get_env_var( 751 repository_ctx, 752 "BAZEL_TARGET_SYSTEM", 753 "local", 754 False, 755 )), 756 "%{tool_paths}": ",\n ".join( 757 ['"%s": "%s"' % (k, v) for k, v in tool_paths.items() if v != None], 758 ), 759 "%{unfiltered_compile_flags}": get_starlark_list( 760 _get_no_canonical_prefixes_opt(repository_ctx, cc) + [ 761 # Make C++ compilation deterministic. Use linkstamping instead of these 762 # compiler symbols. 763 "-Wno-builtin-macro-redefined", 764 "-D__DATE__=\\\"redacted\\\"", 765 "-D__TIMESTAMP__=\\\"redacted\\\"", 766 "-D__TIME__=\\\"redacted\\\"", 767 ], 768 ), 769 }, 770 ) 771