diff --git a/cc/private/toolchain/unix_cc_toolchain_config.bzl b/cc/private/toolchain/unix_cc_toolchain_config.bzl index 86480f8d8..2a551c0ba 100644 --- a/cc/private/toolchain/unix_cc_toolchain_config.bzl +++ b/cc/private/toolchain/unix_cc_toolchain_config.bzl @@ -31,6 +31,8 @@ load( ) load("@rules_cc//cc/common:cc_common.bzl", "cc_common") load("@rules_cc//cc/toolchains:cc_toolchain_config_info.bzl", "CcToolchainConfigInfo") +load("@rules_cc//cc/toolchains:cc_toolchain_info.bzl", RulesBasedFeatureInfo = "FeatureInfo") +load("@rules_cc//cc/toolchains/impl:legacy_converter.bzl", "convert_feature") def _target_os_version(ctx): platform_type = ctx.fragments.apple.single_arch_platform.platform_type @@ -1931,6 +1933,8 @@ def _impl(ctx): if symbol_check: features.append(symbol_check) + features.extend([convert_feature(extra_feature[RulesBasedFeatureInfo]) for extra_feature in ctx.attr.extra_features]) + return cc_common.create_cc_toolchain_config_info( ctx = ctx, features = features, @@ -1965,6 +1969,7 @@ cc_toolchain_config = rule( "cxx_builtin_include_directories": attr.string_list(), "cxx_flags": attr.string_list(), "dbg_compile_flags": attr.string_list(), + "extra_features": attr.label_list(providers = [RulesBasedFeatureInfo], default = []), "extra_flags_per_feature": attr.string_list_dict(), "fastbuild_compile_flags": attr.string_list(), "host_system_name": attr.string(mandatory = True), diff --git a/cc/private/toolchain/windows_cc_toolchain_config.bzl b/cc/private/toolchain/windows_cc_toolchain_config.bzl index b9306bf5e..38460c5d1 100644 --- a/cc/private/toolchain/windows_cc_toolchain_config.bzl +++ b/cc/private/toolchain/windows_cc_toolchain_config.bzl @@ -31,6 +31,8 @@ load( ) load("@rules_cc//cc/common:cc_common.bzl", "cc_common") load("@rules_cc//cc/toolchains:cc_toolchain_config_info.bzl", "CcToolchainConfigInfo") +load("@rules_cc//cc/toolchains:cc_toolchain_info.bzl", RulesBasedFeatureInfo = "FeatureInfo") +load("@rules_cc//cc/toolchains/impl:legacy_converter.bzl", "convert_feature") all_compile_actions = [ ACTION_NAMES.c_compile, @@ -1640,9 +1642,12 @@ def _impl(ctx): ], enabled = True, ) + features.extend([cpp_modules_feature, cpp_module_modmap_file_feature, cpp20_module_compile_flags_feature]) + features.extend([convert_feature(extra_feature[RulesBasedFeatureInfo]) for extra_feature in ctx.attr.extra_features]) + return cc_common.create_cc_toolchain_config_info( ctx = ctx, - features = features + [cpp_modules_feature, cpp_module_modmap_file_feature, cpp20_module_compile_flags_feature], + features = features, action_configs = action_configs, artifact_name_patterns = artifact_name_patterns, cxx_builtin_include_directories = ctx.attr.cxx_builtin_include_directories, @@ -1670,6 +1675,7 @@ cc_toolchain_config = rule( "dbg_mode_debug_flag": attr.string(default = ""), "default_compile_flags": attr.string_list(default = []), "default_link_flags": attr.string_list(default = []), + "extra_features": attr.label_list(providers = [RulesBasedFeatureInfo], default = []), "fastbuild_mode_debug_flag": attr.string(default = ""), "host_system_name": attr.string(), "msvc_cl_path": attr.string(default = "vc_installation_error.bat"), diff --git a/cc/toolchains/cc_toolchain_info.bzl b/cc/toolchains/cc_toolchain_info.bzl index 38148b463..42bf3f64b 100644 --- a/cc/toolchains/cc_toolchain_info.bzl +++ b/cc/toolchains/cc_toolchain_info.bzl @@ -19,6 +19,7 @@ # decide to just require users to use the public user-facing rules. visibility([ "//cc/toolchains/...", + "//cc/private/toolchain/...", "//tests/rule_based_toolchain/...", ]) diff --git a/cc/toolchains/impl/legacy_converter.bzl b/cc/toolchains/impl/legacy_converter.bzl index 8f8a46095..2614123bf 100644 --- a/cc/toolchains/impl/legacy_converter.bzl +++ b/cc/toolchains/impl/legacy_converter.bzl @@ -29,6 +29,7 @@ load( visibility([ "//cc/toolchains/...", + "//cc/private/toolchain/...", "//tests/rule_based_toolchain/...", ]) diff --git a/examples/inject_extra_features/BUILD b/examples/inject_extra_features/BUILD new file mode 100644 index 000000000..41b737c87 --- /dev/null +++ b/examples/inject_extra_features/BUILD @@ -0,0 +1,6 @@ +load("@rules_cc//cc:cc_binary.bzl", "cc_binary") + +cc_binary( + name = "main", + srcs = ["main.cpp"], +) diff --git a/examples/inject_extra_features/main.cpp b/examples/inject_extra_features/main.cpp new file mode 100644 index 000000000..107cc39f4 --- /dev/null +++ b/examples/inject_extra_features/main.cpp @@ -0,0 +1,4 @@ +int main() +{ + return 32; +} diff --git a/examples/inject_extra_features/toolchain/BUILD b/examples/inject_extra_features/toolchain/BUILD new file mode 100644 index 000000000..cbee75553 --- /dev/null +++ b/examples/inject_extra_features/toolchain/BUILD @@ -0,0 +1,185 @@ +# Copyright 2016 The Bazel Authors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# This becomes the BUILD file for @local_config_cc// under non-BSD unixes. + +load("@rules_cc//cc:action_names.bzl", "ACTION_NAMES") +load("@rules_cc//cc/toolchains:cc_toolchain.bzl", "cc_toolchain") +load(":cc_toolchain_config.bzl", "cc_toolchain_config") + +package(default_visibility = ["//visibility:public"]) + +licenses(["notice"]) # Apache 2.0 + +filegroup( + name = "empty", + srcs = [], +) + +filegroup( + name = "cc_wrapper", + srcs = ["cc_wrapper.sh"], +) + +filegroup( + name = "validate_static_library", + srcs = ["validate_static_library.sh"], +) + +filegroup( + name = "deps_scanner_wrapper", + srcs = ["deps_scanner_wrapper.sh"], +) + +filegroup( + name = "compiler_deps", + srcs = glob( + ["extra_tools/**"], + allow_empty = True, + ) + [ + ":builtin_include_directory_paths", + ":cc_wrapper", + ":deps_scanner_wrapper", + ":validate_static_library", + ], +) + +load("@rules_cc//cc/toolchains:args.bzl", "cc_args") +load("@rules_cc//cc/toolchains:feature.bzl", "cc_feature") + +cc_feature( + name = "foo", + args = [":flags"], + feature_name = "foo", + visibility = ["//visibility:public"], +) + +cc_args( + name = "flags", + actions = ["@rules_cc//cc/toolchains/actions:compile_actions"], + args = ["-foo"], +) + +toolchain( + name = "my_linux_toolchain", + exec_compatible_with = [ + "@platforms//os:linux", + "@platforms//cpu:x86_64", + ], + target_compatible_with = [ + "@platforms//os:linux", + "@platforms//cpu:x86_64", + ], + toolchain = ":cc-compiler-k8", + toolchain_type = "@bazel_tools//tools/cpp:toolchain_type", +) + +cc_toolchain( + name = "cc-compiler-k8", + all_files = ":compiler_deps", + ar_files = ":compiler_deps", + as_files = ":compiler_deps", + compiler_files = ":compiler_deps", + dwp_files = ":empty", + linker_files = ":compiler_deps", + module_map = None, + objcopy_files = ":empty", + strip_files = ":empty", + supports_header_parsing = 1, + supports_param_files = 1, + toolchain_config = ":local", + toolchain_identifier = "local", +) + +cc_toolchain_config( + name = "local", + abi_libc_version = "local", + abi_version = "local", + compile_flags = [ + "-fstack-protector", + "-Wall", + "-Wunused-but-set-parameter", + "-Wno-free-nonheap-object", + "-fno-omit-frame-pointer", + ], + compiler = "gcc", + conly_flags = [], + coverage_compile_flags = ["--coverage"], + coverage_link_flags = ["--coverage"], + cpu = "k8", + cxx_builtin_include_directories = [ + "/usr/lib/gcc/x86_64-linux-gnu/10/include", + "/usr/local/include", + "/usr/include/x86_64-linux-gnu", + "/usr/include", + "/usr/include/c++/10", + "/usr/include/x86_64-linux-gnu/c++/10", + "/usr/include/c++/10/backward", + ], + cxx_flags = ["-std=c++17"], + dbg_compile_flags = ["-g"], + extra_features = [":foo"], + host_system_name = "local", + link_flags = [ + "-fuse-ld=gold", + "-B/usr/bin", + "-Wl,-no-as-needed", + "-Wl,-z,relro,-z,now", + "-pass-exit-codes", + ], + link_libs = [ + "-Wl,--push-state,-as-needed", + "-lstdc++", + "-Wl,--pop-state", + "-Wl,--push-state,-as-needed", + "-lm", + "-Wl,--pop-state", + ], + opt_compile_flags = [ + "-g0", + "-O2", + "-D_FORTIFY_SOURCE=1", + "-DNDEBUG", + "-ffunction-sections", + "-fdata-sections", + ], + opt_link_flags = ["-Wl,--gc-sections"], + supports_start_end_lib = True, + target_libc = "local", + target_system_name = "local", + tool_paths = { + "ar": "/usr/bin/ar", + "ld": "/usr/bin/ld", + "cpp": "/usr/bin/cpp-10", + "gcc": "/usr/bin/gcc-10", + "dwp": "/usr/bin/dwp", + "gcov": "/usr/bin/gcov-10", + "nm": "/usr/bin/nm", + "objcopy": "/usr/bin/objcopy", + "objdump": "/usr/bin/objdump", + "strip": "/usr/bin/strip", + "c++filt": "/usr/bin/c++filt", + "cpp-module-deps-scanner": "deps_scanner_wrapper.sh", + "parse_headers": "cc_wrapper.sh", + "validate_static_library": "validate_static_library.sh", + }, + toolchain_identifier = "local", + unfiltered_compile_flags = [ + "-fno-canonical-system-headers", + "-Wno-builtin-macro-redefined", + "-D__DATE__=\"redacted\"", + "-D__TIMESTAMP__=\"redacted\"", + "-D__TIME__=\"redacted\"", + ], +) diff --git a/examples/inject_extra_features/toolchain/builtin_include_directory_paths b/examples/inject_extra_features/toolchain/builtin_include_directory_paths new file mode 100644 index 000000000..53e002e5d --- /dev/null +++ b/examples/inject_extra_features/toolchain/builtin_include_directory_paths @@ -0,0 +1,13 @@ +This file is generated by cc_configure and contains builtin include directories +that /usr/bin/gcc reported. This file is a dependency of every compilation action and +changes to it will be reflected in the action cache key. When some of these +paths change, Bazel will make sure to rerun the action, even though none of +declared action inputs or the action commandline changes. + +/usr/lib/gcc/x86_64-linux-gnu/10/include +/usr/local/include +/usr/include/x86_64-linux-gnu +/usr/include +/usr/include/c++/10 +/usr/include/x86_64-linux-gnu/c++/10 +/usr/include/c++/10/backward diff --git a/examples/inject_extra_features/toolchain/cc_toolchain_config.bzl b/examples/inject_extra_features/toolchain/cc_toolchain_config.bzl new file mode 100644 index 000000000..708cf701c --- /dev/null +++ b/examples/inject_extra_features/toolchain/cc_toolchain_config.bzl @@ -0,0 +1,61 @@ +# buildifier: disable=bzl-visibility +load( + "@rules_cc//cc/private/toolchain:unix_cc_toolchain_config.bzl", + unix_cc_toolchain_config = "cc_toolchain_config", +) + +# Macro for calling cc_toolchain_config from @bazel_tools with setting the +# right paths and flags for the tools. +def cc_toolchain_config( + name, + abi_libc_version, + abi_version, + compile_flags, + compiler, + conly_flags, + coverage_compile_flags, + coverage_link_flags, + cpu, + cxx_builtin_include_directories, + cxx_flags, + dbg_compile_flags, + host_system_name, + link_flags, + link_libs, + opt_compile_flags, + opt_link_flags, + supports_start_end_lib, + target_libc, + target_system_name, + tool_paths, + toolchain_identifier, + unfiltered_compile_flags, + extra_features = []): + unix_cc_toolchain_config( + name = name, + abi_libc_version = abi_libc_version, + abi_version = abi_version, + archive_flags = [], + compile_flags = compile_flags, + compiler = compiler, + conly_flags = conly_flags, + coverage_compile_flags = coverage_compile_flags, + coverage_link_flags = coverage_link_flags, + cpu = cpu, + cxx_builtin_include_directories = cxx_builtin_include_directories, + cxx_flags = cxx_flags, + dbg_compile_flags = dbg_compile_flags, + fastbuild_compile_flags = [], + host_system_name = host_system_name, + link_flags = link_flags, + link_libs = link_libs, + extra_features = extra_features, + opt_compile_flags = opt_compile_flags, + opt_link_flags = opt_link_flags, + supports_start_end_lib = supports_start_end_lib, + target_libc = target_libc, + target_system_name = target_system_name, + tool_paths = tool_paths, + toolchain_identifier = toolchain_identifier, + unfiltered_compile_flags = unfiltered_compile_flags, + ) diff --git a/examples/inject_extra_features/toolchain/cc_wrapper.sh b/examples/inject_extra_features/toolchain/cc_wrapper.sh new file mode 100644 index 000000000..4f0e23536 --- /dev/null +++ b/examples/inject_extra_features/toolchain/cc_wrapper.sh @@ -0,0 +1,54 @@ +#!/usr/bin/env bash +# +# Copyright 2015 The Bazel Authors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Ship the environment to the C++ action +# +set -eu + +OUTPUT= + +function parse_option() { + local -r opt="$1" + if [[ "${OUTPUT}" = "1" ]]; then + OUTPUT=$opt + elif [[ "$opt" = "-o" ]]; then + # output is coming + OUTPUT=1 + fi +} + +# let parse the option list +for i in "$@"; do + if [[ "$i" = @* && -r "${i:1}" ]]; then + while IFS= read -r opt + do + parse_option "$opt" + done < "${i:1}" || exit 1 + else + parse_option "$i" + fi +done + +# Set-up the environment + + +# Call the C++ compiler +/usr/bin/gcc-13 "$@" + +# Generate an empty file if header processing succeeded. +if [[ "${OUTPUT}" == *.h.processed ]]; then + echo -n > "${OUTPUT}" +fi diff --git a/examples/inject_extra_features/toolchain/deps_scanner_wrapper.sh b/examples/inject_extra_features/toolchain/deps_scanner_wrapper.sh new file mode 100644 index 000000000..eaab49d3e --- /dev/null +++ b/examples/inject_extra_features/toolchain/deps_scanner_wrapper.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +# +# Ship the environment to the C++ action +# +set -eu + +# Set-up the environment + + +# Call the C++ compiler + +/usr/bin/gcc-10 -E -x c++ -fmodules-ts -fdeps-file=out.tmp -fdeps-format=p1689r5 "$@" >"$DEPS_SCANNER_OUTPUT_FILE" diff --git a/examples/inject_extra_features/toolchain/validate_static_library.sh b/examples/inject_extra_features/toolchain/validate_static_library.sh new file mode 100644 index 000000000..6c959e4a5 --- /dev/null +++ b/examples/inject_extra_features/toolchain/validate_static_library.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash +# +# Copyright 2023 The Bazel Authors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +set -euo pipefail + +# Find all duplicate symbols in the given static library: +# 1. Use nm to list all global symbols in the library in POSIX format: +# libstatic.a[my_object.o]: my_function T 1234 abcd +# 2. Use sed to transform the output to a format that can be sorted by symbol +# name and is readable by humans: +# my_object.o: T my_function +# By using the `t` and `d` commands, lines for symbols of type U (undefined) +# as well as V and W (weak) and their local lowercase variants are removed. +# 3. Use sort to sort the lines by symbol name. +# 4. Use uniq to only keep the lines corresponding to duplicate symbols. +# 5. Use c++filt to demangle the symbol names. +# c++filt is applied to the duplicated symbols instead of using the -C flag +# of nm because it is not in POSIX and demangled names may not be unique +# (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=35201). +DUPLICATE_SYMBOLS=$( + "/usr/bin/nm" -A -g -P "$1" | + sed -E -e 's/.*\[([^][]+)\]: (.+) ([A-TX-Z]) [a-f0-9]+ [a-f0-9]+/\1: \3 \2/g' -e t -e d | + LC_ALL=C sort -k 3 | + LC_ALL=C uniq -D -f 2 | + "/usr/bin/c++filt") +if [[ -n "$DUPLICATE_SYMBOLS" ]]; then + >&2 echo "Duplicate symbols found in $1:" + >&2 echo "$DUPLICATE_SYMBOLS" + exit 1 +else + touch "$2" +fi