pax_global_header00006660000000000000000000000064147007256150014521gustar00rootroot0000000000000052 comment=be5e15fc2783b11573a9f82d8d89f0c940728fe1 rules_cc-0.0.11/000077500000000000000000000000001470072561500133775ustar00rootroot00000000000000rules_cc-0.0.11/.bazelci/000077500000000000000000000000001470072561500150665ustar00rootroot00000000000000rules_cc-0.0.11/.bazelci/presubmit.yml000066400000000000000000000026211470072561500176240ustar00rootroot00000000000000--- x_defaults: # YAML has a feature for "repeated nodes", BazelCI is fine with extra nodes # it doesn't know about; so that is used to avoid repeating common subparts. common: &common # We have to list every package because even with exclusion notation -//foo # Bazel will load the excluded package and it will be an error because at # release Bazel the cc_libraries do not have all the attributes. build_targets: - "//:all" - "//cc:all" - "//cc/private/rules_impl:all" - "//cc/private/toolchain:all" - "//cc/runfiles:all" - "//examples:all" - "//examples/my_c_archive:all" - "//examples/my_c_compile:all" - "//examples/write_cc_toolchain_cpu:all" - "//tools/migration:all" - "//tests/..." test_flags: - "--test_timeout=120" test_targets: - "//:all" - "//cc:all" - "//cc/private/rules_impl:all" - "//cc/private/toolchain:all" - "//examples:all" - "//examples/my_c_archive:all" - "//examples/my_c_compile:all" - "//examples/write_cc_toolchain_cpu:all" - "//tools/migration:all" - "//tests/..." buildifier: version: latest warnings: "all" tasks: ubuntu1804: <<: *common macos: <<: *common windows: <<: *common ubuntu_bzlmod: name: Bzlmod platform: ubuntu1804 build_flags: - "--enable_bzlmod" - "--ignore_dev_dependency" build_targets: - "//cc/..." rules_cc-0.0.11/.bcr/000077500000000000000000000000001470072561500142235ustar00rootroot00000000000000rules_cc-0.0.11/.bcr/metadata.template.json000066400000000000000000000003521470072561500205100ustar00rootroot00000000000000{ "homepage": "https://github.com/bazelbuild/rules_cc", "maintainers": [ { "email": "ilist@google.com", "github": "comius", "name": "Ivo Ristovski List" } ], "versions": [], "yanked_versions": {} } rules_cc-0.0.11/.bcr/presubmit.yml000066400000000000000000000004061470072561500167600ustar00rootroot00000000000000matrix: platform: ["centos7", "debian10", "macos", "ubuntu2004", "windows"] bazel: - 6.x - 7.x tasks: verify_targets: name: "Verify build targets" platform: ${{ platform }} bazel: ${{ bazel }} build_targets: - "@rules_cc//cc/..." rules_cc-0.0.11/.bcr/source.template.json000066400000000000000000000002301470072561500202230ustar00rootroot00000000000000{ "integrity": "", "strip_prefix": "{REPO}-{VERSION}", "url": "https://github.com/{OWNER}/{REPO}/releases/download/{TAG}/rules_cc-{TAG}.tar.gz" } rules_cc-0.0.11/.gitignore000066400000000000000000000000331470072561500153630ustar00rootroot00000000000000/bazel-* MODULE.bazel.lock rules_cc-0.0.11/AUTHORS000066400000000000000000000004531470072561500144510ustar00rootroot00000000000000# This the official list of authors for copyright purposes. # This file is distinct from the CONTRIBUTORS files. # See the latter for an explanation. # Names should be added to this file as: # Name or Organization # The email address is not required for organizations. Google Inc. rules_cc-0.0.11/BUILD000066400000000000000000000012041470072561500141560ustar00rootroot00000000000000load("//cc:defs.bzl", "cc_library") package(default_visibility = ["//visibility:public"]) licenses(["notice"]) exports_files(["LICENSE"]) cc_library(name = "empty_lib") # Label flag for extra libraries to be linked into every binary. # TODO(bazel-team): Support passing flag multiple times to build a list. label_flag( name = "link_extra_libs", build_setting_default = ":empty_lib", ) # The final extra library to be linked into every binary target. This collects # the above flag, but may also include more libraries depending on config. cc_library( name = "link_extra_lib", deps = [ ":link_extra_libs", ], ) rules_cc-0.0.11/CODEOWNERS000066400000000000000000000000571470072561500147740ustar00rootroot00000000000000* @oquenchil @c-mita @comius @buildbreaker2021 rules_cc-0.0.11/CONTRIBUTING.md000066400000000000000000000021151470072561500156270ustar00rootroot00000000000000# How to Contribute We'd love to accept your patches and contributions to this project. There are just a few small guidelines you need to follow. ## Contributor License Agreement Contributions to this project must be accompanied by a Contributor License Agreement. You (or your employer) retain the copyright to your contribution; this simply gives us permission to use and redistribute your contributions as part of the project. Head over to to see your current agreements on file or to sign a new one. You generally only need to submit a CLA once, so if you've already submitted one (even if it was for a different project), you probably don't need to do it again. ## Code reviews All submissions, including submissions by project members, require review. We use GitHub pull requests for this purpose. Consult [GitHub Help](https://help.github.com/articles/about-pull-requests/) for more information on using pull requests. ## Community Guidelines This project follows [Google's Open Source Community Guidelines](https://opensource.google.com/conduct/). rules_cc-0.0.11/ISSUE_TEMPLATE.md000066400000000000000000000040021470072561500161000ustar00rootroot00000000000000 > ATTENTION! Please read and follow: > - if this is a _question_ about how to build / test / query / deploy using Bazel, ask it on StackOverflow instead: https://stackoverflow.com/questions/tagged/bazel > - if this is a _discussion starter_, send it to bazel-discuss@googlegroups.com or cc-bazel-discuss@googlegroups.com > - if this is a _bug_ or _feature request_, fill the form below as best as you can. ### Description of the problem / feature request: > Replace this line with your answer. ### Feature requests: what underlying problem are you trying to solve with this feature? > Replace this line with your answer. ### Bugs: what's the simplest, easiest way to reproduce this bug? Please provide a minimal example if possible. > Replace this line with your answer. ### What operating system are you running Bazel on? > Replace this line with your answer. ### What's the output of `bazel info release`? > Replace this line with your answer. ### If `bazel info release` returns "development version" or "(@non-git)", tell us how you built Bazel. > Replace this line with your answer. ### What version of rules_cc do you use? Can you paste the workspace rule used to fetch rules_cc? What other relevant dependencies does your project have? > Replace this line with your answer. ### What Bazel options do you use to trigger the issue? What C++ toolchain do you use? > Replace this line with your answer. ### Have you found anything relevant by searching the web? > Replace these lines with your answer. > > Places to look: > * StackOverflow: http://stackoverflow.com/questions/tagged/bazel > * GitHub issues: > * https://github.com/bazelbuild/rules_cc/issues > * https://github.com/bazelbuild/bazel/issues > * email threads: > * https://groups.google.com/forum/#!forum/bazel-discuss > * https://groups.google.com/forum/#!forum/cc-bazel-discuss ### Any other information, logs, or outputs that you want to share? > Replace these lines with your answer. > > If the files are large, upload as attachment or provide link. rules_cc-0.0.11/LICENSE000066400000000000000000000261351470072561500144130ustar00rootroot00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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.rules_cc-0.0.11/MODULE.bazel000066400000000000000000000010411470072561500153770ustar00rootroot00000000000000module( name = "rules_cc", version = "0.0.11", compatibility_level = 1, ) bazel_dep(name = "bazel_skylib", version = "1.7.1") bazel_dep(name = "platforms", version = "0.0.10") cc_configure = use_extension("//cc:extensions.bzl", "cc_configure_extension") use_repo(cc_configure, "local_config_cc", "local_config_cc_toolchains") register_toolchains("@local_config_cc_toolchains//:all") bazel_dep(name = "rules_testing", version = "0.6.0", dev_dependency = True) bazel_dep(name = "stardoc", version = "0.7.0", dev_dependency = True) rules_cc-0.0.11/README.md000066400000000000000000000061731470072561500146650ustar00rootroot00000000000000# C++ rules for Bazel * Postsubmit [![Build status](https://badge.buildkite.com/f03592ae2d7d25a2abc2a2ba776e704823fa17fd3e061f5103.svg?branch=main)](https://buildkite.com/bazel/rules-cc) * Postsubmit + Current Bazel Incompatible flags [![Build status](https://badge.buildkite.com/5ba709cc33e5855078a1f8570adcf8e0a78ea93591bc0b4e81.svg?branch=master)](https://buildkite.com/bazel/rules-cc-plus-bazelisk-migrate) This repository contains a Starlark implementation of C++ rules in Bazel. The rules are being incrementally converted from their native implementations in the [Bazel source tree](https://source.bazel.build/bazel/+/master:src/main/java/com/google/devtools/build/lib/rules/cpp/). For the list of C++ rules, see the Bazel [documentation](https://docs.bazel.build/versions/main/be/overview.html). # Getting Started There is no need to use rules from this repository just yet. If you want to use `rules_cc` anyway, add the following to your `WORKSPACE` file: ```starlark load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") http_archive( name = "rules_cc", urls = ["https://github.com/bazelbuild/rules_cc/archive/refs/tags/.tar.gz"], sha256 = "...", ) ``` Then, in your `BUILD` files, import and use the rules: ```starlark load("@rules_cc//cc:defs.bzl", "cc_library") cc_library( ... ) ``` # Using the rules_cc toolchain This repo contains an auto-detecting toolchain that expects to find tools installed on your host machine. This is non-hermetic, and may have varying behaviors depending on the versions of tools found. There are third-party contributed hermetic toolchains you may want to investigate: - LLVM: - GCC (Linux only): - zig cc: If you'd like to use the cc toolchain defined in this repo, add this to your WORKSPACE after you include rules_cc: ```bzl load("@rules_cc//cc:repositories.bzl", "rules_cc_dependencies", "rules_cc_toolchains") rules_cc_dependencies() rules_cc_toolchains() ``` # Migration Tools This repository also contains migration tools that can be used to migrate your project for Bazel incompatible changes. ## Legacy fields migrator Script that migrates legacy crosstool fields into features ([incompatible flag](https://github.com/bazelbuild/bazel/issues/6861), [tracking issue](https://github.com/bazelbuild/bazel/issues/5883)). TLDR: ``` bazel run @rules_cc//tools/migration:legacy_fields_migrator -- \ --input=my_toolchain/CROSSTOOL \ --inline ``` # Contributing Bazel and `rules_cc` are the work of many contributors. We appreciate your help! To contribute, please read the contribution guidelines: [CONTRIBUTING.md](https://github.com/bazelbuild/rules_cc/blob/main/CONTRIBUTING.md). Note that the `rules_cc` use the GitHub issue tracker for bug reports and feature requests only. For asking questions see: * [Stack Overflow](https://stackoverflow.com/questions/tagged/bazel) * [`rules_cc` mailing list](https://groups.google.com/forum/#!forum/cc-bazel-discuss) * Slack channel `#cc` on [slack.bazel.build](https://slack.bazel.build) rules_cc-0.0.11/WORKSPACE000066400000000000000000000070661470072561500146710ustar00rootroot00000000000000workspace(name = "rules_cc") load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") http_archive( name = "bazel_skylib", sha256 = "b8a1527901774180afc798aeb28c4634bdccf19c4d98e7bdd1ce79d1fe9aaad7", urls = [ "https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/releases/download/1.4.1/bazel-skylib-1.4.1.tar.gz", "https://github.com/bazelbuild/bazel-skylib/releases/download/1.4.1/bazel-skylib-1.4.1.tar.gz", ], ) http_archive( name = "com_google_googletest", sha256 = "81964fe578e9bd7c94dfdb09c8e4d6e6759e19967e397dbea48d1c10e45d0df2", strip_prefix = "googletest-release-1.12.1", urls = [ "https://mirror.bazel.build/github.com/google/googletest/archive/refs/tags/release-1.12.1.tar.gz", "https://github.com/google/googletest/archive/refs/tags/release-1.12.1.tar.gz", ], ) http_archive( name = "io_abseil_py", sha256 = "0fb3a4916a157eb48124ef309231cecdfdd96ff54adf1660b39c0d4a9790a2c0", strip_prefix = "abseil-py-1.4.0", urls = [ "https://github.com/abseil/abseil-py/archive/refs/tags/v1.4.0.tar.gz", ], ) http_archive( name = "io_bazel_rules_go", sha256 = "91585017debb61982f7054c9688857a2ad1fd823fc3f9cb05048b0025c47d023", urls = [ "https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.42.0/rules_go-v0.42.0.zip", "https://github.com/bazelbuild/rules_go/releases/download/v0.42.0/rules_go-v0.42.0.zip", ], ) http_archive( name = "platforms", sha256 = "218efe8ee736d26a3572663b374a253c012b716d8af0c07e842e82f238a0a7ee", urls = [ "https://mirror.bazel.build/github.com/bazelbuild/platforms/releases/download/0.0.10/platforms-0.0.10.tar.gz", "https://github.com/bazelbuild/platforms/releases/download/0.0.10/platforms-0.0.10.tar.gz", ], ) http_archive( name = "py_mock", patch_cmds = [ "mkdir -p py/mock", "mv mock.py py/mock/__init__.py", """echo 'licenses(["notice"])' > BUILD""", "touch py/BUILD", """echo 'py_library(name = "mock", srcs = ["__init__.py"], visibility = ["//visibility:public"],)' > py/mock/BUILD""", ], sha256 = "b839dd2d9c117c701430c149956918a423a9863b48b09c90e30a6013e7d2f44f", strip_prefix = "mock-1.0.1", urls = [ "https://mirror.bazel.build/pypi.python.org/packages/source/m/mock/mock-1.0.1.tar.gz", "https://pypi.python.org/packages/source/m/mock/mock-1.0.1.tar.gz", ], ) http_archive( name = "rules_proto", sha256 = "9a0503631679e9ab4e27d891ea60fee3e86a85654ea2048cae25516171dd260e", strip_prefix = "rules_proto-e51f588e5932966ab9e63e0b0f6de6f740cf04c4", urls = [ "https://mirror.bazel.build/github.com/bazelbuild/rules_proto/archive/e51f588e5932966ab9e63e0b0f6de6f740cf04c4.tar.gz", "https://github.com/bazelbuild/rules_proto/archive/e51f588e5932966ab9e63e0b0f6de6f740cf04c4.tar.gz", ], ) load("@bazel_skylib//:workspace.bzl", "bazel_skylib_workspace") bazel_skylib_workspace() load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies") go_rules_dependencies() go_register_toolchains(version = "1.20.5") load("@rules_proto//proto:repositories.bzl", "rules_proto_dependencies", "rules_proto_toolchains") rules_proto_dependencies() rules_proto_toolchains() http_archive( name = "rules_testing", sha256 = "02c62574631876a4e3b02a1820cb51167bb9cdcdea2381b2fa9d9b8b11c407c4", strip_prefix = "rules_testing-0.6.0", url = "https://github.com/bazelbuild/rules_testing/releases/download/v0.6.0/rules_testing-v0.6.0.tar.gz", ) rules_cc-0.0.11/cc/000077500000000000000000000000001470072561500137645ustar00rootroot00000000000000rules_cc-0.0.11/cc/BUILD000066400000000000000000000050351470072561500145510ustar00rootroot00000000000000# Copyright 2019 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. load("@bazel_skylib//:bzl_library.bzl", "bzl_library") package(default_visibility = ["//visibility:public"]) licenses(["notice"]) # Apache 2.0 filegroup( name = "all_files_for_testing", srcs = glob(["**"]) + [ "//cc/private/rules_impl:srcs", "//cc/private/toolchain:srcs", ], ) exports_files([ "defs.bzl", "action_names.bzl", "system_library.bzl", ]) # The toolchain type used to distinguish cc toolchains. alias( name = "toolchain_type", actual = "@bazel_tools//tools/cpp:toolchain_type", ) filegroup( name = "action_names_test_files", testonly = True, srcs = [ "BUILD", "action_names.bzl", ], visibility = ["//visibility:public"], ) filegroup( name = "bzl_srcs", srcs = glob([ "**/*.bzl", ]) + [ "//cc/private/rules_impl:bzl_srcs", "//cc/private/toolchain:bzl_srcs", ], visibility = ["//visibility:public"], ) filegroup( name = "srcs", srcs = glob([ "**/*.bzl", "**/BUILD", ]) + [ "//cc/private/rules_impl:srcs", "//cc/private/toolchain:srcs", ], visibility = ["//visibility:public"], ) # TODO(aiuto): Find a way to strip this rule from the distribution tarball. filegroup( name = "distribution", srcs = glob([ "**", ]), visibility = [ "//distro:__pkg__", ], ) bzl_library( name = "find_cc_toolchain_bzl", srcs = ["find_cc_toolchain.bzl"], visibility = ["//visibility:public"], ) bzl_library( name = "action_names_bzl", srcs = ["action_names.bzl"], visibility = ["//visibility:public"], ) bzl_library( name = "cc_toolchain_config_lib_bzl", srcs = ["cc_toolchain_config_lib.bzl"], visibility = ["//cc/toolchains:__subpackages__"], ) cc_toolchain_alias(name = "current_cc_toolchain") cc_toolchain_alias( name = "optional_current_cc_toolchain", mandatory = False, ) cc_libc_top_alias(name = "current_libc_top") rules_cc-0.0.11/cc/action_names.bzl000066400000000000000000000171301470072561500171370ustar00rootroot00000000000000# Copyright 2018 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. """Constants for action names used for C++ rules.""" # Keep in sync with //cc/toolchains/actions:BUILD. # Name for the C compilation action. C_COMPILE_ACTION_NAME = "c-compile" # Name of the C++ compilation action. CPP_COMPILE_ACTION_NAME = "c++-compile" # Name of the linkstamp-compile action. LINKSTAMP_COMPILE_ACTION_NAME = "linkstamp-compile" # Name of the action used to compute CC_FLAGS make variable. CC_FLAGS_MAKE_VARIABLE_ACTION_NAME = "cc-flags-make-variable" # Name of the C++ module codegen action. CPP_MODULE_CODEGEN_ACTION_NAME = "c++-module-codegen" # Name of the C++ header parsing action. CPP_HEADER_PARSING_ACTION_NAME = "c++-header-parsing" # Name of the C++ deps scanning action. CPP_MODULE_DEPS_SCANNING_ACTION_NAME = "c++-module-deps-scanning" # Name of the C++ module compile action. CPP20_MODULE_COMPILE_ACTION_NAME = "c++20-module-compile" CPP20_MODULE_CODEGEN_ACTION_NAME = "c++20-module-codegen" # Name of the C++ module compile action. CPP_MODULE_COMPILE_ACTION_NAME = "c++-module-compile" # Name of the assembler action. ASSEMBLE_ACTION_NAME = "assemble" # Name of the assembly preprocessing action. PREPROCESS_ASSEMBLE_ACTION_NAME = "preprocess-assemble" LLVM_COV = "llvm-cov" # Name of the action producing ThinLto index. LTO_INDEXING_ACTION_NAME = "lto-indexing" # Name of the action producing ThinLto index for executable. LTO_INDEX_FOR_EXECUTABLE_ACTION_NAME = "lto-index-for-executable" # Name of the action producing ThinLto index for dynamic library. LTO_INDEX_FOR_DYNAMIC_LIBRARY_ACTION_NAME = "lto-index-for-dynamic-library" # Name of the action producing ThinLto index for nodeps dynamic library. LTO_INDEX_FOR_NODEPS_DYNAMIC_LIBRARY_ACTION_NAME = "lto-index-for-nodeps-dynamic-library" # Name of the action compiling lto bitcodes into native objects. LTO_BACKEND_ACTION_NAME = "lto-backend" # Name of the link action producing executable binary. CPP_LINK_EXECUTABLE_ACTION_NAME = "c++-link-executable" # Name of the link action producing dynamic library. CPP_LINK_DYNAMIC_LIBRARY_ACTION_NAME = "c++-link-dynamic-library" # Name of the link action producing dynamic library that doesn't include it's # transitive dependencies. CPP_LINK_NODEPS_DYNAMIC_LIBRARY_ACTION_NAME = "c++-link-nodeps-dynamic-library" # Name of the archiving action producing static library. CPP_LINK_STATIC_LIBRARY_ACTION_NAME = "c++-link-static-library" # Name of the action stripping the binary. STRIP_ACTION_NAME = "strip" # A string constant for the objc compilation action. OBJC_COMPILE_ACTION_NAME = "objc-compile" # A string constant for the objc++ compile action. OBJCPP_COMPILE_ACTION_NAME = "objc++-compile" # A string constant for the objc executable link action. OBJC_EXECUTABLE_ACTION_NAME = "objc-executable" # A string constant for the objc fully-link link action. OBJC_FULLY_LINK_ACTION_NAME = "objc-fully-link" # A string constant for the clif actions. CLIF_MATCH_ACTION_NAME = "clif-match" # A string constant for the obj copy actions. OBJ_COPY_ACTION_NAME = "objcopy_embed_data" # A string constant for the validation action for cc_static_library. VALIDATE_STATIC_LIBRARY = "validate-static-library" ACTION_NAMES = struct( c_compile = C_COMPILE_ACTION_NAME, cpp_compile = CPP_COMPILE_ACTION_NAME, linkstamp_compile = LINKSTAMP_COMPILE_ACTION_NAME, cc_flags_make_variable = CC_FLAGS_MAKE_VARIABLE_ACTION_NAME, cpp_module_codegen = CPP_MODULE_CODEGEN_ACTION_NAME, cpp_header_parsing = CPP_HEADER_PARSING_ACTION_NAME, cpp_module_deps_scanning = CPP_MODULE_DEPS_SCANNING_ACTION_NAME, cpp20_module_compile = CPP20_MODULE_COMPILE_ACTION_NAME, cpp20_module_codegen = CPP20_MODULE_CODEGEN_ACTION_NAME, cpp_module_compile = CPP_MODULE_COMPILE_ACTION_NAME, assemble = ASSEMBLE_ACTION_NAME, preprocess_assemble = PREPROCESS_ASSEMBLE_ACTION_NAME, llvm_cov = LLVM_COV, lto_indexing = LTO_INDEXING_ACTION_NAME, lto_backend = LTO_BACKEND_ACTION_NAME, lto_index_for_executable = LTO_INDEX_FOR_EXECUTABLE_ACTION_NAME, lto_index_for_dynamic_library = LTO_INDEX_FOR_DYNAMIC_LIBRARY_ACTION_NAME, lto_index_for_nodeps_dynamic_library = LTO_INDEX_FOR_NODEPS_DYNAMIC_LIBRARY_ACTION_NAME, cpp_link_executable = CPP_LINK_EXECUTABLE_ACTION_NAME, cpp_link_dynamic_library = CPP_LINK_DYNAMIC_LIBRARY_ACTION_NAME, cpp_link_nodeps_dynamic_library = CPP_LINK_NODEPS_DYNAMIC_LIBRARY_ACTION_NAME, cpp_link_static_library = CPP_LINK_STATIC_LIBRARY_ACTION_NAME, strip = STRIP_ACTION_NAME, objc_compile = OBJC_COMPILE_ACTION_NAME, objc_executable = OBJC_EXECUTABLE_ACTION_NAME, objc_fully_link = OBJC_FULLY_LINK_ACTION_NAME, objcpp_compile = OBJCPP_COMPILE_ACTION_NAME, clif_match = CLIF_MATCH_ACTION_NAME, objcopy_embed_data = OBJ_COPY_ACTION_NAME, validate_static_library = VALIDATE_STATIC_LIBRARY, ) # Names of actions that parse or compile C++ code. ALL_CPP_COMPILE_ACTION_NAMES = [ ACTION_NAMES.linkstamp_compile, ACTION_NAMES.cpp_compile, ACTION_NAMES.cpp_header_parsing, ACTION_NAMES.cpp_module_compile, ACTION_NAMES.cpp_module_codegen, ACTION_NAMES.lto_backend, ACTION_NAMES.clif_match, ] # Names of actions that parse or compile C, C++ and assembly code. ALL_CC_COMPILE_ACTION_NAMES = ALL_CPP_COMPILE_ACTION_NAMES + [ ACTION_NAMES.c_compile, ACTION_NAMES.preprocess_assemble, ACTION_NAMES.assemble, ] # Names of actions that link C, C++ and assembly code. ALL_CC_LINK_ACTION_NAMES = [ ACTION_NAMES.cpp_link_executable, ACTION_NAMES.cpp_link_dynamic_library, ACTION_NAMES.cpp_link_nodeps_dynamic_library, ACTION_NAMES.lto_index_for_executable, ACTION_NAMES.lto_index_for_dynamic_library, ACTION_NAMES.lto_index_for_nodeps_dynamic_library, ] # Names of actions that link entire programs. CC_LINK_EXECUTABLE_ACTION_NAMES = [ ACTION_NAMES.cpp_link_executable, ACTION_NAMES.lto_index_for_executable, ] # Names of actions that link dynamic libraries. DYNAMIC_LIBRARY_LINK_ACTION_NAMES = [ ACTION_NAMES.cpp_link_dynamic_library, ACTION_NAMES.cpp_link_nodeps_dynamic_library, ACTION_NAMES.lto_index_for_dynamic_library, ACTION_NAMES.lto_index_for_nodeps_dynamic_library, ] # Names of actions that link nodeps dynamic libraries. NODEPS_DYNAMIC_LIBRARY_LINK_ACTION_NAMES = [ ACTION_NAMES.cpp_link_nodeps_dynamic_library, ACTION_NAMES.lto_index_for_nodeps_dynamic_library, ] # Names of actions that link transitive dependencies. TRANSITIVE_LINK_ACTION_NAMES = [ ACTION_NAMES.cpp_link_executable, ACTION_NAMES.cpp_link_dynamic_library, ACTION_NAMES.lto_index_for_executable, ACTION_NAMES.lto_index_for_dynamic_library, ] ACTION_NAME_GROUPS = struct( all_cc_compile_actions = ALL_CC_COMPILE_ACTION_NAMES, all_cc_link_actions = ALL_CC_LINK_ACTION_NAMES, all_cpp_compile_actions = ALL_CPP_COMPILE_ACTION_NAMES, cc_link_executable_actions = CC_LINK_EXECUTABLE_ACTION_NAMES, dynamic_library_link_actions = DYNAMIC_LIBRARY_LINK_ACTION_NAMES, nodeps_dynamic_library_link_actions = NODEPS_DYNAMIC_LIBRARY_LINK_ACTION_NAMES, transitive_link_actions = TRANSITIVE_LINK_ACTION_NAMES, ) rules_cc-0.0.11/cc/cc_binary.bzl000066400000000000000000000032631470072561500164320ustar00rootroot00000000000000# Copyright 2024 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. """cc_binary rule""" # TODO(bazel-team): To avoid breaking changes, if the below are no longer # forwarding to native rules, flag @bazel_tools@bazel_tools//tools/cpp:link_extra_libs # should either: (a) alias the flag @rules_cc//:link_extra_libs, or (b) be # added as a dependency to @rules_cc//:link_extra_lib. The intermediate library # @bazel_tools@bazel_tools//tools/cpp:link_extra_lib should either be added as a dependency # to @rules_cc//:link_extra_lib, or removed entirely (if possible). _LINK_EXTRA_LIB = Label("//:link_extra_lib") def cc_binary(**attrs): """Bazel cc_binary rule. https://docs.bazel.build/versions/main/be/c-cpp.html#cc_binary Args: **attrs: Rule attributes """ is_library = "linkshared" in attrs and attrs["linkshared"] # Executable builds also include the "link_extra_lib" library. if not is_library: if "deps" in attrs and attrs["deps"] != None: attrs["deps"] = attrs["deps"] + [_LINK_EXTRA_LIB] else: attrs["deps"] = [_LINK_EXTRA_LIB] # buildifier: disable=native-cc native.cc_binary(**attrs) rules_cc-0.0.11/cc/cc_import.bzl000066400000000000000000000013111470072561500164500ustar00rootroot00000000000000# Copyright 2024 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. """cc_import rule""" def cc_import(**kwargs): native.cc_import(**kwargs) # buildifier: disable=native-cc rules_cc-0.0.11/cc/cc_library.bzl000066400000000000000000000013141470072561500166050ustar00rootroot00000000000000# Copyright 2024 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. """cc_library rule""" def cc_library(**kwargs): native.cc_library(**kwargs) # buildifier: disable=native-cc rules_cc-0.0.11/cc/cc_shared_library.bzl000066400000000000000000000013321470072561500201330ustar00rootroot00000000000000# Copyright 2024 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. """cc_library rule""" def cc_shared_library(**kwargs): native.cc_shared_library(**kwargs) # buildifier: disable=native-cc rules_cc-0.0.11/cc/cc_test.bzl000066400000000000000000000032521470072561500161230ustar00rootroot00000000000000# Copyright 2024 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. """cc_test rule""" # TODO(bazel-team): To avoid breaking changes, if the below are no longer # forwarding to native rules, flag @bazel_tools@bazel_tools//tools/cpp:link_extra_libs # should either: (a) alias the flag @rules_cc//:link_extra_libs, or (b) be # added as a dependency to @rules_cc//:link_extra_lib. The intermediate library # @bazel_tools@bazel_tools//tools/cpp:link_extra_lib should either be added as a dependency # to @rules_cc//:link_extra_lib, or removed entirely (if possible). _LINK_EXTRA_LIB = Label("//:link_extra_lib") def cc_test(**attrs): """Bazel cc_test rule. https://docs.bazel.build/versions/main/be/c-cpp.html#cc_test Args: **attrs: Rule attributes """ is_library = "linkshared" in attrs and attrs["linkshared"] # Executable builds also include the "link_extra_lib" library. if not is_library: if "deps" in attrs and attrs["deps"] != None: attrs["deps"] = attrs["deps"] + [_LINK_EXTRA_LIB] else: attrs["deps"] = [_LINK_EXTRA_LIB] # buildifier: disable=native-cc native.cc_test(**attrs) rules_cc-0.0.11/cc/cc_toolchain_config_lib.bzl000066400000000000000000000556521470072561500213120ustar00rootroot00000000000000# Copyright 2018 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. """ A library of functions creating structs for CcToolchainConfigInfo.""" def _check_is_none(obj, parameter_name, method_name): if obj != None: fail("{} parameter of {} should be None, found {}." .format(parameter_name, method_name, type(obj))) def _check_is_none_or_right_type(obj, obj_of_right_type, parameter_name, method_name): if obj != None: _check_same_type(obj, obj_of_right_type, parameter_name, method_name) def _check_right_type(obj, expected_type, parameter_name, method_name): if type(obj) != expected_type: fail("{} parameter of {} should be a {}, found {}." .format(parameter_name, method_name, expected_type, type(obj))) def _check_same_type(obj, obj_of_right_type, parameter_name, method_name): _check_right_type(obj, type(obj_of_right_type), parameter_name, method_name) def _check_is_nonempty_string(obj, parameter_name, method_name): _check_same_type(obj, "", parameter_name, method_name) if obj == "": fail("{} parameter of {} must be a nonempty string." .format(parameter_name, method_name)) def _check_is_nonempty_list(obj, parameter_name, method_name): _check_same_type(obj, [], parameter_name, method_name) if len(obj) == 0: fail("{} parameter of {} must be a nonempty list." .format(parameter_name, method_name)) EnvEntryInfo = provider( "A key/value pair to be added as an environment variable.", fields = ["key", "value", "expand_if_available", "type_name"], ) def env_entry(key, value, expand_if_available = None): """ A key/value pair to be added as an environment variable. The returned EnvEntry provider finds its use in EnvSet creation through the env_entries parameter of env_set(); EnvSet groups environment variables that need to be expanded for specific actions. The value of this pair is expanded in the same way as is described in flag_group. The key remains an unexpanded string literal. Args: key: a string literal representing the name of the variable. value: the value to be expanded. expand_if_available: A build variable that needs to be available in order to expand the env_entry. Returns: An EnvEntryInfo provider. """ _check_is_nonempty_string(key, "key", "env_entry") _check_is_nonempty_string(value, "value", "env_entry") _check_is_none_or_right_type(expand_if_available, "string", "expand_if_available", "env_entry") return EnvEntryInfo( key = key, value = value, expand_if_available = expand_if_available, type_name = "env_entry", ) VariableWithValueInfo = provider( "Represents equality check between a variable and a certain value.", fields = ["name", "value", "type_name"], ) def variable_with_value(name, value): """ Represents equality check between a variable and a certain value. The returned provider finds its use through flag_group.expand_if_equal, making the expansion of the flag_group conditional on the value of the variable. Args: name: name of the variable. value: the value the variable should be compared against. Returns: A VariableWithValueInfo provider. """ _check_is_nonempty_string(name, "name", "variable_with_value") _check_is_nonempty_string(value, "value", "variable_with_value") return VariableWithValueInfo( name = name, value = value, type_name = "variable_with_value", ) MakeVariableInfo = provider( "A make variable that is made accessible to rules.", fields = ["name", "value", "type_name"], ) def make_variable(name, value): """ A make variable that is made accessible to rules.""" _check_is_nonempty_string(name, "name", "make_variable") _check_is_nonempty_string(value, "value", "make_variable") return MakeVariableInfo( name = name, value = value, type_name = "make_variable", ) FeatureSetInfo = provider( "A set of features.", fields = ["features", "type_name"], ) def feature_set(features = []): """ A set of features. Used to support logical 'and' when specifying feature requirements in a feature. Args: features: A list of unordered feature names. Returns: A FeatureSetInfo provider. """ _check_same_type(features, [], "features", "feature_set") return FeatureSetInfo(features = features, type_name = "feature_set") WithFeatureSetInfo = provider( "A set of positive and negative features.", fields = ["features", "not_features", "type_name"], ) def with_feature_set(features = [], not_features = []): """ A set of positive and negative features. This stanza will evaluate to true when every 'feature' is enabled, and every 'not_feature' is not enabled. Args: features: A list of feature names that need to be enabled. not_features: A list of feature names that need to not be enabled. Returns: A WithFeatureSetInfo provider. """ _check_same_type(features, [], "features", "with_feature_set") _check_same_type(not_features, [], "not_features", "with_feature_set") return WithFeatureSetInfo( features = features, not_features = not_features, type_name = "with_feature_set", ) EnvSetInfo = provider( "Groups a set of environment variables to apply for certain actions.", fields = ["actions", "env_entries", "with_features", "type_name"], ) def env_set(actions, env_entries = [], with_features = []): """ Groups a set of environment variables to apply for certain actions. EnvSet providers are passed to feature() and action_config(), to be applied to the actions they are specified for. Args: actions: A list of actions this env set applies to; each env set must specify at least one action. env_entries: A list of EnvEntry - the environment variables applied via this env set. with_features: A list of feature sets defining when this env set gets applied. The env set will be applied when any one of the feature sets evaluate to true. (That is, when when every 'feature' is enabled, and every 'not_feature' is not enabled.) If 'with_features' is omitted, the env set will be applied unconditionally for every action specified. Returns: An EnvSetInfo provider. """ _check_is_nonempty_list(actions, "actions", "env_set") _check_same_type(env_entries, [], "env_entries", "env_set") _check_same_type(with_features, [], "with_features", "env_set") return EnvSetInfo( actions = actions, env_entries = env_entries, with_features = with_features, type_name = "env_set", ) FlagGroupInfo = provider( "A group of flags. Supports parametrization via variable expansion.", fields = [ "flags", "flag_groups", "iterate_over", "expand_if_available", "expand_if_not_available", "expand_if_true", "expand_if_false", "expand_if_equal", "type_name", ], ) def flag_group( flags = [], flag_groups = [], iterate_over = None, expand_if_available = None, expand_if_not_available = None, expand_if_true = None, expand_if_false = None, expand_if_equal = None): """ A group of flags. Supports parametrization via variable expansion. To expand a variable of list type, flag_group has to be annotated with `iterate_over` message. Then all nested flags or flag_groups will be expanded repeatedly for each element of the list. For example: flag_group( iterate_over = 'include_path', flags = ['-I', '%{include_path}'], ) ... will get expanded to -I /to/path1 -I /to/path2 ... for each include_path /to/pathN. To expand a variable of structure type, use dot-notation, e.g.: flag_group( iterate_over = "libraries_to_link", flag_groups = [ flag_group( iterate_over = "libraries_to_link.libraries", flags = ["-L%{libraries_to_link.libraries.directory}"], ) ] ) Flag groups can be nested; if they are, the flag group must only contain other flag groups (no flags) so the order is unambiguously specified. In order to expand a variable of nested lists, 'iterate_over' can be used. For example: flag_group ( iterate_over = 'object_files', flag_groups = [ flag_group ( flags = ['--start-lib'], ), flag_group ( iterate_over = 'object_files', flags = ['%{object_files}'], ), flag_group ( flags = ['--end-lib'], ) ] ) ... will get expanded to --start-lib a1.o a2.o ... --end-lib --start-lib b1.o b2.o .. --end-lib with %{object_files} being a variable of nested list type [['a1.o', 'a2.o', ...], ['b1.o', 'b2.o', ...], ...]. Args: flags: a string list, representing flags. Only one of flags and flag_groups can be set, as to avoid ambiguity. flag_groups: a list of FlagGroup entries. Only one of flags and flag_groups can be set, as to avoid ambiguity. iterate_over: a string, representing a variable of list type. expand_if_available: A build variable that needs to be available in order to expand the flag_group. expand_if_not_available: A build variable that needs to be unavailable in order for this flag_group to be expanded. expand_if_true: if set, this variable needs to evaluate to True in order for the flag_group to be expanded. expand_if_false: if set, this variable needs to evalate to False in order for the flag_group to be expanded. expand_if_equal: a VariableWithValue, the flag_group is expanded in case of equality. Returns: A FlagGroupInfo provider. """ _check_same_type(flags, [], "flags", "flag_group") _check_same_type(flag_groups, [], "flag_groups", "flag_group") if len(flags) > 0 and len(flag_groups) > 0: fail("flag_group must not contain both a flag and another flag_group.") if len(flags) == 0 and len(flag_groups) == 0: fail("flag_group must contain either a list of flags or a list of flag_groups.") _check_is_none_or_right_type(expand_if_true, "string", "expand_if_true", "flag_group") _check_is_none_or_right_type(expand_if_false, "string", "expand_if_false", "flag_group") _check_is_none_or_right_type(expand_if_available, "string", "expand_if_available", "flag_group") _check_is_none_or_right_type( expand_if_not_available, "string", "expand_if_not_available", "flag_group", ) _check_is_none_or_right_type(iterate_over, "string", "iterate_over", "flag_group") return FlagGroupInfo( flags = flags, flag_groups = flag_groups, iterate_over = iterate_over, expand_if_available = expand_if_available, expand_if_not_available = expand_if_not_available, expand_if_true = expand_if_true, expand_if_false = expand_if_false, expand_if_equal = expand_if_equal, type_name = "flag_group", ) FlagSetInfo = provider( "A set of flags to be expanded in the command line for specific actions.", fields = [ "actions", "with_features", "flag_groups", "type_name", ], ) def flag_set( actions = [], with_features = [], flag_groups = []): """ A set of flags to be expanded in the command line for specific actions. Args: actions: The actions this flag set applies to; each flag set must specify at least one action. with_features: A list of feature sets defining when this flag set gets applied. The flag set will be applied when any one of the feature sets evaluate to true. (That is, when when every 'feature' is enabled, and every 'not_feature' is not enabled.) If 'with_feature' is omitted, the flag set will be applied unconditionally for every action specified. flag_groups: A FlagGroup list - the flags applied via this flag set. Returns: A FlagSetInfo provider. """ _check_same_type(actions, [], "actions", "flag_set") _check_same_type(with_features, [], "with_features", "flag_set") _check_same_type(flag_groups, [], "flag_groups", "flag_set") return FlagSetInfo( actions = actions, with_features = with_features, flag_groups = flag_groups, type_name = "flag_set", ) FeatureInfo = provider( "Contains all flag specifications for one feature.", fields = [ "name", "enabled", "flag_sets", "env_sets", "requires", "implies", "provides", "type_name", ], ) def feature( name, enabled = False, flag_sets = [], env_sets = [], requires = [], implies = [], provides = []): """ Contains all flag specifications for one feature. Args: name: The feature's name. It is possible to introduce a feature without a change to Bazel by adding a 'feature' section to the toolchain and adding the corresponding string as feature in the BUILD file. enabled: If 'True', this feature is enabled unless a rule type explicitly marks it as unsupported. flag_sets: A FlagSet list - If the given feature is enabled, the flag sets will be applied for the actions are specified for. env_sets: an EnvSet list - If the given feature is enabled, the env sets will be applied for the actions they are specified for. requires: A list of feature sets defining when this feature is supported by the toolchain. The feature is supported if any of the feature sets fully apply, that is, when all features of a feature set are enabled. If 'requires' is omitted, the feature is supported independently of which other features are enabled. Use this for example to filter flags depending on the build mode enabled (opt / fastbuild / dbg). implies: A string list of features or action configs that are automatically enabled when this feature is enabled. If any of the implied features or action configs cannot be enabled, this feature will (silently) not be enabled either. provides: A list of names this feature conflicts with. A feature cannot be enabled if: - 'provides' contains the name of a different feature or action config that we want to enable. - 'provides' contains the same value as a 'provides' in a different feature or action config that we want to enable. Use this in order to ensure that incompatible features cannot be accidentally activated at the same time, leading to hard to diagnose compiler errors. Returns: A FeatureInfo provider. """ _check_same_type(enabled, True, "enabled", "feature") _check_same_type(flag_sets, [], "flag_sets", "feature") _check_same_type(env_sets, [], "env_sets", "feature") _check_same_type(requires, [], "requires", "feature") _check_same_type(provides, [], "provides", "feature") _check_same_type(implies, [], "implies", "feature") return FeatureInfo( name = name, enabled = enabled, flag_sets = flag_sets, env_sets = env_sets, requires = requires, implies = implies, provides = provides, type_name = "feature", ) ToolPathInfo = provider( "Tool locations.", fields = ["name", "path", "type_name"], ) def tool_path(name, path): """ Tool locations. Args: name: Name of the tool. path: Location of the tool; Can be absolute path (in case of non hermetic toolchain), or path relative to the cc_toolchain's package. Returns: A ToolPathInfo provider. Deprecated: Prefer specifying an ActionConfig for the action that needs the tool. TODO(b/27903698) migrate to ActionConfig. """ _check_is_nonempty_string(name, "name", "tool_path") _check_is_nonempty_string(path, "path", "tool_path") return ToolPathInfo(name = name, path = path, type_name = "tool_path") ToolInfo = provider( doc = "Tool information. This differs from ToolPathInfo as it is intended to be used\ in action_configs and can accept labels.", fields = [ "path", "tool", "with_features", "execution_requirements", "type_name", ], ) def tool(path = None, with_features = [], execution_requirements = [], tool = None): """ Describes a tool associated with a crosstool action config. Args: path: Location of the tool; Can be absolute path (in case of non hermetic toolchain), or path relative to the cc_toolchain's package. If this parameter is set, tool must not be set. tool: The built-artifact that should be used as this tool. If this is set, path must not be set. with_features: A list of feature sets defining when this tool is applicable. The tool will used when any one of the feature sets evaluate to true. (That is, when when every 'feature' is enabled, and every 'not_feature' is not enabled.) If 'with_feature' is omitted, the tool will apply for any feature configuration. execution_requirements: Requirements on the execution environment for the execution of this tool, to be passed as out-of-band "hints" to the execution backend. Ex. "requires-mem:24g" Returns: A ToolInfo provider. """ if path == None and tool == None: fail("Parameter path or parameter tool of tool should not be None.") if path != None: _check_is_nonempty_string(path, "path", "tool") _check_is_none(tool, "tool", "tool") if tool != None: _check_is_none(path, "path", "tool") _check_right_type(tool, "File", "tool", "tool") _check_same_type(with_features, [], "with_features", "tool") _check_same_type(execution_requirements, [], "execution_requirements", "tool") return ToolInfo( path = path, tool = tool, with_features = with_features, execution_requirements = execution_requirements, type_name = "tool", ) ActionConfigInfo = provider( "Configuration of a Bazel action.", fields = [ "config_name", "action_name", "enabled", "tools", "flag_sets", "implies", "type_name", ], ) def action_config( action_name, enabled = False, tools = [], flag_sets = [], implies = []): """ Configuration of a Bazel action. An action config corresponds to a Bazel action, and allows selection of a tool based on activated features. Action config activation occurs by the same semantics as features: a feature can 'require' or 'imply' an action config in the same way that it would another feature. Args: action_name: The name of the Bazel action that this config applies to, ex. 'c-compile' or 'c-module-compile'. enabled: If 'True', this action is enabled unless a rule type explicitly marks it as unsupported. tools: The tool applied to the action will be the first Tool with a feature set that matches the feature configuration. An error will be thrown if no tool matches a provided feature configuration - for that reason, it's a good idea to provide a default tool with an empty feature set. flag_sets: If the given action config is enabled, the flag sets will be applied to the corresponding action. implies: A list of features or action configs that are automatically enabled when this action config is enabled. If any of the implied features or action configs cannot be enabled, this action config will (silently) not be enabled either. Returns: An ActionConfigInfo provider. """ _check_is_nonempty_string(action_name, "name", "action_config") _check_same_type(enabled, True, "enabled", "action_config") _check_same_type(tools, [], "tools", "action_config") _check_same_type(flag_sets, [], "flag_sets", "action_config") _check_same_type(implies, [], "implies", "action_config") return ActionConfigInfo( action_name = action_name, enabled = enabled, tools = tools, flag_sets = flag_sets, implies = implies, type_name = "action_config", ) ArtifactNamePatternInfo = provider( "The name for an artifact of a given category of input or output artifacts to an action.", fields = [ "category_name", "prefix", "extension", "type_name", ], ) def artifact_name_pattern(category_name, prefix, extension): """ The name for an artifact of a given category of input or output artifacts to an action. Args: category_name: The category of artifacts that this selection applies to. This field is compared against a list of categories defined in bazel. Example categories include "linked_output" or "debug_symbols". An error is thrown if no category is matched. prefix: The prefix for creating the artifact for this selection. Together with the extension it is used to create an artifact name based on the target name. extension: The extension for creating the artifact for this selection. Together with the prefix it is used to create an artifact name based on the target name. Returns: An ArtifactNamePatternInfo provider """ _check_is_nonempty_string(category_name, "category_name", "artifact_name_pattern") _check_is_none_or_right_type(prefix, "", "prefix", "artifact_name_pattern") _check_is_none_or_right_type(extension, "", "extension", "artifact_name_pattern") return ArtifactNamePatternInfo( category_name = category_name, prefix = prefix, extension = extension, type_name = "artifact_name_pattern", ) rules_cc-0.0.11/cc/common/000077500000000000000000000000001470072561500152545ustar00rootroot00000000000000rules_cc-0.0.11/cc/common/BUILD000066400000000000000000000026671470072561500160510ustar00rootroot00000000000000# Copyright 2024 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. load("@bazel_skylib//:bzl_library.bzl", "bzl_library") bzl_library( name = "common", srcs = glob(["*.bzl"]), visibility = ["//visibility:public"], deps = ["//cc/private/rules_impl:native_bzl"], ) bzl_library( name = "cc_helper_bzl", srcs = ["cc_helper.bzl"], visibility = ["//visibility:public"], deps = [":visibility_bzl"], ) bzl_library( name = "cc_debug_helper_bzl", srcs = ["cc_debug_helper.bzl"], visibility = ["//visibility:public"], deps = [ ":cc_helper_bzl", ":visibility_bzl", "//cc:find_cc_toolchain_bzl", ], ) bzl_library( name = "visibility_bzl", srcs = ["visibility.bzl"], visibility = ["//visibility:private"], ) filegroup( name = "srcs", srcs = glob([ "**/*.bzl", "**/BUILD", ]), visibility = ["//visibility:public"], ) rules_cc-0.0.11/cc/common/cc_common.bzl000066400000000000000000000013201470072561500177160ustar00rootroot00000000000000# Copyright 2024 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. """cc_common module""" load("//cc/private/rules_impl:native.bzl", "native_cc_common") cc_common = native_cc_common rules_cc-0.0.11/cc/common/cc_debug_helper.bzl000066400000000000000000000173501470072561500210650ustar00rootroot00000000000000# Copyright 2024 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. """Utilities for creating cc debug package information outputs""" load("//cc:find_cc_toolchain.bzl", "CC_TOOLCHAIN_TYPE") load(":cc_helper.bzl", "linker_mode") load(":visibility.bzl", "INTERNAL_VISIBILITY") visibility(INTERNAL_VISIBILITY) def create_debug_packager_actions( ctx, cc_toolchain, dwp_output, *, cc_compilation_outputs, cc_debug_context, linking_mode, use_pic = True, lto_artifacts = []): """Creates intermediate and final dwp creation action(s) Args: ctx: (RuleContext) the rule context cc_toolchain: (CcToolchainInfo) the cc toolchain dwp_output: (File) the output of the final dwp action cc_compilation_outputs: (CcCompilationOutputs) cc_debug_context: (DebugContext) linking_mode: (str) See cc_helper.bzl%linker_mode use_pic: (bool) lto_artifacts: ([CcLtoBackendArtifacts]) """ dwo_files = _collect_transitive_dwo_artifacts( cc_compilation_outputs, cc_debug_context, linking_mode, use_pic, lto_artifacts, ) # No inputs? Just generate a trivially empty .dwp. # # Note this condition automatically triggers for any build where fission is disabled. # Because rules referencing .dwp targets may be invoked with or without fission, we need # to support .dwp generation even when fission is disabled. Since no actual functionality # is expected then, an empty file is appropriate. dwo_files_list = dwo_files.to_list() if len(dwo_files_list) == 0: ctx.actions.write(dwp_output, "", False) return # We apply a hierarchical action structure to limit the maximum number of inputs to any # single action. # # While the dwp tool consumes .dwo files, it can also consume intermediate .dwp files, # allowing us to split a large input set into smaller batches of arbitrary size and order. # Aside from the parallelism performance benefits this offers, this also reduces input # size requirements: if a.dwo, b.dwo, c.dwo, and e.dwo are each 1 KB files, we can apply # two intermediate actions DWP(a.dwo, b.dwo) --> i1.dwp and DWP(c.dwo, e.dwo) --> i2.dwp. # When we then apply the final action DWP(i1.dwp, i2.dwp) --> finalOutput.dwp, the inputs # to this action will usually total far less than 4 KB. # # The actions form an n-ary tree with n == MAX_INPUTS_PER_DWP_ACTION. The tree is fuller # at the leaves than the root, but that both increases parallelism and reduces the final # action's input size. packager = _create_intermediate_dwp_packagers(ctx, dwp_output, cc_toolchain, cc_toolchain._dwp_files, dwo_files_list, 1) packager["outputs"].append(dwp_output) packager["arguments"].add("-o", dwp_output) ctx.actions.run( mnemonic = "CcGenerateDwp", tools = packager["tools"], executable = packager["executable"], toolchain = CC_TOOLCHAIN_TYPE, arguments = [packager["arguments"]], inputs = packager["inputs"], outputs = packager["outputs"], ) def _collect_transitive_dwo_artifacts(cc_compilation_outputs, cc_debug_context, linking_mode, use_pic, lto_backend_artifacts): dwo_files = [] transitive_dwo_files = depset() if use_pic: dwo_files.extend(cc_compilation_outputs.pic_dwo_files()) else: dwo_files.extend(cc_compilation_outputs.dwo_files()) if lto_backend_artifacts != None: for lto_backend_artifact in lto_backend_artifacts: if lto_backend_artifact.dwo_file() != None: dwo_files.append(lto_backend_artifact.dwo_file()) if linking_mode != linker_mode.LINKING_DYNAMIC: if use_pic: transitive_dwo_files = cc_debug_context.pic_files else: transitive_dwo_files = cc_debug_context.files return depset(dwo_files, transitive = [transitive_dwo_files]) def _get_intermediate_dwp_file(ctx, dwp_output, order_number): output_path = dwp_output.short_path # Since it is a dwp_output we can assume that it always # ends with .dwp suffix, because it is declared so in outputs # attribute. extension_stripped_output_path = output_path[0:len(output_path) - 4] intermediate_path = extension_stripped_output_path + "-" + str(order_number) + ".dwp" return ctx.actions.declare_file("_dwps/" + intermediate_path) def _create_intermediate_dwp_packagers(ctx, dwp_output, cc_toolchain, dwp_files, dwo_files, intermediate_dwp_count): intermediate_outputs = dwo_files # This long loop is a substitution for recursion, which is not currently supported in Starlark. for _ in range(2147483647): packagers = [] current_packager = _new_dwp_action(ctx, cc_toolchain, dwp_files) inputs_for_current_packager = 0 # Step 1: generate our batches. We currently break into arbitrary batches of fixed maximum # input counts, but we can always apply more intelligent heuristics if the need arises. for dwo_file in intermediate_outputs: if inputs_for_current_packager == 100: packagers.append(current_packager) current_packager = _new_dwp_action(ctx, cc_toolchain, dwp_files) inputs_for_current_packager = 0 current_packager["inputs"].append(dwo_file) # add_all expands all directories to their contained files, see # https://bazel.build/rules/lib/builtins/Args#add_all. add doesn't # do that, so using add_all on the one-item list here allows us to # find dwo files in directories. current_packager["arguments"].add_all([dwo_file]) inputs_for_current_packager += 1 packagers.append(current_packager) # Step 2: given the batches, create the actions. if len(packagers) > 1: # If we have multiple batches, make them all intermediate actions, then pipe their outputs # into an additional level. intermediate_outputs = [] for packager in packagers: intermediate_output = _get_intermediate_dwp_file(ctx, dwp_output, intermediate_dwp_count) intermediate_dwp_count += 1 packager["outputs"].append(intermediate_output) packager["arguments"].add("-o", intermediate_output) ctx.actions.run( mnemonic = "CcGenerateIntermediateDwp", tools = packager["tools"], executable = packager["executable"], toolchain = CC_TOOLCHAIN_TYPE, arguments = [packager["arguments"]], inputs = packager["inputs"], outputs = packager["outputs"], ) intermediate_outputs.append(intermediate_output) else: return packagers[0] # This is to fix buildifier errors, even though we should never reach this part of the code. return None def _new_dwp_action(ctx, cc_toolchain, dwp_tools): return { "arguments": ctx.actions.args(), "executable": cc_toolchain._tool_paths.get("dwp", None), "inputs": [], "outputs": [], "tools": dwp_tools, } rules_cc-0.0.11/cc/common/cc_helper.bzl000066400000000000000000000263471470072561500177250ustar00rootroot00000000000000# Copyright 2020 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. """Utility functions for C++ rules.""" load("//cc:find_cc_toolchain.bzl", "CC_TOOLCHAIN_TYPE") load(":cc_common.bzl", "cc_common") load(":visibility.bzl", "INTERNAL_VISIBILITY") visibility(INTERNAL_VISIBILITY) # LINT.IfChange(linker_mode) linker_mode = struct( LINKING_DYNAMIC = "dynamic_linking_mode", LINKING_STATIC = "static_linking_mode", ) # LINT.ThenChange(https://github.com/bazelbuild/bazel/blob/master/src/main/starlark/builtins_bzl/common/cc/cc_helper.bzl:linker_mode) # LINT.IfChange(forked_exports) def _get_static_mode_params_for_dynamic_library_libraries(libs): linker_inputs = [] for lib in libs.to_list(): if lib.pic_static_library: linker_inputs.append(lib.pic_static_library) elif lib.static_library: linker_inputs.append(lib.static_library) elif lib.interface_library: linker_inputs.append(lib.interface_library) else: linker_inputs.append(lib.dynamic_library) return linker_inputs def _create_strip_action(ctx, cc_toolchain, cpp_config, input, output, feature_configuration): if cc_common.is_enabled(feature_configuration = feature_configuration, feature_name = "no_stripping"): ctx.actions.symlink( output = output, target_file = input, progress_message = "Symlinking original binary as stripped binary", ) return if not cc_common.action_is_enabled(feature_configuration = feature_configuration, action_name = "strip"): fail("Expected action_config for 'strip' to be configured.") variables = cc_common.create_compile_variables( cc_toolchain = cc_toolchain, feature_configuration = feature_configuration, output_file = output.path, input_file = input.path, strip_opts = cpp_config.strip_opts(), ) command_line = cc_common.get_memory_inefficient_command_line( feature_configuration = feature_configuration, action_name = "strip", variables = variables, ) env = cc_common.get_environment_variables( feature_configuration = feature_configuration, action_name = "strip", variables = variables, ) execution_info = {} for execution_requirement in cc_common.get_tool_requirement_for_action(feature_configuration = feature_configuration, action_name = "strip"): execution_info[execution_requirement] = "" ctx.actions.run( inputs = depset( direct = [input], transitive = [cc_toolchain._strip_files], ), outputs = [output], use_default_shell_env = True, env = env, executable = cc_common.get_tool_for_action(feature_configuration = feature_configuration, action_name = "strip"), toolchain = CC_TOOLCHAIN_TYPE, execution_requirements = execution_info, progress_message = "Stripping {} for {}".format(output.short_path, ctx.label), mnemonic = "CcStrip", arguments = command_line, ) def _lookup_var(ctx, additional_vars, var): expanded_make_var_ctx = ctx.var.get(var) expanded_make_var_additional = additional_vars.get(var) if expanded_make_var_additional != None: return expanded_make_var_additional if expanded_make_var_ctx != None: return expanded_make_var_ctx fail("{}: {} not defined".format(ctx.label, "$(" + var + ")")) def _expand_nested_variable(ctx, additional_vars, exp, execpath = True, targets = []): # If make variable is predefined path variable(like $(location ...)) # we will expand it first. if exp.find(" ") != -1: if not execpath: if exp.startswith("location"): exp = exp.replace("location", "rootpath", 1) data_targets = [] if ctx.attr.data != None: data_targets = ctx.attr.data # Make sure we do not duplicate targets. unified_targets_set = {} for data_target in data_targets: unified_targets_set[data_target] = True for target in targets: unified_targets_set[target] = True return ctx.expand_location("$({})".format(exp), targets = unified_targets_set.keys()) # Recursively expand nested make variables, but since there is no recursion # in Starlark we will do it via for loop. unbounded_recursion = True # The only way to check if the unbounded recursion is happening or not # is to have a look at the depth of the recursion. # 10 seems to be a reasonable number, since it is highly unexpected # to have nested make variables which are expanding more than 10 times. for _ in range(10): exp = _lookup_var(ctx, additional_vars, exp) if len(exp) >= 3 and exp[0] == "$" and exp[1] == "(" and exp[len(exp) - 1] == ")": # Try to expand once more. exp = exp[2:len(exp) - 1] continue unbounded_recursion = False break if unbounded_recursion: fail("potentially unbounded recursion during expansion of {}".format(exp)) return exp def _expand(ctx, expression, additional_make_variable_substitutions, execpath = True, targets = []): idx = 0 last_make_var_end = 0 result = [] n = len(expression) for _ in range(n): if idx >= n: break if expression[idx] != "$": idx += 1 continue idx += 1 # We've met $$ pattern, so $ is escaped. if idx < n and expression[idx] == "$": idx += 1 result.append(expression[last_make_var_end:idx - 1]) last_make_var_end = idx # We might have found a potential start for Make Variable. elif idx < n and expression[idx] == "(": # Try to find the closing parentheses. make_var_start = idx make_var_end = make_var_start for j in range(idx + 1, n): if expression[j] == ")": make_var_end = j break # Note we cannot go out of string's bounds here, # because of this check. # If start of the variable is different from the end, # we found a make variable. if make_var_start != make_var_end: # Some clarifications: # *****$(MAKE_VAR_1)*******$(MAKE_VAR_2)***** # ^ ^ ^ # | | | # last_make_var_end make_var_start make_var_end result.append(expression[last_make_var_end:make_var_start - 1]) make_var = expression[make_var_start + 1:make_var_end] exp = _expand_nested_variable(ctx, additional_make_variable_substitutions, make_var, execpath, targets) result.append(exp) # Update indexes. idx = make_var_end + 1 last_make_var_end = idx # Add the last substring which would be skipped by for loop. if last_make_var_end < n: result.append(expression[last_make_var_end:n]) return "".join(result) def _get_expanded_env(ctx, additional_make_variable_substitutions): if not hasattr(ctx.attr, "env"): fail("could not find rule attribute named: 'env'") expanded_env = {} for k in ctx.attr.env: expanded_env[k] = _expand( ctx, ctx.attr.env[k], additional_make_variable_substitutions, # By default, Starlark `ctx.expand_location` has `execpath` semantics. # For legacy attributes, e.g. `env`, we want `rootpath` semantics instead. execpath = False, ) return expanded_env # Implementation of Bourne shell tokenization. # Tokenizes str and appends result to the options list. def _tokenize(options, options_string): token = [] force_token = False quotation = "\0" length = len(options_string) # Since it is impossible to modify loop variable inside loop # in Starlark, and also there is no while loop, I have to # use this ugly hack. i = -1 for _ in range(length): i += 1 if i >= length: break c = options_string[i] if quotation != "\0": # In quotation. if c == quotation: # End quotation. quotation = "\0" elif c == "\\" and quotation == "\"": i += 1 if i == length: fail("backslash at the end of the string: {}".format(options_string)) c = options_string[i] if c != "\\" and c != "\"": token.append("\\") token.append(c) else: # Regular char, in quotation. token.append(c) else: # Not in quotation. if c == "'" or c == "\"": # Begin single double quotation. quotation = c force_token = True elif c == " " or c == "\t": # Space not quoted. if force_token or len(token) > 0: options.append("".join(token)) token = [] force_token = False elif c == "\\": # Backslash not quoted. i += 1 if i == length: fail("backslash at the end of the string: {}".format(options_string)) token.append(options_string[i]) else: # Regular char, not quoted. token.append(c) if quotation != "\0": fail("unterminated quotation at the end of the string: {}".format(options_string)) if force_token or len(token) > 0: options.append("".join(token)) def _should_use_pic(ctx, cc_toolchain, feature_configuration): """Whether to use pic files Args: ctx: (RuleContext) cc_toolchain: (CcToolchainInfo) feature_configuration: (FeatureConfiguration) Returns: (bool) """ return ctx.fragments.cpp.force_pic() or ( cc_toolchain.needs_pic_for_dynamic_libraries(feature_configuration = feature_configuration) and ( ctx.var["COMPILATION_MODE"] != "opt" or cc_common.is_enabled(feature_configuration = feature_configuration, feature_name = "prefer_pic_for_opt_binaries") ) ) cc_helper = struct( create_strip_action = _create_strip_action, get_expanded_env = _get_expanded_env, get_static_mode_params_for_dynamic_library_libraries = _get_static_mode_params_for_dynamic_library_libraries, should_use_pic = _should_use_pic, tokenize = _tokenize, ) # LINT.ThenChange(https://github.com/bazelbuild/bazel/blob/master/src/main/starlark/builtins_bzl/common/cc/cc_helper.bzl:forked_exports) rules_cc-0.0.11/cc/common/cc_info.bzl000066400000000000000000000012731470072561500173700ustar00rootroot00000000000000# Copyright 2024 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. """CcInfo""" load("//cc/private/rules_impl:native.bzl", "NativeCcInfo") CcInfo = NativeCcInfo rules_cc-0.0.11/cc/common/cc_shared_library_hint_info.bzl000066400000000000000000000013721470072561500234640ustar00rootroot00000000000000# Copyright 2024 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. """CcSharedLibraryInfo""" load("//cc/private/rules_impl:native.bzl", "NativeCcSharedLibraryHintInfo") CcSharedLibraryHintInfo = NativeCcSharedLibraryHintInfo rules_cc-0.0.11/cc/common/cc_shared_library_info.bzl000066400000000000000000000013561470072561500224440ustar00rootroot00000000000000# Copyright 2024 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. """CcSharedLibraryInfo""" load("//cc/private/rules_impl:native.bzl", "NativeCcSharedLibraryInfo") CcSharedLibraryInfo = NativeCcSharedLibraryInfo rules_cc-0.0.11/cc/common/debug_package_info.bzl000066400000000000000000000013421470072561500215410ustar00rootroot00000000000000# Copyright 2024 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. """DebugPackageInfo""" load("//cc/private/rules_impl:native.bzl", "NativeDebugPackageInfo") DebugPackageInfo = NativeDebugPackageInfo rules_cc-0.0.11/cc/common/visibility.bzl000066400000000000000000000001121470072561500201460ustar00rootroot00000000000000"""Bzl load visibility package specs""" INTERNAL_VISIBILITY = ["public"] rules_cc-0.0.11/cc/compiler/000077500000000000000000000000001470072561500155765ustar00rootroot00000000000000rules_cc-0.0.11/cc/compiler/BUILD000066400000000000000000000042141470072561500163610ustar00rootroot00000000000000# 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. """Config settings for compilers identified by Bazel. Targets that require compiler-specific flags can use the config_settings defined in this package in their select() statements. *Note*: Before Bazel 6, gcc on Linux and clang on macOS would not match their specific config_setting, but only the fallback case of a select expression. Toolchains not shipped with Bazel are encouraged to use the same names to identify compilers as used below, but this is not enforced. Example: cc_binary( name = "foo", srcs = ["foo.cc"], copts = select({ "//cc/compiler:gcc": [...], "//cc/compiler:clang": [...], "//cc/compiler:msvc-cl": [...], # Fallback case for an undetected compiler. "//conditions:default": [...], }), ) If multiple targets use the same set of conditionally enabled flags, this can be simplified by extracting the select expression into a Starlark constant. """ package(default_visibility = ["//visibility:public"]) licenses(["notice"]) config_setting( name = "clang", flag_values = {"@rules_cc//cc/private/toolchain:compiler": "clang"}, ) config_setting( name = "clang-cl", flag_values = {"@rules_cc//cc/private/toolchain:compiler": "clang-cl"}, ) config_setting( name = "gcc", flag_values = {"@rules_cc//cc/private/toolchain:compiler": "gcc"}, ) config_setting( name = "mingw-gcc", flag_values = {"@rules_cc//cc/private/toolchain:compiler": "mingw-gcc"}, ) config_setting( name = "msvc-cl", flag_values = {"@rules_cc//cc/private/toolchain:compiler": "msvc-cl"}, ) rules_cc-0.0.11/cc/defs.bzl000066400000000000000000000047071470072561500154260ustar00rootroot00000000000000# Copyright 2018 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. """Starlark rules for building C++ projects.""" load("//cc:cc_binary.bzl", _cc_binary = "cc_binary") load("//cc:cc_import.bzl", _cc_import = "cc_import") load("//cc:cc_library.bzl", _cc_library = "cc_library") load("//cc:cc_shared_library.bzl", _cc_shared_library = "cc_shared_library") load("//cc:cc_test.bzl", _cc_test = "cc_test") load("//cc:objc_import.bzl", _objc_import = "objc_import") load("//cc:objc_library.bzl", _objc_library = "objc_library") load("//cc/common:cc_common.bzl", _cc_common = "cc_common") load("//cc/common:cc_info.bzl", _CcInfo = "CcInfo") load("//cc/common:debug_package_info.bzl", _DebugPackageInfo = "DebugPackageInfo") load("//cc/toolchains:cc_flags_supplier.bzl", _cc_flags_supplier = "cc_flags_supplier") load("//cc/toolchains:cc_toolchain.bzl", _cc_toolchain = "cc_toolchain") load("//cc/toolchains:cc_toolchain_config_info.bzl", _CcToolchainConfigInfo = "CcToolchainConfigInfo") load("//cc/toolchains:cc_toolchain_suite.bzl", _cc_toolchain_suite = "cc_toolchain_suite") load("//cc/toolchains:compiler_flag.bzl", _compiler_flag = "compiler_flag") load("//cc/toolchains:fdo_prefetch_hints.bzl", _fdo_prefetch_hints = "fdo_prefetch_hints") load("//cc/toolchains:fdo_profile.bzl", _fdo_profile = "fdo_profile") # Rules cc_library = _cc_library cc_binary = _cc_binary cc_test = _cc_test cc_import = _cc_import cc_shared_library = _cc_shared_library objc_library = _objc_library objc_import = _objc_import cc_proto_library = native.cc_proto_library # For compatibility with current users # Toolchain rules cc_toolchain = _cc_toolchain fdo_profile = _fdo_profile fdo_prefetch_hints = _fdo_prefetch_hints cc_toolchain_suite = _cc_toolchain_suite compiler_flag = _compiler_flag cc_flags_supplier = _cc_flags_supplier # Modules and providers cc_common = _cc_common CcInfo = _CcInfo DebugPackageInfo = _DebugPackageInfo CcToolchainConfigInfo = _CcToolchainConfigInfo rules_cc-0.0.11/cc/extensions.bzl000066400000000000000000000020111470072561500166660ustar00rootroot00000000000000# Copyright 2018 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. """Module extension for cc auto configuration.""" load("//cc/private/toolchain:cc_configure.bzl", "cc_autoconf", "cc_autoconf_toolchains") def _cc_configure_extension_impl(ctx): cc_autoconf_toolchains(name = "local_config_cc_toolchains") cc_autoconf(name = "local_config_cc") return ctx.extension_metadata(reproducible = True) cc_configure_extension = module_extension(implementation = _cc_configure_extension_impl) rules_cc-0.0.11/cc/find_cc_toolchain.bzl000066400000000000000000000107661470072561500201340ustar00rootroot00000000000000# pylint: disable=g-bad-file-header # 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. """ Helpers for CC Toolchains. Rules that require a CC toolchain should call `use_cc_toolchain` and `find_cc_toolchain` to depend on and find a cc toolchain. * When https://github.com/bazelbuild/bazel/issues/7260 is **not** flipped, current C++ toolchain is selected using the legacy mechanism (`--crosstool_top`, `--cpu`, `--compiler`). For that to work the rule needs to declare an `_cc_toolchain` attribute, e.g. foo = rule( implementation = _foo_impl, attrs = { "_cc_toolchain": attr.label( default = Label( "@rules_cc//cc:current_cc_toolchain", ), ), }, ) * When https://github.com/bazelbuild/bazel/issues/7260 **is** flipped, current C++ toolchain is selected using the toolchain resolution mechanism (`--platforms`). For that to work the rule needs to declare a dependency on C++ toolchain type: load(":find_cc_toolchain/bzl", "use_cc_toolchain") foo = rule( implementation = _foo_impl, toolchains = use_cc_toolchain(), ) We advise to depend on both `_cc_toolchain` attr and on the toolchain type for the duration of the migration. After https://github.com/bazelbuild/bazel/issues/7260 is flipped (and support for old Bazel version is not needed), it's enough to only keep the toolchain type. """ CC_TOOLCHAIN_TYPE = Label("@bazel_tools//tools/cpp:toolchain_type") def find_cc_toolchain(ctx, *, mandatory = True): """ Returns the current `CcToolchainInfo`. Args: ctx: The rule context for which to find a toolchain. mandatory: (bool) If this is set to False, this function will return None rather than fail if no toolchain is found. Returns: A CcToolchainInfo or None if the c++ toolchain is declared as optional, mandatory is False and no toolchain has been found. """ # Check the incompatible flag for toolchain resolution. if hasattr(cc_common, "is_cc_toolchain_resolution_enabled_do_not_use") and cc_common.is_cc_toolchain_resolution_enabled_do_not_use(ctx = ctx): if not CC_TOOLCHAIN_TYPE in ctx.toolchains: fail("In order to use find_cc_toolchain, your rule has to depend on C++ toolchain. See find_cc_toolchain.bzl docs for details.") toolchain_info = ctx.toolchains[CC_TOOLCHAIN_TYPE] if toolchain_info == None: if not mandatory: return None # No cpp toolchain was found, so report an error. fail("Unable to find a CC toolchain using toolchain resolution. Target: %s, Platform: %s, Exec platform: %s" % (ctx.label, ctx.fragments.platform.platform, ctx.fragments.platform.host_platform)) if hasattr(toolchain_info, "cc_provider_in_toolchain") and hasattr(toolchain_info, "cc"): return toolchain_info.cc return toolchain_info # Fall back to the legacy implicit attribute lookup. if hasattr(ctx.attr, "_cc_toolchain"): return ctx.attr._cc_toolchain[cc_common.CcToolchainInfo] # We didn't find anything. if not mandatory: return None fail("In order to use find_cc_toolchain, your rule has to depend on C++ toolchain. See find_cc_toolchain.bzl docs for details.") def find_cpp_toolchain(ctx): """Deprecated, use `find_cc_toolchain` instead. Args: ctx: See `find_cc_toolchain`. Returns: A CcToolchainInfo. """ return find_cc_toolchain(ctx) def use_cc_toolchain(mandatory = False): """ Helper to depend on the cc toolchain. Usage: ``` my_rule = rule( toolchains = [other toolchain types] + use_cc_toolchain(), ) ``` Args: mandatory: Whether or not it should be an error if the toolchain cannot be resolved. Returns: A list that can be used as the value for `rule.toolchains`. """ return [config_common.toolchain_type(CC_TOOLCHAIN_TYPE, mandatory = mandatory)] rules_cc-0.0.11/cc/objc_import.bzl000066400000000000000000000013171470072561500170060ustar00rootroot00000000000000# Copyright 2024 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. """objc_import rule""" def objc_import(**kwargs): native.objc_import(**kwargs) # buildifier: disable=native-cc rules_cc-0.0.11/cc/objc_library.bzl000066400000000000000000000013221470072561500171340ustar00rootroot00000000000000# Copyright 2024 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. """objc_library rule""" def objc_library(**kwargs): native.objc_library(**kwargs) # buildifier: disable=native-cc rules_cc-0.0.11/cc/private/000077500000000000000000000000001470072561500154365ustar00rootroot00000000000000rules_cc-0.0.11/cc/private/BUILD000066400000000000000000000014541470072561500162240ustar00rootroot00000000000000# Copyright 2024 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. filegroup( name = "srcs", srcs = glob([ "**/BUILD", ]) + [ "//cc/private/rules_impl:srcs", "//cc/private/toolchain:srcs", ], visibility = ["//visibility:public"], ) rules_cc-0.0.11/cc/private/rules_impl/000077500000000000000000000000001470072561500176115ustar00rootroot00000000000000rules_cc-0.0.11/cc/private/rules_impl/BUILD000066400000000000000000000011041470072561500203670ustar00rootroot00000000000000load("@bazel_skylib//:bzl_library.bzl", "bzl_library") package(default_visibility = ["//visibility:public"]) licenses(["notice"]) # Apache 2.0 filegroup( name = "bzl_srcs", srcs = glob([ "**/*.bzl", ]), ) filegroup( name = "srcs", srcs = glob([ "**/*.bzl", "**/BUILD", ]), ) bzl_library( name = "cc_flags_supplier_lib_bzl", srcs = ["cc_flags_supplier_lib.bzl"], visibility = ["//cc:__subpackages__"], ) bzl_library( name = "native_bzl", srcs = ["native.bzl"], visibility = ["//cc:__subpackages__"], ) rules_cc-0.0.11/cc/private/rules_impl/cc_flags_supplier_lib.bzl000066400000000000000000000051651470072561500246430ustar00rootroot00000000000000# Copyright 2018 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. """Library of functions that provide the CC_FLAGS Make variable.""" # This should match the logic in CcCommon.computeCcFlags: def build_cc_flags(ctx, cc_toolchain, action_name): """Determine the value for CC_FLAGS based on the given toolchain. Args: ctx: The rule context. cc_toolchain: CcToolchainInfo instance. action_name: Name of the action. Returns: string containing flags separated by a space. """ # Get default cc flags from toolchain's make_variables. legacy_cc_flags = cc_common.legacy_cc_flags_make_variable_do_not_use( cc_toolchain = cc_toolchain, ) # Determine the sysroot flag. sysroot_cc_flags = _from_sysroot(cc_toolchain) # Flags from feature config. feature_config_cc_flags = _from_features(ctx, cc_toolchain, action_name) # Combine the different sources, but only add the sysroot flag if nothing # else adds sysroot. # If added, it must appear before the feature config flags. cc_flags = [] if legacy_cc_flags: cc_flags.append(legacy_cc_flags) if sysroot_cc_flags and not _contains_sysroot(feature_config_cc_flags): cc_flags.append(sysroot_cc_flags) cc_flags.extend(feature_config_cc_flags) return " ".join(cc_flags) def _contains_sysroot(flags): for flag in flags: if "--sysroot=" in flag: return True return False def _from_sysroot(cc_toolchain): sysroot = cc_toolchain.sysroot if sysroot: return "--sysroot=%s" % sysroot else: return None def _from_features(ctx, cc_toolchain, action_name): feature_configuration = cc_common.configure_features( ctx = ctx, cc_toolchain = cc_toolchain, requested_features = ctx.features, unsupported_features = ctx.disabled_features, ) variables = cc_common.empty_variables() cc_flags = cc_common.get_memory_inefficient_command_line( feature_configuration = feature_configuration, action_name = action_name, variables = variables, ) return cc_flags rules_cc-0.0.11/cc/private/rules_impl/native.bzl000066400000000000000000000027441470072561500216170ustar00rootroot00000000000000# Copyright 2022 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. # Redefine native symbols with a new name as a workaround for # exporting them in `//third_party/bazel_rules/rules_proto/proto:defs.bzl` with their original name. # # While we cannot force users to load these symbol due to the lack of a # allowlisting mechanism, we can still export them and tell users to # load it to make a future migration to pure Starlark easier. """Lovely workaround to be able to expose native constants pretending to be Starlark.""" # buildifier: disable=native-cc NativeCcInfo = CcInfo # buildifier: disable=native-cc NativeDebugPackageInfo = DebugPackageInfo # buildifier: disable=native-cc NativeCcToolchainConfigInfo = CcToolchainConfigInfo # buildifier: disable=native-cc native_cc_common = cc_common # buildifier: disable=native-cc NativeCcSharedLibraryInfo = CcSharedLibraryInfo # buildifier: disable=native-cc NativeCcSharedLibraryHintInfo = CcSharedLibraryHintInfo rules_cc-0.0.11/cc/private/toolchain/000077500000000000000000000000001470072561500174165ustar00rootroot00000000000000rules_cc-0.0.11/cc/private/toolchain/BUILD000066400000000000000000000037231470072561500202050ustar00rootroot00000000000000load("//cc:defs.bzl", "cc_flags_supplier", "cc_library", "compiler_flag") # Copyright 2018 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. # package(default_visibility = ["//visibility:public"]) licenses(["notice"]) # Apache 2.0 # It is frequently necessary to constrain platforms based on the cc compiler type. constraint_setting(name = "cc_compiler") constraint_value( name = "clang", constraint_setting = ":cc_compiler", ) constraint_value( name = "gcc", constraint_setting = ":cc_compiler", ) constraint_value( name = "msvc", constraint_setting = ":cc_compiler", ) constraint_value( name = "clang-cl", constraint_setting = ":cc_compiler", ) constraint_value( name = "mingw", constraint_setting = ":cc_compiler", ) constraint_value( name = "msys", constraint_setting = ":cc_compiler", ) cc_library( name = "malloc", ) filegroup( name = "grep-includes", srcs = ["grep-includes.sh"], ) filegroup( name = "empty", srcs = [], ) filegroup( name = "bzl_srcs", srcs = glob(["**/*.bzl"]), ) filegroup( name = "srcs", srcs = glob(["**"]), ) filegroup( name = "interface_library_builder", srcs = ["build_interface_so"], ) filegroup( name = "link_dynamic_library", srcs = ["link_dynamic_library.sh"], ) filegroup( name = "lib_cc_configure", srcs = ["lib_cc_configure.bzl"], ) compiler_flag(name = "compiler") cc_flags_supplier(name = "cc_flags") rules_cc-0.0.11/cc/private/toolchain/BUILD.empty.tpl000066400000000000000000000026361470072561500221420ustar00rootroot00000000000000# Copyright 2018 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. load("@rules_cc//cc:defs.bzl", "cc_library", "cc_toolchain", "cc_toolchain_suite") load(":cc_toolchain_config.bzl", "cc_toolchain_config") package(default_visibility = ["//visibility:public"]) cc_library( name = "link_extra_lib", ) cc_library( name = "malloc", ) filegroup( name = "empty", srcs = [], ) cc_toolchain_suite( name = "toolchain", toolchains = { "%{cpu}|local": ":local", "%{cpu}": ":local", }, ) cc_toolchain( name = "local", all_files = ":empty", ar_files = ":empty", as_files = ":empty", compiler_files = ":empty", dwp_files = ":empty", linker_files = ":empty", objcopy_files = ":empty", strip_files = ":empty", toolchain_config = ":local_config", toolchain_identifier = "local", ) cc_toolchain_config(name = "local_config") rules_cc-0.0.11/cc/private/toolchain/BUILD.static.bsd000066400000000000000000000105041470072561500222350ustar00rootroot00000000000000# Copyright 2018 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 FreeBSD and OpenBSD. load(":cc_toolchain_config.bzl", "cc_toolchain_config") load("@rules_cc//cc:defs.bzl", "cc_library", "cc_toolchain", "cc_toolchain_suite") package(default_visibility = ["//visibility:public"]) cc_library(name = "empty_lib") # Label flag for extra libraries to be linked into every binary. # TODO(bazel-team): Support passing flag multiple times to build a list. label_flag( name = "link_extra_libs", build_setting_default = ":empty_lib", ) # The final extra library to be linked into every binary target. This collects # the above flag, but may also include more libraries depending on config. cc_library( name = "link_extra_lib", deps = [ ":link_extra_libs", ], ) cc_library( name = "malloc", ) filegroup( name = "empty", srcs = [], ) # Hardcoded toolchain, legacy behaviour. cc_toolchain_suite( name = "toolchain", toolchains = { "armeabi-v7a|compiler": ":cc-compiler-armeabi-v7a", "freebsd|compiler": ":cc-compiler-freebsd", "openbsd|compiler": ":cc-compiler-openbsd", "armeabi-v7a": ":cc-compiler-armeabi-v7a", "freebsd": ":cc-compiler-freebsd", "openbsd": ":cc-compiler-openbsd", }, ) cc_toolchain( name = "cc-compiler-freebsd", all_files = ":empty", ar_files = ":empty", as_files = ":empty", compiler_files = ":empty", dwp_files = ":empty", linker_files = ":empty", objcopy_files = ":empty", strip_files = ":empty", supports_param_files = 0, toolchain_config = ":local_freebsd", toolchain_identifier = "local_freebsd", ) cc_toolchain_config( name = "local_freebsd", cpu = "freebsd", ) toolchain( name = "cc-toolchain-freebsd", exec_compatible_with = [ "@platforms//cpu:x86_64", "@platforms//os:freebsd", ], target_compatible_with = [ "@platforms//cpu:x86_64", "@platforms//os:freebsd", ], toolchain = ":cc-compiler-freebsd", toolchain_type = "@bazel_tools//tools/cpp:toolchain_type", ) cc_toolchain( name = "cc-compiler-openbsd", all_files = ":empty", ar_files = ":empty", as_files = ":empty", compiler_files = ":empty", dwp_files = ":empty", linker_files = ":empty", objcopy_files = ":empty", strip_files = ":empty", supports_param_files = 0, toolchain_config = ":local_openbsd", toolchain_identifier = "local_openbsd", ) cc_toolchain_config( name = "local_openbsd", cpu = "openbsd", ) toolchain( name = "cc-toolchain-openbsd", exec_compatible_with = [ "@platforms//cpu:x86_64", "@platforms//os:openbsd", ], target_compatible_with = [ "@platforms//cpu:x86_64", "@platforms//os:openbsd", ], toolchain = ":cc-compiler-openbsd", toolchain_type = "@bazel_tools//tools/cpp:toolchain_type", ) cc_toolchain( name = "cc-compiler-armeabi-v7a", all_files = ":empty", ar_files = ":empty", as_files = ":empty", compiler_files = ":empty", dwp_files = ":empty", linker_files = ":empty", objcopy_files = ":empty", strip_files = ":empty", supports_param_files = 0, toolchain_config = ":stub_armeabi-v7a", toolchain_identifier = "stub_armeabi-v7a", ) cc_toolchain_config( name = "stub_armeabi-v7a", cpu = "armeabi-v7a", ) toolchain( name = "cc-toolchain-armeabi-v7a", exec_compatible_with = [ "@platforms//cpu:arm", ], target_compatible_with = [ "@platforms//cpu:armv7", "@platforms//os:android", ], toolchain = ":cc-compiler-armeabi-v7a", toolchain_type = "@bazel_tools//tools/cpp:toolchain_type", ) filegroup( name = "link_dynamic_library", srcs = ["link_dynamic_library.sh"], ) rules_cc-0.0.11/cc/private/toolchain/BUILD.toolchains.tpl000066400000000000000000000012231470072561500231360ustar00rootroot00000000000000load("@local_config_platform//:constraints.bzl", "HOST_CONSTRAINTS") toolchain( name = "cc-toolchain-%{name}", exec_compatible_with = HOST_CONSTRAINTS, target_compatible_with = HOST_CONSTRAINTS, toolchain = "@local_config_cc//:cc-compiler-%{name}", toolchain_type = "@bazel_tools//tools/cpp:toolchain_type", ) toolchain( name = "cc-toolchain-armeabi-v7a", exec_compatible_with = HOST_CONSTRAINTS, target_compatible_with = [ "@platforms//cpu:armv7", "@platforms//os:android", ], toolchain = "@local_config_cc//:cc-compiler-armeabi-v7a", toolchain_type = "@bazel_tools//tools/cpp:toolchain_type", ) rules_cc-0.0.11/cc/private/toolchain/BUILD.tpl000066400000000000000000000106671470072561500210100ustar00rootroot00000000000000# 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(":cc_toolchain_config.bzl", "cc_toolchain_config") load(":armeabi_cc_toolchain_config.bzl", "armeabi_cc_toolchain_config") load("@rules_cc//cc:defs.bzl", "cc_toolchain", "cc_toolchain_suite") package(default_visibility = ["//visibility:public"]) licenses(["notice"]) # Apache 2.0 cc_library(name = "empty_lib") # Label flag for extra libraries to be linked into every binary. # TODO(bazel-team): Support passing flag multiple times to build a list. label_flag( name = "link_extra_libs", build_setting_default = ":empty_lib", ) # The final extra library to be linked into every binary target. This collects # the above flag, but may also include more libraries depending on config. cc_library( name = "link_extra_lib", deps = [ ":link_extra_libs", ], ) cc_library( name = "malloc", ) 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) + [%{cc_compiler_deps}], ) # This is the entry point for --crosstool_top. Toolchains are found # by lopping off the name of --crosstool_top and searching for # the "${CPU}" entry in the toolchains attribute. cc_toolchain_suite( name = "toolchain", toolchains = { "%{name}|%{compiler}": ":cc-compiler-%{name}", "%{name}": ":cc-compiler-%{name}", "armeabi-v7a|compiler": ":cc-compiler-armeabi-v7a", "armeabi-v7a": ":cc-compiler-armeabi-v7a", }, ) cc_toolchain( name = "cc-compiler-%{name}", toolchain_identifier = "%{cc_toolchain_identifier}", toolchain_config = ":%{cc_toolchain_identifier}", all_files = ":compiler_deps", ar_files = ":compiler_deps", as_files = ":compiler_deps", compiler_files = ":compiler_deps", dwp_files = ":empty", linker_files = ":compiler_deps", objcopy_files = ":empty", strip_files = ":empty", supports_header_parsing = 1, supports_param_files = 1, module_map = %{modulemap}, ) cc_toolchain_config( name = "%{cc_toolchain_identifier}", cpu = "%{target_cpu}", compiler = "%{compiler}", toolchain_identifier = "%{cc_toolchain_identifier}", host_system_name = "%{host_system_name}", target_system_name = "%{target_system_name}", target_libc = "%{target_libc}", abi_version = "%{abi_version}", abi_libc_version = "%{abi_libc_version}", cxx_builtin_include_directories = [%{cxx_builtin_include_directories}], tool_paths = {%{tool_paths}}, compile_flags = [%{compile_flags}], opt_compile_flags = [%{opt_compile_flags}], dbg_compile_flags = [%{dbg_compile_flags}], conly_flags = [%{conly_flags}], cxx_flags = [%{cxx_flags}], link_flags = [%{link_flags}], link_libs = [%{link_libs}], opt_link_flags = [%{opt_link_flags}], unfiltered_compile_flags = [%{unfiltered_compile_flags}], coverage_compile_flags = [%{coverage_compile_flags}], coverage_link_flags = [%{coverage_link_flags}], supports_start_end_lib = %{supports_start_end_lib}, extra_flags_per_feature = %{extra_flags_per_feature}, ) # Android tooling requires a default toolchain for the armeabi-v7a cpu. cc_toolchain( name = "cc-compiler-armeabi-v7a", toolchain_identifier = "stub_armeabi-v7a", toolchain_config = ":stub_armeabi-v7a", all_files = ":empty", ar_files = ":empty", as_files = ":empty", compiler_files = ":empty", dwp_files = ":empty", linker_files = ":empty", objcopy_files = ":empty", strip_files = ":empty", supports_param_files = 1, ) armeabi_cc_toolchain_config(name = "stub_armeabi-v7a") rules_cc-0.0.11/cc/private/toolchain/BUILD.windows.tpl000066400000000000000000000562641470072561500225040ustar00rootroot00000000000000# Copyright 2018 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 Windows. load("@rules_cc//cc:defs.bzl", "cc_toolchain", "cc_toolchain_suite", "cc_library") load(":windows_cc_toolchain_config.bzl", "cc_toolchain_config") load(":armeabi_cc_toolchain_config.bzl", "armeabi_cc_toolchain_config") package(default_visibility = ["//visibility:public"]) cc_library(name = "empty_lib") # Label flag for extra libraries to be linked into every binary. # TODO(bazel-team): Support passing flag multiple times to build a list. label_flag( name = "link_extra_libs", build_setting_default = ":empty_lib", ) # The final extra library to be linked into every binary target. This collects # the above flag, but may also include more libraries depending on config. cc_library( name = "link_extra_lib", deps = [ ":link_extra_libs", ], ) cc_library( name = "malloc", ) filegroup( name = "empty", srcs = [], ) filegroup( name = "mingw_compiler_files", srcs = [":builtin_include_directory_paths_mingw"] ) filegroup( name = "clangcl_compiler_files", srcs = [":builtin_include_directory_paths_clangcl"] ) filegroup( name = "msvc_compiler_files", srcs = [ ":builtin_include_directory_paths_msvc", "%{msvc_deps_scanner_wrapper_path_x86}", "%{msvc_deps_scanner_wrapper_path_x64}", "%{msvc_deps_scanner_wrapper_path_arm}", "%{msvc_deps_scanner_wrapper_path_arm64}", ] ) # Hardcoded toolchain, legacy behaviour. cc_toolchain_suite( name = "toolchain", toolchains = { "armeabi-v7a|compiler": ":cc-compiler-armeabi-v7a", "x64_windows|msvc-cl": ":cc-compiler-x64_windows", "x64_x86_windows|msvc-cl": ":cc-compiler-x64_x86_windows", "x64_arm_windows|msvc-cl": ":cc-compiler-x64_arm_windows", "x64_arm64_windows|msvc-cl": ":cc-compiler-arm64_windows", "arm64_windows|msvc-cl": ":cc-compiler-arm64_windows", "x64_windows|msys-gcc": ":cc-compiler-x64_windows_msys", "x64_x86_windows|msys-gcc": ":cc-compiler-x64_x86_windows_msys", "x64_windows|mingw-gcc": ":cc-compiler-x64_windows_mingw", "x64_x86_windows|mingw-gcc": ":cc-compiler-x64_x86_windows_mingw", "x64_windows|clang-cl": ":cc-compiler-x64_windows-clang-cl", "x64_windows_msys": ":cc-compiler-x64_windows_msys", "x64_windows": ":cc-compiler-x64_windows", "x64_x86_windows": ":cc-compiler-x64_x86_windows", "x64_arm_windows": ":cc-compiler-x64_arm_windows", "x64_arm64_windows": ":cc-compiler-arm64_windows", "arm64_windows": ":cc-compiler-arm64_windows", "x64_arm64_windows|clang-cl": ":cc-compiler-arm64_windows-clang-cl", "arm64_windows|clang-cl": ":cc-compiler-arm64_windows-clang-cl", "armeabi-v7a": ":cc-compiler-armeabi-v7a", }, ) cc_toolchain( name = "cc-compiler-x64_windows_msys", toolchain_identifier = "msys_x64", toolchain_config = ":msys_x64", all_files = ":empty", ar_files = ":empty", as_files = ":mingw_compiler_files", compiler_files = ":mingw_compiler_files", dwp_files = ":empty", linker_files = ":empty", objcopy_files = ":empty", strip_files = ":empty", supports_param_files = 1, ) cc_toolchain_config( name = "msys_x64", cpu = "x64_windows", compiler = "msys-gcc", host_system_name = "local", target_system_name = "local", target_libc = "msys", abi_version = "local", abi_libc_version = "local", cxx_builtin_include_directories = [%{cxx_builtin_include_directories}], tool_paths = {%{tool_paths}}, tool_bin_path = "%{tool_bin_path}", ) toolchain( name = "cc-toolchain-x64_windows_msys", exec_compatible_with = [ "@platforms//cpu:x86_64", "@platforms//os:windows", "@rules_cc//cc/private/toolchain:msys", ], target_compatible_with = [ "@platforms//cpu:x86_64", "@platforms//os:windows", ], toolchain = ":cc-compiler-x64_windows_msys", toolchain_type = "@bazel_tools//tools/cpp:toolchain_type", ) cc_toolchain( name = "cc-compiler-x64_x86_windows_msys", toolchain_identifier = "msys_x64_x86", toolchain_config = ":msys_x64_x86", all_files = ":empty", ar_files = ":empty", as_files = ":mingw_compiler_files", compiler_files = ":mingw_compiler_files", dwp_files = ":empty", linker_files = ":empty", objcopy_files = ":empty", strip_files = ":empty", supports_param_files = 1, ) cc_toolchain_config( name = "msys_x64_x86", cpu = "x64_x86_windows", compiler = "msys-gcc", host_system_name = "local", target_system_name = "local", target_libc = "msys", abi_version = "local", abi_libc_version = "local", cxx_builtin_include_directories = [%{cxx_builtin_include_directories}], tool_paths = {%{tool_paths}}, tool_bin_path = "%{tool_bin_path}", default_compile_flags = ["-m32"], default_link_flags = ["-m32"], ) toolchain( name = "cc-toolchain-x64_x86_windows_msys", exec_compatible_with = [ "@platforms//cpu:x86_64", "@platforms//os:windows", "@rules_cc//cc/private/toolchain:msys", ], target_compatible_with = [ "@platforms//cpu:x86_32", "@platforms//os:windows", ], toolchain = ":cc-compiler-x64_x86_windows_msys", toolchain_type = "@bazel_tools//tools/cpp:toolchain_type", ) cc_toolchain( name = "cc-compiler-x64_windows_mingw", toolchain_identifier = "msys_x64_mingw", toolchain_config = ":msys_x64_mingw", all_files = ":empty", ar_files = ":empty", as_files = ":mingw_compiler_files", compiler_files = ":mingw_compiler_files", dwp_files = ":empty", linker_files = ":empty", objcopy_files = ":empty", strip_files = ":empty", supports_param_files = 0, ) cc_toolchain_config( name = "msys_x64_mingw", cpu = "x64_windows", compiler = "mingw-gcc", host_system_name = "local", target_system_name = "local", target_libc = "mingw", abi_version = "local", abi_libc_version = "local", tool_bin_path = "%{mingw_tool_bin_path}", cxx_builtin_include_directories = [%{mingw_cxx_builtin_include_directories}], tool_paths = {%{mingw_tool_paths}}, ) toolchain( name = "cc-toolchain-x64_windows_mingw", exec_compatible_with = [ "@platforms//cpu:x86_64", "@platforms//os:windows", "@rules_cc//cc/private/toolchain:mingw", ], target_compatible_with = [ "@platforms//cpu:x86_64", "@platforms//os:windows", ], toolchain = ":cc-compiler-x64_windows_mingw", toolchain_type = "@bazel_tools//tools/cpp:toolchain_type", ) cc_toolchain( name = "cc-compiler-x64_x86_windows_mingw", toolchain_identifier = "msys_x64_x86_mingw", toolchain_config = ":msys_x64_x86_mingw", all_files = ":empty", ar_files = ":empty", as_files = ":mingw_compiler_files", compiler_files = ":mingw_compiler_files", dwp_files = ":empty", linker_files = ":empty", objcopy_files = ":empty", strip_files = ":empty", supports_param_files = 0, ) cc_toolchain_config( name = "msys_x64_x86_mingw", cpu = "x64_x86_windows", compiler = "mingw-gcc", host_system_name = "local", target_system_name = "local", target_libc = "mingw", abi_version = "local", abi_libc_version = "local", tool_bin_path = "%{mingw_tool_bin_path}", cxx_builtin_include_directories = [%{mingw_cxx_builtin_include_directories}], tool_paths = {%{mingw_tool_paths}}, default_compile_flags = ["-m32"], default_link_flags = ["-m32"], ) toolchain( name = "cc-toolchain-x64_x86_windows_mingw", exec_compatible_with = [ "@platforms//cpu:x86_64", "@platforms//os:windows", "@rules_cc//cc/private/toolchain:mingw", ], target_compatible_with = [ "@platforms//cpu:x86_32", "@platforms//os:windows", ], toolchain = ":cc-compiler-x64_x86_windows_mingw", toolchain_type = "@bazel_tools//tools/cpp:toolchain_type", ) cc_toolchain( name = "cc-compiler-x64_windows", toolchain_identifier = "msvc_x64", toolchain_config = ":msvc_x64", all_files = ":empty", ar_files = ":empty", as_files = ":msvc_compiler_files", compiler_files = ":msvc_compiler_files", dwp_files = ":empty", linker_files = ":empty", objcopy_files = ":empty", strip_files = ":empty", supports_param_files = 1, ) cc_toolchain_config( name = "msvc_x64", cpu = "x64_windows", compiler = "msvc-cl", host_system_name = "local", target_system_name = "local", target_libc = "msvcrt", abi_version = "local", abi_libc_version = "local", toolchain_identifier = "msvc_x64", msvc_env_tmp = "%{msvc_env_tmp_x64}", msvc_env_path = "%{msvc_env_path_x64}", msvc_env_include = "%{msvc_env_include_x64}", msvc_env_lib = "%{msvc_env_lib_x64}", msvc_cl_path = "%{msvc_cl_path_x64}", msvc_ml_path = "%{msvc_ml_path_x64}", msvc_link_path = "%{msvc_link_path_x64}", msvc_lib_path = "%{msvc_lib_path_x64}", cxx_builtin_include_directories = [%{msvc_cxx_builtin_include_directories_x64}], tool_paths = { "ar": "%{msvc_lib_path_x64}", "ml": "%{msvc_ml_path_x64}", "cpp": "%{msvc_cl_path_x64}", "gcc": "%{msvc_cl_path_x64}", "gcov": "wrapper/bin/msvc_nop.bat", "ld": "%{msvc_link_path_x64}", "nm": "wrapper/bin/msvc_nop.bat", "objcopy": "wrapper/bin/msvc_nop.bat", "objdump": "wrapper/bin/msvc_nop.bat", "strip": "wrapper/bin/msvc_nop.bat", "dumpbin": "%{msvc_dumpbin_path_x64}", "cpp-module-deps-scanner": "%{msvc_deps_scanner_wrapper_path_x64}", }, archiver_flags = ["/MACHINE:X64"], default_link_flags = ["/MACHINE:X64"], dbg_mode_debug_flag = "%{dbg_mode_debug_flag_x64}", fastbuild_mode_debug_flag = "%{fastbuild_mode_debug_flag_x64}", supports_parse_showincludes = %{msvc_parse_showincludes_x64}, ) toolchain( name = "cc-toolchain-x64_windows", exec_compatible_with = [ "@platforms//cpu:x86_64", "@platforms//os:windows", ], target_compatible_with = [ "@platforms//cpu:x86_64", "@platforms//os:windows", ], toolchain = ":cc-compiler-x64_windows", toolchain_type = "@bazel_tools//tools/cpp:toolchain_type", ) cc_toolchain( name = "cc-compiler-x64_x86_windows", toolchain_identifier = "msvc_x64_x86", toolchain_config = ":msvc_x64_x86", all_files = ":empty", ar_files = ":empty", as_files = ":msvc_compiler_files", compiler_files = ":msvc_compiler_files", dwp_files = ":empty", linker_files = ":empty", objcopy_files = ":empty", strip_files = ":empty", supports_param_files = 1, ) cc_toolchain_config( name = "msvc_x64_x86", cpu = "x64_windows", compiler = "msvc-cl", host_system_name = "local", target_system_name = "local", target_libc = "msvcrt", abi_version = "local", abi_libc_version = "local", toolchain_identifier = "msvc_x64_x86", msvc_env_tmp = "%{msvc_env_tmp_x86}", msvc_env_path = "%{msvc_env_path_x86}", msvc_env_include = "%{msvc_env_include_x86}", msvc_env_lib = "%{msvc_env_lib_x86}", msvc_cl_path = "%{msvc_cl_path_x86}", msvc_ml_path = "%{msvc_ml_path_x86}", msvc_link_path = "%{msvc_link_path_x86}", msvc_lib_path = "%{msvc_lib_path_x86}", cxx_builtin_include_directories = [%{msvc_cxx_builtin_include_directories_x86}], tool_paths = { "ar": "%{msvc_lib_path_x86}", "ml": "%{msvc_ml_path_x86}", "cpp": "%{msvc_cl_path_x86}", "gcc": "%{msvc_cl_path_x86}", "gcov": "wrapper/bin/msvc_nop.bat", "ld": "%{msvc_link_path_x86}", "nm": "wrapper/bin/msvc_nop.bat", "objcopy": "wrapper/bin/msvc_nop.bat", "objdump": "wrapper/bin/msvc_nop.bat", "strip": "wrapper/bin/msvc_nop.bat", "dumpbin": "%{msvc_dumpbin_path_x86}", "cpp-module-deps-scanner": "%{msvc_deps_scanner_wrapper_path_x86}", }, archiver_flags = ["/MACHINE:X86"], default_link_flags = ["/MACHINE:X86"], dbg_mode_debug_flag = "%{dbg_mode_debug_flag_x86}", fastbuild_mode_debug_flag = "%{fastbuild_mode_debug_flag_x86}", supports_parse_showincludes = %{msvc_parse_showincludes_x86}, ) toolchain( name = "cc-toolchain-x64_x86_windows", exec_compatible_with = [ "@platforms//cpu:x86_64", "@platforms//os:windows", ], target_compatible_with = [ "@platforms//cpu:x86_32", "@platforms//os:windows", ], toolchain = ":cc-compiler-x64_x86_windows", toolchain_type = "@bazel_tools//tools/cpp:toolchain_type", ) cc_toolchain( name = "cc-compiler-x64_arm_windows", toolchain_identifier = "msvc_x64_arm", toolchain_config = ":msvc_x64_arm", all_files = ":empty", ar_files = ":empty", as_files = ":msvc_compiler_files", compiler_files = ":msvc_compiler_files", dwp_files = ":empty", linker_files = ":empty", objcopy_files = ":empty", strip_files = ":empty", supports_param_files = 1, ) cc_toolchain_config( name = "msvc_x64_arm", cpu = "x64_windows", compiler = "msvc-cl", host_system_name = "local", target_system_name = "local", target_libc = "msvcrt", abi_version = "local", abi_libc_version = "local", toolchain_identifier = "msvc_x64_arm", msvc_env_tmp = "%{msvc_env_tmp_arm}", msvc_env_path = "%{msvc_env_path_arm}", msvc_env_include = "%{msvc_env_include_arm}", msvc_env_lib = "%{msvc_env_lib_arm}", msvc_cl_path = "%{msvc_cl_path_arm}", msvc_ml_path = "%{msvc_ml_path_arm}", msvc_link_path = "%{msvc_link_path_arm}", msvc_lib_path = "%{msvc_lib_path_arm}", cxx_builtin_include_directories = [%{msvc_cxx_builtin_include_directories_arm}], tool_paths = { "ar": "%{msvc_lib_path_arm}", "ml": "%{msvc_ml_path_arm}", "cpp": "%{msvc_cl_path_arm}", "gcc": "%{msvc_cl_path_arm}", "gcov": "wrapper/bin/msvc_nop.bat", "ld": "%{msvc_link_path_arm}", "nm": "wrapper/bin/msvc_nop.bat", "objcopy": "wrapper/bin/msvc_nop.bat", "objdump": "wrapper/bin/msvc_nop.bat", "strip": "wrapper/bin/msvc_nop.bat", "dumpbin": "%{msvc_dumpbin_path_arm}", "cpp-module-deps-scanner": "%{msvc_deps_scanner_wrapper_path_arm}", }, archiver_flags = ["/MACHINE:ARM"], default_link_flags = ["/MACHINE:ARM"], dbg_mode_debug_flag = "%{dbg_mode_debug_flag_arm}", fastbuild_mode_debug_flag = "%{fastbuild_mode_debug_flag_arm}", supports_parse_showincludes = %{msvc_parse_showincludes_arm}, ) toolchain( name = "cc-toolchain-x64_arm_windows", exec_compatible_with = [ "@platforms//cpu:x86_64", "@platforms//os:windows", ], target_compatible_with = [ "@platforms//cpu:arm", "@platforms//os:windows", ], toolchain = ":cc-compiler-x64_arm_windows", toolchain_type = "@bazel_tools//tools/cpp:toolchain_type", ) cc_toolchain( name = "cc-compiler-arm64_windows", toolchain_identifier = "msvc_arm64", toolchain_config = ":msvc_arm64", all_files = ":empty", ar_files = ":empty", as_files = ":msvc_compiler_files", compiler_files = ":msvc_compiler_files", dwp_files = ":empty", linker_files = ":empty", objcopy_files = ":empty", strip_files = ":empty", supports_param_files = 1, ) cc_toolchain_config( name = "msvc_arm64", cpu = "x64_windows", compiler = "msvc-cl", host_system_name = "local", target_system_name = "local", target_libc = "msvcrt", abi_version = "local", abi_libc_version = "local", toolchain_identifier = "msvc_arm64", msvc_env_tmp = "%{msvc_env_tmp_arm64}", msvc_env_path = "%{msvc_env_path_arm64}", msvc_env_include = "%{msvc_env_include_arm64}", msvc_env_lib = "%{msvc_env_lib_arm64}", msvc_cl_path = "%{msvc_cl_path_arm64}", msvc_ml_path = "%{msvc_ml_path_arm64}", msvc_link_path = "%{msvc_link_path_arm64}", msvc_lib_path = "%{msvc_lib_path_arm64}", cxx_builtin_include_directories = [%{msvc_cxx_builtin_include_directories_arm64}], tool_paths = { "ar": "%{msvc_lib_path_arm64}", "ml": "%{msvc_ml_path_arm64}", "cpp": "%{msvc_cl_path_arm64}", "gcc": "%{msvc_cl_path_arm64}", "gcov": "wrapper/bin/msvc_nop.bat", "ld": "%{msvc_link_path_arm64}", "nm": "wrapper/bin/msvc_nop.bat", "objcopy": "wrapper/bin/msvc_nop.bat", "objdump": "wrapper/bin/msvc_nop.bat", "strip": "wrapper/bin/msvc_nop.bat", "dumpbin": "%{msvc_dumpbin_path_arm64}", "cpp-module-deps-scanner": "%{msvc_deps_scanner_wrapper_path_arm64}", }, archiver_flags = ["/MACHINE:ARM64"], default_link_flags = ["/MACHINE:ARM64"], dbg_mode_debug_flag = "%{dbg_mode_debug_flag_arm64}", fastbuild_mode_debug_flag = "%{fastbuild_mode_debug_flag_arm64}", supports_parse_showincludes = %{msvc_parse_showincludes_arm64}, ) toolchain( name = "cc-toolchain-arm64_windows", exec_compatible_with = [ "@platforms//os:windows", ], target_compatible_with = [ "@platforms//cpu:arm64", "@platforms//os:windows", ], toolchain = ":cc-compiler-arm64_windows", toolchain_type = "@bazel_tools//tools/cpp:toolchain_type", ) cc_toolchain( name = "cc-compiler-x64_windows-clang-cl", toolchain_identifier = "clang_cl_x64", toolchain_config = ":clang_cl_x64", all_files = ":empty", ar_files = ":empty", as_files = ":clangcl_compiler_files", compiler_files = ":clangcl_compiler_files", dwp_files = ":empty", linker_files = ":empty", objcopy_files = ":empty", strip_files = ":empty", supports_param_files = 1, ) cc_toolchain_config( name = "clang_cl_x64", cpu = "x64_windows", compiler = "clang-cl", host_system_name = "local", target_system_name = "local", target_libc = "msvcrt", abi_version = "local", abi_libc_version = "local", toolchain_identifier = "clang_cl_x64", msvc_env_tmp = "%{clang_cl_env_tmp_x64}", msvc_env_path = "%{clang_cl_env_path_x64}", msvc_env_include = "%{clang_cl_env_include_x64}", msvc_env_lib = "%{clang_cl_env_lib_x64}", msvc_cl_path = "%{clang_cl_cl_path_x64}", msvc_ml_path = "%{clang_cl_ml_path_x64}", msvc_link_path = "%{clang_cl_link_path_x64}", msvc_lib_path = "%{clang_cl_lib_path_x64}", cxx_builtin_include_directories = [%{clang_cl_cxx_builtin_include_directories_x64}], tool_paths = { "ar": "%{clang_cl_lib_path_x64}", "ml": "%{clang_cl_ml_path_x64}", "cpp": "%{clang_cl_cl_path_x64}", "gcc": "%{clang_cl_cl_path_x64}", "gcov": "wrapper/bin/msvc_nop.bat", "ld": "%{clang_cl_link_path_x64}", "nm": "wrapper/bin/msvc_nop.bat", "objcopy": "wrapper/bin/msvc_nop.bat", "objdump": "wrapper/bin/msvc_nop.bat", "strip": "wrapper/bin/msvc_nop.bat", }, archiver_flags = ["/MACHINE:X64"], default_link_flags = ["/MACHINE:X64"], dbg_mode_debug_flag = "%{clang_cl_dbg_mode_debug_flag_x64}", fastbuild_mode_debug_flag = "%{clang_cl_fastbuild_mode_debug_flag_x64}", supports_parse_showincludes = %{clang_cl_parse_showincludes_x64}, ) toolchain( name = "cc-toolchain-x64_windows-clang-cl", exec_compatible_with = [ "@platforms//cpu:x86_64", "@platforms//os:windows", "@rules_cc//cc/private/toolchain:clang-cl", ], target_compatible_with = [ "@platforms//cpu:x86_64", "@platforms//os:windows", ], toolchain = ":cc-compiler-x64_windows-clang-cl", toolchain_type = "@bazel_tools//tools/cpp:toolchain_type", ) cc_toolchain( name = "cc-compiler-arm64_windows-clang-cl", toolchain_identifier = "clang_cl_arm64", toolchain_config = ":clang_cl_arm64", all_files = ":empty", ar_files = ":empty", as_files = ":clangcl_compiler_files", compiler_files = ":clangcl_compiler_files", dwp_files = ":empty", linker_files = ":empty", objcopy_files = ":empty", strip_files = ":empty", supports_param_files = 1, ) cc_toolchain_config( name = "clang_cl_arm64", cpu = "arm64_windows", compiler = "clang-cl", host_system_name = "local", target_system_name = "aarch64-pc-windows-msvc", target_libc = "msvcrt", abi_version = "local", abi_libc_version = "local", toolchain_identifier = "clang_cl_arm64", msvc_env_tmp = "%{clang_cl_env_tmp_arm64}", msvc_env_path = "%{clang_cl_env_path_arm64}", msvc_env_include = "%{clang_cl_env_include_arm64}", msvc_env_lib = "%{clang_cl_env_lib_arm64}", msvc_cl_path = "%{clang_cl_cl_path_arm64}", msvc_ml_path = "%{clang_cl_ml_path_arm64}", msvc_link_path = "%{clang_cl_link_path_arm64}", msvc_lib_path = "%{clang_cl_lib_path_arm64}", cxx_builtin_include_directories = [%{clang_cl_cxx_builtin_include_directories_arm64}], tool_paths = { "ar": "%{clang_cl_lib_path_arm64}", "ml": "%{clang_cl_ml_path_arm64}", "cpp": "%{clang_cl_cl_path_arm64}", "gcc": "%{clang_cl_cl_path_arm64}", "gcov": "wrapper/bin/msvc_nop.bat", "ld": "%{clang_cl_link_path_arm64}", "nm": "wrapper/bin/msvc_nop.bat", "objcopy": "wrapper/bin/msvc_nop.bat", "objdump": "wrapper/bin/msvc_nop.bat", "strip": "wrapper/bin/msvc_nop.bat", }, archiver_flags = ["/MACHINE:ARM64"], default_link_flags = ["/MACHINE:ARM64"], dbg_mode_debug_flag = "%{clang_cl_dbg_mode_debug_flag_arm64}", fastbuild_mode_debug_flag = "%{clang_cl_fastbuild_mode_debug_flag_arm64}", supports_parse_showincludes = %{clang_cl_parse_showincludes_arm64}, ) toolchain( name = "cc-toolchain-arm64_windows-clang-cl", exec_compatible_with = [ "@platforms//os:windows", "@rules_cc//cc/private/toolchain:clang-cl", ], target_compatible_with = [ "@platforms//cpu:arm64", "@platforms//os:windows", ], toolchain = ":cc-compiler-arm64_windows-clang-cl", toolchain_type = "@bazel_tools//tools/cpp:toolchain_type", ) cc_toolchain( name = "cc-compiler-armeabi-v7a", toolchain_identifier = "stub_armeabi-v7a", toolchain_config = ":stub_armeabi-v7a", all_files = ":empty", ar_files = ":empty", as_files = ":empty", compiler_files = ":empty", dwp_files = ":empty", linker_files = ":empty", objcopy_files = ":empty", strip_files = ":empty", supports_param_files = 1, ) armeabi_cc_toolchain_config(name = "stub_armeabi-v7a") toolchain( name = "cc-toolchain-armeabi-v7a", exec_compatible_with = [ ], target_compatible_with = [ "@platforms//cpu:armv7", "@platforms//os:android", ], toolchain = ":cc-compiler-armeabi-v7a", toolchain_type = "@bazel_tools//tools/cpp:toolchain_type", ) rules_cc-0.0.11/cc/private/toolchain/armeabi_cc_toolchain_config.bzl000066400000000000000000000057331470072561500255710ustar00rootroot00000000000000# Copyright 2019 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. """A Starlark cc_toolchain configuration rule""" load( "@rules_cc//cc:cc_toolchain_config_lib.bzl", "feature", "tool_path", ) def _impl(ctx): toolchain_identifier = "stub_armeabi-v7a" host_system_name = "armeabi-v7a" target_system_name = "armeabi-v7a" target_cpu = "armeabi-v7a" target_libc = "armeabi-v7a" compiler = "compiler" abi_version = "armeabi-v7a" abi_libc_version = "armeabi-v7a" cc_target_os = None builtin_sysroot = None action_configs = [] supports_pic_feature = feature(name = "supports_pic", enabled = True) supports_dynamic_linker_feature = feature(name = "supports_dynamic_linker", enabled = True) features = [supports_dynamic_linker_feature, supports_pic_feature] cxx_builtin_include_directories = [] artifact_name_patterns = [] make_variables = [] tool_paths = [ tool_path(name = "ar", path = "/bin/false"), tool_path(name = "compat-ld", path = "/bin/false"), tool_path(name = "cpp", path = "/bin/false"), tool_path(name = "dwp", path = "/bin/false"), tool_path(name = "gcc", path = "/bin/false"), tool_path(name = "gcov", path = "/bin/false"), tool_path(name = "ld", path = "/bin/false"), tool_path(name = "llvm-profdata", path = "/bin/false"), tool_path(name = "nm", path = "/bin/false"), tool_path(name = "objcopy", path = "/bin/false"), tool_path(name = "objdump", path = "/bin/false"), tool_path(name = "strip", path = "/bin/false"), ] return cc_common.create_cc_toolchain_config_info( ctx = ctx, features = features, action_configs = action_configs, artifact_name_patterns = artifact_name_patterns, cxx_builtin_include_directories = cxx_builtin_include_directories, toolchain_identifier = toolchain_identifier, host_system_name = host_system_name, target_system_name = target_system_name, target_cpu = target_cpu, target_libc = target_libc, compiler = compiler, abi_version = abi_version, abi_libc_version = abi_libc_version, tool_paths = tool_paths, make_variables = make_variables, builtin_sysroot = builtin_sysroot, cc_target_os = cc_target_os, ) armeabi_cc_toolchain_config = rule( implementation = _impl, attrs = {}, provides = [CcToolchainConfigInfo], ) rules_cc-0.0.11/cc/private/toolchain/bsd_cc_toolchain_config.bzl000066400000000000000000000244371470072561500247430ustar00rootroot00000000000000# Copyright 2019 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. """A Starlark cc_toolchain configuration rule for FreeBSD and OpenBSD.""" load("@rules_cc//cc:action_names.bzl", "ACTION_NAMES") load( "@rules_cc//cc:cc_toolchain_config_lib.bzl", "action_config", "feature", "flag_group", "flag_set", "tool", "tool_path", "with_feature_set", ) # buildifier: disable=deprecated-function all_compile_actions = [ ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile, ACTION_NAMES.linkstamp_compile, ACTION_NAMES.assemble, ACTION_NAMES.preprocess_assemble, ACTION_NAMES.cpp_header_parsing, ACTION_NAMES.cpp_module_compile, ACTION_NAMES.cpp_module_codegen, ACTION_NAMES.clif_match, ACTION_NAMES.lto_backend, ] all_cpp_compile_actions = [ ACTION_NAMES.cpp_compile, ACTION_NAMES.linkstamp_compile, ACTION_NAMES.cpp_header_parsing, ACTION_NAMES.cpp_module_compile, ACTION_NAMES.cpp_module_codegen, ACTION_NAMES.clif_match, ] all_link_actions = [ ACTION_NAMES.cpp_link_executable, ACTION_NAMES.cpp_link_dynamic_library, ACTION_NAMES.cpp_link_nodeps_dynamic_library, ] def _impl(ctx): cpu = ctx.attr.cpu is_bsd = cpu == "freebsd" or cpu == "openbsd" compiler = "compiler" toolchain_identifier = "local_{}".format(cpu) if is_bsd else "stub_armeabi-v7a" host_system_name = "local" if is_bsd else "armeabi-v7a" target_system_name = "local" if is_bsd else "armeabi-v7a" target_libc = "local" if is_bsd else "armeabi-v7a" abi_version = "local" if is_bsd else "armeabi-v7a" abi_libc_version = "local" if is_bsd else "armeabi-v7a" objcopy_embed_data_action = action_config( action_name = "objcopy_embed_data", enabled = True, tools = [tool(path = "/usr/bin/objcopy")], ) action_configs = [objcopy_embed_data_action] if is_bsd else [] default_link_flags_feature = feature( name = "default_link_flags", enabled = True, flag_sets = [ flag_set( actions = all_link_actions, flag_groups = [ flag_group( flags = [ "-lstdc++", "-Wl,-z,relro,-z,now", "-no-canonical-prefixes", ], ), ], ), flag_set( actions = all_link_actions, flag_groups = [flag_group(flags = ["-Wl,--gc-sections"])], with_features = [with_feature_set(features = ["opt"])], ), ], ) unfiltered_compile_flags_feature = feature( name = "unfiltered_compile_flags", enabled = True, flag_sets = [ flag_set( actions = all_compile_actions, flag_groups = [ flag_group( flags = [ "-no-canonical-prefixes", "-Wno-builtin-macro-redefined", "-D__DATE__=\"redacted\"", "-D__TIMESTAMP__=\"redacted\"", "-D__TIME__=\"redacted\"", ], ), ], ), ], ) supports_pic_feature = feature(name = "supports_pic", enabled = True) default_compile_flags_feature = feature( name = "default_compile_flags", enabled = True, flag_sets = [ flag_set( actions = all_compile_actions, flag_groups = [ flag_group( flags = [ "-U_FORTIFY_SOURCE", "-D_FORTIFY_SOURCE=1", "-fstack-protector", "-Wall", "-fno-omit-frame-pointer", ], ), ], ), flag_set( actions = all_compile_actions, flag_groups = [flag_group(flags = ["-g"])], with_features = [with_feature_set(features = ["dbg"])], ), flag_set( actions = all_compile_actions, flag_groups = [ flag_group( flags = [ "-g0", "-O2", "-DNDEBUG", "-ffunction-sections", "-fdata-sections", ], ), ], with_features = [with_feature_set(features = ["opt"])], ), flag_set( actions = all_cpp_compile_actions + [ACTION_NAMES.lto_backend], flag_groups = [flag_group(flags = ["-std=c++17"])], ), ], ) opt_feature = feature(name = "opt") supports_dynamic_linker_feature = feature(name = "supports_dynamic_linker", enabled = True) objcopy_embed_flags_feature = feature( name = "objcopy_embed_flags", enabled = True, flag_sets = [ flag_set( actions = ["objcopy_embed_data"], flag_groups = [flag_group(flags = ["-I", "binary"])], ), ], ) dbg_feature = feature(name = "dbg") user_compile_flags_feature = feature( name = "user_compile_flags", enabled = True, flag_sets = [ flag_set( actions = all_compile_actions, flag_groups = [ flag_group( flags = ["%{user_compile_flags}"], iterate_over = "user_compile_flags", expand_if_available = "user_compile_flags", ), ], ), ], ) sysroot_feature = feature( name = "sysroot", enabled = True, flag_sets = [ flag_set( actions = [ ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile, ACTION_NAMES.linkstamp_compile, ACTION_NAMES.preprocess_assemble, ACTION_NAMES.cpp_header_parsing, ACTION_NAMES.cpp_module_compile, ACTION_NAMES.cpp_module_codegen, ACTION_NAMES.clif_match, ACTION_NAMES.lto_backend, ] + all_link_actions, flag_groups = [ flag_group( flags = ["--sysroot=%{sysroot}"], expand_if_available = "sysroot", ), ], ), ], ) if is_bsd: features = [ default_compile_flags_feature, default_link_flags_feature, supports_dynamic_linker_feature, supports_pic_feature, objcopy_embed_flags_feature, opt_feature, dbg_feature, user_compile_flags_feature, sysroot_feature, unfiltered_compile_flags_feature, ] else: features = [supports_dynamic_linker_feature, supports_pic_feature] if (is_bsd): cxx_builtin_include_directories = ["/usr/lib/clang", "/usr/local/include", "/usr/include"] else: cxx_builtin_include_directories = [] if is_bsd: tool_paths = [ tool_path(name = "ar", path = "/usr/bin/ar"), tool_path(name = "compat-ld", path = "/usr/bin/ld"), tool_path(name = "cpp", path = "/usr/bin/cpp"), tool_path(name = "dwp", path = "/usr/bin/dwp"), tool_path(name = "gcc", path = "/usr/bin/clang"), tool_path(name = "gcov", path = "/usr/bin/gcov"), tool_path(name = "ld", path = "/usr/bin/ld"), tool_path(name = "nm", path = "/usr/bin/nm"), tool_path(name = "objcopy", path = "/usr/bin/objcopy"), tool_path(name = "objdump", path = "/usr/bin/objdump"), tool_path(name = "strip", path = "/usr/bin/strip"), ] else: tool_paths = [ tool_path(name = "ar", path = "/bin/false"), tool_path(name = "compat-ld", path = "/bin/false"), tool_path(name = "cpp", path = "/bin/false"), tool_path(name = "dwp", path = "/bin/false"), tool_path(name = "gcc", path = "/bin/false"), tool_path(name = "gcov", path = "/bin/false"), tool_path(name = "ld", path = "/bin/false"), tool_path(name = "nm", path = "/bin/false"), tool_path(name = "objcopy", path = "/bin/false"), tool_path(name = "objdump", path = "/bin/false"), tool_path(name = "strip", path = "/bin/false"), ] out = ctx.actions.declare_file(ctx.label.name) ctx.actions.write(out, "Fake executable") return [ cc_common.create_cc_toolchain_config_info( ctx = ctx, features = features, action_configs = action_configs, cxx_builtin_include_directories = cxx_builtin_include_directories, toolchain_identifier = toolchain_identifier, host_system_name = host_system_name, target_system_name = target_system_name, target_cpu = cpu, target_libc = target_libc, compiler = compiler, abi_version = abi_version, abi_libc_version = abi_libc_version, tool_paths = tool_paths, ), DefaultInfo( executable = out, ), ] cc_toolchain_config = rule( implementation = _impl, attrs = { "cpu": attr.string(mandatory = True), }, provides = [CcToolchainConfigInfo], executable = True, ) rules_cc-0.0.11/cc/private/toolchain/build_interface_so000066400000000000000000000001551470072561500231620ustar00rootroot00000000000000#!/bin/bash if [[ $# != 2 ]]; then echo "Usage: $0 " 1>&2 exit 1 fi exec cp $1 $2 rules_cc-0.0.11/cc/private/toolchain/cc_configure.bzl000066400000000000000000000134271470072561500225640ustar00rootroot00000000000000# 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. """Rules for configuring the C++ toolchain (experimental).""" load( ":lib_cc_configure.bzl", "get_cpu_value", "resolve_labels", ) load(":unix_cc_configure.bzl", "configure_unix_toolchain") load(":windows_cc_configure.bzl", "configure_windows_toolchain") def cc_autoconf_toolchains_impl(repository_ctx): """Generate BUILD file with 'toolchain' targets for the local host C++ toolchain. Args: repository_ctx: repository context """ env = repository_ctx.os.environ # Should we try to find C++ toolchain at all? If not, we don't have to generate toolchains for C++ at all. should_detect_cpp_toolchain = "BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN" not in env or env["BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN"] != "1" if should_detect_cpp_toolchain: paths = resolve_labels(repository_ctx, [ "@rules_cc//cc/private/toolchain:BUILD.toolchains.tpl", ]) repository_ctx.template( "BUILD", paths["@rules_cc//cc/private/toolchain:BUILD.toolchains.tpl"], {"%{name}": get_cpu_value(repository_ctx)}, ) else: repository_ctx.file("BUILD", "# C++ toolchain autoconfiguration was disabled by BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN env variable.") cc_autoconf_toolchains = repository_rule( environ = [ "BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN", ], implementation = cc_autoconf_toolchains_impl, configure = True, ) def cc_autoconf_impl(repository_ctx, overriden_tools = dict()): """Generate BUILD file with 'cc_toolchain' targets for the local host C++ toolchain. Args: repository_ctx: repository context overriden_tools: dict of tool paths to use instead of autoconfigured tools """ env = repository_ctx.os.environ cpu_value = get_cpu_value(repository_ctx) if "BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN" in env and env["BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN"] == "1": paths = resolve_labels(repository_ctx, [ "@rules_cc//cc/private/toolchain:BUILD.empty.tpl", "@rules_cc//cc/private/toolchain:empty_cc_toolchain_config.bzl", ]) repository_ctx.symlink(paths["@rules_cc//cc/private/toolchain:empty_cc_toolchain_config.bzl"], "cc_toolchain_config.bzl") repository_ctx.template("BUILD", paths["@rules_cc//cc/private/toolchain:BUILD.empty.tpl"], { "%{cpu}": get_cpu_value(repository_ctx), }) elif cpu_value == "freebsd" or cpu_value == "openbsd": paths = resolve_labels(repository_ctx, [ "@rules_cc//cc/private/toolchain:BUILD.static.bsd", "@rules_cc//cc/private/toolchain:bsd_cc_toolchain_config.bzl", ]) # This is defaulting to a static crosstool. We should eventually # autoconfigure this platform too. Theoretically, FreeBSD and OpenBSD # should be straightforward to add but we cannot run them in a Docker # container so skipping until we have proper tests for these platforms. repository_ctx.symlink(paths["@rules_cc//cc/private/toolchain:bsd_cc_toolchain_config.bzl"], "cc_toolchain_config.bzl") repository_ctx.symlink(paths["@rules_cc//cc/private/toolchain:BUILD.static.bsd"], "BUILD") elif cpu_value in ["x64_windows", "arm64_windows"]: # TODO(ibiryukov): overriden_tools are only supported in configure_unix_toolchain. # We might want to add that to Windows too(at least for msys toolchain). configure_windows_toolchain(repository_ctx) else: configure_unix_toolchain(repository_ctx, cpu_value, overriden_tools) MSVC_ENVVARS = [ "BAZEL_VC", "BAZEL_VC_FULL_VERSION", "BAZEL_VS", "BAZEL_WINSDK_FULL_VERSION", "VS90COMNTOOLS", "VS100COMNTOOLS", "VS110COMNTOOLS", "VS120COMNTOOLS", "VS140COMNTOOLS", "VS150COMNTOOLS", "VS160COMNTOOLS", "TMP", "TEMP", ] cc_autoconf = repository_rule( environ = [ "ABI_LIBC_VERSION", "ABI_VERSION", "BAZEL_COMPILER", "BAZEL_HOST_SYSTEM", "BAZEL_CONLYOPTS", "BAZEL_CXXOPTS", "BAZEL_LINKOPTS", "BAZEL_LINKLIBS", "BAZEL_LLVM_COV", "BAZEL_LLVM_PROFDATA", "BAZEL_PYTHON", "BAZEL_SH", "BAZEL_TARGET_CPU", "BAZEL_TARGET_LIBC", "BAZEL_TARGET_SYSTEM", "BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN", "BAZEL_USE_LLVM_NATIVE_COVERAGE", "BAZEL_LLVM", "BAZEL_IGNORE_SYSTEM_HEADERS_VERSIONS", "USE_CLANG_CL", "CC", "CC_CONFIGURE_DEBUG", "CC_TOOLCHAIN_NAME", "CPLUS_INCLUDE_PATH", "DEVELOPER_DIR", "GCOV", "LIBTOOL", "HOMEBREW_RUBY_PATH", "SYSTEMROOT", "USER", ] + MSVC_ENVVARS, implementation = cc_autoconf_impl, configure = True, ) # buildifier: disable=unnamed-macro def cc_configure(): """A C++ configuration rules that generate the crosstool file.""" cc_autoconf_toolchains(name = "local_config_cc_toolchains") cc_autoconf(name = "local_config_cc") native.bind(name = "cc_toolchain", actual = "@local_config_cc//:toolchain") native.register_toolchains( # Use register_toolchain's target pattern expansion to register all toolchains in the package. "@local_config_cc_toolchains//:all", ) rules_cc-0.0.11/cc/private/toolchain/cc_toolchain_config.bzl000066400000000000000000001636651470072561500241220ustar00rootroot00000000000000# Copyright 2019 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. """A Starlark cc_toolchain configuration rule""" load( "@rules_cc//cc:action_names.bzl", _ASSEMBLE_ACTION_NAME = "ASSEMBLE_ACTION_NAME", _CLIF_MATCH_ACTION_NAME = "CLIF_MATCH_ACTION_NAME", _CPP_COMPILE_ACTION_NAME = "CPP_COMPILE_ACTION_NAME", _CPP_HEADER_PARSING_ACTION_NAME = "CPP_HEADER_PARSING_ACTION_NAME", _CPP_LINK_DYNAMIC_LIBRARY_ACTION_NAME = "CPP_LINK_DYNAMIC_LIBRARY_ACTION_NAME", _CPP_LINK_EXECUTABLE_ACTION_NAME = "CPP_LINK_EXECUTABLE_ACTION_NAME", _CPP_LINK_NODEPS_DYNAMIC_LIBRARY_ACTION_NAME = "CPP_LINK_NODEPS_DYNAMIC_LIBRARY_ACTION_NAME", _CPP_MODULE_CODEGEN_ACTION_NAME = "CPP_MODULE_CODEGEN_ACTION_NAME", _CPP_MODULE_COMPILE_ACTION_NAME = "CPP_MODULE_COMPILE_ACTION_NAME", _C_COMPILE_ACTION_NAME = "C_COMPILE_ACTION_NAME", _LINKSTAMP_COMPILE_ACTION_NAME = "LINKSTAMP_COMPILE_ACTION_NAME", _LTO_BACKEND_ACTION_NAME = "LTO_BACKEND_ACTION_NAME", _PREPROCESS_ASSEMBLE_ACTION_NAME = "PREPROCESS_ASSEMBLE_ACTION_NAME", ) load( "@rules_cc//cc:cc_toolchain_config_lib.bzl", "action_config", "feature", "flag_group", "flag_set", "tool", "tool_path", "with_feature_set", ) all_compile_actions = [ _C_COMPILE_ACTION_NAME, _CPP_COMPILE_ACTION_NAME, _LINKSTAMP_COMPILE_ACTION_NAME, _ASSEMBLE_ACTION_NAME, _PREPROCESS_ASSEMBLE_ACTION_NAME, _CPP_HEADER_PARSING_ACTION_NAME, _CPP_MODULE_COMPILE_ACTION_NAME, _CPP_MODULE_CODEGEN_ACTION_NAME, _CLIF_MATCH_ACTION_NAME, _LTO_BACKEND_ACTION_NAME, ] all_cpp_compile_actions = [ _CPP_COMPILE_ACTION_NAME, _LINKSTAMP_COMPILE_ACTION_NAME, _CPP_HEADER_PARSING_ACTION_NAME, _CPP_MODULE_COMPILE_ACTION_NAME, _CPP_MODULE_CODEGEN_ACTION_NAME, _CLIF_MATCH_ACTION_NAME, ] preprocessor_compile_actions = [ _C_COMPILE_ACTION_NAME, _CPP_COMPILE_ACTION_NAME, _LINKSTAMP_COMPILE_ACTION_NAME, _PREPROCESS_ASSEMBLE_ACTION_NAME, _CPP_HEADER_PARSING_ACTION_NAME, _CPP_MODULE_COMPILE_ACTION_NAME, _CLIF_MATCH_ACTION_NAME, ] codegen_compile_actions = [ _C_COMPILE_ACTION_NAME, _CPP_COMPILE_ACTION_NAME, _LINKSTAMP_COMPILE_ACTION_NAME, _ASSEMBLE_ACTION_NAME, _PREPROCESS_ASSEMBLE_ACTION_NAME, _CPP_MODULE_CODEGEN_ACTION_NAME, _LTO_BACKEND_ACTION_NAME, ] all_link_actions = [ _CPP_LINK_EXECUTABLE_ACTION_NAME, _CPP_LINK_DYNAMIC_LIBRARY_ACTION_NAME, _CPP_LINK_NODEPS_DYNAMIC_LIBRARY_ACTION_NAME, ] def _impl(ctx): if ctx.attr.disable_static_cc_toolchains: fail("@rules_cc//cc/private/toolchain:default-toolchain, as well as the cc_toolchains it points " + "to have been removed. See https://github.com/bazelbuild/bazel/issues/8546.") if (ctx.attr.cpu == "darwin"): toolchain_identifier = "local_darwin" elif (ctx.attr.cpu == "freebsd"): toolchain_identifier = "local_freebsd" elif (ctx.attr.cpu == "local"): toolchain_identifier = "local_linux" elif (ctx.attr.cpu == "x64_windows" and ctx.attr.compiler == "windows_clang"): toolchain_identifier = "local_windows_clang" elif (ctx.attr.cpu == "x64_windows" and ctx.attr.compiler == "windows_mingw"): toolchain_identifier = "local_windows_mingw" elif (ctx.attr.cpu == "x64_windows" and ctx.attr.compiler == "windows_msys64"): toolchain_identifier = "local_windows_msys64" elif (ctx.attr.cpu == "x64_windows" and ctx.attr.compiler == "windows_msys64_mingw64"): toolchain_identifier = "local_windows_msys64_mingw64" elif (ctx.attr.cpu == "armeabi-v7a"): toolchain_identifier = "stub_armeabi-v7a" elif (ctx.attr.cpu == "x64_windows_msvc"): toolchain_identifier = "vc_14_0_x64" else: fail("Unreachable") if (ctx.attr.cpu == "armeabi-v7a"): host_system_name = "armeabi-v7a" elif (ctx.attr.cpu == "darwin" or ctx.attr.cpu == "freebsd" or ctx.attr.cpu == "local" or ctx.attr.cpu == "x64_windows" or ctx.attr.cpu == "x64_windows_msvc"): host_system_name = "local" else: fail("Unreachable") if (ctx.attr.cpu == "armeabi-v7a"): target_system_name = "armeabi-v7a" elif (ctx.attr.cpu == "darwin" or ctx.attr.cpu == "freebsd" or ctx.attr.cpu == "local" or ctx.attr.cpu == "x64_windows" or ctx.attr.cpu == "x64_windows_msvc"): target_system_name = "local" else: fail("Unreachable") if (ctx.attr.cpu == "armeabi-v7a"): target_cpu = "armeabi-v7a" elif (ctx.attr.cpu == "darwin"): target_cpu = "darwin" elif (ctx.attr.cpu == "freebsd"): target_cpu = "freebsd" elif (ctx.attr.cpu == "local"): target_cpu = "local" elif (ctx.attr.cpu == "x64_windows"): target_cpu = "x64_windows" elif (ctx.attr.cpu == "x64_windows_msvc"): target_cpu = "x64_windows_msvc" else: fail("Unreachable") if (ctx.attr.cpu == "armeabi-v7a"): target_libc = "armeabi-v7a" elif (ctx.attr.cpu == "freebsd" or ctx.attr.cpu == "local" or ctx.attr.cpu == "x64_windows"): target_libc = "local" elif (ctx.attr.cpu == "darwin"): target_libc = "macosx" elif (ctx.attr.cpu == "x64_windows_msvc"): target_libc = "msvcrt140" else: fail("Unreachable") if (ctx.attr.cpu == "x64_windows_msvc"): compiler = "cl" elif (ctx.attr.cpu == "armeabi-v7a" or ctx.attr.cpu == "darwin" or ctx.attr.cpu == "freebsd" or ctx.attr.cpu == "local"): compiler = "compiler" elif (ctx.attr.cpu == "x64_windows" and ctx.attr.compiler == "windows_clang"): compiler = "windows_clang" elif (ctx.attr.cpu == "x64_windows" and ctx.attr.compiler == "windows_mingw"): compiler = "windows_mingw" elif (ctx.attr.cpu == "x64_windows" and ctx.attr.compiler == "windows_msys64"): compiler = "windows_msys64" elif (ctx.attr.cpu == "x64_windows" and ctx.attr.compiler == "windows_msys64_mingw64"): compiler = "windows_msys64_mingw64" else: fail("Unreachable") if (ctx.attr.cpu == "armeabi-v7a"): abi_version = "armeabi-v7a" elif (ctx.attr.cpu == "darwin" or ctx.attr.cpu == "freebsd" or ctx.attr.cpu == "local" or ctx.attr.cpu == "x64_windows" or ctx.attr.cpu == "x64_windows_msvc"): abi_version = "local" else: fail("Unreachable") if (ctx.attr.cpu == "armeabi-v7a"): abi_libc_version = "armeabi-v7a" elif (ctx.attr.cpu == "darwin" or ctx.attr.cpu == "freebsd" or ctx.attr.cpu == "local" or ctx.attr.cpu == "x64_windows" or ctx.attr.cpu == "x64_windows_msvc"): abi_libc_version = "local" else: fail("Unreachable") cc_target_os = None builtin_sysroot = None objcopy_embed_data_action = None if (ctx.attr.cpu == "darwin" or ctx.attr.cpu == "freebsd" or ctx.attr.cpu == "local"): objcopy_embed_data_action = action_config( action_name = "objcopy_embed_data", enabled = True, tools = [tool(path = "/usr/bin/objcopy")], ) elif (ctx.attr.cpu == "x64_windows" and ctx.attr.compiler == "windows_clang"): objcopy_embed_data_action = action_config( action_name = "objcopy_embed_data", enabled = True, tools = [tool(path = "C:/Program Files (x86)/LLVM/bin/objcopy")], ) elif (ctx.attr.cpu == "x64_windows" and ctx.attr.compiler == "windows_mingw"): objcopy_embed_data_action = action_config( action_name = "objcopy_embed_data", enabled = True, tools = [tool(path = "C:/mingw/bin/objcopy")], ) elif (ctx.attr.cpu == "x64_windows" and ctx.attr.compiler == "windows_msys64_mingw64"): objcopy_embed_data_action = action_config( action_name = "objcopy_embed_data", enabled = True, tools = [tool(path = "C:/tools/msys64/mingw64/bin/objcopy")], ) elif (ctx.attr.cpu == "x64_windows" and ctx.attr.compiler == "windows_msys64"): objcopy_embed_data_action = action_config( action_name = "objcopy_embed_data", enabled = True, tools = [tool(path = "C:/tools/msys64/usr/bin/objcopy")], ) c_compile_action = action_config( action_name = _C_COMPILE_ACTION_NAME, implies = [ "compiler_input_flags", "compiler_output_flags", "default_compile_flags", "user_compile_flags", "sysroot", "unfiltered_compile_flags", ], tools = [tool(path = "wrapper/bin/msvc_cl.bat")], ) cpp_compile_action = action_config( action_name = _CPP_COMPILE_ACTION_NAME, implies = [ "compiler_input_flags", "compiler_output_flags", "default_compile_flags", "user_compile_flags", "sysroot", "unfiltered_compile_flags", ], tools = [tool(path = "wrapper/bin/msvc_cl.bat")], ) if (ctx.attr.cpu == "armeabi-v7a"): action_configs = [] elif (ctx.attr.cpu == "x64_windows_msvc"): action_configs = [c_compile_action, cpp_compile_action] elif (ctx.attr.cpu == "darwin" or ctx.attr.cpu == "freebsd" or ctx.attr.cpu == "local" or ctx.attr.cpu == "x64_windows"): action_configs = [objcopy_embed_data_action] else: fail("Unreachable") random_seed_feature = feature(name = "random_seed", enabled = True) compiler_output_flags_feature = feature( name = "compiler_output_flags", flag_sets = [ flag_set( actions = [_ASSEMBLE_ACTION_NAME], flag_groups = [ flag_group( flags = ["/Fo%{output_file}", "/Zi"], expand_if_available = "output_file", expand_if_not_available = "output_assembly_file", ), ], ), flag_set( actions = [ _PREPROCESS_ASSEMBLE_ACTION_NAME, _C_COMPILE_ACTION_NAME, _CPP_COMPILE_ACTION_NAME, _CPP_HEADER_PARSING_ACTION_NAME, _CPP_MODULE_COMPILE_ACTION_NAME, _CPP_MODULE_CODEGEN_ACTION_NAME, ], flag_groups = [ flag_group( flags = ["/Fo%{output_file}"], expand_if_available = "output_file", expand_if_not_available = "output_assembly_file", ), flag_group( flags = ["/Fa%{output_file}"], expand_if_available = "output_file", ), flag_group( flags = ["/P", "/Fi%{output_file}"], expand_if_available = "output_file", ), ], ), ], ) default_link_flags_feature = None if (ctx.attr.cpu == "local"): default_link_flags_feature = feature( name = "default_link_flags", enabled = True, flag_sets = [ flag_set( actions = all_link_actions, flag_groups = [ flag_group( flags = [ "-lstdc++", "-Wl,-z,relro,-z,now", "-no-canonical-prefixes", "-pass-exit-codes", ], ), ], ), flag_set( actions = all_link_actions, flag_groups = [flag_group(flags = ["-Wl,--gc-sections"])], with_features = [with_feature_set(features = ["opt"])], ), ], ) elif (ctx.attr.cpu == "freebsd"): default_link_flags_feature = feature( name = "default_link_flags", enabled = True, flag_sets = [ flag_set( actions = all_link_actions, flag_groups = [ flag_group( flags = [ "-lstdc++", "-Wl,-z,relro,-z,now", "-no-canonical-prefixes", ], ), ], ), flag_set( actions = all_link_actions, flag_groups = [flag_group(flags = ["-Wl,--gc-sections"])], with_features = [with_feature_set(features = ["opt"])], ), ], ) elif (ctx.attr.cpu == "darwin"): default_link_flags_feature = feature( name = "default_link_flags", enabled = True, flag_sets = [ flag_set( actions = all_link_actions, flag_groups = [ flag_group( flags = [ "-lstdc++", "-undefined", "dynamic_lookup", "-headerpad_max_install_names", "-no-canonical-prefixes", ], ), ], ), ], ) elif (ctx.attr.cpu == "x64_windows" and ctx.attr.compiler == "windows_msys64"): default_link_flags_feature = feature( name = "default_link_flags", enabled = True, flag_sets = [ flag_set( actions = all_link_actions, flag_groups = [flag_group(flags = ["-lstdc++"])], ), ], ) elif (ctx.attr.cpu == "x64_windows_msvc"): default_link_flags_feature = feature( name = "default_link_flags", enabled = True, flag_sets = [ flag_set( actions = all_link_actions, flag_groups = [flag_group(flags = ["-m64"])], ), ], ) unfiltered_compile_flags_feature = None if (ctx.attr.cpu == "darwin" or ctx.attr.cpu == "freebsd"): unfiltered_compile_flags_feature = feature( name = "unfiltered_compile_flags", enabled = True, flag_sets = [ flag_set( actions = [ _ASSEMBLE_ACTION_NAME, _PREPROCESS_ASSEMBLE_ACTION_NAME, _LINKSTAMP_COMPILE_ACTION_NAME, _C_COMPILE_ACTION_NAME, _CPP_COMPILE_ACTION_NAME, _CPP_HEADER_PARSING_ACTION_NAME, _CPP_MODULE_COMPILE_ACTION_NAME, _CPP_MODULE_CODEGEN_ACTION_NAME, _LTO_BACKEND_ACTION_NAME, _CLIF_MATCH_ACTION_NAME, ], flag_groups = [ flag_group( flags = [ "-no-canonical-prefixes", "-Wno-builtin-macro-redefined", "-D__DATE__=\"redacted\"", "-D__TIMESTAMP__=\"redacted\"", "-D__TIME__=\"redacted\"", ], ), ], ), ], ) elif (ctx.attr.cpu == "local"): unfiltered_compile_flags_feature = feature( name = "unfiltered_compile_flags", enabled = True, flag_sets = [ flag_set( actions = [ _ASSEMBLE_ACTION_NAME, _PREPROCESS_ASSEMBLE_ACTION_NAME, _LINKSTAMP_COMPILE_ACTION_NAME, _C_COMPILE_ACTION_NAME, _CPP_COMPILE_ACTION_NAME, _CPP_HEADER_PARSING_ACTION_NAME, _CPP_MODULE_COMPILE_ACTION_NAME, _CPP_MODULE_CODEGEN_ACTION_NAME, _LTO_BACKEND_ACTION_NAME, _CLIF_MATCH_ACTION_NAME, ], flag_groups = [ flag_group( flags = [ "-no-canonical-prefixes", "-fno-canonical-system-headers", "-Wno-builtin-macro-redefined", "-D__DATE__=\"redacted\"", "-D__TIMESTAMP__=\"redacted\"", "-D__TIME__=\"redacted\"", ], ), ], ), ], ) elif (ctx.attr.cpu == "x64_windows_msvc"): unfiltered_compile_flags_feature = feature( name = "unfiltered_compile_flags", flag_sets = [ flag_set( actions = [ _ASSEMBLE_ACTION_NAME, _PREPROCESS_ASSEMBLE_ACTION_NAME, _C_COMPILE_ACTION_NAME, _CPP_COMPILE_ACTION_NAME, _CPP_HEADER_PARSING_ACTION_NAME, _CPP_MODULE_COMPILE_ACTION_NAME, _CPP_MODULE_CODEGEN_ACTION_NAME, ], flag_groups = [ flag_group( flags = ["%{unfiltered_compile_flags}"], iterate_over = "unfiltered_compile_flags", expand_if_available = "unfiltered_compile_flags", ), ], ), ], ) supports_pic_feature = feature(name = "supports_pic", enabled = True) default_compile_flags_feature = None if (ctx.attr.cpu == "darwin"): default_compile_flags_feature = feature( name = "default_compile_flags", enabled = True, flag_sets = [ flag_set( actions = [ _ASSEMBLE_ACTION_NAME, _PREPROCESS_ASSEMBLE_ACTION_NAME, _LINKSTAMP_COMPILE_ACTION_NAME, _C_COMPILE_ACTION_NAME, _CPP_COMPILE_ACTION_NAME, _CPP_HEADER_PARSING_ACTION_NAME, _CPP_MODULE_COMPILE_ACTION_NAME, _CPP_MODULE_CODEGEN_ACTION_NAME, _LTO_BACKEND_ACTION_NAME, _CLIF_MATCH_ACTION_NAME, ], flag_groups = [ flag_group( flags = [ "-D_FORTIFY_SOURCE=1", "-fstack-protector", "-fcolor-diagnostics", "-Wall", "-Wthread-safety", "-Wself-assign", "-fno-omit-frame-pointer", ], ), ], ), flag_set( actions = [ _ASSEMBLE_ACTION_NAME, _PREPROCESS_ASSEMBLE_ACTION_NAME, _LINKSTAMP_COMPILE_ACTION_NAME, _C_COMPILE_ACTION_NAME, _CPP_COMPILE_ACTION_NAME, _CPP_HEADER_PARSING_ACTION_NAME, _CPP_MODULE_COMPILE_ACTION_NAME, _CPP_MODULE_CODEGEN_ACTION_NAME, _LTO_BACKEND_ACTION_NAME, _CLIF_MATCH_ACTION_NAME, ], flag_groups = [flag_group(flags = ["-g"])], with_features = [with_feature_set(features = ["dbg"])], ), flag_set( actions = [ _ASSEMBLE_ACTION_NAME, _PREPROCESS_ASSEMBLE_ACTION_NAME, _LINKSTAMP_COMPILE_ACTION_NAME, _C_COMPILE_ACTION_NAME, _CPP_COMPILE_ACTION_NAME, _CPP_HEADER_PARSING_ACTION_NAME, _CPP_MODULE_COMPILE_ACTION_NAME, _CPP_MODULE_CODEGEN_ACTION_NAME, _LTO_BACKEND_ACTION_NAME, _CLIF_MATCH_ACTION_NAME, ], flag_groups = [ flag_group( flags = [ "-g0", "-O2", "-DNDEBUG", "-ffunction-sections", "-fdata-sections", ], ), ], with_features = [with_feature_set(features = ["opt"])], ), flag_set( actions = [ _LINKSTAMP_COMPILE_ACTION_NAME, _CPP_COMPILE_ACTION_NAME, _CPP_HEADER_PARSING_ACTION_NAME, _CPP_MODULE_COMPILE_ACTION_NAME, _CPP_MODULE_CODEGEN_ACTION_NAME, _LTO_BACKEND_ACTION_NAME, _CLIF_MATCH_ACTION_NAME, ], flag_groups = [flag_group(flags = ["-std=c++0x"])], ), ], ) elif (ctx.attr.cpu == "local"): default_compile_flags_feature = feature( name = "default_compile_flags", enabled = True, flag_sets = [ flag_set( actions = [ _ASSEMBLE_ACTION_NAME, _PREPROCESS_ASSEMBLE_ACTION_NAME, _LINKSTAMP_COMPILE_ACTION_NAME, _C_COMPILE_ACTION_NAME, _CPP_COMPILE_ACTION_NAME, _CPP_HEADER_PARSING_ACTION_NAME, _CPP_MODULE_COMPILE_ACTION_NAME, _CPP_MODULE_CODEGEN_ACTION_NAME, _LTO_BACKEND_ACTION_NAME, _CLIF_MATCH_ACTION_NAME, ], flag_groups = [ flag_group( flags = [ "-U_FORTIFY_SOURCE", "-D_FORTIFY_SOURCE=1", "-fstack-protector", "-Wall", "-Wunused-but-set-parameter", "-Wno-free-nonheap-object", "-fno-omit-frame-pointer", ], ), ], ), flag_set( actions = [ _ASSEMBLE_ACTION_NAME, _PREPROCESS_ASSEMBLE_ACTION_NAME, _LINKSTAMP_COMPILE_ACTION_NAME, _C_COMPILE_ACTION_NAME, _CPP_COMPILE_ACTION_NAME, _CPP_HEADER_PARSING_ACTION_NAME, _CPP_MODULE_COMPILE_ACTION_NAME, _CPP_MODULE_CODEGEN_ACTION_NAME, _LTO_BACKEND_ACTION_NAME, _CLIF_MATCH_ACTION_NAME, ], flag_groups = [flag_group(flags = ["-g"])], with_features = [with_feature_set(features = ["dbg"])], ), flag_set( actions = [ _ASSEMBLE_ACTION_NAME, _PREPROCESS_ASSEMBLE_ACTION_NAME, _LINKSTAMP_COMPILE_ACTION_NAME, _C_COMPILE_ACTION_NAME, _CPP_COMPILE_ACTION_NAME, _CPP_HEADER_PARSING_ACTION_NAME, _CPP_MODULE_COMPILE_ACTION_NAME, _CPP_MODULE_CODEGEN_ACTION_NAME, _LTO_BACKEND_ACTION_NAME, _CLIF_MATCH_ACTION_NAME, ], flag_groups = [ flag_group( flags = [ "-g0", "-O2", "-DNDEBUG", "-ffunction-sections", "-fdata-sections", ], ), ], with_features = [with_feature_set(features = ["opt"])], ), flag_set( actions = [ _LINKSTAMP_COMPILE_ACTION_NAME, _CPP_COMPILE_ACTION_NAME, _CPP_HEADER_PARSING_ACTION_NAME, _CPP_MODULE_COMPILE_ACTION_NAME, _CPP_MODULE_CODEGEN_ACTION_NAME, _LTO_BACKEND_ACTION_NAME, _CLIF_MATCH_ACTION_NAME, ], flag_groups = [flag_group(flags = ["-std=c++0x"])], ), ], ) elif (ctx.attr.cpu == "freebsd"): default_compile_flags_feature = feature( name = "default_compile_flags", enabled = True, flag_sets = [ flag_set( actions = [ _ASSEMBLE_ACTION_NAME, _PREPROCESS_ASSEMBLE_ACTION_NAME, _LINKSTAMP_COMPILE_ACTION_NAME, _C_COMPILE_ACTION_NAME, _CPP_COMPILE_ACTION_NAME, _CPP_HEADER_PARSING_ACTION_NAME, _CPP_MODULE_COMPILE_ACTION_NAME, _CPP_MODULE_CODEGEN_ACTION_NAME, _LTO_BACKEND_ACTION_NAME, _CLIF_MATCH_ACTION_NAME, ], flag_groups = [ flag_group( flags = [ "-U_FORTIFY_SOURCE", "-D_FORTIFY_SOURCE=1", "-fstack-protector", "-Wall", "-fno-omit-frame-pointer", ], ), ], ), flag_set( actions = [ _ASSEMBLE_ACTION_NAME, _PREPROCESS_ASSEMBLE_ACTION_NAME, _LINKSTAMP_COMPILE_ACTION_NAME, _C_COMPILE_ACTION_NAME, _CPP_COMPILE_ACTION_NAME, _CPP_HEADER_PARSING_ACTION_NAME, _CPP_MODULE_COMPILE_ACTION_NAME, _CPP_MODULE_CODEGEN_ACTION_NAME, _LTO_BACKEND_ACTION_NAME, _CLIF_MATCH_ACTION_NAME, ], flag_groups = [flag_group(flags = ["-g"])], with_features = [with_feature_set(features = ["dbg"])], ), flag_set( actions = [ _ASSEMBLE_ACTION_NAME, _PREPROCESS_ASSEMBLE_ACTION_NAME, _LINKSTAMP_COMPILE_ACTION_NAME, _C_COMPILE_ACTION_NAME, _CPP_COMPILE_ACTION_NAME, _CPP_HEADER_PARSING_ACTION_NAME, _CPP_MODULE_COMPILE_ACTION_NAME, _CPP_MODULE_CODEGEN_ACTION_NAME, _LTO_BACKEND_ACTION_NAME, _CLIF_MATCH_ACTION_NAME, ], flag_groups = [ flag_group( flags = [ "-g0", "-O2", "-DNDEBUG", "-ffunction-sections", "-fdata-sections", ], ), ], with_features = [with_feature_set(features = ["opt"])], ), flag_set( actions = [ _LINKSTAMP_COMPILE_ACTION_NAME, _CPP_COMPILE_ACTION_NAME, _CPP_HEADER_PARSING_ACTION_NAME, _CPP_MODULE_COMPILE_ACTION_NAME, _CPP_MODULE_CODEGEN_ACTION_NAME, _LTO_BACKEND_ACTION_NAME, _CLIF_MATCH_ACTION_NAME, ], flag_groups = [flag_group(flags = ["-std=c++0x"])], ), ], ) elif (ctx.attr.cpu == "x64_windows_msvc"): default_compile_flags_feature = feature( name = "default_compile_flags", enabled = True, flag_sets = [ flag_set( actions = [ _ASSEMBLE_ACTION_NAME, _PREPROCESS_ASSEMBLE_ACTION_NAME, _LINKSTAMP_COMPILE_ACTION_NAME, _C_COMPILE_ACTION_NAME, _CPP_COMPILE_ACTION_NAME, _CPP_HEADER_PARSING_ACTION_NAME, _CPP_MODULE_COMPILE_ACTION_NAME, _CPP_MODULE_CODEGEN_ACTION_NAME, _LTO_BACKEND_ACTION_NAME, _CLIF_MATCH_ACTION_NAME, ], flag_groups = [ flag_group( flags = [ "-m64", "/D__inline__=__inline", "/DCOMPILER_MSVC", "/DNOGDI", "/DNOMINMAX", "/DPRAGMA_SUPPORTED", "/D_WIN32_WINNT=0x0601", "/D_CRT_SECURE_NO_DEPRECATE", "/D_CRT_SECURE_NO_WARNINGS", "/D_SILENCE_STDEXT_HASH_DEPRECATION_WARNINGS", "/D_USE_MATH_DEFINES", "/nologo", "/bigobj", "/Zm500", "/J", "/Gy", "/GF", "/W3", "/EHsc", "/wd4351", "/wd4291", "/wd4250", "/wd4996", ], ), ], ), flag_set( actions = [ _ASSEMBLE_ACTION_NAME, _PREPROCESS_ASSEMBLE_ACTION_NAME, _LINKSTAMP_COMPILE_ACTION_NAME, _C_COMPILE_ACTION_NAME, _CPP_COMPILE_ACTION_NAME, _CPP_HEADER_PARSING_ACTION_NAME, _CPP_MODULE_COMPILE_ACTION_NAME, _CPP_MODULE_CODEGEN_ACTION_NAME, _LTO_BACKEND_ACTION_NAME, _CLIF_MATCH_ACTION_NAME, ], flag_groups = [ flag_group( flags = ["/DDEBUG=1", "-g", "/Od", "-Xcompilation-mode=dbg"], ), ], with_features = [with_feature_set(features = ["dbg"])], ), flag_set( actions = [ _ASSEMBLE_ACTION_NAME, _PREPROCESS_ASSEMBLE_ACTION_NAME, _LINKSTAMP_COMPILE_ACTION_NAME, _C_COMPILE_ACTION_NAME, _CPP_COMPILE_ACTION_NAME, _CPP_HEADER_PARSING_ACTION_NAME, _CPP_MODULE_COMPILE_ACTION_NAME, _CPP_MODULE_CODEGEN_ACTION_NAME, _LTO_BACKEND_ACTION_NAME, _CLIF_MATCH_ACTION_NAME, ], flag_groups = [ flag_group( flags = ["/DNDEBUG", "/Od", "-Xcompilation-mode=fastbuild"], ), ], with_features = [with_feature_set(features = ["fastbuild"])], ), flag_set( actions = [ _ASSEMBLE_ACTION_NAME, _PREPROCESS_ASSEMBLE_ACTION_NAME, _LINKSTAMP_COMPILE_ACTION_NAME, _C_COMPILE_ACTION_NAME, _CPP_COMPILE_ACTION_NAME, _CPP_HEADER_PARSING_ACTION_NAME, _CPP_MODULE_COMPILE_ACTION_NAME, _CPP_MODULE_CODEGEN_ACTION_NAME, _LTO_BACKEND_ACTION_NAME, _CLIF_MATCH_ACTION_NAME, ], flag_groups = [ flag_group( flags = ["/DNDEBUG", "/O2", "-Xcompilation-mode=opt"], ), ], with_features = [with_feature_set(features = ["opt"])], ), ], ) elif (ctx.attr.cpu == "x64_windows" and ctx.attr.compiler == "windows_clang" or ctx.attr.cpu == "x64_windows" and ctx.attr.compiler == "windows_mingw" or ctx.attr.cpu == "x64_windows" and ctx.attr.compiler == "windows_msys64_mingw64"): default_compile_flags_feature = feature( name = "default_compile_flags", enabled = True, flag_sets = [ flag_set( actions = [ _LINKSTAMP_COMPILE_ACTION_NAME, _CPP_COMPILE_ACTION_NAME, _CPP_HEADER_PARSING_ACTION_NAME, _CPP_MODULE_COMPILE_ACTION_NAME, _CPP_MODULE_CODEGEN_ACTION_NAME, _LTO_BACKEND_ACTION_NAME, _CLIF_MATCH_ACTION_NAME, ], flag_groups = [flag_group(flags = ["-std=c++0x"])], ), ], ) elif (ctx.attr.cpu == "x64_windows" and ctx.attr.compiler == "windows_msys64"): default_compile_flags_feature = feature( name = "default_compile_flags", enabled = True, flag_sets = [ flag_set( actions = [ _LINKSTAMP_COMPILE_ACTION_NAME, _CPP_COMPILE_ACTION_NAME, _CPP_HEADER_PARSING_ACTION_NAME, _CPP_MODULE_COMPILE_ACTION_NAME, _CPP_MODULE_CODEGEN_ACTION_NAME, _LTO_BACKEND_ACTION_NAME, _CLIF_MATCH_ACTION_NAME, ], flag_groups = [flag_group(flags = ["-std=gnu++0x"])], ), ], ) opt_feature = feature(name = "opt") supports_dynamic_linker_feature = feature(name = "supports_dynamic_linker", enabled = True) objcopy_embed_flags_feature = feature( name = "objcopy_embed_flags", enabled = True, flag_sets = [ flag_set( actions = ["objcopy_embed_data"], flag_groups = [flag_group(flags = ["-I", "binary"])], ), ], ) dbg_feature = feature(name = "dbg") user_compile_flags_feature = None if (ctx.attr.cpu == "darwin" or ctx.attr.cpu == "freebsd" or ctx.attr.cpu == "local"): user_compile_flags_feature = feature( name = "user_compile_flags", enabled = True, flag_sets = [ flag_set( actions = [ _ASSEMBLE_ACTION_NAME, _PREPROCESS_ASSEMBLE_ACTION_NAME, _LINKSTAMP_COMPILE_ACTION_NAME, _C_COMPILE_ACTION_NAME, _CPP_COMPILE_ACTION_NAME, _CPP_HEADER_PARSING_ACTION_NAME, _CPP_MODULE_COMPILE_ACTION_NAME, _CPP_MODULE_CODEGEN_ACTION_NAME, _LTO_BACKEND_ACTION_NAME, _CLIF_MATCH_ACTION_NAME, ], flag_groups = [ flag_group( flags = ["%{user_compile_flags}"], iterate_over = "user_compile_flags", expand_if_available = "user_compile_flags", ), ], ), ], ) elif (ctx.attr.cpu == "x64_windows_msvc"): user_compile_flags_feature = feature( name = "user_compile_flags", flag_sets = [ flag_set( actions = [ _ASSEMBLE_ACTION_NAME, _PREPROCESS_ASSEMBLE_ACTION_NAME, _C_COMPILE_ACTION_NAME, _CPP_COMPILE_ACTION_NAME, _CPP_HEADER_PARSING_ACTION_NAME, _CPP_MODULE_COMPILE_ACTION_NAME, _CPP_MODULE_CODEGEN_ACTION_NAME, ], flag_groups = [ flag_group( flags = ["%{user_compile_flags}"], iterate_over = "user_compile_flags", expand_if_available = "user_compile_flags", ), ], ), ], ) sysroot_feature = None if (ctx.attr.cpu == "darwin" or ctx.attr.cpu == "freebsd" or ctx.attr.cpu == "local"): sysroot_feature = feature( name = "sysroot", enabled = True, flag_sets = [ flag_set( actions = [ _PREPROCESS_ASSEMBLE_ACTION_NAME, _LINKSTAMP_COMPILE_ACTION_NAME, _C_COMPILE_ACTION_NAME, _CPP_COMPILE_ACTION_NAME, _CPP_HEADER_PARSING_ACTION_NAME, _CPP_MODULE_COMPILE_ACTION_NAME, _CPP_MODULE_CODEGEN_ACTION_NAME, _LTO_BACKEND_ACTION_NAME, _CLIF_MATCH_ACTION_NAME, _CPP_LINK_EXECUTABLE_ACTION_NAME, _CPP_LINK_DYNAMIC_LIBRARY_ACTION_NAME, _CPP_LINK_NODEPS_DYNAMIC_LIBRARY_ACTION_NAME, ], flag_groups = [ flag_group( flags = ["--sysroot=%{sysroot}"], expand_if_available = "sysroot", ), ], ), ], ) elif (ctx.attr.cpu == "x64_windows_msvc"): sysroot_feature = feature( name = "sysroot", flag_sets = [ flag_set( actions = [ _ASSEMBLE_ACTION_NAME, _PREPROCESS_ASSEMBLE_ACTION_NAME, _C_COMPILE_ACTION_NAME, _CPP_COMPILE_ACTION_NAME, _CPP_HEADER_PARSING_ACTION_NAME, _CPP_MODULE_COMPILE_ACTION_NAME, _CPP_MODULE_CODEGEN_ACTION_NAME, _CPP_LINK_EXECUTABLE_ACTION_NAME, _CPP_LINK_DYNAMIC_LIBRARY_ACTION_NAME, _CPP_LINK_NODEPS_DYNAMIC_LIBRARY_ACTION_NAME, ], flag_groups = [ flag_group( flags = ["--sysroot=%{sysroot}"], iterate_over = "sysroot", expand_if_available = "sysroot", ), ], ), ], ) include_paths_feature = feature( name = "include_paths", enabled = True, flag_sets = [ flag_set( actions = [ _PREPROCESS_ASSEMBLE_ACTION_NAME, _C_COMPILE_ACTION_NAME, _CPP_COMPILE_ACTION_NAME, _CPP_HEADER_PARSING_ACTION_NAME, _CPP_MODULE_COMPILE_ACTION_NAME, ], flag_groups = [ flag_group( flags = ["/I%{quote_include_paths}"], iterate_over = "quote_include_paths", ), flag_group( flags = ["/I%{include_paths}"], iterate_over = "include_paths", ), flag_group( flags = ["/I%{system_include_paths}"], iterate_over = "system_include_paths", ), ], ), ], ) dependency_file_feature = feature( name = "dependency_file", enabled = True, flag_sets = [ flag_set( actions = [ _ASSEMBLE_ACTION_NAME, _PREPROCESS_ASSEMBLE_ACTION_NAME, _C_COMPILE_ACTION_NAME, _CPP_COMPILE_ACTION_NAME, _CPP_MODULE_COMPILE_ACTION_NAME, _CPP_HEADER_PARSING_ACTION_NAME, ], flag_groups = [ flag_group( flags = ["/DEPENDENCY_FILE", "%{dependency_file}"], expand_if_available = "dependency_file", ), ], ), ], ) compiler_input_flags_feature = feature( name = "compiler_input_flags", flag_sets = [ flag_set( actions = [ _ASSEMBLE_ACTION_NAME, _PREPROCESS_ASSEMBLE_ACTION_NAME, _C_COMPILE_ACTION_NAME, _CPP_COMPILE_ACTION_NAME, _CPP_HEADER_PARSING_ACTION_NAME, _CPP_MODULE_COMPILE_ACTION_NAME, _CPP_MODULE_CODEGEN_ACTION_NAME, ], flag_groups = [ flag_group( flags = ["/c", "%{source_file}"], expand_if_available = "source_file", ), ], ), ], ) fastbuild_feature = feature(name = "fastbuild") features = None if (ctx.attr.cpu == "x64_windows" and ctx.attr.compiler == "windows_msys64"): features = [ default_compile_flags_feature, default_link_flags_feature, supports_dynamic_linker_feature, objcopy_embed_flags_feature, ] elif (ctx.attr.cpu == "darwin"): features = [ default_compile_flags_feature, default_link_flags_feature, supports_dynamic_linker_feature, supports_pic_feature, objcopy_embed_flags_feature, dbg_feature, opt_feature, user_compile_flags_feature, sysroot_feature, unfiltered_compile_flags_feature, ] elif (ctx.attr.cpu == "freebsd" or ctx.attr.cpu == "local"): features = [ default_compile_flags_feature, default_link_flags_feature, supports_dynamic_linker_feature, supports_pic_feature, objcopy_embed_flags_feature, opt_feature, dbg_feature, user_compile_flags_feature, sysroot_feature, unfiltered_compile_flags_feature, ] elif (ctx.attr.cpu == "x64_windows" and ctx.attr.compiler == "windows_clang" or ctx.attr.cpu == "x64_windows" and ctx.attr.compiler == "windows_mingw" or ctx.attr.cpu == "x64_windows" and ctx.attr.compiler == "windows_msys64_mingw64"): features = [ default_compile_flags_feature, supports_dynamic_linker_feature, objcopy_embed_flags_feature, ] elif (ctx.attr.cpu == "x64_windows_msvc"): features = [ default_link_flags_feature, random_seed_feature, default_compile_flags_feature, include_paths_feature, dependency_file_feature, user_compile_flags_feature, sysroot_feature, unfiltered_compile_flags_feature, compiler_output_flags_feature, compiler_input_flags_feature, dbg_feature, fastbuild_feature, opt_feature, ] elif (ctx.attr.cpu == "armeabi-v7a"): features = [supports_dynamic_linker_feature, supports_pic_feature] if (ctx.attr.cpu == "armeabi-v7a"): cxx_builtin_include_directories = [] elif (ctx.attr.cpu == "darwin"): cxx_builtin_include_directories = ["/"] elif (ctx.attr.cpu == "freebsd"): cxx_builtin_include_directories = ["/usr/lib/clang", "/usr/local/include", "/usr/include"] elif (ctx.attr.cpu == "local" or ctx.attr.cpu == "x64_windows" and ctx.attr.compiler == "windows_clang"): cxx_builtin_include_directories = ["/usr/lib/gcc/", "/usr/local/include", "/usr/include"] elif (ctx.attr.cpu == "x64_windows_msvc"): cxx_builtin_include_directories = [ "C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/INCLUDE", "C:/Program Files (x86)/Windows Kits/10/include/", "C:/Program Files (x86)/Windows Kits/8.1/include/", "C:/Program Files (x86)/GnuWin32/include/", "C:/python_27_amd64/files/include", ] elif (ctx.attr.cpu == "x64_windows" and ctx.attr.compiler == "windows_mingw"): cxx_builtin_include_directories = ["C:/mingw/include", "C:/mingw/lib/gcc"] elif (ctx.attr.cpu == "x64_windows" and ctx.attr.compiler == "windows_msys64_mingw64"): cxx_builtin_include_directories = ["C:/tools/msys64/mingw64/x86_64-w64-mingw32/include"] elif (ctx.attr.cpu == "x64_windows" and ctx.attr.compiler == "windows_msys64"): cxx_builtin_include_directories = ["C:/tools/msys64/", "/usr/"] else: fail("Unreachable") artifact_name_patterns = [] make_variables = [] if (ctx.attr.cpu == "x64_windows" and ctx.attr.compiler == "windows_msys64_mingw64"): tool_paths = [ tool_path( name = "ar", path = "C:/tools/msys64/mingw64/bin/ar", ), tool_path( name = "compat-ld", path = "C:/tools/msys64/mingw64/bin/ld", ), tool_path( name = "cpp", path = "C:/tools/msys64/mingw64/bin/cpp", ), tool_path( name = "dwp", path = "C:/tools/msys64/mingw64/bin/dwp", ), tool_path( name = "gcc", path = "C:/tools/msys64/mingw64/bin/gcc", ), tool_path( name = "gcov", path = "C:/tools/msys64/mingw64/bin/gcov", ), tool_path( name = "ld", path = "C:/tools/msys64/mingw64/bin/ld", ), tool_path( name = "nm", path = "C:/tools/msys64/mingw64/bin/nm", ), tool_path( name = "objcopy", path = "C:/tools/msys64/mingw64/bin/objcopy", ), tool_path( name = "objdump", path = "C:/tools/msys64/mingw64/bin/objdump", ), tool_path( name = "strip", path = "C:/tools/msys64/mingw64/bin/strip", ), ] elif (ctx.attr.cpu == "armeabi-v7a"): tool_paths = [ tool_path(name = "ar", path = "/bin/false"), tool_path(name = "compat-ld", path = "/bin/false"), tool_path(name = "cpp", path = "/bin/false"), tool_path(name = "dwp", path = "/bin/false"), tool_path(name = "gcc", path = "/bin/false"), tool_path(name = "gcov", path = "/bin/false"), tool_path(name = "ld", path = "/bin/false"), tool_path(name = "nm", path = "/bin/false"), tool_path(name = "objcopy", path = "/bin/false"), tool_path(name = "objdump", path = "/bin/false"), tool_path(name = "strip", path = "/bin/false"), ] elif (ctx.attr.cpu == "freebsd"): tool_paths = [ tool_path(name = "ar", path = "/usr/bin/ar"), tool_path(name = "compat-ld", path = "/usr/bin/ld"), tool_path(name = "cpp", path = "/usr/bin/cpp"), tool_path(name = "dwp", path = "/usr/bin/dwp"), tool_path(name = "gcc", path = "/usr/bin/clang"), tool_path(name = "gcov", path = "/usr/bin/gcov"), tool_path(name = "ld", path = "/usr/bin/ld"), tool_path(name = "nm", path = "/usr/bin/nm"), tool_path(name = "objcopy", path = "/usr/bin/objcopy"), tool_path(name = "objdump", path = "/usr/bin/objdump"), tool_path(name = "strip", path = "/usr/bin/strip"), ] elif (ctx.attr.cpu == "local"): tool_paths = [ tool_path(name = "ar", path = "/usr/bin/ar"), tool_path(name = "compat-ld", path = "/usr/bin/ld"), tool_path(name = "cpp", path = "/usr/bin/cpp"), tool_path(name = "dwp", path = "/usr/bin/dwp"), tool_path(name = "gcc", path = "/usr/bin/gcc"), tool_path(name = "gcov", path = "/usr/bin/gcov"), tool_path(name = "ld", path = "/usr/bin/ld"), tool_path(name = "nm", path = "/usr/bin/nm"), tool_path(name = "objcopy", path = "/usr/bin/objcopy"), tool_path(name = "objdump", path = "/usr/bin/objdump"), tool_path(name = "strip", path = "/usr/bin/strip"), ] elif (ctx.attr.cpu == "darwin"): tool_paths = [ tool_path(name = "ar", path = "/usr/bin/libtool"), tool_path(name = "compat-ld", path = "/usr/bin/ld"), tool_path(name = "cpp", path = "/usr/bin/cpp"), tool_path(name = "dwp", path = "/usr/bin/dwp"), tool_path(name = "gcc", path = "osx_cc_wrapper.sh"), tool_path(name = "gcov", path = "/usr/bin/gcov"), tool_path(name = "ld", path = "/usr/bin/ld"), tool_path(name = "nm", path = "/usr/bin/nm"), tool_path(name = "objcopy", path = "/usr/bin/objcopy"), tool_path(name = "objdump", path = "/usr/bin/objdump"), tool_path(name = "strip", path = "/usr/bin/strip"), ] elif (ctx.attr.cpu == "x64_windows" and ctx.attr.compiler == "windows_clang"): tool_paths = [ tool_path(name = "ar", path = "C:/mingw/bin/ar"), tool_path( name = "compat-ld", path = "C:/Program Files (x86)/LLVM/bin/ld", ), tool_path( name = "cpp", path = "C:/Program Files (x86)/LLVM/bin/cpp", ), tool_path( name = "dwp", path = "C:/Program Files (x86)/LLVM/bin/dwp", ), tool_path( name = "gcc", path = "C:/Program Files (x86)/LLVM/bin/clang", ), tool_path( name = "gcov", path = "C:/Program Files (x86)/LLVM/bin/gcov", ), tool_path( name = "ld", path = "C:/Program Files (x86)/LLVM/bin/ld", ), tool_path( name = "nm", path = "C:/Program Files (x86)/LLVM/bin/nm", ), tool_path( name = "objcopy", path = "C:/Program Files (x86)/LLVM/bin/objcopy", ), tool_path( name = "objdump", path = "C:/Program Files (x86)/LLVM/bin/objdump", ), tool_path( name = "strip", path = "C:/Program Files (x86)/LLVM/bin/strip", ), ] elif (ctx.attr.cpu == "x64_windows" and ctx.attr.compiler == "windows_mingw"): tool_paths = [ tool_path(name = "ar", path = "C:/mingw/bin/ar"), tool_path(name = "compat-ld", path = "C:/mingw/bin/ld"), tool_path(name = "cpp", path = "C:/mingw/bin/cpp"), tool_path(name = "dwp", path = "C:/mingw/bin/dwp"), tool_path(name = "gcc", path = "C:/mingw/bin/gcc"), tool_path(name = "gcov", path = "C:/mingw/bin/gcov"), tool_path(name = "ld", path = "C:/mingw/bin/ld"), tool_path(name = "nm", path = "C:/mingw/bin/nm"), tool_path(name = "objcopy", path = "C:/mingw/bin/objcopy"), tool_path(name = "objdump", path = "C:/mingw/bin/objdump"), tool_path(name = "strip", path = "C:/mingw/bin/strip"), ] elif (ctx.attr.cpu == "x64_windows" and ctx.attr.compiler == "windows_msys64"): tool_paths = [ tool_path(name = "ar", path = "C:/tools/msys64/usr/bin/ar"), tool_path( name = "compat-ld", path = "C:/tools/msys64/usr/bin/ld", ), tool_path( name = "cpp", path = "C:/tools/msys64/usr/bin/cpp", ), tool_path( name = "dwp", path = "C:/tools/msys64/usr/bin/dwp", ), tool_path( name = "gcc", path = "C:/tools/msys64/usr/bin/gcc", ), tool_path( name = "gcov", path = "C:/tools/msys64/usr/bin/gcov", ), tool_path(name = "ld", path = "C:/tools/msys64/usr/bin/ld"), tool_path(name = "nm", path = "C:/tools/msys64/usr/bin/nm"), tool_path( name = "objcopy", path = "C:/tools/msys64/usr/bin/objcopy", ), tool_path( name = "objdump", path = "C:/tools/msys64/usr/bin/objdump", ), tool_path( name = "strip", path = "C:/tools/msys64/usr/bin/strip", ), ] elif (ctx.attr.cpu == "x64_windows_msvc"): tool_paths = [ tool_path(name = "ar", path = "wrapper/bin/msvc_link.bat"), tool_path(name = "cpp", path = "wrapper/bin/msvc_cl.bat"), tool_path(name = "gcc", path = "wrapper/bin/msvc_cl.bat"), tool_path(name = "gcov", path = "wrapper/bin/msvc_nop.bat"), tool_path(name = "ld", path = "wrapper/bin/msvc_link.bat"), tool_path(name = "nm", path = "wrapper/bin/msvc_nop.bat"), tool_path( name = "objcopy", path = "wrapper/bin/msvc_nop.bat", ), tool_path( name = "objdump", path = "wrapper/bin/msvc_nop.bat", ), tool_path( name = "strip", path = "wrapper/bin/msvc_nop.bat", ), ] else: fail("Unreachable") out = ctx.actions.declare_file(ctx.label.name) ctx.actions.write(out, "Fake executable") return [ cc_common.create_cc_toolchain_config_info( ctx = ctx, features = features, action_configs = action_configs, artifact_name_patterns = artifact_name_patterns, cxx_builtin_include_directories = cxx_builtin_include_directories, toolchain_identifier = toolchain_identifier, host_system_name = host_system_name, target_system_name = target_system_name, target_cpu = target_cpu, target_libc = target_libc, compiler = compiler, abi_version = abi_version, abi_libc_version = abi_libc_version, tool_paths = tool_paths, make_variables = make_variables, builtin_sysroot = builtin_sysroot, cc_target_os = cc_target_os, ), DefaultInfo( executable = out, ), ] cc_toolchain_config = rule( implementation = _impl, attrs = { "compiler": attr.string(), "cpu": attr.string(mandatory = True), "disable_static_cc_toolchains": attr.bool(), }, provides = [CcToolchainConfigInfo], executable = True, ) rules_cc-0.0.11/cc/private/toolchain/clang_deps_scanner_wrapper.sh.tpl000066400000000000000000000003141470072561500261160ustar00rootroot00000000000000#!/usr/bin/env bash # # Ship the environment to the C++ action # set -eu # Set-up the environment %{env} # Call the C++ compiler %{deps_scanner} -format=p1689 -- %{cc} "$@" >"$DEPS_SCANNER_OUTPUT_FILE" rules_cc-0.0.11/cc/private/toolchain/clang_installation_error.bat.tpl000066400000000000000000000016231470072561500257640ustar00rootroot00000000000000:: Copyright 2019 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. @echo OFF echo. 1>&2 echo The target you are compiling requires the Clang compiler. 1>&2 echo Bazel couldn't find a valid Clang installation on your machine. 1>&2 %{clang_error_message} echo Please check your installation following https://bazel.build/docs/windows#using 1>&2 echo. 1>&2 exit /b 1 rules_cc-0.0.11/cc/private/toolchain/empty.cc000066400000000000000000000011661470072561500210670ustar00rootroot00000000000000// Copyright 2017 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. int main() {} rules_cc-0.0.11/cc/private/toolchain/empty_cc_toolchain_config.bzl000066400000000000000000000025421470072561500253220ustar00rootroot00000000000000# Copyright 2019 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. """A fake C++ toolchain configuration rule""" def _impl(ctx): out = ctx.actions.declare_file(ctx.label.name) ctx.actions.write(out, "Fake executable") return [ cc_common.create_cc_toolchain_config_info( ctx = ctx, toolchain_identifier = "local_linux", host_system_name = "local", target_system_name = "local", target_cpu = "local", target_libc = "local", compiler = "compiler", abi_version = "local", abi_libc_version = "local", ), DefaultInfo( executable = out, ), ] cc_toolchain_config = rule( implementation = _impl, attrs = {}, provides = [CcToolchainConfigInfo], executable = True, ) rules_cc-0.0.11/cc/private/toolchain/gcc_deps_scanner_wrapper.sh.tpl000066400000000000000000000003451470072561500255720ustar00rootroot00000000000000#!/bin/bash # # Ship the environment to the C++ action # set -eu # Set-up the environment %{env} # Call the C++ compiler %{cc} -E -x c++ -fmodules-ts -fdeps-file=out.tmp -fdeps-format=p1689r5 "$@" >"$DEPS_SCANNER_OUTPUT_FILE" rules_cc-0.0.11/cc/private/toolchain/generate_system_module_map.sh000077500000000000000000000021071470072561500253550ustar00rootroot00000000000000#!/bin/bash # Copyright 2020 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 -eu echo 'module "crosstool" [system] {' if [[ "$OSTYPE" == darwin* ]]; then for dir in $@; do find "$dir" -type f \( -name "*.h" -o -name "*.def" -o -path "*/c++/*" \) \ | LANG=C sort -u | while read -r header; do echo " textual header \"${header}\"" done done else for dir in $@; do find -L "${dir}" -type f 2>/dev/null | LANG=C sort -u | while read -r header; do echo " textual header \"${header}\"" done done fi echo "}" rules_cc-0.0.11/cc/private/toolchain/grep-includes.sh000077500000000000000000000013501470072561500225150ustar00rootroot00000000000000#!/bin/bash # # Copyright 2018 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. # # TODO(bazel-team): Support include scanning and grep-includes in Bazel echo "grep-includes is not supported by Bazel" exit 1 rules_cc-0.0.11/cc/private/toolchain/lib_cc_configure.bzl000066400000000000000000000263271470072561500234150ustar00rootroot00000000000000# pylint: disable=g-bad-file-header # 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. """Base library for configuring the C++ toolchain.""" def resolve_labels(repository_ctx, labels): """Resolves a collection of labels to their paths. Label resolution can cause the evaluation of Starlark functions to restart. For functions with side-effects (like the auto-configuration functions, which inspect the system and touch the file system), such restarts are costly. We cannot avoid the restarts, but we can minimize their penalty by resolving all labels upfront. Among other things, doing less work on restarts can cut analysis times by several seconds and may also prevent tickling kernel conditions that cause build failures. See https://github.com/bazelbuild/bazel/issues/5196 for more details. Args: repository_ctx: The context with which to resolve the labels. labels: Labels to be resolved expressed as a list of strings. Returns: A dictionary with the labels as keys and their paths as values. """ return dict([(label, repository_ctx.path(Label(label))) for label in labels]) def escape_string(arg): """Escape percent sign (%) in the string so it can appear in the Crosstool.""" if arg != None: return str(arg).replace("%", "%%") else: return None def split_escaped(string, delimiter): """Split string on the delimiter unless %-escaped. Examples: Basic usage: split_escaped("a:b:c", ":") -> [ "a", "b", "c" ] Delimiter that is not supposed to be splitten on has to be %-escaped: split_escaped("a%:b", ":") -> [ "a:b" ] Literal % can be represented by escaping it as %%: split_escaped("a%%b", ":") -> [ "a%b" ] Consecutive delimiters produce empty strings: split_escaped("a::b", ":") -> [ "a", "", "", "b" ] Args: string: The string to be split. delimiter: Non-empty string not containing %-sign to be used as a delimiter. Returns: A list of substrings. """ if delimiter == "": fail("Delimiter cannot be empty") if delimiter.find("%") != -1: fail("Delimiter cannot contain %-sign") i = 0 result = [] accumulator = [] length = len(string) delimiter_length = len(delimiter) if not string: return [] # Iterate over the length of string since Starlark doesn't have while loops for _ in range(length): if i >= length: break if i + 2 <= length and string[i:i + 2] == "%%": accumulator.append("%") i += 2 elif (i + 1 + delimiter_length <= length and string[i:i + 1 + delimiter_length] == "%" + delimiter): accumulator.append(delimiter) i += 1 + delimiter_length elif i + delimiter_length <= length and string[i:i + delimiter_length] == delimiter: result.append("".join(accumulator)) accumulator = [] i += delimiter_length else: accumulator.append(string[i]) i += 1 # Append the last group still in accumulator result.append("".join(accumulator)) return result def auto_configure_fail(msg): """Output failure message when auto configuration fails.""" red = "\033[0;31m" no_color = "\033[0m" fail("\n%sAuto-Configuration Error:%s %s\n" % (red, no_color, msg)) def auto_configure_warning(msg): """Output warning message during auto configuration.""" yellow = "\033[1;33m" no_color = "\033[0m" # buildifier: disable=print print("\n%sAuto-Configuration Warning:%s %s\n" % (yellow, no_color, msg)) def get_env_var(repository_ctx, name, default = None, enable_warning = True): """Find an environment variable in system path. Doesn't %-escape the value! Args: repository_ctx: The repository context. name: Name of the environment variable. default: Default value to be used when such environment variable is not present. enable_warning: Show warning if the variable is not present. Returns: value of the environment variable or default. """ if name in repository_ctx.os.environ: return repository_ctx.os.environ[name] if default != None: if enable_warning: auto_configure_warning("'%s' environment variable is not set, using '%s' as default" % (name, default)) return default auto_configure_fail("'%s' environment variable is not set" % name) return None def which(repository_ctx, cmd, default = None): """A wrapper around repository_ctx.which() to provide a fallback value. Doesn't %-escape the value! Args: repository_ctx: The repository context. cmd: name of the executable to resolve. default: Value to be returned when such executable couldn't be found. Returns: absolute path to the cmd or default when not found. """ result = repository_ctx.which(cmd) return default if result == None else str(result) def which_cmd(repository_ctx, cmd, default = None): """Find cmd in PATH using repository_ctx.which() and fail if cannot find it. Doesn't %-escape the cmd! Args: repository_ctx: The repository context. cmd: name of the executable to resolve. default: Value to be returned when such executable couldn't be found. Returns: absolute path to the cmd or default when not found. """ result = repository_ctx.which(cmd) if result != None: return str(result) path = get_env_var(repository_ctx, "PATH") if default != None: auto_configure_warning("Cannot find %s in PATH, using '%s' as default.\nPATH=%s" % (cmd, default, path)) return default auto_configure_fail("Cannot find %s in PATH, please make sure %s is installed and add its directory in PATH.\nPATH=%s" % (cmd, cmd, path)) return str(result) def execute( repository_ctx, command, environment = None, expect_failure = False, expect_empty_output = False): """Execute a command, return stdout if succeed and throw an error if it fails. Doesn't %-escape the result! Args: repository_ctx: The repository context. command: command to execute. environment: dictionary with environment variables to set for the command. expect_failure: True if the command is expected to fail. expect_empty_output: True if the command is expected to produce no output. Returns: stdout of the executed command. """ if environment: result = repository_ctx.execute(command, environment = environment) else: result = repository_ctx.execute(command) if expect_failure != (result.return_code != 0): if expect_failure: auto_configure_fail( "expected failure, command %s, stderr: (%s)" % ( command, result.stderr, ), ) else: auto_configure_fail( "non-zero exit code: %d, command %s, stderr: (%s)" % ( result.return_code, command, result.stderr, ), ) stripped_stdout = result.stdout.strip() if expect_empty_output != (not stripped_stdout): if expect_empty_output: auto_configure_fail( "non-empty output from command %s, stdout: (%s), stderr: (%s)" % (command, result.stdout, result.stderr), ) else: auto_configure_fail( "empty output from command %s, stderr: (%s)" % (command, result.stderr), ) return stripped_stdout def get_cpu_value(repository_ctx): """Compute the cpu_value based on the OS name. Doesn't %-escape the result! Args: repository_ctx: The repository context. Returns: One of (darwin, freebsd, x64_windows, ppc, s390x, arm, aarch64, k8, piii) """ os_name = repository_ctx.os.name arch = repository_ctx.os.arch if os_name.startswith("mac os"): # Check if we are on x86_64 or arm64 and return the corresponding cpu value. return "darwin_" + ("arm64" if arch == "aarch64" else "x86_64") if os_name.find("freebsd") != -1: return "freebsd" if os_name.find("openbsd") != -1: return "openbsd" if os_name.find("windows") != -1: if arch == "aarch64": return "arm64_windows" else: return "x64_windows" if arch in ["power", "ppc64le", "ppc", "ppc64"]: return "ppc" if arch in ["s390x"]: return "s390x" if arch in ["mips64"]: return "mips64" if arch in ["riscv64"]: return "riscv64" if arch in ["arm", "armv7l"]: return "arm" if arch in ["aarch64"]: return "aarch64" return "k8" if arch in ["amd64", "x86_64", "x64"] else "piii" def is_cc_configure_debug(repository_ctx): """Returns True if CC_CONFIGURE_DEBUG is set to 1.""" env = repository_ctx.os.environ return "CC_CONFIGURE_DEBUG" in env and env["CC_CONFIGURE_DEBUG"] == "1" def build_flags(flags): """Convert `flags` to a string of flag fields.""" return "\n".join([" flag: '" + flag + "'" for flag in flags]) def get_starlark_list(values): """Convert a list of string into a string that can be passed to a rule attribute.""" if not values: return "" return "\"" + "\",\n \"".join(values) + "\"" def auto_configure_warning_maybe(repository_ctx, msg): """Output warning message when CC_CONFIGURE_DEBUG is enabled.""" if is_cc_configure_debug(repository_ctx): auto_configure_warning(msg) def write_builtin_include_directory_paths(repository_ctx, cc, directories, file_suffix = ""): """Generate output file named 'builtin_include_directory_paths' in the root of the repository.""" if get_env_var(repository_ctx, "BAZEL_IGNORE_SYSTEM_HEADERS_VERSIONS", "0", False) == "1": repository_ctx.file( "builtin_include_directory_paths" + file_suffix, """This file is generated by cc_configure and normally contains builtin include directories that C++ compiler reported. But because BAZEL_IGNORE_SYSTEM_HEADERS_VERSIONS was set to 1, header include directory paths are intentionally not put there. """, ) else: repository_ctx.file( "builtin_include_directory_paths" + file_suffix, """This file is generated by cc_configure and contains builtin include directories that %s 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. %s """ % (cc, "\n".join(directories)), ) rules_cc-0.0.11/cc/private/toolchain/link_dynamic_library.sh000077500000000000000000000100251470072561500241400ustar00rootroot00000000000000#!/bin/bash # # 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 script handles interface library generation for dynamic library # link action. # # Bazel can be configured to generate external interface library script # to generate interface libraries in CppLinkAction for dynamic libraries. # This is not needed on Windows (as the "interface" libraries are # generated by default). This script therefore handles the cases when # external script is provided, or when no script should be used. set -eu E_LINKER_COMMAND_NOT_FOUND=12 E_INTERFACE_BUILDER_NOT_FOUND=13 SUFFIX=".rewritten" other_args="" if [[ "$#" -eq 1 ]]; then if [[ "$1" != @* ]]; then echo "Parameter file must start with @" 1>&2; exit "$E_LINKER_COMMAND_NOT_FOUND" fi filename=$(echo "$1" | cut -c2-) first_five_lines=$(head -n 5 $filename) # Should generate interface library switch (); if the value is "no", # following 3 args are ignored (but must be present) GENERATE_INTERFACE_LIBRARY=$(echo "$first_five_lines" | head -n1 | tail -n1) # Tool which can generate interface library from dynamic library file INTERFACE_LIBRARY_BUILDER=$(echo "$first_five_lines" | head -n2 | tail -n1) # Dynamic library from which we want to generate interface library DYNAMIC_LIBRARY=$(echo "$first_five_lines" | head -n3 | tail -n1) # Resulting interface library INTERFACE_LIBRARY=$(echo "$first_five_lines" | head -n4 | tail -n1) # The command used to generate the dynamic library LINKER_COMMAND=$(echo "$first_five_lines" | head -n5 | tail -n1) rest_of_lines=$(tail -n +6 $filename) new_param_file="${filename}${SUFFIX}" echo "$rest_of_lines" > $new_param_file other_args="@$new_param_file" if [[ ! -e "$LINKER_COMMAND" ]]; then echo "Linker command ($LINKER_COMMAND) not found." 1>&2; exit "$E_LINKER_COMMAND_NOT_FOUND" fi if [[ "no" == "$GENERATE_INTERFACE_LIBRARY" ]]; then INTERFACE_GENERATION=: else if [[ ! -e "$INTERFACE_LIBRARY_BUILDER" ]]; then echo "Interface library builder ($INTERFACE_LIBRARY_BUILDER) not found." 1>&2; exit "$E_INTERFACE_BUILDER_NOT_FOUND" fi INTERFACE_GENERATION="${INTERFACE_LIBRARY_BUILDER} ${DYNAMIC_LIBRARY} ${INTERFACE_LIBRARY}" fi ${LINKER_COMMAND} "$other_args" && ${INTERFACE_GENERATION} else # TODO(b/113358321): Remove this branch once projects are migrated to not # splitting the linking command line. # Should generate interface library switch (); if the value is "no", # following 3 args are ignored (but must be present) GENERATE_INTERFACE_LIBRARY="$1" # Tool which can generate interface library from dynamic library file INTERFACE_LIBRARY_BUILDER="$2" # Dynamic library from which we want to generate interface library DYNAMIC_LIBRARY="$3" # Resulting interface library INTERFACE_LIBRARY="$4" # The command used to generate the dynamic library LINKER_COMMAND="$5" shift 5 if [[ ! -e "$LINKER_COMMAND" ]]; then echo "Linker command ($LINKER_COMMAND) not found." 1>&2; exit "$E_LINKER_COMMAND_NOT_FOUND" fi if [[ "no" == "$GENERATE_INTERFACE_LIBRARY" ]]; then INTERFACE_GENERATION=: else if [[ ! -e "$INTERFACE_LIBRARY_BUILDER" ]]; then echo "Interface library builder ($INTERFACE_LIBRARY_BUILDER) not found." 1>&2; exit "$E_INTERFACE_BUILDER_NOT_FOUND" fi INTERFACE_GENERATION="${INTERFACE_LIBRARY_BUILDER} ${DYNAMIC_LIBRARY} ${INTERFACE_LIBRARY}" fi ${LINKER_COMMAND} "$@" && ${INTERFACE_GENERATION} fi rules_cc-0.0.11/cc/private/toolchain/linux_cc_wrapper.sh.tpl000066400000000000000000000024441470072561500241200ustar00rootroot00000000000000#!/bin/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 %{env} # Call the C++ compiler %{cc} "$@" # Generate an empty file if header processing succeeded. if [[ "${OUTPUT}" == *.h.processed ]]; then echo -n > "${OUTPUT}" fi rules_cc-0.0.11/cc/private/toolchain/msvc_deps_scanner_wrapper.bat.tpl000066400000000000000000000012601470072561500261370ustar00rootroot00000000000000:: Copyright 2024 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. @echo OFF "%{cc}" /scanDependencies- /TP %* >%DEPS_SCANNER_OUTPUT_FILE% rules_cc-0.0.11/cc/private/toolchain/msys_gcc_installation_error.bat000066400000000000000000000015561470072561500257160ustar00rootroot00000000000000:: Copyright 2018 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. @echo OFF echo. 1>&2 echo The target you are compiling requires MSYS gcc / MINGW gcc. 1>&2 echo Bazel couldn't find gcc installation on your machine. 1>&2 echo Please install MSYS gcc / MINGW gcc and set BAZEL_SH environment variable 1>&2 echo. 1>&2 exit /b 1 rules_cc-0.0.11/cc/private/toolchain/osx_cc_wrapper.sh.tpl000066400000000000000000000100251470072561500235640ustar00rootroot00000000000000#!/bin/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. # # OS X relpath is not really working. This is a wrapper script around gcc # to simulate relpath behavior. # # This wrapper uses install_name_tool to replace all paths in the binary # (bazel-out/.../path/to/original/library.so) by the paths relative to # the binary. It parses the command line to behave as rpath is supposed # to work. # # See https://blogs.oracle.com/dipol/entry/dynamic_libraries_rpath_and_mac # on how to set those paths for Mach-O binaries. # set -eu LIBS= LIB_PATHS= LIB_DIRS= RPATHS= OUTPUT= function parse_option() { local -r opt="$1" if [[ "${OUTPUT}" = "1" ]]; then OUTPUT=$opt elif [[ "$opt" =~ ^-l(.*)$ ]]; then LIBS="${BASH_REMATCH[1]} $LIBS" elif [[ "$opt" =~ ^(.*)\.so$ ]]; then LIB_PATHS="${opt} $LIB_PATHS" elif [[ "$opt" =~ ^(.*)\.dylib$ ]]; then LIB_PATHS="${opt} $LIB_PATHS" elif [[ "$opt" =~ ^-L(.*)$ ]]; then LIB_DIRS="${BASH_REMATCH[1]} $LIB_DIRS" elif [[ "$opt" =~ ^\@loader_path/(.*)$ ]]; then RPATHS="${BASH_REMATCH[1]} ${RPATHS}" 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 %{env} # Call the C++ compiler %{cc} "$@" # Generate an empty file if header processing succeeded. if [[ "${OUTPUT}" == *.h.processed ]]; then echo -n > "${OUTPUT}" fi function get_library_path() { for libdir in ${LIB_DIRS}; do if [ -f ${libdir}/lib$1.so ]; then echo "${libdir}/lib$1.so" elif [ -f ${libdir}/lib$1.dylib ]; then echo "${libdir}/lib$1.dylib" fi done } # A convenient method to return the actual path even for non symlinks # and multi-level symlinks. function get_realpath() { local previous="$1" local next=$(readlink "${previous}") while [ -n "${next}" ]; do previous="${next}" next=$(readlink "${previous}") done echo "${previous}" } # Get the path of a lib inside a tool function get_otool_path() { # the lib path is the path of the original lib relative to the workspace get_realpath $1 | sed 's|^.*/bazel-out/|bazel-out/|' } function call_install_name() { /usr/bin/xcrun install_name_tool -change $(get_otool_path "$1") \ "@loader_path/$2/$3" "${OUTPUT}" } # Do replacements in the output for rpath in ${RPATHS}; do for lib in ${LIBS}; do unset libname if [ -f "$(dirname ${OUTPUT})/${rpath}/lib${lib}.so" ]; then libname="lib${lib}.so" elif [ -f "$(dirname ${OUTPUT})/${rpath}/lib${lib}.dylib" ]; then libname="lib${lib}.dylib" fi # ${libname-} --> return $libname if defined, or undefined otherwise. This is to make # this set -e friendly if [[ -n "${libname-}" ]]; then libpath=$(get_library_path ${lib}) if [ -n "${libpath}" ]; then call_install_name "${libpath}" "${rpath}" "${libname}" fi fi done for libpath in ${LIB_PATHS}; do if [ -f "$libpath" ]; then libname=$(basename "$libpath") if [ -f "$(dirname ${OUTPUT})/${rpath}/${libname}" ]; then call_install_name "${libpath}" "${rpath}" "${libname}" fi fi done done rules_cc-0.0.11/cc/private/toolchain/unix_cc_configure.bzl000066400000000000000000000703141470072561500236250ustar00rootroot00000000000000# pylint: disable=g-bad-file-header # 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. """Configuring the C++ toolchain on Unix platforms.""" load( ":lib_cc_configure.bzl", "auto_configure_fail", "auto_configure_warning", "auto_configure_warning_maybe", "escape_string", "execute", "get_env_var", "get_starlark_list", "resolve_labels", "split_escaped", "which", "write_builtin_include_directory_paths", ) def _uniq(iterable): """Remove duplicates from a list.""" unique_elements = {element: None for element in iterable} return unique_elements.keys() def _generate_system_module_map(repository_ctx, dirs, script_path): return execute(repository_ctx, [script_path] + dirs) def _prepare_include_path(repo_ctx, path): """Resolve include path before outputting it into the crosstool. Args: repo_ctx: repository_ctx object. path: an include path to be resolved. Returns: Resolved include path. Resulting path is absolute if it is outside the repository and relative otherwise. """ repo_root = str(repo_ctx.path(".")) # We're on UNIX, so the path delimiter is '/'. repo_root += "/" path = str(repo_ctx.path(path)) if path.startswith(repo_root): return path[len(repo_root):] return path def _find_tool(repository_ctx, tool, overridden_tools): """Find a tool for repository, taking overridden tools into account.""" if tool in overridden_tools: return overridden_tools[tool] return which(repository_ctx, tool, "/usr/bin/" + tool) def _get_tool_paths(repository_ctx, overridden_tools): """Compute the %-escaped path to the various tools""" return dict({ k: escape_string(_find_tool(repository_ctx, k, overridden_tools)) for k in [ "ar", "ld", "llvm-cov", "llvm-profdata", "cpp", "gcc", "dwp", "gcov", "nm", "objcopy", "objdump", "strip", "c++filt", ] }.items()) def _escaped_cplus_include_paths(repository_ctx): """Use ${CPLUS_INCLUDE_PATH} to compute the %-escaped list of flags for cxxflag.""" if "CPLUS_INCLUDE_PATH" in repository_ctx.os.environ: result = [] for p in repository_ctx.os.environ["CPLUS_INCLUDE_PATH"].split(":"): p = escape_string(str(repository_ctx.path(p))) # Normalize the path result.append("-I" + p) return result else: return [] _INC_DIR_MARKER_BEGIN = "#include <...>" # OSX add " (framework directory)" at the end of line, strip it. _OSX_FRAMEWORK_SUFFIX = " (framework directory)" _OSX_FRAMEWORK_SUFFIX_LEN = len(_OSX_FRAMEWORK_SUFFIX) def _cxx_inc_convert(path): """Convert path returned by cc -E xc++ in a complete path. Doesn't %-escape the path!""" path = path.strip() if path.endswith(_OSX_FRAMEWORK_SUFFIX): path = path[:-_OSX_FRAMEWORK_SUFFIX_LEN].strip() return path def _get_cxx_include_directories(repository_ctx, print_resource_dir_supported, cc, lang_flag, additional_flags = []): """Compute the list of C++ include directories.""" result = repository_ctx.execute([cc, "-E", lang_flag, "-", "-v"] + additional_flags) index1 = result.stderr.find(_INC_DIR_MARKER_BEGIN) if index1 == -1: return [] index1 = result.stderr.find("\n", index1) if index1 == -1: return [] index2 = result.stderr.rfind("\n ") if index2 == -1 or index2 < index1: return [] index2 = result.stderr.find("\n", index2 + 1) if index2 == -1: inc_dirs = result.stderr[index1 + 1:] else: inc_dirs = result.stderr[index1 + 1:index2].strip() inc_directories = [ _prepare_include_path(repository_ctx, _cxx_inc_convert(p)) for p in inc_dirs.split("\n") ] if print_resource_dir_supported: resource_dir = repository_ctx.execute( [cc, "-print-resource-dir"] + additional_flags, ).stdout.strip() + "/share" inc_directories.append(_prepare_include_path(repository_ctx, resource_dir)) return inc_directories def _is_compiler_option_supported(repository_ctx, cc, option): """Checks that `option` is supported by the C compiler. Doesn't %-escape the option.""" result = repository_ctx.execute([ cc, option, "-o", "/dev/null", "-c", str(repository_ctx.path("tools/cpp/empty.cc")), ]) return result.stderr.find(option) == -1 def _is_linker_option_supported(repository_ctx, cc, force_linker_flags, option, pattern): """Checks that `option` is supported by the C linker. Doesn't %-escape the option.""" result = repository_ctx.execute([cc] + force_linker_flags + [ option, "-o", "/dev/null", str(repository_ctx.path("tools/cpp/empty.cc")), ]) return result.stderr.find(pattern) == -1 def _find_linker_path(repository_ctx, cc, linker, is_clang): """Checks if a given linker is supported by the C compiler. Args: repository_ctx: repository_ctx. cc: path to the C compiler. linker: linker to find is_clang: whether the compiler is known to be clang Returns: String to put as value to -fuse-ld= flag, or None if linker couldn't be found. """ result = repository_ctx.execute([ cc, str(repository_ctx.path("tools/cpp/empty.cc")), "-o", "/dev/null", # Some macOS clang versions don't fail when setting -fuse-ld=gold, adding # these lines to force it to. This also means that we will not detect # gold when only a very old (year 2010 and older) is present. "-Wl,--start-lib", "-Wl,--end-lib", "-fuse-ld=" + linker, "-v", ]) if result.return_code != 0: return None if not is_clang: return linker # Extract linker path from: # /usr/bin/clang ... # "/usr/bin/ld.lld" -pie -z ... linker_command = result.stderr.splitlines()[-1] return linker_command.strip().split(" ")[0].strip("\"'") def _add_compiler_option_if_supported(repository_ctx, cc, option): """Returns `[option]` if supported, `[]` otherwise. Doesn't %-escape the option.""" return [option] if _is_compiler_option_supported(repository_ctx, cc, option) else [] def _add_linker_option_if_supported(repository_ctx, cc, force_linker_flags, option, pattern): """Returns `[option]` if supported, `[]` otherwise. Doesn't %-escape the option.""" return [option] if _is_linker_option_supported(repository_ctx, cc, force_linker_flags, option, pattern) else [] def _get_no_canonical_prefixes_opt(repository_ctx, cc): # If the compiler sometimes rewrites paths in the .d files without symlinks # (ie when they're shorter), it confuses Bazel's logic for verifying all # #included header files are listed as inputs to the action. # The '-fno-canonical-system-headers' should be enough, but clang does not # support it, so we also try '-no-canonical-prefixes' if first option does # not work. opt = _add_compiler_option_if_supported( repository_ctx, cc, "-fno-canonical-system-headers", ) if len(opt) == 0: return _add_compiler_option_if_supported( repository_ctx, cc, "-no-canonical-prefixes", ) return opt def get_env(repository_ctx): """Convert the environment in a list of export if in Homebrew. Doesn't %-escape the result! Args: repository_ctx: The repository context. Returns: empty string or a list of exports in case we're running with homebrew. Don't ask me why. """ env = repository_ctx.os.environ if "HOMEBREW_RUBY_PATH" in env: return "\n".join([ "export %s='%s'" % (k, env[k].replace("'", "'\\''")) for k in env if k != "_" and k.find(".") == -1 ]) else: return "" def _coverage_flags(repository_ctx, darwin): use_llvm_cov = "1" == get_env_var( repository_ctx, "BAZEL_USE_LLVM_NATIVE_COVERAGE", default = "0", enable_warning = False, ) if darwin or use_llvm_cov: compile_flags = '"-fprofile-instr-generate", "-fcoverage-mapping"' link_flags = '"-fprofile-instr-generate"' else: # gcc requires --coverage being passed for compilation and linking # https://gcc.gnu.org/onlinedocs/gcc/Instrumentation-Options.html#Instrumentation-Options compile_flags = '"--coverage"' link_flags = '"--coverage"' return compile_flags, link_flags def _is_clang(repository_ctx, cc): return "clang" in repository_ctx.execute([cc, "-v"]).stderr def _is_gcc(repository_ctx, cc): # GCC's version output uses the basename of argv[0] as the program name: # https://gcc.gnu.org/git/?p=gcc.git;a=blob;f=gcc/gcc.cc;h=158461167951c1b9540322fb19be6a89d6da07fc;hb=HEAD#l8728 cc_stdout = repository_ctx.execute([cc, "--version"]).stdout return cc_stdout.startswith("gcc ") or cc_stdout.startswith("gcc-") def _get_compiler_name(repository_ctx, cc): if _is_clang(repository_ctx, cc): return "clang" if _is_gcc(repository_ctx, cc): return "gcc" return "compiler" def _find_generic(repository_ctx, name, env_name, overridden_tools, warn = False, silent = False): """Find a generic C++ toolchain tool. Doesn't %-escape the result.""" if name in overridden_tools: return overridden_tools[name] result = name env_value = repository_ctx.os.environ.get(env_name) env_value_with_paren = "" if env_value != None: env_value = env_value.strip() if env_value: result = env_value env_value_with_paren = " (%s)" % env_value if result.startswith("/"): # Absolute path, maybe we should make this supported by our which function. return result result = repository_ctx.which(result) if result == None: msg = ("Cannot find %s or %s%s; either correct your path or set the %s" + " environment variable") % (name, env_name, env_value_with_paren, env_name) if warn: if not silent: auto_configure_warning(msg) else: auto_configure_fail(msg) return result def find_cc(repository_ctx, overridden_tools): """Find the C compiler (gcc or clang) for the repository, considering overridden tools. Args: repository_ctx: The repository context. overridden_tools: A dictionary of overridden tools. Returns: The path to the C compiler. """ cc = _find_generic(repository_ctx, "gcc", "CC", overridden_tools) if _is_clang(repository_ctx, cc): # If clang is run through a symlink with -no-canonical-prefixes, it does # not find its own include directory, which includes the headers for # libc++. Resolving the potential symlink here prevents this. result = repository_ctx.execute(["readlink", "-f", cc]) if result.return_code == 0: return result.stdout.strip() return cc def configure_unix_toolchain(repository_ctx, cpu_value, overridden_tools): """Configure C++ toolchain on Unix platforms. Args: repository_ctx: The repository context. cpu_value: The CPU value. overridden_tools: A dictionary of overridden tools. """ paths = resolve_labels(repository_ctx, [ "@rules_cc//cc/private/toolchain:BUILD.tpl", "@rules_cc//cc/private/toolchain:generate_system_module_map.sh", "@rules_cc//cc/private/toolchain:armeabi_cc_toolchain_config.bzl", "@rules_cc//cc/private/toolchain:unix_cc_toolchain_config.bzl", "@rules_cc//cc/private/toolchain:linux_cc_wrapper.sh.tpl", "@rules_cc//cc/private/toolchain:validate_static_library.sh.tpl", "@rules_cc//cc/private/toolchain:osx_cc_wrapper.sh.tpl", "@rules_cc//cc/private/toolchain:clang_deps_scanner_wrapper.sh.tpl", "@rules_cc//cc/private/toolchain:gcc_deps_scanner_wrapper.sh.tpl", ]) repository_ctx.symlink( paths["@rules_cc//cc/private/toolchain:unix_cc_toolchain_config.bzl"], "cc_toolchain_config.bzl", ) repository_ctx.symlink( paths["@rules_cc//cc/private/toolchain:armeabi_cc_toolchain_config.bzl"], "armeabi_cc_toolchain_config.bzl", ) repository_ctx.file("tools/cpp/empty.cc", "int main() {}") darwin = cpu_value.startswith("darwin") bsd = cpu_value == "freebsd" or cpu_value == "openbsd" cc = find_cc(repository_ctx, overridden_tools) is_clang = _is_clang(repository_ctx, cc) overridden_tools = dict(overridden_tools) overridden_tools["gcc"] = cc overridden_tools["gcov"] = _find_generic( repository_ctx, "gcov", "GCOV", overridden_tools, warn = True, silent = True, ) overridden_tools["llvm-cov"] = _find_generic( repository_ctx, "llvm-cov", "BAZEL_LLVM_COV", overridden_tools, warn = True, silent = True, ) overridden_tools["llvm-profdata"] = _find_generic( repository_ctx, "llvm-profdata", "BAZEL_LLVM_PROFDATA", overridden_tools, warn = True, silent = True, ) overridden_tools["ar"] = _find_generic( repository_ctx, "ar", "AR", overridden_tools, warn = True, silent = True, ) if darwin: overridden_tools["gcc"] = "cc_wrapper.sh" overridden_tools["ar"] = _find_generic(repository_ctx, "libtool", "LIBTOOL", overridden_tools) auto_configure_warning_maybe(repository_ctx, "CC used: " + str(cc)) tool_paths = _get_tool_paths(repository_ctx, overridden_tools) tool_paths["cpp-module-deps-scanner"] = "deps_scanner_wrapper.sh" # The parse_header tool needs to be a wrapper around the compiler as it has # to touch the output file. tool_paths["parse_headers"] = "cc_wrapper.sh" cc_toolchain_identifier = escape_string(get_env_var( repository_ctx, "CC_TOOLCHAIN_NAME", "local", False, )) if "nm" in tool_paths and "c++filt" in tool_paths: repository_ctx.template( "validate_static_library.sh", paths["@rules_cc//cc/private/toolchain:validate_static_library.sh.tpl"], { "%{c++filt}": escape_string(str(repository_ctx.path(tool_paths["c++filt"]))), # Certain weak symbols are otherwise listed with type T in the output of nm on macOS. "%{nm_extra_args}": "--no-weak" if darwin else "", "%{nm}": escape_string(str(repository_ctx.path(tool_paths["nm"]))), }, ) tool_paths["validate_static_library"] = "validate_static_library.sh" cc_wrapper_src = ( "@rules_cc//cc/private/toolchain:osx_cc_wrapper.sh.tpl" if darwin else "@rules_cc//cc/private/toolchain:linux_cc_wrapper.sh.tpl" ) repository_ctx.template( "cc_wrapper.sh", paths[cc_wrapper_src], { "%{cc}": escape_string(str(cc)), "%{env}": escape_string(get_env(repository_ctx)), }, ) deps_scanner_wrapper_src = ( "@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" ) deps_scanner = "cpp-module-deps-scanner_not_found" if is_clang: cc_str = str(cc) path_arr = cc_str.split("/")[:-1] path_arr.append("clang-scan-deps") deps_scanner = "/".join(path_arr) repository_ctx.template( "deps_scanner_wrapper.sh", paths[deps_scanner_wrapper_src], { "%{cc}": escape_string(str(cc)), "%{deps_scanner}": escape_string(deps_scanner), "%{env}": escape_string(get_env(repository_ctx)), }, ) conly_opts = split_escaped(get_env_var( repository_ctx, "BAZEL_CONLYOPTS", "", False, ), ":") cxx_opts = split_escaped(get_env_var( repository_ctx, "BAZEL_CXXOPTS", "-std=c++17", False, ), ":") gold_or_lld_linker_path = ( _find_linker_path(repository_ctx, cc, "lld", is_clang) or _find_linker_path(repository_ctx, cc, "gold", is_clang) ) cc_path = repository_ctx.path(cc) if not str(cc_path).startswith(str(repository_ctx.path(".")) + "/"): # cc is outside the repository, set -B bin_search_flags = ["-B" + escape_string(str(cc_path.dirname))] else: # cc is inside the repository, don't set -B. bin_search_flags = [] if not gold_or_lld_linker_path: ld_path = repository_ctx.path(tool_paths["ld"]) if ld_path.dirname != cc_path.dirname: bin_search_flags.append("-B" + str(ld_path.dirname)) force_linker_flags = [] if gold_or_lld_linker_path: force_linker_flags.append("-fuse-ld=" + gold_or_lld_linker_path) # TODO: It's unclear why these flags aren't added on macOS. if bin_search_flags and not darwin: force_linker_flags.extend(bin_search_flags) use_libcpp = darwin or bsd is_as_needed_supported = _is_linker_option_supported( repository_ctx, cc, force_linker_flags, "-Wl,-no-as-needed", "-no-as-needed", ) is_push_state_supported = _is_linker_option_supported( repository_ctx, cc, force_linker_flags, "-Wl,--push-state", "--push-state", ) if use_libcpp: bazel_default_libs = ["-lc++", "-lm"] else: bazel_default_libs = ["-lstdc++", "-lm"] if is_as_needed_supported and is_push_state_supported: # Do not link against C++ standard libraries unless they are actually # used. # We assume that --push-state support implies --pop-state support. bazel_linklibs_elements = [ arg for lib in bazel_default_libs for arg in ["-Wl,--push-state,-as-needed", lib, "-Wl,--pop-state"] ] else: bazel_linklibs_elements = bazel_default_libs bazel_linklibs = ":".join(bazel_linklibs_elements) bazel_linkopts = "" link_opts = split_escaped(get_env_var( repository_ctx, "BAZEL_LINKOPTS", bazel_linkopts, False, ), ":") link_libs = split_escaped(get_env_var( repository_ctx, "BAZEL_LINKLIBS", bazel_linklibs, False, ), ":") coverage_compile_flags, coverage_link_flags = _coverage_flags(repository_ctx, darwin) print_resource_dir_supported = _is_compiler_option_supported( repository_ctx, cc, "-print-resource-dir", ) no_canonical_prefixes_opt = _get_no_canonical_prefixes_opt(repository_ctx, cc) builtin_include_directories = _uniq( _get_cxx_include_directories(repository_ctx, print_resource_dir_supported, cc, "-xc", conly_opts) + _get_cxx_include_directories(repository_ctx, print_resource_dir_supported, cc, "-xc++", cxx_opts) + _get_cxx_include_directories( repository_ctx, print_resource_dir_supported, cc, "-xc++", cxx_opts + ["-stdlib=libc++"], ) + _get_cxx_include_directories( repository_ctx, print_resource_dir_supported, cc, "-xc", no_canonical_prefixes_opt, ) + _get_cxx_include_directories( repository_ctx, print_resource_dir_supported, cc, "-xc++", cxx_opts + no_canonical_prefixes_opt, ) + _get_cxx_include_directories( repository_ctx, print_resource_dir_supported, cc, "-xc++", cxx_opts + no_canonical_prefixes_opt + ["-stdlib=libc++"], ) + # Always included in case the user has Xcode + the CLT installed, both # paths can be used interchangeably ["/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk"], ) generate_modulemap = is_clang if generate_modulemap: repository_ctx.file("module.modulemap", _generate_system_module_map( repository_ctx, builtin_include_directories, paths["@rules_cc//cc/private/toolchain:generate_system_module_map.sh"], )) extra_flags_per_feature = {} if is_clang: # Only supported by LLVM 14 and later, but required with C++20 and # layering_check as C++ modules are the default. # https://github.com/llvm/llvm-project/commit/0556138624edf48621dd49a463dbe12e7101f17d result = repository_ctx.execute([ cc, "-Xclang", "-fno-cxx-modules", "-o", "/dev/null", "-c", str(repository_ctx.path("tools/cpp/empty.cc")), ]) if "-fno-cxx-modules" not in result.stderr: extra_flags_per_feature["use_module_maps"] = ["-Xclang", "-fno-cxx-modules"] write_builtin_include_directory_paths(repository_ctx, cc, builtin_include_directories) repository_ctx.template( "BUILD", paths["@rules_cc//cc/private/toolchain:BUILD.tpl"], { "%{abi_libc_version}": escape_string(get_env_var( repository_ctx, "ABI_LIBC_VERSION", "local", False, )), "%{abi_version}": escape_string(get_env_var( repository_ctx, "ABI_VERSION", "local", False, )), "%{cc_compiler_deps}": get_starlark_list([ ":builtin_include_directory_paths", ":cc_wrapper", ":deps_scanner_wrapper", ] + ( [":validate_static_library"] if "validate_static_library" in tool_paths else [] )), "%{cc_toolchain_identifier}": cc_toolchain_identifier, "%{compile_flags}": get_starlark_list( [ "-fstack-protector", # All warnings are enabled. "-Wall", # Enable a few more warnings that aren't part of -Wall. ] + (( _add_compiler_option_if_supported(repository_ctx, cc, "-Wthread-safety") + _add_compiler_option_if_supported(repository_ctx, cc, "-Wself-assign") )) + ( # Disable problematic warnings. _add_compiler_option_if_supported(repository_ctx, cc, "-Wunused-but-set-parameter") + # has false positives _add_compiler_option_if_supported(repository_ctx, cc, "-Wno-free-nonheap-object") + # Enable coloring even if there's no attached terminal. Bazel removes the # escape sequences if --nocolor is specified. _add_compiler_option_if_supported(repository_ctx, cc, "-fcolor-diagnostics") ) + [ # Keep stack frames for debugging, even in opt mode. "-fno-omit-frame-pointer", ], ), "%{compiler}": escape_string(get_env_var( repository_ctx, "BAZEL_COMPILER", _get_compiler_name(repository_ctx, cc), False, )), "%{conly_flags}": get_starlark_list(conly_opts), "%{coverage_compile_flags}": coverage_compile_flags, "%{coverage_link_flags}": coverage_link_flags, "%{cxx_builtin_include_directories}": get_starlark_list(builtin_include_directories), "%{cxx_flags}": get_starlark_list(cxx_opts + _escaped_cplus_include_paths(repository_ctx)), "%{dbg_compile_flags}": get_starlark_list(["-g"]), "%{extra_flags_per_feature}": repr(extra_flags_per_feature), "%{host_system_name}": escape_string(get_env_var( repository_ctx, "BAZEL_HOST_SYSTEM", "local", False, )), "%{link_flags}": get_starlark_list(force_linker_flags + ( ["-Wl,-no-as-needed"] if is_as_needed_supported else [] ) + _add_linker_option_if_supported( repository_ctx, cc, force_linker_flags, "-Wl,-z,relro,-z,now", "-z", ) + ( [ "-headerpad_max_install_names", ] if darwin else [ # Gold linker only? Can we enable this by default? # "-Wl,--warn-execstack", # "-Wl,--detect-odr-violations" ] + _add_compiler_option_if_supported( # Have gcc return the exit code from ld. repository_ctx, cc, "-pass-exit-codes", ) ) + link_opts), "%{link_libs}": get_starlark_list(link_libs), "%{modulemap}": ("\":module.modulemap\"" if generate_modulemap else "None"), "%{name}": cpu_value, "%{opt_compile_flags}": get_starlark_list( [ # No debug symbols. # Maybe we should enable https://gcc.gnu.org/wiki/DebugFission for opt or # even generally? However, that can't happen here, as it requires special # handling in Bazel. "-g0", # Conservative choice for -O # -O3 can increase binary size and even slow down the resulting binaries. # Profile first and / or use FDO if you need better performance than this. "-O2", # Security hardening on by default. # Conservative choice; -D_FORTIFY_SOURCE=2 may be unsafe in some cases. "-D_FORTIFY_SOURCE=1", # Disable assertions "-DNDEBUG", # Removal of unused code and data at link time (can this increase binary # size in some cases?). "-ffunction-sections", "-fdata-sections", ], ), "%{opt_link_flags}": get_starlark_list( ["-Wl,-dead_strip"] if darwin else _add_linker_option_if_supported( repository_ctx, cc, force_linker_flags, "-Wl,--gc-sections", "-gc-sections", ), ), "%{supports_start_end_lib}": "True" if gold_or_lld_linker_path else "False", "%{target_cpu}": escape_string(get_env_var( repository_ctx, "BAZEL_TARGET_CPU", cpu_value, False, )), "%{target_libc}": "macosx" if darwin else escape_string(get_env_var( repository_ctx, "BAZEL_TARGET_LIBC", "local", False, )), "%{target_system_name}": escape_string(get_env_var( repository_ctx, "BAZEL_TARGET_SYSTEM", "local", False, )), "%{tool_paths}": ",\n ".join( ['"%s": "%s"' % (k, v) for k, v in tool_paths.items() if v != None], ), "%{unfiltered_compile_flags}": get_starlark_list( _get_no_canonical_prefixes_opt(repository_ctx, cc) + [ # Make C++ compilation deterministic. Use linkstamping instead of these # compiler symbols. "-Wno-builtin-macro-redefined", "-D__DATE__=\\\"redacted\\\"", "-D__TIMESTAMP__=\\\"redacted\\\"", "-D__TIME__=\\\"redacted\\\"", ], ), }, ) rules_cc-0.0.11/cc/private/toolchain/unix_cc_toolchain_config.bzl000066400000000000000000002067201470072561500251530ustar00rootroot00000000000000# Copyright 2019 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. """A Starlark cc_toolchain configuration rule""" load("@rules_cc//cc:action_names.bzl", "ACTION_NAMES") load( "@rules_cc//cc:cc_toolchain_config_lib.bzl", "action_config", "artifact_name_pattern", "env_entry", "env_set", "feature", "feature_set", "flag_group", "flag_set", "tool", "tool_path", "variable_with_value", "with_feature_set", ) def _target_os_version(ctx): platform_type = ctx.fragments.apple.single_arch_platform.platform_type xcode_config = ctx.attr._xcode_config[apple_common.XcodeVersionConfig] return xcode_config.minimum_os_for_platform_type(platform_type) def layering_check_features(compiler, extra_flags_per_feature, is_macos): if compiler != "clang": return [] return [ feature( name = "use_module_maps", requires = [feature_set(features = ["module_maps"])], flag_sets = [ flag_set( actions = [ ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile, ACTION_NAMES.cpp_header_parsing, ACTION_NAMES.cpp_module_compile, ], flag_groups = [ flag_group( # macOS requires -Xclang because of a bug in Apple Clang flags = (["-Xclang"] if is_macos else []) + [ "-fmodule-name=%{module_name}", ] + (["-Xclang"] if is_macos else []) + [ "-fmodule-map-file=%{module_map_file}", ] + extra_flags_per_feature.get("use_module_maps", []), ), ], ), ], ), # Tell blaze we support module maps in general, so they will be generated # for all c/c++ rules. # Note: not all C++ rules support module maps; thus, do not imply this # feature from other features - instead, require it. feature(name = "module_maps", enabled = True), feature( name = "layering_check", implies = ["use_module_maps"], flag_sets = [ flag_set( actions = [ ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile, ACTION_NAMES.cpp_header_parsing, ACTION_NAMES.cpp_module_compile, ], flag_groups = [ flag_group(flags = [ "-fmodules-strict-decluse", "-Wprivate-header", ]), flag_group( iterate_over = "dependent_module_map_files", flags = (["-Xclang"] if is_macos else []) + [ "-fmodule-map-file=%{dependent_module_map_files}", ], ), ], ), ], ), ] def parse_headers_support(parse_headers_tool_path): """ Returns action configurations and features for parsing headers. Args: parse_headers_tool_path: The path to the tool used for parsing headers. Returns: A tuple containing a list of action configurations and a list of features. """ if not parse_headers_tool_path: return [], [] action_configs = [ action_config( action_name = ACTION_NAMES.cpp_header_parsing, tools = [ tool(path = parse_headers_tool_path), ], flag_sets = [ flag_set( flag_groups = [ flag_group( flags = [ # Note: This treats all headers as C++ headers, which may lead to # parsing failures for C headers that are not valid C++. # For such headers, use features = ["-parse_headers"] to selectively # disable parsing. "-xc++-header", "-fsyntax-only", ], ), ], ), ], implies = [ # Copied from the legacy feature definition in CppActionConfigs.java. "legacy_compile_flags", "user_compile_flags", "sysroot", "unfiltered_compile_flags", "compiler_input_flags", "compiler_output_flags", ], ), ] features = [ feature(name = "parse_headers"), ] return action_configs, features all_compile_actions = [ ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile, ACTION_NAMES.linkstamp_compile, ACTION_NAMES.assemble, ACTION_NAMES.preprocess_assemble, ACTION_NAMES.cpp_header_parsing, ACTION_NAMES.cpp_module_compile, ACTION_NAMES.cpp_module_codegen, ACTION_NAMES.cpp_module_deps_scanning, ACTION_NAMES.cpp20_module_compile, ACTION_NAMES.cpp20_module_codegen, ACTION_NAMES.clif_match, ACTION_NAMES.lto_backend, ] all_cpp_compile_actions = [ ACTION_NAMES.cpp_compile, ACTION_NAMES.linkstamp_compile, ACTION_NAMES.cpp_header_parsing, ACTION_NAMES.cpp_module_compile, ACTION_NAMES.cpp_module_codegen, ACTION_NAMES.cpp_module_deps_scanning, ACTION_NAMES.cpp20_module_compile, ACTION_NAMES.cpp20_module_codegen, ACTION_NAMES.clif_match, ] preprocessor_compile_actions = [ ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile, ACTION_NAMES.linkstamp_compile, ACTION_NAMES.preprocess_assemble, ACTION_NAMES.cpp_header_parsing, ACTION_NAMES.cpp_module_compile, ACTION_NAMES.cpp_module_deps_scanning, ACTION_NAMES.cpp20_module_compile, ACTION_NAMES.clif_match, ] codegen_compile_actions = [ ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile, ACTION_NAMES.linkstamp_compile, ACTION_NAMES.assemble, ACTION_NAMES.preprocess_assemble, ACTION_NAMES.cpp_module_codegen, ACTION_NAMES.cpp20_module_codegen, ACTION_NAMES.lto_backend, ] all_link_actions = [ ACTION_NAMES.cpp_link_executable, ACTION_NAMES.cpp_link_dynamic_library, ACTION_NAMES.cpp_link_nodeps_dynamic_library, ] lto_index_actions = [ ACTION_NAMES.lto_index_for_executable, ACTION_NAMES.lto_index_for_dynamic_library, ACTION_NAMES.lto_index_for_nodeps_dynamic_library, ] def _sanitizer_feature(name = "", specific_compile_flags = [], specific_link_flags = []): return feature( name = name, flag_sets = [ flag_set( actions = all_compile_actions, flag_groups = [ flag_group(flags = [ "-fno-omit-frame-pointer", "-fno-sanitize-recover=all", ] + specific_compile_flags), ], with_features = [ with_feature_set(features = [name]), ], ), flag_set( actions = all_link_actions, flag_groups = [ flag_group(flags = specific_link_flags), ], with_features = [ with_feature_set(features = [name]), ], ), ], ) def _impl(ctx): is_linux = ctx.attr.target_libc != "macosx" tool_paths = [ tool_path(name = name, path = path) for name, path in ctx.attr.tool_paths.items() ] action_configs = [] llvm_cov = ctx.attr.tool_paths.get("llvm-cov") if llvm_cov: llvm_cov_action = action_config( action_name = ACTION_NAMES.llvm_cov, tools = [ tool( path = llvm_cov, ), ], ) action_configs.append(llvm_cov_action) objcopy = ctx.attr.tool_paths.get("objcopy") if objcopy: objcopy_action = action_config( action_name = ACTION_NAMES.objcopy_embed_data, tools = [ tool( path = objcopy, ), ], ) action_configs.append(objcopy_action) validate_static_library = ctx.attr.tool_paths.get("validate_static_library") if validate_static_library: validate_static_library_action = action_config( action_name = ACTION_NAMES.validate_static_library, tools = [ tool( path = validate_static_library, ), ], ) action_configs.append(validate_static_library_action) symbol_check = feature( name = "symbol_check", implies = [ACTION_NAMES.validate_static_library], ) else: symbol_check = None deps_scanner = "cpp-module-deps-scanner_not_found" if "cpp-module-deps-scanner" in ctx.attr.tool_paths: deps_scanner = ctx.attr.tool_paths["cpp-module-deps-scanner"] cc = ctx.attr.tool_paths.get("gcc") compile_implies = [ # keep same with c++-compile "legacy_compile_flags", "user_compile_flags", "sysroot", "unfiltered_compile_flags", "compiler_input_flags", "compiler_output_flags", ] cpp_module_scan_deps = action_config( action_name = ACTION_NAMES.cpp_module_deps_scanning, tools = [ tool( path = deps_scanner, ), ], implies = compile_implies, ) action_configs.append(cpp_module_scan_deps) cpp20_module_compile = action_config( action_name = ACTION_NAMES.cpp20_module_compile, tools = [ tool( path = cc, ), ], flag_sets = [ flag_set( flag_groups = [ flag_group( flags = [ "-x", "c++-module" if ctx.attr.compiler == "clang" else "c++", ], ), ], ), ], implies = compile_implies, ) action_configs.append(cpp20_module_compile) cpp20_module_codegen = action_config( action_name = ACTION_NAMES.cpp20_module_codegen, tools = [ tool( path = cc, ), ], implies = compile_implies, ) action_configs.append(cpp20_module_codegen) supports_pic_feature = feature( name = "supports_pic", enabled = True, ) supports_start_end_lib_feature = feature( name = "supports_start_end_lib", enabled = True, ) gcc_quoting_for_param_files_feature = feature( name = "gcc_quoting_for_param_files", enabled = True, ) static_link_cpp_runtimes_feature = feature( name = "static_link_cpp_runtimes", enabled = False, ) default_compile_flags_feature = feature( name = "default_compile_flags", enabled = True, flag_sets = [ flag_set( actions = all_compile_actions, flag_groups = [ flag_group( # Security hardening requires optimization. # We need to undef it as some distributions now have it enabled by default. flags = ["-U_FORTIFY_SOURCE"], ), ], with_features = [ with_feature_set( not_features = ["thin_lto"], ), ], ), flag_set( actions = all_compile_actions, flag_groups = ([ flag_group( flags = ctx.attr.compile_flags, ), ] if ctx.attr.compile_flags else []), ), flag_set( actions = all_compile_actions, flag_groups = ([ flag_group( flags = ctx.attr.dbg_compile_flags, ), ] if ctx.attr.dbg_compile_flags else []), with_features = [with_feature_set(features = ["dbg"])], ), flag_set( actions = all_compile_actions, flag_groups = ([ flag_group( flags = ctx.attr.opt_compile_flags, ), ] if ctx.attr.opt_compile_flags else []), with_features = [with_feature_set(features = ["opt"])], ), flag_set( actions = [ACTION_NAMES.c_compile], flag_groups = ([ flag_group( flags = ctx.attr.conly_flags, ), ] if ctx.attr.conly_flags else []), ), flag_set( actions = all_cpp_compile_actions + [ACTION_NAMES.lto_backend], flag_groups = ([ flag_group( flags = ctx.attr.cxx_flags, ), ] if ctx.attr.cxx_flags else []), ), ], ) default_link_flags_feature = feature( name = "default_link_flags", enabled = True, flag_sets = [ flag_set( actions = all_link_actions + lto_index_actions, flag_groups = ([ flag_group( flags = ctx.attr.link_flags, ), ] if ctx.attr.link_flags else []), ), flag_set( actions = all_link_actions + lto_index_actions, flag_groups = ([ flag_group( flags = ctx.attr.opt_link_flags, ), ] if ctx.attr.opt_link_flags else []), with_features = [with_feature_set(features = ["opt"])], ), ], env_sets = [ env_set( actions = all_link_actions + lto_index_actions + [ACTION_NAMES.cpp_link_static_library], env_entries = ([ env_entry( # Required for hermetic links on macOS key = "ZERO_AR_DATE", value = "1", ), ]), ), ], ) dbg_feature = feature(name = "dbg") opt_feature = feature(name = "opt") sysroot_feature = feature( name = "sysroot", enabled = True, flag_sets = [ flag_set( actions = [ ACTION_NAMES.preprocess_assemble, ACTION_NAMES.linkstamp_compile, ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile, ACTION_NAMES.cpp_header_parsing, ACTION_NAMES.cpp_module_compile, ACTION_NAMES.cpp_module_codegen, ACTION_NAMES.cpp_module_deps_scanning, ACTION_NAMES.cpp20_module_compile, ACTION_NAMES.cpp20_module_codegen, ACTION_NAMES.lto_backend, ACTION_NAMES.clif_match, ] + all_link_actions + lto_index_actions, flag_groups = [ flag_group( flags = ["--sysroot=%{sysroot}"], expand_if_available = "sysroot", ), ], ), ], ) compiler_input_flags_feature = feature( name = "compiler_input_flags", enabled = True, flag_sets = [ flag_set( actions = [ ACTION_NAMES.assemble, ACTION_NAMES.preprocess_assemble, ACTION_NAMES.linkstamp_compile, ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile, ACTION_NAMES.cpp_header_parsing, ACTION_NAMES.cpp_module_compile, ACTION_NAMES.cpp_module_codegen, ACTION_NAMES.cpp_module_deps_scanning, ACTION_NAMES.cpp20_module_compile, ACTION_NAMES.cpp20_module_codegen, ACTION_NAMES.objc_compile, ACTION_NAMES.objcpp_compile, ACTION_NAMES.lto_backend, ], flag_groups = [ flag_group( flags = ["-c", "%{source_file}"], expand_if_available = "source_file", ), ], ), ], ) compiler_output_flags_feature = feature( name = "compiler_output_flags", enabled = True, flag_sets = [ flag_set( actions = [ ACTION_NAMES.assemble, ACTION_NAMES.preprocess_assemble, ACTION_NAMES.linkstamp_compile, ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile, ACTION_NAMES.cpp_header_parsing, ACTION_NAMES.cpp_module_compile, ACTION_NAMES.cpp_module_codegen, ACTION_NAMES.cpp_module_deps_scanning, ACTION_NAMES.cpp20_module_compile, ACTION_NAMES.cpp20_module_codegen, ACTION_NAMES.objc_compile, ACTION_NAMES.objcpp_compile, ACTION_NAMES.lto_backend, ], flag_groups = [ flag_group( flags = ["-S"], expand_if_available = "output_assembly_file", ), flag_group( flags = ["-E"], expand_if_available = "output_preprocess_file", ), flag_group( flags = ["-o", "%{output_file}"], expand_if_available = "output_file", ), ], ), ], ) fdo_optimize_feature = feature( name = "fdo_optimize", flag_sets = [ flag_set( actions = [ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile], flag_groups = [ flag_group( flags = [ "-fprofile-use=%{fdo_profile_path}", "-fprofile-correction", ], expand_if_available = "fdo_profile_path", ), ], ), ], provides = ["profile"], ) supports_dynamic_linker_feature = feature(name = "supports_dynamic_linker", enabled = True) user_compile_flags_feature = feature( name = "user_compile_flags", enabled = True, flag_sets = [ flag_set( actions = all_compile_actions, flag_groups = [ flag_group( flags = ["%{user_compile_flags}"], iterate_over = "user_compile_flags", expand_if_available = "user_compile_flags", ), ], ), ], ) unfiltered_compile_flags_feature = feature( name = "unfiltered_compile_flags", enabled = True, flag_sets = [ flag_set( actions = all_compile_actions, flag_groups = ([ flag_group( flags = ctx.attr.unfiltered_compile_flags, ), ] if ctx.attr.unfiltered_compile_flags else []), ), ], ) library_search_directories_feature = feature( name = "library_search_directories", flag_sets = [ flag_set( actions = all_link_actions + lto_index_actions, flag_groups = [ flag_group( flags = ["-L%{library_search_directories}"], iterate_over = "library_search_directories", expand_if_available = "library_search_directories", ), ], ), ], ) static_libgcc_feature = feature( name = "static_libgcc", enabled = True, flag_sets = [ flag_set( actions = [ ACTION_NAMES.cpp_link_executable, ACTION_NAMES.cpp_link_dynamic_library, ACTION_NAMES.lto_index_for_executable, ACTION_NAMES.lto_index_for_dynamic_library, ], flag_groups = [flag_group(flags = ["-static-libgcc"])], with_features = [ with_feature_set(features = ["static_link_cpp_runtimes"]), ], ), ], ) pic_feature = feature( name = "pic", enabled = True, flag_sets = [ flag_set( actions = [ ACTION_NAMES.assemble, ACTION_NAMES.preprocess_assemble, ACTION_NAMES.linkstamp_compile, ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile, ACTION_NAMES.cpp_module_codegen, ACTION_NAMES.cpp_module_compile, ACTION_NAMES.cpp20_module_compile, ACTION_NAMES.cpp20_module_codegen, ], flag_groups = [ flag_group(flags = ["-fPIC"], expand_if_available = "pic"), ], ), ], ) per_object_debug_info_feature = feature( name = "per_object_debug_info", enabled = True, flag_sets = [ flag_set( actions = [ ACTION_NAMES.assemble, ACTION_NAMES.preprocess_assemble, ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile, ACTION_NAMES.cpp_module_codegen, ACTION_NAMES.cpp20_module_codegen, ], flag_groups = [ flag_group( flags = ["-gsplit-dwarf", "-g"], expand_if_available = "per_object_debug_info_file", ), ], ), ], ) preprocessor_defines_feature = feature( name = "preprocessor_defines", enabled = True, flag_sets = [ flag_set( actions = [ ACTION_NAMES.preprocess_assemble, ACTION_NAMES.linkstamp_compile, ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile, ACTION_NAMES.cpp_header_parsing, ACTION_NAMES.cpp_module_compile, ACTION_NAMES.cpp_module_deps_scanning, ACTION_NAMES.cpp20_module_compile, ACTION_NAMES.cpp20_module_codegen, ACTION_NAMES.clif_match, ], flag_groups = [ flag_group( flags = ["-D%{preprocessor_defines}"], iterate_over = "preprocessor_defines", ), ], ), ], ) cs_fdo_optimize_feature = feature( name = "cs_fdo_optimize", flag_sets = [ flag_set( actions = [ACTION_NAMES.lto_backend], flag_groups = [ flag_group( flags = [ "-fprofile-use=%{fdo_profile_path}", "-Wno-profile-instr-unprofiled", "-Wno-profile-instr-out-of-date", "-fprofile-correction", ], expand_if_available = "fdo_profile_path", ), ], ), ], provides = ["csprofile"], ) autofdo_feature = feature( name = "autofdo", flag_sets = [ flag_set( actions = [ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile], flag_groups = [ flag_group( flags = [ "-fauto-profile=%{fdo_profile_path}", "-fprofile-correction", ], expand_if_available = "fdo_profile_path", ), ], ), ], provides = ["profile"], ) if is_linux: runtime_library_search_directories_feature = feature( name = "runtime_library_search_directories", flag_sets = [ flag_set( actions = all_link_actions + lto_index_actions, flag_groups = [ flag_group( iterate_over = "runtime_library_search_directories", flag_groups = [ flag_group( flags = [ "-Xlinker", "-rpath", "-Xlinker", "$EXEC_ORIGIN/%{runtime_library_search_directories}", ], expand_if_true = "is_cc_test", ), flag_group( flags = [ "-Xlinker", "-rpath", "-Xlinker", "$ORIGIN/%{runtime_library_search_directories}", ], expand_if_false = "is_cc_test", ), ], expand_if_available = "runtime_library_search_directories", ), ], with_features = [ with_feature_set(features = ["static_link_cpp_runtimes"]), ], ), flag_set( actions = all_link_actions + lto_index_actions, flag_groups = [ flag_group( iterate_over = "runtime_library_search_directories", flag_groups = [ flag_group( flags = [ "-Xlinker", "-rpath", "-Xlinker", "$ORIGIN/%{runtime_library_search_directories}", ], ), ], expand_if_available = "runtime_library_search_directories", ), ], with_features = [ with_feature_set( not_features = ["static_link_cpp_runtimes"], ), ], ), ], ) set_install_name_feature = feature( name = "set_soname", flag_sets = [ flag_set( actions = [ ACTION_NAMES.cpp_link_dynamic_library, ACTION_NAMES.cpp_link_nodeps_dynamic_library, ], flag_groups = [ flag_group( flags = [ "-Wl,-soname,%{runtime_solib_name}", ], expand_if_available = "runtime_solib_name", ), ], ), ], ) else: runtime_library_search_directories_feature = feature( name = "runtime_library_search_directories", flag_sets = [ flag_set( actions = all_link_actions + lto_index_actions, flag_groups = [ flag_group( iterate_over = "runtime_library_search_directories", flag_groups = [ flag_group( flags = [ "-Xlinker", "-rpath", "-Xlinker", "@loader_path/%{runtime_library_search_directories}", ], ), ], expand_if_available = "runtime_library_search_directories", ), ], ), ], ) set_install_name_feature = feature( name = "set_install_name", enabled = ctx.fragments.cpp.do_not_use_macos_set_install_name, flag_sets = [ flag_set( actions = [ ACTION_NAMES.cpp_link_dynamic_library, ACTION_NAMES.cpp_link_nodeps_dynamic_library, ], flag_groups = [ flag_group( flags = [ "-Wl,-install_name,@rpath/%{runtime_solib_name}", ], expand_if_available = "runtime_solib_name", ), ], ), ], ) fission_support_feature = feature( name = "fission_support", flag_sets = [ flag_set( actions = all_link_actions + lto_index_actions, flag_groups = [ flag_group( flags = ["-Wl,--gdb-index"], expand_if_available = "is_using_fission", ), ], ), ], ) shared_flag_feature = feature( name = "shared_flag", flag_sets = [ flag_set( actions = [ ACTION_NAMES.cpp_link_dynamic_library, ACTION_NAMES.cpp_link_nodeps_dynamic_library, ACTION_NAMES.lto_index_for_dynamic_library, ACTION_NAMES.lto_index_for_nodeps_dynamic_library, ], flag_groups = [flag_group(flags = ["-shared"])], ), ], ) random_seed_feature = feature( name = "random_seed", enabled = True, flag_sets = [ flag_set( actions = [ ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile, ACTION_NAMES.cpp_module_codegen, ACTION_NAMES.cpp_module_compile, ACTION_NAMES.cpp_module_deps_scanning, ACTION_NAMES.cpp20_module_compile, ACTION_NAMES.cpp20_module_codegen, ], flag_groups = [ flag_group( flags = ["-frandom-seed=%{output_file}"], expand_if_available = "output_file", ), ], ), ], ) includes_feature = feature( name = "includes", enabled = True, flag_sets = [ flag_set( actions = [ ACTION_NAMES.preprocess_assemble, ACTION_NAMES.linkstamp_compile, ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile, ACTION_NAMES.cpp_header_parsing, ACTION_NAMES.cpp_module_compile, ACTION_NAMES.cpp_module_deps_scanning, ACTION_NAMES.cpp20_module_compile, ACTION_NAMES.clif_match, ACTION_NAMES.objc_compile, ACTION_NAMES.objcpp_compile, ], flag_groups = [ flag_group( flags = ["-include", "%{includes}"], iterate_over = "includes", expand_if_available = "includes", ), ], ), ], ) fdo_instrument_feature = feature( name = "fdo_instrument", flag_sets = [ flag_set( actions = [ ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile, ] + all_link_actions + lto_index_actions, flag_groups = [ flag_group( flags = [ "-fprofile-generate=%{fdo_instrument_path}", "-fno-data-sections", ], expand_if_available = "fdo_instrument_path", ), ], ), ], provides = ["profile"], ) cs_fdo_instrument_feature = feature( name = "cs_fdo_instrument", flag_sets = [ flag_set( actions = [ ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile, ACTION_NAMES.lto_backend, ] + all_link_actions + lto_index_actions, flag_groups = [ flag_group( flags = [ "-fcs-profile-generate=%{cs_fdo_instrument_path}", ], expand_if_available = "cs_fdo_instrument_path", ), ], ), ], provides = ["csprofile"], ) include_paths_feature = feature( name = "include_paths", enabled = True, flag_sets = [ flag_set( actions = [ ACTION_NAMES.preprocess_assemble, ACTION_NAMES.linkstamp_compile, ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile, ACTION_NAMES.cpp_header_parsing, ACTION_NAMES.cpp_module_compile, ACTION_NAMES.cpp_module_deps_scanning, ACTION_NAMES.cpp20_module_compile, ACTION_NAMES.clif_match, ACTION_NAMES.objc_compile, ACTION_NAMES.objcpp_compile, ], flag_groups = [ flag_group( flags = ["-iquote", "%{quote_include_paths}"], iterate_over = "quote_include_paths", ), flag_group( flags = ["-I%{include_paths}"], iterate_over = "include_paths", ), flag_group( flags = ["-isystem", "%{system_include_paths}"], iterate_over = "system_include_paths", ), ], ), ], ) external_include_paths_feature = feature( name = "external_include_paths", flag_sets = [ flag_set( actions = [ ACTION_NAMES.preprocess_assemble, ACTION_NAMES.linkstamp_compile, ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile, ACTION_NAMES.cpp_header_parsing, ACTION_NAMES.cpp_module_compile, ACTION_NAMES.cpp_module_deps_scanning, ACTION_NAMES.cpp20_module_compile, ACTION_NAMES.cpp20_module_codegen, ACTION_NAMES.clif_match, ACTION_NAMES.objc_compile, ACTION_NAMES.objcpp_compile, ], flag_groups = [ flag_group( flags = ["-isystem", "%{external_include_paths}"], iterate_over = "external_include_paths", expand_if_available = "external_include_paths", ), ], ), ], ) strip_debug_symbols_feature = feature( name = "strip_debug_symbols", flag_sets = [ flag_set( actions = all_link_actions + lto_index_actions, flag_groups = [ flag_group( flags = ["-Wl,-S"], expand_if_available = "strip_debug_symbols", ), ], ), ], ) build_interface_libraries_feature = feature( name = "build_interface_libraries", flag_sets = [ flag_set( actions = [ ACTION_NAMES.cpp_link_dynamic_library, ACTION_NAMES.cpp_link_nodeps_dynamic_library, ACTION_NAMES.lto_index_for_dynamic_library, ACTION_NAMES.lto_index_for_nodeps_dynamic_library, ], flag_groups = [ flag_group( flags = [ "%{generate_interface_library}", "%{interface_library_builder_path}", "%{interface_library_input_path}", "%{interface_library_output_path}", ], expand_if_available = "generate_interface_library", ), ], with_features = [ with_feature_set( features = ["supports_interface_shared_libraries"], ), ], ), ], ) libraries_to_link_common_flag_groups = [ flag_group( flags = ["-Wl,-whole-archive"], expand_if_true = "libraries_to_link.is_whole_archive", expand_if_equal = variable_with_value( name = "libraries_to_link.type", value = "static_library", ), ), flag_group( flags = ["%{libraries_to_link.object_files}"], iterate_over = "libraries_to_link.object_files", expand_if_equal = variable_with_value( name = "libraries_to_link.type", value = "object_file_group", ), ), flag_group( flags = ["%{libraries_to_link.name}"], expand_if_equal = variable_with_value( name = "libraries_to_link.type", value = "object_file", ), ), flag_group( flags = ["%{libraries_to_link.name}"], expand_if_equal = variable_with_value( name = "libraries_to_link.type", value = "interface_library", ), ), flag_group( flags = ["%{libraries_to_link.name}"], expand_if_equal = variable_with_value( name = "libraries_to_link.type", value = "static_library", ), ), flag_group( flags = ["-l%{libraries_to_link.name}"], expand_if_equal = variable_with_value( name = "libraries_to_link.type", value = "dynamic_library", ), ), flag_group( flags = ["-l:%{libraries_to_link.name}"], expand_if_equal = variable_with_value( name = "libraries_to_link.type", value = "versioned_dynamic_library", ), ), flag_group( flags = ["-Wl,-no-whole-archive"], expand_if_true = "libraries_to_link.is_whole_archive", expand_if_equal = variable_with_value( name = "libraries_to_link.type", value = "static_library", ), ), ] libraries_to_link_feature = feature( name = "libraries_to_link", flag_sets = [ flag_set( actions = [ ACTION_NAMES.cpp_link_executable, ACTION_NAMES.cpp_link_dynamic_library, ] + lto_index_actions, flag_groups = [ flag_group( iterate_over = "libraries_to_link", flag_groups = [ flag_group( flags = ["-Wl,--start-lib"], expand_if_equal = variable_with_value( name = "libraries_to_link.type", value = "object_file_group", ), ), ] + libraries_to_link_common_flag_groups + [ flag_group( flags = ["-Wl,--end-lib"], expand_if_equal = variable_with_value( name = "libraries_to_link.type", value = "object_file_group", ), ), ], expand_if_available = "libraries_to_link", ), flag_group( flags = ["-Wl,@%{thinlto_param_file}"], expand_if_true = "thinlto_param_file", ), ], ), # Object file groups may contain symbols that aren't referenced in the same target that # produces the object files and must thus not be wrapped in --start-lib/--end-lib when # linking a nodeps dynamic library. flag_set( actions = [ACTION_NAMES.cpp_link_nodeps_dynamic_library], flag_groups = [ flag_group( iterate_over = "libraries_to_link", flag_groups = libraries_to_link_common_flag_groups, ), flag_group( flags = ["-Wl,@%{thinlto_param_file}"], expand_if_true = "thinlto_param_file", ), ], ), ], ) user_link_flags_feature = feature( name = "user_link_flags", flag_sets = [ flag_set( actions = all_link_actions + lto_index_actions, flag_groups = [ flag_group( flags = ["%{user_link_flags}"], iterate_over = "user_link_flags", expand_if_available = "user_link_flags", ), ], ), ], ) default_link_libs_feature = feature( name = "default_link_libs", enabled = True, flag_sets = [ flag_set( actions = all_link_actions + lto_index_actions, flag_groups = [flag_group(flags = ctx.attr.link_libs)] if ctx.attr.link_libs else [], ), ], ) fdo_prefetch_hints_feature = feature( name = "fdo_prefetch_hints", flag_sets = [ flag_set( actions = [ ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile, ACTION_NAMES.lto_backend, ], flag_groups = [ flag_group( flags = [ "-mllvm", "-prefetch-hints-file=%{fdo_prefetch_hints_path}", ], expand_if_available = "fdo_prefetch_hints_path", ), ], ), ], ) linkstamps_feature = feature( name = "linkstamps", flag_sets = [ flag_set( actions = all_link_actions + lto_index_actions, flag_groups = [ flag_group( flags = ["%{linkstamp_paths}"], iterate_over = "linkstamp_paths", expand_if_available = "linkstamp_paths", ), ], ), ], ) libtool_feature = feature( name = "libtool", enabled = not is_linux, ) archiver_flags_feature = feature( name = "archiver_flags", flag_sets = [ flag_set( actions = [ACTION_NAMES.cpp_link_static_library], flag_groups = [ flag_group( flags = [ "rcsD" if is_linux else "rcs", "%{output_execpath}", ], expand_if_available = "output_execpath", ), ], with_features = [ with_feature_set( not_features = ["libtool"], ), ], ), flag_set( actions = [ACTION_NAMES.cpp_link_static_library], flag_groups = [ flag_group( flags = [ "-static", "-o", "%{output_execpath}", ], expand_if_available = "output_execpath", ), ], with_features = [ with_feature_set( features = ["libtool"], ), ], ), flag_set( actions = [ACTION_NAMES.cpp_link_static_library], flag_groups = [ flag_group( iterate_over = "libraries_to_link", flag_groups = [ flag_group( flags = ["%{libraries_to_link.name}"], expand_if_equal = variable_with_value( name = "libraries_to_link.type", value = "object_file", ), ), flag_group( flags = ["%{libraries_to_link.object_files}"], iterate_over = "libraries_to_link.object_files", expand_if_equal = variable_with_value( name = "libraries_to_link.type", value = "object_file_group", ), ), ], expand_if_available = "libraries_to_link", ), ], ), flag_set( actions = [ACTION_NAMES.cpp_link_static_library], flag_groups = ([ flag_group( flags = ctx.attr.archive_flags, ), ] if ctx.attr.archive_flags else []), ), flag_set( actions = [ACTION_NAMES.cpp_link_static_library], flag_groups = [ flag_group( flags = ["%{user_archiver_flags}"], iterate_over = "user_archiver_flags", expand_if_available = "user_archiver_flags", ), ], ), ], ) force_pic_flags_feature = feature( name = "force_pic_flags", flag_sets = [ flag_set( actions = [ ACTION_NAMES.cpp_link_executable, ACTION_NAMES.lto_index_for_executable, ], flag_groups = [ flag_group( flags = ["-pie"], expand_if_available = "force_pic", ), ], ), ], ) dependency_file_feature = feature( name = "dependency_file", enabled = True, flag_sets = [ flag_set( actions = [ ACTION_NAMES.assemble, ACTION_NAMES.preprocess_assemble, ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile, ACTION_NAMES.cpp_module_compile, ACTION_NAMES.objc_compile, ACTION_NAMES.objcpp_compile, ACTION_NAMES.cpp_header_parsing, ACTION_NAMES.cpp_module_deps_scanning, ACTION_NAMES.cpp20_module_compile, ACTION_NAMES.clif_match, ], flag_groups = [ flag_group( flags = ["-MD", "-MF", "%{dependency_file}"], expand_if_available = "dependency_file", ), ], ), ], ) serialized_diagnostics_file_feature = feature( name = "serialized_diagnostics_file", flag_sets = [ flag_set( actions = [ ACTION_NAMES.assemble, ACTION_NAMES.preprocess_assemble, ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile, ACTION_NAMES.cpp_module_compile, ACTION_NAMES.objc_compile, ACTION_NAMES.objcpp_compile, ACTION_NAMES.cpp_header_parsing, ACTION_NAMES.cpp_module_deps_scanning, ACTION_NAMES.clif_match, ], flag_groups = [ flag_group( flags = ["--serialize-diagnostics", "%{serialized_diagnostics_file}"], expand_if_available = "serialized_diagnostics_file", ), ], ), ], ) dynamic_library_linker_tool_feature = feature( name = "dynamic_library_linker_tool", flag_sets = [ flag_set( actions = [ ACTION_NAMES.cpp_link_dynamic_library, ACTION_NAMES.cpp_link_nodeps_dynamic_library, ACTION_NAMES.lto_index_for_dynamic_library, ACTION_NAMES.lto_index_for_nodeps_dynamic_library, ], flag_groups = [ flag_group( flags = [" + cppLinkDynamicLibraryToolPath + "], expand_if_available = "generate_interface_library", ), ], with_features = [ with_feature_set( features = ["supports_interface_shared_libraries"], ), ], ), ], ) generate_linkmap_feature = feature( name = "generate_linkmap", flag_sets = [ flag_set( actions = [ ACTION_NAMES.cpp_link_executable, ], flag_groups = [ flag_group( flags = [ "-Wl,-Map=%{output_execpath}.map" if is_linux else "-Wl,-map,%{output_execpath}.map", ], expand_if_available = "output_execpath", ), ], ), ], ) output_execpath_flags_feature = feature( name = "output_execpath_flags", flag_sets = [ flag_set( actions = all_link_actions + lto_index_actions, flag_groups = [ flag_group( flags = ["-o", "%{output_execpath}"], expand_if_available = "output_execpath", ), ], ), ], ) # Note that we also set --coverage for c++-link-nodeps-dynamic-library. The # generated code contains references to gcov symbols, and the dynamic linker # can't resolve them unless the library is linked against gcov. coverage_feature = feature( name = "coverage", provides = ["profile"], flag_sets = [ flag_set( actions = [ ACTION_NAMES.preprocess_assemble, ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile, ACTION_NAMES.cpp_header_parsing, ACTION_NAMES.cpp_module_compile, ], flag_groups = ([ flag_group(flags = ctx.attr.coverage_compile_flags), ] if ctx.attr.coverage_compile_flags else []), ), flag_set( actions = all_link_actions + lto_index_actions, flag_groups = ([ flag_group(flags = ctx.attr.coverage_link_flags), ] if ctx.attr.coverage_link_flags else []), ), ], ) thinlto_feature = feature( name = "thin_lto", flag_sets = [ flag_set( actions = [ ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile, ] + all_link_actions + lto_index_actions, flag_groups = [ flag_group(flags = ["-flto=thin"]), flag_group( expand_if_available = "lto_indexing_bitcode_file", flags = [ "-Xclang", "-fthin-link-bitcode=%{lto_indexing_bitcode_file}", ], ), ], ), flag_set( actions = [ACTION_NAMES.linkstamp_compile], flag_groups = [flag_group(flags = ["-DBUILD_LTO_TYPE=thin"])], ), flag_set( actions = lto_index_actions, flag_groups = [ flag_group(flags = [ "-flto=thin", "-Wl,-plugin-opt,thinlto-index-only%{thinlto_optional_params_file}", "-Wl,-plugin-opt,thinlto-emit-imports-files", "-Wl,-plugin-opt,thinlto-prefix-replace=%{thinlto_prefix_replace}", ]), flag_group( expand_if_available = "thinlto_object_suffix_replace", flags = [ "-Wl,-plugin-opt,thinlto-object-suffix-replace=%{thinlto_object_suffix_replace}", ], ), flag_group( expand_if_available = "thinlto_merged_object_file", flags = [ "-Wl,-plugin-opt,obj-path=%{thinlto_merged_object_file}", ], ), ], ), flag_set( actions = [ACTION_NAMES.lto_backend], flag_groups = [ flag_group(flags = [ "-c", "-fthinlto-index=%{thinlto_index}", "-o", "%{thinlto_output_object_file}", "-x", "ir", "%{thinlto_input_bitcode_file}", ]), ], ), ], ) treat_warnings_as_errors_feature = feature( name = "treat_warnings_as_errors", flag_sets = [ flag_set( actions = [ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile], flag_groups = [flag_group(flags = ["-Werror"])], ), flag_set( actions = all_link_actions, flag_groups = [flag_group( flags = ["-Wl,-fatal-warnings"] if is_linux else ["-Wl,-fatal_warnings"], )], ), ], ) archive_param_file_feature = feature( name = "archive_param_file", enabled = True, ) asan_feature = _sanitizer_feature( name = "asan", specific_compile_flags = [ "-fsanitize=address", "-fno-common", ], specific_link_flags = [ "-fsanitize=address", ], ) tsan_feature = _sanitizer_feature( name = "tsan", specific_compile_flags = [ "-fsanitize=thread", ], specific_link_flags = [ "-fsanitize=thread", ], ) ubsan_feature = _sanitizer_feature( name = "ubsan", specific_compile_flags = [ "-fsanitize=undefined", ], specific_link_flags = [ "-fsanitize=undefined", ], ) # If you have Xcode + the CLT installed the version defaults can be # too old for some standard C apis such as thread locals macos_minimum_os_feature = feature( name = "macos_minimum_os", enabled = True, flag_sets = [ flag_set( actions = all_compile_actions + all_link_actions, flag_groups = [flag_group(flags = ["-mmacosx-version-min={}".format(_target_os_version(ctx))])], ), ], ) # Kept for backwards compatibility with the crosstool that moved. Without # linking the objc runtime binaries don't link CoreFoundation for free, # which breaks abseil. macos_default_link_flags_feature = feature( name = "macos_default_link_flags", enabled = True, flag_sets = [ flag_set( actions = all_link_actions, flag_groups = [flag_group(flags = [ "-no-canonical-prefixes", "-fobjc-link-runtime", ])], ), ], ) # Tell bazel we support C++ modules now cpp_modules_feature = feature( name = "cpp_modules", # set default value to False # to enable the feature # use --features=cpp_modules # or add cpp_modules to features attr enabled = False, ) cpp_module_modmap_file_feature = feature( name = "cpp_module_modmap_file", flag_sets = [ flag_set( actions = [ ACTION_NAMES.cpp_compile, ACTION_NAMES.cpp20_module_compile, ACTION_NAMES.cpp20_module_codegen, ], flag_groups = [ flag_group( flags = ["@%{cpp_module_modmap_file}" if ctx.attr.compiler == "clang" else "-fmodule-mapper=%{cpp_module_modmap_file}"], expand_if_available = "cpp_module_modmap_file", ), ], ), ], enabled = True, ) if ctx.attr.compiler == "clang": flag_groups = [ flag_group( flags = ["-fmodule-output=%{cpp_module_output_file}"], expand_if_available = "cpp_module_output_file", ), ] else: flag_groups = [] cpp20_module_compile_flags_feature = feature( name = "cpp20_module_compile_flags", flag_sets = [ flag_set( actions = [ ACTION_NAMES.cpp20_module_compile, ], flag_groups = flag_groups, ), ], enabled = True, ) # TODO(#8303): Mac crosstool should also declare every feature. if is_linux: # Linux artifact name patterns are the default. artifact_name_patterns = [] features = [ cpp_modules_feature, cpp_module_modmap_file_feature, cpp20_module_compile_flags_feature, dependency_file_feature, serialized_diagnostics_file_feature, random_seed_feature, pic_feature, per_object_debug_info_feature, preprocessor_defines_feature, includes_feature, include_paths_feature, external_include_paths_feature, fdo_instrument_feature, cs_fdo_instrument_feature, cs_fdo_optimize_feature, thinlto_feature, fdo_prefetch_hints_feature, autofdo_feature, build_interface_libraries_feature, dynamic_library_linker_tool_feature, generate_linkmap_feature, shared_flag_feature, linkstamps_feature, output_execpath_flags_feature, runtime_library_search_directories_feature, library_search_directories_feature, libtool_feature, archiver_flags_feature, force_pic_flags_feature, fission_support_feature, strip_debug_symbols_feature, coverage_feature, supports_pic_feature, asan_feature, tsan_feature, ubsan_feature, gcc_quoting_for_param_files_feature, static_link_cpp_runtimes_feature, ] + ( [ supports_start_end_lib_feature, ] if ctx.attr.supports_start_end_lib else [] ) + [ default_compile_flags_feature, default_link_flags_feature, libraries_to_link_feature, user_link_flags_feature, default_link_libs_feature, static_libgcc_feature, fdo_optimize_feature, supports_dynamic_linker_feature, dbg_feature, opt_feature, user_compile_flags_feature, sysroot_feature, compiler_input_flags_feature, compiler_output_flags_feature, unfiltered_compile_flags_feature, treat_warnings_as_errors_feature, archive_param_file_feature, set_install_name_feature, ] + layering_check_features(ctx.attr.compiler, ctx.attr.extra_flags_per_feature, is_macos = False) else: # macOS artifact name patterns differ from the defaults only for dynamic # libraries. artifact_name_patterns = [ artifact_name_pattern( category_name = "dynamic_library", prefix = "lib", extension = ".dylib", ), ] features = [ cpp_modules_feature, cpp_module_modmap_file_feature, cpp20_module_compile_flags_feature, macos_minimum_os_feature, macos_default_link_flags_feature, dependency_file_feature, runtime_library_search_directories_feature, set_install_name_feature, libtool_feature, archiver_flags_feature, asan_feature, tsan_feature, ubsan_feature, gcc_quoting_for_param_files_feature, static_link_cpp_runtimes_feature, ] + ( [ supports_start_end_lib_feature, ] if ctx.attr.supports_start_end_lib else [] ) + [ coverage_feature, default_compile_flags_feature, default_link_flags_feature, user_link_flags_feature, default_link_libs_feature, external_include_paths_feature, fdo_optimize_feature, dbg_feature, opt_feature, user_compile_flags_feature, sysroot_feature, compiler_input_flags_feature, compiler_output_flags_feature, unfiltered_compile_flags_feature, treat_warnings_as_errors_feature, archive_param_file_feature, generate_linkmap_feature, ] + layering_check_features(ctx.attr.compiler, ctx.attr.extra_flags_per_feature, is_macos = True) parse_headers_action_configs, parse_headers_features = parse_headers_support( parse_headers_tool_path = ctx.attr.tool_paths.get("parse_headers"), ) action_configs += parse_headers_action_configs features += parse_headers_features if symbol_check: features.append(symbol_check) return cc_common.create_cc_toolchain_config_info( ctx = ctx, features = features, action_configs = action_configs, artifact_name_patterns = artifact_name_patterns, cxx_builtin_include_directories = ctx.attr.cxx_builtin_include_directories, toolchain_identifier = ctx.attr.toolchain_identifier, host_system_name = ctx.attr.host_system_name, target_system_name = ctx.attr.target_system_name, target_cpu = ctx.attr.cpu, target_libc = ctx.attr.target_libc, compiler = ctx.attr.compiler, abi_version = ctx.attr.abi_version, abi_libc_version = ctx.attr.abi_libc_version, tool_paths = tool_paths, builtin_sysroot = ctx.attr.builtin_sysroot, ) cc_toolchain_config = rule( implementation = _impl, attrs = { "abi_libc_version": attr.string(mandatory = True), "abi_version": attr.string(mandatory = True), "archive_flags": attr.string_list(), "builtin_sysroot": attr.string(), "compile_flags": attr.string_list(), "compiler": attr.string(mandatory = True), "conly_flags": attr.string_list(), "coverage_compile_flags": attr.string_list(), "coverage_link_flags": attr.string_list(), "cpu": attr.string(mandatory = True), "cxx_builtin_include_directories": attr.string_list(), "cxx_flags": attr.string_list(), "dbg_compile_flags": attr.string_list(), "extra_flags_per_feature": attr.string_list_dict(), "host_system_name": attr.string(mandatory = True), "link_flags": attr.string_list(), "link_libs": attr.string_list(), "opt_compile_flags": attr.string_list(), "opt_link_flags": attr.string_list(), "supports_start_end_lib": attr.bool(), "target_libc": attr.string(mandatory = True), "target_system_name": attr.string(mandatory = True), "tool_paths": attr.string_dict(), "toolchain_identifier": attr.string(mandatory = True), "unfiltered_compile_flags": attr.string_list(), "_xcode_config": attr.label(default = configuration_field( fragment = "apple", name = "xcode_config_label", )), }, fragments = ["apple", "cpp"], provides = [CcToolchainConfigInfo], ) rules_cc-0.0.11/cc/private/toolchain/validate_static_library.sh.tpl000077500000000000000000000035311470072561500254410ustar00rootroot00000000000000#!/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=$( "%{nm}" -A -g -P %{nm_extra_args} "$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 | "%{c++filt}") if [[ -n "$DUPLICATE_SYMBOLS" ]]; then >&2 echo "Duplicate symbols found in $1:" >&2 echo "$DUPLICATE_SYMBOLS" exit 1 else touch "$2" fi rules_cc-0.0.11/cc/private/toolchain/vc_installation_error.bat.tpl000066400000000000000000000016451470072561500253140ustar00rootroot00000000000000:: Copyright 2017 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. @echo OFF echo. 1>&2 echo The target you are compiling requires Visual C++ build tools. 1>&2 echo Bazel couldn't find a valid Visual C++ build tools installation on your machine. 1>&2 %{vc_error_message} echo Please check your installation following https://bazel.build/docs/windows#using 1>&2 echo. 1>&2 exit /b 1 rules_cc-0.0.11/cc/private/toolchain/windows_cc_configure.bzl000066400000000000000000001237471470072561500243450ustar00rootroot00000000000000# pylint: disable=g-bad-file-header # 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. """Configuring the C++ toolchain on Windows.""" load( ":lib_cc_configure.bzl", "auto_configure_fail", "auto_configure_warning", "auto_configure_warning_maybe", "escape_string", "execute", "resolve_labels", "write_builtin_include_directory_paths", ) _targets_archs = {"arm": "amd64_arm", "arm64": "amd64_arm64", "x64": "amd64", "x86": "amd64_x86"} _targets_lib_folder = {"arm": "arm", "arm64": "arm64", "x86": ""} def _lookup_env_var(env, name, default = None): """Lookup environment variable case-insensitve. If a matching (case-insensitive) entry is found in the env dict both the key and the value are returned. The returned key might differ from name in casing. If a matching key was found its value is returned otherwise the default is returned. Return a (key, value) tuple""" for key, value in env.items(): if name.lower() == key.lower(): return (key, value) return (name, default) def _get_env_var(repository_ctx, name, default = None): """Returns a value from an environment variable.""" return _lookup_env_var(repository_ctx.os.environ, name, default)[1] def _get_path_env_var(repository_ctx, name): """Returns a path from an environment variable. Removes quotes, replaces '/' with '\', and strips trailing '\'s.""" value = _get_env_var(repository_ctx, name) if value != None: if value[0] == "\"": if len(value) == 1 or value[-1] != "\"": auto_configure_fail("'%s' environment variable has no trailing quote" % name) value = value[1:-1] if "/" in value: value = value.replace("/", "\\") if value[-1] == "\\": value = value.rstrip("\\") return value def _get_temp_env(repository_ctx): """Returns the value of TMP, or TEMP, or if both undefined then C:\\Windows.""" tmp = _get_path_env_var(repository_ctx, "TMP") if not tmp: tmp = _get_path_env_var(repository_ctx, "TEMP") if not tmp: tmp = "C:\\Windows\\Temp" auto_configure_warning( "neither 'TMP' nor 'TEMP' environment variables are set, using '%s' as default" % tmp, ) return tmp def _get_escaped_windows_msys_starlark_content(repository_ctx, use_mingw = False): """Return the content of msys cc toolchain rule.""" msys_root = "" bazel_sh = _get_path_env_var(repository_ctx, "BAZEL_SH") if bazel_sh: bazel_sh = bazel_sh.replace("\\", "/").lower() tokens = bazel_sh.rsplit("/", 1) if tokens[0].endswith("/usr/bin"): msys_root = tokens[0][:len(tokens[0]) - len("usr/bin")] elif tokens[0].endswith("/bin"): msys_root = tokens[0][:len(tokens[0]) - len("bin")] prefix = "mingw64" if use_mingw else "usr" tool_path_prefix = escape_string(msys_root) + prefix tool_bin_path = tool_path_prefix + "/bin" tool_path = {} for tool in ["ar", "cpp", "dwp", "gcc", "gcov", "ld", "nm", "objcopy", "objdump", "strip"]: if msys_root: tool_path[tool] = tool_bin_path + "/" + tool else: tool_path[tool] = "msys_gcc_installation_error.bat" tool_paths = ",\n ".join(['"%s": "%s"' % (k, v) for k, v in tool_path.items()]) include_directories = (' "%s/",\n ' % tool_path_prefix) if msys_root else "" return tool_paths, tool_bin_path, include_directories def _get_system_root(repository_ctx): """Get System root path on Windows, default is C:\\Windows. Doesn't %-escape the result.""" systemroot = _get_path_env_var(repository_ctx, "SYSTEMROOT") if not systemroot: systemroot = "C:\\Windows" auto_configure_warning_maybe( repository_ctx, "SYSTEMROOT is not set, using default SYSTEMROOT=C:\\Windows", ) return escape_string(systemroot) def _add_system_root(repository_ctx, env): """Running VCVARSALL.BAT and VCVARSQUERYREGISTRY.BAT need %SYSTEMROOT%\\\\system32 in PATH.""" env_key, env_value = _lookup_env_var(env, "PATH", default = "") env[env_key] = env_value + ";" + _get_system_root(repository_ctx) + "\\system32" return env def find_vc_path(repository_ctx): """Find Visual C++ build tools install path. Doesn't %-escape the result. Args: repository_ctx: The repository context. Returns: The path to the Visual C++ build tools installation. """ # 1. Check if BAZEL_VC or BAZEL_VS is already set by user. bazel_vc = _get_path_env_var(repository_ctx, "BAZEL_VC") if bazel_vc: if repository_ctx.path(bazel_vc).exists: return bazel_vc else: auto_configure_warning_maybe( repository_ctx, "%BAZEL_VC% is set to non-existent path, ignoring.", ) bazel_vs = _get_path_env_var(repository_ctx, "BAZEL_VS") if bazel_vs: if repository_ctx.path(bazel_vs).exists: bazel_vc = bazel_vs + "\\VC" if repository_ctx.path(bazel_vc).exists: return bazel_vc else: auto_configure_warning_maybe( repository_ctx, "No 'VC' directory found under %BAZEL_VS%, ignoring.", ) else: auto_configure_warning_maybe( repository_ctx, "%BAZEL_VS% is set to non-existent path, ignoring.", ) auto_configure_warning_maybe( repository_ctx, "Neither %BAZEL_VC% nor %BAZEL_VS% are set, start looking for the latest Visual C++" + " installed.", ) # 2. Use vswhere to locate all Visual Studio installations program_files_dir = _get_path_env_var(repository_ctx, "PROGRAMFILES(X86)") if not program_files_dir: program_files_dir = "C:\\Program Files (x86)" auto_configure_warning_maybe( repository_ctx, "'PROGRAMFILES(X86)' environment variable is not set, using '%s' as default" % program_files_dir, ) vswhere_binary = program_files_dir + "\\Microsoft Visual Studio\\Installer\\vswhere.exe" if repository_ctx.path(vswhere_binary).exists: result = repository_ctx.execute([vswhere_binary, "-requires", "Microsoft.VisualStudio.Component.VC.Tools.x86.x64", "-property", "installationPath", "-latest"]) auto_configure_warning_maybe(repository_ctx, "vswhere query result:\n\nSTDOUT(start)\n%s\nSTDOUT(end)\nSTDERR(start):\n%s\nSTDERR(end)\n" % (result.stdout, result.stderr)) installation_path = result.stdout.strip() if not result.stderr and installation_path: vc_dir = installation_path + "\\VC" auto_configure_warning_maybe(repository_ctx, "Visual C++ build tools found at %s" % vc_dir) return vc_dir # 3. Check if VS%VS_VERSION%COMNTOOLS is set, if true then try to find and use # vcvarsqueryregistry.bat / VsDevCmd.bat to detect VC++. auto_configure_warning_maybe(repository_ctx, "Looking for VS%VERSION%COMNTOOLS environment variables, " + "eg. VS140COMNTOOLS") for vscommontools_env, script in [ ("VS160COMNTOOLS", "VsDevCmd.bat"), ("VS150COMNTOOLS", "VsDevCmd.bat"), ("VS140COMNTOOLS", "vcvarsqueryregistry.bat"), ("VS120COMNTOOLS", "vcvarsqueryregistry.bat"), ("VS110COMNTOOLS", "vcvarsqueryregistry.bat"), ("VS100COMNTOOLS", "vcvarsqueryregistry.bat"), ("VS90COMNTOOLS", "vcvarsqueryregistry.bat"), ]: path = _get_path_env_var(repository_ctx, vscommontools_env) if path == None: continue script = path + "\\" + script if not repository_ctx.path(script).exists: continue repository_ctx.file( "get_vc_dir.bat", "@echo off\n" + "call \"" + script + "\" > NUL\n" + "echo %VCINSTALLDIR%", True, ) env = _add_system_root(repository_ctx, repository_ctx.os.environ) vc_dir = execute(repository_ctx, ["./get_vc_dir.bat"], environment = env) auto_configure_warning_maybe(repository_ctx, "Visual C++ build tools found at %s" % vc_dir) return vc_dir # 4. User might have purged all environment variables. If so, look for Visual C++ in registry. # Works for Visual Studio 2017 and older. (Does not work for Visual Studio 2019 Preview.) auto_configure_warning_maybe(repository_ctx, "Looking for Visual C++ through registry") reg_binary = _get_system_root(repository_ctx) + "\\system32\\reg.exe" vc_dir = None for key, suffix in (("VC7", ""), ("VS7", "\\VC")): for version in ["15.0", "14.0", "12.0", "11.0", "10.0", "9.0", "8.0"]: if vc_dir: break result = repository_ctx.execute([reg_binary, "query", "HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\VisualStudio\\SxS\\" + key, "/v", version]) auto_configure_warning_maybe(repository_ctx, "registry query result for VC %s:\n\nSTDOUT(start)\n%s\nSTDOUT(end)\nSTDERR(start):\n%s\nSTDERR(end)\n" % (version, result.stdout, result.stderr)) if not result.stderr: for line in result.stdout.split("\n"): line = line.strip() if line.startswith(version) and line.find("REG_SZ") != -1: vc_dir = line[line.find("REG_SZ") + len("REG_SZ"):].strip() + suffix if vc_dir: auto_configure_warning_maybe(repository_ctx, "Visual C++ build tools found at %s" % vc_dir) return vc_dir # 5. Check default directories for VC installation auto_configure_warning_maybe(repository_ctx, "Looking for default Visual C++ installation directory") for path in [ "Microsoft Visual Studio\\%s\\%s\\VC" % (year, edition) for year in (2022, 2019, 2017) for edition in ("Preview", "BuildTools", "Community", "Professional", "Enterprise") ] + [ "Microsoft Visual Studio 14.0\\VC", ]: path = program_files_dir + "\\" + path if repository_ctx.path(path).exists: vc_dir = path break if not vc_dir: auto_configure_warning_maybe(repository_ctx, "Visual C++ build tools not found.") return None auto_configure_warning_maybe(repository_ctx, "Visual C++ build tools found at %s" % vc_dir) return vc_dir def _is_vs_2017_or_newer(repository_ctx, vc_path): """Check if the installed VS version is Visual Studio 2017 or newer.""" # For VS 2017 and later, a `Tools` directory should exist under `BAZEL_VC` return repository_ctx.path(vc_path).get_child("Tools").exists def _is_msbuildtools(vc_path): """Check if the installed VC version is from MSBuildTools.""" # In MSBuildTools (usually container setup), the location of VC is like: # C:\BuildTools\MSBuild\Microsoft\VC return vc_path.find("BuildTools") != -1 and vc_path.find("MSBuild") != -1 def _find_vcvars_bat_script(repository_ctx, vc_path): """Find batch script to set up environment variables for VC. Doesn't %-escape the result.""" if _is_vs_2017_or_newer(repository_ctx, vc_path): vcvars_script = vc_path + "\\Auxiliary\\Build\\VCVARSALL.BAT" else: vcvars_script = vc_path + "\\VCVARSALL.BAT" if not repository_ctx.path(vcvars_script).exists: return None return vcvars_script def _is_support_vcvars_ver(vc_full_version): """-vcvars_ver option is supported from version 14.11.25503 (VS 2017 version 15.3).""" version = [int(i) for i in vc_full_version.split(".")] min_version = [14, 11, 25503] return version >= min_version def _is_support_winsdk_selection(repository_ctx, vc_path): """Windows SDK selection is supported with VC 2017 / 2019 or with full VS 2015 installation.""" if _is_vs_2017_or_newer(repository_ctx, vc_path): return True # By checking the source code of VCVARSALL.BAT in VC 2015, we know that # when devenv.exe or wdexpress.exe exists, VCVARSALL.BAT supports Windows SDK selection. vc_common_ide = repository_ctx.path(vc_path).dirname.get_child("Common7", "IDE") for tool in ["devenv.exe", "wdexpress.exe"]: if vc_common_ide.get_child(tool).exists: return True return False def _get_vc_env_vars(repository_ctx, vc_path, msvc_vars_x64, target_arch): """Derive the environment variables set of a given target architecture from the environment variables of the x64 target. This is done to avoid running VCVARSALL.BAT script for every target architecture. Args: repository_ctx: the repository_ctx object vc_path: Visual C++ root directory msvc_vars_x64: values of MSVC toolchain including the environment variables for x64 target architecture target_arch: the target architecture to get its environment variables Returns: dictionary of envvars """ env = {} if _is_vs_2017_or_newer(repository_ctx, vc_path): lib = msvc_vars_x64["%{msvc_env_lib_x64}"] full_version = _get_vc_full_version(repository_ctx, vc_path) tools_path = "%s\\Tools\\MSVC\\%s\\bin\\HostX64\\%s" % (vc_path, full_version, target_arch) # For native windows(10) on arm64 builds host toolchain runs in an emulated x86 environment if not repository_ctx.path(tools_path).exists: tools_path = "%s\\Tools\\MSVC\\%s\\bin\\HostX86\\%s" % (vc_path, full_version, target_arch) else: lib = msvc_vars_x64["%{msvc_env_lib_x64}"].replace("amd64", _targets_lib_folder[target_arch]) tools_path = vc_path + "\\bin\\" + _targets_archs[target_arch] env["INCLUDE"] = msvc_vars_x64["%{msvc_env_include_x64}"] env["LIB"] = lib.replace("x64", target_arch) env["PATH"] = escape_string(tools_path.replace("\\", "\\\\")) + ";" + msvc_vars_x64["%{msvc_env_path_x64}"] return env def setup_vc_env_vars(repository_ctx, vc_path, envvars = [], allow_empty = False, escape = True): """Get environment variables set by VCVARSALL.BAT script. Doesn't %-escape the result! Args: repository_ctx: the repository_ctx object vc_path: Visual C++ root directory envvars: list of envvars to retrieve; default is ["PATH", "INCLUDE", "LIB", "WINDOWSSDKDIR"] allow_empty: allow unset envvars; if False then report errors for those escape: if True, escape "\" as "\\" and "%" as "%%" in the envvar values Returns: dictionary of the envvars """ if not envvars: envvars = ["PATH", "INCLUDE", "LIB", "WINDOWSSDKDIR"] vcvars_script = _find_vcvars_bat_script(repository_ctx, vc_path) if not vcvars_script: auto_configure_fail("Cannot find VCVARSALL.BAT script under %s" % vc_path) # Getting Windows SDK version set by user. # Only supports VC 2017 & 2019 and VC 2015 with full VS installation. winsdk_version = _get_winsdk_full_version(repository_ctx) if winsdk_version and not _is_support_winsdk_selection(repository_ctx, vc_path): auto_configure_warning(("BAZEL_WINSDK_FULL_VERSION=%s is ignored, " + "because standalone Visual C++ Build Tools 2015 doesn't support specifying Windows " + "SDK version, please install the full VS 2015 or use VC 2017/2019.") % winsdk_version) winsdk_version = "" # Get VC version set by user. Only supports VC 2017 & 2019. vcvars_ver = "" if _is_vs_2017_or_newer(repository_ctx, vc_path): full_version = _get_vc_full_version(repository_ctx, vc_path) # Because VCVARSALL.BAT is from the latest VC installed, so we check if the latest # version supports -vcvars_ver or not. if _is_support_vcvars_ver(_get_latest_subversion(repository_ctx, vc_path)): vcvars_ver = "-vcvars_ver=" + full_version cmd = "\"%s\" amd64 %s %s" % (vcvars_script, winsdk_version, vcvars_ver) print_envvars = ",".join(["{k}=%{k}%".format(k = k) for k in envvars]) repository_ctx.file( "get_env.bat", "@echo off\n" + ("call %s > NUL \n" % cmd) + ("echo %s \n" % print_envvars), True, ) env = _add_system_root(repository_ctx, {k: "" for k in envvars}) envs = execute(repository_ctx, ["./get_env.bat"], environment = env).split(",") env_map = {} for env in envs: key, value = env.split("=", 1) env_map[key] = escape_string(value.replace("\\", "\\\\")) if escape else value if not allow_empty: _check_env_vars(env_map, cmd, expected = envvars) return env_map def _check_env_vars(env_map, cmd, expected): for env in expected: if not env_map.get(env): auto_configure_fail( "Setting up VC environment variables failed, %s is not set by the following command:\n %s" % (env, cmd), ) def _get_latest_subversion(repository_ctx, vc_path): """Get the latest subversion of a VS 2017/2019 installation. For VS 2017 & 2019, there could be multiple versions of VC build tools. The directories are like: \\Tools\\MSVC\\14.10.24930\\bin\\HostX64\\x64 \\Tools\\MSVC\\14.16.27023\\bin\\HostX64\\x64 This function should return 14.16.27023 in this case.""" versions = [path.basename for path in repository_ctx.path(vc_path + "\\Tools\\MSVC").readdir()] if len(versions) < 1: auto_configure_warning_maybe(repository_ctx, "Cannot find any VC installation under BAZEL_VC(%s)" % vc_path) return None # Parse the version string into integers, then sort the integers to prevent textual sorting. version_list = [] for version in versions: parts = [int(i) for i in version.split(".")] version_list.append((parts, version)) version_list = sorted(version_list) latest_version = version_list[-1][1] auto_configure_warning_maybe(repository_ctx, "Found the following VC versions:\n%s\n\nChoosing the latest version = %s" % ("\n".join(versions), latest_version)) return latest_version def _get_vc_full_version(repository_ctx, vc_path): """Return the value of BAZEL_VC_FULL_VERSION if defined, otherwise the latest version.""" version = _get_env_var(repository_ctx, "BAZEL_VC_FULL_VERSION") if version != None: return version return _get_latest_subversion(repository_ctx, vc_path) def _get_winsdk_full_version(repository_ctx): """Return the value of BAZEL_WINSDK_FULL_VERSION if defined, otherwise an empty string.""" return _get_env_var(repository_ctx, "BAZEL_WINSDK_FULL_VERSION", default = "") def _find_msvc_tools(repository_ctx, vc_path, target_arch = "x64"): """Find the exact paths of the build tools in MSVC for the given target. Doesn't %-escape the result.""" build_tools_paths = {} tools = _get_target_tools(target_arch) for tool_name in tools: build_tools_paths[tool_name] = find_msvc_tool(repository_ctx, vc_path, tools[tool_name], target_arch) return build_tools_paths def find_msvc_tool(repository_ctx, vc_path, tool, target_arch = "x64"): """Find the exact path of a specific build tool in MSVC. Doesn't %-escape the result. Args: repository_ctx: The repository context. vc_path: Visual C++ root directory. tool: The name of the tool to find. target_arch: The target architecture (default is "x64"). Returns: The exact path of the specified build tool in MSVC, or None if not found. """ tool_path = None if _is_vs_2017_or_newer(repository_ctx, vc_path) or _is_msbuildtools(vc_path): full_version = _get_vc_full_version(repository_ctx, vc_path) if full_version: tool_path = "%s\\Tools\\MSVC\\%s\\bin\\HostX64\\%s\\%s" % (vc_path, full_version, target_arch, tool) # For native windows(10) on arm64 builds host toolchain runs in an emulated x86 environment if not repository_ctx.path(tool_path).exists: tool_path = "%s\\Tools\\MSVC\\%s\\bin\\HostX86\\%s\\%s" % (vc_path, full_version, target_arch, tool) else: # For VS 2015 and older version, the tools are under: # C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\amd64 tool_path = vc_path + "\\bin\\" + _targets_archs[target_arch] + "\\" + tool if not tool_path or not repository_ctx.path(tool_path).exists: return None return tool_path.replace("\\", "/") def _find_missing_vc_tools(repository_ctx, vc_path, target_arch = "x64"): """Check if any required tool for the given target architecture is missing under given VC path.""" missing_tools = [] if not _find_vcvars_bat_script(repository_ctx, vc_path): missing_tools.append("VCVARSALL.BAT") tools = _get_target_tools(target_arch) for tool_name in tools: if not find_msvc_tool(repository_ctx, vc_path, tools[tool_name], target_arch): missing_tools.append(tools[tool_name]) return missing_tools def _get_target_tools(target): """Return a list of required tools names and their filenames for a certain target.""" tools = { "arm": {"CL": "cl.exe", "DUMPBIN": "dumpbin.exe", "LIB": "lib.exe", "LINK": "link.exe"}, "arm64": {"CL": "cl.exe", "DUMPBIN": "dumpbin.exe", "LIB": "lib.exe", "LINK": "link.exe"}, "x64": {"CL": "cl.exe", "DUMPBIN": "dumpbin.exe", "LIB": "lib.exe", "LINK": "link.exe", "ML": "ml64.exe"}, "x86": {"CL": "cl.exe", "DUMPBIN": "dumpbin.exe", "LIB": "lib.exe", "LINK": "link.exe", "ML": "ml.exe"}, } if tools.get(target) == None: auto_configure_fail("Target architecture %s is not recognized" % target) return tools.get(target) def _is_support_debug_fastlink(repository_ctx, linker): """Run linker alone to see if it supports /DEBUG:FASTLINK.""" if _use_clang_cl(repository_ctx): # LLVM's lld-link.exe doesn't support /DEBUG:FASTLINK. return False result = execute(repository_ctx, [linker], expect_failure = True) return result.find("/DEBUG[:{FASTLINK|FULL|NONE}]") != -1 def _is_support_parse_showincludes(repository_ctx, cl, env): repository_ctx.file( "main.cpp", "#include \"bazel_showincludes.h\"\nint main(){}\n", ) repository_ctx.file( "bazel_showincludes.h", "\n", ) result = execute( repository_ctx, [cl, "/nologo", "/showIncludes", "/c", "main.cpp", "/out", "main.exe", "/Fo", "main.obj"], # Attempt to force English language. This may fail if the language pack isn't installed. environment = env | {"VSLANG": "1033"}, ) for file in ["main.cpp", "bazel_showincludes.h", "main.exe", "main.obj"]: execute(repository_ctx, ["cmd", "/C", "del", file], expect_empty_output = True) return any([ line.startswith("Note: including file:") and line.endswith("bazel_showincludes.h") for line in result.split("\n") ]) def find_llvm_path(repository_ctx): """Find LLVM install path. Args: repository_ctx: The repository context. Returns: The path to the LLVM installation, or None if not found. """ # 1. Check if BAZEL_LLVM is already set by user. bazel_llvm = _get_path_env_var(repository_ctx, "BAZEL_LLVM") if bazel_llvm: return bazel_llvm auto_configure_warning_maybe(repository_ctx, "'BAZEL_LLVM' is not set, " + "start looking for LLVM installation on machine.") # 2. Look for LLVM installation through registry. auto_configure_warning_maybe(repository_ctx, "Looking for LLVM installation through registry") reg_binary = _get_system_root(repository_ctx) + "\\system32\\reg.exe" llvm_dir = None result = repository_ctx.execute([reg_binary, "query", "HKEY_LOCAL_MACHINE\\SOFTWARE\\WOW6432Node\\LLVM\\LLVM"]) auto_configure_warning_maybe(repository_ctx, "registry query result for LLVM:\n\nSTDOUT(start)\n%s\nSTDOUT(end)\nSTDERR(start):\n%s\nSTDERR(end)\n" % (result.stdout, result.stderr)) if not result.stderr: for line in result.stdout.split("\n"): line = line.strip() if line.startswith("(Default)") and line.find("REG_SZ") != -1: llvm_dir = line[line.find("REG_SZ") + len("REG_SZ"):].strip() if llvm_dir: auto_configure_warning_maybe(repository_ctx, "LLVM installation found at %s" % llvm_dir) return llvm_dir # 3. Check default directories for LLVM installation auto_configure_warning_maybe(repository_ctx, "Looking for default LLVM installation directory") program_files_dir = _get_path_env_var(repository_ctx, "PROGRAMFILES") if not program_files_dir: program_files_dir = "C:\\Program Files" auto_configure_warning_maybe( repository_ctx, "'PROGRAMFILES' environment variable is not set, using '%s' as default" % program_files_dir, ) path = program_files_dir + "\\LLVM" if repository_ctx.path(path).exists: llvm_dir = path if not llvm_dir: auto_configure_warning_maybe(repository_ctx, "LLVM installation not found.") return None auto_configure_warning_maybe(repository_ctx, "LLVM installation found at %s" % llvm_dir) return llvm_dir def find_llvm_tool(repository_ctx, llvm_path, tool): """Find the exact path of a specific build tool in LLVM. Doesn't %-escape the result. Args: repository_ctx: The repository context. llvm_path: The path to the LLVM installation. tool: The name of the tool to find. Returns: The exact path of the specified build tool in LLVM, or None if not found. """ tool_path = llvm_path + "\\bin\\" + tool if not repository_ctx.path(tool_path).exists: return None return tool_path.replace("\\", "/") def _use_clang_cl(repository_ctx): """Returns True if USE_CLANG_CL is set to 1.""" return _get_env_var(repository_ctx, "USE_CLANG_CL", default = "0") == "1" def _find_missing_llvm_tools(repository_ctx, llvm_path): """Check if any required tool is missing under given LLVM path.""" missing_tools = [] for tool in ["clang-cl.exe", "lld-link.exe", "llvm-lib.exe"]: if not find_llvm_tool(repository_ctx, llvm_path, tool): missing_tools.append(tool) return missing_tools def _get_clang_version(repository_ctx, clang_cl): result = repository_ctx.execute([clang_cl, "-v"]) first_line = result.stderr.strip().splitlines()[0].strip() # The first line of stderr should look like "[vendor ]clang version X.X.X" if result.return_code != 0 or first_line.find("clang version ") == -1: auto_configure_fail("Failed to get clang version by running \"%s -v\"" % clang_cl) return first_line.split(" ")[-1] def _get_clang_dir(repository_ctx, llvm_path, clang_version): """Get the clang installation directory.""" # The clang_version string format is "X.X.X" clang_dir = llvm_path + "\\lib\\clang\\" + clang_version if repository_ctx.path(clang_dir).exists: return clang_dir # Clang 16 changed the install path to use just the major number. clang_major_version = clang_version.split(".")[0] return llvm_path + "\\lib\\clang\\" + clang_major_version def _get_msys_mingw_vars(repository_ctx): """Get the variables we need to populate the msys/mingw toolchains.""" tool_paths, tool_bin_path, inc_dir_msys = _get_escaped_windows_msys_starlark_content(repository_ctx) tool_paths_mingw, tool_bin_path_mingw, inc_dir_mingw = _get_escaped_windows_msys_starlark_content(repository_ctx, use_mingw = True) write_builtin_include_directory_paths(repository_ctx, "mingw", [inc_dir_mingw], file_suffix = "_mingw") msys_mingw_vars = { "%{cxx_builtin_include_directories}": inc_dir_msys, "%{mingw_cxx_builtin_include_directories}": inc_dir_mingw, "%{mingw_tool_bin_path}": tool_bin_path_mingw, "%{mingw_tool_paths}": tool_paths_mingw, "%{tool_bin_path}": tool_bin_path, "%{tool_paths}": tool_paths, } return msys_mingw_vars def _get_msvc_vars(repository_ctx, paths, target_arch = "x64", msvc_vars_x64 = None): """Get the variables we need to populate the MSVC toolchains.""" msvc_vars = dict() vc_path = find_vc_path(repository_ctx) missing_tools = None if not vc_path: repository_ctx.template( "vc_installation_error_" + target_arch + ".bat", paths["@rules_cc//cc/private/toolchain:vc_installation_error.bat.tpl"], {"%{vc_error_message}": ""}, ) else: missing_tools = _find_missing_vc_tools(repository_ctx, vc_path, target_arch) if missing_tools: message = "\r\n".join([ "echo. 1>&2", "echo Visual C++ build tools seems to be installed at %s 1>&2" % vc_path, "echo But Bazel can't find the following tools: 1>&2", "echo %s 1>&2" % ", ".join(missing_tools), "echo for %s target architecture 1>&2" % target_arch, "echo. 1>&2", ]) repository_ctx.template( "vc_installation_error_" + target_arch + ".bat", paths["@rules_cc//cc/private/toolchain:vc_installation_error.bat.tpl"], {"%{vc_error_message}": message}, ) if not vc_path or missing_tools: write_builtin_include_directory_paths(repository_ctx, "msvc", [], file_suffix = "_msvc") msvc_vars = { "%{msvc_env_tmp_" + target_arch + "}": "msvc_not_found", "%{msvc_env_include_" + target_arch + "}": "msvc_not_found", "%{msvc_cxx_builtin_include_directories_" + target_arch + "}": "", "%{msvc_env_path_" + target_arch + "}": "msvc_not_found", "%{msvc_env_lib_" + target_arch + "}": "msvc_not_found", "%{msvc_cl_path_" + target_arch + "}": "vc_installation_error_" + target_arch + ".bat", "%{msvc_ml_path_" + target_arch + "}": "vc_installation_error_" + target_arch + ".bat", "%{msvc_link_path_" + target_arch + "}": "vc_installation_error_" + target_arch + ".bat", "%{msvc_lib_path_" + target_arch + "}": "vc_installation_error_" + target_arch + ".bat", "%{dbg_mode_debug_flag_" + target_arch + "}": "/DEBUG", "%{fastbuild_mode_debug_flag_" + target_arch + "}": "/DEBUG", "%{msvc_parse_showincludes_" + target_arch + "}": repr(False), } return msvc_vars if msvc_vars_x64: env = _get_vc_env_vars(repository_ctx, vc_path, msvc_vars_x64, target_arch) else: env = setup_vc_env_vars(repository_ctx, vc_path) escaped_tmp_dir = escape_string(_get_temp_env(repository_ctx).replace("\\", "\\\\")) escaped_include_paths = escape_string(env["INCLUDE"]) build_tools = {} llvm_path = "" if _use_clang_cl(repository_ctx): llvm_path = find_llvm_path(repository_ctx) if not llvm_path: auto_configure_fail("\nUSE_CLANG_CL is set to 1, but Bazel cannot find Clang installation on your system.\n" + "Please install Clang via http://releases.llvm.org/download.html\n") build_tools["CL"] = find_llvm_tool(repository_ctx, llvm_path, "clang-cl.exe") build_tools["ML"] = find_msvc_tool(repository_ctx, vc_path, "ml64.exe", "x64") build_tools["LINK"] = find_llvm_tool(repository_ctx, llvm_path, "lld-link.exe") if not build_tools["LINK"]: build_tools["LINK"] = find_msvc_tool(repository_ctx, vc_path, "link.exe", "x64") build_tools["LIB"] = find_llvm_tool(repository_ctx, llvm_path, "llvm-lib.exe") if not build_tools["LIB"]: build_tools["LIB"] = find_msvc_tool(repository_ctx, vc_path, "lib.exe", "x64") else: build_tools = _find_msvc_tools(repository_ctx, vc_path, target_arch) escaped_cxx_include_directories = [] for path in escaped_include_paths.split(";"): if path: escaped_cxx_include_directories.append("\"%s\"" % path) if llvm_path: clang_version = _get_clang_version(repository_ctx, build_tools["CL"]) clang_dir = _get_clang_dir(repository_ctx, llvm_path, clang_version) clang_include_path = (clang_dir + "\\include").replace("\\", "\\\\") escaped_cxx_include_directories.append("\"%s\"" % clang_include_path) clang_lib_path = (clang_dir + "\\lib\\windows").replace("\\", "\\\\") env["LIB"] = escape_string(env["LIB"]) + ";" + clang_lib_path support_debug_fastlink = _is_support_debug_fastlink(repository_ctx, build_tools["LINK"]) write_builtin_include_directory_paths(repository_ctx, "msvc", escaped_cxx_include_directories, file_suffix = "_msvc") support_parse_showincludes = _is_support_parse_showincludes(repository_ctx, build_tools["CL"], env) if not support_parse_showincludes: auto_configure_warning(""" Header pruning has been disabled since Bazel failed to recognize the output of /showIncludes. This can result in unnecessary recompilation. Fix this by installing the English language pack for the Visual Studio installation at {} and run 'bazel sync --configure'.""".format(vc_path)) msvc_vars = { "%{msvc_env_tmp_" + target_arch + "}": escaped_tmp_dir, "%{msvc_env_include_" + target_arch + "}": escaped_include_paths, "%{msvc_cxx_builtin_include_directories_" + target_arch + "}": " " + ",\n ".join(escaped_cxx_include_directories), "%{msvc_env_path_" + target_arch + "}": escape_string(env["PATH"]), "%{msvc_env_lib_" + target_arch + "}": escape_string(env["LIB"]), "%{msvc_cl_path_" + target_arch + "}": build_tools["CL"], "%{msvc_ml_path_" + target_arch + "}": build_tools.get("ML", "msvc_arm_toolchain_does_not_support_ml"), "%{msvc_link_path_" + target_arch + "}": build_tools["LINK"], "%{msvc_lib_path_" + target_arch + "}": build_tools["LIB"], "%{msvc_dumpbin_path_" + target_arch + "}": build_tools["DUMPBIN"], "%{msvc_parse_showincludes_" + target_arch + "}": repr(support_parse_showincludes), "%{dbg_mode_debug_flag_" + target_arch + "}": "/DEBUG:FULL" if support_debug_fastlink else "/DEBUG", "%{fastbuild_mode_debug_flag_" + target_arch + "}": "/DEBUG:FASTLINK" if support_debug_fastlink else "/DEBUG", } return msvc_vars def _get_clang_cl_vars(repository_ctx, paths, msvc_vars, target_arch): """Get the variables we need to populate the clang-cl toolchains.""" llvm_path = find_llvm_path(repository_ctx) error_script = None if msvc_vars["%{msvc_cl_path_" + target_arch + "}"] == "vc_installation_error_{}.bat".format(target_arch): error_script = "vc_installation_error_{}.bat".format(target_arch) elif not llvm_path: repository_ctx.template( "clang_installation_error.bat", paths["@rules_cc//cc/private/toolchain:clang_installation_error.bat.tpl"], {"%{clang_error_message}": ""}, ) error_script = "clang_installation_error.bat" else: missing_tools = _find_missing_llvm_tools(repository_ctx, llvm_path) if missing_tools: message = "\r\n".join([ "echo. 1>&2", "echo LLVM/Clang seems to be installed at %s 1>&2" % llvm_path, "echo But Bazel can't find the following tools: 1>&2", "echo %s 1>&2" % ", ".join(missing_tools), "echo. 1>&2", ]) repository_ctx.template( "clang_installation_error.bat", paths["@rules_cc//cc/private/toolchain:clang_installation_error.bat.tpl"], {"%{clang_error_message}": message}, ) error_script = "clang_installation_error.bat" if error_script: write_builtin_include_directory_paths(repository_ctx, "clang-cl", [], file_suffix = "_clangcl") clang_cl_vars = { "%{clang_cl_env_tmp_" + target_arch + "}": "clang_cl_not_found", "%{clang_cl_env_path_" + target_arch + "}": "clang_cl_not_found", "%{clang_cl_env_include_" + target_arch + "}": "clang_cl_not_found", "%{clang_cl_env_lib_" + target_arch + "}": "clang_cl_not_found", "%{clang_cl_cl_path_" + target_arch + "}": error_script, "%{clang_cl_link_path_" + target_arch + "}": error_script, "%{clang_cl_lib_path_" + target_arch + "}": error_script, "%{clang_cl_ml_path_" + target_arch + "}": error_script, "%{clang_cl_dbg_mode_debug_flag_" + target_arch + "}": "/DEBUG", "%{clang_cl_fastbuild_mode_debug_flag_" + target_arch + "}": "/DEBUG", "%{clang_cl_cxx_builtin_include_directories_" + target_arch + "}": "", "%{clang_cl_parse_showincludes_" + target_arch + "}": repr(False), } return clang_cl_vars clang_cl_path = find_llvm_tool(repository_ctx, llvm_path, "clang-cl.exe") lld_link_path = find_llvm_tool(repository_ctx, llvm_path, "lld-link.exe") llvm_lib_path = find_llvm_tool(repository_ctx, llvm_path, "llvm-lib.exe") clang_version = _get_clang_version(repository_ctx, clang_cl_path) clang_dir = _get_clang_dir(repository_ctx, llvm_path, clang_version) clang_include_path = (clang_dir + "\\include").replace("\\", "\\\\") clang_lib_path = (clang_dir + "\\lib\\windows").replace("\\", "\\\\") clang_cl_include_directories = msvc_vars["%{msvc_cxx_builtin_include_directories_" + target_arch + "}"] + (",\n \"%s\"" % clang_include_path) write_builtin_include_directory_paths(repository_ctx, "clang-cl", [clang_cl_include_directories], file_suffix = "_clangcl") clang_cl_vars = { "%{clang_cl_env_tmp_" + target_arch + "}": msvc_vars["%{msvc_env_tmp_" + target_arch + "}"], "%{clang_cl_env_path_" + target_arch + "}": msvc_vars["%{msvc_env_path_" + target_arch + "}"], "%{clang_cl_env_include_" + target_arch + "}": msvc_vars["%{msvc_env_include_" + target_arch + "}"] + ";" + clang_include_path, "%{clang_cl_env_lib_" + target_arch + "}": msvc_vars["%{msvc_env_lib_" + target_arch + "}"] + ";" + clang_lib_path, "%{clang_cl_cxx_builtin_include_directories_" + target_arch + "}": clang_cl_include_directories, "%{clang_cl_cl_path_" + target_arch + "}": clang_cl_path, "%{clang_cl_link_path_" + target_arch + "}": lld_link_path, "%{clang_cl_lib_path_" + target_arch + "}": llvm_lib_path, # clang-cl does not support assembly files as input. "%{clang_cl_ml_path_" + target_arch + "}": msvc_vars["%{msvc_ml_path_" + target_arch + "}"], # LLVM's lld-link.exe doesn't support /DEBUG:FASTLINK. "%{clang_cl_dbg_mode_debug_flag_" + target_arch + "}": "/DEBUG", "%{clang_cl_fastbuild_mode_debug_flag_" + target_arch + "}": "/DEBUG", # clang-cl always emits the English language version of the /showIncludes prefix. "%{clang_cl_parse_showincludes_" + target_arch + "}": repr(True), } return clang_cl_vars def _get_msvc_deps_scanner_vars(repository_ctx, paths, template_vars, target_arch = "x64"): repository_ctx.template( "msvc_deps_scanner_wrapper_" + target_arch + ".bat", paths["@rules_cc//cc/private/toolchain:msvc_deps_scanner_wrapper.bat.tpl"], { "%{cc}": template_vars["%{msvc_cl_path_" + target_arch + "}"], }, ) return { "%{msvc_deps_scanner_wrapper_path_" + target_arch + "}": "msvc_deps_scanner_wrapper_" + target_arch + ".bat", } def configure_windows_toolchain(repository_ctx): """Configure C++ toolchain on Windows. Args: repository_ctx: The repository context. """ paths = resolve_labels(repository_ctx, [ "@rules_cc//cc/private/toolchain:BUILD.windows.tpl", "@rules_cc//cc/private/toolchain:windows_cc_toolchain_config.bzl", "@rules_cc//cc/private/toolchain:armeabi_cc_toolchain_config.bzl", "@rules_cc//cc/private/toolchain:vc_installation_error.bat.tpl", "@rules_cc//cc/private/toolchain:msys_gcc_installation_error.bat", "@rules_cc//cc/private/toolchain:clang_installation_error.bat.tpl", "@rules_cc//cc/private/toolchain:msvc_deps_scanner_wrapper.bat.tpl", ]) repository_ctx.symlink( paths["@rules_cc//cc/private/toolchain:windows_cc_toolchain_config.bzl"], "windows_cc_toolchain_config.bzl", ) repository_ctx.symlink( paths["@rules_cc//cc/private/toolchain:armeabi_cc_toolchain_config.bzl"], "armeabi_cc_toolchain_config.bzl", ) repository_ctx.symlink( paths["@rules_cc//cc/private/toolchain:msys_gcc_installation_error.bat"], "msys_gcc_installation_error.bat", ) template_vars = dict() msvc_vars_x64 = _get_msvc_vars(repository_ctx, paths, "x64") template_vars.update(msvc_vars_x64) template_vars.update(_get_clang_cl_vars(repository_ctx, paths, msvc_vars_x64, "x64")) template_vars.update(_get_msys_mingw_vars(repository_ctx)) template_vars.update(_get_msvc_vars(repository_ctx, paths, "x86", msvc_vars_x64)) template_vars.update(_get_msvc_vars(repository_ctx, paths, "arm", msvc_vars_x64)) msvc_vars_arm64 = _get_msvc_vars(repository_ctx, paths, "arm64", msvc_vars_x64) template_vars.update(msvc_vars_arm64) template_vars.update(_get_clang_cl_vars(repository_ctx, paths, msvc_vars_arm64, "arm64")) template_vars.update(_get_msvc_deps_scanner_vars(repository_ctx, paths, template_vars, "x64")) template_vars.update(_get_msvc_deps_scanner_vars(repository_ctx, paths, template_vars, "x86")) template_vars.update(_get_msvc_deps_scanner_vars(repository_ctx, paths, template_vars, "arm")) template_vars.update(_get_msvc_deps_scanner_vars(repository_ctx, paths, template_vars, "arm64")) repository_ctx.template( "BUILD", paths["@rules_cc//cc/private/toolchain:BUILD.windows.tpl"], template_vars, ) rules_cc-0.0.11/cc/private/toolchain/windows_cc_toolchain_config.bzl000066400000000000000000001743441470072561500256700ustar00rootroot00000000000000# Copyright 2019 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. """A Starlark cc_toolchain configuration rule for Windows""" load("@rules_cc//cc:action_names.bzl", "ACTION_NAMES") load( "@rules_cc//cc:cc_toolchain_config_lib.bzl", "action_config", "artifact_name_pattern", "env_entry", "env_set", "feature", "flag_group", "flag_set", "make_variable", "tool", "tool_path", "variable_with_value", "with_feature_set", ) all_compile_actions = [ ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile, ACTION_NAMES.linkstamp_compile, ACTION_NAMES.assemble, ACTION_NAMES.preprocess_assemble, ACTION_NAMES.cpp_header_parsing, ACTION_NAMES.cpp_module_compile, ACTION_NAMES.cpp_module_codegen, ACTION_NAMES.cpp_module_deps_scanning, ACTION_NAMES.cpp20_module_compile, ACTION_NAMES.cpp20_module_codegen, ACTION_NAMES.clif_match, ACTION_NAMES.lto_backend, ] all_cpp_compile_actions = [ ACTION_NAMES.cpp_compile, ACTION_NAMES.linkstamp_compile, ACTION_NAMES.cpp_header_parsing, ACTION_NAMES.cpp_module_compile, ACTION_NAMES.cpp_module_codegen, ACTION_NAMES.cpp_module_deps_scanning, ACTION_NAMES.cpp20_module_compile, ACTION_NAMES.cpp20_module_codegen, ACTION_NAMES.clif_match, ] preprocessor_compile_actions = [ ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile, ACTION_NAMES.linkstamp_compile, ACTION_NAMES.preprocess_assemble, ACTION_NAMES.cpp_header_parsing, ACTION_NAMES.cpp_module_compile, ACTION_NAMES.cpp_module_deps_scanning, ACTION_NAMES.cpp20_module_compile, ACTION_NAMES.clif_match, ] codegen_compile_actions = [ ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile, ACTION_NAMES.linkstamp_compile, ACTION_NAMES.assemble, ACTION_NAMES.preprocess_assemble, ACTION_NAMES.cpp_module_codegen, ACTION_NAMES.cpp20_module_codegen, ACTION_NAMES.lto_backend, ] all_link_actions = [ ACTION_NAMES.cpp_link_executable, ACTION_NAMES.cpp_link_dynamic_library, ACTION_NAMES.cpp_link_nodeps_dynamic_library, ] def _use_msvc_toolchain(ctx): return ctx.attr.cpu in ["x64_windows", "arm64_windows"] and (ctx.attr.compiler == "msvc-cl" or ctx.attr.compiler == "clang-cl") def _impl(ctx): if _use_msvc_toolchain(ctx): artifact_name_patterns = [ artifact_name_pattern( category_name = "object_file", prefix = "", extension = ".obj", ), artifact_name_pattern( category_name = "static_library", prefix = "", extension = ".lib", ), artifact_name_pattern( category_name = "alwayslink_static_library", prefix = "", extension = ".lo.lib", ), artifact_name_pattern( category_name = "executable", prefix = "", extension = ".exe", ), artifact_name_pattern( category_name = "dynamic_library", prefix = "", extension = ".dll", ), artifact_name_pattern( category_name = "interface_library", prefix = "", extension = ".if.lib", ), ] else: artifact_name_patterns = [ artifact_name_pattern( category_name = "executable", prefix = "", extension = ".exe", ), ] if _use_msvc_toolchain(ctx): cpp_link_nodeps_dynamic_library_action = action_config( action_name = ACTION_NAMES.cpp_link_nodeps_dynamic_library, implies = [ "nologo", "shared_flag", "linkstamps", "output_execpath_flags", "input_param_flags", "user_link_flags", "linker_subsystem_flag", "linker_param_file", "msvc_env", "no_stripping", "has_configured_linker_path", "def_file", ], tools = [tool(path = ctx.attr.msvc_link_path)], ) cpp_link_static_library_action = action_config( action_name = ACTION_NAMES.cpp_link_static_library, implies = [ "nologo", "archiver_flags", "input_param_flags", "linker_param_file", "msvc_env", ], tools = [tool(path = ctx.attr.msvc_lib_path)], ) assemble_action = action_config( action_name = ACTION_NAMES.assemble, implies = [ "compiler_input_flags", "compiler_output_flags", "nologo", "msvc_env", "sysroot", ], tools = [tool(path = ctx.attr.msvc_ml_path)], ) preprocess_assemble_action = action_config( action_name = ACTION_NAMES.preprocess_assemble, implies = [ "compiler_input_flags", "compiler_output_flags", "nologo", "msvc_env", "sysroot", ], tools = [tool(path = ctx.attr.msvc_ml_path)], ) c_compile_action = action_config( action_name = ACTION_NAMES.c_compile, implies = [ "compiler_input_flags", "compiler_output_flags", "nologo", "msvc_env", "user_compile_flags", "sysroot", ], tools = [tool(path = ctx.attr.msvc_cl_path)], ) linkstamp_compile_action = action_config( action_name = ACTION_NAMES.linkstamp_compile, implies = [ "compiler_input_flags", "compiler_output_flags", "default_compile_flags", "nologo", "msvc_env", "user_compile_flags", "sysroot", "unfiltered_compile_flags", ], tools = [tool(path = ctx.attr.msvc_cl_path)], ) cpp_compile_action = action_config( action_name = ACTION_NAMES.cpp_compile, implies = [ "compiler_input_flags", "compiler_output_flags", "nologo", "msvc_env", "user_compile_flags", "sysroot", ], tools = [tool(path = ctx.attr.msvc_cl_path)], ) cpp_link_executable_action = action_config( action_name = ACTION_NAMES.cpp_link_executable, implies = [ "nologo", "linkstamps", "output_execpath_flags", "input_param_flags", "user_link_flags", "linker_subsystem_flag", "linker_param_file", "msvc_env", "no_stripping", ], tools = [tool(path = ctx.attr.msvc_link_path)], ) cpp_link_dynamic_library_action = action_config( action_name = ACTION_NAMES.cpp_link_dynamic_library, implies = [ "nologo", "shared_flag", "linkstamps", "output_execpath_flags", "input_param_flags", "user_link_flags", "linker_subsystem_flag", "linker_param_file", "msvc_env", "no_stripping", "has_configured_linker_path", "def_file", ], tools = [tool(path = ctx.attr.msvc_link_path)], ) deps_scanner = "cpp-module-deps-scanner_not_found" if "cpp-module-deps-scanner" in ctx.attr.tool_paths: deps_scanner = ctx.attr.tool_paths["cpp-module-deps-scanner"] cpp_module_scan_deps = action_config( action_name = ACTION_NAMES.cpp_module_deps_scanning, tools = [ tool( path = deps_scanner, ), ], implies = [ "compiler_input_flags", "compiler_output_flags", "nologo", "msvc_env", "user_compile_flags", "sysroot", ], ) cpp20_module_compile = action_config( action_name = ACTION_NAMES.cpp20_module_compile, tools = [ tool( path = ctx.attr.msvc_cl_path, ), ], flag_sets = [ flag_set( flag_groups = [ flag_group( flags = [ "/TP", "/interface", ], ), ], ), ], implies = [ "compiler_input_flags", "compiler_output_flags", "nologo", "msvc_env", "user_compile_flags", "sysroot", ], ) cpp20_module_codegen = action_config( action_name = ACTION_NAMES.cpp20_module_codegen, tools = [ tool( path = ctx.attr.msvc_cl_path, ), ], implies = [ "compiler_input_flags", "compiler_output_flags", "nologo", "msvc_env", "user_compile_flags", "sysroot", ], ) action_configs = [ assemble_action, preprocess_assemble_action, c_compile_action, linkstamp_compile_action, cpp_compile_action, cpp_link_executable_action, cpp_link_dynamic_library_action, cpp_link_nodeps_dynamic_library_action, cpp_link_static_library_action, cpp_module_scan_deps, cpp20_module_compile, cpp20_module_codegen, ] else: action_configs = [] if _use_msvc_toolchain(ctx): msvc_link_env_feature = feature( name = "msvc_link_env", env_sets = [ env_set( actions = all_link_actions + [ACTION_NAMES.cpp_link_static_library], env_entries = [env_entry(key = "LIB", value = ctx.attr.msvc_env_lib)], ), ], ) shared_flag_feature = feature( name = "shared_flag", flag_sets = [ flag_set( actions = [ ACTION_NAMES.cpp_link_dynamic_library, ACTION_NAMES.cpp_link_nodeps_dynamic_library, ], flag_groups = [flag_group(flags = ["/DLL"])], ), ], ) determinism_feature = feature( name = "determinism", enabled = True, flag_sets = [ flag_set( actions = [ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile], flag_groups = [ flag_group( flags = [ "/wd4117", "-D__DATE__=\"redacted\"", "-D__TIMESTAMP__=\"redacted\"", "-D__TIME__=\"redacted\"", ] + (["-Wno-builtin-macro-redefined"] if ctx.attr.compiler == "clang-cl" else []), ), ], ), ], ) sysroot_feature = feature( name = "sysroot", flag_sets = [ flag_set( actions = [ ACTION_NAMES.assemble, ACTION_NAMES.preprocess_assemble, ACTION_NAMES.c_compile, ACTION_NAMES.linkstamp_compile, ACTION_NAMES.cpp_compile, ACTION_NAMES.cpp_header_parsing, ACTION_NAMES.cpp_module_compile, ACTION_NAMES.cpp_module_codegen, ACTION_NAMES.cpp_module_deps_scanning, ACTION_NAMES.cpp20_module_compile, ACTION_NAMES.cpp20_module_codegen, ACTION_NAMES.cpp_link_executable, ACTION_NAMES.cpp_link_dynamic_library, ACTION_NAMES.cpp_link_nodeps_dynamic_library, ], flag_groups = [ flag_group( flags = ["--sysroot=%{sysroot}"], iterate_over = "sysroot", expand_if_available = "sysroot", ), ], ), ], ) unfiltered_compile_flags_feature = feature( name = "unfiltered_compile_flags", enabled = True, flag_sets = [ flag_set( actions = [ ACTION_NAMES.preprocess_assemble, ACTION_NAMES.c_compile, ACTION_NAMES.linkstamp_compile, ACTION_NAMES.cpp_compile, ACTION_NAMES.cpp_header_parsing, ACTION_NAMES.cpp_module_compile, ACTION_NAMES.cpp_module_codegen, ACTION_NAMES.cpp_module_deps_scanning, ACTION_NAMES.cpp20_module_compile, ACTION_NAMES.cpp20_module_codegen, ], flag_groups = [ flag_group( flags = ["%{unfiltered_compile_flags}"], iterate_over = "unfiltered_compile_flags", expand_if_available = "unfiltered_compile_flags", ), ], ), ], ) archive_param_file_feature = feature( name = "archive_param_file", enabled = True, ) compiler_param_file_feature = feature( name = "compiler_param_file", enabled = True, ) copy_dynamic_libraries_to_binary_feature = feature( name = "copy_dynamic_libraries_to_binary", ) input_param_flags_feature = feature( name = "input_param_flags", flag_sets = [ flag_set( actions = [ ACTION_NAMES.cpp_link_dynamic_library, ACTION_NAMES.cpp_link_nodeps_dynamic_library, ], flag_groups = [ flag_group( flags = ["/IMPLIB:%{interface_library_output_path}"], expand_if_available = "interface_library_output_path", ), ], ), flag_set( actions = all_link_actions, flag_groups = [ flag_group( flags = ["%{libopts}"], iterate_over = "libopts", expand_if_available = "libopts", ), ], ), flag_set( actions = all_link_actions + [ACTION_NAMES.cpp_link_static_library], flag_groups = [ flag_group( iterate_over = "libraries_to_link", flag_groups = [ flag_group( iterate_over = "libraries_to_link.object_files", flag_groups = [flag_group(flags = ["%{libraries_to_link.object_files}"])], expand_if_equal = variable_with_value( name = "libraries_to_link.type", value = "object_file_group", ), ), flag_group( flag_groups = [flag_group(flags = ["%{libraries_to_link.name}"])], expand_if_equal = variable_with_value( name = "libraries_to_link.type", value = "object_file", ), ), flag_group( flag_groups = [flag_group(flags = ["%{libraries_to_link.name}"])], expand_if_equal = variable_with_value( name = "libraries_to_link.type", value = "interface_library", ), ), flag_group( flag_groups = [ flag_group( flags = ["%{libraries_to_link.name}"], expand_if_false = "libraries_to_link.is_whole_archive", ), flag_group( flags = ["/WHOLEARCHIVE:%{libraries_to_link.name}"], expand_if_true = "libraries_to_link.is_whole_archive", ), ], expand_if_equal = variable_with_value( name = "libraries_to_link.type", value = "static_library", ), ), ], expand_if_available = "libraries_to_link", ), ], ), ], ) fastbuild_feature = feature( name = "fastbuild", flag_sets = [ flag_set( actions = [ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile], flag_groups = [flag_group(flags = ["/Od", "/Z7"])], ), flag_set( actions = all_link_actions, flag_groups = [ flag_group( flags = [ctx.attr.fastbuild_mode_debug_flag, "/INCREMENTAL:NO"], ), ], ), ], implies = ["generate_pdb_file"], ) user_compile_flags_feature = feature( name = "user_compile_flags", flag_sets = [ flag_set( actions = [ ACTION_NAMES.preprocess_assemble, ACTION_NAMES.c_compile, ACTION_NAMES.linkstamp_compile, ACTION_NAMES.cpp_compile, ACTION_NAMES.cpp_header_parsing, ACTION_NAMES.cpp_module_compile, ACTION_NAMES.cpp_module_codegen, ACTION_NAMES.cpp_module_deps_scanning, ACTION_NAMES.cpp20_module_compile, ACTION_NAMES.cpp20_module_codegen, ], flag_groups = [ flag_group( flags = ["%{user_compile_flags}"], iterate_over = "user_compile_flags", expand_if_available = "user_compile_flags", ), ], ), ], ) archiver_flags_feature = feature( name = "archiver_flags", flag_sets = [ flag_set( actions = [ACTION_NAMES.cpp_link_static_library], flag_groups = [ flag_group( flags = ["/OUT:%{output_execpath}"], expand_if_available = "output_execpath", ), flag_group( flags = ["%{user_archiver_flags}"], iterate_over = "user_archiver_flags", expand_if_available = "user_archiver_flags", ), flag_group( flags = ctx.attr.archiver_flags, ), ], ), ], ) default_link_flags_feature = feature( name = "default_link_flags", enabled = True, flag_sets = [ flag_set( actions = all_link_actions, flag_groups = [flag_group(flags = ctx.attr.default_link_flags)], ), ], ) static_link_msvcrt_feature = feature( name = "static_link_msvcrt", flag_sets = [ flag_set( actions = [ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile], flag_groups = [flag_group(flags = ["/MT"])], with_features = [with_feature_set(not_features = ["dbg"])], ), flag_set( actions = [ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile], flag_groups = [flag_group(flags = ["/MTd"])], with_features = [with_feature_set(features = ["dbg"])], ), flag_set( actions = all_link_actions, flag_groups = [flag_group(flags = ["/DEFAULTLIB:libcmt.lib"])], with_features = [with_feature_set(not_features = ["dbg"])], ), flag_set( actions = all_link_actions, flag_groups = [flag_group(flags = ["/DEFAULTLIB:libcmtd.lib"])], with_features = [with_feature_set(features = ["dbg"])], ), ], ) dynamic_link_msvcrt_feature = feature( name = "dynamic_link_msvcrt", enabled = True, flag_sets = [ flag_set( actions = [ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile], flag_groups = [flag_group(flags = ["/MD"])], with_features = [with_feature_set(not_features = ["dbg", "static_link_msvcrt"])], ), flag_set( actions = [ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile], flag_groups = [flag_group(flags = ["/MDd"])], with_features = [with_feature_set(features = ["dbg"], not_features = ["static_link_msvcrt"])], ), flag_set( actions = all_link_actions, flag_groups = [flag_group(flags = ["/DEFAULTLIB:msvcrt.lib"])], with_features = [with_feature_set(not_features = ["dbg", "static_link_msvcrt"])], ), flag_set( actions = all_link_actions, flag_groups = [flag_group(flags = ["/DEFAULTLIB:msvcrtd.lib"])], with_features = [with_feature_set(features = ["dbg"], not_features = ["static_link_msvcrt"])], ), ], ) dbg_feature = feature( name = "dbg", flag_sets = [ flag_set( actions = [ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile], flag_groups = [flag_group(flags = ["/Od", "/Z7"])], ), flag_set( actions = all_link_actions, flag_groups = [ flag_group( flags = [ctx.attr.dbg_mode_debug_flag, "/INCREMENTAL:NO"], ), ], ), ], implies = ["generate_pdb_file"], ) opt_feature = feature( name = "opt", flag_sets = [ flag_set( actions = [ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile], flag_groups = [flag_group(flags = ["/O2"])], ), ], implies = ["frame_pointer"], ) supports_interface_shared_libraries_feature = feature( name = "supports_interface_shared_libraries", enabled = True, ) user_link_flags_feature = feature( name = "user_link_flags", flag_sets = [ flag_set( actions = all_link_actions, flag_groups = [ flag_group( flags = ["%{user_link_flags}"], iterate_over = "user_link_flags", expand_if_available = "user_link_flags", ), ], ), ], ) default_compile_flags_feature = feature( name = "default_compile_flags", enabled = True, flag_sets = [ flag_set( actions = [ ACTION_NAMES.assemble, ACTION_NAMES.preprocess_assemble, ACTION_NAMES.linkstamp_compile, ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile, ACTION_NAMES.cpp_header_parsing, ACTION_NAMES.cpp_module_compile, ACTION_NAMES.cpp_module_codegen, ACTION_NAMES.cpp_module_deps_scanning, ACTION_NAMES.cpp20_module_compile, ACTION_NAMES.cpp20_module_codegen, ACTION_NAMES.lto_backend, ACTION_NAMES.clif_match, ], flag_groups = [ flag_group( flags = [ "/DCOMPILER_MSVC", "/DNOMINMAX", "/D_WIN32_WINNT=0x0601", "/D_CRT_SECURE_NO_DEPRECATE", "/D_CRT_SECURE_NO_WARNINGS", "/bigobj", "/Zm500", "/EHsc", "/wd4351", "/wd4291", "/wd4250", "/wd4996", ], ), ], ), ], ) msvc_compile_env_feature = feature( name = "msvc_compile_env", env_sets = [ env_set( actions = [ ACTION_NAMES.c_compile, ACTION_NAMES.linkstamp_compile, ACTION_NAMES.cpp_compile, ACTION_NAMES.cpp_module_compile, ACTION_NAMES.cpp_module_codegen, ACTION_NAMES.cpp_header_parsing, ACTION_NAMES.cpp_module_deps_scanning, ACTION_NAMES.cpp20_module_compile, ACTION_NAMES.cpp20_module_codegen, ACTION_NAMES.assemble, ACTION_NAMES.preprocess_assemble, ], env_entries = [env_entry(key = "INCLUDE", value = ctx.attr.msvc_env_include)], ), ], ) preprocessor_defines_feature = feature( name = "preprocessor_defines", enabled = True, flag_sets = [ flag_set( actions = [ ACTION_NAMES.assemble, ACTION_NAMES.preprocess_assemble, ACTION_NAMES.c_compile, ACTION_NAMES.linkstamp_compile, ACTION_NAMES.cpp_compile, ACTION_NAMES.cpp_header_parsing, ACTION_NAMES.cpp_module_compile, ACTION_NAMES.cpp_module_deps_scanning, ACTION_NAMES.cpp20_module_compile, ], flag_groups = [ flag_group( flags = ["/D%{preprocessor_defines}"], iterate_over = "preprocessor_defines", ), ], ), ], ) generate_pdb_file_feature = feature( name = "generate_pdb_file", ) generate_linkmap_feature = feature( name = "generate_linkmap", flag_sets = [ flag_set( actions = [ ACTION_NAMES.cpp_link_executable, ], flag_groups = [ flag_group( flags = [ "/MAP:%{output_execpath}.map", ], expand_if_available = "output_execpath", ), ], ), ], ) output_execpath_flags_feature = feature( name = "output_execpath_flags", flag_sets = [ flag_set( actions = all_link_actions, flag_groups = [ flag_group( flags = ["/OUT:%{output_execpath}"], expand_if_available = "output_execpath", ), ], ), ], ) disable_assertions_feature = feature( name = "disable_assertions", enabled = True, flag_sets = [ flag_set( actions = [ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile], flag_groups = [flag_group(flags = ["/DNDEBUG"])], with_features = [with_feature_set(features = ["opt"])], ), ], ) has_configured_linker_path_feature = feature(name = "has_configured_linker_path") supports_dynamic_linker_feature = feature(name = "supports_dynamic_linker", enabled = True) no_stripping_feature = feature(name = "no_stripping") linker_param_file_feature = feature( name = "linker_param_file", flag_sets = [ flag_set( actions = all_link_actions + [ACTION_NAMES.cpp_link_static_library], flag_groups = [ flag_group( flags = ["@%{linker_param_file}"], expand_if_available = "linker_param_file", ), ], ), ], ) ignore_noisy_warnings_feature = feature( name = "ignore_noisy_warnings", enabled = True, flag_sets = [ flag_set( actions = [ACTION_NAMES.cpp_link_static_library], flag_groups = [flag_group(flags = ["/ignore:4221"])], ), ], ) no_legacy_features_feature = feature(name = "no_legacy_features") parse_showincludes_feature = feature( name = "parse_showincludes", enabled = ctx.attr.supports_parse_showincludes, flag_sets = [ flag_set( actions = [ ACTION_NAMES.preprocess_assemble, ACTION_NAMES.c_compile, ACTION_NAMES.linkstamp_compile, ACTION_NAMES.cpp_compile, ACTION_NAMES.cpp_module_compile, ACTION_NAMES.cpp_header_parsing, ACTION_NAMES.cpp_module_deps_scanning, ACTION_NAMES.cpp20_module_compile, ], flag_groups = [flag_group(flags = ["/showIncludes"])], ), ], env_sets = [ env_set( actions = [ ACTION_NAMES.preprocess_assemble, ACTION_NAMES.c_compile, ACTION_NAMES.linkstamp_compile, ACTION_NAMES.cpp_compile, ACTION_NAMES.cpp_module_compile, ACTION_NAMES.cpp_header_parsing, ], # Force English (and thus a consistent locale) output so that Bazel can parse # the /showIncludes output without having to guess the encoding. env_entries = [env_entry(key = "VSLANG", value = "1033")], ), ], ) # MSVC does not emit .d files. no_dotd_file_feature = feature( name = "no_dotd_file", enabled = True, ) treat_warnings_as_errors_feature = feature( name = "treat_warnings_as_errors", flag_sets = [ flag_set( actions = [ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile] + all_link_actions, flag_groups = [flag_group(flags = ["/WX"])], ), ], ) windows_export_all_symbols_feature = feature(name = "windows_export_all_symbols") no_windows_export_all_symbols_feature = feature(name = "no_windows_export_all_symbols") include_paths_feature = feature( name = "include_paths", enabled = True, flag_sets = [ flag_set( actions = [ ACTION_NAMES.assemble, ACTION_NAMES.preprocess_assemble, ACTION_NAMES.c_compile, ACTION_NAMES.linkstamp_compile, ACTION_NAMES.cpp_compile, ACTION_NAMES.cpp_header_parsing, ACTION_NAMES.cpp_module_compile, ], flag_groups = [ flag_group( flags = ["/I%{quote_include_paths}"], iterate_over = "quote_include_paths", ), flag_group( flags = ["/I%{include_paths}"], iterate_over = "include_paths", ), flag_group( flags = ["/I%{system_include_paths}"], iterate_over = "system_include_paths", ), ], ), ], ) external_include_paths_feature = feature( name = "external_include_paths", flag_sets = [ flag_set( actions = [ ACTION_NAMES.preprocess_assemble, ACTION_NAMES.linkstamp_compile, ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile, ACTION_NAMES.cpp_header_parsing, ACTION_NAMES.cpp_module_compile, ACTION_NAMES.cpp_module_deps_scanning, ACTION_NAMES.cpp20_module_compile, ACTION_NAMES.clif_match, ACTION_NAMES.objc_compile, ACTION_NAMES.objcpp_compile, ], flag_groups = [ flag_group( flags = ["/external:I%{external_include_paths}"], iterate_over = "external_include_paths", expand_if_available = "external_include_paths", ), ], ), ], ) linkstamps_feature = feature( name = "linkstamps", flag_sets = [ flag_set( actions = all_link_actions, flag_groups = [ flag_group( flags = ["%{linkstamp_paths}"], iterate_over = "linkstamp_paths", expand_if_available = "linkstamp_paths", ), ], ), ], ) targets_windows_feature = feature( name = "targets_windows", enabled = True, implies = ["copy_dynamic_libraries_to_binary"], ) linker_subsystem_flag_feature = feature( name = "linker_subsystem_flag", flag_sets = [ flag_set( actions = all_link_actions, flag_groups = [flag_group(flags = ["/SUBSYSTEM:CONSOLE"])], ), ], ) frame_pointer_feature = feature( name = "frame_pointer", flag_sets = [ flag_set( actions = [ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile], flag_groups = [flag_group(flags = ["/Oy-"])], ), ], ) compiler_output_flags_feature = feature( name = "compiler_output_flags", flag_sets = [ flag_set( actions = [ACTION_NAMES.assemble], flag_groups = [ flag_group( flag_groups = [ flag_group( flags = ["/Fo%{output_file}", "/Zi"], expand_if_available = "output_file", expand_if_not_available = "output_assembly_file", ), ], expand_if_not_available = "output_preprocess_file", ), ], ), flag_set( actions = [ ACTION_NAMES.preprocess_assemble, ACTION_NAMES.c_compile, ACTION_NAMES.linkstamp_compile, ACTION_NAMES.cpp_compile, ACTION_NAMES.cpp_header_parsing, ACTION_NAMES.cpp_module_compile, ACTION_NAMES.cpp_module_codegen, ACTION_NAMES.cpp_module_deps_scanning, ACTION_NAMES.cpp20_module_compile, ACTION_NAMES.cpp20_module_codegen, ], flag_groups = [ flag_group( flag_groups = [ flag_group( flags = ["/Fo%{output_file}"], expand_if_not_available = "output_preprocess_file", ), ], expand_if_available = "output_file", expand_if_not_available = "output_assembly_file", ), flag_group( flag_groups = [ flag_group( flags = ["/Fa%{output_file}"], expand_if_available = "output_assembly_file", ), ], expand_if_available = "output_file", ), flag_group( flag_groups = [ flag_group( flags = ["/P", "/Fi%{output_file}"], expand_if_available = "output_preprocess_file", ), ], expand_if_available = "output_file", ), ], ), ], ) nologo_feature = feature( name = "nologo", flag_sets = [ flag_set( actions = [ ACTION_NAMES.c_compile, ACTION_NAMES.linkstamp_compile, ACTION_NAMES.cpp_compile, ACTION_NAMES.cpp_module_compile, ACTION_NAMES.cpp_module_codegen, ACTION_NAMES.cpp_header_parsing, ACTION_NAMES.cpp_module_deps_scanning, ACTION_NAMES.cpp20_module_compile, ACTION_NAMES.cpp20_module_codegen, ACTION_NAMES.assemble, ACTION_NAMES.preprocess_assemble, ACTION_NAMES.cpp_link_executable, ACTION_NAMES.cpp_link_dynamic_library, ACTION_NAMES.cpp_link_nodeps_dynamic_library, ACTION_NAMES.cpp_link_static_library, ], flag_groups = [flag_group(flags = ["/nologo"])], ), ], ) smaller_binary_feature = feature( name = "smaller_binary", enabled = True, flag_sets = [ flag_set( actions = [ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile], flag_groups = [flag_group(flags = ["/Gy", "/Gw"])], with_features = [with_feature_set(features = ["opt"])], ), flag_set( actions = all_link_actions, flag_groups = [flag_group(flags = ["/OPT:ICF", "/OPT:REF"])], with_features = [with_feature_set(features = ["opt"])], ), ], ) remove_unreferenced_code_feature = feature( name = "remove_unreferenced_code", enabled = True, flag_sets = [ flag_set( actions = [ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile], flag_groups = [flag_group(flags = ["/Zc:inline"])], ), ], ) compiler_input_flags_feature = feature( name = "compiler_input_flags", flag_sets = [ flag_set( actions = [ ACTION_NAMES.assemble, ACTION_NAMES.preprocess_assemble, ACTION_NAMES.c_compile, ACTION_NAMES.linkstamp_compile, ACTION_NAMES.cpp_compile, ACTION_NAMES.cpp_header_parsing, ACTION_NAMES.cpp_module_compile, ACTION_NAMES.cpp_module_codegen, ACTION_NAMES.cpp_module_deps_scanning, ACTION_NAMES.cpp20_module_compile, ACTION_NAMES.cpp20_module_codegen, ], flag_groups = [ flag_group( flags = ["/c", "%{source_file}"], expand_if_available = "source_file", ), ], ), ], ) def_file_feature = feature( name = "def_file", flag_sets = [ flag_set( actions = all_link_actions, flag_groups = [ flag_group( flags = ["/DEF:%{def_file_path}", "/ignore:4070"], expand_if_available = "def_file_path", ), ], ), ], ) msvc_env_feature = feature( name = "msvc_env", env_sets = [ env_set( actions = [ ACTION_NAMES.c_compile, ACTION_NAMES.linkstamp_compile, ACTION_NAMES.cpp_compile, ACTION_NAMES.cpp_module_compile, ACTION_NAMES.cpp_module_codegen, ACTION_NAMES.cpp_header_parsing, ACTION_NAMES.cpp_module_deps_scanning, ACTION_NAMES.cpp20_module_compile, ACTION_NAMES.cpp20_module_codegen, ACTION_NAMES.assemble, ACTION_NAMES.preprocess_assemble, ACTION_NAMES.cpp_link_executable, ACTION_NAMES.cpp_link_dynamic_library, ACTION_NAMES.cpp_link_nodeps_dynamic_library, ACTION_NAMES.cpp_link_static_library, ], env_entries = [ env_entry(key = "PATH", value = ctx.attr.msvc_env_path), env_entry(key = "TMP", value = ctx.attr.msvc_env_tmp), env_entry(key = "TEMP", value = ctx.attr.msvc_env_tmp), ], ), ], implies = ["msvc_compile_env", "msvc_link_env"], ) symbol_check_feature = feature( name = "symbol_check", flag_sets = [ flag_set( actions = [ACTION_NAMES.cpp_link_static_library], flag_groups = [flag_group(flags = ["/WX:4006"])], ), ], ) features = [ no_legacy_features_feature, nologo_feature, has_configured_linker_path_feature, no_stripping_feature, targets_windows_feature, copy_dynamic_libraries_to_binary_feature, default_compile_flags_feature, msvc_env_feature, msvc_compile_env_feature, msvc_link_env_feature, include_paths_feature, external_include_paths_feature, preprocessor_defines_feature, parse_showincludes_feature, no_dotd_file_feature, generate_pdb_file_feature, generate_linkmap_feature, shared_flag_feature, linkstamps_feature, output_execpath_flags_feature, archiver_flags_feature, input_param_flags_feature, linker_subsystem_flag_feature, user_link_flags_feature, default_link_flags_feature, linker_param_file_feature, static_link_msvcrt_feature, dynamic_link_msvcrt_feature, dbg_feature, fastbuild_feature, opt_feature, frame_pointer_feature, disable_assertions_feature, determinism_feature, treat_warnings_as_errors_feature, smaller_binary_feature, remove_unreferenced_code_feature, ignore_noisy_warnings_feature, user_compile_flags_feature, sysroot_feature, unfiltered_compile_flags_feature, archive_param_file_feature, compiler_param_file_feature, compiler_output_flags_feature, compiler_input_flags_feature, def_file_feature, windows_export_all_symbols_feature, no_windows_export_all_symbols_feature, supports_dynamic_linker_feature, supports_interface_shared_libraries_feature, symbol_check_feature, ] else: targets_windows_feature = feature( name = "targets_windows", implies = ["copy_dynamic_libraries_to_binary"], enabled = True, ) copy_dynamic_libraries_to_binary_feature = feature(name = "copy_dynamic_libraries_to_binary") gcc_env_feature = feature( name = "gcc_env", enabled = True, env_sets = [ env_set( actions = [ ACTION_NAMES.c_compile, ACTION_NAMES.linkstamp_compile, ACTION_NAMES.cpp_compile, ACTION_NAMES.cpp_module_compile, ACTION_NAMES.cpp_module_codegen, ACTION_NAMES.cpp_header_parsing, ACTION_NAMES.cpp_module_deps_scanning, ACTION_NAMES.cpp20_module_compile, ACTION_NAMES.cpp20_module_codegen, ACTION_NAMES.assemble, ACTION_NAMES.preprocess_assemble, ACTION_NAMES.cpp_link_executable, ACTION_NAMES.cpp_link_dynamic_library, ACTION_NAMES.cpp_link_nodeps_dynamic_library, ACTION_NAMES.cpp_link_static_library, ], env_entries = [ env_entry(key = "PATH", value = ctx.attr.tool_bin_path), ], ), ], ) default_compile_flags_feature = feature( name = "default_compile_flags", enabled = True, flag_sets = [ flag_set( actions = [ ACTION_NAMES.linkstamp_compile, ACTION_NAMES.cpp_compile, ACTION_NAMES.cpp_header_parsing, ACTION_NAMES.cpp_module_compile, ACTION_NAMES.cpp_module_codegen, ACTION_NAMES.cpp_module_deps_scanning, ACTION_NAMES.cpp20_module_compile, ACTION_NAMES.cpp20_module_codegen, ACTION_NAMES.lto_backend, ACTION_NAMES.clif_match, ], flag_groups = [flag_group(flags = ["-std=gnu++14"] + ctx.attr.default_compile_flags)], ), ], ) default_link_flags_feature = feature( name = "default_link_flags", enabled = True, flag_sets = [ flag_set( actions = all_link_actions, flag_groups = [flag_group(flags = ["-lstdc++"] + ctx.attr.default_link_flags)], ), ], ) supports_dynamic_linker_feature = feature( name = "supports_dynamic_linker", enabled = True, ) dbg_feature = feature( name = "dbg", flag_sets = [ flag_set( actions = [ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile], flag_groups = [flag_group(flags = ["-g", "-Og"])], ), ], ) opt_feature = feature( name = "opt", flag_sets = [ flag_set( actions = [ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile], flag_groups = [flag_group(flags = [ "-g0", "-O3", "-DNDEBUG", "-ffunction-sections", "-fdata-sections", ])], ), flag_set( actions = all_link_actions, flag_groups = [flag_group(flags = ["-Wl,--gc-sections"])], ), ], ) if ctx.attr.cpu == "x64_windows" and ctx.attr.compiler == "mingw-gcc": archive_param_file_feature = feature( name = "archive_param_file", enabled = True, ) compiler_param_file_feature = feature( name = "compiler_param_file", ) features = [ targets_windows_feature, copy_dynamic_libraries_to_binary_feature, gcc_env_feature, default_compile_flags_feature, archive_param_file_feature, compiler_param_file_feature, default_link_flags_feature, supports_dynamic_linker_feature, dbg_feature, opt_feature, ] else: supports_pic_feature = feature( name = "supports_pic", enabled = True, ) sysroot_feature = feature( name = "sysroot", enabled = True, flag_sets = [ flag_set( actions = [ ACTION_NAMES.preprocess_assemble, ACTION_NAMES.linkstamp_compile, ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile, ACTION_NAMES.cpp_header_parsing, ACTION_NAMES.cpp_module_compile, ACTION_NAMES.cpp_module_codegen, ACTION_NAMES.cpp_module_deps_scanning, ACTION_NAMES.cpp20_module_compile, ACTION_NAMES.cpp20_module_codegen, ACTION_NAMES.lto_backend, ACTION_NAMES.clif_match, ACTION_NAMES.cpp_link_executable, ACTION_NAMES.cpp_link_dynamic_library, ACTION_NAMES.cpp_link_nodeps_dynamic_library, ], flag_groups = [ flag_group( flags = ["--sysroot=%{sysroot}"], expand_if_available = "sysroot", ), ], ), ], ) fdo_optimize_feature = feature( name = "fdo_optimize", flag_sets = [ flag_set( actions = [ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile], flag_groups = [ flag_group( flags = [ "-fprofile-use=%{fdo_profile_path}", "-fprofile-correction", ], expand_if_available = "fdo_profile_path", ), ], ), ], provides = ["profile"], ) treat_warnings_as_errors_feature = feature( name = "treat_warnings_as_errors", flag_sets = [ flag_set( actions = [ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile], flag_groups = [flag_group(flags = ["-Werror"])], ), flag_set( actions = all_link_actions, flag_groups = [flag_group(flags = ["-Wl,-fatal-warnings"])], ), ], ) user_compile_flags_feature = feature( name = "user_compile_flags", enabled = True, flag_sets = [ flag_set( actions = [ ACTION_NAMES.assemble, ACTION_NAMES.preprocess_assemble, ACTION_NAMES.linkstamp_compile, ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile, ACTION_NAMES.cpp_header_parsing, ACTION_NAMES.cpp_module_compile, ACTION_NAMES.cpp_module_codegen, ACTION_NAMES.cpp_module_deps_scanning, ACTION_NAMES.cpp20_module_compile, ACTION_NAMES.cpp20_module_codegen, ACTION_NAMES.lto_backend, ACTION_NAMES.clif_match, ], flag_groups = [ flag_group( flags = ["%{user_compile_flags}"], iterate_over = "user_compile_flags", expand_if_available = "user_compile_flags", ), ], ), ], ) features = [ targets_windows_feature, copy_dynamic_libraries_to_binary_feature, gcc_env_feature, supports_pic_feature, default_compile_flags_feature, default_link_flags_feature, fdo_optimize_feature, supports_dynamic_linker_feature, dbg_feature, opt_feature, user_compile_flags_feature, treat_warnings_as_errors_feature, sysroot_feature, ] tool_paths = [ tool_path(name = name, path = path) for name, path in ctx.attr.tool_paths.items() ] make_variables = [] # dumpbin.exe is not available in MSYS toolchain if "dumpbin" in ctx.attr.tool_paths: make_variables.append(make_variable(name = "DUMPBIN", value = ctx.attr.tool_paths["dumpbin"])) # Tell bazel we support C++ modules now cpp_modules_feature = feature( name = "cpp_modules", # set default value to False # to enable the feature # use --features=cpp_modules # or add cpp_modules to features attr enabled = False, ) cpp_module_modmap_file_feature = feature( name = "cpp_module_modmap_file", flag_sets = [ flag_set( actions = [ ACTION_NAMES.cpp_compile, ACTION_NAMES.cpp20_module_compile, ACTION_NAMES.cpp20_module_codegen, ], flag_groups = [ flag_group( flags = ["@%{cpp_module_modmap_file}"], expand_if_available = "cpp_module_modmap_file", ), ], ), ], enabled = True, ) cpp20_module_compile_flags_feature = feature( name = "cpp20_module_compile_flags", flag_sets = [ flag_set( actions = [ ACTION_NAMES.cpp20_module_compile, ], flag_groups = [ flag_group( flags = ["/ifcOutput%{cpp_module_output_file}"], expand_if_available = "cpp_module_output_file", ), ], ), ], enabled = True, ) 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], action_configs = action_configs, artifact_name_patterns = artifact_name_patterns, cxx_builtin_include_directories = ctx.attr.cxx_builtin_include_directories, toolchain_identifier = ctx.attr.toolchain_identifier, host_system_name = ctx.attr.host_system_name, target_system_name = ctx.attr.target_system_name, target_cpu = ctx.attr.cpu, target_libc = ctx.attr.target_libc, compiler = ctx.attr.compiler, abi_version = ctx.attr.abi_version, abi_libc_version = ctx.attr.abi_libc_version, tool_paths = tool_paths, make_variables = make_variables, ) cc_toolchain_config = rule( implementation = _impl, attrs = { "abi_libc_version": attr.string(), "abi_version": attr.string(), "archiver_flags": attr.string_list(default = []), "compiler": attr.string(), "cpu": attr.string(mandatory = True), "cxx_builtin_include_directories": attr.string_list(), "dbg_mode_debug_flag": attr.string(default = ""), "default_compile_flags": attr.string_list(default = []), "default_link_flags": attr.string_list(default = []), "fastbuild_mode_debug_flag": attr.string(default = ""), "host_system_name": attr.string(), "msvc_cl_path": attr.string(default = "vc_installation_error.bat"), "msvc_env_include": attr.string(default = "msvc_not_found"), "msvc_env_lib": attr.string(default = "msvc_not_found"), "msvc_env_path": attr.string(default = "msvc_not_found"), "msvc_env_tmp": attr.string(default = "msvc_not_found"), "msvc_lib_path": attr.string(default = "vc_installation_error.bat"), "msvc_link_path": attr.string(default = "vc_installation_error.bat"), "msvc_ml_path": attr.string(default = "vc_installation_error.bat"), "supports_parse_showincludes": attr.bool(), "target_libc": attr.string(), "target_system_name": attr.string(), "tool_bin_path": attr.string(default = "not_found"), "tool_paths": attr.string_dict(), "toolchain_identifier": attr.string(), }, provides = [CcToolchainConfigInfo], ) rules_cc-0.0.11/cc/proto/000077500000000000000000000000001470072561500151275ustar00rootroot00000000000000rules_cc-0.0.11/cc/proto/BUILD000066400000000000000000000002631470072561500157120ustar00rootroot00000000000000package(default_visibility = ["//visibility:public"]) # Toolchain type provided by proto_lang_toolchain rule and used by cc_proto_library toolchain_type(name = "toolchain_type") rules_cc-0.0.11/cc/repositories.bzl000066400000000000000000000003751470072561500172310ustar00rootroot00000000000000"""Repository rules entry point module for rules_cc.""" load("//cc/private/toolchain:cc_configure.bzl", "cc_configure") def rules_cc_dependencies(): pass # buildifier: disable=unnamed-macro def rules_cc_toolchains(*args): cc_configure(*args) rules_cc-0.0.11/cc/runfiles/000077500000000000000000000000001470072561500156135ustar00rootroot00000000000000rules_cc-0.0.11/cc/runfiles/BUILD000066400000000000000000000002211470072561500163700ustar00rootroot00000000000000licenses(["notice"]) alias( name = "runfiles", actual = "@bazel_tools//tools/cpp/runfiles", visibility = ["//visibility:public"], ) rules_cc-0.0.11/cc/system_library.bzl000066400000000000000000000370361470072561500175560ustar00rootroot00000000000000"""system_library is a repository rule for importing system libraries""" BAZEL_LIB_ADDITIONAL_PATHS_ENV_VAR = "BAZEL_LIB_ADDITIONAL_PATHS" BAZEL_LIB_OVERRIDE_PATHS_ENV_VAR = "BAZEL_LIB_OVERRIDE_PATHS" BAZEL_INCLUDE_ADDITIONAL_PATHS_ENV_VAR = "BAZEL_INCLUDE_ADDITIONAL_PATHS" BAZEL_INCLUDE_OVERRIDE_PATHS_ENV_VAR = "BAZEL_INCLUDE_OVERRIDE_PATHS" ENV_VAR_SEPARATOR = "," ENV_VAR_ASSIGNMENT = "=" def _make_flags(flag_values, flag): flags = [] if flag_values: for s in flag_values: flags.append(flag + s) return " ".join(flags) def _split_env_var(repo_ctx, var_name): value = repo_ctx.os.environ.get(var_name) if value: assignments = value.split(ENV_VAR_SEPARATOR) dict = {} for assignment in assignments: pair = assignment.split(ENV_VAR_ASSIGNMENT) if len(pair) != 2: fail( "Assignments should have form 'name=value', " + "but encountered {} in env variable {}" .format(assignment, var_name), ) key, value = pair[0], pair[1] if not dict.get(key): dict[key] = [] dict[key].append(value) return dict else: return {} def _get_list_from_env_var(repo_ctx, var_name, key): return _split_env_var(repo_ctx, var_name).get(key, default = []) def _execute_bash(repo_ctx, cmd): return repo_ctx.execute(["/bin/bash", "-c", cmd]).stdout.strip("\n") def _find_linker(repo_ctx): ld = _execute_bash(repo_ctx, "which ld") lld = _execute_bash(repo_ctx, "which lld") if ld: return ld elif lld: return lld else: fail("No linker found") def _find_compiler(repo_ctx): gcc = _execute_bash(repo_ctx, "which g++") clang = _execute_bash(repo_ctx, "which clang++") if gcc: return gcc elif clang: return clang else: fail("No compiler found") def _find_lib_path(repo_ctx, lib_name, archive_names, lib_path_hints): override_paths = _get_list_from_env_var( repo_ctx, BAZEL_LIB_OVERRIDE_PATHS_ENV_VAR, lib_name, ) additional_paths = _get_list_from_env_var( repo_ctx, BAZEL_LIB_ADDITIONAL_PATHS_ENV_VAR, lib_name, ) # Directories will be searched in order path_flags = _make_flags( override_paths + lib_path_hints + additional_paths, "-L", ) linker = _find_linker(repo_ctx) for archive_name in archive_names: cmd = """ {} -verbose -l:{} {} 2>/dev/null | \\ grep succeeded | \\ head -1 | \\ sed -e 's/^\\s*attempt to open //' -e 's/ succeeded\\s*$//' """.format( linker, archive_name, path_flags, ) path = _execute_bash(repo_ctx, cmd) if path: return (archive_name, path) return (None, None) def _find_header_path(repo_ctx, lib_name, header_name, includes): override_paths = _get_list_from_env_var( repo_ctx, BAZEL_INCLUDE_OVERRIDE_PATHS_ENV_VAR, lib_name, ) additional_paths = _get_list_from_env_var( repo_ctx, BAZEL_INCLUDE_ADDITIONAL_PATHS_ENV_VAR, lib_name, ) compiler = _find_compiler(repo_ctx) cmd = """ print | \\ {} -Wp,-v -x c++ - -fsyntax-only 2>&1 | \\ sed -n -e '/^\\s\\+/p' | \\ sed -e 's/^[ \t]*//' """.format(compiler) system_includes = _execute_bash(repo_ctx, cmd).split("\n") all_includes = (override_paths + includes + system_includes + additional_paths) for directory in all_includes: cmd = """ test -f "{dir}/{hdr}" && echo "{dir}/{hdr}" """.format(dir = directory, hdr = header_name) result = _execute_bash(repo_ctx, cmd) if result: return result return None def _system_library_impl(repo_ctx): repo_name = repo_ctx.attr.name includes = repo_ctx.attr.includes hdrs = repo_ctx.attr.hdrs optional_hdrs = repo_ctx.attr.optional_hdrs deps = repo_ctx.attr.deps lib_path_hints = repo_ctx.attr.lib_path_hints static_lib_names = repo_ctx.attr.static_lib_names shared_lib_names = repo_ctx.attr.shared_lib_names static_lib_name, static_lib_path = _find_lib_path( repo_ctx, repo_name, static_lib_names, lib_path_hints, ) shared_lib_name, shared_lib_path = _find_lib_path( repo_ctx, repo_name, shared_lib_names, lib_path_hints, ) if not static_lib_path and not shared_lib_path: fail("Library {} could not be found".format(repo_name)) hdr_names = [] hdr_paths = [] for hdr in hdrs: hdr_path = _find_header_path(repo_ctx, repo_name, hdr, includes) if hdr_path: repo_ctx.symlink(hdr_path, hdr) hdr_names.append(hdr) hdr_paths.append(hdr_path) else: fail("Could not find required header {}".format(hdr)) for hdr in optional_hdrs: hdr_path = _find_header_path(repo_ctx, repo_name, hdr, includes) if hdr_path: repo_ctx.symlink(hdr_path, hdr) hdr_names.append(hdr) hdr_paths.append(hdr_path) hdrs_param = "hdrs = {},".format(str(hdr_names)) # This is needed for the case when quote-includes and system-includes # alternate in the include chain, i.e. # #include -> #include "SDL_main.h" # -> #include -> #include "SDL_platform.h" # The problem is that the quote-includes are assumed to be # in the same directory as the header they are included from - # they have no subdir prefix ("SDL2/") in their paths include_subdirs = {} for hdr in hdr_names: path_segments = hdr.split("/") path_segments.pop() current_path_segments = ["external", repo_name] for segment in path_segments: current_path_segments.append(segment) current_path = "/".join(current_path_segments) include_subdirs.update({current_path: None}) includes_param = "includes = {},".format(str(include_subdirs.keys())) deps_names = [] for dep in deps: dep_name = repr("@" + dep) deps_names.append(dep_name) deps_param = "deps = [{}],".format(",".join(deps_names)) link_hdrs_command = "mkdir -p $(RULEDIR)/remote \n" remote_hdrs = [] for path, hdr in zip(hdr_paths, hdr_names): remote_hdr = "remote/" + hdr remote_hdrs.append(remote_hdr) link_hdrs_command += "cp {path} $(RULEDIR)/{hdr}\n ".format( path = path, hdr = remote_hdr, ) link_remote_static_lib_genrule = "" link_remote_shared_lib_genrule = "" remote_static_library_param = "" remote_shared_library_param = "" static_library_param = "" shared_library_param = "" if static_lib_path: repo_ctx.symlink(static_lib_path, static_lib_name) static_library_param = "static_library = \"{}\",".format( static_lib_name, ) remote_static_library = "remote/" + static_lib_name link_library_command = """ mkdir -p $(RULEDIR)/remote && cp {path} $(RULEDIR)/{lib}""".format( path = static_lib_path, lib = remote_static_library, ) remote_static_library_param = """ static_library = "remote_link_static_library",""" link_remote_static_lib_genrule = """ genrule( name = "remote_link_static_library", outs = ["{remote_static_library}"], cmd = {link_library_command} ) """.format( link_library_command = repr(link_library_command), remote_static_library = remote_static_library, ) if shared_lib_path: repo_ctx.symlink(shared_lib_path, shared_lib_name) shared_library_param = "shared_library = \"{}\",".format( shared_lib_name, ) remote_shared_library = "remote/" + shared_lib_name link_library_command = """ mkdir -p $(RULEDIR)/remote && cp {path} $(RULEDIR)/{lib}""".format( path = shared_lib_path, lib = remote_shared_library, ) remote_shared_library_param = """ shared_library = "remote_link_shared_library",""" link_remote_shared_lib_genrule = """ genrule( name = "remote_link_shared_library", outs = ["{remote_shared_library}"], cmd = {link_library_command} ) """.format( link_library_command = repr(link_library_command), remote_shared_library = remote_shared_library, ) repo_ctx.file( "BUILD", executable = False, content = """ load("@bazel_tools//tools/build_defs/cc:cc_import.bzl", "cc_import") cc_import( name = "local_includes", {static_library} {shared_library} {hdrs} {deps} {includes} ) genrule( name = "remote_link_headers", outs = {remote_hdrs}, cmd = {link_hdrs_command} ) {link_remote_static_lib_genrule} {link_remote_shared_lib_genrule} cc_import( name = "remote_includes", hdrs = [":remote_link_headers"], {remote_static_library} {remote_shared_library} {deps} {includes} ) alias( name = "{name}", actual = select({{ "@bazel_tools//src/conditions:remote": "remote_includes", "//conditions:default": "local_includes", }}), visibility = ["//visibility:public"], ) """.format( static_library = static_library_param, shared_library = shared_library_param, hdrs = hdrs_param, deps = deps_param, hdr_names = str(hdr_names), link_hdrs_command = repr(link_hdrs_command), name = repo_name, includes = includes_param, remote_hdrs = remote_hdrs, link_remote_static_lib_genrule = link_remote_static_lib_genrule, link_remote_shared_lib_genrule = link_remote_shared_lib_genrule, remote_static_library = remote_static_library_param, remote_shared_library = remote_shared_library_param, ), ) system_library = repository_rule( implementation = _system_library_impl, local = True, remotable = True, environ = [ BAZEL_INCLUDE_ADDITIONAL_PATHS_ENV_VAR, BAZEL_INCLUDE_OVERRIDE_PATHS_ENV_VAR, BAZEL_LIB_ADDITIONAL_PATHS_ENV_VAR, BAZEL_LIB_OVERRIDE_PATHS_ENV_VAR, ], attrs = { "deps": attr.string_list(doc = """ List of names of system libraries this target depends upon. """), "hdrs": attr.string_list( mandatory = True, allow_empty = False, doc = """ List of the library's public headers which must be imported. """, ), "includes": attr.string_list(doc = """ List of directories that should be browsed when looking for headers. """), "lib_path_hints": attr.string_list(doc = """ List of directories that should be browsed when looking for library archives. """), "optional_hdrs": attr.string_list(doc = """ List of library's private headers. """), "shared_lib_names": attr.string_list(doc = """ List of possible shared library names in order of preference. """), "static_lib_names": attr.string_list(doc = """ List of possible static library names in order of preference. """), }, doc = """system_library is a repository rule for importing system libraries `system_library` is a repository rule for safely depending on system-provided libraries on Linux. It can be used with remote caching and remote execution. Under the hood it uses gcc/clang for finding the library files and headers and symlinks them into the build directory. Symlinking allows Bazel to take these files into account when it calculates a checksum of the project. This prevents cache poisoning from happening. Currently `system_library` requires two exeperimental flags: --experimental_starlark_cc_import --experimental_repo_remote_exec A typical usage looks like this: WORKSPACE ``` system_library( name = "jpeg", hdrs = ["jpeglib.h"], shared_lib_names = ["libjpeg.so, libjpeg.so.62"], static_lib_names = ["libjpeg.a"], includes = ["/usr/additional_includes"], lib_path_hints = ["/usr/additional_libs", "/usr/some/other_path"] optional_hdrs = [ "jconfig.h", "jmorecfg.h", ], ) system_library( name = "bar", hdrs = ["bar.h"], shared_lib_names = ["libbar.so"], deps = ["jpeg"] ) ``` BUILD ``` cc_binary( name = "foo", srcs = ["foo.cc"], deps = ["@bar"] ) ``` foo.cc ``` #include "jpeglib.h" #include "bar.h" [code using symbols from jpeglib and bar] ``` `system_library` requires users to specify at least one header (as it makes no sense to import a library without headers). Public headers of a library (i.e. those included in the user-written code, like `jpeglib.h` in the example above) should be put in `hdrs` param, as they are required for the library to work. However, some libraries may use more "private" headers. They should be imported as well, but their names may differ from system to system. They should be specified in the `optional_hdrs` param. The build will not fail if some of them are not found, so it's safe to put a superset there, containing all possible combinations of names for different versions/distributions. It's up to the user to determine which headers are required for the library to work. One `system_library` target always imports exactly one library. Users can specify many potential names for the library file, as these names can differ from system to system. The order of names establishes the order of preference. As some libraries can be linked both statically and dynamically, the names of files of each kind can be specified separately. `system_library` rule will try to find library archives of both kinds, but it's up to the top-level target (for example, `cc_binary`) to decide which kind of linking will be used. `system_library` rule depends on gcc/clang (whichever is installed) for finding the actual locations of library archives and headers. Libraries installed in a standard way by a package manager (`sudo apt install libjpeg-dev`) are usually placed in one of directories searched by the compiler/linker by default - on Ubuntu library most archives are stored in `/usr/lib/x86_64-linux-gnu/` and their headers in `/usr/include/`. If the maintainer of a project expects the files to be installed in a non-standard location, they can use the `includes` parameter to add directories to the search path for headers and `lib_path_hints` to add directories to the search path for library archives. User building the project can override or extend these search paths by providing these environment variables to the build: BAZEL_INCLUDE_ADDITIONAL_PATHS, BAZEL_INCLUDE_OVERRIDE_PATHS, BAZEL_LIB_ADDITIONAL_PATHS, BAZEL_LIB_OVERRIDE_PATHS. The syntax for setting the env variables is: `=,=`. Users can provide multiple paths for one library by repeating this segment: `=`. So in order to build the example presented above but with custom paths for the jpeg lib, one would use the following command: ``` bazel build //:foo \ --experimental_starlark_cc_import \ --experimental_repo_remote_exec \ --action_env=BAZEL_LIB_OVERRIDE_PATHS=jpeg=/custom/libraries/path \ --action_env=BAZEL_INCLUDE_OVERRIDE_PATHS=jpeg=/custom/include/path,jpeg=/inc ``` Some libraries can depend on other libraries. `system_library` rule provides a `deps` parameter for specifying such relationships. `system_library` targets can depend only on other system libraries. """, ) rules_cc-0.0.11/cc/toolchain_utils.bzl000066400000000000000000000016641470072561500177040ustar00rootroot00000000000000# pylint: disable=g-bad-file-header # 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. """ Deprecated, use find_cc_toolchain.bzl """ load(":find_cc_toolchain.bzl", "find_cc_toolchain") def find_cpp_toolchain(ctx): """Deprecated, use `find_cc_toolchain` instead. Args: ctx: See `find_cc_toolchain`. Returns: A CcToolchainInfo. """ return find_cc_toolchain(ctx) rules_cc-0.0.11/cc/toolchains/000077500000000000000000000000001470072561500161275ustar00rootroot00000000000000rules_cc-0.0.11/cc/toolchains/BUILD000066400000000000000000000023511470072561500167120ustar00rootroot00000000000000# Copyright 2024 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. load("@bazel_skylib//:bzl_library.bzl", "bzl_library") bzl_library( name = "toolchain_rules", srcs = glob(["*.bzl"]), visibility = ["//visibility:public"], deps = [ "//cc:action_names_bzl", "//cc:cc_toolchain_config_lib_bzl", "//cc:find_cc_toolchain_bzl", "//cc/private/rules_impl:cc_flags_supplier_lib_bzl", "//cc/private/rules_impl:native_bzl", "//cc/toolchains/impl:toolchain_impl_rules", "@bazel_skylib//rules/directory:glob", ], ) filegroup( name = "srcs", srcs = glob([ "**/*.bzl", "**/BUILD", ]), visibility = ["//visibility:public"], ) rules_cc-0.0.11/cc/toolchains/README.md000066400000000000000000000233331470072561500174120ustar00rootroot00000000000000# Writing a custom rule_based C++ toolchain with rule-based definition. Work in progress! This document serves two purposes: * Until complete, this serves as an agreement for the final user-facing API. * Once complete, this will serve as onboarding documentation. This section will be removed once complete. ## Step 1: Define tools A tool is simply a binary. Just like any other bazel binary, a tool can specify additional files required to run. We can use any bazel binary as an input to anything that requires tools. In the example below, you could use both clang and ld as tools. ``` # @sysroot//:BUILD cc_tool( name = "clang", exe = ":bin/clang", execution_requirements = ["requires-mem:24g"], data = [...], ) sh_binary( name = "ld", srcs = ["ld_wrapper.sh"], data = [":bin/ld"], ) ``` ## Step 2: Generate action configs from those tools An action config is a mapping from action to: * A list of tools, (the first one matching the execution requirements is used). * A list of args and features that are always enabled for the action * A set of additional files required for the action Each action can only be specified once in the toolchain. Specifying multiple actions in a single `cc_action_type_config` is just a shorthand for specifying the same config for every one of those actions. If you're already familiar with how to define toolchains, the additional files is a replacement for `compile_files`, `link_files`, etc. Additionally, to replace `all_files`, we add `cc_additional_files_for_actions`. This allows you to specify that particular files are required for particular actions. We provide `additional_files` on the `cc_action_type_config` as a shorthand for specifying `cc_additional_files_for_actions` Warning: Implying a feature that is not listed directly in the toolchain will throw an error. This is to ensure you don't accidentally add a feature to the toolchain. ``` cc_action_type_config( name = "c_compile", actions = ["@rules_cc//actions:all_c_compile"], tools = ["@sysroot//:clang"], args = [":my_args"], implies = [":my_feature"], additional_files = ["@sysroot//:all_header_files"], ) cc_additional_files_for_actions( name = "all_action_files", actions = ["@rules_cc//actions:all_actions"], additional_files = ["@sysroot//:always_needed_files"] ) ``` ## Step 3: Define some arguments Arguments are our replacement for `flag_set` and `env_set`. To add arguments to our tools, we take heavy inspiration from bazel's [`Args`](https://bazel.build/rules/lib/builtins/Args) type. We provide the same API, with the following caveats: * `actions` specifies which actions the arguments apply to (same as `flag_set`). * `requires_any_of` is equivalent to `with_features` on the `flag_set`. * `args` may be used instead of `add` if your command-line is only strings. * `env` may be used to add environment variables to the arguments. Environment variables set by later args take priority. * By default, all inputs are automatically added to the corresponding actions. `additional_files` specifies files that are required for an action when using that argument. ``` cc_args( name = "inline", actions = ["@rules_cc//actions:all_cpp_compile_actions"], args = ["--foo"], requires_any_of = [":feature"] env = {"FOO": "bar"}, additional_files = [":file"], ) ``` For more complex use cases, we use the same API as `Args`. Values are either: * A list of files (or a single file for `cc_add_args`). * Something returning `CcVariableInfo`, which is equivalent to a list of strings. ``` cc_variable( name = "bar_baz", values = ["bar", "baz"], ) # Expands to CcVariableInfo(values = ["x86_64-unknown-linux-gnu"]) custom_variable_rule( name = "triple", ... ) # Taken from https://bazel.build/rules/lib/builtins/Args#add cc_add_args( name = "single", arg_name = "--platform", value = ":triple", # Either a single file or a cc_variable format = "%s", ) # Taken from https://bazel.build/rules/lib/builtins/Args#add_all cc_add_args_all( name = "multiple", arg_name = "--foo", values = [":file", ":file_set"], # Either files or cc_variable. # map_each not supported. Write a custom rule if you want that. format_each = "%s", before_each = "--foo", omit_if_empty = True, uniquify = False, # Expand_directories not yet supported. terminate_with = "foo", ) # Taken from https://bazel.build/rules/lib/builtins/Args#add_joined cc_add_args_joined( name = "joined", arg_name = "--foo", values = [":file", ":file_set"], # Either files or cc_variable. join_with = ",", # map_each not supported. Write a custom rule if you want that. format_each = "%s", format_joined = "--foo=%s", omit_if_empty = True, uniquify = False, # Expand_directories not yet supported. ) cc_args( name = "complex", actions = ["@rules_cc//actions:c_compile"], add = [":single", ":multiple", ":joined"], ) cc_args_list( name = "all_flags", args = [":inline", ":complex"], ) ``` ## Step 4: Define some features A feature is a set of args and configurations that can be enabled or disabled. Although the existing toolchain recommends using features to avoid duplication of definitions, we recommend avoiding using features unless you want the user to be able to enable / disable the feature themselves. This is because we provide alternatives such as `cc_args_list` to allow combining arguments and specifying them on each action in the action config. ``` cc_feature( name = "my_feature", feature_name = "my_feature", args = [":all_args"], implies = [":other_feature"], ) ``` ## Step 5: Generate the toolchain The `cc_toolchain` macro: * Performs validation on the inputs (eg. no two action configs for a single action) * Converts the type-safe providers to the unsafe ones in `cc_toolchain_config_lib.bzl` * Generates a set of providers for each of the filegroups respectively * Generates the appropriate `native.cc_toolchain` invocation. ``` cc_toolchain( name = "toolchain", features = [":my_feature"] unconditional_args = [":all_warnings"], action_type_configs = [":c_compile"], additional_files = [":all_action_files"], ) ``` # Ancillary components for type-safe toolchains. ## Well-known features Well-known features will be defined in `@rules_cc//features/well_known:*`. Any feature with `feature_name` in the well known features will have to specify overrides. `cc_toolchain` is aware of the builtin / well-known features. In order to ensure that a user understands that this overrides the builtin opt feature (I originally thought that it added extra flags to opt, but you still got the default ones, so that can definitely happen), and to ensure that they don't accidentally do so, we will force them to explicitly specify that it overrides the builtin one. This is essentially just an acknowledgement of "I know what I'm doing". Warning: Specifying two features with the same name is an error, unless one overrides the other. ``` cc_feature( name = "opt", ..., overrides = "@rules_cc//features/well_known:opt", ) ``` In addition to well-known features, we could also consider in future iterations to also use known features for partial migrations, where you still imply a feature that's still defined by the legacy API: ``` # Implementation def cc_legacy_features(name, features): for feature in features: cc_known_feature(name = name + "_" + feature.name) cc_legacy_features(name = name, features = FEATURES) # Build file FOO = feature(name = "foo", args=[arg_group(...)]) FEATURES = [FOO] cc_legacy_features(name = "legacy_features", features = FEATURES) cc_feature(name = "bar", implies = [":legacy_features_foo"]) cc_toolchain( name = "toolchain", legacy_features = ":legacy_features", features = [":bar"], ) ``` ## Mutual exclusion Features can be mutually exclusive. We allow two approaches to mutual exclusion - via features or via categories. The existing toolchain uses `provides` for both of these. We rename it so that it makes more sense semantically. ``` cc_feature( name = "incompatible_with_my_feature", feature_name = "bar", mutually_exclusive = [":my_feature"], ) # This is an example of how we would define compilation mode. # Since it already exists, this wouldn't work. cc_mutual_exclusion_category( name = "compilation_mode", ) cc_feature( name = "opt", ... mutually_exclusive = [":compilation_mode"], ) cc_feature( name = "dbg", ... mutually_exclusive = [":compilation_mode"], ) ``` ## Feature requirements Feature requirements can come in two formats. For example: * Features can require some subset of features to be enabled. * Arguments can require some subset of features to be enabled, but others to be disabled. This is very confusing for toolchain authors, so we will simplify things with the use of providers: * `cc_feature` will provide `feature`, `feature_set`, and `with_feature` * `cc_feature_set` will provide `feature_set` and `with_feature`. * `cc_feature_constraint` will provide `with_features` only. We will rename all `with_features` and `requires` to `requires_any_of`, to make it very clear that only one of the requirements needs to be met. ``` cc_feature_set( name = "my_feature_set", all_of = [":my_feature"], ) cc_feature_constraint( name = "my_feature_constraint", all_of = [":my_feature"], none_of = [":my_other_feature"], ) cc_args( name = "foo", # All of these provide with_feature. requires_any_of = [":my_feature", ":my_feature_set", ":my_feature_constraint"] ) # my_feature_constraint would be an error here. cc_feature( name = "foo", # Both of these provide feature_set. requires_any_of = [":my_feature", ":my_feature_set"] implies = [":my_other_feature", :my_other_feature_set"], ) ``` rules_cc-0.0.11/cc/toolchains/actions.bzl000066400000000000000000000067131470072561500203070ustar00rootroot00000000000000# Copyright 2024 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. """Rules to turn action types into bazel labels.""" load("//cc/toolchains/impl:collect.bzl", "collect_action_types") load(":cc_toolchain_info.bzl", "ActionTypeInfo", "ActionTypeSetInfo") visibility("public") def _cc_action_type_impl(ctx): action_type = ActionTypeInfo(label = ctx.label, name = ctx.attr.action_name) return [ action_type, ActionTypeSetInfo( label = ctx.label, actions = depset([action_type]), ), ] cc_action_type = rule( implementation = _cc_action_type_impl, attrs = { "action_name": attr.string( mandatory = True, ), }, doc = """A type of action (eg. c_compile, assemble, strip). `cc_action_type` rules are used to associate arguments and tools together to perform a specific action. Bazel prescribes a set of known action types that are used to drive typical C/C++/ObjC actions like compiling, linking, and archiving. The set of well-known action types can be found in [//third_party/bazel_rules/rules_cc/cc/toolchains/actions:BUILD](https://github.com/bazelbuild/rules_cc/tree/main/cc/toolchains/actions/BUILD). It's possible to create project-specific action types for use in toolchains. Be careful when doing this, because every toolchain that encounters the action will need to be configured to support the custom action type. If your project is a library, avoid creating new action types as it will reduce compatibility with existing toolchains and increase setup complexity for users. Example: ``` load("//cc:action_names.bzl", "ACTION_NAMES") load("//cc/toolchains:actions.bzl", "cc_action_type") cc_action_type( name = "cpp_compile", action_name = = ACTION_NAMES.cpp_compile, ) ``` """, provides = [ActionTypeInfo, ActionTypeSetInfo], ) def _cc_action_type_set_impl(ctx): if not ctx.attr.actions and not ctx.attr.allow_empty: fail("Each cc_action_type_set must contain at least one action type.") return [ActionTypeSetInfo( label = ctx.label, actions = collect_action_types(ctx.attr.actions), )] cc_action_type_set = rule( doc = """Represents a set of actions. This is a convenience rule to allow for more compact representation of a group of action types. Use this anywhere a `cc_action_type` is accepted. Example: ``` load("//cc/toolchains:actions.bzl", "cc_action_type_set") cc_action_type_set( name = "link_executable_actions", actions = [ "//cc/toolchains/actions:cpp_link_executable", "//cc/toolchains/actions:lto_index_for_executable", ], ) ``` """, implementation = _cc_action_type_set_impl, attrs = { "actions": attr.label_list( providers = [ActionTypeSetInfo], mandatory = True, doc = "A list of cc_action_type or cc_action_type_set", ), "allow_empty": attr.bool(default = False), }, provides = [ActionTypeSetInfo], ) rules_cc-0.0.11/cc/toolchains/actions/000077500000000000000000000000001470072561500175675ustar00rootroot00000000000000rules_cc-0.0.11/cc/toolchains/actions/BUILD000066400000000000000000000166301470072561500203570ustar00rootroot00000000000000# Copyright 2024 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. load("//cc:action_names.bzl", "ACTION_NAMES") load("//cc/toolchains:actions.bzl", "cc_action_type", "cc_action_type_set") package(default_visibility = ["//visibility:public"]) # Keep in sync with //cc:action_names.bzl. cc_action_type( name = "c_compile", action_name = ACTION_NAMES.c_compile, ) cc_action_type( name = "cpp_compile", action_name = ACTION_NAMES.cpp_compile, ) cc_action_type( name = "linkstamp_compile", action_name = ACTION_NAMES.linkstamp_compile, ) cc_action_type( name = "cc_flags_make_variable", action_name = ACTION_NAMES.cc_flags_make_variable, ) cc_action_type( name = "cpp_module_codegen", action_name = ACTION_NAMES.cpp_module_codegen, ) cc_action_type( name = "cpp_header_analysis", action_name = "c++-header-analysis", ) cc_action_type( name = "cpp_header_parsing", action_name = ACTION_NAMES.cpp_header_parsing, ) cc_action_type( name = "cpp_module_deps_scanning", action_name = ACTION_NAMES.cpp_module_deps_scanning, ) cc_action_type( name = "cpp20_module_compile", action_name = ACTION_NAMES.cpp20_module_compile, ) cc_action_type( name = "cpp20_module_codegen", action_name = ACTION_NAMES.cpp20_module_codegen, ) cc_action_type( name = "cpp_module_compile", action_name = ACTION_NAMES.cpp_module_compile, ) cc_action_type( name = "assemble", action_name = ACTION_NAMES.assemble, ) cc_action_type( name = "preprocess_assemble", action_name = ACTION_NAMES.preprocess_assemble, ) cc_action_type( name = "llvm_cov", action_name = ACTION_NAMES.llvm_cov, ) cc_action_type( name = "lto_indexing", action_name = ACTION_NAMES.lto_indexing, ) cc_action_type( name = "lto_backend", action_name = ACTION_NAMES.lto_backend, ) cc_action_type( name = "lto_index_for_executable", action_name = ACTION_NAMES.lto_index_for_executable, ) cc_action_type( name = "lto_index_for_dynamic_library", action_name = ACTION_NAMES.lto_index_for_dynamic_library, ) cc_action_type( name = "lto_index_for_nodeps_dynamic_library", action_name = ACTION_NAMES.lto_index_for_nodeps_dynamic_library, ) cc_action_type( name = "cpp_link_executable", action_name = ACTION_NAMES.cpp_link_executable, ) cc_action_type( name = "cpp_link_dynamic_library", action_name = ACTION_NAMES.cpp_link_dynamic_library, ) cc_action_type( name = "cpp_link_nodeps_dynamic_library", action_name = ACTION_NAMES.cpp_link_nodeps_dynamic_library, ) cc_action_type( name = "cpp_link_static_library", action_name = ACTION_NAMES.cpp_link_static_library, ) cc_action_type( name = "strip", action_name = ACTION_NAMES.strip, ) cc_action_type( name = "objcopy_embed_data", action_name = ACTION_NAMES.objcopy_embed_data, ) cc_action_type( name = "validate_static_library", action_name = ACTION_NAMES.validate_static_library, ) # ld_embed_data is only available within google. cc_action_type( # # copybara-comment-this-out-please name = "ld_embed_data_action", # # copybara-comment-this-out-please action_name = "ld_embed_data", # # copybara-comment-this-out-please ) # # copybara-comment-this-out-please # To make things simple, both internal and external rules will refer to # ld_embed_data, but externally it will evaluate to the empty set. cc_action_type_set( name = "ld_embed_data", actions = [ ":ld_embed_data_action", # # copybara-comment-this-out-please ], allow_empty = True, visibility = ["//cc/toolchains:__subpackages__"], ) cc_action_type( name = "objc_compile", action_name = ACTION_NAMES.objc_compile, ) cc_action_type( name = "objc_executable", action_name = ACTION_NAMES.objc_executable, ) cc_action_type( name = "objc_fully_link", action_name = ACTION_NAMES.objc_fully_link, ) cc_action_type( name = "objcpp_compile", action_name = ACTION_NAMES.objcpp_compile, ) cc_action_type( name = "objcpp_executable", action_name = "objc++-executable", ) cc_action_type( name = "clif_match", action_name = ACTION_NAMES.clif_match, ) cc_action_type_set( name = "ar_actions", actions = [":cpp_link_static_library"], ) cc_action_type_set( name = "assembly_actions", actions = [ ":preprocess_assemble", ":assemble", ], ) cc_action_type_set( name = "c_compile_actions", actions = [ ":c_compile", ], ) cc_action_type_set( name = "cpp_compile_actions", actions = [ ":linkstamp_compile", ":cpp_compile", ":cpp_header_parsing", ":cpp_module_compile", ":cpp_module_codegen", ":lto_backend", ":clif_match", ], ) cc_action_type_set( name = "compile_actions", actions = [ ":cpp_compile_actions", ":c_compile_actions", ":assembly_actions", ":objc_compile", ":objcpp_compile", ], ) cc_action_type_set( name = "link_actions", actions = [ ":link_executable_actions", ":dynamic_library_link_actions", ], ) cc_action_type_set( name = "link_executable_actions", actions = [ ":cpp_link_executable", ":lto_index_for_executable", ], ) cc_action_type_set( name = "dynamic_library_link_actions", actions = [ ":cpp_link_dynamic_library", ":lto_index_for_dynamic_library", ":nodeps_dynamic_library_link_actions", ], ) cc_action_type_set( name = "nodeps_dynamic_library_link_actions", actions = [ ":cpp_link_nodeps_dynamic_library", ":lto_index_for_nodeps_dynamic_library", ], ) cc_action_type_set( name = "transitive_link_actions", actions = [ ":cpp_link_executable", ":cpp_link_dynamic_library", ":lto_index_for_executable", ":lto_index_for_dynamic_library", ], ) cc_action_type_set( name = "all_actions", actions = [ ":c_compile", ":cpp_compile", ":linkstamp_compile", ":cc_flags_make_variable", ":cpp_module_codegen", ":cpp_header_analysis", ":cpp_header_parsing", ":cpp_module_deps_scanning", ":cpp20_module_compile", ":cpp20_module_codegen", ":cpp_module_compile", ":assemble", ":preprocess_assemble", ":llvm_cov", ":lto_indexing", ":lto_backend", ":lto_index_for_executable", ":lto_index_for_dynamic_library", ":lto_index_for_nodeps_dynamic_library", ":cpp_link_executable", ":cpp_link_dynamic_library", ":cpp_link_nodeps_dynamic_library", ":cpp_link_static_library", ":strip", ":objcopy_embed_data", ":ld_embed_data", ":objc_compile", ":objc_executable", ":objc_fully_link", ":objcpp_compile", ":objcpp_executable", ":clif_match", ":validate_static_library", ], ) rules_cc-0.0.11/cc/toolchains/args.bzl000066400000000000000000000300721470072561500175760ustar00rootroot00000000000000# Copyright 2024 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. """All providers for rule-based bazel toolchain config.""" load("@bazel_skylib//rules/directory:providers.bzl", "DirectoryInfo") load("//cc/toolchains/impl:args_utils.bzl", "validate_nested_args") load( "//cc/toolchains/impl:collect.bzl", "collect_action_types", "collect_files", "collect_provider", ) load( "//cc/toolchains/impl:nested_args.bzl", "NESTED_ARGS_ATTRS", "nested_args_provider_from_ctx", ) load( ":cc_toolchain_info.bzl", "ActionTypeSetInfo", "ArgsInfo", "ArgsListInfo", "BuiltinVariablesInfo", "FeatureConstraintInfo", ) visibility("public") def _cc_args_impl(ctx): actions = collect_action_types(ctx.attr.actions) nested = None if ctx.attr.args or ctx.attr.nested: nested = nested_args_provider_from_ctx(ctx) validate_nested_args( variables = ctx.attr._variables[BuiltinVariablesInfo].variables, nested_args = nested, actions = actions.to_list(), label = ctx.label, ) files = nested.files else: files = collect_files(ctx.attr.data + ctx.attr.allowlist_include_directories) requires = collect_provider(ctx.attr.requires_any_of, FeatureConstraintInfo) args = ArgsInfo( label = ctx.label, actions = actions, requires_any_of = tuple(requires), nested = nested, env = ctx.attr.env, files = files, allowlist_include_directories = depset( direct = [d[DirectoryInfo] for d in ctx.attr.allowlist_include_directories], ), ) return [ args, ArgsListInfo( label = ctx.label, args = tuple([args]), files = files, by_action = tuple([ struct(action = action, args = tuple([args]), files = files) for action in actions.to_list() ]), allowlist_include_directories = args.allowlist_include_directories, ), ] _cc_args = rule( implementation = _cc_args_impl, attrs = { "actions": attr.label_list( providers = [ActionTypeSetInfo], mandatory = True, doc = """See documentation for cc_args macro wrapper.""", ), "allowlist_include_directories": attr.label_list( providers = [DirectoryInfo], doc = """See documentation for cc_args macro wrapper.""", ), "env": attr.string_dict( doc = """See documentation for cc_args macro wrapper.""", ), "requires_any_of": attr.label_list( providers = [FeatureConstraintInfo], doc = """See documentation for cc_args macro wrapper.""", ), "_variables": attr.label( default = "//cc/toolchains/variables:variables", ), } | NESTED_ARGS_ATTRS, provides = [ArgsInfo], doc = """Declares a list of arguments bound to a set of actions. Roughly equivalent to ctx.actions.args() Examples: cc_args( name = "warnings_as_errors", args = ["-Werror"], ) """, ) def cc_args( *, name, actions = None, allowlist_include_directories = None, args = None, data = None, env = None, format = {}, iterate_over = None, nested = None, requires_not_none = None, requires_none = None, requires_true = None, requires_false = None, requires_equal = None, requires_equal_value = None, requires_any_of = None, **kwargs): """Action-specific arguments for use with a cc_toolchain. This rule is the fundamental building building block for every toolchain tool invocation. Each argument expressed in a toolchain tool invocation (e.g. `gcc`, `llvm-ar`) is declared in a `cc_args` rule that applies an ordered list of arguments to a set of toolchain actions. `cc_args` rules can be added unconditionally to a `cc_toolchain`, conditionally via `select()` statements, or dynamically via an intermediate `cc_feature`. Conceptually, this is similar to the old `CFLAGS`, `CPPFLAGS`, etc. environment variables that many build systems use to determine which flags to use for a given action. The significant difference is that `cc_args` rules are declared in a structured way that allows for significantly more powerful and sharable toolchain configurations. Also, due to Bazel's more granular action types, it's possible to bind flags to very specific actions (e.g. LTO indexing for an executable vs a dynamic library) multiple different actions (e.g. C++ compile and link simultaneously). Example usage: ``` load("//cc/toolchains:args.bzl", "cc_args") # Basic usage: a trivial flag. # # An example of expressing `-Werror` as a `cc_args` rule. cc_args( name = "warnings_as_errors", actions = [ # Applies to all C/C++ compile actions. "//cc/toolchains/actions:compile_actions", ], args = ["-Werror"], ) # Basic usage: ordered flags. # # An example of linking against libc++, which uses two flags that must be applied in order. cc_args( name = "link_libcxx", actions = [ # Applies to all link actions. "//cc/toolchains/actions:link_actions", ], # On tool invocation, this appears as `-Xlinker -lc++`. Nothing will ever end up between # the two flags. args = [ "-Xlinker", "-lc++", ], ) # Advanced usage: built-in variable expansions. # # Expands to `-L/path/to/search_dir` for each directory in the built-in variable # `library_search_directories`. This variable is managed internally by Bazel through inherent # behaviors of Bazel and the interactions between various C/C++ build rules. cc_args( name = "library_search_directories", actions = [ "//cc/toolchains/actions:link_actions", ], args = ["-L{search_dir}"], iterate_over = "//cc/toolchains/variables:library_search_directories", requires_not_none = "//cc/toolchains/variables:library_search_directories", format = { "search_dir": "//cc/toolchains/variables:library_search_directories", }, ) ``` For more extensive examples, see the usages here: https://github.com/bazelbuild/rules_cc/tree/main/cc/toolchains/args Args: name: (str) The name of the target. actions: (List[Label]) A list of labels of `cc_action_type` or `cc_action_type_set` rules that dictate which actions these arguments should be applied to. allowlist_include_directories: (List[Label]) A list of include paths that are implied by using this rule. These must point to a skylib [directory](https://github.com/bazelbuild/bazel-skylib/tree/main/doc/directory_doc.md#directory) or [subdirectory](https://github.com/bazelbuild/bazel-skylib/tree/main/doc/directory_subdirectory_doc.md#subdirectory) rule. Some flags (e.g. --sysroot) imply certain include paths are available despite not explicitly specifying a normal include path flag (`-I`, `-isystem`, etc.). Bazel checks that all included headers are properly provided by a dependency or allowlisted through this mechanism. As a rule of thumb, only use this if Bazel is complaining about absolute paths in your toolchain and you've ensured that the toolchain is compiling with the `-no-canonical-prefixes` and/or `-fno-canonical-system-headers` arguments. This can help work around errors like: `the source file 'main.c' includes the following non-builtin files with absolute paths (if these are builtin files, make sure these paths are in your toolchain)`. args: (List[str]) The command-line arguments that are applied by using this rule. This is mutually exclusive with [nested](#cc_args-nested). data: (List[Label]) A list of runtime data dependencies that are required for these arguments to work as intended. env: (Dict[str, str]) Environment variables that should be set when the tool is invoked. format: (Dict[str, Label]) A mapping of format strings to the label of the corresponding `cc_variable` that the value should be pulled from. All instances of `{variable_name}` will be replaced with the expanded value of `variable_name` in this dictionary. The complete list of possible variables can be found in https://github.com/bazelbuild/rules_cc/tree/main/cc/toolchains/variables/BUILD. It is not possible to declare custom variables--these are inherent to Bazel itself. iterate_over: (Label) The label of a `cc_variable` that should be iterated over. This is intended for use with built-in variables that are lists. nested: (List[Label]) A list of `cc_nested_args` rules that should be expanded to command-line arguments when this rule is used. This is mutually exclusive with [args](#cc_args-args). requires_not_none: (Label) The label of a `cc_variable` that should be checked for existence before expanding this rule. If the variable is None, this rule will be ignored. requires_none: (Label) The label of a `cc_variable` that should be checked for non-existence before expanding this rule. If the variable is not None, this rule will be ignored. requires_true: (Label) The label of a `cc_variable` that should be checked for truthiness before expanding this rule. If the variable is false, this rule will be ignored. requires_false: (Label) The label of a `cc_variable` that should be checked for falsiness before expanding this rule. If the variable is true, this rule will be ignored. requires_equal: (Label) The label of a `cc_variable` that should be checked for equality before expanding this rule. If the variable is not equal to (requires_equal_value)[#cc_args-requires_equal_value], this rule will be ignored. requires_equal_value: (str) The value to compare (requires_equal)[#cc_args-requires_equal] against. requires_any_of: (List[Label]) These arguments will be used in a tool invocation when at least one of the [cc_feature_constraint](#cc_feature_constraint) entries in this list are satisfied. If omitted, this flag set will be enabled unconditionally. **kwargs: [common attributes](https://bazel.build/reference/be/common-definitions#common-attributes) that should be applied to this rule. """ return _cc_args( name = name, actions = actions, allowlist_include_directories = allowlist_include_directories, args = args, data = data, env = env, # We flip the key/value pairs in the dictionary here because Bazel doesn't have a # string-keyed label dict attribute type. format = {k: v for v, k in format.items()}, iterate_over = iterate_over, nested = nested, requires_not_none = requires_not_none, requires_none = requires_none, requires_true = requires_true, requires_false = requires_false, requires_equal = requires_equal, requires_equal_value = requires_equal_value, requires_any_of = requires_any_of, **kwargs ) rules_cc-0.0.11/cc/toolchains/args/000077500000000000000000000000001470072561500170635ustar00rootroot00000000000000rules_cc-0.0.11/cc/toolchains/args/BUILD000066400000000000000000000043161470072561500176510ustar00rootroot00000000000000load("//cc/toolchains:feature.bzl", "cc_feature") package(default_visibility = ["//visibility:public"]) # All of these arguments originate from the legacy features defined in Bazel's Java code: # https://github.com/bazelbuild/bazel/blob/master/src/main/java/com/google/devtools/build/lib/rules/cpp/CppActionConfigs.java # This feature replaces the need for action configs to list legacy features # in `implies` to produce a working toolchain. The full list is the set of # features that are implied (enabled) by built-in action config definitions. # Note that some other legacy features are still hidden and enabled by default, # and others exist that are NOT enabled at all by default. As args are built # out, the `implies` entry should be removed and then moved into `args`. cc_feature( name = "experimental_replace_legacy_action_config_features", args = [ "//cc/toolchains/args/archiver_flags", "//cc/toolchains/args/force_pic_flags", "//cc/toolchains/args/libraries_to_link", "//cc/toolchains/args/linker_param_file", "//cc/toolchains/args/runtime_library_search_directories", "//cc/toolchains/args/shared_flag", ], feature_name = "experimental_replace_legacy_action_config_features", # TODO: Convert remaining items in this list into their actual args. implies = [ "//cc/toolchains/features/legacy:build_interface_libraries", "//cc/toolchains/features/legacy:compiler_input_flags", "//cc/toolchains/features/legacy:compiler_output_flags", "//cc/toolchains/features/legacy:dynamic_library_linker_tool", "//cc/toolchains/features/legacy:fission_support", "//cc/toolchains/features/legacy:legacy_compile_flags", "//cc/toolchains/features/legacy:legacy_link_flags", "//cc/toolchains/features/legacy:library_search_directories", "//cc/toolchains/features/legacy:linkstamps", "//cc/toolchains/features/legacy:output_execpath_flags", "//cc/toolchains/features/legacy:strip_debug_symbols", "//cc/toolchains/features/legacy:unfiltered_compile_flags", "//cc/toolchains/features/legacy:user_compile_flags", "//cc/toolchains/features/legacy:user_link_flags", ], ) rules_cc-0.0.11/cc/toolchains/args/archiver_flags/000077500000000000000000000000001470072561500220425ustar00rootroot00000000000000rules_cc-0.0.11/cc/toolchains/args/archiver_flags/BUILD000066400000000000000000000040361470072561500226270ustar00rootroot00000000000000load("//cc/toolchains:args.bzl", "cc_args") load("//cc/toolchains:args_list.bzl", "cc_args_list") load("//cc/toolchains:nested_args.bzl", "cc_nested_args") package(default_visibility = ["//visibility:private"]) cc_args_list( name = "archiver_flags", args = [ ":create_static_archive", ":output_execpath", ":libraries_to_link", ], visibility = ["//visibility:public"], ) cc_args( name = "create_static_archive", actions = ["//cc/toolchains/actions:ar_actions"], args = select({ "@platforms//os:macos": ["-static"], "//conditions:default": ["rcsD"], }), ) cc_args( name = "output_execpath", actions = ["//cc/toolchains/actions:ar_actions"], args = select({ "@platforms//os:macos": ["-o"], "//conditions:default": [], }) + ["{output_execpath}"], format = {"output_execpath": "//cc/toolchains/variables:output_execpath"}, requires_not_none = "//cc/toolchains/variables:output_execpath", ) cc_args( name = "libraries_to_link", actions = ["//cc/toolchains/actions:ar_actions"], nested = ["libraries_to_link_expansion"], requires_not_none = "//cc/toolchains/variables:libraries_to_link", ) cc_nested_args( name = "libraries_to_link_expansion", iterate_over = "//cc/toolchains/variables:libraries_to_link", nested = [ ":link_obj_file", ":link_object_file_group", ], ) cc_nested_args( name = "link_obj_file", args = ["{object_file}"], format = {"object_file": "//cc/toolchains/variables:libraries_to_link.name"}, requires_equal = "//cc/toolchains/variables:libraries_to_link.type", requires_equal_value = "object_file", ) cc_nested_args( name = "link_object_file_group", args = ["{object_files}"], format = {"object_files": "//cc/toolchains/variables:libraries_to_link.object_files"}, iterate_over = "//cc/toolchains/variables:libraries_to_link.object_files", requires_equal = "//cc/toolchains/variables:libraries_to_link.type", requires_equal_value = "object_file_group", ) rules_cc-0.0.11/cc/toolchains/args/force_pic_flags/000077500000000000000000000000001470072561500221705ustar00rootroot00000000000000rules_cc-0.0.11/cc/toolchains/args/force_pic_flags/BUILD000066400000000000000000000006561470072561500227610ustar00rootroot00000000000000load("//cc/toolchains:args.bzl", "cc_args") package(default_visibility = ["//visibility:private"]) cc_args( name = "force_pic_flags", actions = ["//cc/toolchains/actions:link_executable_actions"], args = select({ "@platforms//os:macos": ["-Wl,-pie"], "//conditions:default": ["-pie"], }), requires_not_none = "//cc/toolchains/variables:force_pic", visibility = ["//visibility:public"], ) rules_cc-0.0.11/cc/toolchains/args/libraries_to_link/000077500000000000000000000000001470072561500225565ustar00rootroot00000000000000rules_cc-0.0.11/cc/toolchains/args/libraries_to_link/BUILD000066400000000000000000000121341470072561500233410ustar00rootroot00000000000000load("//cc/toolchains:args.bzl", "cc_args") load("//cc/toolchains:nested_args.bzl", "cc_nested_args") load("//cc/toolchains/args/libraries_to_link/private:library_link_args.bzl", "library_link_args") package(default_visibility = ["//visibility:private"]) cc_args( name = "libraries_to_link", actions = ["//cc/toolchains/actions:link_actions"], nested = [ ":thinlto_param_file", ":libraries_to_link_args", ], visibility = ["//visibility:public"], ) cc_nested_args( name = "thinlto_param_file", args = ["-Wl,@{param_file}"], format = { "param_file": "//cc/toolchains/variables:thinlto_param_file", }, requires_not_none = "//cc/toolchains/variables:thinlto_param_file", ) cc_nested_args( name = "libraries_to_link_args", nested = [":iterate_over_libraries_to_link"], requires_not_none = "//cc/toolchains/variables:libraries_to_link", ) cc_nested_args( name = "iterate_over_libraries_to_link", iterate_over = "//cc/toolchains/variables:libraries_to_link", nested = [ ":optional_object_file_group_start", ":single_library_args", ":optional_object_file_group_end", ], ) cc_nested_args( name = "optional_object_file_group_start", nested = [":start_lib_arg"], requires_equal = "//cc/toolchains/variables:libraries_to_link.type", requires_equal_value = "object_file_group", ) cc_nested_args( name = "start_lib_arg", args = ["-Wl,--start-lib"], requires_false = "//cc/toolchains/variables:libraries_to_link.is_whole_archive", ) cc_nested_args( name = "optional_object_file_group_end", nested = [":end_lib_arg"], requires_equal = "//cc/toolchains/variables:libraries_to_link.type", requires_equal_value = "object_file_group", ) cc_nested_args( name = "end_lib_arg", args = ["-Wl,--end-lib"], requires_false = "//cc/toolchains/variables:libraries_to_link.is_whole_archive", ) cc_nested_args( name = "single_library_args", nested = select({ "@platforms//os:macos": [], "//conditions:default": [":optional_whole_archive_start"], }) + [ ":optional_object_file_group", ":optional_object_file", ":optional_interface_library", ":optional_static_library", ":optional_dynamic_library", ] + select({ # maOS has a minor nuance where it uses the path to the library instead of `-l:{library_name}`. "@platforms//os:macos": [":macos_optional_versioned_dynamic_library"], "//conditions:default": [":generic_optional_versioned_dynamic_library"], }) + select({ "@platforms//os:macos": [], "//conditions:default": [":optional_whole_archive_end"], }), ) cc_nested_args( name = "optional_whole_archive_start", nested = [":whole_archive_start_arg"], requires_true = "//cc/toolchains/variables:libraries_to_link.is_whole_archive", ) cc_nested_args( name = "whole_archive_start_arg", args = ["-Wl,-whole-archive"], requires_equal = "//cc/toolchains/variables:libraries_to_link.type", requires_equal_value = "static_library", ) cc_nested_args( name = "optional_whole_archive_end", nested = [":whole_archive_end_arg"], requires_true = "//cc/toolchains/variables:libraries_to_link.is_whole_archive", ) cc_nested_args( name = "whole_archive_end_arg", args = ["-Wl,-no-whole-archive"], requires_equal = "//cc/toolchains/variables:libraries_to_link.type", requires_equal_value = "static_library", ) library_link_args( name = "optional_object_file_group", from_variable = "//cc/toolchains/variables:libraries_to_link.object_files", iterate_over_variable = True, library_type = "object_file_group", ) library_link_args( name = "optional_object_file", from_variable = "//cc/toolchains/variables:libraries_to_link.name", library_type = "object_file", ) library_link_args( name = "optional_interface_library", from_variable = "//cc/toolchains/variables:libraries_to_link.name", library_type = "interface_library", ) library_link_args( name = "optional_static_library", from_variable = "//cc/toolchains/variables:libraries_to_link.name", library_type = "static_library", ) cc_nested_args( name = "optional_dynamic_library", args = ["-l{library}"], format = { "library": "//cc/toolchains/variables:libraries_to_link.name", }, requires_equal = "//cc/toolchains/variables:libraries_to_link.type", requires_equal_value = "dynamic_library", ) cc_nested_args( name = "generic_optional_versioned_dynamic_library", args = ["-l:{library_name}"], format = { "library_name": "//cc/toolchains/variables:libraries_to_link.name", }, requires_equal = "//cc/toolchains/variables:libraries_to_link.type", requires_equal_value = "versioned_dynamic_library", ) cc_nested_args( name = "macos_optional_versioned_dynamic_library", args = ["{library_path}"], format = { "library_path": "//cc/toolchains/variables:libraries_to_link.path", }, requires_equal = "//cc/toolchains/variables:libraries_to_link.type", requires_equal_value = "versioned_dynamic_library", ) rules_cc-0.0.11/cc/toolchains/args/libraries_to_link/private/000077500000000000000000000000001470072561500242305ustar00rootroot00000000000000rules_cc-0.0.11/cc/toolchains/args/libraries_to_link/private/BUILD000066400000000000000000000000671470072561500250150ustar00rootroot00000000000000package(default_visibility = ["//visibility:private"]) rules_cc-0.0.11/cc/toolchains/args/libraries_to_link/private/library_link_args.bzl000066400000000000000000000072011470072561500304360ustar00rootroot00000000000000# Copyright 2024 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. """Helper macros for declaring library link arguments.""" load("//cc/toolchains:nested_args.bzl", "cc_nested_args") def macos_force_load_library_args(name, variable): """A helper for declaring -force_load argument expansion for a library. This creates an argument expansion that will expand to -Wl,-force_load, if the library should be linked as a whole archive. Args: name: The name of the rule. variable: The variable to expand. """ cc_nested_args( name = name, nested = [ ":{}_force_load_library".format(name), ":{}_no_force_load_library".format(name), ], ) cc_nested_args( name = name + "_no_force_load_library", requires_false = "//cc/toolchains/variables:libraries_to_link.is_whole_archive", args = ["{library}"], format = { "library": variable, }, ) cc_nested_args( name = name + "_force_load_library", requires_true = "//cc/toolchains/variables:libraries_to_link.is_whole_archive", args = ["-Wl,-force_load,{library}"], format = { "library": variable, }, ) def library_link_args(name, library_type, from_variable, iterate_over_variable = False): """A helper for declaring a library to link. For most platforms, this expands something akin to the following: cc_nested_args( name = "foo", requires_equal = "//cc/toolchains/variables:libraries_to_link.type", requires_equal_value = "interface_library", iterate_over = None, args = ["{library}"], format = { "library": //cc/toolchains/variables:libraries_to_link.name, }, ) For macos, this expands to a more complex cc_nested_args structure that handles the -force_load flag. Args: name: The name of the rule. library_type: The type of the library. from_variable: The variable to expand. iterate_over_variable: Whether to iterate over the variable. """ native.alias( name = name, actual = select({ "@platforms//os:macos": ":macos_{}".format(name), "//conditions:default": ":generic_{}".format(name), }), ) cc_nested_args( name = "generic_{}".format(name), requires_equal = "//cc/toolchains/variables:libraries_to_link.type", requires_equal_value = library_type, iterate_over = from_variable if iterate_over_variable else None, args = ["{library}"], format = { "library": from_variable, }, ) cc_nested_args( name = "macos_{}".format(name), requires_equal = "//cc/toolchains/variables:libraries_to_link.type", requires_equal_value = library_type, iterate_over = from_variable if iterate_over_variable else None, nested = [":{}_maybe_force_load".format(name)], ) macos_force_load_library_args( name = "{}_maybe_force_load".format(name), variable = from_variable, ) rules_cc-0.0.11/cc/toolchains/args/linker_param_file/000077500000000000000000000000001470072561500225265ustar00rootroot00000000000000rules_cc-0.0.11/cc/toolchains/args/linker_param_file/BUILD000066400000000000000000000011441470072561500233100ustar00rootroot00000000000000load("//cc/toolchains:args.bzl", "cc_args") load("//cc/toolchains:args_list.bzl", "cc_args_list") package(default_visibility = ["//visibility:private"]) cc_args_list( name = "linker_param_file", args = [":use_param_file"], visibility = ["//visibility:public"], ) cc_args( name = "use_param_file", actions = [ "//cc/toolchains/actions:link_actions", "//cc/toolchains/actions:ar_actions", ], args = ["@{param_file}"], format = {"param_file": "//cc/toolchains/variables:linker_param_file"}, requires_not_none = "//cc/toolchains/variables:linker_param_file", ) rules_cc-0.0.11/cc/toolchains/args/runtime_library_search_directories/000077500000000000000000000000001470072561500262135ustar00rootroot00000000000000rules_cc-0.0.11/cc/toolchains/args/runtime_library_search_directories/BUILD000066400000000000000000000070511470072561500270000ustar00rootroot00000000000000load("//cc/toolchains:args.bzl", "cc_args") load("//cc/toolchains:args_list.bzl", "cc_args_list") load("//cc/toolchains:feature_constraint.bzl", "cc_feature_constraint") load("//cc/toolchains:nested_args.bzl", "cc_nested_args") package(default_visibility = ["//visibility:private"]) # TODO: b/27153401 - The implementation of this is particularly complex because # of what appears to be a workaround where macOS cc_test targets with # static_link_cpp_runtimes enabled utilize a $EXEC_ORIGIN/ prefix. This can be # paired down significantly after it is clear this workaround is no longer # required. cc_feature_constraint( name = "static_link_cpp_runtimes_enabled", all_of = ["//cc/toolchains/features:static_link_cpp_runtimes"], ) cc_feature_constraint( name = "static_link_cpp_runtimes_disabled", none_of = ["//cc/toolchains/features:static_link_cpp_runtimes"], ) cc_args_list( name = "runtime_library_search_directories", args = [ ":runtime_library_search_directories_static_runtimes_args", ":runtime_library_search_directories_args", ], visibility = ["//visibility:public"], ) cc_args( name = "runtime_library_search_directories_static_runtimes_args", actions = ["//cc/toolchains/actions:link_actions"], nested = [":iterate_over_search_dirs"], requires_any_of = [":static_link_cpp_runtimes_enabled"], requires_not_none = "//cc/toolchains/variables:runtime_library_search_directories", ) cc_nested_args( name = "iterate_over_search_dirs", iterate_over = "//cc/toolchains/variables:runtime_library_search_directories", nested = [ ":unit_test_static_runtime_search_dir_args", ":static_runtime_search_dir_args", ], ) cc_nested_args( name = "unit_test_static_runtime_search_dir_args", args = [ "-Xlinker", "-rpath", "-Xlinker", # TODO(b/27153401): This should probably be @loader_path on osx. "$EXEC_ORIGIN/{search_path}", ], format = { "search_path": "//cc/toolchains/variables:runtime_library_search_directories", }, requires_true = "//cc/toolchains/variables:is_cc_test", ) cc_nested_args( name = "static_runtime_search_dir_args", args = [ "-Xlinker", "-rpath", "-Xlinker", ] + select({ "@platforms//os:macos": ["@loader_path/{search_path}"], "//conditions:default": ["$ORIGIN/{search_path}"], }), format = { "search_path": "//cc/toolchains/variables:runtime_library_search_directories", }, requires_false = "//cc/toolchains/variables:is_cc_test", ) # TODO: b/27153401 - runtime_library_search_directories_args and # search_dir_args are all we need to keep if the workaround is no # longer required. cc_args( name = "runtime_library_search_directories_args", actions = ["//cc/toolchains/actions:link_actions"], nested = [":search_dir_args"], # Remove the requires_any_of here if the workaround for b/27153401 is no # longer required. requires_any_of = [":static_link_cpp_runtimes_disabled"], requires_not_none = "//cc/toolchains/variables:runtime_library_search_directories", ) cc_nested_args( name = "search_dir_args", args = [ "-Xlinker", "-rpath", "-Xlinker", ] + select({ "@platforms//os:macos": ["@loader_path/{search_path}"], "//conditions:default": ["$ORIGIN/{search_path}"], }), format = { "search_path": "//cc/toolchains/variables:runtime_library_search_directories", }, iterate_over = "//cc/toolchains/variables:runtime_library_search_directories", ) rules_cc-0.0.11/cc/toolchains/args/shared_flag/000077500000000000000000000000001470072561500213225ustar00rootroot00000000000000rules_cc-0.0.11/cc/toolchains/args/shared_flag/BUILD000066400000000000000000000004241470072561500221040ustar00rootroot00000000000000load("//cc/toolchains:args.bzl", "cc_args") package(default_visibility = ["//visibility:private"]) cc_args( name = "shared_flag", actions = ["//cc/toolchains/actions:dynamic_library_link_actions"], args = ["-shared"], visibility = ["//visibility:public"], ) rules_cc-0.0.11/cc/toolchains/args/sysroot.bzl000066400000000000000000000026071470072561500213230ustar00rootroot00000000000000# Copyright 2024 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. """Implementation of the cc_sysroot macro.""" load("//cc/toolchains:args.bzl", "cc_args") visibility("public") def cc_sysroot(name, sysroot, args = [], **kwargs): """Creates args for a sysroot. Args: name: (str) The name of the target sysroot: (bazel_skylib's directory rule) The directory that should be the sysroot. args: (List[str]) Extra command-line args to add. **kwargs: kwargs to pass to cc_args. """ cc_args( name = name, actions = [ Label("//cc/toolchains/actions:cpp_compile_actions"), Label("//cc/toolchains/actions:c_compile"), Label("//cc/toolchains/actions:link_actions"), ], args = ["--sysroot={sysroot}"] + args, format = {"sysroot": sysroot}, **kwargs ) rules_cc-0.0.11/cc/toolchains/args_list.bzl000066400000000000000000000042141470072561500206300ustar00rootroot00000000000000# Copyright 2024 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. """All providers for rule-based bazel toolchain config.""" load( "//cc/toolchains/impl:collect.bzl", "collect_args_lists", ) load(":cc_toolchain_info.bzl", "ArgsListInfo") def _cc_args_list_impl(ctx): return [collect_args_lists(ctx.attr.args, ctx.label)] cc_args_list = rule( implementation = _cc_args_list_impl, doc = """An ordered list of cc_args. This is a convenience rule to allow you to group a set of multiple `cc_args` into a single list. This particularly useful for toolchain behaviors that require different flags for different actions. Note: The order of the arguments in `args` is preserved to support order-sensitive flags. Example usage: ``` load("//cc/toolchains:cc_args.bzl", "cc_args") load("//cc/toolchains:args_list.bzl", "cc_args_list") cc_args( name = "gc_sections", actions = [ "//cc/toolchains/actions:link_actions", ], args = ["-Wl,--gc-sections"], ) cc_args( name = "function_sections", actions = [ "//cc/toolchains/actions:compile_actions", "//cc/toolchains/actions:link_actions", ], args = ["-ffunction-sections"], ) cc_args_list( name = "gc_functions", args = [ ":function_sections", ":gc_sections", ], ) ``` """, attrs = { "args": attr.label_list( providers = [ArgsListInfo], doc = "(ordered) cc_args to include in this list.", ), }, provides = [ArgsListInfo], ) rules_cc-0.0.11/cc/toolchains/capabilities/000077500000000000000000000000001470072561500205605ustar00rootroot00000000000000rules_cc-0.0.11/cc/toolchains/capabilities/BUILD000066400000000000000000000005551470072561500213470ustar00rootroot00000000000000load("//cc/toolchains:tool_capability.bzl", "cc_tool_capability") package(default_visibility = ["//visibility:public"]) cc_tool_capability( name = "supports_start_end_lib", ) cc_tool_capability( name = "supports_interface_shared_libraries", ) cc_tool_capability( name = "supports_dynamic_linker", ) cc_tool_capability( name = "supports_pic", ) rules_cc-0.0.11/cc/toolchains/cc_flags_supplier.bzl000066400000000000000000000025751470072561500223350ustar00rootroot00000000000000# Copyright 2018 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. """Rule that provides the CC_FLAGS Make variable.""" load("//cc:action_names.bzl", "CC_FLAGS_MAKE_VARIABLE_ACTION_NAME") load("//cc:find_cc_toolchain.bzl", "find_cpp_toolchain", "use_cc_toolchain") load("//cc/private/rules_impl:cc_flags_supplier_lib.bzl", "build_cc_flags") def _cc_flags_supplier_impl(ctx): cc_toolchain = find_cpp_toolchain(ctx) cc_flags = build_cc_flags(ctx, cc_toolchain, CC_FLAGS_MAKE_VARIABLE_ACTION_NAME) variables = platform_common.TemplateVariableInfo({ "CC_FLAGS": cc_flags, }) return [variables] cc_flags_supplier = rule( implementation = _cc_flags_supplier_impl, attrs = { "_cc_toolchain": attr.label(default = Label("@rules_cc//cc:current_cc_toolchain")), }, toolchains = use_cc_toolchain(), fragments = ["cpp"], ) rules_cc-0.0.11/cc/toolchains/cc_toolchain.bzl000066400000000000000000000013231470072561500212640ustar00rootroot00000000000000# Copyright 2024 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. """cc_toolchain rule""" def cc_toolchain(**kwargs): native.cc_toolchain(**kwargs) # buildifier: disable=native-cc rules_cc-0.0.11/cc/toolchains/cc_toolchain_config_info.bzl000066400000000000000000000013671470072561500236340ustar00rootroot00000000000000# Copyright 2024 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. """CcToolchainConfigInfo""" load("//cc/private/rules_impl:native.bzl", "NativeCcToolchainConfigInfo") CcToolchainConfigInfo = NativeCcToolchainConfigInfo rules_cc-0.0.11/cc/toolchains/cc_toolchain_info.bzl000066400000000000000000000232521470072561500223040ustar00rootroot00000000000000# Copyright 2024 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. """All providers for rule-based bazel toolchain config.""" # Until the providers are stabilized, ensure that rules_cc is the only place # that can access the providers directly. # Once it's stabilized, we *may* consider opening up parts of the API, or we may # decide to just require users to use the public user-facing rules. visibility([ "//cc/toolchains/...", "//tests/rule_based_toolchain/...", ]) # Note that throughout this file, we never use a list. This is because mutable # types cannot be stored in depsets. Thus, we type them as a sequence in the # provider, and convert them to a tuple in the constructor to ensure # immutability. ActionTypeInfo = provider( doc = "A type of action (eg. c-compile, c++-link-executable)", # @unsorted-dict-items fields = { "label": "(Label) The label defining this provider. Place in error messages to simplify debugging", "name": "(str) The action name, as defined by action_names.bzl", }, ) ActionTypeSetInfo = provider( doc = "A set of types of actions", # @unsorted-dict-items fields = { "label": "(Label) The label defining this provider. Place in error messages to simplify debugging", "actions": "(depset[ActionTypeInfo]) Set of action types", }, ) VariableInfo = provider( """A variable defined by the toolchain""", # @unsorted-dict-items fields = { "name": "(str) The variable name", "label": "(Label) The label defining this provider. Place in error messages to simplify debugging", "actions": "(Optional[depset[ActionTypeInfo]]) The actions this variable is available for", "type": "A type constructed using variables.types.*", }, ) BuiltinVariablesInfo = provider( doc = "The builtin variables", fields = { "variables": "(dict[str, VariableInfo]) A mapping from variable name to variable metadata.", }, ) NestedArgsInfo = provider( doc = "A provider representation of Args.add/add_all/add_joined parameters", # @unsorted-dict-items fields = { "label": "(Label) The label defining this provider. Place in error messages to simplify debugging", "nested": "(Sequence[NestedArgsInfo]) The nested arg expansion. Mutually exclusive with args", "iterate_over": "(Optional[str]) The variable to iterate over", "files": "(depset[File]) The files required to use this variable", "requires_types": "(dict[str, str]) A mapping from variables to their expected type name (not type). This means that we can require the generic type Option, rather than an Option[T]", "legacy_flag_group": "(flag_group) The flag_group this corresponds to", "unwrap_options": "(List[str]) A list of variables for which we should unwrap the option. For example, if a user writes `requires_not_none = \":foo\"`, then we change the type of foo from Option[str] to str", }, ) ArgsInfo = provider( doc = "A set of arguments to be added to the command line for specific actions", # @unsorted-dict-items fields = { "label": "(Label) The label defining this provider. Place in error messages to simplify debugging", "actions": "(depset[ActionTypeInfo]) The set of actions this is associated with", "requires_any_of": "(Sequence[FeatureConstraintInfo]) This will be enabled if any of the listed predicates are met. Equivalent to with_features", "nested": "(Optional[NestedArgsInfo]) The args expand. Equivalent to a flag group.", "files": "(depset[File]) Files required for the args", "env": "(dict[str, str]) Environment variables to apply", "allowlist_include_directories": "(depset[DirectoryInfo]) Include directories implied by these arguments that should be allowlisted in Bazel's include checker", }, ) ArgsListInfo = provider( doc = "A ordered list of arguments", # @unsorted-dict-items fields = { "label": "(Label) The label defining this provider. Place in error messages to simplify debugging", "args": "(Sequence[ArgsInfo]) The flag sets contained within", "files": "(depset[File]) The files required for all of the arguments", "by_action": "(Sequence[struct(action=ActionTypeInfo, args=List[ArgsInfo], files=depset[Files])]) Relevant information about the args keyed by the action type.", "allowlist_include_directories": "(depset[DirectoryInfo]) Include directories implied by these arguments that should be allowlisted in Bazel's include checker", }, ) FeatureInfo = provider( doc = "Contains all flag specifications for one feature.", # @unsorted-dict-items fields = { "label": "(Label) The label defining this provider. Place in error messages to simplify debugging", "name": "(str) The name of the feature", "enabled": "(bool) Whether this feature is enabled by default", "args": "(ArgsListInfo) Args enabled by this feature", "implies": "(depset[FeatureInfo]) Set of features implied by this feature", "requires_any_of": "(Sequence[FeatureSetInfo]) A list of feature sets, at least one of which is required to enable this feature. This is semantically equivalent to the requires attribute of rules_cc's FeatureInfo", "mutually_exclusive": "(Sequence[MutuallyExclusiveCategoryInfo]) Indicates that this feature is one of several mutually exclusive alternate features.", "external": "(bool) Whether a feature is defined elsewhere.", "overridable": "(bool) Whether the feature is an overridable feature.", "overrides": "(Optional[FeatureInfo]) The feature that this overrides. Must be a known feature", "allowlist_include_directories": "(depset[DirectoryInfo]) Include directories implied by this feature that should be allowlisted in Bazel's include checker", }, ) FeatureSetInfo = provider( doc = "A set of features", # @unsorted-dict-items fields = { "label": "(Label) The label defining this provider. Place in error messages to simplify debugging", "features": "(depset[FeatureInfo]) The set of features this corresponds to", }, ) FeatureConstraintInfo = provider( doc = "A predicate checking that certain features are enabled and others disabled.", # @unsorted-dict-items fields = { "label": "(Label) The label defining this provider. Place in error messages to simplify debugging", "all_of": "(depset[FeatureInfo]) A set of features which must be enabled", "none_of": "(depset[FeatureInfo]) A set of features, none of which can be enabled", }, ) MutuallyExclusiveCategoryInfo = provider( doc = "Multiple features with the category will be mutally exclusive", # @unsorted-dict-items fields = { "label": "(Label) The label defining this provider. Place in error messages to simplify debugging", "name": "(str) The name of the category", }, ) ToolInfo = provider( doc = "A binary, with additional metadata to make it useful for action configs.", # @unsorted-dict-items fields = { "label": "(Label) The label defining this provider. Place in error messages to simplify debugging", "exe": "(File) The file corresponding to the tool", "runfiles": "(runfiles) The files required to run the tool", "execution_requirements": "(Sequence[str]) A set of execution requirements of the tool", "allowlist_include_directories": "(depset[DirectoryInfo]) Built-in include directories implied by this tool that should be allowlisted in Bazel's include checker", "capabilities": "(Sequence[ToolCapabilityInfo]) Capabilities supported by the tool.", }, ) ToolCapabilityInfo = provider( doc = "A capability associated with a tool (eg. supports_pic).", # @unsorted-dict-items fields = { "label": "(Label) The label defining this provider. Place in error messages to simplify debugging", "feature": "(FeatureInfo) The feature this capability defines", }, ) ToolConfigInfo = provider( doc = "A mapping from action to tool", # @unsorted-dict-items fields = { "label": "(Label) The label defining this provider. Place in error messages to simplify debugging", "configs": "(dict[ActionTypeInfo, ToolInfo]) A mapping from action to tool.", }, ) ToolchainConfigInfo = provider( doc = "The configuration for a toolchain", # @unsorted-dict-items fields = { "label": "(Label) The label defining this provider. Place in error messages to simplify debugging", "features": "(Sequence[FeatureInfo]) The features available for this toolchain", "enabled_features": "(Sequence[FeatureInfo]) The features That are enabled by default for this toolchain", "tool_map": "(ToolConfigInfo) A provider mapping toolchain action types to tools.", "args": "(Sequence[ArgsInfo]) A list of arguments to be unconditionally applied to the toolchain.", "files": "(dict[ActionTypeInfo, depset[File]]) Files required for the toolchain, keyed by the action type.", "allowlist_include_directories": "(depset[DirectoryInfo]) Built-in include directories implied by this toolchain's args and tools that should be allowlisted in Bazel's include checker", }, ) rules_cc-0.0.11/cc/toolchains/cc_toolchain_suite.bzl000066400000000000000000000013451470072561500225010ustar00rootroot00000000000000# Copyright 2024 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. """cc_toolchain_suite rule""" def cc_toolchain_suite(**kwargs): native.cc_toolchain_suite(**kwargs) # buildifier: disable=native-cc rules_cc-0.0.11/cc/toolchains/compiler_flag.bzl000066400000000000000000000021241470072561500214420ustar00rootroot00000000000000# Copyright 2018 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. """Rule that allows select() to differentiate between compilers.""" load("//cc:find_cc_toolchain.bzl", "find_cpp_toolchain", "use_cc_toolchain") def _compiler_flag_impl(ctx): toolchain = find_cpp_toolchain(ctx) return [config_common.FeatureFlagInfo(value = toolchain.compiler)] compiler_flag = rule( implementation = _compiler_flag_impl, attrs = { "_cc_toolchain": attr.label(default = Label("@rules_cc//cc:current_cc_toolchain")), }, toolchains = use_cc_toolchain(), ) rules_cc-0.0.11/cc/toolchains/directory_tool.bzl000066400000000000000000000034461470072561500217100ustar00rootroot00000000000000# Copyright 2024 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. """Macro to extract tools from a directory.""" load("@bazel_skylib//rules/directory:glob.bzl", "directory_glob") load(":tool.bzl", "cc_tool") def cc_directory_tool(name, directory, executable, data = [], exclude = [], allow_empty = False, **kwargs): """A tool extracted from a directory. Args: name: (str) The name of the generated target directory: (Label) The directory to extract from executable: (str) The relative path from the directory to the executable. data: (List[str]) A list of globs to runfiles for the executable, relative to the directory. exclude: (List[str]) A list of globs to exclude from data. allow_empty: (bool) If false, any glob that fails to match anything will result in a failure. **kwargs: Kwargs to be passed through to cc_tool. """ files_name = "_%s_files" % name directory_glob( name = files_name, directory = directory, srcs = [executable], data = data, exclude = exclude, allow_empty = allow_empty, visibility = ["//visibility:private"], ) cc_tool( name = name, src = files_name, **kwargs ) rules_cc-0.0.11/cc/toolchains/fdo_prefetch_hints.bzl000066400000000000000000000013451470072561500225000ustar00rootroot00000000000000# Copyright 2024 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. """fdo_prefetch_hints rule""" def fdo_prefetch_hints(**kwargs): native.fdo_prefetch_hints(**kwargs) # buildifier: disable=native-cc rules_cc-0.0.11/cc/toolchains/fdo_profile.bzl000066400000000000000000000013201470072561500211240ustar00rootroot00000000000000# Copyright 2024 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. """fdo_profile rule""" def fdo_profile(**kwargs): native.fdo_profile(**kwargs) # buildifier: disable=native-cc rules_cc-0.0.11/cc/toolchains/feature.bzl000066400000000000000000000221751470072561500203020ustar00rootroot00000000000000# Copyright 2024 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. """Implementation of the cc_feature rule.""" load( "//cc/toolchains/impl:collect.bzl", "collect_args_lists", "collect_features", "collect_provider", ) load( ":cc_toolchain_info.bzl", "ArgsListInfo", "FeatureConstraintInfo", "FeatureInfo", "FeatureSetInfo", "MutuallyExclusiveCategoryInfo", ) def _cc_feature_impl(ctx): if bool(ctx.attr.feature_name) == (ctx.attr.overrides != None): fail("Exactly one of 'feature_name' and 'overrides' are required") if ctx.attr.overrides == None: overrides = None # In the future, we may consider making feature_name optional, # defaulting to ctx.label.name. However, starting that way would make it # very difficult if we did want to later change that. name = ctx.attr.feature_name else: overrides = ctx.attr.overrides[FeatureInfo] if not overrides.overridable: fail("Attempting to override %s, which is not overridable" % overrides.label) name = overrides.name # In the following scenario: # cc_args(name = "foo", env = {"FOO": "BAR"}, args = ["--foo"]) # cc_action_config(name = "ac", args=[":foo"]) # We will translate this into providers roughly equivalent to the following: # cc_args(name = "implied_by_ac_env", env = {"FOO": "BAR"}, args = ["--foo"]) # cc_feature(name = "implied_by_ac", args = [":implied_by_ac_env"]) # cc_action_config( # name = "c_compile", # implies = [":implied_by_c_compile"] # ) # The reason for this is because although the legacy providers support # flag_sets in action_config, they don't support env sets. if name.startswith("implied_by_"): fail("Feature names starting with 'implied_by' are reserved") args = collect_args_lists(ctx.attr.args, ctx.label) feature = FeatureInfo( label = ctx.label, name = name, # Unused field, but leave it just in case we want to reuse it in the # future. enabled = False, args = args, implies = collect_features(ctx.attr.implies), requires_any_of = tuple(collect_provider( ctx.attr.requires_any_of, FeatureSetInfo, )), mutually_exclusive = tuple(collect_provider( ctx.attr.mutually_exclusive, MutuallyExclusiveCategoryInfo, )), external = False, overridable = False, overrides = overrides, allowlist_include_directories = args.allowlist_include_directories, ) return [ feature, FeatureSetInfo(label = ctx.label, features = depset([feature])), FeatureConstraintInfo( label = ctx.label, all_of = depset([feature]), none_of = depset([]), ), MutuallyExclusiveCategoryInfo(label = ctx.label, name = name), ] cc_feature = rule( implementation = _cc_feature_impl, # @unsorted-dict-items attrs = { "feature_name": attr.string( doc = """The name of the feature that this rule implements. The feature name is a string that will be used in the `features` attribute of rules to enable them (eg. `cc_binary(..., features = ["opt"])`. While two features with the same `feature_name` may not be bound to the same toolchain, they can happily live alongside each other in the same BUILD file. Example: ``` cc_feature( name = "sysroot_macos", feature_name = "sysroot", ... ) cc_feature( name = "sysroot_linux", feature_name = "sysroot", ... ) ``` """, ), "args": attr.label_list( doc = """A list of `cc_args` or `cc_args_list` labels that are expanded when this feature is enabled.""", providers = [ArgsListInfo], ), "requires_any_of": attr.label_list( doc = """A list of feature sets that define toolchain compatibility. If *at least one* of the listed `cc_feature_set`s are fully satisfied (all features exist in the toolchain AND are currently enabled), this feature is deemed compatible and may be enabled. Note: Even if `cc_feature.requires_any_of` is satisfied, a feature is not enabled unless another mechanism (e.g. command-line flags, `cc_feature.implies`, `cc_toolchain_config.enabled_features`) signals that the feature should actually be enabled. """, providers = [FeatureSetInfo], ), "implies": attr.label_list( providers = [FeatureSetInfo], doc = """List of features enabled along with this feature. Warning: If any of the features cannot be enabled, this feature is silently disabled. """, ), "mutually_exclusive": attr.label_list( providers = [MutuallyExclusiveCategoryInfo], doc = """A list of things that this feature is mutually exclusive with. It can be either: * A feature, in which case the two features are mutually exclusive. * A `cc_mutually_exclusive_category`, in which case all features that write `mutually_exclusive = [":category"]` are mutually exclusive with each other. If this feature has a side-effect of implementing another feature, it can be useful to list that feature here to ensure they aren't enabled at the same time. """, ), "overrides": attr.label( providers = [FeatureInfo], doc = """A declaration that this feature overrides a known feature. In the example below, if you missed the "overrides" attribute, it would complain that the feature "opt" was defined twice. Example: ``` load("//cc/toolchains:feature.bzl", "cc_feature") cc_feature( name = "opt", feature_name = "opt", args = [":size_optimized"], overrides = "//cc/toolchains/features:opt", ) ``` """, ), }, provides = [ FeatureInfo, FeatureSetInfo, FeatureConstraintInfo, MutuallyExclusiveCategoryInfo, ], doc = """A dynamic set of toolchain flags that create a singular [feature](https://bazel.build/docs/cc-toolchain-config-reference#features) definition. A feature is basically a dynamically toggleable `cc_args_list`. There are a variety of dependencies and compatibility requirements that must be satisfied to enable a `cc_feature`. Once those conditions are met, the arguments in [`cc_feature.args`](#cc_feature-args) are expanded and added to the command-line. A feature may be enabled or disabled through the following mechanisms: * Via command-line flags, or a `.bazelrc` file via the [`--features` flag](https://bazel.build/reference/command-line-reference#flag--features) * Through inter-feature relationships (via [`cc_feature.implies`](#cc_feature-implies)) where one feature may implicitly enable another. * Individual rules (e.g. `cc_library`) or `package` definitions may elect to manually enable or disable features through the [`features` attribute](https://bazel.build/reference/be/common-definitions#common.features). Note that a feature may alternate between enabled and disabled dynamically over the course of a build. Because of their toggleable nature, it's generally best to avoid adding arguments to a `cc_toolchain` as a `cc_feature` unless strictly necessary. Instead, prefer to express arguments via [`cc_toolchain.args`](#cc_toolchain-args) whenever possible. You should use a `cc_feature` when any of the following apply: * You need the flags to be dynamically toggled over the course of a build. * You want build files to be able to configure the flags in question. For example, a binary might specify `features = ["optimize_for_size"]` to create a small binary instead of optimizing for performance. * You need to carry forward Starlark toolchain behaviors. If you're migrating a complex Starlark-based toolchain definition to these rules, many of the workflows and flags were likely based on features. If you only need to configure flags via the Bazel command-line, instead consider adding a [`bool_flag`](https://github.com/bazelbuild/bazel-skylib/tree/main/doc/common_settings_doc.md#bool_flag) paired with a [`config_setting`](https://bazel.build/reference/be/general#config_setting) and then make your `cc_args` rule `select` on the `config_setting`. For more details about how Bazel handles features, see the official Bazel documentation at https://bazel.build/docs/cc-toolchain-config-reference#features. Example: ``` load("//cc/toolchains:feature.bzl", "cc_feature") # A feature that enables LTO, which may be incompatible when doing interop with various # languages (e.g. rust, go), or may need to be disabled for particular `cc_binary` rules # for various reasons. cc_feature( name = "lto", feature_name = "lto", args = [":lto_args"], ) ``` """, ) rules_cc-0.0.11/cc/toolchains/feature_constraint.bzl000066400000000000000000000047611470072561500225470ustar00rootroot00000000000000# Copyright 2024 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. """Implementation of the cc_feature_constraint rule.""" load( "//cc/toolchains/impl:collect.bzl", "collect_features", "collect_provider", ) load( ":cc_toolchain_info.bzl", "FeatureConstraintInfo", "FeatureSetInfo", ) def _cc_feature_constraint_impl(ctx): if ctx.attr.features: fail("Features is a reserved attribute in bazel. Use the attributes `all_of` and `none_of` for feature constraints") all_of = collect_provider(ctx.attr.all_of, FeatureConstraintInfo) none_of = [collect_features(ctx.attr.none_of)] none_of.extend([fc.none_of for fc in all_of]) return [FeatureConstraintInfo( label = ctx.label, all_of = depset(transitive = [fc.all_of for fc in all_of]), none_of = depset(transitive = none_of), )] cc_feature_constraint = rule( implementation = _cc_feature_constraint_impl, attrs = { "all_of": attr.label_list( providers = [FeatureConstraintInfo], ), "none_of": attr.label_list( providers = [FeatureSetInfo], ), }, provides = [FeatureConstraintInfo], doc = """Defines a compound relationship between features. This rule can be used with [`cc_args.require_any_of`](#cc_args-require_any_of) to specify that a set of arguments are only enabled when a constraint is met. Both `all_of` and `none_of` must be satisfied simultaneously. This is basically a `cc_feature_set` that supports `none_of` expressions. This extra flexibility is why this rule may only be used by [`cc_args.require_any_of`](#cc_args-require_any_of). Example: ``` load("//cc/toolchains:feature_constraint.bzl", "cc_feature_constraint") # A constraint that requires a `linker_supports_thinlto` feature to be enabled, # AND a `no_optimization` to be disabled. cc_feature_constraint( name = "thinlto_constraint", all_of = [":linker_supports_thinlto"], none_of = [":no_optimization"], ) ``` """, ) rules_cc-0.0.11/cc/toolchains/feature_set.bzl000066400000000000000000000035161470072561500211530ustar00rootroot00000000000000# Copyright 2024 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. """Implementation of the cc_feature_set rule.""" load("//cc/toolchains/impl:collect.bzl", "collect_features") load( ":cc_toolchain_info.bzl", "FeatureConstraintInfo", "FeatureSetInfo", ) def _cc_feature_set_impl(ctx): if ctx.attr.features: fail("Features is a reserved attribute in bazel. cc_feature_set takes `all_of` instead.") features = collect_features(ctx.attr.all_of) return [ FeatureSetInfo(label = ctx.label, features = features), FeatureConstraintInfo( label = ctx.label, all_of = features, none_of = depset([]), ), ] cc_feature_set = rule( implementation = _cc_feature_set_impl, attrs = { "all_of": attr.label_list( providers = [FeatureSetInfo], doc = "A set of features", ), }, provides = [FeatureSetInfo], doc = """Defines a set of features. This may be used by both `cc_feature` and `cc_args` rules, and is effectively a way to express a logical `AND` operation across multiple requred features. Example: ``` load("//cc/toolchains:feature_set.bzl", "cc_feature_set") cc_feature_set( name = "thin_lto_requirements", all_of = [ ":thin_lto", ":opt", ], ) ``` """, ) rules_cc-0.0.11/cc/toolchains/features/000077500000000000000000000000001470072561500177455ustar00rootroot00000000000000rules_cc-0.0.11/cc/toolchains/features/BUILD000066400000000000000000000030521470072561500205270ustar00rootroot00000000000000load("//cc/toolchains:feature_set.bzl", "cc_feature_set") load("//cc/toolchains/impl:external_feature.bzl", "cc_external_feature") package(default_visibility = ["//visibility:public"]) # See https://bazel.build/docs/cc-toolchain-config-reference#wellknown-features cc_external_feature( name = "opt", feature_name = "opt", overridable = True, ) cc_external_feature( name = "dbg", feature_name = "dbg", overridable = True, ) cc_external_feature( name = "fastbuild", feature_name = "fastbuild", overridable = True, ) cc_external_feature( name = "static_linking_mode", feature_name = "static_linking_mode", overridable = True, ) cc_external_feature( name = "dynamic_linking_mode", feature_name = "dynamic_linking_mode", overridable = True, ) cc_external_feature( name = "per_object_debug_info", feature_name = "per_object_debug_info", overridable = True, ) cc_external_feature( name = "static_link_cpp_runtimes", feature_name = "static_link_cpp_runtimes", overridable = True, ) cc_feature_set( name = "all_non_legacy_builtin_features", all_of = [ ":opt", ":dbg", ":fastbuild", ":static_linking_mode", ":dynamic_linking_mode", ":per_object_debug_info", ":static_link_cpp_runtimes", ], visibility = ["//visibility:private"], ) cc_feature_set( name = "all_builtin_features", all_of = [ ":all_non_legacy_builtin_features", "//cc/toolchains/features/legacy:all_legacy_builtin_features", ], ) rules_cc-0.0.11/cc/toolchains/features/legacy/000077500000000000000000000000001470072561500212115ustar00rootroot00000000000000rules_cc-0.0.11/cc/toolchains/features/legacy/BUILD000066400000000000000000000145611470072561500220020ustar00rootroot00000000000000load("//cc/toolchains:feature_set.bzl", "cc_feature_set") load("//cc/toolchains/impl:external_feature.bzl", "cc_external_feature") package(default_visibility = ["//visibility:public"]) # See https://bazel.build/docs/cc-toolchain-config-reference#wellknown-features. cc_external_feature( name = "legacy_compile_flags", feature_name = "legacy_compile_flags", overridable = True, ) cc_external_feature( name = "default_compile_flags", feature_name = "default_compile_flags", overridable = True, ) cc_external_feature( name = "dependency_file", feature_name = "dependency_file", overridable = True, ) cc_external_feature( name = "pic", feature_name = "pic", overridable = True, ) cc_external_feature( name = "preprocessor_defines", feature_name = "preprocessor_defines", overridable = True, ) cc_external_feature( name = "includes", feature_name = "includes", overridable = True, ) cc_external_feature( name = "include_paths", feature_name = "include_paths", overridable = True, ) cc_external_feature( name = "fdo_instrument", feature_name = "fdo_instrument", overridable = True, ) cc_external_feature( name = "fdo_optimize", feature_name = "fdo_optimize", overridable = True, ) cc_external_feature( name = "cs_fdo_instrument", feature_name = "cs_fdo_instrument", overridable = True, ) cc_external_feature( name = "cs_fdo_optimize", feature_name = "cs_fdo_optimize", overridable = True, ) cc_external_feature( name = "fdo_prefetch_hints", feature_name = "fdo_prefetch_hints", overridable = True, ) cc_external_feature( name = "autofdo", feature_name = "autofdo", overridable = True, ) cc_external_feature( name = "build_interface_libraries", feature_name = "build_interface_libraries", overridable = True, ) cc_external_feature( name = "dynamic_library_linker_tool", feature_name = "dynamic_library_linker_tool", overridable = True, ) cc_external_feature( name = "shared_flag", deprecation = "Use //cc/toolchains/args/shared_flag instead", feature_name = "shared_flag", overridable = True, ) cc_external_feature( name = "linkstamps", feature_name = "linkstamps", overridable = True, ) cc_external_feature( name = "output_execpath_flags", feature_name = "output_execpath_flags", overridable = True, ) cc_external_feature( name = "runtime_library_search_directories", deprecation = "Use //cc/toolchains/args/runtime_library_search_directories instead", feature_name = "runtime_library_search_directories", overridable = True, ) cc_external_feature( name = "library_search_directories", feature_name = "library_search_directories", overridable = True, ) cc_external_feature( name = "archiver_flags", deprecation = "Use //cc/toolchains/args/archiver_flags instead", feature_name = "archiver_flags", overridable = True, ) cc_external_feature( name = "libraries_to_link", deprecation = "Use //cc/toolchains/args/libraries_to_link instead", feature_name = "libraries_to_link", overridable = True, ) cc_external_feature( name = "force_pic_flags", deprecation = "Use //cc/toolchains/args/force_pic_flags instead", feature_name = "force_pic_flags", overridable = True, ) cc_external_feature( name = "user_link_flags", feature_name = "user_link_flags", overridable = True, ) cc_external_feature( name = "legacy_link_flags", feature_name = "legacy_link_flags", overridable = True, ) cc_external_feature( name = "static_libgcc", feature_name = "static_libgcc", overridable = True, ) cc_external_feature( name = "fission_support", feature_name = "fission_support", overridable = True, ) cc_external_feature( name = "strip_debug_symbols", feature_name = "strip_debug_symbols", overridable = True, ) cc_external_feature( name = "coverage", feature_name = "coverage", overridable = True, ) cc_external_feature( name = "llvm_coverage_map_format", feature_name = "llvm_coverage_map_format", overridable = True, ) cc_external_feature( name = "gcc_coverage_map_format", feature_name = "gcc_coverage_map_format", overridable = True, ) cc_external_feature( name = "fully_static_link", feature_name = "fully_static_link", overridable = True, ) cc_external_feature( name = "user_compile_flags", feature_name = "user_compile_flags", overridable = True, ) # Instead of the "sysroot" legacy flag, use the cc_sysroot macro in # //cc/toolchains/args:sysroot.bzl cc_external_feature( name = "unfiltered_compile_flags", feature_name = "unfiltered_compile_flags", overridable = True, ) cc_external_feature( name = "linker_param_file", deprecation = "Use //cc/toolchains/args/linker_param_file instead", feature_name = "linker_param_file", overridable = True, ) cc_external_feature( name = "compiler_input_flags", feature_name = "compiler_input_flags", overridable = True, ) cc_external_feature( name = "compiler_output_flags", feature_name = "compiler_output_flags", overridable = True, ) cc_feature_set( name = "all_legacy_builtin_features", all_of = [ ":legacy_compile_flags", ":default_compile_flags", ":dependency_file", ":pic", ":preprocessor_defines", ":includes", ":include_paths", ":fdo_instrument", ":fdo_optimize", ":cs_fdo_instrument", ":cs_fdo_optimize", ":fdo_prefetch_hints", ":autofdo", ":build_interface_libraries", ":dynamic_library_linker_tool", ":shared_flag", ":linkstamps", ":output_execpath_flags", ":runtime_library_search_directories", ":library_search_directories", ":archiver_flags", ":libraries_to_link", ":force_pic_flags", ":user_link_flags", ":legacy_link_flags", ":static_libgcc", ":fission_support", ":strip_debug_symbols", ":coverage", ":llvm_coverage_map_format", ":gcc_coverage_map_format", ":fully_static_link", ":user_compile_flags", ":unfiltered_compile_flags", ":linker_param_file", ":compiler_input_flags", ":compiler_output_flags", ], visibility = ["//cc/toolchains/features:__pkg__"], ) rules_cc-0.0.11/cc/toolchains/impl/000077500000000000000000000000001470072561500170705ustar00rootroot00000000000000rules_cc-0.0.11/cc/toolchains/impl/BUILD000066400000000000000000000011631470072561500176530ustar00rootroot00000000000000# This directory contains implementations of starlark functions that contain # complex logic. The objective is to keep the rules themselves as simple as # possible, so that we can perform very thorough testing on the implementation. # I wanted to call it private / internal, but then buildifier complains about # referencing it from the tests directory. load("@bazel_skylib//:bzl_library.bzl", "bzl_library") exports_files( ["documented_api.bzl"], visibility = ["//docs:__pkg__"], ) bzl_library( name = "toolchain_impl_rules", srcs = glob(["*.bzl"]), visibility = ["//cc/toolchains:__subpackages__"], ) rules_cc-0.0.11/cc/toolchains/impl/args_utils.bzl000066400000000000000000000120031470072561500217510ustar00rootroot00000000000000# Copyright 2024 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. """Helper functions for working with args.""" load(":variables.bzl", "get_type") visibility([ "//cc/toolchains", "//tests/rule_based_toolchain/...", ]) def get_action_type(args_list, action_type): """Returns the corresponding entry in ArgsListInfo.by_action. Args: args_list: (ArgsListInfo) The args list to look through action_type: (ActionTypeInfo) The action type to look up. Returns: The information corresponding to this action type. """ for args in args_list.by_action: if args.action == action_type: return args return struct(action = action_type, args = tuple(), files = depset([])) def validate_nested_args(*, nested_args, variables, actions, label, fail = fail): """Validates the typing for an nested_args invocation. Args: nested_args: (NestedArgsInfo) The nested_args to validate variables: (Dict[str, VariableInfo]) A mapping from variable name to the metadata (variable type and valid actions). actions: (List[ActionTypeInfo]) The actions we require these variables to be valid for. label: (Label) The label of the rule we're currently validating. Used for error messages. fail: The fail function. Use for testing only. """ stack = [(nested_args, {})] for _ in range(9999999): if not stack: break nested_args, overrides = stack.pop() if nested_args.iterate_over != None or nested_args.unwrap_options: # Make sure we don't keep using the same object. overrides = dict(**overrides) if nested_args.iterate_over != None: type = get_type( name = nested_args.iterate_over, variables = variables, overrides = overrides, actions = actions, args_label = label, nested_label = nested_args.label, fail = fail, ) if type["name"] == "list": # Rewrite the type of the thing we iterate over from a List[T] # to a T. overrides[nested_args.iterate_over] = type["elements"] elif type["name"] == "option" and type["elements"]["name"] == "list": # Rewrite Option[List[T]] to T. overrides[nested_args.iterate_over] = type["elements"]["elements"] else: fail("Attempting to iterate over %s, but it was not a list - it was a %s" % (nested_args.iterate_over, type["repr"])) # 1) Validate variables marked with after_option_unwrap = False. # 2) Unwrap Option[T] to T as required. # 3) Validate variables marked with after_option_unwrap = True. for after_option_unwrap in [False, True]: for var_name, requirements in nested_args.requires_types.items(): for requirement in requirements: if requirement.after_option_unwrap == after_option_unwrap: type = get_type( name = var_name, variables = variables, overrides = overrides, actions = actions, args_label = label, nested_label = nested_args.label, fail = fail, ) if type["name"] not in requirement.valid_types: fail("{msg}, but {var_name} has type {type}".format( var_name = var_name, msg = requirement.msg, type = type["repr"], )) # Only unwrap the options after the first iteration of this loop. if not after_option_unwrap: for var in nested_args.unwrap_options: type = get_type( name = var, variables = variables, overrides = overrides, actions = actions, args_label = label, nested_label = nested_args.label, fail = fail, ) if type["name"] == "option": overrides[var] = type["elements"] for child in nested_args.nested: stack.append((child, overrides)) rules_cc-0.0.11/cc/toolchains/impl/collect.bzl000066400000000000000000000123641470072561500212340ustar00rootroot00000000000000# Copyright 2024 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. """Helper functions to allow us to collect data from attr.label_list.""" load( "//cc/toolchains:cc_toolchain_info.bzl", "ActionTypeSetInfo", "ArgsListInfo", "FeatureSetInfo", "ToolInfo", ) visibility([ "//cc/toolchains/...", "//tests/rule_based_toolchain/...", ]) def collect_provider(targets, provider): """Collects providers from a label list. Args: targets: (List[Target]) An attribute from attr.label_list provider: (provider) The provider to look up Returns: A list of the providers """ return [target[provider] for target in targets] def collect_defaultinfo(targets): """Collects DefaultInfo from a label list. Args: targets: (List[Target]) An attribute from attr.label_list Returns: A list of the associated defaultinfo """ return collect_provider(targets, DefaultInfo) def _make_collector(provider, field): def collector(targets, direct = [], transitive = []): # Avoid mutating what was passed in. transitive = transitive[:] for value in collect_provider(targets, provider): transitive.append(getattr(value, field)) return depset(direct = direct, transitive = transitive) return collector collect_action_types = _make_collector(ActionTypeSetInfo, "actions") collect_features = _make_collector(FeatureSetInfo, "features") collect_files = _make_collector(DefaultInfo, "files") def collect_data(ctx, targets): """Collects from a 'data' attribute. This is distinguished from collect_files by the fact that data attributes attributes include runfiles. Args: ctx: (Context) The ctx for the current rule targets: (List[Target]) A list of files or executables Returns: A depset containing all files for each of the targets, and all runfiles required to run them. """ return ctx.runfiles(transitive_files = collect_files(targets)).merge_all([ info.default_runfiles for info in collect_defaultinfo(targets) if info.default_runfiles != None ]) def collect_tools(ctx, targets, fail = fail): """Collects tools from a label_list. Each entry in the label list may either be a cc_tool or a binary. Args: ctx: (Context) The ctx for the current rule targets: (List[Target]) A list of targets. Each of these targets may be either a cc_tool or an executable. fail: (function) The fail function. Should only be used in tests. Returns: A List[ToolInfo], with regular executables creating custom tool info. """ tools = [] for target in targets: info = target[DefaultInfo] if ToolInfo in target: tools.append(target[ToolInfo]) elif info.files_to_run != None and info.files_to_run.executable != None: tools.append(ToolInfo( label = target.label, exe = info.files_to_run.executable, runfiles = collect_data(ctx, [target]), execution_requirements = tuple(), allowlist_include_directories = depset(), capabilities = tuple(), )) else: fail("Expected %s to be a cc_tool or a binary rule" % target.label) return tools def collect_args_lists(targets, label): """Collects a label_list of ArgsListInfo into a single ArgsListInfo Args: targets: (List[Target]) A label_list of targets providing ArgsListInfo label: The label to attach to the resulting ArgsListInfo Returns: An ArgsListInfo that is the result of joining all of the ArgsListInfos together. """ args = [] by_action = {} transitive_files = [] for target in targets: args_list = target[ArgsListInfo] args.extend(args_list.args) transitive_files.extend([args_info.files for args_info in args_list.args]) for value in args_list.by_action: out = by_action.setdefault( value.action, struct(args = [], transitive_files = [], action = value.action), ) out.args.extend(value.args) out.transitive_files.append(value.files) return ArgsListInfo( label = label, args = tuple(args), files = depset(transitive = transitive_files), allowlist_include_directories = depset( transitive = [a.allowlist_include_directories for a in args], ), by_action = tuple([ struct( action = k, args = tuple(v.args), files = depset(transitive = v.transitive_files), ) for k, v in by_action.items() ]), ) rules_cc-0.0.11/cc/toolchains/impl/documented_api.bzl000066400000000000000000000053471470072561500225720ustar00rootroot00000000000000# Copyright 2024 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 is a list of rules/macros that should be exported as documentation.""" load("//cc/toolchains:actions.bzl", _cc_action_type = "cc_action_type", _cc_action_type_set = "cc_action_type_set") load("//cc/toolchains:args.bzl", _cc_args = "cc_args") load("//cc/toolchains:args_list.bzl", _cc_args_list = "cc_args_list") load("//cc/toolchains:feature.bzl", _cc_feature = "cc_feature") load("//cc/toolchains:feature_constraint.bzl", _cc_feature_constraint = "cc_feature_constraint") load("//cc/toolchains:feature_set.bzl", _cc_feature_set = "cc_feature_set") load("//cc/toolchains:mutually_exclusive_category.bzl", _cc_mutually_exclusive_category = "cc_mutually_exclusive_category") load("//cc/toolchains:nested_args.bzl", _cc_nested_args = "cc_nested_args") load("//cc/toolchains:tool.bzl", _cc_tool = "cc_tool") load("//cc/toolchains:tool_capability.bzl", _cc_tool_capability = "cc_tool_capability") load("//cc/toolchains:tool_map.bzl", _cc_tool_map = "cc_tool_map") load("//cc/toolchains/impl:external_feature.bzl", _cc_external_feature = "cc_external_feature") load("//cc/toolchains/impl:variables.bzl", _cc_variable = "cc_variable") cc_tool_map = _cc_tool_map cc_tool = _cc_tool cc_tool_capability = _cc_tool_capability cc_args = _cc_args cc_nested_args = _cc_nested_args cc_args_list = _cc_args_list cc_action_type = _cc_action_type cc_action_type_set = _cc_action_type_set cc_variable = _cc_variable cc_feature = _cc_feature cc_feature_constraint = _cc_feature_constraint cc_feature_set = _cc_feature_set cc_mutually_exclusive_category = _cc_mutually_exclusive_category cc_external_feature = _cc_external_feature # This list is used to automatically remap instances of `foo` to [`foo`](#foo) # links in the generated documentation so that maintainers don't need to manually # ensure every reference to a rule is properly linked. DOCUMENTED_TOOLCHAIN_RULES = [ "cc_tool_map", "cc_tool", "cc_tool_capability", "cc_args", "cc_nested_args", "cc_args_list", "cc_action_type", "cc_action_type_set", "cc_variable", "cc_feature", "cc_feature_constraint", "cc_feature_set", "cc_mutually_exclusive_category", "cc_external_feature", ] rules_cc-0.0.11/cc/toolchains/impl/external_feature.bzl000066400000000000000000000061161470072561500231420ustar00rootroot00000000000000# Copyright 2024 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. """Implementation of the cc_external_feature rule.""" load( "//cc/toolchains:cc_toolchain_info.bzl", "ArgsListInfo", "FeatureConstraintInfo", "FeatureInfo", "FeatureSetInfo", ) visibility([ "//cc/toolchains/...", "//tests/rule_based_toolchain/...", ]) def _cc_external_feature_impl(ctx): feature = FeatureInfo( label = ctx.label, name = ctx.attr.feature_name, enabled = False, args = ArgsListInfo( label = ctx.label, args = (), files = depset([]), by_action = (), ), implies = depset([]), requires_any_of = (), mutually_exclusive = (), external = True, overridable = ctx.attr.overridable, overrides = None, allowlist_include_directories = depset(), ) providers = [ feature, FeatureSetInfo(label = ctx.label, features = depset([feature])), FeatureConstraintInfo( label = ctx.label, all_of = depset([feature]), none_of = depset([]), ), ] return providers cc_external_feature = rule( implementation = _cc_external_feature_impl, attrs = { "feature_name": attr.string( mandatory = True, doc = "The name of the feature", ), "overridable": attr.bool( doc = "Whether the feature can be overridden", mandatory = True, ), }, provides = [FeatureInfo, FeatureSetInfo, FeatureConstraintInfo], doc = """A declaration that a [feature](https://bazel.build/docs/cc-toolchain-config-reference#features) with this name is defined elsewhere. This rule communicates that a feature has been defined externally to make it possible to reference features that live outside the rule-based cc toolchain ecosystem. This allows various toolchain rules to reference the external feature without accidentally re-defining said feature. This rule is currently considered a private API of the toolchain rules to encourage the Bazel ecosystem to migrate to properly defining their features as rules. Example: ``` load("//cc/toolchains:external_feature.bzl", "cc_external_feature") # rules_rust defines a feature that is disabled whenever rust artifacts are being linked using # the cc toolchain to signal that incompatible flags should be disabled as well. cc_external_feature( name = "rules_rust_unsupported_feature", feature_name = "rules_rust_unsupported_feature", overridable = False, ) ``` """, ) rules_cc-0.0.11/cc/toolchains/impl/legacy_converter.bzl000066400000000000000000000141251470072561500231370ustar00rootroot00000000000000# Copyright 2024 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. """Conversion helper functions to legacy cc_toolchain_config_info.""" load( "//cc:cc_toolchain_config_lib.bzl", legacy_action_config = "action_config", legacy_env_entry = "env_entry", legacy_env_set = "env_set", legacy_feature = "feature", legacy_feature_set = "feature_set", legacy_flag_set = "flag_set", legacy_tool = "tool", legacy_with_feature_set = "with_feature_set", ) load( "//cc/toolchains:cc_toolchain_info.bzl", "ArgsListInfo", "FeatureInfo", ) visibility([ "//cc/toolchains/...", "//tests/rule_based_toolchain/...", ]) # Note that throughout this file, we sort anything for which the order is # nondeterministic (eg. depset's .to_list(), dictionary iteration). # This allows our tests to call equals() on the output, # and *may* provide better caching properties. def _convert_actions(actions): return sorted([action.name for action in actions.to_list()]) def convert_feature_constraint(constraint): return legacy_with_feature_set( features = sorted([ft.name for ft in constraint.all_of.to_list()]), not_features = sorted([ft.name for ft in constraint.none_of.to_list()]), ) def convert_args(args): """Converts an ArgsInfo to flag_sets and env_sets. Args: args: (ArgsInfo) The args to convert Returns: struct(flag_sets = List[flag_set], env_sets = List[env_sets]) """ actions = _convert_actions(args.actions) with_features = [ convert_feature_constraint(fc) for fc in args.requires_any_of ] flag_sets = [] if args.nested != None: flag_sets.append(legacy_flag_set( actions = actions, with_features = with_features, flag_groups = [args.nested.legacy_flag_group], )) env_sets = [] if args.env: env_sets.append(legacy_env_set( actions = actions, with_features = with_features, env_entries = [ legacy_env_entry( key = key, value = value, ) for key, value in args.env.items() ], )) return struct( flag_sets = flag_sets, env_sets = env_sets, ) def _convert_args_sequence(args_sequence): flag_sets = [] env_sets = [] for args in args_sequence: legacy_args = convert_args(args) flag_sets.extend(legacy_args.flag_sets) env_sets.extend(legacy_args.env_sets) return struct(flag_sets = flag_sets, env_sets = env_sets) def convert_feature(feature, enabled = False): if feature.external: return None args = _convert_args_sequence(feature.args.args) return legacy_feature( name = feature.name, enabled = enabled or feature.enabled, flag_sets = args.flag_sets, env_sets = args.env_sets, implies = sorted([ft.name for ft in feature.implies.to_list()]), requires = [ legacy_feature_set(sorted([ feature.name for feature in requirement.features.to_list() ])) for requirement in feature.requires_any_of ], provides = [ mutex.name for mutex in feature.mutually_exclusive ], ) def convert_tool(tool): return legacy_tool( tool = tool.exe, execution_requirements = list(tool.execution_requirements), with_features = [], ) def convert_capability(capability): return legacy_feature( name = capability.name, enabled = False, ) def _convert_tool_map(tool_map): action_configs = [] caps = {} for action_type, tool in tool_map.configs.items(): action_configs.append(legacy_action_config( action_name = action_type.name, enabled = True, tools = [convert_tool(tool)], implies = [cap.feature.name for cap in tool.capabilities], )) for cap in tool.capabilities: caps[cap] = None cap_features = [ legacy_feature(name = cap.feature.name, enabled = False) for cap in caps ] return action_configs, cap_features def convert_toolchain(toolchain): """Converts a rule-based toolchain into the legacy providers. Args: toolchain: (ToolchainConfigInfo) The toolchain config to convert. Returns: A struct containing parameters suitable to pass to cc_common.create_cc_toolchain_config_info. """ features = [ convert_feature(feature, enabled = feature in toolchain.enabled_features) for feature in toolchain.features ] action_configs, cap_features = _convert_tool_map(toolchain.tool_map) features.extend(cap_features) features.append(convert_feature(FeatureInfo( # We reserve names starting with implied_by. This ensures we don't # conflict with the name of a feature the user creates. name = "implied_by_always_enabled", enabled = True, args = ArgsListInfo(args = toolchain.args), implies = depset([]), requires_any_of = [], mutually_exclusive = [], external = False, allowlist_include_directories = depset(), ))) cxx_builtin_include_directories = [ d.path for d in toolchain.allowlist_include_directories.to_list() ] return struct( features = [ft for ft in features if ft != None], action_configs = sorted(action_configs, key = lambda ac: ac.action_name), cxx_builtin_include_directories = cxx_builtin_include_directories, ) rules_cc-0.0.11/cc/toolchains/impl/markdown_helpers.bzl000066400000000000000000000032041470072561500231440ustar00rootroot00000000000000# Copyright 2024 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. """A few small helpers for working with Markdown.""" def markdown_link(link_text, href): """Creates a markdown link. Args: link_text: The text to display for the link. href: The href for the link. Returns: A markdown link. """ return "[" + link_text + "](" + href + ")" def xref_substitutions(match_text_patterns): """Creates a dictionary of substitutions for use for linkification of text. Example: ``` # Produces a dictionary containing: # { # "foo": "[foo](http://foo.com)" # "bar": "[bar](http://bar.com)" # } substitutions = xref_substitutions({ "foo": "http://foo.com", "bar": "http://bar.com", }) ``` Args: match_text_patterns: A dictionary mapping string literals to the links they should point to. Returns: A dictionary of string literals mapped to their linkified substitutions. """ return { match_text: markdown_link(match_text, href) for match_text, href in match_text_patterns.items() } rules_cc-0.0.11/cc/toolchains/impl/nested_args.bzl000066400000000000000000000323121470072561500221000ustar00rootroot00000000000000# Copyright 2024 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. """Helper functions for working with args.""" load("@bazel_skylib//rules/directory:providers.bzl", "DirectoryInfo") load("//cc:cc_toolchain_config_lib.bzl", "flag_group", "variable_with_value") load("//cc/toolchains:cc_toolchain_info.bzl", "NestedArgsInfo", "VariableInfo") load(":collect.bzl", "collect_files", "collect_provider") visibility([ "//cc/toolchains", "//tests/rule_based_toolchain/...", ]) REQUIRES_MUTUALLY_EXCLUSIVE_ERR = "requires_none, requires_not_none, requires_true, requires_false, and requires_equal are mutually exclusive" REQUIRES_NOT_NONE_ERR = "requires_not_none only works on options" REQUIRES_NONE_ERR = "requires_none only works on options" REQUIRES_TRUE_ERR = "requires_true only works on bools" REQUIRES_FALSE_ERR = "requires_false only works on bools" REQUIRES_EQUAL_ERR = "requires_equal only works on strings" REQUIRES_EQUAL_VALUE_ERR = "When requires_equal is provided, you must also provide requires_equal_value to specify what it should be equal to" FORMAT_ARGS_ERR = "format only works on string, file, or directory type variables" # @unsorted-dict-items. NESTED_ARGS_ATTRS = { "args": attr.string_list( doc = """json-encoded arguments to be added to the command-line. Usage: cc_args( ..., args = ["--foo={foo}"], format = { "//cc/toolchains/variables:foo": "foo" }, ) This is equivalent to flag_group(flags = ["--foo", "%{foo}"]) Mutually exclusive with nested. """, ), "nested": attr.label_list( providers = [NestedArgsInfo], doc = """nested_args that should be added on the command-line. Mutually exclusive with args.""", ), "data": attr.label_list( allow_files = True, doc = """Files required to add this argument to the command-line. For example, a flag that sets the header directory might add the headers in that directory as additional files. """, ), "format": attr.label_keyed_string_dict( doc = "Variables to be used in substitutions", ), "iterate_over": attr.label(providers = [VariableInfo], doc = "Replacement for flag_group.iterate_over"), "requires_not_none": attr.label(providers = [VariableInfo], doc = "Replacement for flag_group.expand_if_available"), "requires_none": attr.label(providers = [VariableInfo], doc = "Replacement for flag_group.expand_if_not_available"), "requires_true": attr.label(providers = [VariableInfo], doc = "Replacement for flag_group.expand_if_true"), "requires_false": attr.label(providers = [VariableInfo], doc = "Replacement for flag_group.expand_if_false"), "requires_equal": attr.label(providers = [VariableInfo], doc = "Replacement for flag_group.expand_if_equal"), "requires_equal_value": attr.string(), } def _var(target): if target == None: return None return target[VariableInfo].name # TODO: Consider replacing this with a subrule in the future. However, maybe not # for a long time, since it'll break compatibility with all bazel versions < 7. def nested_args_provider_from_ctx(ctx): """Gets the nested args provider from a rule that has NESTED_ARGS_ATTRS. Args: ctx: The rule context Returns: NestedArgsInfo """ return nested_args_provider( label = ctx.label, args = ctx.attr.args, format = ctx.attr.format, nested = collect_provider(ctx.attr.nested, NestedArgsInfo), files = collect_files(ctx.attr.data + getattr(ctx.attr, "allowlist_include_directories", [])), iterate_over = ctx.attr.iterate_over, requires_not_none = _var(ctx.attr.requires_not_none), requires_none = _var(ctx.attr.requires_none), requires_true = _var(ctx.attr.requires_true), requires_false = _var(ctx.attr.requires_false), requires_equal = _var(ctx.attr.requires_equal), requires_equal_value = ctx.attr.requires_equal_value, ) def nested_args_provider( *, label, args = [], nested = [], format = {}, files = depset([]), iterate_over = None, requires_not_none = None, requires_none = None, requires_true = None, requires_false = None, requires_equal = None, requires_equal_value = "", fail = fail): """Creates a validated NestedArgsInfo. Does not validate types, as you can't know the type of a variable until you have a cc_args wrapping it, because the outer layers can change that type using iterate_over. Args: label: (Label) The context we are currently evaluating in. Used for error messages. args: (List[str]) The command-line arguments to add. nested: (List[NestedArgsInfo]) command-line arguments to expand. format: (dict[Target, str]) A mapping from target to format string name files: (depset[File]) Files required for this set of command-line args. iterate_over: (Optional[Target]) Target for the variable to iterate over requires_not_none: (Optional[str]) If provided, this NestedArgsInfo will be ignored if the variable is None requires_none: (Optional[str]) If provided, this NestedArgsInfo will be ignored if the variable is not None requires_true: (Optional[str]) If provided, this NestedArgsInfo will be ignored if the variable is false requires_false: (Optional[str]) If provided, this NestedArgsInfo will be ignored if the variable is true requires_equal: (Optional[str]) If provided, this NestedArgsInfo will be ignored if the variable is not equal to requires_equal_value. requires_equal_value: (str) The value to compare the requires_equal variable with fail: A fail function. Use only for testing. Returns: NestedArgsInfo """ if bool(args) and bool(nested): fail("Args and nested are mutually exclusive") replacements = {} if iterate_over: # Since the user didn't assign a name to iterate_over, allow them to # reference it as "--foo={}" replacements[""] = iterate_over # Intentionally ensure that {} clashes between an explicit user format # string "" and the implicit one provided by iterate_over. for target, name in format.items(): if name in replacements: fail("Both %s and %s have the format string name %r" % ( target.label, replacements[name].label, name, )) replacements[name] = target # Intentionally ensure that we do not have to use the variable provided by # iterate_over in the format string. # For example, a valid use case is: # cc_args( # nested = ":nested", # iterate_over = "//cc/toolchains/variables:libraries_to_link", # ) # cc_nested_args( # args = ["{}"], # iterate_over = "//cc/toolchains/variables:libraries_to_link.object_files", # ) args = format_args(args, replacements, must_use = format.values(), fail = fail) transitive_files = [ea.files for ea in nested] transitive_files.append(files) has_value = [attr for attr in [ requires_not_none, requires_none, requires_true, requires_false, requires_equal, ] if attr != None] # We may want to reconsider this down the line, but it's easier to open up # an API than to lock down an API. if len(has_value) > 1: fail(REQUIRES_MUTUALLY_EXCLUSIVE_ERR) kwargs = {} if args: kwargs["flags"] = args requires_types = {} if nested: kwargs["flag_groups"] = [ea.legacy_flag_group for ea in nested] unwrap_options = [] if iterate_over: kwargs["iterate_over"] = _var(iterate_over) if requires_not_none: kwargs["expand_if_available"] = requires_not_none requires_types.setdefault(requires_not_none, []).append(struct( msg = REQUIRES_NOT_NONE_ERR, valid_types = ["option"], after_option_unwrap = False, )) unwrap_options.append(requires_not_none) elif requires_none: kwargs["expand_if_not_available"] = requires_none requires_types.setdefault(requires_none, []).append(struct( msg = REQUIRES_NONE_ERR, valid_types = ["option"], after_option_unwrap = False, )) elif requires_true: kwargs["expand_if_true"] = requires_true requires_types.setdefault(requires_true, []).append(struct( msg = REQUIRES_TRUE_ERR, valid_types = ["bool"], after_option_unwrap = True, )) unwrap_options.append(requires_true) elif requires_false: kwargs["expand_if_false"] = requires_false requires_types.setdefault(requires_false, []).append(struct( msg = REQUIRES_FALSE_ERR, valid_types = ["bool"], after_option_unwrap = True, )) unwrap_options.append(requires_false) elif requires_equal: if not requires_equal_value: fail(REQUIRES_EQUAL_VALUE_ERR) kwargs["expand_if_equal"] = variable_with_value( name = requires_equal, value = requires_equal_value, ) unwrap_options.append(requires_equal) requires_types.setdefault(requires_equal, []).append(struct( msg = REQUIRES_EQUAL_ERR, valid_types = ["string"], after_option_unwrap = True, )) for arg in format: if VariableInfo in arg: requires_types.setdefault(arg[VariableInfo].name, []).append(struct( msg = FORMAT_ARGS_ERR, valid_types = ["string", "file", "directory"], after_option_unwrap = True, )) return NestedArgsInfo( label = label, nested = nested, files = depset(transitive = transitive_files), iterate_over = _var(iterate_over), unwrap_options = unwrap_options, requires_types = requires_types, legacy_flag_group = flag_group(**kwargs), ) def _escape(s): return s.replace("%", "%%") def _format_target(target, fail = fail): if VariableInfo in target: return "%%{%s}" % target[VariableInfo].name elif DirectoryInfo in target: return _escape(target[DirectoryInfo].path) files = target[DefaultInfo].files.to_list() if len(files) == 1: return _escape(files[0].path) fail("%s should be either a variable, a directory, or a single file." % target.label) def format_args(args, format, must_use = [], fail = fail): """Lists all of the variables referenced by an argument. Eg: format_args(["--foo", "--bar={bar}"], {"bar": VariableInfo(name="bar")}) => ["--foo", "--bar=%{bar}"] Args: args: (List[str]) The command-line arguments. format: (Dict[str, Target]) A mapping of substitutions from key to target. must_use: (List[str]) A list of substitutions that must be used. fail: The fail function. Used for tests Returns: A string defined to be compatible with flag groups. """ formatted = [] used_vars = {} for arg in args: upto = 0 out = [] has_format = False # This should be "while true". I used this number because it's an upper # bound of the number of iterations. for _ in range(len(arg)): if upto >= len(arg): break # Escaping via "{{" and "}}" if arg[upto] in "{}" and upto + 1 < len(arg) and arg[upto + 1] == arg[upto]: out.append(arg[upto]) upto += 2 elif arg[upto] == "{": chunks = arg[upto + 1:].split("}", 1) if len(chunks) != 2: fail("Unmatched { in %r" % arg) variable = chunks[0] if variable not in format: fail('Unknown variable %r in format string %r. Try using cc_args(..., format = {"//path/to:variable": %r})' % (variable, arg, variable)) elif has_format: fail("The format string %r contained multiple variables, which is unsupported." % arg) else: used_vars[variable] = None has_format = True out.append(_format_target(format[variable], fail = fail)) upto += len(variable) + 2 elif arg[upto] == "}": fail("Unexpected } in %r" % arg) else: out.append(_escape(arg[upto])) upto += 1 formatted.append("".join(out)) unused_vars = [var for var in must_use if var not in used_vars] if unused_vars: fail("The variable %r was not used in the format string." % unused_vars[0]) return formatted rules_cc-0.0.11/cc/toolchains/impl/toolchain_config.bzl000066400000000000000000000074451470072561500231200ustar00rootroot00000000000000# Copyright 2024 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. """Implementation of the cc_toolchain rule.""" load( "//cc/toolchains:cc_toolchain_info.bzl", "ActionTypeSetInfo", "ArgsListInfo", "FeatureSetInfo", "ToolConfigInfo", "ToolchainConfigInfo", ) load(":collect.bzl", "collect_action_types") load(":legacy_converter.bzl", "convert_toolchain") load(":toolchain_config_info.bzl", "toolchain_config_info") visibility([ "//cc/toolchains/...", "//tests/rule_based_toolchain/...", ]) def _cc_legacy_file_group_impl(ctx): files = ctx.attr.config[ToolchainConfigInfo].files return [DefaultInfo(files = depset(transitive = [ files[action] for action in collect_action_types(ctx.attr.actions).to_list() if action in files ]))] cc_legacy_file_group = rule( implementation = _cc_legacy_file_group_impl, attrs = { "actions": attr.label_list(providers = [ActionTypeSetInfo], mandatory = True), "config": attr.label(providers = [ToolchainConfigInfo], mandatory = True), }, ) def _cc_toolchain_config_impl(ctx): if ctx.attr.features: fail("Features is a reserved attribute in bazel. Did you mean 'known_features' or 'enabled_features'?") toolchain_config = toolchain_config_info( label = ctx.label, known_features = ctx.attr.known_features + [ctx.attr._builtin_features], enabled_features = ctx.attr.enabled_features, tool_map = ctx.attr.tool_map, args = ctx.attr.args, ) legacy = convert_toolchain(toolchain_config) return [ toolchain_config, cc_common.create_cc_toolchain_config_info( ctx = ctx, action_configs = legacy.action_configs, features = legacy.features, cxx_builtin_include_directories = legacy.cxx_builtin_include_directories, # toolchain_identifier is deprecated, but setting it to None results # in an error that it expected a string, and for safety's sake, I'd # prefer to provide something unique. toolchain_identifier = str(ctx.label), # These fields are only relevant for legacy toolchain resolution. target_system_name = "", target_cpu = "", target_libc = "", compiler = "", abi_version = "", abi_libc_version = "", ), # This allows us to support all_files. # If all_files was simply an alias to # //cc/toolchains/actions:all_actions, # then if a toolchain introduced a new type of action, it wouldn't get # put in all_files. DefaultInfo(files = depset(transitive = toolchain_config.files.values())), ] cc_toolchain_config = rule( implementation = _cc_toolchain_config_impl, # @unsorted-dict-items attrs = { # Attributes new to this rule. "tool_map": attr.label(providers = [ToolConfigInfo], mandatory = True), "args": attr.label_list(providers = [ArgsListInfo]), "known_features": attr.label_list(providers = [FeatureSetInfo]), "enabled_features": attr.label_list(providers = [FeatureSetInfo]), "_builtin_features": attr.label(default = "//cc/toolchains/features:all_builtin_features"), }, provides = [ToolchainConfigInfo], ) rules_cc-0.0.11/cc/toolchains/impl/toolchain_config_info.bzl000066400000000000000000000167531470072561500241350ustar00rootroot00000000000000# Copyright 2024 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. """Helper functions to create and validate a ToolchainConfigInfo.""" load("//cc/toolchains:cc_toolchain_info.bzl", "ToolConfigInfo", "ToolchainConfigInfo") load(":args_utils.bzl", "get_action_type") load(":collect.bzl", "collect_args_lists", "collect_features") visibility([ "//cc/toolchains/...", "//tests/rule_based_toolchain/...", ]) _FEATURE_NAME_ERR = """The feature name {name} was defined by both {lhs} and {rhs}. Possible causes: * If you're overriding a feature in //cc/toolchains/features/..., then try adding the "overrides" parameter instead of specifying a feature name. * If you intentionally have multiple features with the same name (eg. one for ARM and one for x86), then maybe you need add select() calls so that they're not defined at the same time. * Otherwise, this is probably a real problem, and you need to give them different names. """ _INVALID_CONSTRAINT_ERR = """It is impossible to enable {provider}. None of the entries in requires_any_of could be matched. This is required features are not implicitly added to the toolchain. It's likely that the feature that you require needs to be added to the toolchain explicitly. """ _UNKNOWN_FEATURE_ERR = """{self} implies the feature {ft}, which was unable to be found. Implied features are not implicitly added to your toolchain. You likely need to add features = ["{ft}"] to your cc_toolchain rule. """ # Equality comparisons with bazel do not evaluate depsets. # s = struct() # d = depset([s]) # depset([s]) != depset([s]) # d == d # This means that complex structs such as FeatureInfo will only compare as equal # iff they are the *same* object or if there are no depsets inside them. # Unfortunately, it seems that the FeatureInfo is copied during the # cc_action_type_config rule. Ideally we'd like to fix that, but I don't really # know what power we even have over such a thing. def _feature_key(feature): # This should be sufficiently unique. return (feature.label, feature.name) def _get_known_features(features, capability_features, fail): feature_names = {} for ft in capability_features + features: if ft.name in feature_names: other = feature_names[ft.name] if other.overrides != ft and ft.overrides != other: fail(_FEATURE_NAME_ERR.format( name = ft.name, lhs = ft.label, rhs = other.label, )) feature_names[ft.name] = ft return {_feature_key(feature): None for feature in features} def _can_theoretically_be_enabled(requirement, known_features): return all([ _feature_key(ft) in known_features for ft in requirement ]) def _validate_requires_any_of(fn, self, known_features, fail): valid = any([ _can_theoretically_be_enabled(fn(requirement), known_features) for requirement in self.requires_any_of ]) # No constraints is always valid. if self.requires_any_of and not valid: fail(_INVALID_CONSTRAINT_ERR.format(provider = self.label)) def _validate_requires_any_of_feature_set(self, known_features, fail): return _validate_requires_any_of( lambda feature_set: feature_set.features.to_list(), self, known_features, fail, ) def _validate_implies(self, known_features, fail = fail): for ft in self.implies.to_list(): if _feature_key(ft) not in known_features: fail(_UNKNOWN_FEATURE_ERR.format(self = self.label, ft = ft.label)) def _validate_args(self, known_features, fail): return _validate_requires_any_of( lambda constraint: constraint.all_of.to_list(), self, known_features, fail, ) def _validate_feature(self, known_features, fail): _validate_requires_any_of_feature_set(self, known_features, fail = fail) for arg in self.args.args: _validate_args(arg, known_features, fail = fail) _validate_implies(self, known_features, fail = fail) def _validate_toolchain(self, fail = fail): capabilities = [] for tool in self.tool_map.configs.values(): capabilities.extend([cap.feature for cap in tool.capabilities]) known_features = _get_known_features(self.features, capabilities, fail = fail) for feature in self.features: _validate_feature(feature, known_features, fail = fail) for args in self.args: _validate_args(args, known_features, fail = fail) def _collect_files_for_action_type(action_type, tool_map, features, args): transitive_files = [tool_map[action_type].runfiles.files, get_action_type(args, action_type).files] for ft in features: transitive_files.append(get_action_type(ft.args, action_type).files) return depset(transitive = transitive_files) def toolchain_config_info(label, known_features = [], enabled_features = [], args = [], tool_map = None, fail = fail): """Generates and validates a ToolchainConfigInfo from lists of labels. Args: label: (Label) The label to apply to the ToolchainConfigInfo known_features: (List[Target]) A list of features that can be enabled. enabled_features: (List[Target]) A list of features that are enabled by default. Every enabled feature is implicitly also a known feature. args: (List[Target]) A list of targets providing ArgsListInfo tool_map: (Target) A target providing ToolMapInfo. fail: A fail function. Use only during tests. Returns: A validated ToolchainConfigInfo """ # Later features will come after earlier features on the command-line, and # thus override them. Because of this, we ensure that known_features comes # *after* enabled_features, so that if we do enable them, they override the # default feature flags. features = collect_features(enabled_features + known_features).to_list() enabled_features = collect_features(enabled_features).to_list() if tool_map == None: fail("tool_map is required") # The `return` here is to support testing, since injecting `fail()` has a # side-effect of allowing code to continue. return None # buildifier: disable=unreachable args = collect_args_lists(args, label = label) tools = tool_map[ToolConfigInfo].configs files = { action_type: _collect_files_for_action_type(action_type, tools, features, args) for action_type in tools.keys() } allowlist_include_directories = depset( transitive = [ src.allowlist_include_directories for src in features + tools.values() ] + [args.allowlist_include_directories], ) toolchain_config = ToolchainConfigInfo( label = label, features = features, enabled_features = enabled_features, tool_map = tool_map[ToolConfigInfo], args = args.args, files = files, allowlist_include_directories = allowlist_include_directories, ) _validate_toolchain(toolchain_config, fail = fail) return toolchain_config rules_cc-0.0.11/cc/toolchains/impl/variables.bzl000066400000000000000000000160301470072561500215510ustar00rootroot00000000000000# Copyright 2024 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. """Rules for accessing cc build variables in bazel toolchains safely.""" load("//cc/toolchains:cc_toolchain_info.bzl", "ActionTypeSetInfo", "BuiltinVariablesInfo", "VariableInfo") load(":collect.bzl", "collect_action_types", "collect_provider") visibility([ "//cc/toolchains/variables", "//tests/rule_based_toolchain/...", ]) types = struct( unknown = dict(name = "unknown", repr = "unknown"), void = dict(name = "void", repr = "void"), string = dict(name = "string", repr = "string"), bool = dict(name = "bool", repr = "bool"), # File and directory are basically the same thing as string for now. file = dict(name = "file", repr = "File"), directory = dict(name = "directory", repr = "directory"), option = lambda element: dict( name = "option", elements = element, repr = "Option[%s]" % element["repr"], ), list = lambda elements: dict( name = "list", elements = elements, repr = "List[%s]" % elements["repr"], ), struct = lambda **kv: dict( name = "struct", kv = kv, repr = "struct(%s)" % ", ".join([ "{k}={v}".format(k = k, v = v["repr"]) for k, v in sorted(kv.items()) ]), ), ) def _cc_variable_impl(ctx): return [VariableInfo( name = ctx.label.name, label = ctx.label, type = json.decode(ctx.attr.type), actions = collect_action_types(ctx.attr.actions) if ctx.attr.actions else None, )] _cc_variable = rule( implementation = _cc_variable_impl, attrs = { "actions": attr.label_list(providers = [ActionTypeSetInfo]), "type": attr.string(mandatory = True), }, provides = [VariableInfo], ) def cc_variable(name, type, **kwargs): """Exposes a toolchain variable to use in toolchain argument expansions. This internal rule exposes [toolchain variables](https://bazel.build/docs/cc-toolchain-config-reference#cctoolchainconfiginfo-build-variables) that may be expanded in `cc_args` or `cc_nested_args` rules. Because these varaibles merely expose variables inherrent to Bazel, it's not possible to declare custom variables. For a full list of available variables, see [//third_party/bazel_rules/rules_cc/cc/toolchains/varaibles:BUILD](https://github.com/bazelbuild/rules_cc/tree/main/cc/toolchains/variables/BUILD). Example: ``` load("//cc/toolchains/impl:variables.bzl", "cc_variable") # Defines two targets, ":foo" and ":foo.bar" cc_variable( name = "foo", type = types.list(types.struct(bar = types.string)), ) ``` Args: name: (str) The name of the outer variable, and the rule. type: The type of the variable, constructed using `types` factory in [//third_party/bazel_rules/rules_cc/cc/toolchains/impl:variables.bzl](https://github.com/bazelbuild/rules_cc/tree/main/cc/toolchains/impl/variables.bzl). **kwargs: [common attributes](https://bazel.build/reference/be/common-definitions#common-attributes) that should be applied to this rule. """ _cc_variable(name = name, type = json.encode(type), **kwargs) def _cc_builtin_variables_impl(ctx): return [BuiltinVariablesInfo(variables = { variable.name: variable for variable in collect_provider(ctx.attr.srcs, VariableInfo) })] cc_builtin_variables = rule( implementation = _cc_builtin_variables_impl, attrs = { "srcs": attr.label_list(providers = [VariableInfo]), }, ) def get_type(*, name, variables, overrides, actions, args_label, nested_label, fail): """Gets the type of a variable. Args: name: (str) The variable to look up. variables: (dict[str, VariableInfo]) Mapping from variable name to metadata. Top-level variables only overrides: (dict[str, type]) Mapping from variable names to type. Can be used for nested variables. actions: (depset[ActionTypeInfo]) The set of actions for which the variable is requested. args_label: (Label) The label for the args that included the rule that references this variable. Only used for error messages. nested_label: (Label) The label for the rule that references this variable. Only used for error messages. fail: A function to be called upon failure. Use for testing only. Returns: The type of the variable "name". """ outer = name.split(".")[0] if outer not in variables: # With a fail function, we actually need to return since the fail # function doesn't propagate. fail("The variable %s does not exist. Did you mean one of the following?\n%s" % (outer, "\n".join(sorted(variables)))) # buildifier: disable=unreachable return types.void if variables[outer].actions != None: valid_actions = variables[outer].actions.to_list() for action in actions: if action not in valid_actions: fail("The variable {var} is inaccessible from the action {action}. This is required because it is referenced in {nested_label}, which is included by {args_label}, which references that action".format( var = variables[outer].label, nested_label = nested_label, args_label = args_label, action = action.label, )) # buildifier: disable=unreachable return types.void type = overrides.get(outer, variables[outer].type) parent = outer for part in name.split(".")[1:]: full = parent + "." + part if type["name"] != "struct": extra_error = "" if type["name"] == "list" and type["elements"]["name"] == "struct": extra_error = " Maybe you meant to use iterate_over." fail("Attempted to access %r, but %r was not a struct - it had type %s.%s" % (full, parent, type["repr"], extra_error)) # buildifier: disable=unreachable return types.void if part not in type["kv"] and full not in overrides: attrs = [] for attr, value in sorted(type["kv"].items()): attrs.append("%s: %s" % (attr, value["repr"])) fail("Unable to find %r in %r, which had the following attributes:\n%s" % (part, parent, "\n".join(attrs))) # buildifier: disable=unreachable return types.void type = overrides.get(full, type["kv"][part]) parent = full return type rules_cc-0.0.11/cc/toolchains/memprof_profile.bzl000066400000000000000000000012401470072561500220220ustar00rootroot00000000000000# Copyright 2024 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. """memprof_profile rule""" memprof_profile = native.memprof_profile rules_cc-0.0.11/cc/toolchains/mutually_exclusive_category.bzl000066400000000000000000000037561470072561500245130ustar00rootroot00000000000000# Copyright 2024 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. """Rule for mutually exclusive categories in the rule based toolchain.""" load(":cc_toolchain_info.bzl", "MutuallyExclusiveCategoryInfo") def _cc_mutually_exclusive_category_impl(ctx): return [MutuallyExclusiveCategoryInfo( label = ctx.label, name = str(ctx.label), )] cc_mutually_exclusive_category = rule( implementation = _cc_mutually_exclusive_category_impl, doc = """A rule used to categorize `cc_feature` definitions for which only one can be enabled. This is used by [`cc_feature.mutually_exclusive`](#cc_feature-mutually_exclusive) to express groups of `cc_feature` definitions that are inherently incompatible with each other and must be treated as mutually exclusive. Warning: These groups are keyed by name, so two `cc_mutually_exclusive_category` definitions of the same name in different packages will resolve to the same logical group. Example: ``` load("//cc/toolchains:feature.bzl", "cc_feature") load("//cc/toolchains:mutually_exclusive_category.bzl", "cc_mutually_exclusive_category") cc_mutually_exclusive_category( name = "opt_level", ) cc_feature( name = "speed_optimized", mutually_exclusive = [":opt_level"], ) cc_feature( name = "size_optimized", mutually_exclusive = [":opt_level"], ) cc_feature( name = "unoptimized", mutually_exclusive = [":opt_level"], ) ``` """, attrs = {}, provides = [MutuallyExclusiveCategoryInfo], ) rules_cc-0.0.11/cc/toolchains/nested_args.bzl000066400000000000000000000132761470072561500211470ustar00rootroot00000000000000# Copyright 2024 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. """All providers for rule-based bazel toolchain config.""" load( "//cc/toolchains/impl:nested_args.bzl", "NESTED_ARGS_ATTRS", "nested_args_provider_from_ctx", ) load( ":cc_toolchain_info.bzl", "NestedArgsInfo", ) visibility("public") _cc_nested_args = rule( implementation = lambda ctx: [nested_args_provider_from_ctx(ctx)], attrs = NESTED_ARGS_ATTRS, provides = [NestedArgsInfo], doc = """Declares a list of arguments bound to a set of actions. Roughly equivalent to ctx.actions.args() Examples: cc_nested_args( name = "warnings_as_errors", args = ["-Werror"], ) """, ) def cc_nested_args( *, name, args = None, data = None, format = {}, iterate_over = None, nested = None, requires_not_none = None, requires_none = None, requires_true = None, requires_false = None, requires_equal = None, requires_equal_value = None, **kwargs): """Nested arguments for use in more complex `cc_args` expansions. While this rule is very similar in shape to `cc_args`, it is intended to be used as a dependency of `cc_args` to provide additional arguments that should be applied to the same actions as defined by the parent `cc_args` rule. The key motivation for this rule is to allow for more complex variable-based argument expensions. Prefer expressing collections of arguments as `cc_args` and `cc_args_list` rules when possible. For living examples of how this rule is used, see the usages here: https://github.com/bazelbuild/rules_cc/tree/main/cc/toolchains/args/runtime_library_search_directories/BUILD https://github.com/bazelbuild/rules_cc/tree/main/cc/toolchains/args/libraries_to_link/BUILD Note: These examples are non-trivial, but they illustrate when it is absolutely necessary to use this rule. Args: name: (str) The name of the target. args: (List[str]) The command-line arguments that are applied by using this rule. This is mutually exclusive with [nested](#cc_nested_args-nested). data: (List[Label]) A list of runtime data dependencies that are required for these arguments to work as intended. format: (Dict[str, Label]) A mapping of format strings to the label of the corresponding `cc_variable` that the value should be pulled from. All instances of `{variable_name}` will be replaced with the expanded value of `variable_name` in this dictionary. The complete list of possible variables can be found in https://github.com/bazelbuild/rules_cc/tree/main/cc/toolchains/variables/BUILD. It is not possible to declare custom variables--these are inherent to Bazel itself. iterate_over: (Label) The label of a `cc_variable` that should be iterated over. This is intended for use with built-in variables that are lists. nested: (List[Label]) A list of `cc_nested_args` rules that should be expanded to command-line arguments when this rule is used. This is mutually exclusive with [args](#cc_nested_args-args). requires_not_none: (Label) The label of a `cc_variable` that should be checked for existence before expanding this rule. If the variable is None, this rule will be ignored. requires_none: (Label) The label of a `cc_variable` that should be checked for non-existence before expanding this rule. If the variable is not None, this rule will be ignored. requires_true: (Label) The label of a `cc_variable` that should be checked for truthiness before expanding this rule. If the variable is false, this rule will be ignored. requires_false: (Label) The label of a `cc_variable` that should be checked for falsiness before expanding this rule. If the variable is true, this rule will be ignored. requires_equal: (Label) The label of a `cc_variable` that should be checked for equality before expanding this rule. If the variable is not equal to (requires_equal_value)[#cc_nested_args-requires_equal_value], this rule will be ignored. requires_equal_value: (str) The value to compare (requires_equal)[#cc_nested_args-requires_equal] against. **kwargs: [common attributes](https://bazel.build/reference/be/common-definitions#common-attributes) that should be applied to this rule. """ return _cc_nested_args( name = name, args = args, data = data, # We flip the key/value pairs in the dictionary here because Bazel doesn't have a # string-keyed label dict attribute type. format = {k: v for v, k in format.items()}, iterate_over = iterate_over, nested = nested, requires_not_none = requires_not_none, requires_none = requires_none, requires_true = requires_true, requires_false = requires_false, requires_equal = requires_equal, requires_equal_value = requires_equal_value, **kwargs ) rules_cc-0.0.11/cc/toolchains/propeller_optimize.bzl000066400000000000000000000012511470072561500225630ustar00rootroot00000000000000# Copyright 2024 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. """propeller_optimize rule""" propeller_optimize = native.propeller_optimize rules_cc-0.0.11/cc/toolchains/tool.bzl000066400000000000000000000117751470072561500176300ustar00rootroot00000000000000# 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. """Implementation of cc_tool""" load("@bazel_skylib//rules/directory:providers.bzl", "DirectoryInfo") load("//cc/toolchains/impl:collect.bzl", "collect_data", "collect_provider") load( ":cc_toolchain_info.bzl", "ToolCapabilityInfo", "ToolInfo", ) def _cc_tool_impl(ctx): exe_info = ctx.attr.src[DefaultInfo] if exe_info.files_to_run != None and exe_info.files_to_run.executable != None: exe = exe_info.files_to_run.executable elif len(exe_info.files.to_list()) == 1: exe = exe_info.files.to_list()[0] else: fail("Expected cc_tool's src attribute to be either an executable or a single file") runfiles = collect_data(ctx, ctx.attr.data + [ctx.attr.src] + ctx.attr.allowlist_include_directories) tool = ToolInfo( label = ctx.label, exe = exe, runfiles = runfiles, execution_requirements = tuple(ctx.attr.tags), allowlist_include_directories = depset( direct = [d[DirectoryInfo] for d in ctx.attr.allowlist_include_directories], ), capabilities = tuple(collect_provider(ctx.attr.capabilities, ToolCapabilityInfo)), ) link = ctx.actions.declare_file(ctx.label.name) ctx.actions.symlink( output = link, target_file = exe, is_executable = True, ) return [ tool, # This isn't required, but now we can do "bazel run ", which can # be very helpful when debugging toolchains. DefaultInfo( files = depset([link]), runfiles = runfiles, executable = link, ), ] cc_tool = rule( implementation = _cc_tool_impl, # @unsorted-dict-items attrs = { "src": attr.label( allow_files = True, cfg = "exec", doc = """The underlying binary that this tool represents. Usually just a single prebuilt (eg. @toolchain//:bin/clang), but may be any executable label. """, ), "data": attr.label_list( allow_files = True, doc = """Additional files that are required for this tool to run. Frequently, clang and gcc require additional files to execute as they often shell out to other binaries (e.g. `cc1`). """, ), "allowlist_include_directories": attr.label_list( providers = [DirectoryInfo], doc = """Include paths implied by using this tool. Compilers may include a set of built-in headers that are implicitly available unless flags like `-nostdinc` are provided. Bazel checks that all included headers are properly provided by a dependency or allowlisted through this mechanism. As a rule of thumb, only use this if Bazel is complaining about absolute paths in your toolchain and you've ensured that the toolchain is compiling with the `-no-canonical-prefixes` and/or `-fno-canonical-system-headers` arguments. This can help work around errors like: `the source file 'main.c' includes the following non-builtin files with absolute paths (if these are builtin files, make sure these paths are in your toolchain)`. """, ), "capabilities": attr.label_list( providers = [ToolCapabilityInfo], doc = """Declares that a tool is capable of doing something. For example, `//third_party/bazel_rules/rules_cc/cc/toolchains/capabilities:supports_pic`. """, ), }, provides = [ToolInfo], doc = """Declares a tool for use by toolchain actions. `cc_tool` rules are used in a `cc_tool_map` rule to ensure all files and metadata required to run a tool are available when constructing a `cc_toolchain`. In general, include all files that are always required to run a tool (e.g. libexec/** and cross-referenced tools in bin/*) in the [data](#cc_tool-data) attribute. If some files are only required when certain flags are passed to the tool, consider using a `cc_args` rule to bind the files to the flags that require them. This reduces the overhead required to properly enumerate a sandbox with all the files required to run a tool, and ensures that there isn't unintentional leakage across configurations and actions. Example: ``` load("//cc/toolchains:tool.bzl", "cc_tool") cc_tool( name = "clang_tool", executable = "@llvm_toolchain//:bin/clang", # Suppose clang needs libc to run. data = ["@llvm_toolchain//:lib/x86_64-linux-gnu/libc.so.6"] tags = ["requires-network"], capabilities = ["//cc/toolchains/capabilities:supports_pic"], ) ``` """, executable = True, ) rules_cc-0.0.11/cc/toolchains/tool_capability.bzl000066400000000000000000000051261470072561500220220ustar00rootroot00000000000000# Copyright 2024 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. """Implementation of the cc_tool_capability rule.""" load( ":cc_toolchain_info.bzl", "ArgsListInfo", "FeatureConstraintInfo", "FeatureInfo", "ToolCapabilityInfo", ) def _cc_tool_capability_impl(ctx): ft = FeatureInfo( name = ctx.attr.feature_name or ctx.label.name, label = ctx.label, enabled = False, args = ArgsListInfo( label = ctx.label, args = (), files = depset(), by_action = (), allowlist_include_directories = depset(), ), implies = depset(), requires_any_of = (), mutually_exclusive = (), # Mark it as external so that it doesn't complain if we say # "requires" on a constraint that was never referenced elsewhere # in the toolchain. external = True, overridable = True, overrides = None, allowlist_include_directories = depset(), ) return [ ToolCapabilityInfo(label = ctx.label, feature = ft), # Only give it a feature constraint info and not a feature info. # This way you can't imply it - you can only require it. FeatureConstraintInfo(label = ctx.label, all_of = depset([ft])), ] cc_tool_capability = rule( implementation = _cc_tool_capability_impl, provides = [ToolCapabilityInfo, FeatureConstraintInfo], doc = """A capability is an optional feature that a tool supports. For example, not all compilers support PIC, so to handle this, we write: ``` cc_tool( name = "clang", src = "@host_tools/bin/clang", capabilities = [ "//cc/toolchains/capabilities:supports_pic", ], ) cc_args( name = "pic", requires = [ "//cc/toolchains/capabilities:supports_pic" ], args = ["-fPIC"], ) ``` This ensures that `-fPIC` is added to the command-line only when we are using a tool that supports PIC. """, attrs = { "feature_name": attr.string(doc = "The name of the feature to generate for this capability"), }, ) rules_cc-0.0.11/cc/toolchains/tool_map.bzl000066400000000000000000000107241470072561500204560ustar00rootroot00000000000000# Copyright 2024 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. """Implementation of cc_tool_map.""" load( "//cc/toolchains/impl:collect.bzl", "collect_provider", "collect_tools", ) load( ":cc_toolchain_info.bzl", "ActionTypeSetInfo", "ToolConfigInfo", ) def _cc_tool_map_impl(ctx): tools = collect_tools(ctx, ctx.attr.tools) action_sets = collect_provider(ctx.attr.actions, ActionTypeSetInfo) action_to_tool = {} action_to_as = {} for i in range(len(action_sets)): action_set = action_sets[i] tool = tools[i] for action in action_set.actions.to_list(): if action in action_to_as: fail("The action %s appears multiple times in your tool_map (as %s and %s)" % (action.label, action_set.label, action_to_as[action].label)) action_to_as[action] = action_set action_to_tool[action] = tool return [ToolConfigInfo(label = ctx.label, configs = action_to_tool)] _cc_tool_map = rule( implementation = _cc_tool_map_impl, # @unsorted-dict-items attrs = { "actions": attr.label_list( providers = [ActionTypeSetInfo], mandatory = True, doc = """A list of action names to apply this action to. See //cc/toolchains/actions:BUILD for valid options. """, ), "tools": attr.label_list( mandatory = True, cfg = "exec", allow_files = True, doc = """The tool to use for the specified actions. The tool may be a `cc_tool` or other executable rule. """, ), }, provides = [ToolConfigInfo], ) def cc_tool_map(name, tools, **kwargs): """A toolchain configuration rule that maps toolchain actions to tools. A `cc_tool_map` aggregates all the tools that may be used for a given toolchain and maps them to their corresponding actions. Conceptually, this is similar to the `CXX=/path/to/clang++` environment variables that most build systems use to determine which tools to use for a given action. To simplify usage, some actions have been grouped together (for example, [//third_party/bazel_rules/rules_cc/cc/toolchains/actions:cpp_compile_actions](https://github.com/bazelbuild/rules_cc/tree/main/cc/toolchains/actions/BUILD)) to logically express "all the C++ compile actions". In Bazel, there is a little more granularity to the mapping, so the mapping doesn't follow the traditional `CXX`, `AR`, etc. naming scheme. For a comprehensive list of all the well-known actions, see //cc/toolchains/actions:BUILD. Example usage: ``` load("//cc/toolchains:tool_map.bzl", "cc_tool_map") cc_tool_map( name = "all_tools", tools = { "//cc/toolchains/actions:assembly_actions": ":asm", "//cc/toolchains/actions:c_compile": ":clang", "//cc/toolchains/actions:cpp_compile_actions": ":clang++", "//cc/toolchains/actions:link_actions": ":lld", "//cc/toolchains/actions:objcopy_embed_data": ":llvm-objcopy", "//cc/toolchains/actions:strip": ":llvm-strip", "//cc/toolchains/actions:ar_actions": ":llvm-ar", }, ) ``` Note: Due to an implementation limitation, if you need to map the same tool to multiple actions, you will need to create an intermediate alias for the tool for each set of actions. See https://github.com/bazelbuild/rules_cc/issues/235 for more details. Args: name: (str) The name of the target. tools: (Dict[Label, Label]) A mapping between `cc_action_type`/`cc_action_type_set` targets and the `cc_tool` or executable target that implements that action. **kwargs: [common attributes](https://bazel.build/reference/be/common-definitions#common-attributes) that should be applied to this rule. """ _cc_tool_map( name = name, actions = tools.keys(), tools = tools.values(), **kwargs ) rules_cc-0.0.11/cc/toolchains/toolchain.bzl000066400000000000000000000126541470072561500206300ustar00rootroot00000000000000# Copyright 2024 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. """Implementation of the cc_toolchain rule.""" load("//cc:defs.bzl", _cc_toolchain = "cc_toolchain") load( "//cc/toolchains/impl:toolchain_config.bzl", "cc_legacy_file_group", "cc_toolchain_config", ) visibility("public") # Taken from https://bazel.build/docs/cc-toolchain-config-reference#actions # TODO: This is best-effort. Update this with the correct file groups once we # work out what actions correspond to what file groups. _LEGACY_FILE_GROUPS = { "ar_files": [ Label("//cc/toolchains/actions:ar_actions"), ], "as_files": [ Label("//cc/toolchains/actions:assembly_actions"), ], "compiler_files": [ Label("//cc/toolchains/actions:cc_flags_make_variable"), Label("//cc/toolchains/actions:c_compile"), Label("//cc/toolchains/actions:cpp_compile"), Label("//cc/toolchains/actions:cpp_header_parsing"), ], # There are no actions listed for coverage, dwp, and objcopy in action_names.bzl. "coverage_files": [], "dwp_files": [], "linker_files": [ Label("//cc/toolchains/actions:cpp_link_dynamic_library"), Label("//cc/toolchains/actions:cpp_link_nodeps_dynamic_library"), Label("//cc/toolchains/actions:cpp_link_executable"), ], "objcopy_files": [], "strip_files": [ Label("//cc/toolchains/actions:strip"), ], } def cc_toolchain( name, dynamic_runtime_lib = None, libc_top = None, module_map = None, output_licenses = [], static_runtime_lib = None, supports_header_parsing = False, supports_param_files = True, target_compatible_with = None, exec_compatible_with = None, compatible_with = None, tags = [], visibility = None, **kwargs): """A macro that invokes native.cc_toolchain under the hood. Generated rules: {name}: A `cc_toolchain` for this toolchain. _{name}_config: A `cc_toolchain_config` for this toolchain. _{name}_*_files: Generated rules that group together files for "ar_files", "as_files", "compiler_files", "coverage_files", "dwp_files", "linker_files", "objcopy_files", and "strip_files" normally enumerated as part of the `cc_toolchain` rule. Args: name: str: The name of the label for the toolchain. dynamic_runtime_lib: See cc_toolchain.dynamic_runtime_lib libc_top: See cc_toolchain.libc_top module_map: See cc_toolchain.module_map output_licenses: See cc_toolchain.output_licenses static_runtime_lib: See cc_toolchain.static_runtime_lib supports_header_parsing: See cc_toolchain.supports_header_parsing supports_param_files: See cc_toolchain.supports_param_files target_compatible_with: target_compatible_with to apply to all generated rules exec_compatible_with: exec_compatible_with to apply to all generated rules compatible_with: compatible_with to apply to all generated rules tags: Tags to apply to all generated rules visibility: Visibility of toolchain rule **kwargs: Args to be passed through to cc_toolchain_config. """ all_kwargs = { "compatible_with": compatible_with, "exec_compatible_with": exec_compatible_with, "tags": tags, "target_compatible_with": target_compatible_with, } for group in _LEGACY_FILE_GROUPS: if group in kwargs: fail("Don't use legacy file groups such as %s. Instead, associate files with tools, actions, and args." % group) config_name = "_{}_config".format(name) cc_toolchain_config( name = config_name, visibility = ["//visibility:private"], **(all_kwargs | kwargs) ) # Provides ar_files, compiler_files, linker_files, ... legacy_file_groups = {} for group, actions in _LEGACY_FILE_GROUPS.items(): group_name = "_{}_{}".format(name, group) cc_legacy_file_group( name = group_name, config = config_name, actions = actions, visibility = ["//visibility:private"], **all_kwargs ) legacy_file_groups[group] = group_name if visibility != None: all_kwargs["visibility"] = visibility _cc_toolchain( name = name, toolchain_config = config_name, all_files = config_name, dynamic_runtime_lib = dynamic_runtime_lib, libc_top = libc_top, module_map = module_map, output_licenses = output_licenses, static_runtime_lib = static_runtime_lib, supports_header_parsing = supports_header_parsing, supports_param_files = supports_param_files, # This is required for Bazel versions <= 7.x.x. It is ignored in later versions. exec_transition_for_inputs = False, **(all_kwargs | legacy_file_groups) ) rules_cc-0.0.11/cc/toolchains/toolchain_config_utils.bzl000066400000000000000000000023041470072561500233640ustar00rootroot00000000000000# Copyright 2024 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. """Exposing some helper functions for configure cc toolchains.""" load("//cc/private/toolchain:cc_configure.bzl", _MSVC_ENVVARS = "MSVC_ENVVARS") load("//cc/private/toolchain:lib_cc_configure.bzl", _escape_string = "escape_string") load("//cc/private/toolchain:windows_cc_configure.bzl", _find_vc_path = "find_vc_path", _setup_vc_env_vars = "setup_vc_env_vars") MSVC_ENVVARS = _MSVC_ENVVARS def find_vc_path(repository_ctx): return _find_vc_path(repository_ctx) def setup_vc_env_vars(repository_ctx): return _setup_vc_env_vars(repository_ctx) def escape_string(string): return _escape_string(string) rules_cc-0.0.11/cc/toolchains/variables/000077500000000000000000000000001470072561500200775ustar00rootroot00000000000000rules_cc-0.0.11/cc/toolchains/variables/BUILD000066400000000000000000000330111470072561500206570ustar00rootroot00000000000000load("//cc/toolchains/impl:variables.bzl", "cc_builtin_variables", "cc_variable", "types") package(default_visibility = ["//visibility:public"]) cc_variable( name = "cs_fdo_instrument_path", actions = [ "//cc/toolchains/actions:link_actions", "//cc/toolchains/actions:compile_actions", ], type = types.directory, ) cc_variable( name = "def_file_path", actions = ["//cc/toolchains/actions:link_actions"], type = types.option(types.file), ) cc_variable( name = "dependency_file", actions = ["//cc/toolchains/actions:compile_actions"], type = types.file, ) cc_variable( name = "dependent_module_map_files", actions = ["//cc/toolchains/actions:compile_actions"], type = types.option(types.list(types.file)), ) cc_variable( name = "external_include_paths", actions = ["//cc/toolchains/actions:compile_actions"], type = types.option(types.list(types.directory)), ) cc_variable( name = "fdo_instrument_path", actions = [ "//cc/toolchains/actions:link_actions", "//cc/toolchains/actions:compile_actions", ], type = types.directory, ) cc_variable( name = "fdo_prefetch_hints_path", actions = ["//cc/toolchains/actions:compile_actions"], type = types.file, ) cc_variable( name = "fdo_profile_path", actions = ["//cc/toolchains/actions:compile_actions"], type = types.file, ) cc_variable( name = "force_pic", actions = ["//cc/toolchains/actions:link_actions"], # Provided when --force-pic is passed type = types.option(types.void), ) cc_variable( name = "framework_include_paths", actions = ["//cc/toolchains/actions:compile_actions"], type = types.list(types.directory), ) cc_variable( name = "gcov_gcno_file", actions = ["//cc/toolchains/actions:compile_actions"], type = types.file, ) cc_variable( name = "generate_interface_library", actions = ["//cc/toolchains/actions:link_actions"], # "yes" or "no" type = types.option(types.string), ) cc_variable( name = "include", actions = ["//cc/toolchains/actions:compile_actions"], type = types.list(types.file), ) cc_variable( name = "include_paths", actions = ["//cc/toolchains/actions:compile_actions"], type = types.list(types.directory), ) cc_variable( name = "includes", actions = ["//cc/toolchains/actions:compile_actions"], type = types.option(types.list(types.file)), ) cc_variable( name = "input_file", actions = ["//cc/toolchains/actions:strip"], type = types.file, ) cc_variable( name = "interface_library_builder_path", actions = ["//cc/toolchains/actions:link_actions"], # Should be a file, but contains the string "ignored" when there's no value. type = types.option(types.string), ) cc_variable( name = "interface_library_input_path", actions = ["//cc/toolchains/actions:link_actions"], # Should be a file, but contains the string "ignored" when there's no value. type = types.option(types.string), ) cc_variable( name = "interface_library_output_path", actions = ["//cc/toolchains/actions:link_actions"], # Should be a file, but contains the string "ignored" when there's no value. type = types.option(types.string), ) cc_variable( name = "is_cc_test", actions = ["//cc/toolchains/actions:link_actions"], type = types.option(types.bool), ) cc_variable( name = "is_using_fission", actions = [ "//cc/toolchains/actions:link_actions", "//cc/toolchains/actions:compile_actions", ], type = types.option(types.void), ) cc_variable( name = "legacy_compile_flags", actions = ["//cc/toolchains/actions:compile_actions"], type = types.list(types.string), ) cc_variable( name = "legacy_link_flags", actions = ["//cc/toolchains/actions:link_actions"], type = types.list(types.string), ) cc_variable( name = "libraries_to_link", actions = [ "//cc/toolchains/actions:cpp_link_static_library", "//cc/toolchains/actions:link_actions", ], type = types.option(types.list(types.struct( name = types.string, is_whole_archive = types.bool, object_files = types.list(types.file), path = types.string, shared_libraries = types.list(types.struct( name = types.string, is_whole_archive = types.bool, object_files = types.list(types.file), path = types.file, type = types.string, )), type = types.string, ))), ) cc_variable( name = "libraries_to_link.type", actions = [ "//cc/toolchains/actions:cpp_link_static_library", "//cc/toolchains/actions:link_actions", ], # See :libraries_to_link. type = types.string, ) cc_variable( name = "libraries_to_link.name", actions = [ "//cc/toolchains/actions:cpp_link_static_library", "//cc/toolchains/actions:link_actions", ], # See :libraries_to_link. type = types.string, ) cc_variable( name = "libraries_to_link.path", actions = [ "//cc/toolchains/actions:cpp_link_static_library", "//cc/toolchains/actions:link_actions", ], # See :libraries_to_link. type = types.string, ) cc_variable( name = "libraries_to_link.object_files", actions = [ "//cc/toolchains/actions:cpp_link_static_library", "//cc/toolchains/actions:link_actions", ], # See :libraries_to_link. type = types.list(types.file), ) cc_variable( name = "libraries_to_link.is_whole_archive", actions = ["//cc/toolchains/actions:link_actions"], type = types.bool, ) cc_variable( name = "libraries_to_link.shared_libraries", actions = ["//cc/toolchains/actions:link_actions"], # See :libraries_to_link. type = types.unknown, ) cc_variable( name = "libraries_to_link.shared_libraries.is_whole_archive", actions = ["//cc/toolchains/actions:link_actions"], type = types.string, ) cc_variable( name = "libraries_to_link.shared_libraries.name", actions = ["//cc/toolchains/actions:link_actions"], type = types.string, ) cc_variable( name = "libraries_to_link.shared_libraries.object_files", actions = ["//cc/toolchains/actions:link_actions"], type = types.list(types.file), ) cc_variable( name = "libraries_to_link.shared_libraries.path", actions = ["//cc/toolchains/actions:link_actions"], type = types.file, ) cc_variable( name = "libraries_to_link.shared_libraries.type", actions = ["//cc/toolchains/actions:link_actions"], type = types.string, ) cc_variable( name = "library_search_directories", actions = ["//cc/toolchains/actions:link_actions"], type = types.list(types.directory), ) cc_variable( name = "linker_param_file", actions = [ "//cc/toolchains/actions:cpp_link_static_library", "//cc/toolchains/actions:link_actions", ], type = types.option(types.file), ) cc_variable( name = "linkstamp_paths", actions = ["//cc/toolchains/actions:link_actions"], type = types.list(types.directory), ) cc_variable( name = "lto_indexing_bitcode_file", actions = ["//cc/toolchains/actions:compile_actions"], type = types.option(types.file), ) cc_variable( name = "module_files", actions = ["//cc/toolchains/actions:compile_actions"], type = types.option(types.list(types.file)), ) cc_variable( name = "module_map_file", actions = ["//cc/toolchains/actions:compile_actions"], type = types.option(types.file), ) cc_variable( name = "module_name", actions = ["//cc/toolchains/actions:compile_actions"], type = types.option(types.string), ) cc_variable( name = "output_assembly_file", actions = ["//cc/toolchains/actions:compile_actions"], type = types.file, ) cc_variable( name = "output_execpath", actions = [ "//cc/toolchains/actions:cpp_link_static_library", "//cc/toolchains/actions:link_actions", ], type = types.option(types.directory), ) cc_variable( name = "output_file", actions = [ "//cc/toolchains/actions:compile_actions", "//cc/toolchains/actions:strip", ], type = types.file, ) cc_variable( name = "output_preprocess_file", actions = ["//cc/toolchains/actions:compile_actions"], type = types.file, ) cc_variable( name = "per_object_debug_info_file", actions = ["//cc/toolchains/actions:compile_actions"], type = types.file, ) cc_variable( name = "pic", actions = ["//cc/toolchains/actions:compile_actions"], type = types.option(types.void), ) cc_variable( name = "preprocessor_defines", actions = ["//cc/toolchains/actions:compile_actions"], type = types.list(types.string), ) cc_variable( name = "propellor_optimize_ld_path", actions = ["//cc/toolchains/actions:link_actions"], type = types.option(types.file), ) cc_variable( name = "quote_include_paths", actions = ["//cc/toolchains/actions:compile_actions"], type = types.list(types.directory), ) cc_variable( name = "runtime_library_search_directories", actions = ["//cc/toolchains/actions:link_actions"], type = types.option(types.list(types.directory)), ) cc_variable( name = "runtime_solib_name", actions = ["//cc/toolchains/actions:link_actions"], type = types.option(types.string), ) cc_variable( name = "serialized_diagnostics_file", actions = ["//cc/toolchains/actions:compile_actions"], type = types.option(types.file), ) cc_variable( name = "source_file", actions = ["//cc/toolchains/actions:compile_actions"], type = types.file, ) cc_variable( name = "strip_debug_symbols", actions = ["//cc/toolchains/actions:link_actions"], type = types.option(types.void), ) cc_variable( name = "stripopts", actions = ["//cc/toolchains/actions:strip"], type = types.list(types.string), ) # Instead of the "sysroot" variable, use the cc_sysroot macro in # //cc/toolchains/args:sysroot.bzl cc_variable( name = "system_include_paths", actions = ["//cc/toolchains/actions:compile_actions"], type = types.list(types.directory), ) cc_variable( name = "thinlto_index", actions = ["//cc/toolchains/actions:compile_actions"], type = types.option(types.string), ) cc_variable( name = "thinlto_indexing_param_file", actions = ["//cc/toolchains/actions:link_actions"], type = types.option(types.string), ) cc_variable( name = "thinlto_input_bitcode_file", actions = ["//cc/toolchains/actions:compile_actions"], type = types.option(types.file), ) cc_variable( name = "thinlto_merged_object_file", actions = ["//cc/toolchains/actions:link_actions"], type = types.option(types.file), ) cc_variable( name = "thinlto_object_suffix_replace", actions = ["//cc/toolchains/actions:link_actions"], type = types.option(types.string), ) cc_variable( name = "thinlto_output_object_file", actions = ["//cc/toolchains/actions:compile_actions"], type = types.option(types.file), ) cc_variable( name = "thinlto_param_file", actions = ["//cc/toolchains/actions:link_actions"], type = types.option(types.file), ) cc_variable( name = "thinlto_prefix_replace", actions = ["//cc/toolchains/actions:link_actions"], type = types.option(types.string), ) cc_variable( name = "unfiltered_compile_flags", actions = ["//cc/toolchains/actions:compile_actions"], type = types.list(types.string), ) cc_variable( name = "user_compile_flags", actions = ["//cc/toolchains/actions:compile_actions"], type = types.list(types.string), ) cc_variable( name = "user_link_flags", actions = ["//cc/toolchains/actions:link_actions"], type = types.list(types.string), ) cc_builtin_variables( name = "variables", srcs = [ ":cs_fdo_instrument_path", ":def_file_path", ":dependency_file", ":dependent_module_map_files", ":external_include_paths", ":fdo_instrument_path", ":fdo_prefetch_hints_path", ":fdo_profile_path", ":force_pic", ":framework_include_paths", ":gcov_gcno_file", ":generate_interface_library", ":include", ":include_paths", ":includes", ":input_file", ":interface_library_builder_path", ":interface_library_input_path", ":interface_library_output_path", ":is_cc_test", ":is_using_fission", ":legacy_compile_flags", ":legacy_link_flags", ":libraries_to_link", ":library_search_directories", ":linker_param_file", ":linkstamp_paths", ":lto_indexing_bitcode_file", ":module_files", ":module_map_file", ":module_name", ":output_assembly_file", ":output_execpath", ":output_file", ":output_preprocess_file", ":per_object_debug_info_file", ":pic", ":preprocessor_defines", ":propellor_optimize_ld_path", ":quote_include_paths", ":runtime_library_search_directories", ":runtime_solib_name", ":serialized_diagnostics_file", ":source_file", ":strip_debug_symbols", ":stripopts", ":system_include_paths", ":thinlto_index", ":thinlto_indexing_param_file", ":thinlto_input_bitcode_file", ":thinlto_merged_object_file", ":thinlto_object_suffix_replace", ":thinlto_output_object_file", ":thinlto_param_file", ":thinlto_prefix_replace", ":unfiltered_compile_flags", ":user_compile_flags", ":user_link_flags", ], visibility = ["//visibility:public"], ) rules_cc-0.0.11/docs/000077500000000000000000000000001470072561500143275ustar00rootroot00000000000000rules_cc-0.0.11/docs/BUILD000066400000000000000000000040111470072561500151050ustar00rootroot00000000000000# Copyright 2024 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. load("@bazel_skylib//rules:diff_test.bzl", "diff_test") load("@bazel_skylib//rules:expand_template.bzl", "expand_template") load("@stardoc//stardoc:stardoc.bzl", "stardoc") load("//cc/toolchains/impl:documented_api.bzl", "DOCUMENTED_TOOLCHAIN_RULES") load("//cc/toolchains/impl:markdown_helpers.bzl", "xref_substitutions") filegroup( name = "srcs", srcs = glob([ "**/*.bzl", "**/BUILD", ]), visibility = ["//visibility:public"], ) stardoc( name = "toolchain_api", out = "raw_generated_toolchain_api.md", input = "//cc/toolchains/impl:documented_api.bzl", deps = ["//cc/toolchains:toolchain_rules"], ) expand_template( name = "toolchain_api_md", out = "generated_toolchain_api.md", # Dictionary order 100% matters here! # buildifier: disable=unsorted-dict-items substitutions = { # Strip @rules_cc to prevent instances of @rules_cc@rules_cc//cc. "@rules_cc//cc": "//cc", # In GitHub, we prefer to clarify all the labels that come from # rules_cc. "//cc": "@rules_cc//cc", } | xref_substitutions({ "`{}`".format(rule_name): "#{}".format(rule_name) for rule_name in DOCUMENTED_TOOLCHAIN_RULES }), # buildifier: enable=unsorted-dict-items template = ":raw_generated_toolchain_api.md", ) diff_test( name = "toolchain_api_diff_test", file1 = ":generated_toolchain_api.md", file2 = ":toolchain_api.md", ) rules_cc-0.0.11/docs/toolchain_api.md000066400000000000000000001164601470072561500174720ustar00rootroot00000000000000 This is a list of rules/macros that should be exported as documentation. ## cc_action_type
cc_action_type(name, action_name)
A type of action (eg. c_compile, assemble, strip). [`cc_action_type`](#cc_action_type) rules are used to associate arguments and tools together to perform a specific action. Bazel prescribes a set of known action types that are used to drive typical C/C++/ObjC actions like compiling, linking, and archiving. The set of well-known action types can be found in [@rules_cc//cc/toolchains/actions:BUILD](https://github.com/bazelbuild/rules_cc/tree/main/cc/toolchains/actions/BUILD). It's possible to create project-specific action types for use in toolchains. Be careful when doing this, because every toolchain that encounters the action will need to be configured to support the custom action type. If your project is a library, avoid creating new action types as it will reduce compatibility with existing toolchains and increase setup complexity for users. Example: ``` load("@rules_cc//cc:action_names.bzl", "ACTION_NAMES") load("@rules_cc//cc/toolchains:actions.bzl", "cc_action_type") cc_action_type( name = "cpp_compile", action_name = = ACTION_NAMES.cpp_compile, ) ``` **ATTRIBUTES** | Name | Description | Type | Mandatory | Default | | :------------- | :------------- | :------------- | :------------- | :------------- | | name | A unique name for this target. | Name | required | | | action_name | - | String | required | | ## cc_action_type_set
cc_action_type_set(name, actions, allow_empty)
Represents a set of actions. This is a convenience rule to allow for more compact representation of a group of action types. Use this anywhere a [`cc_action_type`](#cc_action_type) is accepted. Example: ``` load("@rules_cc//cc/toolchains:actions.bzl", "cc_action_type_set") cc_action_type_set( name = "link_executable_actions", actions = [ "@rules_cc//cc/toolchains/actions:cpp_link_executable", "@rules_cc//cc/toolchains/actions:lto_index_for_executable", ], ) ``` **ATTRIBUTES** | Name | Description | Type | Mandatory | Default | | :------------- | :------------- | :------------- | :------------- | :------------- | | name | A unique name for this target. | Name | required | | | actions | A list of cc_action_type or cc_action_type_set | List of labels | required | | | allow_empty | - | Boolean | optional | `False` | ## cc_args_list
cc_args_list(name, args)
An ordered list of cc_args. This is a convenience rule to allow you to group a set of multiple [`cc_args`](#cc_args) into a single list. This particularly useful for toolchain behaviors that require different flags for different actions. Note: The order of the arguments in `args` is preserved to support order-sensitive flags. Example usage: ``` load("@rules_cc//cc/toolchains:cc_args.bzl", "cc_args") load("@rules_cc//cc/toolchains:args_list.bzl", "cc_args_list") cc_args( name = "gc_sections", actions = [ "@rules_cc//cc/toolchains/actions:link_actions", ], args = ["-Wl,--gc-sections"], ) cc_args( name = "function_sections", actions = [ "@rules_cc//cc/toolchains/actions:compile_actions", "@rules_cc//cc/toolchains/actions:link_actions", ], args = ["-ffunction-sections"], ) cc_args_list( name = "gc_functions", args = [ ":function_sections", ":gc_sections", ], ) ``` **ATTRIBUTES** | Name | Description | Type | Mandatory | Default | | :------------- | :------------- | :------------- | :------------- | :------------- | | name | A unique name for this target. | Name | required | | | args | (ordered) cc_args to include in this list. | List of labels | optional | `[]` | ## cc_external_feature
cc_external_feature(name, feature_name, overridable)
A declaration that a [feature](https://bazel.build/docs/cc-toolchain-config-reference#features) with this name is defined elsewhere. This rule communicates that a feature has been defined externally to make it possible to reference features that live outside the rule-based cc toolchain ecosystem. This allows various toolchain rules to reference the external feature without accidentally re-defining said feature. This rule is currently considered a private API of the toolchain rules to encourage the Bazel ecosystem to migrate to properly defining their features as rules. Example: ``` load("@rules_cc//cc/toolchains:external_feature.bzl", "cc_external_feature") # rules_rust defines a feature that is disabled whenever rust artifacts are being linked using # the cc toolchain to signal that incompatible flags should be disabled as well. cc_external_feature( name = "rules_rust_unsupported_feature", feature_name = "rules_rust_unsupported_feature", overridable = False, ) ``` **ATTRIBUTES** | Name | Description | Type | Mandatory | Default | | :------------- | :------------- | :------------- | :------------- | :------------- | | name | A unique name for this target. | Name | required | | | feature_name | The name of the feature | String | required | | | overridable | Whether the feature can be overridden | Boolean | required | | ## cc_feature
cc_feature(name, args, feature_name, implies, mutually_exclusive, overrides, requires_any_of)
A dynamic set of toolchain flags that create a singular [feature](https://bazel.build/docs/cc-toolchain-config-reference#features) definition. A feature is basically a dynamically toggleable [`cc_args_list`](#cc_args_list). There are a variety of dependencies and compatibility requirements that must be satisfied to enable a [`cc_feature`](#cc_feature). Once those conditions are met, the arguments in [`cc_feature.args`](#cc_feature-args) are expanded and added to the command-line. A feature may be enabled or disabled through the following mechanisms: * Via command-line flags, or a `.bazelrc` file via the [`--features` flag](https://bazel.build/reference/command-line-reference#flag--features) * Through inter-feature relationships (via [`cc_feature.implies`](#cc_feature-implies)) where one feature may implicitly enable another. * Individual rules (e.g. `cc_library`) or `package` definitions may elect to manually enable or disable features through the [`features` attribute](https://bazel.build/reference/be/common-definitions#common.features). Note that a feature may alternate between enabled and disabled dynamically over the course of a build. Because of their toggleable nature, it's generally best to avoid adding arguments to a `cc_toolchain` as a [`cc_feature`](#cc_feature) unless strictly necessary. Instead, prefer to express arguments via [`cc_toolchain.args`](#cc_toolchain-args) whenever possible. You should use a [`cc_feature`](#cc_feature) when any of the following apply: * You need the flags to be dynamically toggled over the course of a build. * You want build files to be able to configure the flags in question. For example, a binary might specify `features = ["optimize_for_size"]` to create a small binary instead of optimizing for performance. * You need to carry forward Starlark toolchain behaviors. If you're migrating a complex Starlark-based toolchain definition to these rules, many of the workflows and flags were likely based on features. If you only need to configure flags via the Bazel command-line, instead consider adding a [`bool_flag`](https://github.com/bazelbuild/bazel-skylib/tree/main/doc/common_settings_doc.md#bool_flag) paired with a [`config_setting`](https://bazel.build/reference/be/general#config_setting) and then make your [`cc_args`](#cc_args) rule `select` on the `config_setting`. For more details about how Bazel handles features, see the official Bazel documentation at https://bazel.build/docs/cc-toolchain-config-reference#features. Example: ``` load("@rules_cc//cc/toolchains:feature.bzl", "cc_feature") # A feature that enables LTO, which may be incompatible when doing interop with various # languages (e.g. rust, go), or may need to be disabled for particular `cc_binary` rules # for various reasons. cc_feature( name = "lto", feature_name = "lto", args = [":lto_args"], ) ``` **ATTRIBUTES** | Name | Description | Type | Mandatory | Default | | :------------- | :------------- | :------------- | :------------- | :------------- | | name | A unique name for this target. | Name | required | | | args | A list of [`cc_args`](#cc_args) or [`cc_args_list`](#cc_args_list) labels that are expanded when this feature is enabled. | List of labels | optional | `[]` | | feature_name | The name of the feature that this rule implements.

The feature name is a string that will be used in the `features` attribute of rules to enable them (eg. `cc_binary(..., features = ["opt"])`.

While two features with the same `feature_name` may not be bound to the same toolchain, they can happily live alongside each other in the same BUILD file.

Example:
cc_feature(
    name = "sysroot_macos",
    feature_name = "sysroot",
    ...
)

cc_feature(
    name = "sysroot_linux",
    feature_name = "sysroot",
    ...
)
| String | optional | `""` | | implies | List of features enabled along with this feature.

Warning: If any of the features cannot be enabled, this feature is silently disabled. | List of labels | optional | `[]` | | mutually_exclusive | A list of things that this feature is mutually exclusive with.

It can be either: * A feature, in which case the two features are mutually exclusive. * A [`cc_mutually_exclusive_category`](#cc_mutually_exclusive_category), in which case all features that write `mutually_exclusive = [":category"]` are mutually exclusive with each other.

If this feature has a side-effect of implementing another feature, it can be useful to list that feature here to ensure they aren't enabled at the same time. | List of labels | optional | `[]` | | overrides | A declaration that this feature overrides a known feature.

In the example below, if you missed the "overrides" attribute, it would complain that the feature "opt" was defined twice.

Example:
load("@rules_cc//cc/toolchains:feature.bzl", "cc_feature")

cc_feature(
    name = "opt",
    feature_name = "opt",
    args = [":size_optimized"],
    overrides = "@rules_cc//cc/toolchains/features:opt",
)
| Label | optional | `None` | | requires_any_of | A list of feature sets that define toolchain compatibility.

If *at least one* of the listed [`cc_feature_set`](#cc_feature_set)s are fully satisfied (all features exist in the toolchain AND are currently enabled), this feature is deemed compatible and may be enabled.

Note: Even if `cc_feature.requires_any_of` is satisfied, a feature is not enabled unless another mechanism (e.g. command-line flags, `cc_feature.implies`, `cc_toolchain_config.enabled_features`) signals that the feature should actually be enabled. | List of labels | optional | `[]` | ## cc_feature_constraint
cc_feature_constraint(name, all_of, none_of)
Defines a compound relationship between features. This rule can be used with [`cc_args.require_any_of`](#cc_args-require_any_of) to specify that a set of arguments are only enabled when a constraint is met. Both `all_of` and `none_of` must be satisfied simultaneously. This is basically a [`cc_feature_set`](#cc_feature_set) that supports `none_of` expressions. This extra flexibility is why this rule may only be used by [`cc_args.require_any_of`](#cc_args-require_any_of). Example: ``` load("@rules_cc//cc/toolchains:feature_constraint.bzl", "cc_feature_constraint") # A constraint that requires a `linker_supports_thinlto` feature to be enabled, # AND a `no_optimization` to be disabled. cc_feature_constraint( name = "thinlto_constraint", all_of = [":linker_supports_thinlto"], none_of = [":no_optimization"], ) ``` **ATTRIBUTES** | Name | Description | Type | Mandatory | Default | | :------------- | :------------- | :------------- | :------------- | :------------- | | name | A unique name for this target. | Name | required | | | all_of | - | List of labels | optional | `[]` | | none_of | - | List of labels | optional | `[]` | ## cc_feature_set
cc_feature_set(name, all_of)
Defines a set of features. This may be used by both [`cc_feature`](#cc_feature) and [`cc_args`](#cc_args) rules, and is effectively a way to express a logical `AND` operation across multiple requred features. Example: ``` load("@rules_cc//cc/toolchains:feature_set.bzl", "cc_feature_set") cc_feature_set( name = "thin_lto_requirements", all_of = [ ":thin_lto", ":opt", ], ) ``` **ATTRIBUTES** | Name | Description | Type | Mandatory | Default | | :------------- | :------------- | :------------- | :------------- | :------------- | | name | A unique name for this target. | Name | required | | | all_of | A set of features | List of labels | optional | `[]` | ## cc_mutually_exclusive_category
cc_mutually_exclusive_category(name)
A rule used to categorize [`cc_feature`](#cc_feature) definitions for which only one can be enabled. This is used by [`cc_feature.mutually_exclusive`](#cc_feature-mutually_exclusive) to express groups of [`cc_feature`](#cc_feature) definitions that are inherently incompatible with each other and must be treated as mutually exclusive. Warning: These groups are keyed by name, so two [`cc_mutually_exclusive_category`](#cc_mutually_exclusive_category) definitions of the same name in different packages will resolve to the same logical group. Example: ``` load("@rules_cc//cc/toolchains:feature.bzl", "cc_feature") load("@rules_cc//cc/toolchains:mutually_exclusive_category.bzl", "cc_mutually_exclusive_category") cc_mutually_exclusive_category( name = "opt_level", ) cc_feature( name = "speed_optimized", mutually_exclusive = [":opt_level"], ) cc_feature( name = "size_optimized", mutually_exclusive = [":opt_level"], ) cc_feature( name = "unoptimized", mutually_exclusive = [":opt_level"], ) ``` **ATTRIBUTES** | Name | Description | Type | Mandatory | Default | | :------------- | :------------- | :------------- | :------------- | :------------- | | name | A unique name for this target. | Name | required | | ## cc_tool
cc_tool(name, src, data, allowlist_include_directories, capabilities)
Declares a tool for use by toolchain actions. [`cc_tool`](#cc_tool) rules are used in a [`cc_tool_map`](#cc_tool_map) rule to ensure all files and metadata required to run a tool are available when constructing a `cc_toolchain`. In general, include all files that are always required to run a tool (e.g. libexec/** and cross-referenced tools in bin/*) in the [data](#cc_tool-data) attribute. If some files are only required when certain flags are passed to the tool, consider using a [`cc_args`](#cc_args) rule to bind the files to the flags that require them. This reduces the overhead required to properly enumerate a sandbox with all the files required to run a tool, and ensures that there isn't unintentional leakage across configurations and actions. Example: ``` load("@rules_cc//cc/toolchains:tool.bzl", "cc_tool") cc_tool( name = "clang_tool", executable = "@llvm_toolchain//:bin/clang", # Suppose clang needs libc to run. data = ["@llvm_toolchain//:lib/x86_64-linux-gnu/libc.so.6"] tags = ["requires-network"], capabilities = ["@rules_cc//cc/toolchains/capabilities:supports_pic"], ) ``` **ATTRIBUTES** | Name | Description | Type | Mandatory | Default | | :------------- | :------------- | :------------- | :------------- | :------------- | | name | A unique name for this target. | Name | required | | | src | The underlying binary that this tool represents.

Usually just a single prebuilt (eg. @toolchain//:bin/clang), but may be any executable label. | Label | optional | `None` | | data | Additional files that are required for this tool to run.

Frequently, clang and gcc require additional files to execute as they often shell out to other binaries (e.g. `cc1`). | List of labels | optional | `[]` | | allowlist_include_directories | Include paths implied by using this tool.

Compilers may include a set of built-in headers that are implicitly available unless flags like `-nostdinc` are provided. Bazel checks that all included headers are properly provided by a dependency or allowlisted through this mechanism.

As a rule of thumb, only use this if Bazel is complaining about absolute paths in your toolchain and you've ensured that the toolchain is compiling with the `-no-canonical-prefixes` and/or `-fno-canonical-system-headers` arguments.

This can help work around errors like: `the source file 'main.c' includes the following non-builtin files with absolute paths (if these are builtin files, make sure these paths are in your toolchain)`. | List of labels | optional | `[]` | | capabilities | Declares that a tool is capable of doing something.

For example, `@rules_cc//cc/toolchains/capabilities:supports_pic`. | List of labels | optional | `[]` | ## cc_tool_capability
cc_tool_capability(name, feature_name)
A capability is an optional feature that a tool supports. For example, not all compilers support PIC, so to handle this, we write: ``` cc_tool( name = "clang", src = "@host_tools/bin/clang", capabilities = [ "@rules_cc//cc/toolchains/capabilities:supports_pic", ], ) cc_args( name = "pic", requires = [ "@rules_cc//cc/toolchains/capabilities:supports_pic" ], args = ["-fPIC"], ) ``` This ensures that `-fPIC` is added to the command-line only when we are using a tool that supports PIC. **ATTRIBUTES** | Name | Description | Type | Mandatory | Default | | :------------- | :------------- | :------------- | :------------- | :------------- | | name | A unique name for this target. | Name | required | | | feature_name | The name of the feature to generate for this capability | String | optional | `""` | ## cc_args
cc_args(name, actions, allowlist_include_directories, args, data, env, format, iterate_over, nested,
        requires_not_none, requires_none, requires_true, requires_false, requires_equal,
        requires_equal_value, requires_any_of, kwargs)
Action-specific arguments for use with a cc_toolchain. This rule is the fundamental building building block for every toolchain tool invocation. Each argument expressed in a toolchain tool invocation (e.g. `gcc`, `llvm-ar`) is declared in a [`cc_args`](#cc_args) rule that applies an ordered list of arguments to a set of toolchain actions. [`cc_args`](#cc_args) rules can be added unconditionally to a `cc_toolchain`, conditionally via `select()` statements, or dynamically via an intermediate [`cc_feature`](#cc_feature). Conceptually, this is similar to the old `CFLAGS`, `CPPFLAGS`, etc. environment variables that many build systems use to determine which flags to use for a given action. The significant difference is that [`cc_args`](#cc_args) rules are declared in a structured way that allows for significantly more powerful and sharable toolchain configurations. Also, due to Bazel's more granular action types, it's possible to bind flags to very specific actions (e.g. LTO indexing for an executable vs a dynamic library) multiple different actions (e.g. C++ compile and link simultaneously). Example usage: ``` load("@rules_cc//cc/toolchains:args.bzl", "cc_args") # Basic usage: a trivial flag. # # An example of expressing `-Werror` as a [`cc_args`](#cc_args) rule. cc_args( name = "warnings_as_errors", actions = [ # Applies to all C/C++ compile actions. "@rules_cc//cc/toolchains/actions:compile_actions", ], args = ["-Werror"], ) # Basic usage: ordered flags. # # An example of linking against libc++, which uses two flags that must be applied in order. cc_args( name = "link_libcxx", actions = [ # Applies to all link actions. "@rules_cc//cc/toolchains/actions:link_actions", ], # On tool invocation, this appears as `-Xlinker -lc++`. Nothing will ever end up between # the two flags. args = [ "-Xlinker", "-lc++", ], ) # Advanced usage: built-in variable expansions. # # Expands to `-L/path/to/search_dir` for each directory in the built-in variable # `library_search_directories`. This variable is managed internally by Bazel through inherent # behaviors of Bazel and the interactions between various C/C++ build rules. cc_args( name = "library_search_directories", actions = [ "@rules_cc//cc/toolchains/actions:link_actions", ], args = ["-L{search_dir}"], iterate_over = "@rules_cc//cc/toolchains/variables:library_search_directories", requires_not_none = "@rules_cc//cc/toolchains/variables:library_search_directories", format = { "search_dir": "@rules_cc//cc/toolchains/variables:library_search_directories", }, ) ``` For more extensive examples, see the usages here: https://github.com/bazelbuild/rules_cc/tree/main/cc/toolchains/args **PARAMETERS** | Name | Description | Default Value | | :------------- | :------------- | :------------- | | name | (str) The name of the target. | none | | actions | (List[Label]) A list of labels of [`cc_action_type`](#cc_action_type) or [`cc_action_type_set`](#cc_action_type_set) rules that dictate which actions these arguments should be applied to. | `None` | | allowlist_include_directories | (List[Label]) A list of include paths that are implied by using this rule. These must point to a skylib [directory](https://github.com/bazelbuild/bazel-skylib/tree/main/doc/directory_doc.md#directory) or [subdirectory](https://github.com/bazelbuild/bazel-skylib/tree/main/doc/directory_subdirectory_doc.md#subdirectory) rule. Some flags (e.g. --sysroot) imply certain include paths are available despite not explicitly specifying a normal include path flag (`-I`, `-isystem`, etc.). Bazel checks that all included headers are properly provided by a dependency or allowlisted through this mechanism.

As a rule of thumb, only use this if Bazel is complaining about absolute paths in your toolchain and you've ensured that the toolchain is compiling with the `-no-canonical-prefixes` and/or `-fno-canonical-system-headers` arguments.

This can help work around errors like: `the source file 'main.c' includes the following non-builtin files with absolute paths (if these are builtin files, make sure these paths are in your toolchain)`. | `None` | | args | (List[str]) The command-line arguments that are applied by using this rule. This is mutually exclusive with [nested](#cc_args-nested). | `None` | | data | (List[Label]) A list of runtime data dependencies that are required for these arguments to work as intended. | `None` | | env | (Dict[str, str]) Environment variables that should be set when the tool is invoked. | `None` | | format | (Dict[str, Label]) A mapping of format strings to the label of the corresponding [`cc_variable`](#cc_variable) that the value should be pulled from. All instances of `{variable_name}` will be replaced with the expanded value of `variable_name` in this dictionary. The complete list of possible variables can be found in https://github.com/bazelbuild/rules_cc/tree/main/cc/toolchains/variables/BUILD. It is not possible to declare custom variables--these are inherent to Bazel itself. | `{}` | | iterate_over | (Label) The label of a [`cc_variable`](#cc_variable) that should be iterated over. This is intended for use with built-in variables that are lists. | `None` | | nested | (List[Label]) A list of [`cc_nested_args`](#cc_nested_args) rules that should be expanded to command-line arguments when this rule is used. This is mutually exclusive with [args](#cc_args-args). | `None` | | requires_not_none | (Label) The label of a [`cc_variable`](#cc_variable) that should be checked for existence before expanding this rule. If the variable is None, this rule will be ignored. | `None` | | requires_none | (Label) The label of a [`cc_variable`](#cc_variable) that should be checked for non-existence before expanding this rule. If the variable is not None, this rule will be ignored. | `None` | | requires_true | (Label) The label of a [`cc_variable`](#cc_variable) that should be checked for truthiness before expanding this rule. If the variable is false, this rule will be ignored. | `None` | | requires_false | (Label) The label of a [`cc_variable`](#cc_variable) that should be checked for falsiness before expanding this rule. If the variable is true, this rule will be ignored. | `None` | | requires_equal | (Label) The label of a [`cc_variable`](#cc_variable) that should be checked for equality before expanding this rule. If the variable is not equal to (requires_equal_value)[#cc_args-requires_equal_value], this rule will be ignored. | `None` | | requires_equal_value | (str) The value to compare (requires_equal)[#cc_args-requires_equal] against. | `None` | | requires_any_of | (List[Label]) These arguments will be used in a tool invocation when at least one of the [cc_feature_constraint](#cc_feature_constraint) entries in this list are satisfied. If omitted, this flag set will be enabled unconditionally. | `None` | | kwargs | [common attributes](https://bazel.build/reference/be/common-definitions#common-attributes) that should be applied to this rule. | none | ## cc_nested_args
cc_nested_args(name, args, data, format, iterate_over, nested, requires_not_none, requires_none,
               requires_true, requires_false, requires_equal, requires_equal_value, kwargs)
Nested arguments for use in more complex [`cc_args`](#cc_args) expansions. While this rule is very similar in shape to [`cc_args`](#cc_args), it is intended to be used as a dependency of [`cc_args`](#cc_args) to provide additional arguments that should be applied to the same actions as defined by the parent [`cc_args`](#cc_args) rule. The key motivation for this rule is to allow for more complex variable-based argument expensions. Prefer expressing collections of arguments as [`cc_args`](#cc_args) and [`cc_args_list`](#cc_args_list) rules when possible. For living examples of how this rule is used, see the usages here: https://github.com/bazelbuild/rules_cc/tree/main/cc/toolchains/args/runtime_library_search_directories/BUILD https://github.com/bazelbuild/rules_cc/tree/main/cc/toolchains/args/libraries_to_link/BUILD Note: These examples are non-trivial, but they illustrate when it is absolutely necessary to use this rule. **PARAMETERS** | Name | Description | Default Value | | :------------- | :------------- | :------------- | | name | (str) The name of the target. | none | | args | (List[str]) The command-line arguments that are applied by using this rule. This is mutually exclusive with [nested](#cc_nested_args-nested). | `None` | | data | (List[Label]) A list of runtime data dependencies that are required for these arguments to work as intended. | `None` | | format | (Dict[str, Label]) A mapping of format strings to the label of the corresponding [`cc_variable`](#cc_variable) that the value should be pulled from. All instances of `{variable_name}` will be replaced with the expanded value of `variable_name` in this dictionary. The complete list of possible variables can be found in https://github.com/bazelbuild/rules_cc/tree/main/cc/toolchains/variables/BUILD. It is not possible to declare custom variables--these are inherent to Bazel itself. | `{}` | | iterate_over | (Label) The label of a [`cc_variable`](#cc_variable) that should be iterated over. This is intended for use with built-in variables that are lists. | `None` | | nested | (List[Label]) A list of [`cc_nested_args`](#cc_nested_args) rules that should be expanded to command-line arguments when this rule is used. This is mutually exclusive with [args](#cc_nested_args-args). | `None` | | requires_not_none | (Label) The label of a [`cc_variable`](#cc_variable) that should be checked for existence before expanding this rule. If the variable is None, this rule will be ignored. | `None` | | requires_none | (Label) The label of a [`cc_variable`](#cc_variable) that should be checked for non-existence before expanding this rule. If the variable is not None, this rule will be ignored. | `None` | | requires_true | (Label) The label of a [`cc_variable`](#cc_variable) that should be checked for truthiness before expanding this rule. If the variable is false, this rule will be ignored. | `None` | | requires_false | (Label) The label of a [`cc_variable`](#cc_variable) that should be checked for falsiness before expanding this rule. If the variable is true, this rule will be ignored. | `None` | | requires_equal | (Label) The label of a [`cc_variable`](#cc_variable) that should be checked for equality before expanding this rule. If the variable is not equal to (requires_equal_value)[#cc_nested_args-requires_equal_value], this rule will be ignored. | `None` | | requires_equal_value | (str) The value to compare (requires_equal)[#cc_nested_args-requires_equal] against. | `None` | | kwargs | [common attributes](https://bazel.build/reference/be/common-definitions#common-attributes) that should be applied to this rule. | none | ## cc_tool_map
cc_tool_map(name, tools, kwargs)
A toolchain configuration rule that maps toolchain actions to tools. A [`cc_tool_map`](#cc_tool_map) aggregates all the tools that may be used for a given toolchain and maps them to their corresponding actions. Conceptually, this is similar to the `CXX=/path/to/clang++` environment variables that most build systems use to determine which tools to use for a given action. To simplify usage, some actions have been grouped together (for example, [@rules_cc//cc/toolchains/actions:cpp_compile_actions](https://github.com/bazelbuild/rules_cc/tree/main/cc/toolchains/actions/BUILD)) to logically express "all the C++ compile actions". In Bazel, there is a little more granularity to the mapping, so the mapping doesn't follow the traditional `CXX`, `AR`, etc. naming scheme. For a comprehensive list of all the well-known actions, see @rules_cc//cc/toolchains/actions:BUILD. Example usage: ``` load("@rules_cc//cc/toolchains:tool_map.bzl", "cc_tool_map") cc_tool_map( name = "all_tools", tools = { "@rules_cc//cc/toolchains/actions:assembly_actions": ":asm", "@rules_cc//cc/toolchains/actions:c_compile": ":clang", "@rules_cc//cc/toolchains/actions:cpp_compile_actions": ":clang++", "@rules_cc//cc/toolchains/actions:link_actions": ":lld", "@rules_cc//cc/toolchains/actions:objcopy_embed_data": ":llvm-objcopy", "@rules_cc//cc/toolchains/actions:strip": ":llvm-strip", "@rules_cc//cc/toolchains/actions:ar_actions": ":llvm-ar", }, ) ``` Note: Due to an implementation limitation, if you need to map the same tool to multiple actions, you will need to create an intermediate alias for the tool for each set of actions. See https://github.com/bazelbuild/rules_cc/issues/235 for more details. **PARAMETERS** | Name | Description | Default Value | | :------------- | :------------- | :------------- | | name | (str) The name of the target. | none | | tools | (Dict[Label, Label]) A mapping between [`cc_action_type`](#cc_action_type)/[`cc_action_type_set`](#cc_action_type_set) targets and the [`cc_tool`](#cc_tool) or executable target that implements that action. | none | | kwargs | [common attributes](https://bazel.build/reference/be/common-definitions#common-attributes) that should be applied to this rule. | none | ## cc_variable
cc_variable(name, type, kwargs)
Exposes a toolchain variable to use in toolchain argument expansions. This internal rule exposes [toolchain variables](https://bazel.build/docs/cc-toolchain-config-reference#cctoolchainconfiginfo-build-variables) that may be expanded in [`cc_args`](#cc_args) or [`cc_nested_args`](#cc_nested_args) rules. Because these varaibles merely expose variables inherrent to Bazel, it's not possible to declare custom variables. For a full list of available variables, see [@rules_cc//cc/toolchains/varaibles:BUILD](https://github.com/bazelbuild/rules_cc/tree/main/cc/toolchains/variables/BUILD). Example: ``` load("@rules_cc//cc/toolchains/impl:variables.bzl", "cc_variable") # Defines two targets, ":foo" and ":foo.bar" cc_variable( name = "foo", type = types.list(types.struct(bar = types.string)), ) ``` **PARAMETERS** | Name | Description | Default Value | | :------------- | :------------- | :------------- | | name | (str) The name of the outer variable, and the rule. | none | | type | The type of the variable, constructed using `types` factory in [@rules_cc//cc/toolchains/impl:variables.bzl](https://github.com/bazelbuild/rules_cc/tree/main/cc/toolchains/impl/variables.bzl). | none | | kwargs | [common attributes](https://bazel.build/reference/be/common-definitions#common-attributes) that should be applied to this rule. | none | rules_cc-0.0.11/examples/000077500000000000000000000000001470072561500152155ustar00rootroot00000000000000rules_cc-0.0.11/examples/BUILD000066400000000000000000000024751470072561500160070ustar00rootroot00000000000000# Copyright 2019 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. # A collection of examples showing the usage of rules_cc load("@bazel_skylib//:bzl_library.bzl", "bzl_library") load("@bazel_skylib//rules:common_settings.bzl", "bool_flag") licenses(["notice"]) bool_flag( name = "incompatible_link_once", build_setting_default = False, visibility = ["//visibility:public"], ) bool_flag( name = "enable_permissions_check", build_setting_default = False, visibility = ["//visibility:public"], ) bool_flag( name = "experimental_debug", build_setting_default = False, visibility = ["//visibility:public"], ) bzl_library( name = "experimental_cc_shared_library_bzl", srcs = ["experimental_cc_shared_library.bzl"], visibility = ["//visibility:private"], ) rules_cc-0.0.11/examples/custom_toolchain/000077500000000000000000000000001470072561500205675ustar00rootroot00000000000000rules_cc-0.0.11/examples/custom_toolchain/BUILD000066400000000000000000000106161470072561500213550ustar00rootroot00000000000000# Copyright 2021 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. # Proof-of-concept example showing how to write a custom C++ toolchain. # # Important documentation: # # - https://docs.bazel.build/versions/master/platforms-intro.html#c # - https://docs.bazel.build/versions/master/tutorial/cc-toolchain-config.html # - https://docs.bazel.build/versions/master/be/c-cpp.html#cc_toolchain # # There are two ways to select C++ toolchains: # # - NEW (USE IF POSSIBLE): with the --platforms flag # - LEGACY: with the --crosstool_top and --cpu flags # # See https://docs.bazel.build/versions/master/platforms-intro.html#c for details. # # This example demonstrates both approaches. load("@rules_cc//cc:defs.bzl", "cc_library", "cc_toolchain", "cc_toolchain_suite") # Load the Starlark logic defining the toolchain's behavior. For example: what # program runs to compile a source file and how its command line is # constructed. See toolchain_config.bzl for details. load(":toolchain_config.bzl", "cc_toolchain_config") # The library we want to build. Building this calls two C++ actions: compile (.cc -> # .o) and archive (.o -> .a). cc_library( name = "buildme", srcs = ["buildme.cc"], ) # This example intentionally makes the cc_toolchain_config definition # simple. You could alternative add attributes to support multiple # cc_toolchain_config targets with finer customization. cc_toolchain_config( name = "toolchain_semantics", ) # Register the toolchain with Bazel. Most of these attribute just tell Bazel # where to find the files needed to run C++ commands. The toolchain_config # attribute registers the behavior specification declared above. cc_toolchain( name = "my_custom_toolchain", all_files = ":toolchain_files", ar_files = ":toolchain_files", compiler_files = ":toolchain_files", dwp_files = ":toolchain_files", linker_files = ":toolchain_files", objcopy_files = ":toolchain_files", strip_files = ":toolchain_files", toolchain_config = ":toolchain_semantics", ) filegroup( name = "toolchain_files", srcs = [ "sample_compiler", "sample_linker", ], ) # Implements legacy toolchain selection. # # Setting --crosstool_top here registers the set of available # toolchains. Setting --cpu to one of the toolchain attribute's keys selects a #toolchain. cc_toolchain_suite( name = "legacy_selector", toolchains = { "x86": ":my_custom_toolchain", }, ) # Implements platform-based (recommended) toolchain selection. # # See https://docs.bazel.build/versions/master/platforms-intro.html. The main # differences are: # # 1. --cpu / --crosstool_top are replaced by a platform() definition with # much more customizable properties. For example, a platform can specify # OS, device type (server, phone, tablet) or custom hardware extensions. # 2. All languages can support platform-based toolchains. A single --platforms # value can choose C++, Python, Scala, and all other toolchains in your # build. This is especially useful for multi-language builds. # 3. Platforms support features like incompatible target skipping: # https://docs.bazel.build/versions/master/platforms.html#skipping-incompatible-targets. toolchain( name = "platform_based_toolchain", # Trigger this toolchain for x86-compatible platforms. # See https://github.com/bazelbuild/platforms. target_compatible_with = ["@platforms//cpu:x86_64"], # Register this toolchain with platforms. toolchain = ":my_custom_toolchain", # The public interface for all C++ toolchains. Starlark rules that use C++ # access the toolchain through this interface. toolchain_type = "@bazel_tools//tools/cpp:toolchain_type", ) # Define a platform matching any x86-compatible toolchain. See # https://docs.bazel.build/versions/master/platforms.html. platform( name = "x86_platform", constraint_values = ["@platforms//cpu:x86_64"], ) rules_cc-0.0.11/examples/custom_toolchain/README.md000066400000000000000000000065741470072561500220620ustar00rootroot00000000000000# Writing a custom C++ toolchain This example shows how to define and use a simple custom C++ toolchain. Output is non-functional: simple scripts replace compilation and linking with `I compiled!` and `I linked!` messages. [BUILD](BUILD) provides detailed implementation walkthrough. The fundamental sequence is: 1. Define the toolchain 1. Define how to invoke the toolchain. `1` is C++-specific: the logic and structure depends specifically on C++'s language model. Other languages have their own models. `2` supports two variations. `--crosstool_top` / `--cpu`, the legacy version, is C++-specific. `--platforms`, the modern version, is much more generic and supports all languages and features like [incompatible target skipping](https://docs.bazel.build/versions/master/platforms.html#skipping-incompatible-targets). See [Building with Platforms](https://docs.bazel.build/versions/master/platforms-intro.html) and its [C++ notes](https://docs.bazel.build/versions/master/platforms-intro.html#c) for full review. ## Building with the default toolchain ``` $ bazel clean $ bazel build //examples/custom_toolchain:buildme $ file bazel-bin/examples/custom_toolchain/libbuildme.a bazel-bin/examples/custom_toolchain/libbuildme.a: current ar archive ``` ## Custom toolchain with platforms This mode requires `--incompatible_enable_cc_toolchain_resolution`. Without this flag, `--platforms` and `--extra_toolchains` are ignored and the default toolchain triggers. ``` $ bazel clean $ bazel build //examples/custom_toolchain:buildme --platforms=//examples/custom_toolchain:x86_platform --extra_toolchains=//examples/custom_toolchain:platform_based_toolchain --incompatible_enable_cc_toolchain_resolution DEBUG: /usr/local/google/home/gregce/bazel/rules_cc/examples/custom_toolchain/toolchain_config.bzl:17:10: Invoking my custom toolchain! INFO: From Compiling examples/custom_toolchain/buildme.cc: examples/custom_toolchain/sample_compiler: running sample cc_library compiler (produces .o output). INFO: From Linking examples/custom_toolchain/libbuildme.a: examples/custom_toolchain/sample_linker: running sample cc_library linker (produces .a output). $ cat bazel-bin/examples/custom_toolchain/libbuildme.a examples/custom_toolchain/sample_linker: sample output ``` This example uses a long command line for demonstration purposes. A real project would [register toolchains](https://docs.bazel.build/versions/master/toolchains.html#registering-and-building-with-toolchains) in `WORKSPACE` and auto-set `--incompatible_enable_cc_toolchain_resolution`. That reduces the command to: ``` $ bazel build //examples/custom_toolchain:buildme --platforms=//examples/custom_toolchain:x86_platform ``` ## Custom toolchain with legacy selection: ``` $ bazel clean $ bazel build //examples/custom_toolchain:buildme --crosstool_top=//examples/custom_toolchain:legacy_selector --cpu=x86 DEBUG: /usr/local/google/home/gregce/bazel/rules_cc/examples/custom_toolchain/toolchain_config.bzl:17:10: Invoking my custom toolchain! INFO: From Compiling examples/custom_toolchain/buildme.cc: examples/custom_toolchain/sample_compiler: running sample cc_library compiler (produces .o output). INFO: From Linking examples/custom_toolchain/libbuildme.a: examples/custom_toolchain/sample_linker: running sample cc_library linker (produces .a output). $ cat bazel-bin/examples/custom_toolchain/libbuildme.a examples/custom_toolchain/sample_linker: sample output ``` rules_cc-0.0.11/examples/custom_toolchain/buildme.cc000066400000000000000000000000451470072561500225160ustar00rootroot00000000000000 int some_function() { return 0; } rules_cc-0.0.11/examples/custom_toolchain/sample_compiler000077500000000000000000000014671470072561500237000ustar00rootroot00000000000000#!/bin/bash # # Sample script demonstrating custom C++ toolchain selection: handles # the command that translates a cc_library's .cc (source file) into .o (object # file). echo "$0: running sample cc_library compiler (produces .o output)." # https://docs.bazel.build/versions/master/cc-toolchain-config-reference.html # defines fancier ways to generate custom command lines. This script just shows # the default, which looks like: # # examples/custom_toolchain/sample_compiler -o bazel-out/x86-fastbuild/bin/examples/custom_toolchain/_objs/buildme/buildme.o. # The .o is the last parameter. OBJECT_FILE=${@: -1} # Swap out .o for .d to get expected .d (source dependency output). DOTD_FILE=${OBJECT_FILE%?}d echo "$0: sample .o output" > $OBJECT_FILE echo "sample .d output ($0)" > $DOTD_FILE rules_cc-0.0.11/examples/custom_toolchain/sample_linker000077500000000000000000000014171470072561500233450ustar00rootroot00000000000000#!/bin/bash # # Sample script demonstrating custom C++ toolchain selection: handles # the command that translates a cc_library's .o (object file) into # .a (archive). echo "$0: running sample cc_library linker (produces .a output)." # https://docs.bazel.build/versions/master/cc-toolchain-config-reference.html # defines fancier ways to generate custom command lines. This script just shows # the default, which looks like: # # examples/custom_toolchain/sample_linker @bazel-out/x86-fastbuild/bin/examples/custom_toolchain/libbuildme.a-2.params. # Get "@bazel-out/.../libbuildme.a-2.params". PARAMS_FILE=${@: -1} # Remove the "@" prefix. OUTFILE=${PARAMS_FILE#?} # Replace "libbuildme.a-2.params" with "libbuildme.a". OUTFILE=${OUTFILE%-*} echo "$0: sample output" > $OUTFILE rules_cc-0.0.11/examples/custom_toolchain/toolchain_config.bzl000066400000000000000000000046351470072561500246150ustar00rootroot00000000000000"""Sample Starlark definition defining a C++ toolchain's behavior. When you build a cc_* rule, this logic defines what programs run for what build steps (e.g. compile / link / archive) and how their command lines are structured. This is a proof-of-concept simple implementation. It doesn't construct fancy command lines and uses mock shell scripts to compile and link ("sample_compiler" and "sample_linker"). See https://docs.bazel.build/versions/main/cc-toolchain-config-reference.html and https://docs.bazel.build/versions/main/tutorial/cc-toolchain-config.html for advanced usage. """ load("@rules_cc//cc:cc_toolchain_config_lib.bzl", "tool_path") # buildifier: disable=deprecated-function def _impl(ctx): tool_paths = [ tool_path( name = "ar", path = "sample_linker", ), tool_path( name = "cpp", path = "not_used_in_this_example", ), tool_path( name = "gcc", path = "sample_compiler", ), tool_path( name = "gcov", path = "not_used_in_this_example", ), tool_path( name = "ld", path = "sample_linker", ), tool_path( name = "nm", path = "not_used_in_this_example", ), tool_path( name = "objdump", path = "not_used_in_this_example", ), tool_path( name = "strip", path = "not_used_in_this_example", ), ] # Documented at # https://docs.bazel.build/versions/main/skylark/lib/cc_common.html#create_cc_toolchain_config_info. # # create_cc_toolchain_config_info is the public interface for registering # C++ toolchain behavior. return cc_common.create_cc_toolchain_config_info( ctx = ctx, toolchain_identifier = "custom-toolchain-identifier", host_system_name = "local", target_system_name = "local", target_cpu = "sample_cpu", target_libc = "unknown", compiler = "gcc", abi_version = "unknown", abi_libc_version = "unknown", tool_paths = tool_paths, ) cc_toolchain_config = rule( implementation = _impl, # You can alternatively define attributes here that make it possible to # instantiate different cc_toolchain_config targets with different behavior. attrs = {}, provides = [CcToolchainConfigInfo], ) rules_cc-0.0.11/examples/experimental_cc_shared_library.bzl000066400000000000000000000041541470072561500241460ustar00rootroot00000000000000"""This is an experimental implementation of cc_shared_library. We may change the implementation at any moment or even delete this file. Do not rely on this. It requires bazel >1.2 and passing the flag --experimental_cc_shared_library """ # Add this as a tag to any target that can be linked by more than one # cc_shared_library because it doesn't have static initializers or anything # else that may cause issues when being linked more than once. This should be # used sparingly after making sure it's safe to use. LINKABLE_MORE_THAN_ONCE = "LINKABLE_MORE_THAN_ONCE" CcSharedLibraryPermissionsInfo = provider( "Permissions for a cc shared library.", fields = { "targets": "Matches targets that can be exported.", }, ) GraphNodeInfo = provider( "Nodes in the graph of shared libraries.", fields = { "children": "Other GraphNodeInfo from dependencies of this target", "label": "Label of the target visited", "linkable_more_than_once": "Linkable into more than a single cc_shared_library", }, ) CcSharedLibraryInfo = provider( "Information about a cc shared library.", fields = { "dynamic_deps": "All shared libraries depended on transitively", "exports": "cc_libraries that are linked statically and exported", "link_once_static_libs": "All libraries linked statically into this library that should " + "only be linked once, e.g. because they have static " + "initializers. If we try to link them more than once, " + "we will throw an error", "linker_input": "the resulting linker input artifact for the shared library", "preloaded_deps": "cc_libraries needed by this cc_shared_library that should" + " be linked the binary. If this is set, this cc_shared_library has to " + " be a direct dependency of the cc_binary", }, ) def cc_shared_library_permissions(**kwargs): native.cc_shared_library_permissions(**kwargs) def cc_shared_library(**kwargs): native.cc_shared_library(**kwargs) rules_cc-0.0.11/examples/my_c_archive/000077500000000000000000000000001470072561500176455ustar00rootroot00000000000000rules_cc-0.0.11/examples/my_c_archive/BUILD000066400000000000000000000025101470072561500204250ustar00rootroot00000000000000# Copyright 2019 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. # Example showing how to create a custom Starlark rule that rules_cc can depend on load("@bazel_skylib//:bzl_library.bzl", "bzl_library") load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library") load("//examples/my_c_archive:my_c_archive.bzl", "my_c_archive") load("//examples/my_c_compile:my_c_compile.bzl", "my_c_compile") licenses(["notice"]) cc_binary( name = "main", srcs = ["main.c"], deps = [":archive"], ) my_c_archive( name = "archive", object = ":object", deps = [":bar"], ) my_c_compile( name = "object", src = "foo.c", ) cc_library( name = "bar", srcs = ["bar.c"], ) bzl_library( name = "my_c_archive_bzl", srcs = ["my_c_archive.bzl"], visibility = ["//visibility:private"], ) rules_cc-0.0.11/examples/my_c_archive/bar.c000066400000000000000000000000321470072561500205500ustar00rootroot00000000000000int bar() { return -42; } rules_cc-0.0.11/examples/my_c_archive/foo.c000066400000000000000000000012011470072561500205660ustar00rootroot00000000000000// Copyright 2019 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. int foo() { return 42; } rules_cc-0.0.11/examples/my_c_archive/main.c000066400000000000000000000000731470072561500207350ustar00rootroot00000000000000int foo(); int bar(); int main() { return foo() + bar(); } rules_cc-0.0.11/examples/my_c_archive/my_c_archive.bzl000066400000000000000000000071471470072561500230170ustar00rootroot00000000000000# Copyright 2019 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. """Example showing how to create a rule that rules_cc can depend on.""" load("@rules_cc//cc:action_names.bzl", "CPP_LINK_STATIC_LIBRARY_ACTION_NAME") load("@rules_cc//cc:find_cc_toolchain.bzl", "find_cpp_toolchain", "use_cc_toolchain") load("//examples/my_c_compile:my_c_compile.bzl", "MyCCompileInfo") def _my_c_archive_impl(ctx): cc_toolchain = find_cpp_toolchain(ctx) object_file = ctx.attr.object[MyCCompileInfo].object output_file = ctx.actions.declare_file(ctx.label.name + ".a") feature_configuration = cc_common.configure_features( ctx = ctx, cc_toolchain = cc_toolchain, requested_features = ctx.features, unsupported_features = ctx.disabled_features, ) linker_input = cc_common.create_linker_input( owner = ctx.label, libraries = depset(direct = [ cc_common.create_library_to_link( actions = ctx.actions, feature_configuration = feature_configuration, cc_toolchain = cc_toolchain, static_library = output_file, ), ]), ) compilation_context = cc_common.create_compilation_context() linking_context = cc_common.create_linking_context(linker_inputs = depset(direct = [linker_input])) archiver_path = cc_common.get_tool_for_action( feature_configuration = feature_configuration, action_name = CPP_LINK_STATIC_LIBRARY_ACTION_NAME, ) archiver_variables = cc_common.create_link_variables( feature_configuration = feature_configuration, cc_toolchain = cc_toolchain, output_file = output_file.path, is_using_linker = False, ) command_line = cc_common.get_memory_inefficient_command_line( feature_configuration = feature_configuration, action_name = CPP_LINK_STATIC_LIBRARY_ACTION_NAME, variables = archiver_variables, ) args = ctx.actions.args() args.add_all(command_line) args.add(object_file) env = cc_common.get_environment_variables( feature_configuration = feature_configuration, action_name = CPP_LINK_STATIC_LIBRARY_ACTION_NAME, variables = archiver_variables, ) ctx.actions.run( executable = archiver_path, arguments = [args], env = env, inputs = depset( direct = [object_file], transitive = [ cc_toolchain.all_files, ], ), outputs = [output_file], ) cc_info = cc_common.merge_cc_infos(cc_infos = [ CcInfo(compilation_context = compilation_context, linking_context = linking_context), ] + [dep[CcInfo] for dep in ctx.attr.deps]) return [cc_info] my_c_archive = rule( implementation = _my_c_archive_impl, attrs = { "deps": attr.label_list(providers = [CcInfo]), "object": attr.label(mandatory = True, providers = [MyCCompileInfo]), "_cc_toolchain": attr.label(default = Label("@rules_cc//cc:current_cc_toolchain")), }, fragments = ["cpp"], toolchains = use_cc_toolchain(), ) rules_cc-0.0.11/examples/my_c_compile/000077500000000000000000000000001470072561500176545ustar00rootroot00000000000000rules_cc-0.0.11/examples/my_c_compile/BUILD000066400000000000000000000017571470072561500204500ustar00rootroot00000000000000load("@bazel_skylib//:bzl_library.bzl", "bzl_library") load("//examples/my_c_compile:my_c_compile.bzl", "my_c_compile") # Copyright 2019 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. # Example showing how to create a custom Starlark rule that just compiles C sources licenses(["notice"]) my_c_compile( name = "foo", src = "foo.c", ) bzl_library( name = "my_c_compile_bzl", srcs = ["my_c_compile.bzl"], visibility = ["//visibility:private"], ) rules_cc-0.0.11/examples/my_c_compile/foo.c000066400000000000000000000012011470072561500205750ustar00rootroot00000000000000// Copyright 2019 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. int foo() { return 42; } rules_cc-0.0.11/examples/my_c_compile/my_c_compile.bzl000066400000000000000000000056161470072561500230340ustar00rootroot00000000000000# Copyright 2019 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. """Example showing how to create a rule that just compiles C sources.""" load("@rules_cc//cc:action_names.bzl", "C_COMPILE_ACTION_NAME") load("@rules_cc//cc:find_cc_toolchain.bzl", "find_cpp_toolchain", "use_cc_toolchain") MyCCompileInfo = provider(doc = "", fields = ["object"]) DISABLED_FEATURES = [ "module_maps", # # copybara-comment-this-out-please ] def _my_c_compile_impl(ctx): cc_toolchain = find_cpp_toolchain(ctx) source_file = ctx.file.src output_file = ctx.actions.declare_file(ctx.label.name + ".o") feature_configuration = cc_common.configure_features( ctx = ctx, cc_toolchain = cc_toolchain, requested_features = ctx.features, unsupported_features = DISABLED_FEATURES + ctx.disabled_features, ) c_compiler_path = cc_common.get_tool_for_action( feature_configuration = feature_configuration, action_name = C_COMPILE_ACTION_NAME, ) c_compile_variables = cc_common.create_compile_variables( feature_configuration = feature_configuration, cc_toolchain = cc_toolchain, user_compile_flags = ctx.fragments.cpp.copts + ctx.fragments.cpp.conlyopts, source_file = source_file.path, output_file = output_file.path, ) command_line = cc_common.get_memory_inefficient_command_line( feature_configuration = feature_configuration, action_name = C_COMPILE_ACTION_NAME, variables = c_compile_variables, ) env = cc_common.get_environment_variables( feature_configuration = feature_configuration, action_name = C_COMPILE_ACTION_NAME, variables = c_compile_variables, ) ctx.actions.run( executable = c_compiler_path, arguments = command_line, env = env, inputs = depset( [source_file], transitive = [cc_toolchain.all_files], ), outputs = [output_file], ) return [ DefaultInfo(files = depset([output_file])), MyCCompileInfo(object = output_file), ] my_c_compile = rule( implementation = _my_c_compile_impl, attrs = { "src": attr.label(mandatory = True, allow_single_file = True), "_cc_toolchain": attr.label(default = Label("@rules_cc//cc:current_cc_toolchain")), }, toolchains = use_cc_toolchain(), fragments = ["cpp"], ) rules_cc-0.0.11/examples/write_cc_toolchain_cpu/000077500000000000000000000000001470072561500217235ustar00rootroot00000000000000rules_cc-0.0.11/examples/write_cc_toolchain_cpu/BUILD000066400000000000000000000020201470072561500224770ustar00rootroot00000000000000load("@bazel_skylib//:bzl_library.bzl", "bzl_library") load("//examples/write_cc_toolchain_cpu:write_cc_toolchain_cpu.bzl", "write_cc_toolchain_cpu") # Copyright 2019 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. # Example showing how to get CcToolchainInfo in a custom starlark rule licenses(["notice"]) write_cc_toolchain_cpu(name = "write_me_the_cpu") bzl_library( name = "write_cc_toolchain_cpu_bzl", srcs = ["write_cc_toolchain_cpu.bzl"], visibility = ["//visibility:private"], ) rules_cc-0.0.11/examples/write_cc_toolchain_cpu/write_cc_toolchain_cpu.bzl000066400000000000000000000024651470072561500271510ustar00rootroot00000000000000# Copyright 2019 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. """Example showing how to get CcToolchainInfo in a custom rule.""" load("@rules_cc//cc:find_cc_toolchain.bzl", "find_cpp_toolchain", "use_cc_toolchain") def _write_cc_toolchain_cpu_impl(ctx): cc_toolchain = find_cpp_toolchain(ctx) output = ctx.actions.declare_file(ctx.label.name + "_cpu") ctx.actions.write(output, cc_toolchain.cpu) return [DefaultInfo(files = depset([output]))] # This rule does nothing, just writes the target_cpu from the cc_toolchain used for this build. write_cc_toolchain_cpu = rule( implementation = _write_cc_toolchain_cpu_impl, attrs = { "_cc_toolchain": attr.label(default = Label("@rules_cc//cc:current_cc_toolchain")), }, toolchains = use_cc_toolchain(), ) rules_cc-0.0.11/renovate.json000066400000000000000000000000611470072561500161120ustar00rootroot00000000000000{ "extends": [ "config:base" ] } rules_cc-0.0.11/tests/000077500000000000000000000000001470072561500145415ustar00rootroot00000000000000rules_cc-0.0.11/tests/compiler_settings/000077500000000000000000000000001470072561500202735ustar00rootroot00000000000000rules_cc-0.0.11/tests/compiler_settings/BUILD000066400000000000000000000022111470072561500210510ustar00rootroot00000000000000# 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. load("//cc:defs.bzl", "cc_binary") licenses(["notice"]) cc_binary( name = "main", srcs = ["main.cc"], local_defines = select( { "//cc/compiler:clang": ["COMPILER=clang"], "//cc/compiler:clang-cl": ["COMPILER=clang-cl"], "//cc/compiler:gcc": ["COMPILER=gcc"], "//cc/compiler:mingw-gcc": ["COMPILER=mingw-gcc"], "//cc/compiler:msvc-cl": ["COMPILER=msvc-cl"], "//conditions:default": [], }, no_match_error = "Compiler not detected by Bazel", ), ) rules_cc-0.0.11/tests/compiler_settings/main.cc000066400000000000000000000014141470072561500215260ustar00rootroot00000000000000// 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. #include #define STRINGIFY(x) #x #define TO_STRING(x) STRINGIFY(x) int main() { std::cout << "Hello, " << TO_STRING(COMPILER) << "!" << std::endl; } rules_cc-0.0.11/tests/load_from_macro/000077500000000000000000000000001470072561500176645ustar00rootroot00000000000000rules_cc-0.0.11/tests/load_from_macro/BUILD000066400000000000000000000016321470072561500204500ustar00rootroot00000000000000# Copyright 2019 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. load("@bazel_skylib//:bzl_library.bzl", "bzl_library") load("//cc:defs.bzl", "cc_library") load(":tags.bzl", "TAGS") licenses(["notice"]) cc_library( name = "foo", srcs = ["foo.cc"], tags = TAGS, ) bzl_library( name = "tags_bzl", srcs = ["tags.bzl"], visibility = ["//visibility:private"], ) rules_cc-0.0.11/tests/load_from_macro/foo.cc000066400000000000000000000011471470072561500207610ustar00rootroot00000000000000// Copyright 2019 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. rules_cc-0.0.11/tests/load_from_macro/tags.bzl000066400000000000000000000012561470072561500213370ustar00rootroot00000000000000# Copyright 2019 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. """ Example tags defined in a separate file. """ TAGS = ["first_tag", "second_tag"] rules_cc-0.0.11/tests/rule_based_toolchain/000077500000000000000000000000001470072561500207065ustar00rootroot00000000000000rules_cc-0.0.11/tests/rule_based_toolchain/BUILD000066400000000000000000000000001470072561500214560ustar00rootroot00000000000000rules_cc-0.0.11/tests/rule_based_toolchain/actions/000077500000000000000000000000001470072561500223465ustar00rootroot00000000000000rules_cc-0.0.11/tests/rule_based_toolchain/actions/BUILD000066400000000000000000000015651470072561500231370ustar00rootroot00000000000000load("@rules_testing//lib:util.bzl", "util") load("//cc/toolchains:actions.bzl", "cc_action_type", "cc_action_type_set") load("//tests/rule_based_toolchain:analysis_test_suite.bzl", "analysis_test_suite") load(":actions_test.bzl", "TARGETS", "TESTS") util.helper_target( cc_action_type, name = "c_compile", action_name = "c_compile", visibility = ["//tests/rule_based_toolchain:__subpackages__"], ) util.helper_target( cc_action_type, name = "cpp_compile", action_name = "cpp_compile", visibility = ["//tests/rule_based_toolchain:__subpackages__"], ) util.helper_target( cc_action_type_set, name = "all_compile", actions = [ ":c_compile", ":cpp_compile", ], visibility = ["//tests/rule_based_toolchain:__subpackages__"], ) analysis_test_suite( name = "test_suite", targets = TARGETS, tests = TESTS, ) rules_cc-0.0.11/tests/rule_based_toolchain/actions/actions_test.bzl000066400000000000000000000025671470072561500255700ustar00rootroot00000000000000# Copyright 2024 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. """Tests for actions for the rule based toolchain.""" load( "//cc/toolchains:cc_toolchain_info.bzl", "ActionTypeInfo", "ActionTypeSetInfo", ) visibility("private") def _test_action_types_impl(env, targets): env.expect.that_target(targets.c_compile).provider(ActionTypeInfo) \ .name().equals("c_compile") env.expect.that_target(targets.cpp_compile).provider(ActionTypeSetInfo) \ .actions().contains_exactly([targets.cpp_compile.label]) env.expect.that_target(targets.all_compile).provider(ActionTypeSetInfo) \ .actions().contains_exactly([ targets.c_compile.label, targets.cpp_compile.label, ]) TARGETS = [ ":c_compile", ":cpp_compile", ":all_compile", ] TESTS = { "actions_test": _test_action_types_impl, } rules_cc-0.0.11/tests/rule_based_toolchain/analysis_test_suite.bzl000066400000000000000000000036521470072561500255200ustar00rootroot00000000000000# Copyright 2024 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. """Test suites for the rule based toolchain.""" load("@rules_testing//lib:analysis_test.bzl", "analysis_test") load(":subjects.bzl", "FACTORIES") visibility("//tests/rule_based_toolchain/...") _DEFAULT_TARGET = "//tests/rule_based_toolchain/actions:c_compile" # Tests of internal starlark functions will often not require any targets, # but analysis_test requires at least one, so we pick an arbitrary one. def analysis_test_suite(name, tests, targets = [_DEFAULT_TARGET]): """A test suite for the internals of the toolchain. Args: name: (str) The name of the test suite. tests: (dict[str, fn]) A mapping from test name to implementations. targets: (List[Label|str]) List of targets accessible to the test. """ targets = [native.package_relative_label(target) for target in targets] test_case_names = [] for test_name, impl in tests.items(): if not test_name.endswith("_test"): fail("Expected test keys to end with '_test', got test case %r" % test_name) test_case_names.append(":" + test_name) analysis_test( name = test_name, impl = impl, provider_subject_factories = FACTORIES, targets = {label.name: label for label in targets}, ) native.test_suite( name = name, tests = test_case_names, ) rules_cc-0.0.11/tests/rule_based_toolchain/args/000077500000000000000000000000001470072561500216425ustar00rootroot00000000000000rules_cc-0.0.11/tests/rule_based_toolchain/args/BUILD000066400000000000000000000022461470072561500224300ustar00rootroot00000000000000load("@rules_testing//lib:util.bzl", "util") load("//cc/toolchains:args.bzl", "cc_args") load("//tests/rule_based_toolchain:analysis_test_suite.bzl", "analysis_test_suite") load(":args_test.bzl", "TARGETS", "TESTS") util.helper_target( cc_args, name = "simple", actions = ["//tests/rule_based_toolchain/actions:all_compile"], args = [ "--foo", "foo", ], data = [ "//tests/rule_based_toolchain/testdata:file1", "//tests/rule_based_toolchain/testdata:multiple", ], env = {"BAR": "bar"}, ) util.helper_target( cc_args, name = "env_only", actions = ["//tests/rule_based_toolchain/actions:all_compile"], data = [ "//tests/rule_based_toolchain/testdata:file1", "//tests/rule_based_toolchain/testdata:multiple", ], env = {"BAR": "bar"}, ) util.helper_target( cc_args, name = "with_dir", actions = ["//tests/rule_based_toolchain/actions:all_compile"], allowlist_include_directories = ["//tests/rule_based_toolchain/testdata:directory"], args = ["--secret-builtin-include-dir"], ) analysis_test_suite( name = "test_suite", targets = TARGETS, tests = TESTS, ) rules_cc-0.0.11/tests/rule_based_toolchain/args/args_test.bzl000066400000000000000000000077471470072561500243650ustar00rootroot00000000000000# Copyright 2024 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. """Tests for the cc_args rule.""" load( "//cc:cc_toolchain_config_lib.bzl", "env_entry", "env_set", "flag_group", "flag_set", ) load( "//cc/toolchains:cc_toolchain_info.bzl", "ActionTypeInfo", "ArgsInfo", "ArgsListInfo", ) load( "//cc/toolchains/impl:legacy_converter.bzl", "convert_args", ) load("//tests/rule_based_toolchain:subjects.bzl", "subjects") visibility("private") _SIMPLE_FILES = [ "tests/rule_based_toolchain/testdata/file1", "tests/rule_based_toolchain/testdata/multiple1", "tests/rule_based_toolchain/testdata/multiple2", ] _TOOL_DIRECTORY = "tests/rule_based_toolchain/testdata" _CONVERTED_ARGS = subjects.struct( flag_sets = subjects.collection, env_sets = subjects.collection, ) def _simple_test(env, targets): simple = env.expect.that_target(targets.simple).provider(ArgsInfo) simple.actions().contains_exactly([ targets.c_compile.label, targets.cpp_compile.label, ]) simple.env().contains_exactly({"BAR": "bar"}) simple.files().contains_exactly(_SIMPLE_FILES) c_compile = env.expect.that_target(targets.simple).provider(ArgsListInfo).by_action().get( targets.c_compile[ActionTypeInfo], ) c_compile.args().contains_exactly([targets.simple[ArgsInfo]]) c_compile.files().contains_exactly(_SIMPLE_FILES) converted = env.expect.that_value( convert_args(targets.simple[ArgsInfo]), factory = _CONVERTED_ARGS, ) converted.env_sets().contains_exactly([env_set( actions = ["c_compile", "cpp_compile"], env_entries = [env_entry(key = "BAR", value = "bar")], )]) converted.flag_sets().contains_exactly([flag_set( actions = ["c_compile", "cpp_compile"], flag_groups = [flag_group(flags = ["--foo", "foo"])], )]) def _env_only_test(env, targets): env_only = env.expect.that_target(targets.env_only).provider(ArgsInfo) env_only.actions().contains_exactly([ targets.c_compile.label, targets.cpp_compile.label, ]) env_only.env().contains_exactly({"BAR": "bar"}) env_only.files().contains_exactly(_SIMPLE_FILES) c_compile = env.expect.that_target(targets.simple).provider(ArgsListInfo).by_action().get( targets.c_compile[ActionTypeInfo], ) c_compile.files().contains_exactly(_SIMPLE_FILES) converted = env.expect.that_value( convert_args(targets.env_only[ArgsInfo]), factory = _CONVERTED_ARGS, ) converted.env_sets().contains_exactly([env_set( actions = ["c_compile", "cpp_compile"], env_entries = [env_entry(key = "BAR", value = "bar")], )]) converted.flag_sets().contains_exactly([]) def _with_dir_test(env, targets): with_dir = env.expect.that_target(targets.with_dir).provider(ArgsInfo) with_dir.allowlist_include_directories().contains_exactly([_TOOL_DIRECTORY]) with_dir.files().contains_at_least(_SIMPLE_FILES) c_compile = env.expect.that_target(targets.with_dir).provider(ArgsListInfo).by_action().get( targets.c_compile[ActionTypeInfo], ) c_compile.files().contains_at_least(_SIMPLE_FILES) TARGETS = [ ":simple", ":env_only", ":with_dir", "//tests/rule_based_toolchain/actions:c_compile", "//tests/rule_based_toolchain/actions:cpp_compile", ] # @unsorted-dict-items TESTS = { "simple_test": _simple_test, "env_only_test": _env_only_test, "with_dir_test": _with_dir_test, } rules_cc-0.0.11/tests/rule_based_toolchain/args_list/000077500000000000000000000000001470072561500226755ustar00rootroot00000000000000rules_cc-0.0.11/tests/rule_based_toolchain/args_list/BUILD000066400000000000000000000043661470072561500234700ustar00rootroot00000000000000load("@rules_testing//lib:util.bzl", "util") load("//cc/toolchains:args.bzl", "cc_args") load("//cc/toolchains:args_list.bzl", "cc_args_list") load("//tests/rule_based_toolchain:analysis_test_suite.bzl", "analysis_test_suite") load(":args_list_test.bzl", "TARGETS", "TESTS") util.helper_target( cc_args, name = "c_compile_args", actions = ["//tests/rule_based_toolchain/actions:c_compile"], args = ["c"], data = ["//tests/rule_based_toolchain/testdata:file1"], visibility = ["//tests/rule_based_toolchain:__subpackages__"], ) util.helper_target( cc_args, name = "cpp_compile_args", actions = ["//tests/rule_based_toolchain/actions:cpp_compile"], args = ["cpp"], data = ["//tests/rule_based_toolchain/testdata:file2"], visibility = ["//tests/rule_based_toolchain:__subpackages__"], ) util.helper_target( cc_args, name = "all_compile_args", actions = ["//tests/rule_based_toolchain/actions:all_compile"], args = ["all"], data = ["//tests/rule_based_toolchain/testdata:multiple1"], visibility = ["//tests/rule_based_toolchain:__subpackages__"], ) util.helper_target( cc_args_list, name = "args_list", args = [ ":c_compile_args", ":cpp_compile_args", ":all_compile_args", ], visibility = ["//tests/rule_based_toolchain:__subpackages__"], ) util.helper_target( cc_args, name = "args_with_dir_1", actions = ["//tests/rule_based_toolchain/actions:c_compile"], allowlist_include_directories = ["//tests/rule_based_toolchain/testdata:subdirectory_1"], args = ["dir1"], visibility = ["//tests/rule_based_toolchain:__subpackages__"], ) util.helper_target( cc_args, name = "args_with_dir_2", actions = ["//tests/rule_based_toolchain/actions:cpp_compile"], allowlist_include_directories = ["//tests/rule_based_toolchain/testdata:subdirectory_2"], args = ["dir2"], visibility = ["//tests/rule_based_toolchain:__subpackages__"], ) util.helper_target( cc_args_list, name = "args_list_with_dir", args = [ ":args_with_dir_1", ":args_with_dir_2", ], visibility = ["//tests/rule_based_toolchain:__subpackages__"], ) analysis_test_suite( name = "test_suite", targets = TARGETS, tests = TESTS, ) rules_cc-0.0.11/tests/rule_based_toolchain/args_list/args_list_test.bzl000066400000000000000000000066451470072561500264470ustar00rootroot00000000000000# Copyright 2024 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. """Tests for the cc_args rule.""" load( "//cc/toolchains:cc_toolchain_info.bzl", "ActionTypeInfo", "ArgsInfo", "ArgsListInfo", ) visibility("private") _C_COMPILE_FILE = "tests/rule_based_toolchain/testdata/file1" _CPP_COMPILE_FILE = "tests/rule_based_toolchain/testdata/file2" _BOTH_FILE = "tests/rule_based_toolchain/testdata/multiple1" _TEST_DIR_1 = "tests/rule_based_toolchain/testdata/subdir1" _TEST_DIR_2 = "tests/rule_based_toolchain/testdata/subdir2" _ALL_TEST_DIRS = [ _TEST_DIR_1, _TEST_DIR_2, ] _TEST_DIR_1_FILES = [ "tests/rule_based_toolchain/testdata/subdir1/file_foo", ] _TEST_DIR_2_FILES = [ "tests/rule_based_toolchain/testdata/subdir2/file_bar", ] _ALL_TEST_DIRS_FILES = _TEST_DIR_1_FILES + _TEST_DIR_2_FILES def _collect_args_lists_test(env, targets): args = env.expect.that_target(targets.args_list).provider(ArgsListInfo) args.args().contains_exactly([ targets.c_compile_args.label, targets.cpp_compile_args.label, targets.all_compile_args.label, ]) args.files().contains_exactly([ _C_COMPILE_FILE, _CPP_COMPILE_FILE, _BOTH_FILE, ]) c_compile_action = args.by_action().get(targets.c_compile[ActionTypeInfo]) cpp_compile_action = args.by_action().get(targets.cpp_compile[ActionTypeInfo]) c_compile_action.files().contains_exactly([_C_COMPILE_FILE, _BOTH_FILE]) c_compile_action.args().contains_exactly([ targets.c_compile_args[ArgsInfo], targets.all_compile_args[ArgsInfo], ]) cpp_compile_action.files().contains_exactly([_CPP_COMPILE_FILE, _BOTH_FILE]) cpp_compile_action.args().contains_exactly([ targets.cpp_compile_args[ArgsInfo], targets.all_compile_args[ArgsInfo], ]) def _collect_args_list_dirs_test(env, targets): args = env.expect.that_target(targets.args_list_with_dir).provider(ArgsListInfo) args.allowlist_include_directories().contains_exactly(_ALL_TEST_DIRS) args.files().contains_exactly(_ALL_TEST_DIRS_FILES) c_compile = env.expect.that_target(targets.args_list_with_dir).provider(ArgsListInfo).by_action().get( targets.c_compile[ActionTypeInfo], ) c_compile.files().contains_exactly(_TEST_DIR_1_FILES) cpp_compile = env.expect.that_target(targets.args_list_with_dir).provider(ArgsListInfo).by_action().get( targets.cpp_compile[ActionTypeInfo], ) cpp_compile.files().contains_exactly(_TEST_DIR_2_FILES) TARGETS = [ ":c_compile_args", ":cpp_compile_args", ":all_compile_args", ":args_list", ":args_with_dir_1", ":args_with_dir_2", ":args_list_with_dir", "//tests/rule_based_toolchain/actions:c_compile", "//tests/rule_based_toolchain/actions:cpp_compile", ] TESTS = { "collect_args_list_dirs_test": _collect_args_list_dirs_test, "collect_args_lists_test": _collect_args_lists_test, } rules_cc-0.0.11/tests/rule_based_toolchain/features/000077500000000000000000000000001470072561500225245ustar00rootroot00000000000000rules_cc-0.0.11/tests/rule_based_toolchain/features/BUILD000066400000000000000000000060141470072561500233070ustar00rootroot00000000000000load("@rules_testing//lib:util.bzl", "util") load("//cc/toolchains:args.bzl", "cc_args") load("//cc/toolchains:feature.bzl", "cc_feature") load("//cc/toolchains:feature_constraint.bzl", "cc_feature_constraint") load("//cc/toolchains:feature_set.bzl", "cc_feature_set") load("//cc/toolchains:mutually_exclusive_category.bzl", "cc_mutually_exclusive_category") load("//cc/toolchains/impl:external_feature.bzl", "cc_external_feature") load("//tests/rule_based_toolchain:analysis_test_suite.bzl", "analysis_test_suite") load(":features_test.bzl", "TARGETS", "TESTS") util.helper_target( cc_args, name = "c_compile_args", actions = ["//tests/rule_based_toolchain/actions:c_compile"], args = ["c"], data = ["//tests/rule_based_toolchain/testdata:file1"], ) util.helper_target( cc_feature, name = "simple", args = [":c_compile_args"], feature_name = "feature_name", visibility = ["//tests/rule_based_toolchain:__subpackages__"], ) util.helper_target( cc_feature, name = "simple2", args = [":c_compile_args"], feature_name = "simple2", ) util.helper_target( cc_feature_set, name = "feature_set", all_of = [ ":simple", ":simple2", ], ) util.helper_target( cc_feature, name = "requires", args = [":c_compile_args"], feature_name = "requires", requires_any_of = [":feature_set"], ) util.helper_target( cc_feature, name = "implies", args = [":c_compile_args"], feature_name = "implies", implies = [":simple"], ) cc_mutually_exclusive_category( name = "category", ) util.helper_target( cc_feature, name = "mutual_exclusion_feature", args = [":c_compile_args"], feature_name = "mutual_exclusion", mutually_exclusive = [ ":simple", ":category", ], ) util.helper_target( cc_feature_constraint, name = "direct_constraint", all_of = [":simple"], none_of = [":simple2"], visibility = ["//tests/rule_based_toolchain:__subpackages__"], ) util.helper_target( cc_feature_constraint, name = "transitive_constraint", all_of = [ ":direct_constraint", ":requires", ], none_of = [":implies"], ) util.helper_target( cc_external_feature, name = "builtin_feature", feature_name = "builtin_feature", overridable = True, ) util.helper_target( cc_feature, name = "overrides", args = [":c_compile_args"], overrides = ":builtin_feature", ) util.helper_target( cc_feature, name = "sentinel_feature", feature_name = "sentinel_feature_name", ) util.helper_target( cc_args, name = "args_with_dir", actions = ["//tests/rule_based_toolchain/actions:c_compile"], allowlist_include_directories = ["//tests/rule_based_toolchain/testdata:subdirectory_1"], args = ["--include-builtin-dirs"], ) util.helper_target( cc_feature, name = "feature_with_dir", args = [":args_with_dir"], feature_name = "feature_with_dir", ) analysis_test_suite( name = "test_suite", targets = TARGETS, tests = TESTS, ) rules_cc-0.0.11/tests/rule_based_toolchain/features/features_test.bzl000066400000000000000000000161411470072561500261150ustar00rootroot00000000000000# Copyright 2024 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. """Tests for features for the rule based toolchain.""" load( "//cc:cc_toolchain_config_lib.bzl", legacy_feature_set = "feature_set", legacy_flag_group = "flag_group", legacy_flag_set = "flag_set", ) load( "//cc/toolchains:cc_toolchain_info.bzl", "ActionTypeInfo", "ArgsInfo", "FeatureConstraintInfo", "FeatureInfo", "FeatureSetInfo", "MutuallyExclusiveCategoryInfo", ) load( "//cc/toolchains/impl:legacy_converter.bzl", "convert_feature", "convert_feature_constraint", ) visibility("private") _C_COMPILE_FILE = "tests/rule_based_toolchain/testdata/file1" _SUBDIR1 = "tests/rule_based_toolchain/testdata/subdir1" _SUBDIR1_FILES = ["tests/rule_based_toolchain/testdata/subdir1/file_foo"] def _sentinel_feature_test(env, targets): sentinel_feature = env.expect.that_target(targets.sentinel_feature).provider(FeatureInfo) sentinel_feature.name().equals("sentinel_feature_name") sentinel_feature.args().args().contains_exactly([]) def _simple_feature_test(env, targets): simple = env.expect.that_target(targets.simple).provider(FeatureInfo) simple.name().equals("feature_name") simple.args().args().contains_exactly([targets.c_compile_args.label]) simple.enabled().equals(False) simple.overrides().is_none() simple.overridable().equals(False) simple.args().files().contains_exactly([_C_COMPILE_FILE]) c_compile_action = simple.args().by_action().get( targets.c_compile_args[ArgsInfo].actions.to_list()[0], ) c_compile_action.files().contains_exactly([_C_COMPILE_FILE]) c_compile_action.args().contains_exactly([targets.c_compile_args[ArgsInfo]]) legacy = convert_feature(simple.actual) env.expect.that_str(legacy.name).equals("feature_name") env.expect.that_bool(legacy.enabled).equals(False) env.expect.that_collection(legacy.flag_sets).contains_exactly([ legacy_flag_set( actions = ["c_compile"], with_features = [], flag_groups = [legacy_flag_group(flags = ["c"])], ), ]) def _feature_collects_requirements_test(env, targets): ft = env.expect.that_target(targets.requires).provider(FeatureInfo) ft.requires_any_of().contains_exactly([ targets.feature_set.label, ]) legacy = convert_feature(ft.actual) env.expect.that_collection(legacy.requires).contains_exactly([ legacy_feature_set(features = ["feature_name", "simple2"]), ]) def _feature_collects_implies_test(env, targets): env.expect.that_target(targets.implies).provider( FeatureInfo, ).implies().contains_exactly([ targets.simple.label, ]) def _feature_collects_mutual_exclusion_test(env, targets): env.expect.that_target(targets.simple).provider( MutuallyExclusiveCategoryInfo, ).name().equals("feature_name") env.expect.that_target(targets.mutual_exclusion_feature).provider( FeatureInfo, ).mutually_exclusive().contains_exactly([ targets.simple.label, targets.category.label, ]) def _feature_set_collects_features_test(env, targets): env.expect.that_target(targets.feature_set).provider( FeatureSetInfo, ).features().contains_exactly([ targets.simple.label, targets.simple2.label, ]) def _feature_constraint_collects_direct_features_test(env, targets): constraint = env.expect.that_target(targets.direct_constraint).provider( FeatureConstraintInfo, ) constraint.all_of().contains_exactly([targets.simple.label]) constraint.none_of().contains_exactly([targets.simple2.label]) def _feature_constraint_collects_transitive_features_test(env, targets): constraint = env.expect.that_target(targets.transitive_constraint).provider( FeatureConstraintInfo, ) constraint.all_of().contains_exactly([ targets.simple.label, targets.requires.label, ]) constraint.none_of().contains_exactly([ targets.simple2.label, targets.implies.label, ]) legacy = convert_feature_constraint(constraint.actual) env.expect.that_collection(legacy.features).contains_exactly([ "feature_name", "requires", ]) env.expect.that_collection(legacy.not_features).contains_exactly([ "simple2", "implies", ]) def _external_feature_is_a_feature_test(env, targets): external_feature = env.expect.that_target(targets.builtin_feature).provider( FeatureInfo, ) external_feature.name().equals("builtin_feature") # It's not a string, but we don't have a factory for the type. env.expect.that_str(convert_feature(external_feature.actual)).equals(None) def _feature_can_be_overridden_test(env, targets): overrides = env.expect.that_target(targets.overrides).provider(FeatureInfo) overrides.name().equals("builtin_feature") overrides.overrides().some().label().equals(targets.builtin_feature.label) def _feature_with_directory_test(env, targets): with_dir = env.expect.that_target(targets.feature_with_dir).provider(FeatureInfo) with_dir.allowlist_include_directories().contains_exactly([_SUBDIR1]) c_compile = env.expect.that_target(targets.feature_with_dir).provider(FeatureInfo).args().by_action().get( targets.c_compile[ActionTypeInfo], ) c_compile.files().contains_at_least(_SUBDIR1_FILES) TARGETS = [ ":args_with_dir", ":builtin_feature", ":c_compile_args", ":category", ":direct_constraint", ":feature_set", ":feature_with_dir", ":implies", ":mutual_exclusion_feature", ":overrides", ":requires", ":sentinel_feature", ":simple", ":simple2", ":transitive_constraint", "//tests/rule_based_toolchain/actions:c_compile", ] # @unsorted-dict-items TESTS = { "sentinel_feature_test": _sentinel_feature_test, "simple_feature_test": _simple_feature_test, "feature_collects_requirements_test": _feature_collects_requirements_test, "feature_collects_implies_test": _feature_collects_implies_test, "feature_collects_mutual_exclusion_test": _feature_collects_mutual_exclusion_test, "feature_set_collects_features_test": _feature_set_collects_features_test, "feature_constraint_collects_direct_features_test": _feature_constraint_collects_direct_features_test, "feature_constraint_collects_transitive_features_test": _feature_constraint_collects_transitive_features_test, "external_feature_is_a_feature_test": _external_feature_is_a_feature_test, "feature_can_be_overridden_test": _feature_can_be_overridden_test, "feature_with_directory_test": _feature_with_directory_test, } rules_cc-0.0.11/tests/rule_based_toolchain/generate_factory.bzl000066400000000000000000000111621470072561500247410ustar00rootroot00000000000000# Copyright 2024 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. """Generates provider factories.""" load("@bazel_skylib//lib:structs.bzl", "structs") load("@rules_testing//lib:truth.bzl", "subjects") visibility("private") def generate_factory(type, name, attrs): """Generates a factory for a custom struct. There are three reasons we need to do so: 1. It's very difficult to read providers printed by these types. eg. If you have a 10 layer deep diamond dependency graph, and try to print the top value, the bottom value will be printed 2^10 times. 2. Collections of subjects are not well supported by rules_testing eg. `FeatureInfo(flag_sets = [FlagSetInfo(...)])` (You can do it, but the inner values are just regular bazel structs and you can't do fluent assertions on them). 3. Recursive types are not supported at all eg. `FeatureInfo(implies = depset([FeatureInfo(...)]))` To solve this, we create a factory that: * Validates that the types of the children are correct. * Inlines providers to their labels when unambiguous. For example, given: ``` foo = FeatureInfo(name = "foo", label = Label("//:foo")) bar = FeatureInfo(..., implies = depset([foo])) ``` It would convert itself a subject for the following struct: `FeatureInfo(..., implies = depset([Label("//:foo")]))` Args: type: (type) The type to create a factory for (eg. FooInfo) name: (str) The name of the type (eg. "FooInfo") attrs: (dict[str, Factory]) The attributes associated with this type. Returns: A struct `FooFactory` suitable for use with * `analysis_test(provider_subject_factories=[FooFactory])` * `generate_factory(..., attrs=dict(foo = FooFactory))` * `ProviderSequence(FooFactory)` * `DepsetSequence(FooFactory)` """ attrs["label"] = subjects.label want_keys = sorted(attrs.keys()) def validate(*, value, meta): if value == None: meta.add_failure("Wanted a %s but got" % name, value) got_keys = sorted(structs.to_dict(value).keys()) subjects.collection(got_keys, meta = meta.derive(details = [ "Value %r was not a %s - it has a different set of fields" % (value, name), ])).contains_exactly(want_keys).in_order() def type_factory(value, *, meta): validate(value = value, meta = meta) transformed_value = {} transformed_factories = {} for field, factory in attrs.items(): field_value = getattr(value, field) # If it's a type generated by generate_factory, inline it. if hasattr(factory, "factory"): factory.validate(value = field_value, meta = meta.derive(field)) transformed_value[field] = field_value.label transformed_factories[field] = subjects.label else: transformed_value[field] = field_value transformed_factories[field] = factory return subjects.struct( struct(**transformed_value), meta = meta, attrs = transformed_factories, ) return struct( type = type, name = name, factory = type_factory, validate = validate, ) def _provider_collection(element_factory, fn): def factory(value, *, meta): value = fn(value) # Validate that it really is the correct type for i in range(len(value)): element_factory.validate( value = value[i], meta = meta.derive("offset({})".format(i)), ) # Inline the providers to just labels. return subjects.collection([v.label for v in value], meta = meta) return factory # This acts like a class, so we name it like one. # buildifier: disable=name-conventions ProviderSequence = lambda element_factory: _provider_collection( element_factory, fn = lambda x: list(x), ) # buildifier: disable=name-conventions ProviderDepset = lambda element_factory: _provider_collection( element_factory, fn = lambda x: x.to_list(), ) rules_cc-0.0.11/tests/rule_based_toolchain/generics.bzl000066400000000000000000000107171470072561500232240ustar00rootroot00000000000000# Copyright 2024 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. """Implementation of a result type for use with rules_testing.""" load("@bazel_skylib//lib:structs.bzl", "structs") load("@rules_testing//lib:truth.bzl", "subjects") visibility("//tests/rule_based_toolchain/...") def result_fn_wrapper(fn): """Wraps a function that may fail in a type similar to rust's Result type. An example usage is the following: # Implementation file def get_only(value, fail=fail): if len(value) == 1: return value[0] elif not value: fail("Unexpectedly empty") else: fail("%r had length %d, expected 1" % (value, len(value)) # Test file load("...", _fn=fn) fn = result_fn_wrapper(_fn) int_result = result_subject(subjects.int) def my_test(env, _): env.expect.that_value(fn([]), factory=int_result) .err().equals("Unexpectedly empty") env.expect.that_value(fn([1]), factory=int_result) .ok().equals(1) env.expect.that_value(fn([1, 2]), factory=int_result) .err().contains("had length 2, expected 1") Args: fn: A function that takes in a parameter fail and calls it on failure. Returns: On success: struct(ok = , err = None) On failure: struct(ok = None, err = """ def new_fn(*args, **kwargs): # Use a mutable type so that the fail_wrapper can modify this. failures = [] def fail_wrapper(msg): failures.append(msg) result = fn(fail = fail_wrapper, *args, **kwargs) if failures: return struct(ok = None, err = failures[0]) else: return struct(ok = result, err = None) return new_fn def result_subject(factory): """A subject factory for Result. Args: factory: A subject factory for T Returns: A subject factory for Result """ def new_factory(value, *, meta): def ok(): if value.err != None: meta.add_failure("Wanted a value, but got an error", value.err) return factory(value.ok, meta = meta.derive("ok()")) def err(): if value.err == None: meta.add_failure("Wanted an error, but got a value", value.ok) subject = subjects.str(value.err, meta = meta.derive("err()")) def contains_all_of(values): for value in values: subject.contains(str(value)) return struct(contains_all_of = contains_all_of, **structs.to_dict(subject)) return struct(ok = ok, err = err) return new_factory def optional_subject(factory): """A subject factory for Optional. Args: factory: A subject factory for T Returns: A subject factory for Optional """ def new_factory(value, *, meta): def some(): if value == None: meta.add_failure("Wanted a value, but got None", None) return factory(value, meta = meta) def is_none(): if value != None: meta.add_failure("Wanted None, but got a value", value) return struct(some = some, is_none = is_none) return new_factory # Curry subjects.struct so the type is actually generic. struct_subject = lambda **attrs: lambda value, *, meta: subjects.struct( value, meta = meta, attrs = attrs, ) # We can't do complex assertions on containers. This allows you to write # assert.that_value({"foo": 1), factory=dict_key_subject(subjects.int)) # .get("foo").equals(1) dict_key_subject = lambda factory: lambda value, *, meta: struct( get = lambda key: factory( value[key], meta = meta.derive("get({})".format(key)), ), keys = lambda: subjects.collection(value.keys(), meta = meta.derive("keys()")), contains = lambda key: subjects.bool(key in value, meta = meta.derive("contains({})".format(key))), ) rules_cc-0.0.11/tests/rule_based_toolchain/legacy_features_as_args/000077500000000000000000000000001470072561500255475ustar00rootroot00000000000000rules_cc-0.0.11/tests/rule_based_toolchain/legacy_features_as_args/BUILD000066400000000000000000000055141470072561500263360ustar00rootroot00000000000000load(":compare_feature.bzl", "compare_feature_implementation") # These tests validate that the produced legacy feature implementations # properly reflect the implementations housed in the Java source of truth at # https://github.com/bazelbuild/bazel/blob/master/src/main/java/com/google/devtools/build/lib/rules/cpp/CppActionConfigs.java. # # Note: the golden textprotos are not a 1:1 match of the textprotos inlined in # the Java files. These aim to have identical behavior, but with allowance # for slight differences in structure due to implementation details. This also # makes it easier to review the final results. compare_feature_implementation( name = "archiver_flags_test", actual_implementation = "//cc/toolchains/args/archiver_flags", expected = select({ "@platforms//os:macos": "//tests/rule_based_toolchain/legacy_features_as_args:goldens/macos/archiver_flags.textproto", "//conditions:default": "//tests/rule_based_toolchain/legacy_features_as_args:goldens/unix/archiver_flags.textproto", }), ) compare_feature_implementation( name = "force_pic_flags_test", actual_implementation = "//cc/toolchains/args/force_pic_flags", expected = select({ "@platforms//os:macos": "//tests/rule_based_toolchain/legacy_features_as_args:goldens/macos/force_pic_flags.textproto", "//conditions:default": "//tests/rule_based_toolchain/legacy_features_as_args:goldens/unix/force_pic_flags.textproto", }), ) compare_feature_implementation( name = "libraries_to_link_test", actual_implementation = "//cc/toolchains/args/libraries_to_link", expected = select({ "@platforms//os:macos": "//tests/rule_based_toolchain/legacy_features_as_args:goldens/macos/libraries_to_link.textproto", "//conditions:default": "//tests/rule_based_toolchain/legacy_features_as_args:goldens/unix/libraries_to_link.textproto", }), ) compare_feature_implementation( name = "linker_param_file_test", actual_implementation = "//cc/toolchains/args/linker_param_file", expected = "//tests/rule_based_toolchain/legacy_features_as_args:goldens/unix/linker_param_file.textproto", ) compare_feature_implementation( name = "runtime_library_search_directories_test", actual_implementation = "//cc/toolchains/args/runtime_library_search_directories", expected = select({ "@platforms//os:macos": "//tests/rule_based_toolchain/legacy_features_as_args:goldens/macos/runtime_library_search_directories.textproto", "//conditions:default": "//tests/rule_based_toolchain/legacy_features_as_args:goldens/unix/runtime_library_search_directories.textproto", }), ) compare_feature_implementation( name = "shared_flag_test", actual_implementation = "//cc/toolchains/args/shared_flag", expected = "//tests/rule_based_toolchain/legacy_features_as_args:goldens/unix/shared_flag.textproto", ) rules_cc-0.0.11/tests/rule_based_toolchain/legacy_features_as_args/compare_feature.bzl000066400000000000000000000045261470072561500314300ustar00rootroot00000000000000# Copyright 2024 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. """Test helper for cc_arg_list validation.""" load("@bazel_skylib//rules:diff_test.bzl", "diff_test") load("//cc:cc_toolchain_config_lib.bzl", "feature") load("//cc/toolchains:cc_toolchain_info.bzl", "ArgsListInfo") load("//cc/toolchains/impl:legacy_converter.bzl", "convert_args") def _generate_textproto_for_args_impl(ctx): out = ctx.actions.declare_file(ctx.attr.output.name) converted_args = [convert_args(arg) for arg in ctx.attr.actual_implementation[ArgsListInfo].args] feature_impl = feature( name = ctx.attr.feature_name, flag_sets = [fs for one_arg in converted_args for fs in one_arg.flag_sets], env_sets = [es for one_arg in converted_args for es in one_arg.env_sets], ) strip_types = [line for line in proto.encode_text(feature_impl).splitlines() if "type_name:" not in line] # Ensure trailing newline. strip_types.append("") ctx.actions.write(out, "\n".join(strip_types)) return DefaultInfo(files = depset([out])) _generate_textproto_for_args = rule( implementation = _generate_textproto_for_args_impl, attrs = { "actual_implementation": attr.label( mandatory = True, providers = [ArgsListInfo], ), "feature_name": attr.string(mandatory = True), "output": attr.output(mandatory = True), }, ) def compare_feature_implementation(name, actual_implementation, expected): output_filename = name + ".actual.textproto" _generate_textproto_for_args( name = name + "_implementation", actual_implementation = actual_implementation, feature_name = name, output = output_filename, testonly = True, ) diff_test( name = name, file1 = expected, file2 = output_filename, ) rules_cc-0.0.11/tests/rule_based_toolchain/legacy_features_as_args/goldens/000077500000000000000000000000001470072561500272025ustar00rootroot00000000000000rules_cc-0.0.11/tests/rule_based_toolchain/legacy_features_as_args/goldens/macos/000077500000000000000000000000001470072561500303045ustar00rootroot00000000000000archiver_flags.textproto000066400000000000000000000016101470072561500351740ustar00rootroot00000000000000rules_cc-0.0.11/tests/rule_based_toolchain/legacy_features_as_args/goldens/macosenabled: false flag_sets { actions: "c++-link-static-library" flag_groups { flags: "-static" } } flag_sets { actions: "c++-link-static-library" flag_groups { expand_if_available: "output_execpath" flags: "-o" flags: "%{output_execpath}" } } flag_sets { actions: "c++-link-static-library" flag_groups { expand_if_available: "libraries_to_link" flag_groups { flag_groups { expand_if_equal { name: "libraries_to_link.type" value: "object_file" } flags: "%{libraries_to_link.name}" } flag_groups { expand_if_equal { name: "libraries_to_link.type" value: "object_file_group" } flags: "%{libraries_to_link.object_files}" iterate_over: "libraries_to_link.object_files" } iterate_over: "libraries_to_link" } } } name: "archiver_flags_test" force_pic_flags.textproto000066400000000000000000000003201470072561500353170ustar00rootroot00000000000000rules_cc-0.0.11/tests/rule_based_toolchain/legacy_features_as_args/goldens/macosenabled: false flag_sets { actions: "c++-link-executable" actions: "lto-index-for-executable" flag_groups { expand_if_available: "force_pic" flags: "-Wl,-pie" } } name: "force_pic_flags_test" libraries_to_link.textproto000066400000000000000000000074761470072561500357300ustar00rootroot00000000000000rules_cc-0.0.11/tests/rule_based_toolchain/legacy_features_as_args/goldens/macosenabled: false flag_sets { actions: "c++-link-dynamic-library" actions: "c++-link-executable" actions: "c++-link-nodeps-dynamic-library" actions: "lto-index-for-dynamic-library" actions: "lto-index-for-executable" actions: "lto-index-for-nodeps-dynamic-library" flag_groups { flag_groups { expand_if_available: "thinlto_param_file" flags: "-Wl,@%{thinlto_param_file}" } flag_groups { expand_if_available: "libraries_to_link" flag_groups { flag_groups { expand_if_equal { name: "libraries_to_link.type" value: "object_file_group" } flag_groups { expand_if_false: "libraries_to_link.is_whole_archive" flags: "-Wl,--start-lib" } } flag_groups { flag_groups { expand_if_equal { name: "libraries_to_link.type" value: "object_file_group" } flag_groups { flag_groups { expand_if_true: "libraries_to_link.is_whole_archive" flags: "-Wl,-force_load,%{libraries_to_link.object_files}" } flag_groups { expand_if_false: "libraries_to_link.is_whole_archive" flags: "%{libraries_to_link.object_files}" } } iterate_over: "libraries_to_link.object_files" } flag_groups { expand_if_equal { name: "libraries_to_link.type" value: "object_file" } flag_groups { flag_groups { expand_if_true: "libraries_to_link.is_whole_archive" flags: "-Wl,-force_load,%{libraries_to_link.name}" } flag_groups { expand_if_false: "libraries_to_link.is_whole_archive" flags: "%{libraries_to_link.name}" } } } flag_groups { expand_if_equal { name: "libraries_to_link.type" value: "interface_library" } flag_groups { flag_groups { expand_if_true: "libraries_to_link.is_whole_archive" flags: "-Wl,-force_load,%{libraries_to_link.name}" } flag_groups { expand_if_false: "libraries_to_link.is_whole_archive" flags: "%{libraries_to_link.name}" } } } flag_groups { expand_if_equal { name: "libraries_to_link.type" value: "static_library" } flag_groups { flag_groups { expand_if_true: "libraries_to_link.is_whole_archive" flags: "-Wl,-force_load,%{libraries_to_link.name}" } flag_groups { expand_if_false: "libraries_to_link.is_whole_archive" flags: "%{libraries_to_link.name}" } } } flag_groups { expand_if_equal { name: "libraries_to_link.type" value: "dynamic_library" } flags: "-l%{libraries_to_link.name}" } flag_groups { expand_if_equal { name: "libraries_to_link.type" value: "versioned_dynamic_library" } flags: "%{libraries_to_link.path}" } } flag_groups { expand_if_equal { name: "libraries_to_link.type" value: "object_file_group" } flag_groups { expand_if_false: "libraries_to_link.is_whole_archive" flags: "-Wl,--end-lib" } } iterate_over: "libraries_to_link" } } } } name: "libraries_to_link_test" runtime_library_search_directories.textproto000066400000000000000000000030741470072561500413530ustar00rootroot00000000000000rules_cc-0.0.11/tests/rule_based_toolchain/legacy_features_as_args/goldens/macosenabled: false flag_sets { actions: "c++-link-dynamic-library" actions: "c++-link-executable" actions: "c++-link-nodeps-dynamic-library" actions: "lto-index-for-dynamic-library" actions: "lto-index-for-executable" actions: "lto-index-for-nodeps-dynamic-library" flag_groups { expand_if_available: "runtime_library_search_directories" flag_groups { flag_groups { expand_if_true: "is_cc_test" flags: "-Xlinker" flags: "-rpath" flags: "-Xlinker" flags: "$EXEC_ORIGIN/%{runtime_library_search_directories}" } flag_groups { expand_if_false: "is_cc_test" flags: "-Xlinker" flags: "-rpath" flags: "-Xlinker" flags: "@loader_path/%{runtime_library_search_directories}" } iterate_over: "runtime_library_search_directories" } } with_features { features: "static_link_cpp_runtimes" } } flag_sets { actions: "c++-link-dynamic-library" actions: "c++-link-executable" actions: "c++-link-nodeps-dynamic-library" actions: "lto-index-for-dynamic-library" actions: "lto-index-for-executable" actions: "lto-index-for-nodeps-dynamic-library" flag_groups { expand_if_available: "runtime_library_search_directories" flag_groups { flags: "-Xlinker" flags: "-rpath" flags: "-Xlinker" flags: "@loader_path/%{runtime_library_search_directories}" iterate_over: "runtime_library_search_directories" } } with_features { not_features: "static_link_cpp_runtimes" } } name: "runtime_library_search_directories_test" rules_cc-0.0.11/tests/rule_based_toolchain/legacy_features_as_args/goldens/unix/000077500000000000000000000000001470072561500301655ustar00rootroot00000000000000archiver_flags.textproto000066400000000000000000000015651470072561500350660ustar00rootroot00000000000000rules_cc-0.0.11/tests/rule_based_toolchain/legacy_features_as_args/goldens/unixenabled: false flag_sets { actions: "c++-link-static-library" flag_groups { flags: "rcsD" } } flag_sets { actions: "c++-link-static-library" flag_groups { expand_if_available: "output_execpath" flags: "%{output_execpath}" } } flag_sets { actions: "c++-link-static-library" flag_groups { expand_if_available: "libraries_to_link" flag_groups { flag_groups { expand_if_equal { name: "libraries_to_link.type" value: "object_file" } flags: "%{libraries_to_link.name}" } flag_groups { expand_if_equal { name: "libraries_to_link.type" value: "object_file_group" } flags: "%{libraries_to_link.object_files}" iterate_over: "libraries_to_link.object_files" } iterate_over: "libraries_to_link" } } } name: "archiver_flags_test" force_pic_flags.textproto000066400000000000000000000003141470072561500352030ustar00rootroot00000000000000rules_cc-0.0.11/tests/rule_based_toolchain/legacy_features_as_args/goldens/unixenabled: false flag_sets { actions: "c++-link-executable" actions: "lto-index-for-executable" flag_groups { expand_if_available: "force_pic" flags: "-pie" } } name: "force_pic_flags_test" libraries_to_link.textproto000066400000000000000000000061601470072561500355760ustar00rootroot00000000000000rules_cc-0.0.11/tests/rule_based_toolchain/legacy_features_as_args/goldens/unixenabled: false flag_sets { actions: "c++-link-dynamic-library" actions: "c++-link-executable" actions: "c++-link-nodeps-dynamic-library" actions: "lto-index-for-dynamic-library" actions: "lto-index-for-executable" actions: "lto-index-for-nodeps-dynamic-library" flag_groups { flag_groups { expand_if_available: "thinlto_param_file" flags: "-Wl,@%{thinlto_param_file}" } flag_groups { expand_if_available: "libraries_to_link" flag_groups { flag_groups { expand_if_equal { name: "libraries_to_link.type" value: "object_file_group" } flag_groups { expand_if_false: "libraries_to_link.is_whole_archive" flags: "-Wl,--start-lib" } } flag_groups { flag_groups { expand_if_true: "libraries_to_link.is_whole_archive" flag_groups { expand_if_equal { name: "libraries_to_link.type" value: "static_library" } flags: "-Wl,-whole-archive" } } flag_groups { expand_if_equal { name: "libraries_to_link.type" value: "object_file_group" } flags: "%{libraries_to_link.object_files}" iterate_over: "libraries_to_link.object_files" } flag_groups { expand_if_equal { name: "libraries_to_link.type" value: "object_file" } flags: "%{libraries_to_link.name}" } flag_groups { expand_if_equal { name: "libraries_to_link.type" value: "interface_library" } flags: "%{libraries_to_link.name}" } flag_groups { expand_if_equal { name: "libraries_to_link.type" value: "static_library" } flags: "%{libraries_to_link.name}" } flag_groups { expand_if_equal { name: "libraries_to_link.type" value: "dynamic_library" } flags: "-l%{libraries_to_link.name}" } flag_groups { expand_if_equal { name: "libraries_to_link.type" value: "versioned_dynamic_library" } flags: "-l:%{libraries_to_link.name}" } flag_groups { expand_if_true: "libraries_to_link.is_whole_archive" flag_groups { expand_if_equal { name: "libraries_to_link.type" value: "static_library" } flags: "-Wl,-no-whole-archive" } } } flag_groups { expand_if_equal { name: "libraries_to_link.type" value: "object_file_group" } flag_groups { expand_if_false: "libraries_to_link.is_whole_archive" flags: "-Wl,--end-lib" } } iterate_over: "libraries_to_link" } } } } name: "libraries_to_link_test" linker_param_file.textproto000066400000000000000000000006741470072561500355520ustar00rootroot00000000000000rules_cc-0.0.11/tests/rule_based_toolchain/legacy_features_as_args/goldens/unixenabled: false flag_sets { actions: "c++-link-dynamic-library" actions: "c++-link-executable" actions: "c++-link-nodeps-dynamic-library" actions: "c++-link-static-library" actions: "lto-index-for-dynamic-library" actions: "lto-index-for-executable" actions: "lto-index-for-nodeps-dynamic-library" flag_groups { expand_if_available: "linker_param_file" flags: "@%{linker_param_file}" } } name: "linker_param_file_test" runtime_library_search_directories.textproto000066400000000000000000000030621470072561500412310ustar00rootroot00000000000000rules_cc-0.0.11/tests/rule_based_toolchain/legacy_features_as_args/goldens/unixenabled: false flag_sets { actions: "c++-link-dynamic-library" actions: "c++-link-executable" actions: "c++-link-nodeps-dynamic-library" actions: "lto-index-for-dynamic-library" actions: "lto-index-for-executable" actions: "lto-index-for-nodeps-dynamic-library" flag_groups { expand_if_available: "runtime_library_search_directories" flag_groups { flag_groups { expand_if_true: "is_cc_test" flags: "-Xlinker" flags: "-rpath" flags: "-Xlinker" flags: "$EXEC_ORIGIN/%{runtime_library_search_directories}" } flag_groups { expand_if_false: "is_cc_test" flags: "-Xlinker" flags: "-rpath" flags: "-Xlinker" flags: "$ORIGIN/%{runtime_library_search_directories}" } iterate_over: "runtime_library_search_directories" } } with_features { features: "static_link_cpp_runtimes" } } flag_sets { actions: "c++-link-dynamic-library" actions: "c++-link-executable" actions: "c++-link-nodeps-dynamic-library" actions: "lto-index-for-dynamic-library" actions: "lto-index-for-executable" actions: "lto-index-for-nodeps-dynamic-library" flag_groups { expand_if_available: "runtime_library_search_directories" flag_groups { flags: "-Xlinker" flags: "-rpath" flags: "-Xlinker" flags: "$ORIGIN/%{runtime_library_search_directories}" iterate_over: "runtime_library_search_directories" } } with_features { not_features: "static_link_cpp_runtimes" } } name: "runtime_library_search_directories_test" shared_flag.textproto000066400000000000000000000004171470072561500343410ustar00rootroot00000000000000rules_cc-0.0.11/tests/rule_based_toolchain/legacy_features_as_args/goldens/unixenabled: false flag_sets { actions: "c++-link-dynamic-library" actions: "c++-link-nodeps-dynamic-library" actions: "lto-index-for-dynamic-library" actions: "lto-index-for-nodeps-dynamic-library" flag_groups { flags: "-shared" } } name: "shared_flag_test" rules_cc-0.0.11/tests/rule_based_toolchain/nested_args/000077500000000000000000000000001470072561500232045ustar00rootroot00000000000000rules_cc-0.0.11/tests/rule_based_toolchain/nested_args/BUILD000066400000000000000000000006521470072561500237710ustar00rootroot00000000000000load("//cc/toolchains/impl:variables.bzl", "cc_variable", "types") load("//tests/rule_based_toolchain:analysis_test_suite.bzl", "analysis_test_suite") load(":nested_args_test.bzl", "TARGETS", "TESTS") cc_variable( name = "foo", type = types.string, ) cc_variable( name = "my_list", type = types.list(types.string), ) analysis_test_suite( name = "test_suite", targets = TARGETS, tests = TESTS, ) rules_cc-0.0.11/tests/rule_based_toolchain/nested_args/nested_args_test.bzl000066400000000000000000000141271470072561500272570ustar00rootroot00000000000000# Copyright 2024 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. """Tests for the cc_args rule.""" load("@bazel_skylib//rules/directory:providers.bzl", "DirectoryInfo") load("//cc:cc_toolchain_config_lib.bzl", "flag_group", "variable_with_value") load( "//cc/toolchains/impl:nested_args.bzl", "FORMAT_ARGS_ERR", "REQUIRES_EQUAL_ERR", "REQUIRES_MUTUALLY_EXCLUSIVE_ERR", "REQUIRES_NONE_ERR", "format_args", "nested_args_provider", ) load("//tests/rule_based_toolchain:subjects.bzl", "result_fn_wrapper", "subjects") visibility("private") def _expect_that_nested(env, expr = None, **kwargs): return env.expect.that_value( expr = expr, value = result_fn_wrapper(nested_args_provider)( label = Label("//:args"), **kwargs ), factory = subjects.result(subjects.NestedArgsInfo), ) def _expect_that_formatted(env, args, format, must_use = [], expr = None): return env.expect.that_value( result_fn_wrapper(format_args)(args, format, must_use = must_use), factory = subjects.result(subjects.collection), expr = expr or "format_args(%r, %r)" % (args, format), ) def _format_args_test(env, targets): _expect_that_formatted( env, [ "a % b", "a {{", "}} b", "a {{ b }}", ], {}, ).ok().contains_exactly([ "a %% b", "a {", "} b", "a { b }", ]).in_order() _expect_that_formatted( env, ["{foo"], {}, ).err().equals('Unmatched { in "{foo"') _expect_that_formatted( env, ["foo}"], {}, ).err().equals('Unexpected } in "foo}"') _expect_that_formatted( env, ["{foo}"], {}, ).err().contains('Unknown variable "foo" in format string "{foo}"') _expect_that_formatted( env, [ "a {var}", "b {directory}", "c {file}", ], { "directory": targets.directory, "file": targets.bin_wrapper, "var": targets.foo, }, ).ok().contains_exactly([ "a %{foo}", "b " + targets.directory[DirectoryInfo].path, "c " + targets.bin_wrapper[DefaultInfo].files.to_list()[0].path, ]).in_order() _expect_that_formatted( env, ["{var}", "{var}"], {"var": targets.foo}, ).ok().contains_exactly(["%{foo}", "%{foo}"]) _expect_that_formatted( env, [], {"var": targets.foo}, must_use = ["var"], ).err().contains('"var" was not used') _expect_that_formatted( env, ["{var} {var}"], {"var": targets.foo}, ).err().contains('"{var} {var}" contained multiple variables') _expect_that_formatted( env, ["{foo} {bar}"], {"bar": targets.foo, "foo": targets.foo}, ).err().contains('"{foo} {bar}" contained multiple variables') def _iterate_over_test(env, targets): inner = _expect_that_nested( env, args = ["--foo"], ).ok().actual env.expect.that_str(inner.legacy_flag_group).equals(flag_group(flags = ["--foo"])) nested = _expect_that_nested( env, nested = [inner], iterate_over = targets.my_list, ).ok() nested.iterate_over().some().equals("my_list") nested.legacy_flag_group().equals(flag_group( iterate_over = "my_list", flag_groups = [inner.legacy_flag_group], )) nested.requires_types().contains_exactly({}) def _requires_types_test(env, targets): _expect_that_nested( env, requires_not_none = "abc", requires_none = "def", args = ["--foo"], expr = "mutually_exclusive", ).err().equals(REQUIRES_MUTUALLY_EXCLUSIVE_ERR) _expect_that_nested( env, requires_none = "var", args = ["--foo"], expr = "requires_none", ).ok().requires_types().contains_exactly( {"var": [struct( msg = REQUIRES_NONE_ERR, valid_types = ["option"], after_option_unwrap = False, )]}, ) _expect_that_nested( env, args = ["foo {foo} baz"], format = {targets.foo: "foo"}, expr = "type_validation", ).ok().requires_types().contains_exactly( {"foo": [struct( msg = FORMAT_ARGS_ERR, valid_types = ["string", "file", "directory"], after_option_unwrap = True, )]}, ) nested = _expect_that_nested( env, requires_equal = "foo", requires_equal_value = "value", args = ["--foo={foo}"], format = {targets.foo: "foo"}, expr = "type_and_requires_equal_validation", ).ok() nested.requires_types().contains_exactly( {"foo": [ struct( msg = REQUIRES_EQUAL_ERR, valid_types = ["string"], after_option_unwrap = True, ), struct( msg = FORMAT_ARGS_ERR, valid_types = ["string", "file", "directory"], after_option_unwrap = True, ), ]}, ) nested.legacy_flag_group().equals(flag_group( expand_if_equal = variable_with_value(name = "foo", value = "value"), flags = ["--foo=%{foo}"], )) TARGETS = [ ":foo", ":my_list", "//tests/rule_based_toolchain/testdata:directory", "//tests/rule_based_toolchain/testdata:bin_wrapper", ] TESTS = { "format_args_test": _format_args_test, "iterate_over_test": _iterate_over_test, "requires_types_test": _requires_types_test, } rules_cc-0.0.11/tests/rule_based_toolchain/subjects.bzl000066400000000000000000000165041470072561500232470ustar00rootroot00000000000000# Copyright 2024 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. """Test subjects for cc_toolchain_info providers.""" load("@bazel_skylib//lib:structs.bzl", "structs") load("@rules_testing//lib:truth.bzl", _subjects = "subjects") load( "//cc/toolchains:cc_toolchain_info.bzl", "ActionTypeInfo", "ActionTypeSetInfo", "ArgsInfo", "ArgsListInfo", "FeatureConstraintInfo", "FeatureInfo", "FeatureSetInfo", "MutuallyExclusiveCategoryInfo", "NestedArgsInfo", "ToolCapabilityInfo", "ToolConfigInfo", "ToolInfo", "ToolchainConfigInfo", ) load(":generate_factory.bzl", "ProviderDepset", "ProviderSequence", "generate_factory") load(":generics.bzl", "dict_key_subject", "optional_subject", "result_subject", "struct_subject", _result_fn_wrapper = "result_fn_wrapper") visibility("//tests/rule_based_toolchain/...") # The default runfiles subject uses path instead of short_path. # This makes it rather awkward for copybara. runfiles_subject = lambda value, meta: _subjects.depset_file(value.files, meta = meta) # The string type has .equals(), which is all we can really do for an unknown # type. unknown_subject = _subjects.str # Directory depsets are quite complex, so just simplify them as a list of paths. # buildifier: disable=name-conventions _FakeDirectoryDepset = lambda value, *, meta: _subjects.collection([v.path for v in value.to_list()], meta = meta) # buildifier: disable=name-conventions _ActionTypeFactory = generate_factory( ActionTypeInfo, "ActionTypeInfo", dict( name = _subjects.str, ), ) # buildifier: disable=name-conventions _ActionTypeSetFactory = generate_factory( ActionTypeSetInfo, "ActionTypeInfo", dict( actions = ProviderDepset(_ActionTypeFactory), ), ) # buildifier: disable=name-conventions _MutuallyExclusiveCategoryFactory = generate_factory( MutuallyExclusiveCategoryInfo, "MutuallyExclusiveCategoryInfo", dict(name = _subjects.str), ) _FEATURE_FLAGS = dict( name = _subjects.str, enabled = _subjects.bool, args = None, implies = None, requires_any_of = None, mutually_exclusive = ProviderSequence(_MutuallyExclusiveCategoryFactory), overridable = _subjects.bool, external = _subjects.bool, overrides = None, allowlist_include_directories = _FakeDirectoryDepset, ) # Break the dependency loop. # buildifier: disable=name-conventions _FakeFeatureFactory = generate_factory( FeatureInfo, "FeatureInfo", _FEATURE_FLAGS, ) # buildifier: disable=name-conventions _FeatureSetFactory = generate_factory( FeatureSetInfo, "FeatureSetInfo", dict(features = ProviderDepset(_FakeFeatureFactory)), ) # buildifier: disable=name-conventions _FeatureConstraintFactory = generate_factory( FeatureConstraintInfo, "FeatureConstraintInfo", dict( all_of = ProviderDepset(_FakeFeatureFactory), none_of = ProviderDepset(_FakeFeatureFactory), ), ) _NESTED_ARGS_FLAGS = dict( nested = None, files = _subjects.depset_file, iterate_over = optional_subject(_subjects.str), legacy_flag_group = unknown_subject, requires_types = _subjects.dict, unwrap_options = _subjects.collection, ) # buildifier: disable=name-conventions _FakeNestedArgsFactory = generate_factory( NestedArgsInfo, "NestedArgsInfo", _NESTED_ARGS_FLAGS, ) # buildifier: disable=name-conventions _NestedArgsFactory = generate_factory( NestedArgsInfo, "NestedArgsInfo", _NESTED_ARGS_FLAGS | dict( nested = ProviderSequence(_FakeNestedArgsFactory), ), ) # buildifier: disable=name-conventions _ArgsFactory = generate_factory( ArgsInfo, "ArgsInfo", dict( actions = ProviderDepset(_ActionTypeFactory), env = _subjects.dict, files = _subjects.depset_file, # Use .factory so it's not inlined. nested = optional_subject(_NestedArgsFactory.factory), requires_any_of = ProviderSequence(_FeatureConstraintFactory), allowlist_include_directories = _FakeDirectoryDepset, ), ) # buildifier: disable=name-conventions _ArgsListFactory = generate_factory( ArgsListInfo, "ArgsListInfo", dict( args = ProviderSequence(_ArgsFactory), by_action = lambda values, *, meta: dict_key_subject(struct_subject( args = _subjects.collection, files = _subjects.depset_file, ))({value.action: value for value in values}, meta = meta), files = _subjects.depset_file, allowlist_include_directories = _FakeDirectoryDepset, ), ) # buildifier: disable=name-conventions _FeatureFactory = generate_factory( FeatureInfo, "FeatureInfo", _FEATURE_FLAGS | dict( # Use .factory so it's not inlined. args = _ArgsListFactory.factory, implies = ProviderDepset(_FakeFeatureFactory), requires_any_of = ProviderSequence(_FeatureSetFactory), overrides = optional_subject(_FakeFeatureFactory.factory), ), ) # buildifier: disable=name-conventions _ToolCapabilityFactory = generate_factory( ToolCapabilityInfo, "ToolCapabilityInfo", dict( name = _subjects.str, ), ) # buildifier: disable=name-conventions _ToolFactory = generate_factory( ToolInfo, "ToolInfo", dict( exe = _subjects.file, runfiles = runfiles_subject, execution_requirements = _subjects.collection, allowlist_include_directories = _FakeDirectoryDepset, capabilities = ProviderSequence(_ToolCapabilityFactory), ), ) # buildifier: disable=name-conventions _ToolConfigFactory = generate_factory( ToolConfigInfo, "ToolConfigInfo", dict( configs = dict_key_subject(_ToolFactory.factory), ), ) # buildifier: disable=name-conventions _ToolchainConfigFactory = generate_factory( ToolchainConfigInfo, "ToolchainConfigInfo", dict( features = ProviderDepset(_FeatureFactory), enabled_features = _subjects.collection, tool_map = optional_subject(_ToolConfigFactory.factory), args = ProviderSequence(_ArgsFactory), files = dict_key_subject(_subjects.depset_file), allowlist_include_directories = _FakeDirectoryDepset, ), ) FACTORIES = [ _ActionTypeFactory, _ActionTypeSetFactory, _NestedArgsFactory, _ArgsFactory, _ArgsListFactory, _MutuallyExclusiveCategoryFactory, _FeatureFactory, _FeatureConstraintFactory, _FeatureSetFactory, _ToolFactory, _ToolConfigFactory, _ToolchainConfigFactory, ] result_fn_wrapper = _result_fn_wrapper subjects = struct( **(structs.to_dict(_subjects) | dict( unknown = unknown_subject, result = result_subject, optional = optional_subject, struct = struct_subject, runfiles = runfiles_subject, dict_key = dict_key_subject, ) | {factory.name: factory.factory for factory in FACTORIES}) ) rules_cc-0.0.11/tests/rule_based_toolchain/testdata/000077500000000000000000000000001470072561500225175ustar00rootroot00000000000000rules_cc-0.0.11/tests/rule_based_toolchain/testdata/BUILD000066400000000000000000000025171470072561500233060ustar00rootroot00000000000000load("@bazel_skylib//rules:native_binary.bzl", "native_binary") load("@bazel_skylib//rules/directory:directory.bzl", "directory") load("@bazel_skylib//rules/directory:subdirectory.bzl", "subdirectory") package(default_visibility = ["//tests/rule_based_toolchain:__subpackages__"]) directory( name = "directory", srcs = glob( ["**"], exclude = ["BUILD"], ), ) subdirectory( name = "subdirectory_1", parent = ":directory", path = "subdir1", ) subdirectory( name = "subdirectory_2", parent = ":directory", path = "subdir2", ) subdirectory( name = "subdirectory_3", parent = ":directory", path = "subdir3", ) exports_files( glob( ["*"], exclude = ["BUILD"], ), ) native_binary( name = "bin_wrapper", src = "bin_wrapper.sh", out = "bin_wrapper", data = [":bin"], ) filegroup( name = "multiple", srcs = [ "multiple1", "multiple2", ], ) # Analysis_test is unable to depend on source files directly, but it can depend # on a filegroup containing a single file. filegroup( name = "bin_filegroup", srcs = ["bin"], ) # Analysis_test is unable to depend on source files directly, but it can depend # on a filegroup containing a single file. filegroup( name = "bin_wrapper_filegroup", srcs = ["bin_wrapper.sh"], ) rules_cc-0.0.11/tests/rule_based_toolchain/testdata/bin000077500000000000000000000000531470072561500232130ustar00rootroot00000000000000#!/bin/bash echo "Running unwrapped tool" rules_cc-0.0.11/tests/rule_based_toolchain/testdata/bin_wrapper.sh000077500000000000000000000000511470072561500253620ustar00rootroot00000000000000#!/bin/bash echo "Running tool wrapper" rules_cc-0.0.11/tests/rule_based_toolchain/testdata/file1000066400000000000000000000000001470072561500234300ustar00rootroot00000000000000rules_cc-0.0.11/tests/rule_based_toolchain/testdata/file2000066400000000000000000000000001470072561500234310ustar00rootroot00000000000000rules_cc-0.0.11/tests/rule_based_toolchain/testdata/multiple1000066400000000000000000000000001470072561500243440ustar00rootroot00000000000000rules_cc-0.0.11/tests/rule_based_toolchain/testdata/multiple2000066400000000000000000000000001470072561500243450ustar00rootroot00000000000000rules_cc-0.0.11/tests/rule_based_toolchain/testdata/subdir1/000077500000000000000000000000001470072561500240705ustar00rootroot00000000000000rules_cc-0.0.11/tests/rule_based_toolchain/testdata/subdir1/file_foo000066400000000000000000000000001470072561500255630ustar00rootroot00000000000000rules_cc-0.0.11/tests/rule_based_toolchain/testdata/subdir2/000077500000000000000000000000001470072561500240715ustar00rootroot00000000000000rules_cc-0.0.11/tests/rule_based_toolchain/testdata/subdir2/file_bar000066400000000000000000000000001470072561500255450ustar00rootroot00000000000000rules_cc-0.0.11/tests/rule_based_toolchain/testdata/subdir3/000077500000000000000000000000001470072561500240725ustar00rootroot00000000000000rules_cc-0.0.11/tests/rule_based_toolchain/testdata/subdir3/file_baz000066400000000000000000000000001470072561500255560ustar00rootroot00000000000000rules_cc-0.0.11/tests/rule_based_toolchain/testing_rules.bzl000066400000000000000000000031201470072561500243020ustar00rootroot00000000000000# Copyright 2024 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. """Helpers for creating tests for the rule based toolchain.""" load("@rules_testing//lib:analysis_test.bzl", _analysis_test = "analysis_test") load("@rules_testing//lib:truth.bzl", "matching") load("@rules_testing//lib:util.bzl", "util") load(":subjects.bzl", "FACTORIES") visibility("//tests/rule_based_toolchain/...") helper_target = util.helper_target def analysis_test(*, name, **kwargs): """An analysis test for the toolchain rules. Args: name: (str) The name of the test suite. **kwargs: Kwargs to be passed to rules_testing's analysis_test. """ _analysis_test( name = name, provider_subject_factories = FACTORIES, **kwargs ) def expect_failure_test(*, name, target, failure_message): def _impl(env, target): env.expect.that_target(target).failures().contains_predicate(matching.contains(failure_message)) _analysis_test( name = name, expect_failure = True, impl = _impl, target = target, ) rules_cc-0.0.11/tests/rule_based_toolchain/tool/000077500000000000000000000000001470072561500216635ustar00rootroot00000000000000rules_cc-0.0.11/tests/rule_based_toolchain/tool/BUILD000066400000000000000000000023331470072561500224460ustar00rootroot00000000000000load("//cc/toolchains:directory_tool.bzl", "cc_directory_tool") load("//cc/toolchains:tool.bzl", "cc_tool") load("//tests/rule_based_toolchain:analysis_test_suite.bzl", "analysis_test_suite") load(":tool_test.bzl", "TARGETS", "TESTS") cc_tool( name = "tool", src = "//tests/rule_based_toolchain/testdata:bin_wrapper.sh", capabilities = ["//cc/toolchains/capabilities:supports_pic"], data = ["//tests/rule_based_toolchain/testdata:bin"], tags = ["requires-network"], ) cc_tool( name = "wrapped_tool", src = "//tests/rule_based_toolchain/testdata:bin_wrapper", visibility = ["//tests/rule_based_toolchain:__subpackages__"], ) cc_tool( name = "tool_with_allowlist_include_directories", src = "//tests/rule_based_toolchain/testdata:bin_wrapper.sh", allowlist_include_directories = ["//tests/rule_based_toolchain/testdata:directory"], visibility = ["//tests/rule_based_toolchain:__subpackages__"], ) cc_directory_tool( name = "directory_tool", data = ["bin"], directory = "//tests/rule_based_toolchain/testdata:directory", executable = "bin_wrapper.sh", tags = ["requires-network"], ) analysis_test_suite( name = "test_suite", targets = TARGETS, tests = TESTS, ) rules_cc-0.0.11/tests/rule_based_toolchain/tool/tool_test.bzl000066400000000000000000000122731470072561500244150ustar00rootroot00000000000000# Copyright 2024 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. """Tests for the cc_args rule.""" load("//cc/toolchains:cc_toolchain_info.bzl", "ToolInfo") load("//cc/toolchains/impl:collect.bzl", _collect_tools = "collect_tools") load("//cc/toolchains/impl:legacy_converter.bzl", "convert_tool") load("//tests/rule_based_toolchain:subjects.bzl", "result_fn_wrapper", "subjects") visibility("private") collect_tools = result_fn_wrapper(_collect_tools) collection_result = subjects.result(subjects.collection) collect_tool = result_fn_wrapper( lambda ctx, target, fail: _collect_tools(ctx, [target], fail = fail)[0], ) tool_result = subjects.result(subjects.ToolInfo) # Generated by native_binary. _BIN_WRAPPER_SYMLINK = "tests/rule_based_toolchain/testdata/bin_wrapper" _BIN_WRAPPER = "tests/rule_based_toolchain/testdata/bin_wrapper.sh" _BIN = "tests/rule_based_toolchain/testdata/bin" _FILE1 = "tests/rule_based_toolchain/testdata/file1" _TOOL_DIRECTORY = "tests/rule_based_toolchain/testdata" def _tool_test(env, target): tool = env.expect.that_target(target).provider(ToolInfo) tool.exe().short_path_equals(_BIN_WRAPPER) tool.execution_requirements().contains_exactly(["requires-network"]) tool.runfiles().contains_exactly([ _BIN_WRAPPER, _BIN, ]) legacy = convert_tool(tool.actual) env.expect.that_file(legacy.tool).equals(tool.actual.exe) env.expect.that_collection(legacy.execution_requirements).contains_exactly(["requires-network"]) env.expect.that_collection(legacy.with_features).contains_exactly([]) def _wrapped_tool_includes_runfiles_test(env, targets): tool = env.expect.that_target(targets.wrapped_tool).provider(ToolInfo) tool.exe().short_path_equals(_BIN_WRAPPER_SYMLINK) tool.runfiles().contains_exactly([ _BIN_WRAPPER_SYMLINK, _BIN, ]) def _tool_with_allowlist_include_directories_test(env, targets): tool = env.expect.that_target(targets.tool_with_allowlist_include_directories).provider(ToolInfo) tool.allowlist_include_directories().contains_exactly([_TOOL_DIRECTORY]) tool.runfiles().contains_at_least([ _BIN, _FILE1, ]) def _collect_tools_collects_tools_test(env, targets): env.expect.that_value( value = collect_tools(env.ctx, [targets.tool, targets.wrapped_tool]), factory = collection_result, ).ok().contains_exactly( [targets.tool[ToolInfo], targets.wrapped_tool[ToolInfo]], ).in_order() def _collect_tools_collects_binaries_test(env, targets): tool_wrapper = env.expect.that_value( value = collect_tool(env.ctx, targets.bin_wrapper), factory = tool_result, ).ok() tool_wrapper.label().equals(targets.bin_wrapper.label) tool_wrapper.exe().short_path_equals(_BIN_WRAPPER_SYMLINK) tool_wrapper.runfiles().contains_exactly([ _BIN_WRAPPER_SYMLINK, _BIN, ]) def _collect_tools_collects_single_files_test(env, targets): bin = env.expect.that_value( value = collect_tool(env.ctx, targets.bin_filegroup), factory = tool_result, expr = "bin_filegroup", ).ok() bin.label().equals(targets.bin_filegroup.label) bin.exe().short_path_equals(_BIN) bin.runfiles().contains_exactly([_BIN]) def _collect_tools_fails_on_non_binary_test(env, targets): env.expect.that_value( value = collect_tools(env.ctx, [targets.multiple]), factory = collection_result, expr = "multiple_non_binary", ).err() TARGETS = [ "//tests/rule_based_toolchain/features:direct_constraint", "//tests/rule_based_toolchain/tool:tool", "//tests/rule_based_toolchain/tool:wrapped_tool", "//tests/rule_based_toolchain/tool:directory_tool", "//tests/rule_based_toolchain/tool:tool_with_allowlist_include_directories", "//tests/rule_based_toolchain/testdata:bin_wrapper", "//tests/rule_based_toolchain/testdata:multiple", "//tests/rule_based_toolchain/testdata:bin_filegroup", "//tests/rule_based_toolchain/testdata:bin_wrapper_filegroup", ] # @unsorted-dict-items TESTS = { "tool_test": lambda env, targets: _tool_test(env, targets.tool), "directory_tool_test": lambda env, targets: _tool_test(env, targets.directory_tool), "wrapped_tool_includes_runfiles_test": _wrapped_tool_includes_runfiles_test, "collect_tools_collects_tools_test": _collect_tools_collects_tools_test, "collect_tools_collects_binaries_test": _collect_tools_collects_binaries_test, "collect_tools_collects_single_files_test": _collect_tools_collects_single_files_test, "collect_tools_fails_on_non_binary_test": _collect_tools_fails_on_non_binary_test, "tool_with_allowlist_include_directories_test": _tool_with_allowlist_include_directories_test, } rules_cc-0.0.11/tests/rule_based_toolchain/tool_map/000077500000000000000000000000001470072561500225205ustar00rootroot00000000000000rules_cc-0.0.11/tests/rule_based_toolchain/tool_map/BUILD000066400000000000000000000002701470072561500233010ustar00rootroot00000000000000load( ":tool_map_test.bzl", "duplicate_tool_test", "valid_config_test", ) duplicate_tool_test(name = "duplicate_tool_test") valid_config_test(name = "valid_config_test") rules_cc-0.0.11/tests/rule_based_toolchain/tool_map/tool_map_test.bzl000066400000000000000000000051361470072561500261070ustar00rootroot00000000000000# Copyright 2024 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. """Tests for the cc_tool_map rule.""" load("//cc/toolchains:cc_toolchain_info.bzl", "ActionTypeInfo", "ToolConfigInfo") load("//cc/toolchains:tool_map.bzl", "cc_tool_map") load("//tests/rule_based_toolchain:subjects.bzl", "subjects") load("//tests/rule_based_toolchain:testing_rules.bzl", "analysis_test", "expect_failure_test", "helper_target") _ALL_ACTIONS = "//cc/toolchains/actions:all_actions" _C_COMPILE = "//cc/toolchains/actions:c_compile" _CPP_COMPILE = "//cc/toolchains/actions:cpp_compile" _ALL_CPP_COMPILE = "//cc/toolchains/actions:cpp_compile_actions" _STRIP = "//cc/toolchains/actions:strip" _BIN = "//tests/rule_based_toolchain/testdata:bin" _BIN_WRAPPER = "//tests/rule_based_toolchain/testdata:bin_wrapper" def valid_config_test(name): subject_name = "_%s_subject" % name cc_tool_map( name = subject_name, tools = { _C_COMPILE: _BIN_WRAPPER, _ALL_CPP_COMPILE: _BIN, }, ) analysis_test( name = name, impl = _valid_config_test_impl, targets = { "c_compile": _C_COMPILE, "cpp_compile": _CPP_COMPILE, "strip": _STRIP, "subject": subject_name, }, ) def _valid_config_test_impl(env, targets): configs = env.expect.that_target(targets.subject).provider(ToolConfigInfo).configs() configs.contains(targets.strip[ActionTypeInfo]).equals(False) configs.get(targets.c_compile[ActionTypeInfo]).exe().path().split("/").offset(-1, subjects.str).equals("bin_wrapper") configs.get(targets.cpp_compile[ActionTypeInfo]).exe().path().split("/").offset(-1, subjects.str).equals("bin") def duplicate_tool_test(name): subject_name = "_%s_subject" % name helper_target( cc_tool_map, name = subject_name, tools = { _C_COMPILE: _BIN_WRAPPER, _ALL_ACTIONS: _BIN, }, ) expect_failure_test( name = name, target = subject_name, failure_message = "appears multiple times in your tool_map", ) rules_cc-0.0.11/tests/rule_based_toolchain/toolchain_config/000077500000000000000000000000001470072561500242135ustar00rootroot00000000000000rules_cc-0.0.11/tests/rule_based_toolchain/toolchain_config/BUILD000066400000000000000000000120371470072561500250000ustar00rootroot00000000000000load("@rules_testing//lib:util.bzl", "util") load("//cc/toolchains:args.bzl", "cc_args") load("//cc/toolchains:feature.bzl", "cc_feature") load("//cc/toolchains:feature_set.bzl", "cc_feature_set") load("//cc/toolchains:tool.bzl", "cc_tool") load("//cc/toolchains:tool_map.bzl", "cc_tool_map") load("//cc/toolchains/args:sysroot.bzl", "cc_sysroot") load("//cc/toolchains/impl:external_feature.bzl", "cc_external_feature") load("//cc/toolchains/impl:toolchain_config.bzl", "cc_legacy_file_group", "cc_toolchain_config") load("//tests/rule_based_toolchain:analysis_test_suite.bzl", "analysis_test_suite") load(":toolchain_config_test.bzl", "TARGETS", "TESTS") util.helper_target( cc_feature_set, name = "all_simple_features", all_of = [ ":simple_feature", "simple_feature2", ], ) util.helper_target( cc_external_feature, name = "builtin_feature", feature_name = "builtin_feature", overridable = True, ) util.helper_target( cc_args, name = "c_compile_args", actions = ["//tests/rule_based_toolchain/actions:c_compile"], allowlist_include_directories = ["//tests/rule_based_toolchain/testdata:subdirectory_1"], args = ["c_compile_args"], data = ["//tests/rule_based_toolchain/testdata:file1"], ) util.helper_target( cc_args, name = "cpp_compile_args", actions = ["//tests/rule_based_toolchain/actions:cpp_compile"], args = ["cpp_compile_args"], env = {"CPP_COMPILE": "1"}, ) cc_tool( name = "c_compile_tool", src = "//tests/rule_based_toolchain/testdata:bin_wrapper", allowlist_include_directories = ["//tests/rule_based_toolchain/testdata:subdirectory_3"], capabilities = ["//cc/toolchains/capabilities:supports_pic"], ) cc_sysroot( name = "sysroot", sysroot = "//tests/rule_based_toolchain/testdata:directory", ) util.helper_target( cc_toolchain_config, name = "collects_files_toolchain_config", args = [ ":sysroot", ":c_compile_args", ], enabled_features = [":simple_feature"], known_features = [":compile_feature"], tool_map = ":compile_tool_map", ) util.helper_target( cc_legacy_file_group, name = "collects_files_c_compile", actions = ["//tests/rule_based_toolchain/actions:c_compile"], config = ":collects_files_toolchain_config", ) util.helper_target( cc_legacy_file_group, name = "collects_files_cpp_compile", actions = ["//tests/rule_based_toolchain/actions:cpp_compile"], config = ":collects_files_toolchain_config", ) util.helper_target( cc_args, name = "compile_args", actions = ["//tests/rule_based_toolchain/actions:all_compile"], allowlist_include_directories = ["//tests/rule_based_toolchain/testdata:subdirectory_2"], args = ["compile_args"], data = ["//tests/rule_based_toolchain/testdata:file2"], ) util.helper_target( cc_tool_map, name = "compile_tool_map", tools = { "//tests/rule_based_toolchain/actions:c_compile": ":c_compile_tool", "//tests/rule_based_toolchain/actions:cpp_compile": "//tests/rule_based_toolchain/tool:wrapped_tool", }, ) util.helper_target( cc_feature, name = "compile_feature", args = [":compile_args"], feature_name = "compile_feature", ) util.helper_target( cc_tool_map, name = "c_compile_tool_map", tools = { "//tests/rule_based_toolchain/actions:c_compile": "//tests/rule_based_toolchain/tool:wrapped_tool", }, ) util.helper_target( cc_tool_map, name = "empty_tool_map", tools = {}, ) util.helper_target( cc_feature, name = "implies_simple_feature", args = [":c_compile_args"], feature_name = "implies", implies = [":simple_feature"], ) util.helper_target( cc_feature, name = "overrides_feature", args = [":c_compile_args"], overrides = ":builtin_feature", ) util.helper_target( cc_args, name = "requires_all_simple_args", actions = ["//tests/rule_based_toolchain/actions:c_compile"], args = ["--foo"], requires_any_of = [":all_simple_features"], ) util.helper_target( cc_feature, name = "requires_all_simple_feature", args = [":c_compile_args"], feature_name = "requires_any_simple", requires_any_of = [":all_simple_features"], ) util.helper_target( cc_feature, name = "requires_any_simple_feature", args = [":c_compile_args"], feature_name = "requires_any_simple", requires_any_of = [ ":simple_feature", ":simple_feature2", ], ) util.helper_target( cc_feature, name = "same_feature_name", args = [":c_compile_args"], feature_name = "simple_feature", visibility = ["//tests/rule_based_toolchain:__subpackages__"], ) util.helper_target( cc_feature, name = "simple_feature", args = [":c_compile_args"], feature_name = "simple_feature", ) util.helper_target( cc_feature, name = "simple_feature2", args = [":c_compile_args"], feature_name = "simple_feature2", visibility = ["//tests/rule_based_toolchain:__subpackages__"], ) analysis_test_suite( name = "test_suite", targets = TARGETS, tests = TESTS, ) rules_cc-0.0.11/tests/rule_based_toolchain/toolchain_config/toolchain_config_test.bzl000066400000000000000000000256341470072561500313020ustar00rootroot00000000000000# Copyright 2024 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. """Tests for the cc_toolchain_config rule.""" load( "//cc:cc_toolchain_config_lib.bzl", legacy_action_config = "action_config", legacy_feature = "feature", legacy_flag_group = "flag_group", legacy_flag_set = "flag_set", legacy_tool = "tool", ) load("//cc/toolchains:cc_toolchain_info.bzl", "ActionTypeInfo", "ToolchainConfigInfo") load("//cc/toolchains/impl:legacy_converter.bzl", "convert_toolchain") load("//cc/toolchains/impl:toolchain_config_info.bzl", _toolchain_config_info = "toolchain_config_info") load("//tests/rule_based_toolchain:subjects.bzl", "result_fn_wrapper", "subjects") visibility("private") toolchain_config_info = result_fn_wrapper(_toolchain_config_info) _COLLECTED_CPP_COMPILE_FILES = [ # From :compile_config's tool "tests/rule_based_toolchain/testdata/bin", "tests/rule_based_toolchain/testdata/bin_wrapper", # From :compile_feature's args "tests/rule_based_toolchain/testdata/file2", # From :compile_feature's args' allowlist_include_directories "tests/rule_based_toolchain/testdata/subdir2/file_bar", ] _COLLECTED_C_COMPILE_FILES = _COLLECTED_CPP_COMPILE_FILES + [ # From :c_compile_args "tests/rule_based_toolchain/testdata/file1", # From :c_compile_args's allowlist_include_directories "tests/rule_based_toolchain/testdata/subdir1/file_foo", # From :c_compile_tool's allowlist_include_directories "tests/rule_based_toolchain/testdata/subdir3/file_baz", ] def _expect_that_toolchain(env, expr = None, **kwargs): return env.expect.that_value( value = toolchain_config_info(label = Label("//:toolchain"), **kwargs), expr = expr, factory = subjects.result(subjects.ToolchainConfigInfo), ) def _missing_tool_map_invalid_test(env, _targets): _expect_that_toolchain( env, tool_map = None, expr = "missing_tool_map", ).err().contains( "tool_map is required", ) def _empty_toolchain_valid_test(env, targets): _expect_that_toolchain( env, tool_map = targets.empty_tool_map, # tool_map is always required. ).ok() def _duplicate_feature_names_invalid_test(env, targets): _expect_that_toolchain( env, known_features = [targets.simple_feature, targets.same_feature_name], tool_map = targets.empty_tool_map, expr = "duplicate_feature_name", ).err().contains_all_of([ "The feature name simple_feature was defined by", targets.same_feature_name.label, targets.simple_feature.label, ]) # Overriding a feature gives it the same name. Ensure this isn't blocked. _expect_that_toolchain( env, known_features = [targets.builtin_feature, targets.overrides_feature], tool_map = targets.empty_tool_map, expr = "override_feature", ).ok() def _feature_config_implies_missing_feature_invalid_test(env, targets): _expect_that_toolchain( env, expr = "feature_with_implies", known_features = [targets.simple_feature, targets.implies_simple_feature], tool_map = targets.empty_tool_map, ).ok() _expect_that_toolchain( env, known_features = [targets.implies_simple_feature], tool_map = targets.empty_tool_map, expr = "feature_missing_implies", ).err().contains( "%s implies the feature %s" % (targets.implies_simple_feature.label, targets.simple_feature.label), ) def _feature_missing_requirements_invalid_test(env, targets): _expect_that_toolchain( env, known_features = [targets.requires_any_simple_feature, targets.simple_feature], tool_map = targets.empty_tool_map, expr = "requires_any_simple_has_simple", ).ok() _expect_that_toolchain( env, known_features = [targets.requires_any_simple_feature, targets.simple_feature2], tool_map = targets.empty_tool_map, expr = "requires_any_simple_has_simple2", ).ok() _expect_that_toolchain( env, known_features = [targets.requires_any_simple_feature], tool_map = targets.empty_tool_map, expr = "requires_any_simple_has_none", ).err().contains( "It is impossible to enable %s" % targets.requires_any_simple_feature.label, ) _expect_that_toolchain( env, known_features = [targets.requires_all_simple_feature, targets.simple_feature, targets.simple_feature2], tool_map = targets.empty_tool_map, expr = "requires_all_simple_has_both", ).ok() _expect_that_toolchain( env, known_features = [targets.requires_all_simple_feature, targets.simple_feature], tool_map = targets.empty_tool_map, expr = "requires_all_simple_has_simple", ).err().contains( "It is impossible to enable %s" % targets.requires_all_simple_feature.label, ) _expect_that_toolchain( env, known_features = [targets.requires_all_simple_feature, targets.simple_feature2], tool_map = targets.empty_tool_map, expr = "requires_all_simple_has_simple2", ).err().contains( "It is impossible to enable %s" % targets.requires_all_simple_feature.label, ) def _args_missing_requirements_invalid_test(env, targets): _expect_that_toolchain( env, args = [targets.requires_all_simple_args], known_features = [targets.simple_feature, targets.simple_feature2], tool_map = targets.empty_tool_map, expr = "has_both", ).ok() _expect_that_toolchain( env, args = [targets.requires_all_simple_args], known_features = [targets.simple_feature], tool_map = targets.empty_tool_map, expr = "has_only_one", ).err().contains( "It is impossible to enable %s" % targets.requires_all_simple_args.label, ) def _toolchain_collects_files_test(env, targets): tc = env.expect.that_target( targets.collects_files_toolchain_config, ).provider(ToolchainConfigInfo) tc.files().get(targets.c_compile[ActionTypeInfo]).contains_exactly(_COLLECTED_C_COMPILE_FILES) tc.files().get(targets.cpp_compile[ActionTypeInfo]).contains_exactly(_COLLECTED_CPP_COMPILE_FILES) env.expect.that_target( targets.collects_files_c_compile, ).default_outputs().contains_exactly(_COLLECTED_C_COMPILE_FILES) env.expect.that_target( targets.collects_files_cpp_compile, ).default_outputs().contains_exactly(_COLLECTED_CPP_COMPILE_FILES) legacy = convert_toolchain(tc.actual) env.expect.that_collection(legacy.features).contains_exactly([ legacy_feature( name = "simple_feature", enabled = True, flag_sets = [legacy_flag_set( actions = ["c_compile"], flag_groups = [ legacy_flag_group(flags = ["c_compile_args"]), ], )], ), legacy_feature( name = "compile_feature", enabled = False, flag_sets = [legacy_flag_set( actions = ["c_compile", "cpp_compile"], flag_groups = [ legacy_flag_group(flags = ["compile_args"]), ], )], ), legacy_feature( name = "supports_pic", enabled = False, ), legacy_feature( name = "implied_by_always_enabled", enabled = True, flag_sets = [ legacy_flag_set( actions = [ "c++-compile", "c++-header-parsing", "c++-link-dynamic-library", "c++-link-executable", "c++-link-nodeps-dynamic-library", "c++-module-codegen", "c++-module-compile", "c-compile", "clif-match", "linkstamp-compile", "lto-backend", "lto-index-for-dynamic-library", "lto-index-for-executable", "lto-index-for-nodeps-dynamic-library", ], flag_groups = [ legacy_flag_group(flags = [ "--sysroot=tests/rule_based_toolchain/testdata", ]), ], ), legacy_flag_set( actions = ["c_compile"], flag_groups = [ legacy_flag_group(flags = ["c_compile_args"]), ], ), ], ), ]).in_order() exe = tc.tool_map().some().configs().get( targets.c_compile[ActionTypeInfo], ).actual.exe env.expect.that_collection(legacy.action_configs).contains_exactly([ legacy_action_config( action_name = "c_compile", enabled = True, tools = [legacy_tool(tool = exe)], implies = ["supports_pic"], ), legacy_action_config( action_name = "cpp_compile", enabled = True, tools = [legacy_tool(tool = exe)], implies = [], ), ]).in_order() TARGETS = [ "//tests/rule_based_toolchain/actions:c_compile", "//tests/rule_based_toolchain/actions:cpp_compile", ":builtin_feature", ":compile_tool_map", ":collects_files_c_compile", ":collects_files_cpp_compile", ":collects_files_toolchain_config", ":compile_feature", ":c_compile_args", ":c_compile_tool_map", ":empty_tool_map", ":implies_simple_feature", ":overrides_feature", ":requires_any_simple_feature", ":requires_all_simple_feature", ":requires_all_simple_args", ":simple_feature", ":simple_feature2", ":same_feature_name", ] # @unsorted-dict-items TESTS = { "empty_toolchain_valid_test": _empty_toolchain_valid_test, "missing_tool_map_invalid_test": _missing_tool_map_invalid_test, "duplicate_feature_names_fail_validation_test": _duplicate_feature_names_invalid_test, "feature_config_implies_missing_feature_invalid_test": _feature_config_implies_missing_feature_invalid_test, "feature_missing_requirements_invalid_test": _feature_missing_requirements_invalid_test, "args_missing_requirements_invalid_test": _args_missing_requirements_invalid_test, "toolchain_collects_files_test": _toolchain_collects_files_test, } rules_cc-0.0.11/tests/rule_based_toolchain/variables/000077500000000000000000000000001470072561500226565ustar00rootroot00000000000000rules_cc-0.0.11/tests/rule_based_toolchain/variables/BUILD000066400000000000000000000061711470072561500234450ustar00rootroot00000000000000load("//cc/toolchains:nested_args.bzl", "cc_nested_args") load("//cc/toolchains/impl:variables.bzl", "cc_builtin_variables", "cc_variable", "types") load("//tests/rule_based_toolchain:analysis_test_suite.bzl", "analysis_test_suite") load(":variables_test.bzl", "TARGETS", "TESTS") cc_variable( name = "str", type = types.string, ) cc_variable( name = "optional_list", type = types.option(types.list(types.string)), ) cc_variable( name = "str_list", type = types.list(types.string), ) cc_variable( name = "str_option", type = types.option(types.string), ) cc_variable( name = "struct", actions = ["//tests/rule_based_toolchain/actions:c_compile"], type = types.struct( nested_str = types.string, nested_str_list = types.list(types.string), ), ) cc_variable( name = "struct_list", actions = ["//tests/rule_based_toolchain/actions:c_compile"], type = types.list(types.struct( nested_str = types.string, nested_str_list = types.list(types.string), )), ) cc_variable( name = "struct_list.nested_str_list", type = types.unknown, ) # Dots in the name confuse the test rules. # It would end up generating targets.struct_list.nested_str_list. alias( name = "nested_str_list", actual = ":struct_list.nested_str_list", ) cc_nested_args( name = "simple_str", args = ["{str}"], format = {"str": ":str"}, ) cc_nested_args( name = "list_not_allowed", args = ["{s}"], format = {"s": ":str_list"}, ) cc_nested_args( name = "iterate_over_list", args = ["{}"], iterate_over = ":str_list", ) cc_nested_args( name = "iterate_over_non_list", args = ["--foo"], iterate_over = ":str", ) cc_nested_args( name = "str_not_a_bool", args = ["--foo"], requires_true = ":str", ) cc_nested_args( name = "str_equal", args = ["--foo"], requires_equal = ":str", requires_equal_value = "bar", ) cc_nested_args( name = "inner_iter", args = ["{}"], iterate_over = ":struct_list.nested_str_list", ) cc_nested_args( name = "outer_iter", iterate_over = ":struct_list", nested = [":inner_iter"], ) cc_nested_args( name = "bad_inner_iter", args = ["{s}"], format = {"s": ":struct_list.nested_str_list"}, ) cc_nested_args( name = "bad_outer_iter", iterate_over = ":struct_list", nested = [":bad_inner_iter"], ) cc_nested_args( name = "bad_nested_optional", args = ["{s}"], format = {"s": ":str_option"}, ) cc_nested_args( name = "good_nested_optional", args = ["{s}"], format = {"s": ":str_option"}, requires_not_none = ":str_option", ) cc_nested_args( name = "optional_list_iter", args = ["--foo"], iterate_over = ":optional_list", ) cc_builtin_variables( name = "variables", srcs = [ ":optional_list", ":str", ":str_list", ":str_option", ":struct", ":struct_list", ], ) cc_builtin_variables( name = "nested_variables", srcs = [ ":struct_list.nested_str_list", ], ) analysis_test_suite( name = "test_suite", targets = TARGETS, tests = TESTS, ) rules_cc-0.0.11/tests/rule_based_toolchain/variables/variables_test.bzl000066400000000000000000000205031470072561500263760ustar00rootroot00000000000000# Copyright 2024 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. """Tests for variables rule.""" load("//cc/toolchains:cc_toolchain_info.bzl", "ActionTypeInfo", "BuiltinVariablesInfo", "NestedArgsInfo", "VariableInfo") load("//cc/toolchains/impl:args_utils.bzl", _validate_nested_args = "validate_nested_args") load( "//cc/toolchains/impl:nested_args.bzl", "FORMAT_ARGS_ERR", "REQUIRES_TRUE_ERR", ) load("//cc/toolchains/impl:variables.bzl", "types", _get_type = "get_type") load("//tests/rule_based_toolchain:subjects.bzl", "result_fn_wrapper", "subjects") visibility("private") get_type = result_fn_wrapper(_get_type) validate_nested_args = result_fn_wrapper(_validate_nested_args) _ARGS_LABEL = Label("//:args") _NESTED_LABEL = Label("//:nested_vars") def _type(target): return target[VariableInfo].type def _types_represent_correctly_test(env, targets): env.expect.that_str(_type(targets.str_list)["repr"]).equals("List[string]") env.expect.that_str(_type(targets.str_option)["repr"]).equals("Option[string]") env.expect.that_str(_type(targets.struct)["repr"]).equals("struct(nested_str=string, nested_str_list=List[string])") env.expect.that_str(_type(targets.struct_list)["repr"]).equals("List[struct(nested_str=string, nested_str_list=List[string])]") def _get_types_test(env, targets): c_compile = targets.c_compile[ActionTypeInfo] cpp_compile = targets.cpp_compile[ActionTypeInfo] variables = targets.variables[BuiltinVariablesInfo].variables def expect_type(key, overrides = {}, expr = None, actions = []): return env.expect.that_value( get_type( variables = variables, overrides = overrides, args_label = _ARGS_LABEL, nested_label = _NESTED_LABEL, actions = actions, name = key, ), # It's not a string, it's a complex recursive type, but string # supports .equals, which is all we care about. factory = subjects.result(subjects.str), expr = expr or key, ) expect_type("unknown").err().contains( """The variable unknown does not exist. Did you mean one of the following? optional_list str str_list """, ) expect_type("str").ok().equals(types.string) expect_type("str.invalid").err().equals("""Attempted to access "str.invalid", but "str" was not a struct - it had type string.""") expect_type("str_option").ok().equals(types.option(types.string)) expect_type("str_list").ok().equals(types.list(types.string)) expect_type("str_list.invalid").err().equals("""Attempted to access "str_list.invalid", but "str_list" was not a struct - it had type List[string].""") expect_type("struct").ok().equals(_type(targets.struct)) expect_type("struct.nested_str_list").ok().equals(types.list(types.string)) expect_type("struct_list").ok().equals(_type(targets.struct_list)) expect_type("struct_list.nested_str_list").err().equals("""Attempted to access "struct_list.nested_str_list", but "struct_list" was not a struct - it had type List[struct(nested_str=string, nested_str_list=List[string])]. Maybe you meant to use iterate_over.""") expect_type("struct.unknown").err().equals("""Unable to find "unknown" in "struct", which had the following attributes: nested_str: string nested_str_list: List[string]""") expect_type("struct", actions = [c_compile]).ok() expect_type("struct", actions = [c_compile, cpp_compile]).err().equals( "The variable %s is inaccessible from the action %s. This is required because it is referenced in %s, which is included by %s, which references that action" % (targets.struct.label, cpp_compile.label, _NESTED_LABEL, _ARGS_LABEL), ) expect_type("struct.nested_str_list", actions = [c_compile]).ok() expect_type("struct.nested_str_list", actions = [c_compile, cpp_compile]).err() # Simulate someone doing iterate_over = struct_list. expect_type( "struct_list", overrides = {"struct_list": _type(targets.struct)}, expr = "struct_list_override", ).ok().equals(_type(targets.struct)) expect_type( "struct_list.nested_str_list", overrides = {"struct_list": _type(targets.struct)}, ).ok().equals(types.list(types.string)) expect_type( "struct_list.nested_str_list", overrides = { "struct_list": _type(targets.struct), "struct_list.nested_str_list": types.string, }, ).ok().equals(types.string) def _variable_validation_test(env, targets): c_compile = targets.c_compile[ActionTypeInfo] cpp_compile = targets.cpp_compile[ActionTypeInfo] variables = targets.variables[BuiltinVariablesInfo].variables def _expect_validated(target, expr = None, actions = []): return env.expect.that_value( validate_nested_args( nested_args = target[NestedArgsInfo], variables = variables, actions = actions, label = _ARGS_LABEL, ), expr = expr, # Type is Result[None] factory = subjects.result(subjects.unknown), ) _expect_validated(targets.simple_str, expr = "simple_str").ok() _expect_validated(targets.list_not_allowed).err().equals( FORMAT_ARGS_ERR + ", but str_list has type List[string]", ) _expect_validated(targets.iterate_over_list, expr = "iterate_over_list").ok() _expect_validated(targets.iterate_over_non_list, expr = "iterate_over_non_list").err().equals( "Attempting to iterate over str, but it was not a list - it was a string", ) _expect_validated(targets.str_not_a_bool, expr = "str_not_a_bool").err().equals( REQUIRES_TRUE_ERR + ", but str has type string", ) _expect_validated(targets.str_equal, expr = "str_equal").ok() _expect_validated(targets.inner_iter, expr = "inner_iter_standalone").err().equals( 'Attempted to access "struct_list.nested_str_list", but "struct_list" was not a struct - it had type List[struct(nested_str=string, nested_str_list=List[string])]. Maybe you meant to use iterate_over.', ) _expect_validated(targets.outer_iter, actions = [c_compile], expr = "outer_iter_valid_action").ok() _expect_validated(targets.outer_iter, actions = [c_compile, cpp_compile], expr = "outer_iter_missing_action").err().equals( "The variable %s is inaccessible from the action %s. This is required because it is referenced in %s, which is included by %s, which references that action" % (targets.struct_list.label, cpp_compile.label, targets.outer_iter.label, _ARGS_LABEL), ) _expect_validated(targets.bad_outer_iter, expr = "bad_outer_iter").err().equals( FORMAT_ARGS_ERR + ", but struct_list.nested_str_list has type List[string]", ) _expect_validated(targets.optional_list_iter, expr = "optional_list_iter").ok() _expect_validated(targets.bad_nested_optional, expr = "bad_nested_optional").err().equals( FORMAT_ARGS_ERR + ", but str_option has type Option[string]", ) _expect_validated(targets.good_nested_optional, expr = "good_nested_optional").ok() TARGETS = [ "//tests/rule_based_toolchain/actions:c_compile", "//tests/rule_based_toolchain/actions:cpp_compile", ":bad_nested_optional", ":bad_outer_iter", ":good_nested_optional", ":inner_iter", ":iterate_over_list", ":iterate_over_non_list", ":list_not_allowed", ":nested_str_list", ":optional_list_iter", ":outer_iter", ":simple_str", ":str", ":str_equal", ":str_list", ":str_not_a_bool", ":str_option", ":struct", ":struct_list", ":variables", ] # @unsorted-dict-items TESTS = { "types_represent_correctly_test": _types_represent_correctly_test, "get_types_test": _get_types_test, "variable_validation_test": _variable_validation_test, } rules_cc-0.0.11/tests/simple_binary/000077500000000000000000000000001470072561500173765ustar00rootroot00000000000000rules_cc-0.0.11/tests/simple_binary/BUILD000066400000000000000000000014341470072561500201620ustar00rootroot00000000000000# 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. load("//cc:defs.bzl", "cc_binary") licenses(["notice"]) cc_binary( name = "foo", srcs = ["foo.cc"], ) cc_binary( name = "libfoo.so", srcs = ["foo.cc"], linkshared = 1, ) rules_cc-0.0.11/tests/simple_binary/foo.cc000066400000000000000000000012271470072561500204720ustar00rootroot00000000000000// 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. int main(int argc, char *argv[]) { return 0; } rules_cc-0.0.11/tests/system_library/000077500000000000000000000000001470072561500176115ustar00rootroot00000000000000rules_cc-0.0.11/tests/system_library/BUILD000066400000000000000000000016071470072561500203770ustar00rootroot00000000000000# 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. sh_test( name = "system_library_test", size = "small", srcs = ["system_library_test.sh"], data = [ ":unittest.bash", "//cc:system_library.bzl", "@bazel_tools//tools/bash/runfiles", ], target_compatible_with = [ "@platforms//os:linux", ], ) rules_cc-0.0.11/tests/system_library/system_library_test.sh000077500000000000000000000127001470072561500242570ustar00rootroot00000000000000# --- begin runfiles.bash initialization --- set -euo pipefail if [[ ! -d "${RUNFILES_DIR:-/dev/null}" && ! -f "${RUNFILES_MANIFEST_FILE:-/dev/null}" ]]; then if [[ -f "$0.runfiles_manifest" ]]; then export RUNFILES_MANIFEST_FILE="$0.runfiles_manifest" elif [[ -f "$0.runfiles/MANIFEST" ]]; then export RUNFILES_MANIFEST_FILE="$0.runfiles/MANIFEST" elif [[ -f "$0.runfiles/bazel_tools/tools/bash/runfiles/runfiles.bash" ]]; then export RUNFILES_DIR="$0.runfiles" fi fi if [[ -f "${RUNFILES_DIR:-/dev/null}/bazel_tools/tools/bash/runfiles/runfiles.bash" ]]; then source "${RUNFILES_DIR}/bazel_tools/tools/bash/runfiles/runfiles.bash" elif [[ -f "${RUNFILES_MANIFEST_FILE:-/dev/null}" ]]; then source "$(grep -m1 "^bazel_tools/tools/bash/runfiles/runfiles.bash " \ "$RUNFILES_MANIFEST_FILE" | cut -d ' ' -f 2-)" else echo >&2 "ERROR: cannot find @bazel_tools//tools/bash/runfiles:runfiles.bash" exit 1 fi # --- end runfiles.bash initialization --- source "$(rlocation rules_cc/tests/system_library/unittest.bash)" \ || { echo "Could not rules_cc/source tests/system_library/unittest.bash" >&2; exit 1; } function setup_system_library() { mkdir -p systemlib cat << EOF > systemlib/foo.cc int bar() { return 42; } EOF cat << EOF > systemlib/foo.h int bar(); EOF cd systemlib g++ -c -fpic foo.cc || fail "Expected foo.o to build successfully" g++ -shared -o libfoo.so foo.o || fail "Expected foo.so to build successfully" g++ -c foo.cc || fail "Expected foo.o to build successfully" ar rvs foo.a foo.o || fail "Expected foo.a to build successfully" cd .. cat << EOF > WORKSPACE load("//:cc/system_library.bzl", "system_library") system_library( name = "foo", hdrs = [ "foo.h", ], static_lib_names = ["libfoo.a"], shared_lib_names = ["libfoo.so"] ) system_library( name = "foo_hardcoded_path", hdrs = [ "foo.h", ], static_lib_names = ["libfoo.a"], shared_lib_names = ["libfoo.so"], lib_path_hints = ["${PWD}/systemlib"], includes = ["${PWD}/systemlib"] ) EOF cat << EOF > BUILD cc_binary( name = "test", srcs = ["test.cc"], deps = ["@foo"] ) cc_binary( name = "test_static", srcs = ["test.cc"], deps = ["@foo"], linkstatic = True ) cc_binary( name = "test_hardcoded_path", srcs = ["test.cc"], deps = ["@foo_hardcoded_path"] ) cc_binary( name = "test_static_hardcoded_path", srcs = ["test.cc"], deps = ["@foo_hardcoded_path"], linkstatic = True ) cc_binary( name = "fake_rbe", srcs = ["test.cc"], deps = ["@foo_hardcoded_path"] ) EOF cat << EOF > test.cc #include "foo.h" int main() { return 42 - bar(); } EOF } #### TESTS ############################################################# # Make sure it fails with a correct message when no library is found function test_system_library_not_found() { setup_system_library bazel run //:test \ --experimental_starlark_cc_import \ --experimental_repo_remote_exec \ &> $TEST_log \ || true expect_log "Library foo could not be found" bazel run //:test_static \ --experimental_starlark_cc_import \ --experimental_repo_remote_exec \ &> $TEST_log \ || true expect_log "Library foo could not be found" } function test_override_paths() { setup_system_library bazel run //:test \ --experimental_starlark_cc_import \ --experimental_repo_remote_exec \ --action_env=BAZEL_LIB_OVERRIDE_PATHS=foo="${PWD}"/systemlib \ --action_env=BAZEL_INCLUDE_OVERRIDE_PATHS=foo="${PWD}"/systemlib \ || fail "Expected test to run successfully" bazel run //:test_static \ --experimental_starlark_cc_import \ --experimental_repo_remote_exec \ --action_env=BAZEL_LIB_OVERRIDE_PATHS=foo="${PWD}"/systemlib \ --action_env=BAZEL_INCLUDE_OVERRIDE_PATHS=foo="${PWD}"/systemlib \ || fail "Expected test_static to run successfully" } function test_additional_paths() { setup_system_library bazel run //:test \ --experimental_starlark_cc_import \ --experimental_repo_remote_exec \ --action_env=BAZEL_LIB_ADDITIONAL_PATHS=foo="${PWD}"/systemlib \ --action_env=BAZEL_INCLUDE_ADDITIONAL_PATHS=foo="${PWD}"/systemlib \ || fail "Expected test to run successfully" bazel run //:test_static \ --experimental_starlark_cc_import \ --experimental_repo_remote_exec \ --action_env=BAZEL_LIB_ADDITIONAL_PATHS=foo="${PWD}"/systemlib \ --action_env=BAZEL_INCLUDE_ADDITIONAL_PATHS=foo="${PWD}"/systemlib \ || fail "Expected test_static to run successfully" } function test_hardcoded_paths() { setup_system_library bazel run //:test_hardcoded_path \ --experimental_starlark_cc_import \ --experimental_repo_remote_exec \ || fail "Expected test_hardcoded_path to run successfully" bazel run //:test_static_hardcoded_path \ --experimental_starlark_cc_import \ --experimental_repo_remote_exec \ || fail "Expected test_static_hardcoded_path to run successfully" } function test_system_library_no_lib_names() { cat << EOF > WORKSPACE load("//:cc/system_library.bzl", "system_library") system_library( name = "foo", hdrs = [ "foo.h", ] ) EOF cat << EOF > BUILD cc_binary( name = "test", srcs = ["test.cc"], deps = ["@foo"] ) EOF # It should fail when no static_lib_names and static_lib_names are given bazel run //:test \ --experimental_starlark_cc_import \ --experimental_repo_remote_exec \ &> $TEST_log \ || true expect_log "Library foo could not be found" } run_suite "Integration tests for system_library."rules_cc-0.0.11/tests/system_library/unittest.bash000066400000000000000000000612421470072561500223340ustar00rootroot00000000000000#!/bin/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. # # Common utility file for Bazel shell tests # # unittest.bash: a unit test framework in Bash. # # A typical test suite looks like so: # # ------------------------------------------------------------------------ # #!/bin/bash # # source path/to/unittest.bash || exit 1 # # # Test that foo works. # function test_foo() { # foo >$TEST_log || fail "foo failed"; # expect_log "blah" "Expected to see 'blah' in output of 'foo'." # } # # # Test that bar works. # function test_bar() { # bar 2>$TEST_log || fail "bar failed"; # expect_not_log "ERROR" "Unexpected error from 'bar'." # ... # assert_equals $x $y # } # # run_suite "Test suite for blah" # ------------------------------------------------------------------------ # # Each test function is considered to pass iff fail() is not called # while it is active. fail() may be called directly, or indirectly # via other assertions such as expect_log(). run_suite must be called # at the very end. # # A test function may redefine functions "set_up" and/or "tear_down"; # these functions are executed before and after each test function, # respectively. Similarly, "cleanup" and "timeout" may be redefined, # and these function are called upon exit (of any kind) or a timeout. # # The user can pass --test_arg to bazel test to select specific tests # to run. Specifying --test_arg multiple times allows to select several # tests to be run in the given order. Additionally the user may define # TESTS=(test_foo test_bar ...) to specify a subset of test functions to # execute, for example, a working set during debugging. By default, all # functions called test_* will be executed. # # This file provides utilities for assertions over the output of a # command. The output of the command under test is directed to the # file $TEST_log, and then the expect_log* assertions can be used to # test for the presence of certain regular expressions in that file. # # The test framework is responsible for restoring the original working # directory before each test. # # The order in which test functions are run is not defined, so it is # important that tests clean up after themselves. # # Each test will be run in a new subshell. # # Functions named __* are not intended for use by clients. # # This framework implements the "test sharding protocol". # [ -n "$BASH_VERSION" ] || { echo "unittest.bash only works with bash!" >&2; exit 1; } DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) #### Configuration variables (may be overridden by testenv.sh or the suite): # This function may be called by testenv.sh or a test suite to enable errexit # in a way that enables us to print pretty stack traces when something fails. function enable_errexit() { set -o errtrace set -eu trap __test_terminated_err ERR } function disable_errexit() { set +o errtrace set +eu trap - ERR } #### Set up the test environment, branched from the old shell/testenv.sh # Enable errexit with pretty stack traces. enable_errexit # Print message in "$1" then exit with status "$2" die () { # second argument is optional, defaulting to 1 local status_code=${2:-1} # Stop capturing stdout/stderr, and dump captured output if [ "$CAPTURED_STD_ERR" -ne 0 -o "$CAPTURED_STD_OUT" -ne 0 ]; then restore_outputs if [ "$CAPTURED_STD_OUT" -ne 0 ]; then cat "${TEST_TMPDIR}/captured.out" CAPTURED_STD_OUT=0 fi if [ "$CAPTURED_STD_ERR" -ne 0 ]; then cat "${TEST_TMPDIR}/captured.err" 1>&2 CAPTURED_STD_ERR=0 fi fi if [ -n "${1-}" ] ; then echo "$1" 1>&2 fi if [ -n "${BASH-}" ]; then local caller_n=0 while [ $caller_n -lt 4 ] && caller_out=$(caller $caller_n 2>/dev/null); do test $caller_n -eq 0 && echo "CALLER stack (max 4):" echo " $caller_out" let caller_n=caller_n+1 done 1>&2 fi if [ x"$status_code" != x -a x"$status_code" != x"0" ]; then exit "$status_code" else exit 1 fi } # Print message in "$1" then record that a non-fatal error occurred in ERROR_COUNT ERROR_COUNT="${ERROR_COUNT:-0}" error () { if [ -n "$1" ] ; then echo "$1" 1>&2 fi ERROR_COUNT=$(($ERROR_COUNT + 1)) } # Die if "$1" != "$2", print $3 as death reason check_eq () { [ "$1" = "$2" ] || die "Check failed: '$1' == '$2' ${3:+ ($3)}" } # Die if "$1" == "$2", print $3 as death reason check_ne () { [ "$1" != "$2" ] || die "Check failed: '$1' != '$2' ${3:+ ($3)}" } # The structure of the following if statements is such that if '[' fails # (e.g., a non-number was passed in) then the check will fail. # Die if "$1" > "$2", print $3 as death reason check_le () { [ "$1" -gt "$2" ] || die "Check failed: '$1' <= '$2' ${3:+ ($3)}" } # Die if "$1" >= "$2", print $3 as death reason check_lt () { [ "$1" -lt "$2" ] || die "Check failed: '$1' < '$2' ${3:+ ($3)}" } # Die if "$1" < "$2", print $3 as death reason check_ge () { [ "$1" -ge "$2" ] || die "Check failed: '$1' >= '$2' ${3:+ ($3)}" } # Die if "$1" <= "$2", print $3 as death reason check_gt () { [ "$1" -gt "$2" ] || die "Check failed: '$1' > '$2' ${3:+ ($3)}" } # Die if $2 !~ $1; print $3 as death reason check_match () { expr match "$2" "$1" >/dev/null || \ die "Check failed: '$2' does not match regex '$1' ${3:+ ($3)}" } # Run command "$1" at exit. Like "trap" but multiple atexits don't # overwrite each other. Will break if someone does call trap # directly. So, don't do that. ATEXIT="${ATEXIT-}" atexit () { if [ -z "$ATEXIT" ]; then ATEXIT="$1" else ATEXIT="$1 ; $ATEXIT" fi trap "$ATEXIT" EXIT } ## TEST_TMPDIR if [ -z "${TEST_TMPDIR:-}" ]; then export TEST_TMPDIR="$(mktemp -d ${TMPDIR:-/tmp}/bazel-test.XXXXXXXX)" fi if [ ! -e "${TEST_TMPDIR}" ]; then mkdir -p -m 0700 "${TEST_TMPDIR}" # Clean TEST_TMPDIR on exit atexit "rm -fr ${TEST_TMPDIR}" fi # Functions to compare the actual output of a test to the expected # (golden) output. # # Usage: # capture_test_stdout # ... do something ... # diff_test_stdout "$TEST_SRCDIR/path/to/golden.out" # Redirect a file descriptor to a file. CAPTURED_STD_OUT="${CAPTURED_STD_OUT:-0}" CAPTURED_STD_ERR="${CAPTURED_STD_ERR:-0}" capture_test_stdout () { exec 3>&1 # Save stdout as fd 3 exec 4>"${TEST_TMPDIR}/captured.out" exec 1>&4 CAPTURED_STD_OUT=1 } capture_test_stderr () { exec 6>&2 # Save stderr as fd 6 exec 7>"${TEST_TMPDIR}/captured.err" exec 2>&7 CAPTURED_STD_ERR=1 } # Force XML_OUTPUT_FILE to an existing path if [ -z "${XML_OUTPUT_FILE:-}" ]; then XML_OUTPUT_FILE=${TEST_TMPDIR}/ouput.xml fi #### Global variables: TEST_name="" # The name of the current test. TEST_log=$TEST_TMPDIR/log # The log file over which the # expect_log* assertions work. Must # be absolute to be robust against # tests invoking 'cd'! TEST_passed="true" # The result of the current test; # failed assertions cause this to # become false. # These variables may be overridden by the test suite: TESTS=() # A subset or "working set" of test # functions that should be run. By # default, all tests called test_* are # run. if [ $# -gt 0 ]; then # Legacy behavior is to ignore missing regexp, but with errexit # the following line fails without || true. # TODO(dmarting): maybe we should revisit the way of selecting # test with that framework (use Bazel's environment variable instead). TESTS=($(for i in $@; do echo $i; done | grep ^test_ || true)) if (( ${#TESTS[@]} == 0 )); then echo "WARNING: Arguments do not specifies tests!" >&2 fi fi TEST_verbose="true" # Whether or not to be verbose. A # command; "true" or "false" are # acceptable. The default is: true. TEST_script="$(pwd)/$0" # Full path to test script #### Internal functions function __show_log() { echo "-- Test log: -----------------------------------------------------------" [[ -e $TEST_log ]] && cat $TEST_log || echo "(Log file did not exist.)" echo "------------------------------------------------------------------------" } # Usage: __pad <pad-char> # Print $title padded to 80 columns with $pad_char. function __pad() { local title=$1 local pad=$2 { echo -n "$pad$pad $title " printf "%80s" " " | tr ' ' "$pad" } | head -c 80 echo } #### Exported functions # Usage: init_test ... # Deprecated. Has no effect. function init_test() { : } # Usage: set_up # Called before every test function. May be redefined by the test suite. function set_up() { : } # Usage: tear_down # Called after every test function. May be redefined by the test suite. function tear_down() { : } # Usage: cleanup # Called upon eventual exit of the test suite. May be redefined by # the test suite. function cleanup() { : } # Usage: timeout # Called upon early exit from a test due to timeout. function timeout() { : } # Usage: fail <message> [<message> ...] # Print failure message with context information, and mark the test as # a failure. The context includes a stacktrace including the longest sequence # of calls outside this module. (We exclude the top and bottom portions of # the stack because they just add noise.) Also prints the contents of # $TEST_log. function fail() { __show_log >&2 echo "$TEST_name FAILED:" "$@" "." >&2 echo "$@" >$TEST_TMPDIR/__fail TEST_passed="false" __show_stack # Cleanup as we are leaving the subshell now tear_down exit 1 } # Usage: warn <message> # Print a test warning with context information. # The context includes a stacktrace including the longest sequence # of calls outside this module. (We exclude the top and bottom portions of # the stack because they just add noise.) function warn() { __show_log >&2 echo "$TEST_name WARNING: $1." >&2 __show_stack if [ -n "${TEST_WARNINGS_OUTPUT_FILE:-}" ]; then echo "$TEST_name WARNING: $1." >> "$TEST_WARNINGS_OUTPUT_FILE" fi } # Usage: show_stack # Prints the portion of the stack that does not belong to this module, # i.e. the user's code that called a failing assertion. Stack may not # be available if Bash is reading commands from stdin; an error is # printed in that case. __show_stack() { local i=0 local trace_found=0 # Skip over active calls within this module: while (( i < ${#FUNCNAME[@]} )) && [[ ${BASH_SOURCE[i]:-} == ${BASH_SOURCE[0]} ]]; do (( ++i )) done # Show all calls until the next one within this module (typically run_suite): while (( i < ${#FUNCNAME[@]} )) && [[ ${BASH_SOURCE[i]:-} != ${BASH_SOURCE[0]} ]]; do # Read online docs for BASH_LINENO to understand the strange offset. # Undefined can occur in the BASH_SOURCE stack apparently when one exits from a subshell echo "${BASH_SOURCE[i]:-"Unknown"}:${BASH_LINENO[i - 1]:-"Unknown"}: in call to ${FUNCNAME[i]:-"Unknown"}" >&2 (( ++i )) trace_found=1 done [ $trace_found = 1 ] || echo "[Stack trace not available]" >&2 } # Usage: expect_log <regexp> [error-message] # Asserts that $TEST_log matches regexp. Prints the contents of # $TEST_log and the specified (optional) error message otherwise, and # returns non-zero. function expect_log() { local pattern=$1 local message=${2:-Expected regexp "$pattern" not found} grep -sq -- "$pattern" $TEST_log && return 0 fail "$message" return 1 } # Usage: expect_log_warn <regexp> [error-message] # Warns if $TEST_log does not match regexp. Prints the contents of # $TEST_log and the specified (optional) error message on mismatch. function expect_log_warn() { local pattern=$1 local message=${2:-Expected regexp "$pattern" not found} grep -sq -- "$pattern" $TEST_log && return 0 warn "$message" return 1 } # Usage: expect_log_once <regexp> [error-message] # Asserts that $TEST_log contains one line matching <regexp>. # Prints the contents of $TEST_log and the specified (optional) # error message otherwise, and returns non-zero. function expect_log_once() { local pattern=$1 local message=${2:-Expected regexp "$pattern" not found exactly once} expect_log_n "$pattern" 1 "$message" } # Usage: expect_log_n <regexp> <count> [error-message] # Asserts that $TEST_log contains <count> lines matching <regexp>. # Prints the contents of $TEST_log and the specified (optional) # error message otherwise, and returns non-zero. function expect_log_n() { local pattern=$1 local expectednum=${2:-1} local message=${3:-Expected regexp "$pattern" not found exactly $expectednum times} local count=$(grep -sc -- "$pattern" $TEST_log) [[ $count = $expectednum ]] && return 0 fail "$message" return 1 } # Usage: expect_not_log <regexp> [error-message] # Asserts that $TEST_log does not match regexp. Prints the contents # of $TEST_log and the specified (optional) error message otherwise, and # returns non-zero. function expect_not_log() { local pattern=$1 local message=${2:-Unexpected regexp "$pattern" found} grep -sq -- "$pattern" $TEST_log || return 0 fail "$message" return 1 } # Usage: expect_log_with_timeout <regexp> <timeout> [error-message] # Waits for the given regexp in the $TEST_log for up to timeout seconds. # Prints the contents of $TEST_log and the specified (optional) # error message otherwise, and returns non-zero. function expect_log_with_timeout() { local pattern=$1 local timeout=$2 local message=${3:-Regexp "$pattern" not found in "$timeout" seconds} local count=0 while [ $count -lt $timeout ]; do grep -sq -- "$pattern" $TEST_log && return 0 let count=count+1 sleep 1 done grep -sq -- "$pattern" $TEST_log && return 0 fail "$message" return 1 } # Usage: expect_cmd_with_timeout <expected> <cmd> [timeout] # Repeats the command once a second for up to timeout seconds (10s by default), # until the output matches the expected value. Fails and returns 1 if # the command does not return the expected value in the end. function expect_cmd_with_timeout() { local expected="$1" local cmd="$2" local timeout=${3:-10} local count=0 while [ $count -lt $timeout ]; do local actual="$($cmd)" [ "$expected" = "$actual" ] && return 0 let count=count+1 sleep 1 done [ "$expected" = "$actual" ] && return 0 fail "Expected '$expected' within ${timeout}s, was '$actual'" return 1 } # Usage: assert_one_of <expected_list>... <actual> # Asserts that actual is one of the items in expected_list # Example: assert_one_of ( "foo", "bar", "baz" ) actualval function assert_one_of() { local args=("$@") local last_arg_index=$((${#args[@]} - 1)) local actual=${args[last_arg_index]} unset args[last_arg_index] for expected_item in "${args[@]}"; do [ "$expected_item" = "$actual" ] && return 0 done; fail "Expected one of '${args[@]}', was '$actual'" return 1 } # Usage: assert_equals <expected> <actual> # Asserts [ expected = actual ]. function assert_equals() { local expected=$1 actual=$2 [ "$expected" = "$actual" ] && return 0 fail "Expected '$expected', was '$actual'" return 1 } # Usage: assert_not_equals <unexpected> <actual> # Asserts [ unexpected != actual ]. function assert_not_equals() { local unexpected=$1 actual=$2 [ "$unexpected" != "$actual" ] && return 0; fail "Expected not '$unexpected', was '$actual'" return 1 } # Usage: assert_contains <regexp> <file> [error-message] # Asserts that file matches regexp. Prints the contents of # file and the specified (optional) error message otherwise, and # returns non-zero. function assert_contains() { local pattern=$1 local file=$2 local message=${3:-Expected regexp "$pattern" not found in "$file"} grep -sq -- "$pattern" "$file" && return 0 cat "$file" >&2 fail "$message" return 1 } # Usage: assert_not_contains <regexp> <file> [error-message] # Asserts that file does not match regexp. Prints the contents of # file and the specified (optional) error message otherwise, and # returns non-zero. function assert_not_contains() { local pattern=$1 local file=$2 local message=${3:-Expected regexp "$pattern" found in "$file"} grep -sq -- "$pattern" "$file" || return 0 cat "$file" >&2 fail "$message" return 1 } # Updates the global variables TESTS if # sharding is enabled, i.e. ($TEST_TOTAL_SHARDS > 0). function __update_shards() { [ -z "${TEST_TOTAL_SHARDS-}" ] && return 0 [ "$TEST_TOTAL_SHARDS" -gt 0 ] || { echo "Invalid total shards $TEST_TOTAL_SHARDS" >&2; exit 1; } [ "$TEST_SHARD_INDEX" -lt 0 -o "$TEST_SHARD_INDEX" -ge "$TEST_TOTAL_SHARDS" ] && { echo "Invalid shard $shard_index" >&2; exit 1; } TESTS=$(for test in "${TESTS[@]}"; do echo "$test"; done | awk "NR % $TEST_TOTAL_SHARDS == $TEST_SHARD_INDEX") [ -z "${TEST_SHARD_STATUS_FILE-}" ] || touch "$TEST_SHARD_STATUS_FILE" } # Usage: __test_terminated <signal-number> # Handler that is called when the test terminated unexpectedly function __test_terminated() { __show_log >&2 echo "$TEST_name FAILED: terminated by signal $1." >&2 TEST_passed="false" __show_stack timeout exit 1 } # Usage: __test_terminated_err # Handler that is called when the test terminated unexpectedly due to "errexit". function __test_terminated_err() { # When a subshell exits due to signal ERR, its parent shell also exits, # thus the signal handler is called recursively and we print out the # error message and stack trace multiple times. We're only interested # in the first one though, as it contains the most information, so ignore # all following. if [[ -f $TEST_TMPDIR/__err_handled ]]; then exit 1 fi __show_log >&2 if [[ ! -z "$TEST_name" ]]; then echo -n "$TEST_name " fi echo "FAILED: terminated because this command returned a non-zero status:" >&2 touch $TEST_TMPDIR/__err_handled TEST_passed="false" __show_stack # If $TEST_name is still empty, the test suite failed before we even started # to run tests, so we shouldn't call tear_down. if [[ ! -z "$TEST_name" ]]; then tear_down fi exit 1 } # Usage: __trap_with_arg <handler> <signals ...> # Helper to install a trap handler for several signals preserving the signal # number, so that the signal number is available to the trap handler. function __trap_with_arg() { func="$1" ; shift for sig ; do trap "$func $sig" "$sig" done } # Usage: <node> <block> # Adds the block to the given node in the report file. Quotes in the in # arguments need to be escaped. function __log_to_test_report() { local node="$1" local block="$2" if [[ ! -e "$XML_OUTPUT_FILE" ]]; then local xml_header='<?xml version="1.0" encoding="UTF-8"?>' echo "$xml_header<testsuites></testsuites>" > $XML_OUTPUT_FILE fi # replace match on node with block and match # replacement expression only needs escaping for quotes perl -e "\ \$input = @ARGV[0]; \ \$/=undef; \ open FILE, '+<$XML_OUTPUT_FILE'; \ \$content = <FILE>; \ if (\$content =~ /($node.*)\$/) { \ seek FILE, 0, 0; \ print FILE \$\` . \$input . \$1; \ }; \ close FILE" "$block" } # Usage: <total> <passed> # Adds the test summaries to the xml nodes. function __finish_test_report() { local total=$1 local passed=$2 local failed=$((total - passed)) cat $XML_OUTPUT_FILE | \ sed \ "s/<testsuites>/<testsuites tests=\"$total\" failures=\"0\" errors=\"$failed\">/" | \ sed \ "s/<testsuite>/<testsuite tests=\"$total\" failures=\"0\" errors=\"$failed\">/" \ > $XML_OUTPUT_FILE.bak rm -f $XML_OUTPUT_FILE mv $XML_OUTPUT_FILE.bak $XML_OUTPUT_FILE } # Multi-platform timestamp function UNAME=$(uname -s | tr 'A-Z' 'a-z') if [ "$UNAME" = "linux" ] || [[ "$UNAME" =~ msys_nt* ]]; then function timestamp() { echo $(($(date +%s%N)/1000000)) } else function timestamp() { # OS X and FreeBSD do not have %N so python is the best we can do python -c 'import time; print int(round(time.time() * 1000))' } fi function get_run_time() { local ts_start=$1 local ts_end=$2 run_time_ms=$((${ts_end}-${ts_start})) echo $(($run_time_ms/1000)).${run_time_ms: -3} } # Usage: run_tests <suite-comment> # Must be called from the end of the user's test suite. # Calls exit with zero on success, non-zero otherwise. function run_suite() { echo >&2 echo "$1" >&2 echo >&2 __log_to_test_report "<\/testsuites>" "<testsuite></testsuite>" local total=0 local passed=0 atexit "cleanup" # If the user didn't specify an explicit list of tests (e.g. a # working set), use them all. if [ ${#TESTS[@]} = 0 ]; then TESTS=$(declare -F | awk '{print $3}' | grep ^test_) elif [ -n "${TEST_WARNINGS_OUTPUT_FILE:-}" ]; then if grep -q "TESTS=" "$TEST_script" ; then echo "TESTS variable overridden in Bazel sh_test. Please remove before submitting" \ >> "$TEST_WARNINGS_OUTPUT_FILE" fi fi __update_shards for TEST_name in ${TESTS[@]}; do >$TEST_log # Reset the log. TEST_passed="true" total=$(($total + 1)) if [[ "$TEST_verbose" == "true" ]]; then __pad $TEST_name '*' >&2 fi local run_time="0.0" rm -f $TEST_TMPDIR/{__ts_start,__ts_end} if [ "$(type -t $TEST_name)" = function ]; then # Save exit handlers eventually set. local SAVED_ATEXIT="$ATEXIT"; ATEXIT= # Run test in a subshell. rm -f $TEST_TMPDIR/__err_handled __trap_with_arg __test_terminated INT KILL PIPE TERM ABRT FPE ILL QUIT SEGV ( timestamp >$TEST_TMPDIR/__ts_start set_up eval $TEST_name tear_down timestamp >$TEST_TMPDIR/__ts_end test $TEST_passed == "true" ) 2>&1 | tee $TEST_TMPDIR/__log # Note that tee will prevent the control flow continuing if the test # spawned any processes which are still running and have not closed # their stdout. test_subshell_status=${PIPESTATUS[0]} if [ "$test_subshell_status" != 0 ]; then TEST_passed="false" # Ensure that an end time is recorded in case the test subshell # terminated prematurely. [ -f $TEST_TMPDIR/__ts_end ] || timestamp >$TEST_TMPDIR/__ts_end fi # Calculate run time for the testcase. local ts_start=$(cat $TEST_TMPDIR/__ts_start) local ts_end=$(cat $TEST_TMPDIR/__ts_end) run_time=$(get_run_time $ts_start $ts_end) # Eventually restore exit handlers. if [ -n "$SAVED_ATEXIT" ]; then ATEXIT="$SAVED_ATEXIT" trap "$ATEXIT" EXIT fi else # Bad test explicitly specified in $TESTS. fail "Not a function: '$TEST_name'" fi local testcase_tag="" if [[ "$TEST_passed" == "true" ]]; then if [[ "$TEST_verbose" == "true" ]]; then echo "PASSED: $TEST_name" >&2 fi passed=$(($passed + 1)) testcase_tag="<testcase name=\"$TEST_name\" status=\"run\" time=\"$run_time\" classname=\"\"></testcase>" else echo "FAILED: $TEST_name" >&2 # end marker in CDATA cannot be escaped, we need to split the CDATA sections log=$(cat $TEST_TMPDIR/__log | sed 's/]]>/]]>]]><![CDATA[/g') fail_msg=$(cat $TEST_TMPDIR/__fail 2> /dev/null || echo "No failure message") testcase_tag="<testcase name=\"$TEST_name\" status=\"run\" time=\"$run_time\" classname=\"\"><error message=\"$fail_msg\"><![CDATA[$log]]></error></testcase>" fi if [[ "$TEST_verbose" == "true" ]]; then echo >&2 fi __log_to_test_report "<\/testsuite>" "$testcase_tag" done __finish_test_report $total $passed __pad "$passed / $total tests passed." '*' >&2 [ $total = $passed ] || { __pad "There were errors." '*' exit 1 } >&2 exit 0 } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������rules_cc-0.0.11/third_party/������������������������������������������������������������������������0000775�0000000�0000000�00000000000�14700725615�0015730�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������rules_cc-0.0.11/third_party/BUILD�������������������������������������������������������������������0000664�0000000�0000000�00000000103�14700725615�0016504�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Intentionally empty, only there to make //third_party a package. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������rules_cc-0.0.11/third_party/com/��������������������������������������������������������������������0000775�0000000�0000000�00000000000�14700725615�0016506�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������rules_cc-0.0.11/third_party/com/github/�������������������������������������������������������������0000775�0000000�0000000�00000000000�14700725615�0017770�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������rules_cc-0.0.11/third_party/com/github/bazelbuild/��������������������������������������������������0000775�0000000�0000000�00000000000�14700725615�0022105�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������rules_cc-0.0.11/third_party/com/github/bazelbuild/bazel/��������������������������������������������0000775�0000000�0000000�00000000000�14700725615�0023202�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������rules_cc-0.0.11/third_party/com/github/bazelbuild/bazel/src/����������������������������������������0000775�0000000�0000000�00000000000�14700725615�0023771�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������rules_cc-0.0.11/third_party/com/github/bazelbuild/bazel/src/main/�����������������������������������0000775�0000000�0000000�00000000000�14700725615�0024715�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������rules_cc-0.0.11/third_party/com/github/bazelbuild/bazel/src/main/protobuf/��������������������������0000775�0000000�0000000�00000000000�14700725615�0026555�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������rules_cc-0.0.11/third_party/com/github/bazelbuild/bazel/src/main/protobuf/BUILD���������������������0000664�0000000�0000000�00000001435�14700725615�0027342�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������load("@com_google_protobuf//:protobuf.bzl", "py_proto_library") load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") load("@rules_proto//proto:defs.bzl", "proto_library") licenses(["notice"]) # Apache 2.0 py_proto_library( name = "crosstool_config_py_pb2", srcs = ["crosstool_config.proto"], visibility = [ "//tools/migration:__pkg__", ], ) proto_library( name = "crosstool_config_pb2", srcs = ["crosstool_config.proto"], visibility = [ "//tools/migration:__pkg__", ], ) go_proto_library( name = "crosstool_config_go_proto", importpath = "third_party/com/github/bazelbuild/bazel/src/main/protobuf/crosstool_config_go_proto", proto = ":crosstool_config_pb2", visibility = [ "//tools/migration:__pkg__", ], ) �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������rules_cc-0.0.11/third_party/com/github/bazelbuild/bazel/src/main/protobuf/crosstool_config.proto����0000664�0000000�0000000�00000052733�14700725615�0033230�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������// Copyright 2014 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. // // File format for Blaze to configure Crosstool releases. syntax = "proto2"; package com.google.devtools.build.lib.view.config.crosstool; // option java_api_version = 2; // copybara-comment-this-out-please option java_package = "com.google.devtools.build.lib.view.config.crosstool"; // A description of a toolchain, which includes all the tools generally expected // to be available for building C/C++ targets, based on the GNU C compiler. // // System and cpu names are two overlapping concepts, which need to be both // supported at this time. The cpu name is the blaze command-line name for the // target system. The most common values are 'k8' and 'piii'. The system name is // a more generic identification of the executable system, based on the names // used by the GNU C compiler. // // Typically, the system name contains an identifier for the cpu (e.g. x86_64 or // alpha), an identifier for the machine (e.g. pc, or unknown), and an // identifier for the operating system (e.g. cygwin or linux-gnu). Typical // examples are 'x86_64-unknown-linux-gnu' and 'i686-unknown-cygwin'. // // The system name is used to determine if a given machine can execute a given // executable. In particular, it is used to check if the compilation products of // a toolchain can run on the host machine. message CToolchain { // A group of correlated flags. Supports parametrization via variable // expansion. // // To expand a variable of list type, flag_group has to be annotated with // `iterate_over` message. Then all nested flags or flag_groups will be // expanded repeatedly for each element of the list. // // For example: // flag_group { // iterate_over: 'include_path' // flag: '-I' // flag: '%{include_path}' // } // ... will get expanded to -I /to/path1 -I /to/path2 ... for each // include_path /to/pathN. // // To expand a variable of structure type, use dot-notation, e.g.: // flag_group { // iterate_over: "libraries_to_link" // flag_group { // iterate_over: "libraries_to_link.libraries" // flag: "-L%{libraries_to_link.libraries.directory}" // } // } // // Flag groups can be nested; if they are, the flag group must only contain // other flag groups (no flags) so the order is unambiguously specified. // In order to expand a variable of nested lists, 'iterate_over' can be used. // // For example: // flag_group { // iterate_over: 'object_files' // flag_group { flag: '--start-lib' } // flag_group { // iterate_over: 'object_files' // flag: '%{object_files}' // } // flag_group { flag: '--end-lib' } // } // ... will get expanded to // --start-lib a1.o a2.o ... --end-lib --start-lib b1.o b2.o .. --end-lib // with %{object_files} being a variable of nested list type // [['a1.o', 'a2.o', ...], ['b1.o', 'b2.o', ...], ...]. // // TODO(bazel-team): Write more elaborate documentation and add a link to it. message FlagGroup { repeated string flag = 1; repeated FlagGroup flag_group = 2; optional string iterate_over = 3; repeated string expand_if_all_available = 4; repeated string expand_if_none_available = 5; optional string expand_if_true = 6; optional string expand_if_false = 7; optional VariableWithValue expand_if_equal = 8; } message VariableWithValue { required string variable = 1; required string value = 2; } // A key/value pair to be added as an environment variable. The value of // this pair is expanded in the same way as is described in FlagGroup. // The key remains an unexpanded string literal. message EnvEntry { required string key = 1; required string value = 2; repeated string expand_if_all_available = 3; } // A set of features; used to support logical 'and' when specifying feature // requirements in Feature. message FeatureSet { repeated string feature = 1; } // A set of positive and negative features. This stanza will // evaluate to true when every 'feature' is enabled, and every // 'not_feature' is not enabled. message WithFeatureSet { repeated string feature = 1; repeated string not_feature = 2; } // A set of flags that are expanded in the command line for specific actions. message FlagSet { // The actions this flag set applies to; each flag set must specify at // least one action. repeated string action = 1; // The flags applied via this flag set. repeated FlagGroup flag_group = 2; // A list of feature sets defining when this flag set gets applied. The // flag set will be applied when any one of the feature sets evaluate to // true. (That is, when when every 'feature' is enabled, and every // 'not_feature' is not enabled.) // // If 'with_feature' is omitted, the flag set will be applied // unconditionally for every action specified. repeated WithFeatureSet with_feature = 3; // Deprecated (https://github.com/bazelbuild/bazel/issues/7008) - use // expand_if_all_available in flag_group // // A list of build variables that this feature set needs, but which are // allowed to not be set. If any of the build variables listed is not // set, the feature set will not be expanded. // // NOTE: Consider alternatives before using this; usually tools should // consistently create the same set of files, even if empty; use this // only for backwards compatibility with already existing behavior in tools // that are currently not worth changing. repeated string expand_if_all_available = 4; } // A set of environment variables that are expanded in the command line for // specific actions. message EnvSet { // The actions this env set applies to; each env set must specify at // least one action. repeated string action = 1; // The environment variables applied via this env set. repeated EnvEntry env_entry = 2; // A list of feature sets defining when this env set gets applied. The // env set will be applied when any one of the feature sets evaluate to // true. (That is, when when every 'feature' is enabled, and every // 'not_feature' is not enabled.) // // If 'with_feature' is omitted, the env set will be applied // unconditionally for every action specified. repeated WithFeatureSet with_feature = 3; } // Contains all flag specifications for one feature. // Next ID: 8 message Feature { // The feature's name. Feature names are generally defined by Bazel; it is // possible to introduce a feature without a change to Bazel by adding a // 'feature' section to the toolchain and adding the corresponding string as // feature in the BUILD file. optional string name = 1; // If 'true', this feature is enabled unless a rule type explicitly marks it // as unsupported. Such features cannot be turned off from within a BUILD // file or the command line. optional bool enabled = 7; // If the given feature is enabled, the flag sets will be applied for the // actions in the modes that they are specified for. repeated FlagSet flag_set = 2; // If the given feature is enabled, the env sets will be applied for the // actions in the modes that they are specified for. repeated EnvSet env_set = 6; // A list of feature sets defining when this feature is supported by the // toolchain. The feature is supported if any of the feature sets fully // apply, that is, when all features of a feature set are enabled. // // If 'requires' is omitted, the feature is supported independently of which // other features are enabled. // // Use this for example to filter flags depending on the build mode // enabled (opt / fastbuild / dbg). repeated FeatureSet requires = 3; // A list of features or action configs that are automatically enabled when // this feature is enabled. If any of the implied features or action configs // cannot be enabled, this feature will (silently) not be enabled either. repeated string implies = 4; // A list of names this feature conflicts with. // A feature cannot be enabled if: // - 'provides' contains the name of a different feature or action config // that we want to enable. // - 'provides' contains the same value as a 'provides' in a different // feature or action config that we want to enable. // // Use this in order to ensure that incompatible features cannot be // accidentally activated at the same time, leading to hard to diagnose // compiler errors. repeated string provides = 5; } // Describes a tool associated with a crosstool action config. message Tool { // Describes the origin of a path. enum PathOrigin { // Indicates that `tool_path` is relative to the location of the // crosstool. For legacy reasons, absolute paths are als0 allowed here. CROSSTOOL_PACKAGE = 0; // Indicates that `tool_path` is an absolute path. // This is enforced by Bazel. FILESYSTEM_ROOT = 1; // Indicates that `tool_path` is relative to the current workspace's // exec root. WORKSPACE_ROOT = 2; } // Path to the tool, relative to the location of the crosstool. required string tool_path = 1; // Origin of `tool_path`. // Optional only for legacy reasons. New crosstools should set this value! optional PathOrigin tool_path_origin = 4 [default = CROSSTOOL_PACKAGE]; // A list of feature sets defining when this tool is applicable. The tool // will used when any one of the feature sets evaluate to true. (That is, // when when every 'feature' is enabled, and every 'not_feature' is not // enabled.) // // If 'with_feature' is omitted, the tool will apply for any feature // configuration. repeated WithFeatureSet with_feature = 2; // Requirements on the execution environment for the execution of this tool, // to be passed as out-of-band "hints" to the execution backend. // Ex. "requires-darwin" repeated string execution_requirement = 3; } // The name for an artifact of a given category of input or output artifacts // to an action. message ArtifactNamePattern { // The category of artifacts that this selection applies to. This field // is compared against a list of categories defined in bazel. Example // categories include "linked_output" or "debug_symbols". An error is thrown // if no category is matched. required string category_name = 1; // The prefix and extension for creating the artifact for this selection. // They are used to create an artifact name based on the target name. required string prefix = 2; required string extension = 3; } // An action config corresponds to a blaze action, and allows selection of // a tool based on activated features. Action configs come in two varieties: // automatic (the blaze action will exist whether or not the action config // is activated) and attachable (the blaze action will be added to the // action graph only if the action config is activated). // // Action config activation occurs by the same semantics as features: a // feature can 'require' or 'imply' an action config in the same way that it // would another feature. // Next ID: 9 message ActionConfig { // The name other features will use to activate this action config. Can // be the same as action_name. required string config_name = 1; // The name of the blaze action that this config applies to, ex. 'c-compile' // or 'c-module-compile'. required string action_name = 2; // If 'true', this feature is enabled unless a rule type explicitly marks it // as unsupported. Such action_configs cannot be turned off from within a // BUILD file or the command line. optional bool enabled = 8; // The tool applied to the action will be the first Tool with a feature // set that matches the feature configuration. An error will be thrown // if no tool matches a provided feature configuration - for that reason, // it's a good idea to provide a default tool with an empty feature set. repeated Tool tool = 3; // If the given action config is enabled, the flag sets will be applied // to the corresponding action. repeated FlagSet flag_set = 4; // If the given action config is enabled, the env sets will be applied // to the corresponding action. repeated EnvSet env_set = 5; // A list of feature sets defining when this action config // is supported by the toolchain. The action config is supported if any of // the feature sets fully apply, that is, when all features of a // feature set are enabled. // // If 'requires' is omitted, the action config is supported independently // of which other features are enabled. // // Use this for example to filter actions depending on the build // mode enabled (opt / fastbuild / dbg). repeated FeatureSet requires = 6; // A list of features or action configs that are automatically enabled when // this action config is enabled. If any of the implied features or action // configs cannot be enabled, this action config will (silently) // not be enabled either. repeated string implies = 7; } repeated Feature feature = 50; repeated ActionConfig action_config = 53; repeated ArtifactNamePattern artifact_name_pattern = 54; // The unique identifier of the toolchain within the crosstool release. It // must be possible to use this as a directory name in a path. // It has to match the following regex: [a-zA-Z_][\.\- \w]* required string toolchain_identifier = 1; // A basic toolchain description. required string host_system_name = 2; required string target_system_name = 3; required string target_cpu = 4; required string target_libc = 5; required string compiler = 6; required string abi_version = 7; required string abi_libc_version = 8; // Tool locations. Relative paths are resolved relative to the configuration // file directory. // NOTE: DEPRECATED. Prefer specifying an ActionConfig for the action that // needs the tool. // TODO(b/27903698) migrate to ActionConfig. repeated ToolPath tool_path = 9; // Feature flags. // TODO(bazel-team): Sink those into 'Feature' instances. // Legacy field, ignored by Bazel. optional bool supports_gold_linker = 10 [default = false]; // Legacy field, ignored by Bazel. optional bool supports_thin_archives = 11 [default = false]; // Legacy field, use 'supports_start_end_lib' feature instead. optional bool supports_start_end_lib = 28 [default = false]; // Legacy field, use 'supports_interface_shared_libraries' instead. optional bool supports_interface_shared_objects = 32 [default = false]; // Legacy field, use 'static_link_cpp_runtimes' feature instead. optional bool supports_embedded_runtimes = 40 [default = false]; // If specified, Blaze finds statically linked / dynamically linked runtime // libraries in the declared crosstool filegroup. Otherwise, Blaze // looks in "[static|dynamic]-runtime-libs-$TARGET_CPU". // Deprecated, see https://github.com/bazelbuild/bazel/issues/6942 optional string static_runtimes_filegroup = 45; // Deprecated, see https://github.com/bazelbuild/bazel/issues/6942 optional string dynamic_runtimes_filegroup = 46; // Legacy field, ignored by Bazel. optional bool supports_incremental_linker = 41 [default = false]; // Legacy field, ignored by Bazel. optional bool supports_normalizing_ar = 26 [default = false]; // Legacy field, use 'per_object_debug_info' feature instead. optional bool supports_fission = 43 [default = false]; // Legacy field, ignored by Bazel. optional bool supports_dsym = 51 [default = false]; // Legacy field, use 'supports_pic' feature instead optional bool needsPic = 12 [default = false]; // Compiler flags for C/C++/Asm compilation. repeated string compiler_flag = 13; // Additional compiler flags for C++ compilation. repeated string cxx_flag = 14; // Additional unfiltered compiler flags for C/C++/Asm compilation. // These are not subject to nocopt filtering in cc_* rules. // Note: These flags are *not* applied to objc/objc++ compiles. repeated string unfiltered_cxx_flag = 25; // Linker flags. repeated string linker_flag = 15; // Additional linker flags when linking dynamic libraries. repeated string dynamic_library_linker_flag = 27; // Additional test-only linker flags. repeated string test_only_linker_flag = 49; // Objcopy flags for embedding files into binaries. repeated string objcopy_embed_flag = 16; // Ld flags for embedding files into binaries. This is used by filewrapper // since it calls ld directly and needs to know what -m flag to pass. repeated string ld_embed_flag = 23; // Ar flags for combining object files into archives. If this is not set, it // defaults to "rcsD". // TODO(b/37271982): Remove after blaze with ar action_config release repeated string ar_flag = 47; // Legacy field, ignored by Bazel. repeated string ar_thin_archives_flag = 48; // Legacy field, ignored by Bazel. repeated string gcc_plugin_compiler_flag = 34; // Additional compiler and linker flags depending on the compilation mode. repeated CompilationModeFlags compilation_mode_flags = 17; // Additional linker flags depending on the linking mode. repeated LinkingModeFlags linking_mode_flags = 18; // Legacy field, ignored by Bazel. repeated string gcc_plugin_header_directory = 19; // Legacy field, ignored by Bazel. repeated string mao_plugin_header_directory = 20; // Make variables that are made accessible to rules. repeated MakeVariable make_variable = 21; // Built-in include directories for C++ compilation. These should be the exact // paths used by the compiler, and are generally relative to the exec root. // The paths used by the compiler can be determined by 'gcc -Wp,-v some.c'. // We currently use the C++ paths also for C compilation, which is safe as // long as there are no name clashes between C++ and C header files. // // Relative paths are resolved relative to the configuration file directory. // // If the compiler has --sysroot support, then these paths should use // %sysroot% rather than the include path, and specify the sysroot attribute // in order to give blaze the information necessary to make the correct // replacements. repeated string cxx_builtin_include_directory = 22; // The built-in sysroot. If this attribute is not present, blaze does not // allow using a different sysroot, i.e. through the --grte_top option. Also // see the documentation above. optional string builtin_sysroot = 24; // Legacy field, ignored by Bazel. optional string default_python_top = 29; // Legacy field, ignored by Bazel. optional string default_python_version = 30; // Legacy field, ignored by Bazel. optional bool python_preload_swigdeps = 42; // The default GRTE to use. This should be a label, and gets the same // treatment from Blaze as the --grte_top option. This setting is only used in // the absence of an explicit --grte_top option. If unset, Blaze will not pass // -sysroot by default. The local part must be 'everything', i.e., // '//some/label:everything'. There can only be one GRTE library per package, // because the compiler expects the directory as a parameter of the -sysroot // option. // This may only be set to a non-empty value if builtin_sysroot is also set! optional string default_grte_top = 31; // Legacy field, ignored by Bazel. repeated string debian_extra_requires = 33; // Legacy field, ignored by Bazel. Only there for compatibility with // things internal to Google. optional string cc_target_os = 55; // Next free id: 56 } message ToolPath { required string name = 1; required string path = 2; } enum CompilationMode { FASTBUILD = 1; DBG = 2; OPT = 3; // This value is ignored and should not be used in new files. COVERAGE = 4; } message CompilationModeFlags { required CompilationMode mode = 1; repeated string compiler_flag = 2; repeated string cxx_flag = 3; // Linker flags that are added when compiling in a certain mode. repeated string linker_flag = 4; } enum LinkingMode { FULLY_STATIC = 1; MOSTLY_STATIC = 2; DYNAMIC = 3; MOSTLY_STATIC_LIBRARIES = 4; } message LinkingModeFlags { required LinkingMode mode = 1; repeated string linker_flag = 2; } message MakeVariable { required string name = 1; required string value = 2; } message DefaultCpuToolchain { required string cpu = 1; required string toolchain_identifier = 2; } // An entire crosstool release, containing the version number, and a set of // toolchains. message CrosstoolRelease { // The major and minor version of the crosstool release. required string major_version = 1; required string minor_version = 2; // Legacy field, ignored by Bazel. optional string default_target_cpu = 3; // Legacy field, ignored by Bazel. repeated DefaultCpuToolchain default_toolchain = 4; // All the toolchains in this release. repeated CToolchain toolchain = 5; } �������������������������������������rules_cc-0.0.11/third_party/six.BUILD���������������������������������������������������������������0000664�0000000�0000000�00000000541�14700725615�0017314�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Description: # Six provides simple utilities for wrapping over differences between Python 2 # and Python 3. load("@rules_python//python:defs.bzl", "py_library") licenses(["notice"]) # MIT exports_files(["LICENSE"]) py_library( name = "six", srcs = ["six.py"], srcs_version = "PY2AND3", visibility = ["//visibility:public"], ) ���������������������������������������������������������������������������������������������������������������������������������������������������������������rules_cc-0.0.11/tools/������������������������������������������������������������������������������0000775�0000000�0000000�00000000000�14700725615�0014537�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������rules_cc-0.0.11/tools/migration/��������������������������������������������������������������������0000775�0000000�0000000�00000000000�14700725615�0016530�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������rules_cc-0.0.11/tools/migration/BUILD���������������������������������������������������������������0000664�0000000�0000000�00000010406�14700725615�0017313�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Copyright 2018 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. load("@bazel_skylib//:bzl_library.bzl", "bzl_library") load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library", "go_test") load("@rules_python//python:defs.bzl", "py_binary", "py_library", "py_test") package(default_visibility = ["//visibility:public"]) licenses(["notice"]) py_binary( name = "legacy_fields_migrator", srcs = ["legacy_fields_migrator.py"], python_version = "PY3", deps = [ ":legacy_fields_migration_lib", "//third_party/com/github/bazelbuild/bazel/src/main/protobuf:crosstool_config_py_pb2", "@io_abseil_py//absl:app", "@io_abseil_py//absl/flags", #internal proto upb dep, ], ) py_library( name = "legacy_fields_migration_lib", srcs = ["legacy_fields_migration_lib.py"], deps = [ "//third_party/com/github/bazelbuild/bazel/src/main/protobuf:crosstool_config_py_pb2", ], ) py_test( name = "legacy_fields_migration_lib_test", srcs = ["legacy_fields_migration_lib_test.py"], python_version = "PY3", deps = [ ":legacy_fields_migration_lib", "//third_party/com/github/bazelbuild/bazel/src/main/protobuf:crosstool_config_py_pb2", ], ) py_binary( name = "crosstool_query", srcs = ["crosstool_query.py"], python_version = "PY3", deps = [ "//third_party/com/github/bazelbuild/bazel/src/main/protobuf:crosstool_config_py_pb2", "@io_abseil_py//absl:app", "@io_abseil_py//absl/flags", #internal proto upb dep, ], ) py_binary( name = "ctoolchain_comparator", srcs = ["ctoolchain_comparator.py"], python_version = "PY3", deps = [ ":ctoolchain_comparator_lib", "//third_party/com/github/bazelbuild/bazel/src/main/protobuf:crosstool_config_py_pb2", "@io_abseil_py//absl:app", "@io_abseil_py//absl/flags", #internal proto upb dep, ], ) py_library( name = "ctoolchain_comparator_lib", srcs = ["ctoolchain_comparator_lib.py"], deps = [ "//third_party/com/github/bazelbuild/bazel/src/main/protobuf:crosstool_config_py_pb2", ], ) py_test( name = "ctoolchain_comparator_lib_test", srcs = ["ctoolchain_comparator_lib_test.py"], python_version = "PY3", deps = [ ":ctoolchain_comparator_lib", "//third_party/com/github/bazelbuild/bazel/src/main/protobuf:crosstool_config_py_pb2", "@py_mock//py/mock", ], ) go_binary( name = "convert_crosstool_to_starlark", srcs = ["convert_crosstool_to_starlark.go"], deps = [ ":crosstooltostarlarklib", "//third_party/com/github/bazelbuild/bazel/src/main/protobuf:crosstool_config_go_proto", "@com_github_golang_protobuf//proto:go_default_library", ], ) go_library( name = "crosstooltostarlarklib", srcs = ["crosstool_to_starlark_lib.go"], importpath = "tools/migration/crosstooltostarlarklib", deps = ["//third_party/com/github/bazelbuild/bazel/src/main/protobuf:crosstool_config_go_proto"], ) go_test( name = "crosstooltostarlarklib_test", size = "small", srcs = ["crosstool_to_starlark_lib_test.go"], embed = [":crosstooltostarlarklib"], deps = [ "//third_party/com/github/bazelbuild/bazel/src/main/protobuf:crosstool_config_go_proto", "@com_github_golang_protobuf//proto:go_default_library", ], ) filegroup( name = "bazel_osx_p4deps", srcs = [ "BUILD", "ctoolchain_compare.bzl", ], ) bzl_library( name = "ctoolchain_compare_bzl", srcs = ["ctoolchain_compare.bzl"], visibility = ["//visibility:private"], ) bzl_library( name = "cc_toolchain_config_comparator_bzl", srcs = ["cc_toolchain_config_comparator.bzl"], visibility = ["//visibility:private"], ) ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������rules_cc-0.0.11/tools/migration/cc_toolchain_config_comparator.bzl����������������������������������0000664�0000000�0000000�00000003376�14700725615�0025453�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""A test rule that compares two C++ toolchain configuration rules in proto format.""" def _impl(ctx): first_toolchain_config_proto = ctx.actions.declare_file( ctx.label.name + "_first_toolchain_config.proto", ) ctx.actions.write( first_toolchain_config_proto, ctx.attr.first[CcToolchainConfigInfo].proto, ) second_toolchain_config_proto = ctx.actions.declare_file( ctx.label.name + "_second_toolchain_config.proto", ) ctx.actions.write( second_toolchain_config_proto, ctx.attr.second[CcToolchainConfigInfo].proto, ) script = ("%s --before='%s' --after='%s'" % ( ctx.executable._comparator.short_path, first_toolchain_config_proto.short_path, second_toolchain_config_proto.short_path, )) test_executable = ctx.actions.declare_file(ctx.label.name) ctx.actions.write(test_executable, script, is_executable = True) runfiles = ctx.runfiles(files = [first_toolchain_config_proto, second_toolchain_config_proto]) runfiles = runfiles.merge(ctx.attr._comparator[DefaultInfo].default_runfiles) return DefaultInfo(runfiles = runfiles, executable = test_executable) cc_toolchain_config_compare_test = rule( implementation = _impl, attrs = { "first": attr.label( mandatory = True, providers = [CcToolchainConfigInfo], doc = "A C++ toolchain config rule", ), "second": attr.label( mandatory = True, providers = [CcToolchainConfigInfo], doc = "A C++ toolchain config rule", ), "_comparator": attr.label( default = ":ctoolchain_comparator", executable = True, cfg = "exec", ), }, test = True, ) ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������rules_cc-0.0.11/tools/migration/convert_crosstool_to_starlark.go������������������������������������0000664�0000000�0000000�00000004612�14700725615�0025256�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* The convert_crosstool_to_starlark script takes in a CROSSTOOL file and generates a Starlark rule. See https://github.com/bazelbuild/bazel/issues/5380 Example usage: bazel run \ @rules_cc//tools/migration:convert_crosstool_to_starlark -- \ --crosstool=/path/to/CROSSTOOL \ --output_location=/path/to/cc_config.bzl */ package main import ( "flag" "fmt" "io/ioutil" "os" "os/user" "path" "strings" // Google internal base/go package, commented out by copybara "log" crosstoolpb "third_party/com/github/bazelbuild/bazel/src/main/protobuf/crosstool_config_go_proto" "github.com/golang/protobuf/proto" "tools/migration/crosstooltostarlarklib" ) var ( crosstoolLocation = flag.String( "crosstool", "", "Location of the CROSSTOOL file") outputLocation = flag.String( "output_location", "", "Location of the output .bzl file") ) func toAbsolutePath(pathString string) (string, error) { usr, err := user.Current() if err != nil { return "", err } homeDir := usr.HomeDir if strings.HasPrefix(pathString, "~") { return path.Join(homeDir, pathString[1:]), nil } if path.IsAbs(pathString) { return pathString, nil } workingDirectory := os.Getenv("BUILD_WORKING_DIRECTORY") return path.Join(workingDirectory, pathString), nil } func main() { flag.Parse() if *crosstoolLocation == "" { log.Fatalf("Missing mandatory argument 'crosstool'") } crosstoolPath, err := toAbsolutePath(*crosstoolLocation) if err != nil { log.Fatalf("Error while resolving CROSSTOOL location:", err) } if *outputLocation == "" { log.Fatalf("Missing mandatory argument 'output_location'") } outputPath, err := toAbsolutePath(*outputLocation) if err != nil { log.Fatalf("Error resolving output location:", err) } in, err := ioutil.ReadFile(crosstoolPath) if err != nil { log.Fatalf("Error reading CROSSTOOL file:", err) } crosstool := &crosstoolpb.CrosstoolRelease{} if err := proto.UnmarshalText(string(in), crosstool); err != nil { log.Fatalf("Failed to parse CROSSTOOL:", err) } file, err := os.Create(outputPath) if err != nil { log.Fatalf("Error creating output file:", err) } defer file.Close() rule, err := crosstooltostarlarklib.Transform(crosstool) if err != nil { log.Fatalf("Error converting CROSSTOOL to a Starlark rule:", err) } if _, err := file.WriteString(rule); err != nil { log.Fatalf("Error converting CROSSTOOL to a Starlark rule:", err) } fmt.Println("Success!") } ����������������������������������������������������������������������������������������������������������������������rules_cc-0.0.11/tools/migration/crosstool_query.py��������������������������������������������������0000664�0000000�0000000�00000003205�14700725615�0022356�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Script to make automated CROSSTOOL refactorings easier. This script reads the CROSSTOOL file and allows for querying of its fields. """ from absl import app from absl import flags from google.protobuf import text_format from third_party.com.github.bazelbuild.bazel.src.main.protobuf import crosstool_config_pb2 flags.DEFINE_string("crosstool", None, "CROSSTOOL file path to be queried") flags.DEFINE_string("identifier", None, "Toolchain identifier to specify toolchain.") flags.DEFINE_string("print_field", None, "Field to be printed to stdout.") def main(unused_argv): crosstool = crosstool_config_pb2.CrosstoolRelease() crosstool_filename = flags.FLAGS.crosstool identifier = flags.FLAGS.identifier print_field = flags.FLAGS.print_field if not crosstool_filename: raise app.UsageError("ERROR crosstool unspecified") if not identifier: raise app.UsageError("ERROR identifier unspecified") if not print_field: raise app.UsageError("ERROR print_field unspecified") with open(crosstool_filename, "r") as f: text = f.read() text_format.Merge(text, crosstool) toolchain_found = False for toolchain in crosstool.toolchain: if toolchain.toolchain_identifier == identifier: toolchain_found = True if not print_field: continue for field, value in toolchain.ListFields(): if print_field == field.name: print value if not toolchain_found: print "toolchain_identifier %s not found, valid values are:" % identifier for toolchain in crosstool.toolchain: print " " + toolchain.toolchain_identifier if __name__ == "__main__": app.run(main) �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������rules_cc-0.0.11/tools/migration/crosstool_to_starlark_lib.go����������������������������������������0000664�0000000�0000000�00000125375�14700725615�0024356�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Package crosstooltostarlarklib provides the Transform method for conversion of a CROSSTOOL file to a Starlark rule. https://github.com/bazelbuild/bazel/issues/5380 */ package crosstooltostarlarklib import ( "bytes" "errors" "fmt" "sort" "strings" crosstoolpb "third_party/com/github/bazelbuild/bazel/src/main/protobuf/crosstool_config_go_proto" ) // CToolchainIdentifier is what we'll use to differ between CToolchains // If a CToolchain can be distinguished from the other CToolchains // by only one of the fields (eg if cpu is different for each CToolchain // then only that field will be set. type CToolchainIdentifier struct { cpu string compiler string } // Writes the load statement for the cc_toolchain_config_lib func getCcToolchainConfigHeader() string { return `load("@rules_cc//cc:cc_toolchain_config_lib.bzl", "action_config", "artifact_name_pattern", "env_entry", "env_set", "feature", "feature_set", "flag_group", "flag_set", "make_variable", "tool", "tool_path", "variable_with_value", "with_feature_set", ) ` } var allCompileActions = []string{ "c-compile", "c++-compile", "linkstamp-compile", "assemble", "preprocess-assemble", "c++-header-parsing", "c++-module-compile", "c++-module-codegen", "clif-match", "lto-backend", } var allCppCompileActions = []string{ "c++-compile", "linkstamp-compile", "c++-header-parsing", "c++-module-compile", "c++-module-codegen", "clif-match", } var preprocessorCompileActions = []string{ "c-compile", "c++-compile", "linkstamp-compile", "preprocess-assemble", "c++-header-parsing", "c++-module-compile", "clif-match", } var codegenCompileActions = []string{ "c-compile", "c++-compile", "linkstamp-compile", "assemble", "preprocess-assemble", "c++-module-codegen", "lto-backend", } var allLinkActions = []string{ "c++-link-executable", "c++-link-dynamic-library", "c++-link-nodeps-dynamic-library", } var actionNames = map[string]string{ "c-compile": "ACTION_NAMES.c_compile", "c++-compile": "ACTION_NAMES.cpp_compile", "linkstamp-compile": "ACTION_NAMES.linkstamp_compile", "cc-flags-make-variable": "ACTION_NAMES.cc_flags_make_variable", "c++-module-codegen": "ACTION_NAMES.cpp_module_codegen", "c++-header-parsing": "ACTION_NAMES.cpp_header_parsing", "c++-module-compile": "ACTION_NAMES.cpp_module_compile", "assemble": "ACTION_NAMES.assemble", "preprocess-assemble": "ACTION_NAMES.preprocess_assemble", "lto-indexing": "ACTION_NAMES.lto_indexing", "lto-backend": "ACTION_NAMES.lto_backend", "c++-link-executable": "ACTION_NAMES.cpp_link_executable", "c++-link-dynamic-library": "ACTION_NAMES.cpp_link_dynamic_library", "c++-link-nodeps-dynamic-library": "ACTION_NAMES.cpp_link_nodeps_dynamic_library", "c++-link-static-library": "ACTION_NAMES.cpp_link_static_library", "strip": "ACTION_NAMES.strip", "objc-compile": "ACTION_NAMES.objc_compile", "objc++-compile": "ACTION_NAMES.objcpp_compile", "clif-match": "ACTION_NAMES.clif_match", // "objcopy_embed_data": "ACTION_NAMES.objcopy_embed_data", // copybara-comment-this-out-please // "ld_embed_data": "ACTION_NAMES.ld_embed_data", // copybara-comment-this-out-please } func getLoadActionsStmt() string { return "load(\"@rules_cc//cc:action_names.bzl\", \"ACTION_NAMES\")\n\n" } // Returns a map {toolchain_identifier : CToolchainIdentifier} func toolchainToCToolchainIdentifier( crosstool *crosstoolpb.CrosstoolRelease) map[string]CToolchainIdentifier { cpuToCompiler := make(map[string][]string) compilerToCPU := make(map[string][]string) var cpus []string var compilers []string var identifiers []string res := make(map[string]CToolchainIdentifier) for _, cToolchain := range crosstool.GetToolchain() { cpu := cToolchain.GetTargetCpu() compiler := cToolchain.GetCompiler() cpuToCompiler[cpu] = append(cpuToCompiler[cpu], compiler) compilerToCPU[compiler] = append(compilerToCPU[compiler], cpu) cpus = append(cpus, cToolchain.GetTargetCpu()) compilers = append(compilers, cToolchain.GetCompiler()) identifiers = append(identifiers, cToolchain.GetToolchainIdentifier()) } for i := range cpus { if len(cpuToCompiler[cpus[i]]) == 1 { // if cpu is unique among CToolchains, we don't need the compiler field res[identifiers[i]] = CToolchainIdentifier{cpu: cpus[i], compiler: ""} } else { res[identifiers[i]] = CToolchainIdentifier{ cpu: cpus[i], compiler: compilers[i], } } } return res } func getConditionStatementForCToolchainIdentifier(identifier CToolchainIdentifier) string { if identifier.compiler != "" { return fmt.Sprintf( "ctx.attr.cpu == \"%s\" and ctx.attr.compiler == \"%s\"", identifier.cpu, identifier.compiler) } return fmt.Sprintf("ctx.attr.cpu == \"%s\"", identifier.cpu) } func isArrayPrefix(prefix []string, arr []string) bool { if len(prefix) > len(arr) { return false } for i := 0; i < len(prefix); i++ { if arr[i] != prefix[i] { return false } } return true } func isAllCompileActions(actions []string) (bool, []string) { if isArrayPrefix(allCompileActions, actions) { return true, actions[len(allCompileActions):] } return false, actions } func isAllCppCompileActions(actions []string) (bool, []string) { if isArrayPrefix(allCppCompileActions, actions) { return true, actions[len(allCppCompileActions):] } return false, actions } func isPreprocessorCompileActions(actions []string) (bool, []string) { if isArrayPrefix(preprocessorCompileActions, actions) { return true, actions[len(preprocessorCompileActions):] } return false, actions } func isCodegenCompileActions(actions []string) (bool, []string) { if isArrayPrefix(codegenCompileActions, actions) { return true, actions[len(codegenCompileActions):] } return false, actions } func isAllLinkActions(actions []string) (bool, []string) { if isArrayPrefix(allLinkActions, actions) { return true, actions[len(allLinkActions):] } return false, actions } func getActionNames(actions []string) []string { var res []string for _, el := range actions { if name, ok := actionNames[el]; ok { res = append(res, name) } else { res = append(res, "\""+el+"\"") } } return res } func getListOfActions(name string, depth int) string { var res []string if name == "all_compile_actions" { res = getActionNames(allCompileActions) } else if name == "all_cpp_compile_actions" { res = getActionNames(allCppCompileActions) } else if name == "preprocessor_compile_actions" { res = getActionNames(preprocessorCompileActions) } else if name == "codegen_compile_actions" { res = getActionNames(codegenCompileActions) } else if name == "all_link_actions" { res = getActionNames(allLinkActions) } stmt := fmt.Sprintf("%s%s = %s\n\n", getTabs(depth), name, makeStringArr(res, depth /* isPlainString= */, false)) return stmt } func processActions(actions []string, depth int) []string { var res []string var ok bool initLen := len(actions) if ok, actions = isAllCompileActions(actions); ok { res = append(res, "all_compile_actions") } if ok, actions = isAllCppCompileActions(actions); ok { res = append(res, "all_cpp_compile_actions") } if ok, actions = isPreprocessorCompileActions(actions); ok { res = append(res, "preprocessor_compile_actions") } if ok, actions = isCodegenCompileActions(actions); ok { res = append(res, "codegen_actions") } if ok, actions = isAllLinkActions(actions); ok { res = append(res, "all_link_actions") } if len(actions) != 0 { actions = getActionNames(actions) newDepth := depth + 1 if len(actions) != initLen { newDepth++ } res = append(res, makeStringArr(actions, newDepth /* isPlainString= */, false)) } return res } func getUniqueValues(arr []string) []string { valuesSet := make(map[string]bool) for _, val := range arr { valuesSet[val] = true } var uniques []string for val, _ := range valuesSet { uniques = append(uniques, val) } sort.Strings(uniques) return uniques } func getRule(cToolchainIdentifiers map[string]CToolchainIdentifier, allowedCompilers []string) string { cpus := make(map[string]bool) shouldUseCompilerAttribute := false for _, val := range cToolchainIdentifiers { cpus[val.cpu] = true if val.compiler != "" { shouldUseCompilerAttribute = true } } var cpuValues []string for cpu := range cpus { cpuValues = append(cpuValues, cpu) } var args []string sort.Strings(cpuValues) args = append(args, fmt.Sprintf( `"cpu": attr.string(mandatory=True, values=["%s"]),`, strings.Join(cpuValues, "\", \""))) if shouldUseCompilerAttribute { // If there are two CToolchains that share the cpu we need the compiler attribute // for our cc_toolchain_config rule. allowedCompilers = getUniqueValues(allowedCompilers) args = append(args, fmt.Sprintf(`"compiler": attr.string(mandatory=True, values=["%s"]),`, strings.Join(allowedCompilers, "\", \""))) } return fmt.Sprintf(`cc_toolchain_config = rule( implementation = _impl, attrs = { %s }, provides = [CcToolchainConfigInfo], executable = True, ) `, strings.Join(args, "\n ")) } func getImplHeader() string { return "def _impl(ctx):\n" } func getStringStatement(crosstool *crosstoolpb.CrosstoolRelease, cToolchainIdentifiers map[string]CToolchainIdentifier, field string, depth int) string { identifiers := getToolchainIdentifiers(crosstool) var fieldValues []string if field == "toolchain_identifier" { fieldValues = getToolchainIdentifiers(crosstool) } else if field == "host_system_name" { fieldValues = getHostSystemNames(crosstool) } else if field == "target_system_name" { fieldValues = getTargetSystemNames(crosstool) } else if field == "target_cpu" { fieldValues = getTargetCpus(crosstool) } else if field == "target_libc" { fieldValues = getTargetLibcs(crosstool) } else if field == "compiler" { fieldValues = getCompilers(crosstool) } else if field == "abi_version" { fieldValues = getAbiVersions(crosstool) } else if field == "abi_libc_version" { fieldValues = getAbiLibcVersions(crosstool) } else if field == "cc_target_os" { fieldValues = getCcTargetOss(crosstool) } else if field == "builtin_sysroot" { fieldValues = getBuiltinSysroots(crosstool) } mappedValuesToIds := getMappedStringValuesToIdentifiers(identifiers, fieldValues) return getAssignmentStatement(field, mappedValuesToIds, crosstool, cToolchainIdentifiers, depth /* isPlainString= */, true /* shouldFail= */, true) } func getFeatures(crosstool *crosstoolpb.CrosstoolRelease) ( map[string][]string, map[string]map[string][]string, error) { featureNameToFeature := make(map[string]map[string][]string) toolchainToFeatures := make(map[string][]string) for _, toolchain := range crosstool.GetToolchain() { id := toolchain.GetToolchainIdentifier() if len(toolchain.GetFeature()) == 0 { toolchainToFeatures[id] = []string{} } for _, feature := range toolchain.GetFeature() { featureName := strings.ToLower(feature.GetName()) + "_feature" featureName = strings.Replace(featureName, "+", "p", -1) featureName = strings.Replace(featureName, ".", "_", -1) featureName = strings.Replace(featureName, "-", "_", -1) stringFeature, err := parseFeature(feature, 1) if err != nil { return nil, nil, fmt.Errorf( "Error in feature '%s': %v", feature.GetName(), err) } if _, ok := featureNameToFeature[featureName]; !ok { featureNameToFeature[featureName] = make(map[string][]string) } featureNameToFeature[featureName][stringFeature] = append( featureNameToFeature[featureName][stringFeature], id) toolchainToFeatures[id] = append(toolchainToFeatures[id], featureName) } } return toolchainToFeatures, featureNameToFeature, nil } func getFeaturesDeclaration(crosstool *crosstoolpb.CrosstoolRelease, cToolchainIdentifiers map[string]CToolchainIdentifier, featureNameToFeature map[string]map[string][]string, depth int) string { var res []string for featureName, featureStringToID := range featureNameToFeature { res = append(res, getAssignmentStatement( featureName, featureStringToID, crosstool, cToolchainIdentifiers, depth, /* isPlainString= */ false, /* shouldFail= */ false)) } return strings.Join(res, "") } func getFeaturesStmt(cToolchainIdentifiers map[string]CToolchainIdentifier, toolchainToFeatures map[string][]string, depth int) string { var res []string arrToIdentifier := make(map[string][]string) for id, features := range toolchainToFeatures { arrayString := strings.Join(features, "{arrayFieldDelimiter}") arrToIdentifier[arrayString] = append(arrToIdentifier[arrayString], id) } res = append(res, getStringArrStatement( "features", arrToIdentifier, cToolchainIdentifiers, depth, /* isPlainString= */ false)) return strings.Join(res, "\n") } func getActions(crosstool *crosstoolpb.CrosstoolRelease) ( map[string][]string, map[string]map[string][]string, error) { actionNameToAction := make(map[string]map[string][]string) toolchainToActions := make(map[string][]string) for _, toolchain := range crosstool.GetToolchain() { id := toolchain.GetToolchainIdentifier() var actionName string if len(toolchain.GetActionConfig()) == 0 { toolchainToActions[id] = []string{} } for _, action := range toolchain.GetActionConfig() { if aName, ok := actionNames[action.GetActionName()]; ok { actionName = aName } else { actionName = strings.ToLower(action.GetActionName()) actionName = strings.Replace(actionName, "+", "p", -1) actionName = strings.Replace(actionName, ".", "_", -1) actionName = strings.Replace(actionName, "-", "_", -1) } stringAction, err := parseAction(action, 1) if err != nil { return nil, nil, fmt.Errorf( "Error in action_config '%s': %v", action.GetActionName(), err) } if _, ok := actionNameToAction[actionName]; !ok { actionNameToAction[actionName] = make(map[string][]string) } actionNameToAction[actionName][stringAction] = append( actionNameToAction[actionName][stringAction], id) toolchainToActions[id] = append( toolchainToActions[id], strings.TrimPrefix(strings.ToLower(actionName), "action_names.")+"_action") } } return toolchainToActions, actionNameToAction, nil } func getActionConfigsDeclaration( crosstool *crosstoolpb.CrosstoolRelease, cToolchainIdentifiers map[string]CToolchainIdentifier, actionNameToAction map[string]map[string][]string, depth int) string { var res []string for actionName, actionStringToID := range actionNameToAction { variableName := strings.TrimPrefix(strings.ToLower(actionName), "action_names.") + "_action" res = append(res, getAssignmentStatement( variableName, actionStringToID, crosstool, cToolchainIdentifiers, depth, /* isPlainString= */ false, /* shouldFail= */ false)) } return strings.Join(res, "") } func getActionConfigsStmt( cToolchainIdentifiers map[string]CToolchainIdentifier, toolchainToActions map[string][]string, depth int) string { var res []string arrToIdentifier := make(map[string][]string) for id, actions := range toolchainToActions { var arrayString string arrayString = strings.Join(actions, "{arrayFieldDelimiter}") arrToIdentifier[arrayString] = append(arrToIdentifier[arrayString], id) } res = append(res, getStringArrStatement( "action_configs", arrToIdentifier, cToolchainIdentifiers, depth, /* isPlainString= */ false)) return strings.Join(res, "\n") } func parseAction(action *crosstoolpb.CToolchain_ActionConfig, depth int) (string, error) { actionName := action.GetActionName() aName := "" if val, ok := actionNames[actionName]; ok { aName = val } else { aName = "\"" + action.GetActionName() + "\"" } name := fmt.Sprintf("action_name = %s", aName) fields := []string{name} if action.GetEnabled() { fields = append(fields, "enabled = True") } if len(action.GetFlagSet()) != 0 { flagSets, err := parseFlagSets(action.GetFlagSet(), depth+1) if err != nil { return "", err } fields = append(fields, "flag_sets = "+flagSets) } if len(action.GetImplies()) != 0 { implies := "implies = " + makeStringArr(action.GetImplies(), depth+1 /* isPlainString= */, true) fields = append(fields, implies) } if len(action.GetTool()) != 0 { tools := "tools = " + parseTools(action.GetTool(), depth+1) fields = append(fields, tools) } return createObject("action_config", fields, depth), nil } func getStringArrStatement(attr string, arrValToIds map[string][]string, cToolchainIdentifiers map[string]CToolchainIdentifier, depth int, plainString bool) string { var b bytes.Buffer if len(arrValToIds) == 0 { b.WriteString(fmt.Sprintf("%s%s = []\n", getTabs(depth), attr)) } else if len(arrValToIds) == 1 { for value := range arrValToIds { var arr []string if value == "" { arr = []string{} } else if value == "None" { b.WriteString(fmt.Sprintf("%s%s = None\n", getTabs(depth), attr)) break } else { arr = strings.Split(value, "{arrayFieldDelimiter}") } b.WriteString( fmt.Sprintf( "%s%s = %s\n", getTabs(depth), attr, makeStringArr(arr, depth+1, plainString))) break } } else { first := true var keys []string for k := range arrValToIds { keys = append(keys, k) } sort.Strings(keys) for _, value := range keys { ids := arrValToIds[value] branch := "elif" if first { branch = "if" } first = false var arr []string if value == "" { arr = []string{} } else if value == "None" { b.WriteString( getIfStatement( branch, ids, attr, "None", cToolchainIdentifiers, depth /* isPlainString= */, true)) continue } else { arr = strings.Split(value, "{arrayFieldDelimiter}") } b.WriteString( getIfStatement(branch, ids, attr, makeStringArr(arr, depth+1, plainString), cToolchainIdentifiers, depth /* isPlainString= */, false)) } b.WriteString(fmt.Sprintf("%selse:\n%sfail(\"Unreachable\")\n", getTabs(depth), getTabs(depth+1))) } b.WriteString("\n") return b.String() } func getStringArr(crosstool *crosstoolpb.CrosstoolRelease, cToolchainIdentifiers map[string]CToolchainIdentifier, attr string, depth int) string { var res []string arrToIdentifier := make(map[string][]string) for _, toolchain := range crosstool.GetToolchain() { id := toolchain.GetToolchainIdentifier() arrayString := strings.Join(getArrField(attr, toolchain), "{arrayFieldDelimiter}") arrToIdentifier[arrayString] = append(arrToIdentifier[arrayString], id) } statement := getStringArrStatement(attr, arrToIdentifier, cToolchainIdentifiers, depth /* isPlainString= */, true) res = append(res, statement) return strings.Join(res, "\n") } func getArrField(attr string, toolchain *crosstoolpb.CToolchain) []string { var arr []string if attr == "cxx_builtin_include_directories" { arr = toolchain.GetCxxBuiltinIncludeDirectory() } return arr } func getTabs(depth int) string { var res string for i := 0; i < depth; i++ { res = res + " " } return res } func createObject(objtype string, fields []string, depth int) string { if len(fields) == 0 { return objtype + "()" } singleLine := objtype + "(" + strings.Join(fields, ", ") + ")" if len(singleLine) < 60 { return singleLine } return objtype + "(\n" + getTabs(depth+1) + strings.Join(fields, ",\n"+getTabs(depth+1)) + ",\n" + getTabs(depth) + ")" } func getArtifactNamePatterns(crosstool *crosstoolpb.CrosstoolRelease, cToolchainIdentifiers map[string]CToolchainIdentifier, depth int) string { var res []string artifactToIds := make(map[string][]string) for _, toolchain := range crosstool.GetToolchain() { artifactNamePatterns := parseArtifactNamePatterns( toolchain.GetArtifactNamePattern(), depth) artifactToIds[artifactNamePatterns] = append( artifactToIds[artifactNamePatterns], toolchain.GetToolchainIdentifier()) } res = append(res, getAssignmentStatement( "artifact_name_patterns", artifactToIds, crosstool, cToolchainIdentifiers, depth, /* isPlainString= */ false, /* shouldFail= */ true)) return strings.Join(res, "\n") } func parseArtifactNamePatterns( artifactNamePatterns []*crosstoolpb.CToolchain_ArtifactNamePattern, depth int) string { var res []string for _, pattern := range artifactNamePatterns { res = append(res, parseArtifactNamePattern(pattern, depth+1)) } return makeStringArr(res, depth /* isPlainString= */, false) } func parseArtifactNamePattern( artifactNamePattern *crosstoolpb.CToolchain_ArtifactNamePattern, depth int) string { categoryName := fmt.Sprintf("category_name = \"%s\"", artifactNamePattern.GetCategoryName()) prefix := fmt.Sprintf("prefix = \"%s\"", artifactNamePattern.GetPrefix()) extension := fmt.Sprintf("extension = \"%s\"", artifactNamePattern.GetExtension()) fields := []string{categoryName, prefix, extension} return createObject("artifact_name_pattern", fields, depth) } func parseFeature(feature *crosstoolpb.CToolchain_Feature, depth int) (string, error) { name := fmt.Sprintf("name = \"%s\"", feature.GetName()) fields := []string{name} if feature.GetEnabled() { fields = append(fields, "enabled = True") } if len(feature.GetFlagSet()) > 0 { flagSets, err := parseFlagSets(feature.GetFlagSet(), depth+1) if err != nil { return "", err } fields = append(fields, "flag_sets = "+flagSets) } if len(feature.GetEnvSet()) > 0 { envSets := "env_sets = " + parseEnvSets(feature.GetEnvSet(), depth+1) fields = append(fields, envSets) } if len(feature.GetRequires()) > 0 { requires := "requires = " + parseFeatureSets(feature.GetRequires(), depth+1) fields = append(fields, requires) } if len(feature.GetImplies()) > 0 { implies := "implies = " + makeStringArr(feature.GetImplies(), depth+1 /* isPlainString= */, true) fields = append(fields, implies) } if len(feature.GetProvides()) > 0 { provides := "provides = " + makeStringArr(feature.GetProvides(), depth+1 /* isPlainString= */, true) fields = append(fields, provides) } return createObject("feature", fields, depth), nil } func parseFlagSets(flagSets []*crosstoolpb.CToolchain_FlagSet, depth int) (string, error) { var res []string for _, flagSet := range flagSets { parsedFlagset, err := parseFlagSet(flagSet, depth+1) if err != nil { return "", err } res = append(res, parsedFlagset) } return makeStringArr(res, depth /* isPlainString= */, false), nil } func parseFlagSet(flagSet *crosstoolpb.CToolchain_FlagSet, depth int) (string, error) { var fields []string if len(flagSet.GetAction()) > 0 { actionArr := processActions(flagSet.GetAction(), depth) actions := "actions = " + strings.Join(actionArr, " +\n"+getTabs(depth+2)) fields = append(fields, actions) } if len(flagSet.GetFlagGroup()) > 0 { flagGroups, err := parseFlagGroups(flagSet.GetFlagGroup(), depth+1) if err != nil { return "", err } fields = append(fields, "flag_groups = "+flagGroups) } if len(flagSet.GetWithFeature()) > 0 { withFeatures := "with_features = " + parseWithFeatureSets(flagSet.GetWithFeature(), depth+1) fields = append(fields, withFeatures) } return createObject("flag_set", fields, depth), nil } func parseFlagGroups(flagGroups []*crosstoolpb.CToolchain_FlagGroup, depth int) (string, error) { var res []string for _, flagGroup := range flagGroups { flagGroupString, err := parseFlagGroup(flagGroup, depth+1) if err != nil { return "", err } res = append(res, flagGroupString) } return makeStringArr(res, depth /* isPlainString= */, false), nil } func parseFlagGroup(flagGroup *crosstoolpb.CToolchain_FlagGroup, depth int) (string, error) { var res []string if len(flagGroup.GetFlag()) != 0 { res = append(res, "flags = "+makeStringArr(flagGroup.GetFlag(), depth+1, true)) } if flagGroup.GetIterateOver() != "" { res = append(res, fmt.Sprintf("iterate_over = \"%s\"", flagGroup.GetIterateOver())) } if len(flagGroup.GetFlagGroup()) != 0 { flagGroupString, err := parseFlagGroups(flagGroup.GetFlagGroup(), depth+1) if err != nil { return "", err } res = append(res, "flag_groups = "+flagGroupString) } if len(flagGroup.GetExpandIfAllAvailable()) > 1 { return "", errors.New("Flag group must not have more than one 'expand_if_all_available' field") } if len(flagGroup.GetExpandIfAllAvailable()) != 0 { res = append(res, fmt.Sprintf( "expand_if_available = \"%s\"", flagGroup.GetExpandIfAllAvailable()[0])) } if len(flagGroup.GetExpandIfNoneAvailable()) > 1 { return "", errors.New("Flag group must not have more than one 'expand_if_none_available' field") } if len(flagGroup.GetExpandIfNoneAvailable()) != 0 { res = append(res, fmt.Sprintf( "expand_if_not_available = \"%s\"", flagGroup.GetExpandIfNoneAvailable()[0])) } if flagGroup.GetExpandIfTrue() != "" { res = append(res, fmt.Sprintf("expand_if_true = \"%s\"", flagGroup.GetExpandIfTrue())) } if flagGroup.GetExpandIfFalse() != "" { res = append(res, fmt.Sprintf("expand_if_false = \"%s\"", flagGroup.GetExpandIfFalse())) } if flagGroup.GetExpandIfEqual() != nil { res = append(res, "expand_if_equal = "+parseVariableWithValue( flagGroup.GetExpandIfEqual(), depth+1)) } return createObject("flag_group", res, depth), nil } func parseVariableWithValue(variable *crosstoolpb.CToolchain_VariableWithValue, depth int) string { variableName := fmt.Sprintf("name = \"%s\"", variable.GetVariable()) value := fmt.Sprintf("value = \"%s\"", variable.GetValue()) return createObject("variable_with_value", []string{variableName, value}, depth) } func getToolPaths(crosstool *crosstoolpb.CrosstoolRelease, cToolchainIdentifiers map[string]CToolchainIdentifier, depth int) string { var res []string toolPathsToIds := make(map[string][]string) for _, toolchain := range crosstool.GetToolchain() { toolPaths := parseToolPaths(toolchain.GetToolPath(), depth) toolPathsToIds[toolPaths] = append( toolPathsToIds[toolPaths], toolchain.GetToolchainIdentifier()) } res = append(res, getAssignmentStatement( "tool_paths", toolPathsToIds, crosstool, cToolchainIdentifiers, depth, /* isPlainString= */ false, /* shouldFail= */ true)) return strings.Join(res, "\n") } func parseToolPaths(toolPaths []*crosstoolpb.ToolPath, depth int) string { var res []string for _, toolPath := range toolPaths { res = append(res, parseToolPath(toolPath, depth+1)) } return makeStringArr(res, depth /* isPlainString= */, false) } func parseToolPath(toolPath *crosstoolpb.ToolPath, depth int) string { name := fmt.Sprintf("name = \"%s\"", toolPath.GetName()) path := toolPath.GetPath() if path == "" { path = "NOT_USED" } path = fmt.Sprintf("path = \"%s\"", path) return createObject("tool_path", []string{name, path}, depth) } func getMakeVariables(crosstool *crosstoolpb.CrosstoolRelease, cToolchainIdentifiers map[string]CToolchainIdentifier, depth int) string { var res []string makeVariablesToIds := make(map[string][]string) for _, toolchain := range crosstool.GetToolchain() { makeVariables := parseMakeVariables(toolchain.GetMakeVariable(), depth) makeVariablesToIds[makeVariables] = append( makeVariablesToIds[makeVariables], toolchain.GetToolchainIdentifier()) } res = append(res, getAssignmentStatement( "make_variables", makeVariablesToIds, crosstool, cToolchainIdentifiers, depth, /* isPlainString= */ false, /* shouldFail= */ true)) return strings.Join(res, "\n") } func parseMakeVariables(makeVariables []*crosstoolpb.MakeVariable, depth int) string { var res []string for _, makeVariable := range makeVariables { res = append(res, parseMakeVariable(makeVariable, depth+1)) } return makeStringArr(res, depth /* isPlainString= */, false) } func parseMakeVariable(makeVariable *crosstoolpb.MakeVariable, depth int) string { name := fmt.Sprintf("name = \"%s\"", makeVariable.GetName()) value := fmt.Sprintf("value = \"%s\"", makeVariable.GetValue()) return createObject("make_variable", []string{name, value}, depth) } func parseTools(tools []*crosstoolpb.CToolchain_Tool, depth int) string { var res []string for _, tool := range tools { res = append(res, parseTool(tool, depth+1)) } return makeStringArr(res, depth /* isPlainString= */, false) } func parseTool(tool *crosstoolpb.CToolchain_Tool, depth int) string { toolPath := "path = \"NOT_USED\"" if tool.GetToolPath() != "" { toolPath = fmt.Sprintf("path = \"%s\"", tool.GetToolPath()) } fields := []string{toolPath} if len(tool.GetWithFeature()) != 0 { withFeatures := "with_features = " + parseWithFeatureSets(tool.GetWithFeature(), depth+1) fields = append(fields, withFeatures) } if len(tool.GetExecutionRequirement()) != 0 { executionRequirements := "execution_requirements = " + makeStringArr(tool.GetExecutionRequirement(), depth+1 /* isPlainString= */, true) fields = append(fields, executionRequirements) } return createObject("tool", fields, depth) } func parseEnvEntries(envEntries []*crosstoolpb.CToolchain_EnvEntry, depth int) string { var res []string for _, envEntry := range envEntries { res = append(res, parseEnvEntry(envEntry, depth+1)) } return makeStringArr(res, depth /* isPlainString= */, false) } func parseEnvEntry(envEntry *crosstoolpb.CToolchain_EnvEntry, depth int) string { key := fmt.Sprintf("key = \"%s\"", envEntry.GetKey()) value := fmt.Sprintf("value = \"%s\"", envEntry.GetValue()) return createObject("env_entry", []string{key, value}, depth) } func parseWithFeatureSets(withFeatureSets []*crosstoolpb.CToolchain_WithFeatureSet, depth int) string { var res []string for _, withFeature := range withFeatureSets { res = append(res, parseWithFeatureSet(withFeature, depth+1)) } return makeStringArr(res, depth /* isPlainString= */, false) } func parseWithFeatureSet(withFeature *crosstoolpb.CToolchain_WithFeatureSet, depth int) string { var fields []string if len(withFeature.GetFeature()) != 0 { features := "features = " + makeStringArr(withFeature.GetFeature(), depth+1 /* isPlainString= */, true) fields = append(fields, features) } if len(withFeature.GetNotFeature()) != 0 { notFeatures := "not_features = " + makeStringArr(withFeature.GetNotFeature(), depth+1 /* isPlainString= */, true) fields = append(fields, notFeatures) } return createObject("with_feature_set", fields, depth) } func parseEnvSets(envSets []*crosstoolpb.CToolchain_EnvSet, depth int) string { var res []string for _, envSet := range envSets { envSetString := parseEnvSet(envSet, depth+1) res = append(res, envSetString) } return makeStringArr(res, depth /* isPlainString= */, false) } func parseEnvSet(envSet *crosstoolpb.CToolchain_EnvSet, depth int) string { actionsStatement := processActions(envSet.GetAction(), depth) actions := "actions = " + strings.Join(actionsStatement, " +\n"+getTabs(depth+2)) fields := []string{actions} if len(envSet.GetEnvEntry()) != 0 { envEntries := "env_entries = " + parseEnvEntries(envSet.GetEnvEntry(), depth+1) fields = append(fields, envEntries) } if len(envSet.GetWithFeature()) != 0 { withFeatures := "with_features = " + parseWithFeatureSets(envSet.GetWithFeature(), depth+1) fields = append(fields, withFeatures) } return createObject("env_set", fields, depth) } func parseFeatureSets(featureSets []*crosstoolpb.CToolchain_FeatureSet, depth int) string { var res []string for _, featureSet := range featureSets { res = append(res, parseFeatureSet(featureSet, depth+1)) } return makeStringArr(res, depth /* isPlainString= */, false) } func parseFeatureSet(featureSet *crosstoolpb.CToolchain_FeatureSet, depth int) string { features := "features = " + makeStringArr(featureSet.GetFeature(), depth+1 /* isPlainString= */, true) return createObject("feature_set", []string{features}, depth) } // Takes in a list of string elements and returns a string that represents // an array : // [ // "element1", // "element2", // ] // The isPlainString argument tells us whether the input elements should be // treated as string (eg, flags), or not (eg, variable names) func makeStringArr(arr []string, depth int, isPlainString bool) string { if len(arr) == 0 { return "[]" } var escapedArr []string for _, el := range arr { if isPlainString { escapedArr = append(escapedArr, strings.Replace(el, "\"", "\\\"", -1)) } else { escapedArr = append(escapedArr, el) } } addQuote := "" if isPlainString { addQuote = "\"" } singleLine := "[" + addQuote + strings.Join(escapedArr, addQuote+", "+addQuote) + addQuote + "]" if len(singleLine) < 60 { return singleLine } return "[\n" + getTabs(depth+1) + addQuote + strings.Join(escapedArr, addQuote+",\n"+getTabs(depth+1)+addQuote) + addQuote + ",\n" + getTabs(depth) + "]" } // Returns a string that represents a value assignment // (eg if ctx.attr.cpu == "linux": // compiler = "llvm" // elif ctx.attr.cpu == "windows": // compiler = "mingw" // else: // fail("Unreachable") func getAssignmentStatement(field string, valToIds map[string][]string, crosstool *crosstoolpb.CrosstoolRelease, toCToolchainIdentifier map[string]CToolchainIdentifier, depth int, isPlainString, shouldFail bool) string { var b bytes.Buffer if len(valToIds) <= 1 { // if there is only one possible value for this field, we don't need if statements for val := range valToIds { if val != "None" && isPlainString { val = "\"" + val + "\"" } b.WriteString(fmt.Sprintf("%s%s = %s\n", getTabs(depth), field, val)) break } } else { first := true var keys []string for k := range valToIds { keys = append(keys, k) } sort.Strings(keys) for _, value := range keys { ids := valToIds[value] branch := "elif" if first { branch = "if" } b.WriteString( getIfStatement(branch, ids, field, value, toCToolchainIdentifier, depth, isPlainString)) first = false } if shouldFail { b.WriteString( fmt.Sprintf( "%selse:\n%sfail(\"Unreachable\")\n", getTabs(depth), getTabs(depth+1))) } else { b.WriteString( fmt.Sprintf( "%selse:\n%s%s = None\n", getTabs(depth), getTabs(depth+1), field)) } } b.WriteString("\n") return b.String() } func getCPUToCompilers(identifiers []CToolchainIdentifier) map[string][]string { res := make(map[string][]string) for _, identifier := range identifiers { if identifier.compiler != "" { res[identifier.cpu] = append(res[identifier.cpu], identifier.compiler) } } return res } func getIfStatement(ifOrElseIf string, identifiers []string, field, val string, toCToolchainIdentifier map[string]CToolchainIdentifier, depth int, isPlainString bool) string { usedStmts := make(map[string]bool) if val != "None" && isPlainString { val = "\"" + val + "\"" } var cToolchainIdentifiers []CToolchainIdentifier for _, value := range toCToolchainIdentifier { cToolchainIdentifiers = append(cToolchainIdentifiers, value) } cpuToCompilers := getCPUToCompilers(cToolchainIdentifiers) countCpus := make(map[string]int) var conditions []string for _, id := range identifiers { identifier := toCToolchainIdentifier[id] stmt := getConditionStatementForCToolchainIdentifier(identifier) if _, ok := usedStmts[stmt]; !ok { conditions = append(conditions, stmt) usedStmts[stmt] = true if identifier.compiler != "" { countCpus[identifier.cpu]++ } } } var compressedConditions []string usedStmtsOptimized := make(map[string]bool) for _, id := range identifiers { identifier := toCToolchainIdentifier[id] var stmt string if _, ok := countCpus[identifier.cpu]; ok { if countCpus[identifier.cpu] == len(cpuToCompilers[identifier.cpu]) { stmt = getConditionStatementForCToolchainIdentifier( CToolchainIdentifier{cpu: identifier.cpu, compiler: ""}) } else { stmt = getConditionStatementForCToolchainIdentifier(identifier) } } else { stmt = getConditionStatementForCToolchainIdentifier(identifier) } if _, ok := usedStmtsOptimized[stmt]; !ok { compressedConditions = append(compressedConditions, stmt) usedStmtsOptimized[stmt] = true } } sort.Strings(compressedConditions) val = strings.Join(strings.Split(val, "\n"+getTabs(depth)), "\n"+getTabs(depth+1)) return fmt.Sprintf(`%s%s %s: %s%s = %s `, getTabs(depth), ifOrElseIf, "("+strings.Join(compressedConditions, "\n"+getTabs(depth+1)+"or ")+")", getTabs(depth+1), field, val) } func getToolchainIdentifiers(crosstool *crosstoolpb.CrosstoolRelease) []string { var res []string for _, toolchain := range crosstool.GetToolchain() { res = append(res, toolchain.GetToolchainIdentifier()) } return res } func getHostSystemNames(crosstool *crosstoolpb.CrosstoolRelease) []string { var res []string for _, toolchain := range crosstool.GetToolchain() { res = append(res, toolchain.GetHostSystemName()) } return res } func getTargetSystemNames(crosstool *crosstoolpb.CrosstoolRelease) []string { var res []string for _, toolchain := range crosstool.GetToolchain() { res = append(res, toolchain.GetTargetSystemName()) } return res } func getTargetCpus(crosstool *crosstoolpb.CrosstoolRelease) []string { var res []string for _, toolchain := range crosstool.GetToolchain() { res = append(res, toolchain.GetTargetCpu()) } return res } func getTargetLibcs(crosstool *crosstoolpb.CrosstoolRelease) []string { var res []string for _, toolchain := range crosstool.GetToolchain() { res = append(res, toolchain.GetTargetLibc()) } return res } func getCompilers(crosstool *crosstoolpb.CrosstoolRelease) []string { var res []string for _, toolchain := range crosstool.GetToolchain() { res = append(res, toolchain.GetCompiler()) } return res } func getAbiVersions(crosstool *crosstoolpb.CrosstoolRelease) []string { var res []string for _, toolchain := range crosstool.GetToolchain() { res = append(res, toolchain.GetAbiVersion()) } return res } func getAbiLibcVersions(crosstool *crosstoolpb.CrosstoolRelease) []string { var res []string for _, toolchain := range crosstool.GetToolchain() { res = append(res, toolchain.GetAbiLibcVersion()) } return res } func getCcTargetOss(crosstool *crosstoolpb.CrosstoolRelease) []string { var res []string for _, toolchain := range crosstool.GetToolchain() { targetOS := "None" if toolchain.GetCcTargetOs() != "" { targetOS = toolchain.GetCcTargetOs() } res = append(res, targetOS) } return res } func getBuiltinSysroots(crosstool *crosstoolpb.CrosstoolRelease) []string { var res []string for _, toolchain := range crosstool.GetToolchain() { sysroot := "None" if toolchain.GetBuiltinSysroot() != "" { sysroot = toolchain.GetBuiltinSysroot() } res = append(res, sysroot) } return res } func getMappedStringValuesToIdentifiers(identifiers, fields []string) map[string][]string { res := make(map[string][]string) for i := range identifiers { res[fields[i]] = append(res[fields[i]], identifiers[i]) } return res } func getReturnStatement() string { return ` out = ctx.actions.declare_file(ctx.label.name) ctx.actions.write(out, "Fake executable") return [ cc_common.create_cc_toolchain_config_info( ctx = ctx, features = features, action_configs = action_configs, artifact_name_patterns = artifact_name_patterns, cxx_builtin_include_directories = cxx_builtin_include_directories, toolchain_identifier = toolchain_identifier, host_system_name = host_system_name, target_system_name = target_system_name, target_cpu = target_cpu, target_libc = target_libc, compiler = compiler, abi_version = abi_version, abi_libc_version = abi_libc_version, tool_paths = tool_paths, make_variables = make_variables, builtin_sysroot = builtin_sysroot, cc_target_os = cc_target_os ), DefaultInfo( executable = out, ), ] ` } // Transform writes a cc_toolchain_config rule functionally equivalent to the // CROSSTOOL file. func Transform(crosstool *crosstoolpb.CrosstoolRelease) (string, error) { var b bytes.Buffer cToolchainIdentifiers := toolchainToCToolchainIdentifier(crosstool) toolchainToFeatures, featureNameToFeature, err := getFeatures(crosstool) if err != nil { return "", err } toolchainToActions, actionNameToAction, err := getActions(crosstool) if err != nil { return "", err } header := getCcToolchainConfigHeader() if _, err := b.WriteString(header); err != nil { return "", err } loadActionsStmt := getLoadActionsStmt() if _, err := b.WriteString(loadActionsStmt); err != nil { return "", err } implHeader := getImplHeader() if _, err := b.WriteString(implHeader); err != nil { return "", err } stringFields := []string{ "toolchain_identifier", "host_system_name", "target_system_name", "target_cpu", "target_libc", "compiler", "abi_version", "abi_libc_version", "cc_target_os", "builtin_sysroot", } for _, stringField := range stringFields { stmt := getStringStatement(crosstool, cToolchainIdentifiers, stringField, 1) if _, err := b.WriteString(stmt); err != nil { return "", err } } listsOfActions := []string{ "all_compile_actions", "all_cpp_compile_actions", "preprocessor_compile_actions", "codegen_compile_actions", "all_link_actions", } for _, listOfActions := range listsOfActions { actions := getListOfActions(listOfActions, 1) if _, err := b.WriteString(actions); err != nil { return "", err } } actionConfigDeclaration := getActionConfigsDeclaration( crosstool, cToolchainIdentifiers, actionNameToAction, 1) if _, err := b.WriteString(actionConfigDeclaration); err != nil { return "", err } actionConfigStatement := getActionConfigsStmt( cToolchainIdentifiers, toolchainToActions, 1) if _, err := b.WriteString(actionConfigStatement); err != nil { return "", err } featureDeclaration := getFeaturesDeclaration( crosstool, cToolchainIdentifiers, featureNameToFeature, 1) if _, err := b.WriteString(featureDeclaration); err != nil { return "", err } featuresStatement := getFeaturesStmt( cToolchainIdentifiers, toolchainToFeatures, 1) if _, err := b.WriteString(featuresStatement); err != nil { return "", err } includeDirectories := getStringArr( crosstool, cToolchainIdentifiers, "cxx_builtin_include_directories", 1) if _, err := b.WriteString(includeDirectories); err != nil { return "", err } artifactNamePatterns := getArtifactNamePatterns( crosstool, cToolchainIdentifiers, 1) if _, err := b.WriteString(artifactNamePatterns); err != nil { return "", err } makeVariables := getMakeVariables(crosstool, cToolchainIdentifiers, 1) if _, err := b.WriteString(makeVariables); err != nil { return "", err } toolPaths := getToolPaths(crosstool, cToolchainIdentifiers, 1) if _, err := b.WriteString(toolPaths); err != nil { return "", err } if _, err := b.WriteString(getReturnStatement()); err != nil { return "", err } rule := getRule(cToolchainIdentifiers, getCompilers(crosstool)) if _, err := b.WriteString(rule); err != nil { return "", err } return b.String(), nil } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������rules_cc-0.0.11/tools/migration/crosstool_to_starlark_lib_test.go�����������������������������������0000664�0000000�0000000�00000146217�14700725615�0025413�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������package crosstooltostarlarklib import ( "fmt" "strings" "testing" "log" crosstoolpb "third_party/com/github/bazelbuild/bazel/src/main/protobuf/crosstool_config_go_proto" "github.com/golang/protobuf/proto" ) func makeCToolchainString(lines []string) string { return fmt.Sprintf(`toolchain { %s }`, strings.Join(lines, "\n ")) } func makeCrosstool(CToolchains []string) *crosstoolpb.CrosstoolRelease { crosstool := &crosstoolpb.CrosstoolRelease{} requiredFields := []string{ "major_version: '0'", "minor_version: '0'", "default_target_cpu: 'cpu'", } CToolchains = append(CToolchains, requiredFields...) if err := proto.UnmarshalText(strings.Join(CToolchains, "\n"), crosstool); err != nil { log.Fatalf("Failed to parse CROSSTOOL:", err) } return crosstool } func getSimpleCToolchain(id string) string { lines := []string{ "toolchain_identifier: 'id-" + id + "'", "host_system_name: 'host-" + id + "'", "target_system_name: 'target-" + id + "'", "target_cpu: 'cpu-" + id + "'", "compiler: 'compiler-" + id + "'", "target_libc: 'libc-" + id + "'", "abi_version: 'version-" + id + "'", "abi_libc_version: 'libc_version-" + id + "'", } return makeCToolchainString(lines) } func getCToolchain(id, cpu, compiler string, extraLines []string) string { lines := []string{ "toolchain_identifier: '" + id + "'", "host_system_name: 'host'", "target_system_name: 'target'", "target_cpu: '" + cpu + "'", "compiler: '" + compiler + "'", "target_libc: 'libc'", "abi_version: 'version'", "abi_libc_version: 'libc_version'", } lines = append(lines, extraLines...) return makeCToolchainString(lines) } func TestStringFieldsConditionStatement(t *testing.T) { toolchain1 := getSimpleCToolchain("1") toolchain2 := getSimpleCToolchain("2") toolchains := []string{toolchain1, toolchain2} crosstool := makeCrosstool(toolchains) testCases := []struct { field string expectedText string }{ {field: "toolchain_identifier", expectedText: ` if (ctx.attr.cpu == "cpu-1"): toolchain_identifier = "id-1" elif (ctx.attr.cpu == "cpu-2"): toolchain_identifier = "id-2" else: fail("Unreachable")`}, {field: "host_system_name", expectedText: ` if (ctx.attr.cpu == "cpu-1"): host_system_name = "host-1" elif (ctx.attr.cpu == "cpu-2"): host_system_name = "host-2" else: fail("Unreachable")`}, {field: "target_system_name", expectedText: ` if (ctx.attr.cpu == "cpu-1"): target_system_name = "target-1" elif (ctx.attr.cpu == "cpu-2"): target_system_name = "target-2" else: fail("Unreachable")`}, {field: "target_cpu", expectedText: ` if (ctx.attr.cpu == "cpu-1"): target_cpu = "cpu-1" elif (ctx.attr.cpu == "cpu-2"): target_cpu = "cpu-2" else: fail("Unreachable")`}, {field: "target_libc", expectedText: ` if (ctx.attr.cpu == "cpu-1"): target_libc = "libc-1" elif (ctx.attr.cpu == "cpu-2"): target_libc = "libc-2" else: fail("Unreachable")`}, {field: "compiler", expectedText: ` if (ctx.attr.cpu == "cpu-1"): compiler = "compiler-1" elif (ctx.attr.cpu == "cpu-2"): compiler = "compiler-2" else: fail("Unreachable")`}, {field: "abi_version", expectedText: ` if (ctx.attr.cpu == "cpu-1"): abi_version = "version-1" elif (ctx.attr.cpu == "cpu-2"): abi_version = "version-2" else: fail("Unreachable")`}, {field: "abi_libc_version", expectedText: ` if (ctx.attr.cpu == "cpu-1"): abi_libc_version = "libc_version-1" elif (ctx.attr.cpu == "cpu-2"): abi_libc_version = "libc_version-2" else: fail("Unreachable")`}} got, err := Transform(crosstool) if err != nil { t.Fatalf("CROSSTOOL conversion failed: %v", err) } failed := false for _, tc := range testCases { if !strings.Contains(got, tc.expectedText) { t.Errorf("Failed to correctly convert '%s' field, expected to contain:\n%v\n", tc.field, tc.expectedText) failed = true } } if failed { t.Fatalf("Tested CROSSTOOL:\n%v\n\nGenerated rule:\n%v\n", strings.Join(toolchains, "\n"), got) } } func TestConditionsSameCpu(t *testing.T) { toolchainAA := getCToolchain("1", "cpuA", "compilerA", []string{}) toolchainAB := getCToolchain("2", "cpuA", "compilerB", []string{}) toolchains := []string{toolchainAA, toolchainAB} crosstool := makeCrosstool(toolchains) testCases := []struct { field string expectedText string }{ {field: "toolchain_identifier", expectedText: ` if (ctx.attr.cpu == "cpuA" and ctx.attr.compiler == "compilerA"): toolchain_identifier = "1" elif (ctx.attr.cpu == "cpuA" and ctx.attr.compiler == "compilerB"): toolchain_identifier = "2" else: fail("Unreachable")`}, {field: "host_system_name", expectedText: ` host_system_name = "host"`}, {field: "target_system_name", expectedText: ` target_system_name = "target"`}, {field: "target_cpu", expectedText: ` target_cpu = "cpuA"`}, {field: "target_libc", expectedText: ` target_libc = "libc"`}, {field: "compiler", expectedText: ` if (ctx.attr.cpu == "cpuA" and ctx.attr.compiler == "compilerA"): compiler = "compilerA" elif (ctx.attr.cpu == "cpuA" and ctx.attr.compiler == "compilerB"): compiler = "compilerB" else: fail("Unreachable")`}, {field: "abi_version", expectedText: ` abi_version = "version"`}, {field: "abi_libc_version", expectedText: ` abi_libc_version = "libc_version"`}} got, err := Transform(crosstool) if err != nil { t.Fatalf("CROSSTOOL conversion failed: %v", err) } failed := false for _, tc := range testCases { if !strings.Contains(got, tc.expectedText) { t.Errorf("Failed to correctly convert '%s' field, expected to contain:\n%v\n", tc.field, tc.expectedText) failed = true } } if failed { t.Fatalf("Tested CROSSTOOL:\n%v\n\nGenerated rule:\n%v\n", strings.Join(toolchains, "\n"), got) } } func TestConditionsSameCompiler(t *testing.T) { toolchainAA := getCToolchain("1", "cpuA", "compilerA", []string{}) toolchainBA := getCToolchain("2", "cpuB", "compilerA", []string{}) toolchains := []string{toolchainAA, toolchainBA} crosstool := makeCrosstool(toolchains) testCases := []struct { field string expectedText string }{ {field: "toolchain_identifier", expectedText: ` if (ctx.attr.cpu == "cpuA"): toolchain_identifier = "1" elif (ctx.attr.cpu == "cpuB"): toolchain_identifier = "2" else: fail("Unreachable")`}, {field: "target_cpu", expectedText: ` if (ctx.attr.cpu == "cpuA"): target_cpu = "cpuA" elif (ctx.attr.cpu == "cpuB"): target_cpu = "cpuB" else: fail("Unreachable")`}, {field: "compiler", expectedText: ` compiler = "compilerA"`}} got, err := Transform(crosstool) if err != nil { t.Fatalf("CROSSTOOL conversion failed: %v", err) } failed := false for _, tc := range testCases { if !strings.Contains(got, tc.expectedText) { t.Errorf("Failed to correctly convert '%s' field, expected to contain:\n%v\n", tc.field, tc.expectedText) failed = true } } if failed { t.Fatalf("Tested CROSSTOOL:\n%v\n\nGenerated rule:\n%v\n", strings.Join(toolchains, "\n"), got) } } func TestNonMandatoryStrings(t *testing.T) { toolchainAA := getCToolchain("1", "cpuA", "compilerA", []string{"cc_target_os: 'osA'"}) toolchainBB := getCToolchain("2", "cpuB", "compilerB", []string{}) toolchains := []string{toolchainAA, toolchainBB} crosstool := makeCrosstool(toolchains) testCases := []struct { field string expectedText string }{ {field: "cc_target_os", expectedText: ` if (ctx.attr.cpu == "cpuB"): cc_target_os = None elif (ctx.attr.cpu == "cpuA"): cc_target_os = "osA" else: fail("Unreachable")`}, {field: "builtin_sysroot", expectedText: ` builtin_sysroot = None`}} got, err := Transform(crosstool) if err != nil { t.Fatalf("CROSSTOOL conversion failed: %v", err) } failed := false for _, tc := range testCases { if !strings.Contains(got, tc.expectedText) { t.Errorf("Failed to correctly convert '%s' field, expected to contain:\n%v\n", tc.field, tc.expectedText) failed = true } } if failed { t.Fatalf("Tested CROSSTOOL:\n%v\n\nGenerated rule:\n%v\n", strings.Join(toolchains, "\n"), got) } } func TestBuiltinIncludeDirectories(t *testing.T) { toolchainAA := getCToolchain("1", "cpuA", "compilerA", []string{}) toolchainBA := getCToolchain("2", "cpuB", "compilerA", []string{}) toolchainCA := getCToolchain("3", "cpuC", "compilerA", []string{"cxx_builtin_include_directory: 'dirC'"}) toolchainCB := getCToolchain("4", "cpuC", "compilerB", []string{"cxx_builtin_include_directory: 'dirC'", "cxx_builtin_include_directory: 'dirB'"}) toolchainDA := getCToolchain("5", "cpuD", "compilerA", []string{"cxx_builtin_include_directory: 'dirC'"}) toolchainsEmpty := []string{toolchainAA, toolchainBA} toolchainsOneNonempty := []string{toolchainAA, toolchainBA, toolchainCA} toolchainsSameNonempty := []string{toolchainCA, toolchainDA} allToolchains := []string{toolchainAA, toolchainBA, toolchainCA, toolchainCB, toolchainDA} testCases := []struct { field string toolchains []string expectedText string }{ {field: "cxx_builtin_include_directories", toolchains: toolchainsEmpty, expectedText: ` cxx_builtin_include_directories = []`}, {field: "cxx_builtin_include_directories", toolchains: toolchainsOneNonempty, expectedText: ` if (ctx.attr.cpu == "cpuA" or ctx.attr.cpu == "cpuB"): cxx_builtin_include_directories = [] elif (ctx.attr.cpu == "cpuC"): cxx_builtin_include_directories = ["dirC"] else: fail("Unreachable")`}, {field: "cxx_builtin_include_directories", toolchains: toolchainsSameNonempty, expectedText: ` cxx_builtin_include_directories = ["dirC"]`}, {field: "cxx_builtin_include_directories", toolchains: allToolchains, expectedText: ` if (ctx.attr.cpu == "cpuA" or ctx.attr.cpu == "cpuB"): cxx_builtin_include_directories = [] elif (ctx.attr.cpu == "cpuC" and ctx.attr.compiler == "compilerA" or ctx.attr.cpu == "cpuD"): cxx_builtin_include_directories = ["dirC"] elif (ctx.attr.cpu == "cpuC" and ctx.attr.compiler == "compilerB"): cxx_builtin_include_directories = ["dirC", "dirB"]`}} for _, tc := range testCases { crosstool := makeCrosstool(tc.toolchains) got, err := Transform(crosstool) if err != nil { t.Fatalf("CROSSTOOL conversion failed: %v", err) } if !strings.Contains(got, tc.expectedText) { t.Errorf("Failed to correctly convert '%s' field, expected to contain:\n%v\n", tc.field, tc.expectedText) t.Fatalf("Tested CROSSTOOL:\n%v\n\nGenerated rule:\n%v\n", strings.Join(tc.toolchains, "\n"), got) } } } func TestMakeVariables(t *testing.T) { toolchainEmpty1 := getCToolchain("1", "cpuA", "compilerA", []string{}) toolchainEmpty2 := getCToolchain("2", "cpuB", "compilerA", []string{}) toolchainA1 := getCToolchain("3", "cpuC", "compilerA", []string{"make_variable {name: 'A', value: 'a/b/c'}"}) toolchainA2 := getCToolchain("4", "cpuC", "compilerB", []string{"make_variable {name: 'A', value: 'a/b/c'}"}) toolchainAB := getCToolchain("5", "cpuC", "compilerC", []string{"make_variable {name: 'A', value: 'a/b/c'}", "make_variable {name: 'B', value: 'a/b/c'}"}) toolchainBA := getCToolchain("6", "cpuD", "compilerA", []string{"make_variable {name: 'B', value: 'a/b/c'}", "make_variable {name: 'A', value: 'a b c'}"}) toolchainsEmpty := []string{toolchainEmpty1, toolchainEmpty2} toolchainsOneNonempty := []string{toolchainEmpty1, toolchainA1} toolchainsSameNonempty := []string{toolchainA1, toolchainA2} toolchainsDifferentOrder := []string{toolchainAB, toolchainBA} allToolchains := []string{ toolchainEmpty1, toolchainEmpty2, toolchainA1, toolchainA2, toolchainAB, toolchainBA, } testCases := []struct { field string toolchains []string expectedText string }{ {field: "make_variables", toolchains: toolchainsEmpty, expectedText: ` make_variables = []`}, {field: "make_variables", toolchains: toolchainsOneNonempty, expectedText: ` if (ctx.attr.cpu == "cpuA"): make_variables = [] elif (ctx.attr.cpu == "cpuC"): make_variables = [make_variable(name = "A", value = "a/b/c")] else: fail("Unreachable")`}, {field: "make_variables", toolchains: toolchainsSameNonempty, expectedText: ` make_variables = [make_variable(name = "A", value = "a/b/c")]`}, {field: "make_variables", toolchains: toolchainsDifferentOrder, expectedText: ` if (ctx.attr.cpu == "cpuC"): make_variables = [ make_variable(name = "A", value = "a/b/c"), make_variable(name = "B", value = "a/b/c"), ] elif (ctx.attr.cpu == "cpuD"): make_variables = [ make_variable(name = "B", value = "a/b/c"), make_variable(name = "A", value = "a b c"), ] else: fail("Unreachable")`}, {field: "make_variables", toolchains: allToolchains, expectedText: ` if (ctx.attr.cpu == "cpuC" and ctx.attr.compiler == "compilerC"): make_variables = [ make_variable(name = "A", value = "a/b/c"), make_variable(name = "B", value = "a/b/c"), ] elif (ctx.attr.cpu == "cpuD"): make_variables = [ make_variable(name = "B", value = "a/b/c"), make_variable(name = "A", value = "a b c"), ] elif (ctx.attr.cpu == "cpuA" or ctx.attr.cpu == "cpuB"): make_variables = [] elif (ctx.attr.cpu == "cpuC" and ctx.attr.compiler == "compilerA" or ctx.attr.cpu == "cpuC" and ctx.attr.compiler == "compilerB"): make_variables = [make_variable(name = "A", value = "a/b/c")] else: fail("Unreachable")`}} for _, tc := range testCases { crosstool := makeCrosstool(tc.toolchains) got, err := Transform(crosstool) if err != nil { t.Fatalf("CROSSTOOL conversion failed: %v", err) } if !strings.Contains(got, tc.expectedText) { t.Errorf("Failed to correctly convert '%s' field, expected to contain:\n%v\n", tc.field, tc.expectedText) t.Fatalf("Tested CROSSTOOL:\n%v\n\nGenerated rule:\n%v\n", strings.Join(tc.toolchains, "\n"), got) } } } func TestToolPaths(t *testing.T) { toolchainEmpty1 := getCToolchain("1", "cpuA", "compilerA", []string{}) toolchainEmpty2 := getCToolchain("2", "cpuB", "compilerA", []string{}) toolchainA1 := getCToolchain("3", "cpuC", "compilerA", []string{"tool_path {name: 'A', path: 'a/b/c'}"}) toolchainA2 := getCToolchain("4", "cpuC", "compilerB", []string{"tool_path {name: 'A', path: 'a/b/c'}"}) toolchainAB := getCToolchain("5", "cpuC", "compilerC", []string{"tool_path {name: 'A', path: 'a/b/c'}", "tool_path {name: 'B', path: 'a/b/c'}"}) toolchainBA := getCToolchain("6", "cpuD", "compilerA", []string{"tool_path {name: 'B', path: 'a/b/c'}", "tool_path {name: 'A', path: 'a/b/c'}"}) toolchainsEmpty := []string{toolchainEmpty1, toolchainEmpty2} toolchainsOneNonempty := []string{toolchainEmpty1, toolchainA1} toolchainsSameNonempty := []string{toolchainA1, toolchainA2} toolchainsDifferentOrder := []string{toolchainAB, toolchainBA} allToolchains := []string{ toolchainEmpty1, toolchainEmpty2, toolchainA1, toolchainA2, toolchainAB, toolchainBA, } testCases := []struct { field string toolchains []string expectedText string }{ {field: "tool_paths", toolchains: toolchainsEmpty, expectedText: ` tool_paths = []`}, {field: "tool_paths", toolchains: toolchainsOneNonempty, expectedText: ` if (ctx.attr.cpu == "cpuA"): tool_paths = [] elif (ctx.attr.cpu == "cpuC"): tool_paths = [tool_path(name = "A", path = "a/b/c")] else: fail("Unreachable")`}, {field: "tool_paths", toolchains: toolchainsSameNonempty, expectedText: ` tool_paths = [tool_path(name = "A", path = "a/b/c")]`}, {field: "tool_paths", toolchains: toolchainsDifferentOrder, expectedText: ` if (ctx.attr.cpu == "cpuC"): tool_paths = [ tool_path(name = "A", path = "a/b/c"), tool_path(name = "B", path = "a/b/c"), ] elif (ctx.attr.cpu == "cpuD"): tool_paths = [ tool_path(name = "B", path = "a/b/c"), tool_path(name = "A", path = "a/b/c"), ] else: fail("Unreachable")`}, {field: "tool_paths", toolchains: allToolchains, expectedText: ` if (ctx.attr.cpu == "cpuC" and ctx.attr.compiler == "compilerC"): tool_paths = [ tool_path(name = "A", path = "a/b/c"), tool_path(name = "B", path = "a/b/c"), ] elif (ctx.attr.cpu == "cpuD"): tool_paths = [ tool_path(name = "B", path = "a/b/c"), tool_path(name = "A", path = "a/b/c"), ] elif (ctx.attr.cpu == "cpuA" or ctx.attr.cpu == "cpuB"): tool_paths = [] elif (ctx.attr.cpu == "cpuC" and ctx.attr.compiler == "compilerA" or ctx.attr.cpu == "cpuC" and ctx.attr.compiler == "compilerB"): tool_paths = [tool_path(name = "A", path = "a/b/c")] else: fail("Unreachable")`}} for _, tc := range testCases { crosstool := makeCrosstool(tc.toolchains) got, err := Transform(crosstool) if err != nil { t.Fatalf("CROSSTOOL conversion failed: %v", err) } if !strings.Contains(got, tc.expectedText) { t.Errorf("Failed to correctly convert '%s' field, expected to contain:\n%v\n", tc.field, tc.expectedText) t.Fatalf("Tested CROSSTOOL:\n%v\n\nGenerated rule:\n%v\n", strings.Join(tc.toolchains, "\n"), got) } } } func getArtifactNamePattern(lines []string) string { return fmt.Sprintf(`artifact_name_pattern { %s }`, strings.Join(lines, "\n ")) } func TestArtifactNamePatterns(t *testing.T) { toolchainEmpty1 := getCToolchain("1", "cpuA", "compilerA", []string{}) toolchainEmpty2 := getCToolchain("2", "cpuB", "compilerA", []string{}) toolchainA1 := getCToolchain("3", "cpuC", "compilerA", []string{ getArtifactNamePattern([]string{ "category_name: 'A'", "prefix: 'p'", "extension: '.exe'"}), }, ) toolchainA2 := getCToolchain("4", "cpuC", "compilerB", []string{ getArtifactNamePattern([]string{ "category_name: 'A'", "prefix: 'p'", "extension: '.exe'"}), }, ) toolchainAB := getCToolchain("5", "cpuC", "compilerC", []string{ getArtifactNamePattern([]string{ "category_name: 'A'", "prefix: 'p'", "extension: '.exe'"}), getArtifactNamePattern([]string{ "category_name: 'B'", "prefix: 'p'", "extension: '.exe'"}), }, ) toolchainBA := getCToolchain("6", "cpuD", "compilerA", []string{ getArtifactNamePattern([]string{ "category_name: 'B'", "prefix: 'p'", "extension: '.exe'"}), getArtifactNamePattern([]string{ "category_name: 'A'", "prefix: 'p'", "extension: '.exe'"}), }, ) toolchainsEmpty := []string{toolchainEmpty1, toolchainEmpty2} toolchainsOneNonempty := []string{toolchainEmpty1, toolchainA1} toolchainsSameNonempty := []string{toolchainA1, toolchainA2} toolchainsDifferentOrder := []string{toolchainAB, toolchainBA} allToolchains := []string{ toolchainEmpty1, toolchainEmpty2, toolchainA1, toolchainA2, toolchainAB, toolchainBA, } testCases := []struct { field string toolchains []string expectedText string }{ {field: "artifact_name_patterns", toolchains: toolchainsEmpty, expectedText: ` artifact_name_patterns = []`}, {field: "artifact_name_patterns", toolchains: toolchainsOneNonempty, expectedText: ` if (ctx.attr.cpu == "cpuC"): artifact_name_patterns = [ artifact_name_pattern( category_name = "A", prefix = "p", extension = ".exe", ), ] elif (ctx.attr.cpu == "cpuA"): artifact_name_patterns = [] else: fail("Unreachable")`}, {field: "artifact_name_patterns", toolchains: toolchainsSameNonempty, expectedText: ` artifact_name_patterns = [ artifact_name_pattern( category_name = "A", prefix = "p", extension = ".exe", ), ]`}, {field: "artifact_name_patterns", toolchains: toolchainsDifferentOrder, expectedText: ` if (ctx.attr.cpu == "cpuC"): artifact_name_patterns = [ artifact_name_pattern( category_name = "A", prefix = "p", extension = ".exe", ), artifact_name_pattern( category_name = "B", prefix = "p", extension = ".exe", ), ] elif (ctx.attr.cpu == "cpuD"): artifact_name_patterns = [ artifact_name_pattern( category_name = "B", prefix = "p", extension = ".exe", ), artifact_name_pattern( category_name = "A", prefix = "p", extension = ".exe", ), ] else: fail("Unreachable")`}, {field: "artifact_name_patterns", toolchains: allToolchains, expectedText: ` if (ctx.attr.cpu == "cpuC" and ctx.attr.compiler == "compilerC"): artifact_name_patterns = [ artifact_name_pattern( category_name = "A", prefix = "p", extension = ".exe", ), artifact_name_pattern( category_name = "B", prefix = "p", extension = ".exe", ), ] elif (ctx.attr.cpu == "cpuC" and ctx.attr.compiler == "compilerA" or ctx.attr.cpu == "cpuC" and ctx.attr.compiler == "compilerB"): artifact_name_patterns = [ artifact_name_pattern( category_name = "A", prefix = "p", extension = ".exe", ), ] elif (ctx.attr.cpu == "cpuD"): artifact_name_patterns = [ artifact_name_pattern( category_name = "B", prefix = "p", extension = ".exe", ), artifact_name_pattern( category_name = "A", prefix = "p", extension = ".exe", ), ] elif (ctx.attr.cpu == "cpuA" or ctx.attr.cpu == "cpuB"): artifact_name_patterns = [] else: fail("Unreachable")`}} for _, tc := range testCases { crosstool := makeCrosstool(tc.toolchains) got, err := Transform(crosstool) if err != nil { t.Fatalf("CROSSTOOL conversion failed: %v", err) } if !strings.Contains(got, tc.expectedText) { t.Errorf("Failed to correctly convert '%s' field, expected to contain:\n%v\n", tc.field, tc.expectedText) t.Fatalf("Tested CROSSTOOL:\n%v\n\nGenerated rule:\n%v\n", strings.Join(tc.toolchains, "\n"), got) } } } func getFeature(lines []string) string { return fmt.Sprintf(`feature { %s }`, strings.Join(lines, "\n ")) } func TestFeatureListAssignment(t *testing.T) { toolchainEmpty1 := getCToolchain("1", "cpuA", "compilerA", []string{}) toolchainEmpty2 := getCToolchain("2", "cpuB", "compilerA", []string{}) toolchainA1 := getCToolchain("3", "cpuC", "compilerA", []string{getFeature([]string{"name: 'A'"})}, ) toolchainA2 := getCToolchain("4", "cpuC", "compilerB", []string{getFeature([]string{"name: 'A'"})}, ) toolchainAB := getCToolchain("5", "cpuC", "compilerC", []string{ getFeature([]string{"name: 'A'"}), getFeature([]string{"name: 'B'"}), }, ) toolchainBA := getCToolchain("6", "cpuD", "compilerA", []string{ getFeature([]string{"name: 'B'"}), getFeature([]string{"name: 'A'"}), }, ) toolchainsEmpty := []string{toolchainEmpty1, toolchainEmpty2} toolchainsOneNonempty := []string{toolchainEmpty1, toolchainA1} toolchainsSameNonempty := []string{toolchainA1, toolchainA2} toolchainsDifferentOrder := []string{toolchainAB, toolchainBA} allToolchains := []string{ toolchainEmpty1, toolchainEmpty2, toolchainA1, toolchainA2, toolchainAB, toolchainBA, } testCases := []struct { field string toolchains []string expectedText string }{ {field: "features", toolchains: toolchainsEmpty, expectedText: ` features = []`}, {field: "features", toolchains: toolchainsOneNonempty, expectedText: ` if (ctx.attr.cpu == "cpuA"): features = [] elif (ctx.attr.cpu == "cpuC"): features = [a_feature] else: fail("Unreachable")`}, {field: "features", toolchains: toolchainsSameNonempty, expectedText: ` features = [a_feature]`}, {field: "features", toolchains: toolchainsDifferentOrder, expectedText: ` if (ctx.attr.cpu == "cpuC"): features = [a_feature, b_feature] elif (ctx.attr.cpu == "cpuD"): features = [b_feature, a_feature] else: fail("Unreachable")`}, {field: "features", toolchains: allToolchains, expectedText: ` if (ctx.attr.cpu == "cpuA" or ctx.attr.cpu == "cpuB"): features = [] elif (ctx.attr.cpu == "cpuC" and ctx.attr.compiler == "compilerA" or ctx.attr.cpu == "cpuC" and ctx.attr.compiler == "compilerB"): features = [a_feature] elif (ctx.attr.cpu == "cpuC" and ctx.attr.compiler == "compilerC"): features = [a_feature, b_feature] elif (ctx.attr.cpu == "cpuD"): features = [b_feature, a_feature] else: fail("Unreachable")`}} for _, tc := range testCases { crosstool := makeCrosstool(tc.toolchains) got, err := Transform(crosstool) if err != nil { t.Fatalf("CROSSTOOL conversion failed: %v", err) } if !strings.Contains(got, tc.expectedText) { t.Errorf("Failed to correctly convert '%s' field, expected to contain:\n%v\n", tc.field, tc.expectedText) t.Fatalf("Tested CROSSTOOL:\n%v\n\nGenerated rule:\n%v\n", strings.Join(tc.toolchains, "\n"), got) } } } func getActionConfig(lines []string) string { return fmt.Sprintf(`action_config { %s }`, strings.Join(lines, "\n ")) } func TestActionConfigListAssignment(t *testing.T) { toolchainEmpty1 := getCToolchain("1", "cpuA", "compilerA", []string{}) toolchainEmpty2 := getCToolchain("2", "cpuB", "compilerA", []string{}) toolchainA1 := getCToolchain("3", "cpuC", "compilerA", []string{ getActionConfig([]string{"action_name: 'A'", "config_name: 'A'"}), }, ) toolchainA2 := getCToolchain("4", "cpuC", "compilerB", []string{ getActionConfig([]string{"action_name: 'A'", "config_name: 'A'"}), }, ) toolchainAB := getCToolchain("5", "cpuC", "compilerC", []string{ getActionConfig([]string{"action_name: 'A'", "config_name: 'A'"}), getActionConfig([]string{"action_name: 'B'", "config_name: 'B'"}), }, ) toolchainBA := getCToolchain("6", "cpuD", "compilerA", []string{ getActionConfig([]string{"action_name: 'B'", "config_name: 'B'"}), getActionConfig([]string{"action_name: 'A'", "config_name: 'A'"}), }, ) toolchainsEmpty := []string{toolchainEmpty1, toolchainEmpty2} toolchainsOneNonempty := []string{toolchainEmpty1, toolchainA1} toolchainsSameNonempty := []string{toolchainA1, toolchainA2} toolchainsDifferentOrder := []string{toolchainAB, toolchainBA} allToolchains := []string{ toolchainEmpty1, toolchainEmpty2, toolchainA1, toolchainA2, toolchainAB, toolchainBA, } testCases := []struct { field string toolchains []string expectedText string }{ {field: "action_configs", toolchains: toolchainsEmpty, expectedText: ` action_configs = []`}, {field: "action_configs", toolchains: toolchainsOneNonempty, expectedText: ` if (ctx.attr.cpu == "cpuA"): action_configs = [] elif (ctx.attr.cpu == "cpuC"): action_configs = [a_action] else: fail("Unreachable")`}, {field: "action_configs", toolchains: toolchainsSameNonempty, expectedText: ` action_configs = [a_action]`}, {field: "action_configs", toolchains: toolchainsDifferentOrder, expectedText: ` if (ctx.attr.cpu == "cpuC"): action_configs = [a_action, b_action] elif (ctx.attr.cpu == "cpuD"): action_configs = [b_action, a_action] else: fail("Unreachable")`}, {field: "action_configs", toolchains: allToolchains, expectedText: ` if (ctx.attr.cpu == "cpuA" or ctx.attr.cpu == "cpuB"): action_configs = [] elif (ctx.attr.cpu == "cpuC" and ctx.attr.compiler == "compilerA" or ctx.attr.cpu == "cpuC" and ctx.attr.compiler == "compilerB"): action_configs = [a_action] elif (ctx.attr.cpu == "cpuC" and ctx.attr.compiler == "compilerC"): action_configs = [a_action, b_action] elif (ctx.attr.cpu == "cpuD"): action_configs = [b_action, a_action] else: fail("Unreachable")`}} for _, tc := range testCases { crosstool := makeCrosstool(tc.toolchains) got, err := Transform(crosstool) if err != nil { t.Fatalf("CROSSTOOL conversion failed: %v", err) } if !strings.Contains(got, tc.expectedText) { t.Errorf("Failed to correctly convert '%s' field, expected to contain:\n%v\n", tc.field, tc.expectedText) t.Fatalf("Tested CROSSTOOL:\n%v\n\nGenerated rule:\n%v\n", strings.Join(tc.toolchains, "\n"), got) } } } func TestAllAndNoneAvailableErrorsWhenMoreThanOneElement(t *testing.T) { toolchainFeatureAllAvailable := getCToolchain("1", "cpu", "compiler", []string{getFeature([]string{ "name: 'A'", "flag_set {", " action: 'A'", " flag_group {", " flag: 'f'", " expand_if_all_available: 'e1'", " expand_if_all_available: 'e2'", " }", "}", })}, ) toolchainFeatureNoneAvailable := getCToolchain("1", "cpu", "compiler", []string{getFeature([]string{ "name: 'A'", "flag_set {", " action: 'A'", " flag_group {", " flag: 'f'", " expand_if_none_available: 'e1'", " expand_if_none_available: 'e2'", " }", "}", })}, ) toolchainActionConfigAllAvailable := getCToolchain("1", "cpu", "compiler", []string{getActionConfig([]string{ "config_name: 'A'", "action_name: 'A'", "flag_set {", " action: 'A'", " flag_group {", " flag: 'f'", " expand_if_all_available: 'e1'", " expand_if_all_available: 'e2'", " }", "}", })}, ) toolchainActionConfigNoneAvailable := getCToolchain("1", "cpu", "compiler", []string{getActionConfig([]string{ "config_name: 'A'", "action_name: 'A'", "flag_set {", " action: 'A'", " flag_group {", " flag: 'f'", " expand_if_none_available: 'e1'", " expand_if_none_available: 'e2'", " }", "}", })}, ) testCases := []struct { field string toolchain string expectedText string }{ {field: "features", toolchain: toolchainFeatureAllAvailable, expectedText: "Error in feature 'A': Flag group must not have more " + "than one 'expand_if_all_available' field"}, {field: "features", toolchain: toolchainFeatureNoneAvailable, expectedText: "Error in feature 'A': Flag group must not have more " + "than one 'expand_if_none_available' field"}, {field: "action_configs", toolchain: toolchainActionConfigAllAvailable, expectedText: "Error in action_config 'A': Flag group must not have more " + "than one 'expand_if_all_available' field"}, {field: "action_configs", toolchain: toolchainActionConfigNoneAvailable, expectedText: "Error in action_config 'A': Flag group must not have more " + "than one 'expand_if_none_available' field"}, } for _, tc := range testCases { crosstool := makeCrosstool([]string{tc.toolchain}) _, err := Transform(crosstool) if err == nil || !strings.Contains(err.Error(), tc.expectedText) { t.Errorf("Expected error: %s, got: %v", tc.expectedText, err) } } } func TestFeaturesAndActionConfigsSetToNoneWhenAllOptionsAreExausted(t *testing.T) { toolchainFeatureAEnabled := getCToolchain("1", "cpuA", "compilerA", []string{getFeature([]string{"name: 'A'", "enabled: true"})}, ) toolchainFeatureADisabled := getCToolchain("2", "cpuA", "compilerB", []string{getFeature([]string{"name: 'A'", "enabled: false"})}, ) toolchainWithoutFeatureA := getCToolchain("3", "cpuA", "compilerC", []string{}) toolchainActionConfigAEnabled := getCToolchain("4", "cpuA", "compilerD", []string{getActionConfig([]string{ "config_name: 'A'", "action_name: 'A'", "enabled: true", })}) toolchainActionConfigADisabled := getCToolchain("5", "cpuA", "compilerE", []string{getActionConfig([]string{ "config_name: 'A'", "action_name: 'A'", })}) toolchainWithoutActionConfigA := getCToolchain("6", "cpuA", "compilerF", []string{}) testCases := []struct { field string toolchains []string expectedText string }{ {field: "features", toolchains: []string{ toolchainFeatureAEnabled, toolchainFeatureADisabled, toolchainWithoutFeatureA}, expectedText: ` if (ctx.attr.cpu == "cpuA" and ctx.attr.compiler == "compilerB"): a_feature = feature(name = "A") elif (ctx.attr.cpu == "cpuA" and ctx.attr.compiler == "compilerA"): a_feature = feature(name = "A", enabled = True) else: a_feature = None `}, {field: "action_config", toolchains: []string{ toolchainActionConfigAEnabled, toolchainActionConfigADisabled, toolchainWithoutActionConfigA}, expectedText: ` if (ctx.attr.cpu == "cpuA" and ctx.attr.compiler == "compilerE"): a_action = action_config(action_name = "A") elif (ctx.attr.cpu == "cpuA" and ctx.attr.compiler == "compilerD"): a_action = action_config(action_name = "A", enabled = True) else: a_action = None `}, } for _, tc := range testCases { crosstool := makeCrosstool(tc.toolchains) got, err := Transform(crosstool) if err != nil { t.Fatalf("CROSSTOOL conversion failed: %v", err) } if !strings.Contains(got, tc.expectedText) { t.Errorf("Failed to correctly convert '%s' field, expected to contain:\n%v\n", tc.field, tc.expectedText) t.Fatalf("Tested CROSSTOOL:\n%v\n\nGenerated rule:\n%v\n", strings.Join(tc.toolchains, "\n"), got) } } } func TestActionConfigDeclaration(t *testing.T) { toolchainEmpty1 := getCToolchain("1", "cpuA", "compilerA", []string{}) toolchainEmpty2 := getCToolchain("2", "cpuB", "compilerA", []string{}) toolchainNameNotInDict := getCToolchain("3", "cpBC", "compilerB", []string{ getActionConfig([]string{"action_name: 'A-B.C'", "config_name: 'A-B.C'"}), }, ) toolchainNameInDictA := getCToolchain("4", "cpuC", "compilerA", []string{ getActionConfig([]string{"action_name: 'c++-compile'", "config_name: 'c++-compile'"}), }, ) toolchainNameInDictB := getCToolchain("5", "cpuC", "compilerB", []string{ getActionConfig([]string{ "action_name: 'c++-compile'", "config_name: 'c++-compile'", "tool {", " tool_path: '/a/b/c'", "}", }), }, ) toolchainComplexActionConfig := getCToolchain("6", "cpuC", "compilerC", []string{ getActionConfig([]string{ "action_name: 'action-complex'", "config_name: 'action-complex'", "enabled: true", "tool {", " tool_path: '/a/b/c'", " with_feature {", " feature: 'a'", " feature: 'b'", " not_feature: 'c'", " not_feature: 'd'", " }", " with_feature{", " feature: 'e'", " }", " execution_requirement: 'a'", "}", "tool {", " tool_path: ''", "}", "flag_set {", " flag_group {", " flag: 'a'", " flag: '%b'", " iterate_over: 'c'", " expand_if_all_available: 'd'", " expand_if_none_available: 'e'", " expand_if_true: 'f'", " expand_if_false: 'g'", " expand_if_equal {", " variable: 'var'", " value: 'val'", " }", " }", " flag_group {", " flag_group {", " flag: 'a'", " }", " }", "}", "flag_set {", " with_feature {", " feature: 'a'", " feature: 'b'", " not_feature: 'c'", " not_feature: 'd'", " }", "}", "env_set {", " action: 'a'", " env_entry {", " key: 'k'", " value: 'v'", " }", " with_feature {", " feature: 'a'", " }", "}", "requires {", " feature: 'a'", " feature: 'b'", "}", "implies: 'a'", "implies: 'b'", }), }, ) testCases := []struct { toolchains []string expectedText string }{ { toolchains: []string{toolchainEmpty1, toolchainEmpty2}, expectedText: ` action_configs = []`}, { toolchains: []string{toolchainEmpty1, toolchainNameNotInDict}, expectedText: ` a_b_c_action = action_config(action_name = "A-B.C")`}, { toolchains: []string{toolchainNameInDictA, toolchainNameInDictB}, expectedText: ` if (ctx.attr.cpu == "cpuC" and ctx.attr.compiler == "compilerB"): cpp_compile_action = action_config( action_name = ACTION_NAMES.cpp_compile, tools = [tool(path = "/a/b/c")], ) elif (ctx.attr.cpu == "cpuC" and ctx.attr.compiler == "compilerA"): cpp_compile_action = action_config(action_name = ACTION_NAMES.cpp_compile)`}, { toolchains: []string{toolchainComplexActionConfig}, expectedText: ` action_complex_action = action_config( action_name = "action-complex", enabled = True, flag_sets = [ flag_set( flag_groups = [ flag_group( flags = ["a", "%b"], iterate_over = "c", expand_if_available = "d", expand_if_not_available = "e", expand_if_true = "f", expand_if_false = "g", expand_if_equal = variable_with_value(name = "var", value = "val"), ), flag_group(flag_groups = [flag_group(flags = ["a"])]), ], ), flag_set( with_features = [ with_feature_set( features = ["a", "b"], not_features = ["c", "d"], ), ], ), ], implies = ["a", "b"], tools = [ tool( path = "/a/b/c", with_features = [ with_feature_set( features = ["a", "b"], not_features = ["c", "d"], ), with_feature_set(features = ["e"]), ], execution_requirements = ["a"], ), tool(path = "NOT_USED"), ], )`}} for _, tc := range testCases { crosstool := makeCrosstool(tc.toolchains) got, err := Transform(crosstool) if err != nil { t.Fatalf("CROSSTOOL conversion failed: %v", err) } if !strings.Contains(got, tc.expectedText) { t.Errorf("Failed to correctly declare an action_config, expected to contain:\n%v\n", tc.expectedText) t.Fatalf("Tested CROSSTOOL:\n%v\n\nGenerated rule:\n%v\n", strings.Join(tc.toolchains, "\n"), got) } } } func TestFeatureDeclaration(t *testing.T) { toolchainEmpty1 := getCToolchain("1", "cpuA", "compilerA", []string{}) toolchainEmpty2 := getCToolchain("2", "cpuB", "compilerA", []string{}) toolchainSimpleFeatureA1 := getCToolchain("3", "cpuB", "compilerB", []string{ getFeature([]string{"name: 'Feature-c++.a'", "enabled: true"}), }, ) toolchainSimpleFeatureA2 := getCToolchain("4", "cpuC", "compilerA", []string{ getFeature([]string{"name: 'Feature-c++.a'"}), }, ) toolchainComplexFeature := getCToolchain("5", "cpuC", "compilerC", []string{ getFeature([]string{ "name: 'complex-feature'", "enabled: true", "flag_set {", " action: 'c++-compile'", // in ACTION_NAMES " action: 'something-else'", // not in ACTION_NAMES " flag_group {", " flag: 'a'", " flag: '%b'", " iterate_over: 'c'", " expand_if_all_available: 'd'", " expand_if_none_available: 'e'", " expand_if_true: 'f'", " expand_if_false: 'g'", " expand_if_equal {", " variable: 'var'", " value: 'val'", " }", " }", " flag_group {", " flag_group {", " flag: 'a'", " }", " }", "}", "flag_set {", // all_compile_actions " action: 'c-compile'", " action: 'c++-compile'", " action: 'linkstamp-compile'", " action: 'assemble'", " action: 'preprocess-assemble'", " action: 'c++-header-parsing'", " action: 'c++-module-compile'", " action: 'c++-module-codegen'", " action: 'clif-match'", " action: 'lto-backend'", "}", "flag_set {", // all_cpp_compile_actions " action: 'c++-compile'", " action: 'linkstamp-compile'", " action: 'c++-header-parsing'", " action: 'c++-module-compile'", " action: 'c++-module-codegen'", " action: 'clif-match'", "}", "flag_set {", // all_link_actions " action: 'c++-link-executable'", " action: 'c++-link-dynamic-library'", " action: 'c++-link-nodeps-dynamic-library'", "}", "flag_set {", // all_cpp_compile_actions + all_link_actions " action: 'c++-compile'", " action: 'linkstamp-compile'", " action: 'c++-header-parsing'", " action: 'c++-module-compile'", " action: 'c++-module-codegen'", " action: 'clif-match'", " action: 'c++-link-executable'", " action: 'c++-link-dynamic-library'", " action: 'c++-link-nodeps-dynamic-library'", "}", "flag_set {", // all_link_actions + something else " action: 'c++-link-executable'", " action: 'c++-link-dynamic-library'", " action: 'c++-link-nodeps-dynamic-library'", " action: 'some.unknown-c++.action'", "}", "env_set {", " action: 'a'", " env_entry {", " key: 'k'", " value: 'v'", " }", " with_feature {", " feature: 'a'", " }", "}", "env_set {", " action: 'c-compile'", "}", "env_set {", // all_compile_actions " action: 'c-compile'", " action: 'c++-compile'", " action: 'linkstamp-compile'", " action: 'assemble'", " action: 'preprocess-assemble'", " action: 'c++-header-parsing'", " action: 'c++-module-compile'", " action: 'c++-module-codegen'", " action: 'clif-match'", " action: 'lto-backend'", "}", "requires {", " feature: 'a'", " feature: 'b'", "}", "implies: 'a'", "implies: 'b'", "provides: 'c'", "provides: 'd'", }), }, ) testCases := []struct { toolchains []string expectedText string }{ { toolchains: []string{toolchainEmpty1, toolchainEmpty2}, expectedText: ` features = [] `}, { toolchains: []string{toolchainEmpty1, toolchainSimpleFeatureA1}, expectedText: ` feature_cpp_a_feature = feature(name = "Feature-c++.a", enabled = True)`}, { toolchains: []string{toolchainSimpleFeatureA1, toolchainSimpleFeatureA2}, expectedText: ` if (ctx.attr.cpu == "cpuC"): feature_cpp_a_feature = feature(name = "Feature-c++.a") elif (ctx.attr.cpu == "cpuB"): feature_cpp_a_feature = feature(name = "Feature-c++.a", enabled = True)`}, { toolchains: []string{toolchainComplexFeature}, expectedText: ` complex_feature_feature = feature( name = "complex-feature", enabled = True, flag_sets = [ flag_set( actions = [ACTION_NAMES.cpp_compile, "something-else"], flag_groups = [ flag_group( flags = ["a", "%b"], iterate_over = "c", expand_if_available = "d", expand_if_not_available = "e", expand_if_true = "f", expand_if_false = "g", expand_if_equal = variable_with_value(name = "var", value = "val"), ), flag_group(flag_groups = [flag_group(flags = ["a"])]), ], ), flag_set(actions = all_compile_actions), flag_set(actions = all_cpp_compile_actions), flag_set(actions = all_link_actions), flag_set( actions = all_cpp_compile_actions + all_link_actions, ), flag_set( actions = all_link_actions + ["some.unknown-c++.action"], ), ], env_sets = [ env_set( actions = ["a"], env_entries = [env_entry(key = "k", value = "v")], with_features = [with_feature_set(features = ["a"])], ), env_set(actions = [ACTION_NAMES.c_compile]), env_set(actions = all_compile_actions), ], requires = [feature_set(features = ["a", "b"])], implies = ["a", "b"], provides = ["c", "d"], )`}} for _, tc := range testCases { crosstool := makeCrosstool(tc.toolchains) got, err := Transform(crosstool) if err != nil { t.Fatalf("CROSSTOOL conversion failed: %v", err) } if !strings.Contains(got, tc.expectedText) { t.Errorf("Failed to correctly declare a feature, expected to contain:\n%v\n", tc.expectedText) t.Fatalf("Tested CROSSTOOL:\n%v\n\nGenerated rule:\n%v\n", strings.Join(tc.toolchains, "\n"), got) } } } func TestRule(t *testing.T) { simpleToolchain := getSimpleCToolchain("simple") expected := `load("@rules_cc//cc:cc_toolchain_config_lib.bzl", "action_config", "artifact_name_pattern", "env_entry", "env_set", "feature", "feature_set", "flag_group", "flag_set", "make_variable", "tool", "tool_path", "variable_with_value", "with_feature_set", ) load("@rules_cc//cc:action_names.bzl", "ACTION_NAMES") def _impl(ctx): toolchain_identifier = "id-simple" host_system_name = "host-simple" target_system_name = "target-simple" target_cpu = "cpu-simple" target_libc = "libc-simple" compiler = "compiler-simple" abi_version = "version-simple" abi_libc_version = "libc_version-simple" cc_target_os = None builtin_sysroot = None all_compile_actions = [ ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile, ACTION_NAMES.linkstamp_compile, ACTION_NAMES.assemble, ACTION_NAMES.preprocess_assemble, ACTION_NAMES.cpp_header_parsing, ACTION_NAMES.cpp_module_compile, ACTION_NAMES.cpp_module_codegen, ACTION_NAMES.clif_match, ACTION_NAMES.lto_backend, ] all_cpp_compile_actions = [ ACTION_NAMES.cpp_compile, ACTION_NAMES.linkstamp_compile, ACTION_NAMES.cpp_header_parsing, ACTION_NAMES.cpp_module_compile, ACTION_NAMES.cpp_module_codegen, ACTION_NAMES.clif_match, ] preprocessor_compile_actions = [ ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile, ACTION_NAMES.linkstamp_compile, ACTION_NAMES.preprocess_assemble, ACTION_NAMES.cpp_header_parsing, ACTION_NAMES.cpp_module_compile, ACTION_NAMES.clif_match, ] codegen_compile_actions = [ ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile, ACTION_NAMES.linkstamp_compile, ACTION_NAMES.assemble, ACTION_NAMES.preprocess_assemble, ACTION_NAMES.cpp_module_codegen, ACTION_NAMES.lto_backend, ] all_link_actions = [ ACTION_NAMES.cpp_link_executable, ACTION_NAMES.cpp_link_dynamic_library, ACTION_NAMES.cpp_link_nodeps_dynamic_library, ] action_configs = [] features = [] cxx_builtin_include_directories = [] artifact_name_patterns = [] make_variables = [] tool_paths = [] out = ctx.actions.declare_file(ctx.label.name) ctx.actions.write(out, "Fake executable") return [ cc_common.create_cc_toolchain_config_info( ctx = ctx, features = features, action_configs = action_configs, artifact_name_patterns = artifact_name_patterns, cxx_builtin_include_directories = cxx_builtin_include_directories, toolchain_identifier = toolchain_identifier, host_system_name = host_system_name, target_system_name = target_system_name, target_cpu = target_cpu, target_libc = target_libc, compiler = compiler, abi_version = abi_version, abi_libc_version = abi_libc_version, tool_paths = tool_paths, make_variables = make_variables, builtin_sysroot = builtin_sysroot, cc_target_os = cc_target_os ), DefaultInfo( executable = out, ), ] cc_toolchain_config = rule( implementation = _impl, attrs = { "cpu": attr.string(mandatory=True, values=["cpu-simple"]), }, provides = [CcToolchainConfigInfo], executable = True, ) ` crosstool := makeCrosstool([]string{simpleToolchain}) got, err := Transform(crosstool) if err != nil { t.Fatalf("CROSSTOOL conversion failed: %v", err) } if got != expected { t.Fatalf("Expected:\n%v\nGot:\n%v\nTested CROSSTOOL:\n%v", expected, got, simpleToolchain) } } func TestAllowedCompilerValues(t *testing.T) { toolchainAA := getCToolchain("1", "cpuA", "compilerA", []string{}) toolchainBA := getCToolchain("2", "cpuB", "compilerA", []string{}) toolchainBB := getCToolchain("3", "cpuB", "compilerB", []string{}) toolchainCC := getCToolchain("4", "cpuC", "compilerC", []string{}) testCases := []struct { toolchains []string expectedText string }{ { toolchains: []string{toolchainAA, toolchainBA}, expectedText: ` cc_toolchain_config = rule( implementation = _impl, attrs = { "cpu": attr.string(mandatory=True, values=["cpuA", "cpuB"]), }, provides = [CcToolchainConfigInfo], executable = True, ) `}, { toolchains: []string{toolchainBA, toolchainBB}, expectedText: ` cc_toolchain_config = rule( implementation = _impl, attrs = { "cpu": attr.string(mandatory=True, values=["cpuB"]), "compiler": attr.string(mandatory=True, values=["compilerA", "compilerB"]), }, provides = [CcToolchainConfigInfo], executable = True, ) `}, { toolchains: []string{toolchainAA, toolchainBA, toolchainBB}, expectedText: ` cc_toolchain_config = rule( implementation = _impl, attrs = { "cpu": attr.string(mandatory=True, values=["cpuA", "cpuB"]), "compiler": attr.string(mandatory=True, values=["compilerA", "compilerB"]), }, provides = [CcToolchainConfigInfo], executable = True, ) `}, { toolchains: []string{toolchainAA, toolchainBA, toolchainBB, toolchainCC}, expectedText: ` cc_toolchain_config = rule( implementation = _impl, attrs = { "cpu": attr.string(mandatory=True, values=["cpuA", "cpuB", "cpuC"]), "compiler": attr.string(mandatory=True, values=["compilerA", "compilerB", "compilerC"]), }, provides = [CcToolchainConfigInfo], executable = True, ) `}} for _, tc := range testCases { crosstool := makeCrosstool(tc.toolchains) got, err := Transform(crosstool) if err != nil { t.Fatalf("CROSSTOOL conversion failed: %v", err) } if !strings.Contains(got, tc.expectedText) { t.Errorf("Failed to correctly declare the rule, expected to contain:\n%v\n", tc.expectedText) t.Fatalf("Tested CROSSTOOL:\n%v\n\nGenerated rule:\n%v\n", strings.Join(tc.toolchains, "\n"), got) } } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������rules_cc-0.0.11/tools/migration/ctoolchain_comparator.py��������������������������������������������0000664�0000000�0000000�00000011463�14700725615�0023461�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Copyright 2018 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. r"""A script that compares 2 CToolchains from proto format. This script accepts two files in either a CROSSTOOL proto text format or a CToolchain proto text format. It then locates the CToolchains with the given toolchain_identifier and checks if the resulting CToolchain objects in Java are the same. Example usage: bazel run \ @rules_cc//tools/migration:ctoolchain_comparator -- \ --before=/path/to/CROSSTOOL1 \ --after=/path/to/CROSSTOOL2 \ --toolchain_identifier=id """ import os from absl import app from absl import flags from google.protobuf import text_format from third_party.com.github.bazelbuild.bazel.src.main.protobuf import crosstool_config_pb2 from tools.migration.ctoolchain_comparator_lib import compare_ctoolchains flags.DEFINE_string( "before", None, ("A text proto file containing the relevant CTooclchain before the change, " "either a CROSSTOOL file or a single CToolchain proto text")) flags.DEFINE_string( "after", None, ("A text proto file containing the relevant CToolchain after the change, " "either a CROSSTOOL file or a single CToolchain proto text")) flags.DEFINE_string("toolchain_identifier", None, "The identifier of the CToolchain that is being compared.") flags.mark_flag_as_required("before") flags.mark_flag_as_required("after") def _to_absolute_path(path): path = os.path.expanduser(path) if os.path.isabs(path): return path else: if "BUILD_WORKING_DIRECTORY" in os.environ: return os.path.join(os.environ["BUILD_WORKING_DIRECTORY"], path) else: return path def _find_toolchain(crosstool, toolchain_identifier): for toolchain in crosstool.toolchain: if toolchain.toolchain_identifier == toolchain_identifier: return toolchain return None def _read_crosstool_or_ctoolchain_proto(input_file, toolchain_identifier=None): """Reads a proto file and finds the CToolchain with the given identifier.""" with open(input_file, "r") as f: text = f.read() crosstool_release = crosstool_config_pb2.CrosstoolRelease() c_toolchain = crosstool_config_pb2.CToolchain() try: text_format.Merge(text, crosstool_release) if toolchain_identifier is None: print("CROSSTOOL proto needs a 'toolchain_identifier' specified in " "order to be able to select the right toolchain for comparison.") return None toolchain = _find_toolchain(crosstool_release, toolchain_identifier) if toolchain is None: print(("Cannot find a CToolchain with an identifier '%s' in CROSSTOOL " "file") % toolchain_identifier) return None return toolchain except text_format.ParseError as crosstool_error: try: text_format.Merge(text, c_toolchain) if (toolchain_identifier is not None and c_toolchain.toolchain_identifier != toolchain_identifier): print(("Expected CToolchain with identifier '%s', got CToolchain with " "identifier '%s'" % (toolchain_identifier, c_toolchain.toolchain_identifier))) return None return c_toolchain except text_format.ParseError as toolchain_error: print(("Error parsing file '%s':" % input_file)) # pylint: disable=superfluous-parens print("Attempt to parse it as a CROSSTOOL proto:") # pylint: disable=superfluous-parens print(crosstool_error) # pylint: disable=superfluous-parens print("Attempt to parse it as a CToolchain proto:") # pylint: disable=superfluous-parens print(toolchain_error) # pylint: disable=superfluous-parens return None def main(unused_argv): before_file = _to_absolute_path(flags.FLAGS.before) after_file = _to_absolute_path(flags.FLAGS.after) toolchain_identifier = flags.FLAGS.toolchain_identifier toolchain_before = _read_crosstool_or_ctoolchain_proto( before_file, toolchain_identifier) toolchain_after = _read_crosstool_or_ctoolchain_proto(after_file, toolchain_identifier) if not toolchain_before or not toolchain_after: print("There was an error getting the required toolchains.") exit(1) found_difference = compare_ctoolchains(toolchain_before, toolchain_after) if found_difference: exit(1) if __name__ == "__main__": app.run(main) �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������rules_cc-0.0.11/tools/migration/ctoolchain_comparator_lib.py����������������������������������������0000664�0000000�0000000�00000054312�14700725615�0024307�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Copyright 2018 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. """Module providing compare_ctoolchains function. compare_ctoolchains takes in two parsed CToolchains and compares them """ def _print_difference(field_name, before_value, after_value): if not before_value and after_value: print(("Difference in '%s' field:\nValue before change is not set\n" "Value after change is set to '%s'") % (field_name, after_value)) elif before_value and not after_value: print(("Difference in '%s' field:\nValue before change is set to '%s'\n" "Value after change is not set") % (field_name, before_value)) else: print(("Difference in '%s' field:\nValue before change:\t'%s'\n" "Value after change:\t'%s'\n") % (field_name, before_value, after_value)) def _array_to_string(arr, ordered=False): if not arr: return "[]" elif len(arr) == 1: return "[" + list(arr)[0] + "]" if not ordered: return "[\n\t%s\n]" % "\n\t".join(arr) else: return "[\n\t%s\n]" % "\n\t".join(sorted(list(arr))) def _check_with_feature_set_equivalence(before, after): before_set = set() after_set = set() for el in before: before_set.add((str(set(el.feature)), str(set(el.not_feature)))) for el in after: after_set.add((str(set(el.feature)), str(set(el.not_feature)))) return before_set == after_set def _check_tool_equivalence(before, after): """Compares two "CToolchain.Tool"s.""" if before.tool_path == "NOT_USED": before.tool_path = "" if after.tool_path == "NOT_USED": after.tool_path = "" if before.tool_path != after.tool_path: return False if set(before.execution_requirement) != set(after.execution_requirement): return False if not _check_with_feature_set_equivalence(before.with_feature, after.with_feature): return False return True def _check_flag_group_equivalence(before, after): """Compares two "CToolchain.FlagGroup"s.""" if before.flag != after.flag: return False if before.expand_if_true != after.expand_if_true: return False if before.expand_if_false != after.expand_if_false: return False if set(before.expand_if_all_available) != set(after.expand_if_all_available): return False if set(before.expand_if_none_available) != set( after.expand_if_none_available): return False if before.iterate_over != after.iterate_over: return False if before.expand_if_equal != after.expand_if_equal: return False if len(before.flag_group) != len(after.flag_group): return False for (flag_group_before, flag_group_after) in zip(before.flag_group, after.flag_group): if not _check_flag_group_equivalence(flag_group_before, flag_group_after): return False return True def _check_flag_set_equivalence(before, after, in_action_config=False): """Compares two "CToolchain.FlagSet"s.""" # ActionConfigs in proto format do not have a 'FlagSet.action' field set. # Instead, when construction the Java ActionConfig object, we set the # flag_set.action field to the action name. This currently causes the # CcToolchainConfigInfo.proto to generate a CToolchain.ActionConfig that still # has the action name in the FlagSet.action field, therefore we don't compare # the FlagSet.action field when comparing flag_sets that belong to an # ActionConfig. if not in_action_config and set(before.action) != set(after.action): return False if not _check_with_feature_set_equivalence(before.with_feature, after.with_feature): return False if len(before.flag_group) != len(after.flag_group): return False for (flag_group_before, flag_group_after) in zip(before.flag_group, after.flag_group): if not _check_flag_group_equivalence(flag_group_before, flag_group_after): return False return True def _check_action_config_equivalence(before, after): """Compares two "CToolchain.ActionConfig"s.""" if before.config_name != after.config_name: return False if before.action_name != after.action_name: return False if before.enabled != after.enabled: return False if len(before.tool) != len(after.tool): return False for (tool_before, tool_after) in zip(before.tool, after.tool): if not _check_tool_equivalence(tool_before, tool_after): return False if before.implies != after.implies: return False if len(before.flag_set) != len(after.flag_set): return False for (flag_set_before, flag_set_after) in zip(before.flag_set, after.flag_set): if not _check_flag_set_equivalence(flag_set_before, flag_set_after, True): return False return True def _check_env_set_equivalence(before, after): """Compares two "CToolchain.EnvSet"s.""" if set(before.action) != set(after.action): return False if not _check_with_feature_set_equivalence(before.with_feature, after.with_feature): return False if before.env_entry != after.env_entry: return False return True def _check_feature_equivalence(before, after): """Compares two "CToolchain.Feature"s.""" if before.name != after.name: return False if before.enabled != after.enabled: return False if len(before.flag_set) != len(after.flag_set): return False for (flag_set_before, flag_set_after) in zip(before.flag_set, after.flag_set): if not _check_flag_set_equivalence(flag_set_before, flag_set_after): return False if len(before.env_set) != len(after.env_set): return False for (env_set_before, env_set_after) in zip(before.env_set, after.env_set): if not _check_env_set_equivalence(env_set_before, env_set_after): return False if len(before.requires) != len(after.requires): return False for (requires_before, requires_after) in zip(before.requires, after.requires): if set(requires_before.feature) != set(requires_after.feature): return False if before.implies != after.implies: return False if before.provides != after.provides: return False return True def _compare_features(features_before, features_after): """Compares two "CToolchain.FlagFeature" lists.""" feature_name_to_feature_before = {} feature_name_to_feature_after = {} for feature in features_before: feature_name_to_feature_before[feature.name] = feature for feature in features_after: feature_name_to_feature_after[feature.name] = feature feature_names_before = set(feature_name_to_feature_before.keys()) feature_names_after = set(feature_name_to_feature_after.keys()) before_after_diff = feature_names_before - feature_names_after after_before_diff = feature_names_after - feature_names_before diff_string = "Difference in 'feature' field:" found_difference = False if before_after_diff: if not found_difference: print(diff_string) # pylint: disable=superfluous-parens found_difference = True print(("* List before change contains entries for the following features " "that the list after the change doesn't:\n%s") % _array_to_string( before_after_diff, ordered=True)) if after_before_diff: if not found_difference: print(diff_string) # pylint: disable=superfluous-parens found_difference = True print(("* List after change contains entries for the following features " "that the list before the change doesn't:\n%s") % _array_to_string( after_before_diff, ordered=True)) names_before = [feature.name for feature in features_before] names_after = [feature.name for feature in features_after] if names_before != names_after: if not found_difference: print(diff_string) # pylint: disable=superfluous-parens found_difference = True print(("Features not in right order:\n" "* List of features before change:\t%s" "* List of features before change:\t%s") % (_array_to_string(names_before), _array_to_string(names_after))) for name in feature_name_to_feature_before: feature_before = feature_name_to_feature_before[name] feature_after = feature_name_to_feature_after.get(name, None) if feature_after and not _check_feature_equivalence(feature_before, feature_after): if not found_difference: print(diff_string) # pylint: disable=superfluous-parens found_difference = True print(("* Feature '%s' differs before and after the change:\n" "Value before change:\n%s\n" "Value after change:\n%s") % (name, str(feature_before), str(feature_after))) if found_difference: print("") # pylint: disable=superfluous-parens return found_difference def _compare_action_configs(action_configs_before, action_configs_after): """Compares two "CToolchain.ActionConfig" lists.""" action_name_to_action_before = {} action_name_to_action_after = {} for action_config in action_configs_before: action_name_to_action_before[action_config.config_name] = action_config for action_config in action_configs_after: action_name_to_action_after[action_config.config_name] = action_config config_names_before = set(action_name_to_action_before.keys()) config_names_after = set(action_name_to_action_after.keys()) before_after_diff = config_names_before - config_names_after after_before_diff = config_names_after - config_names_before diff_string = "Difference in 'action_config' field:" found_difference = False if before_after_diff: if not found_difference: print(diff_string) # pylint: disable=superfluous-parens found_difference = True print(("* List before change contains entries for the following " "action_configs that the list after the change doesn't:\n%s") % _array_to_string(before_after_diff, ordered=True)) if after_before_diff: if not found_difference: print(diff_string) # pylint: disable=superfluous-parens found_difference = True print(("* List after change contains entries for the following " "action_configs that the list before the change doesn't:\n%s") % _array_to_string(after_before_diff, ordered=True)) names_before = [config.config_name for config in action_configs_before] names_after = [config.config_name for config in action_configs_after] if names_before != names_after: if not found_difference: print(diff_string) # pylint: disable=superfluous-parens found_difference = True print(("Action configs not in right order:\n" "* List of action configs before change:\t%s" "* List of action_configs before change:\t%s") % (_array_to_string(names_before), _array_to_string(names_after))) for name in config_names_before: action_config_before = action_name_to_action_before[name] action_config_after = action_name_to_action_after.get(name, None) if action_config_after and not _check_action_config_equivalence( action_config_before, action_config_after): if not found_difference: print(diff_string) # pylint: disable=superfluous-parens found_difference = True print(("* Action config '%s' differs before and after the change:\n" "Value before change:\n%s\n" "Value after change:\n%s") % (name, str(action_config_before), str(action_config_after))) if found_difference: print("") # pylint: disable=superfluous-parens return found_difference def _compare_tool_paths(tool_paths_before, tool_paths_after): """Compares two "CToolchain.ToolPath" lists.""" tool_to_path_before = {} tool_to_path_after = {} for tool_path in tool_paths_before: tool_to_path_before[tool_path.name] = ( tool_path.path if tool_path.path != "NOT_USED" else "") for tool_path in tool_paths_after: tool_to_path_after[tool_path.name] = ( tool_path.path if tool_path.path != "NOT_USED" else "") tool_names_before = set(tool_to_path_before.keys()) tool_names_after = set(tool_to_path_after.keys()) before_after_diff = tool_names_before - tool_names_after after_before_diff = tool_names_after - tool_names_before diff_string = "Difference in 'tool_path' field:" found_difference = False if before_after_diff: if not found_difference: print(diff_string) # pylint: disable=superfluous-parens found_difference = True print(("* List before change contains entries for the following tools " "that the list after the change doesn't:\n%s") % _array_to_string( before_after_diff, ordered=True)) if after_before_diff: if not found_difference: print(diff_string) # pylint: disable=superfluous-parens found_difference = True print(("* List after change contains entries for the following tools that " "the list before the change doesn't:\n%s") % _array_to_string( after_before_diff, ordered=True)) for tool in tool_to_path_before: path_before = tool_to_path_before[tool] path_after = tool_to_path_after.get(tool, None) if path_after and path_after != path_before: if not found_difference: print(diff_string) # pylint: disable=superfluous-parens found_difference = True print(("* Path for tool '%s' differs before and after the change:\n" "Value before change:\t'%s'\n" "Value after change:\t'%s'") % (tool, path_before, path_after)) if found_difference: print("") # pylint: disable=superfluous-parens return found_difference def _compare_make_variables(make_variables_before, make_variables_after): """Compares two "CToolchain.MakeVariable" lists.""" name_to_variable_before = {} name_to_variable_after = {} for variable in make_variables_before: name_to_variable_before[variable.name] = variable.value for variable in make_variables_after: name_to_variable_after[variable.name] = variable.value variable_names_before = set(name_to_variable_before.keys()) variable_names_after = set(name_to_variable_after.keys()) before_after_diff = variable_names_before - variable_names_after after_before_diff = variable_names_after - variable_names_before diff_string = "Difference in 'make_variable' field:" found_difference = False if before_after_diff: if not found_difference: print(diff_string) # pylint: disable=superfluous-parens found_difference = True print(("* List before change contains entries for the following variables " "that the list after the change doesn't:\n%s") % _array_to_string( before_after_diff, ordered=True)) if after_before_diff: if not found_difference: print(diff_string) # pylint: disable=superfluous-parens found_difference = True print(("* List after change contains entries for the following variables " "that the list before the change doesn't:\n%s") % _array_to_string( after_before_diff, ordered=True)) for variable in name_to_variable_before: value_before = name_to_variable_before[variable] value_after = name_to_variable_after.get(variable, None) if value_after and value_after != value_before: if not found_difference: print(diff_string) # pylint: disable=superfluous-parens found_difference = True print( ("* Value for variable '%s' differs before and after the change:\n" "Value before change:\t'%s'\n" "Value after change:\t'%s'") % (variable, value_before, value_after)) if found_difference: print("") # pylint: disable=superfluous-parens return found_difference def _compare_cxx_builtin_include_directories(directories_before, directories_after): if directories_before != directories_after: print(("Difference in 'cxx_builtin_include_directory' field:\n" "List of elements before change:\n%s\n" "List of elements after change:\n%s\n") % (_array_to_string(directories_before), _array_to_string(directories_after))) return True return False def _compare_artifact_name_patterns(artifact_name_patterns_before, artifact_name_patterns_after): """Compares two "CToolchain.ArtifactNamePattern" lists.""" category_to_values_before = {} category_to_values_after = {} for name_pattern in artifact_name_patterns_before: category_to_values_before[name_pattern.category_name] = ( name_pattern.prefix, name_pattern.extension) for name_pattern in artifact_name_patterns_after: category_to_values_after[name_pattern.category_name] = ( name_pattern.prefix, name_pattern.extension) category_names_before = set(category_to_values_before.keys()) category_names_after = set(category_to_values_after.keys()) before_after_diff = category_names_before - category_names_after after_before_diff = category_names_after - category_names_before diff_string = "Difference in 'artifact_name_pattern' field:" found_difference = False if before_after_diff: if not found_difference: print(diff_string) # pylint: disable=superfluous-parens found_difference = True print(("* List before change contains entries for the following categories " "that the list after the change doesn't:\n%s") % _array_to_string( before_after_diff, ordered=True)) if after_before_diff: if not found_difference: print(diff_string) # pylint: disable=superfluous-parens found_difference = True print(("* List after change contains entries for the following categories " "that the list before the change doesn't:\n%s") % _array_to_string( after_before_diff, ordered=True)) for category in category_to_values_before: value_before = category_to_values_before[category] value_after = category_to_values_after.get(category, None) if value_after and value_after != value_before: if not found_difference: print(diff_string) # pylint: disable=superfluous-parens found_difference = True print(("* Value for category '%s' differs before and after the change:\n" "Value before change:\tprefix:'%s'\textension:'%s'\n" "Value after change:\tprefix:'%s'\textension:'%s'") % (category, value_before[0], value_before[1], value_after[0], value_after[1])) if found_difference: print("") # pylint: disable=superfluous-parens return found_difference def compare_ctoolchains(toolchain_before, toolchain_after): """Compares two CToolchains.""" found_difference = False if (toolchain_before.toolchain_identifier != toolchain_after.toolchain_identifier): _print_difference("toolchain_identifier", toolchain_before.toolchain_identifier, toolchain_after.toolchain_identifier) if toolchain_before.host_system_name != toolchain_after.host_system_name: _print_difference("host_system_name", toolchain_before.host_system_name, toolchain_after.host_system_name) found_difference = True if toolchain_before.target_system_name != toolchain_after.target_system_name: _print_difference("target_system_name", toolchain_before.target_system_name, toolchain_after.target_system_name) found_difference = True if toolchain_before.target_cpu != toolchain_after.target_cpu: _print_difference("target_cpu", toolchain_before.target_cpu, toolchain_after.target_cpu) found_difference = True if toolchain_before.target_libc != toolchain_after.target_libc: _print_difference("target_libc", toolchain_before.target_libc, toolchain_after.target_libc) found_difference = True if toolchain_before.compiler != toolchain_after.compiler: _print_difference("compiler", toolchain_before.compiler, toolchain_after.compiler) found_difference = True if toolchain_before.abi_version != toolchain_after.abi_version: _print_difference("abi_version", toolchain_before.abi_version, toolchain_after.abi_version) found_difference = True if toolchain_before.abi_libc_version != toolchain_after.abi_libc_version: _print_difference("abi_libc_version", toolchain_before.abi_libc_version, toolchain_after.abi_libc_version) found_difference = True if toolchain_before.cc_target_os != toolchain_after.cc_target_os: _print_difference("cc_target_os", toolchain_before.cc_target_os, toolchain_after.cc_target_os) found_difference = True if toolchain_before.builtin_sysroot != toolchain_after.builtin_sysroot: _print_difference("builtin_sysroot", toolchain_before.builtin_sysroot, toolchain_after.builtin_sysroot) found_difference = True found_difference = _compare_features( toolchain_before.feature, toolchain_after.feature) or found_difference found_difference = _compare_action_configs( toolchain_before.action_config, toolchain_after.action_config) or found_difference found_difference = _compare_tool_paths( toolchain_before.tool_path, toolchain_after.tool_path) or found_difference found_difference = _compare_cxx_builtin_include_directories( toolchain_before.cxx_builtin_include_directory, toolchain_after.cxx_builtin_include_directory) or found_difference found_difference = _compare_make_variables( toolchain_before.make_variable, toolchain_after.make_variable) or found_difference found_difference = _compare_artifact_name_patterns( toolchain_before.artifact_name_pattern, toolchain_after.artifact_name_pattern) or found_difference if not found_difference: print("No difference") # pylint: disable=superfluous-parens return found_difference ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������rules_cc-0.0.11/tools/migration/ctoolchain_comparator_lib_test.py�����������������������������������0000664�0000000�0000000�00000136066�14700725615�0025355�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Copyright 2018 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. import unittest from py import mock from google.protobuf import text_format from third_party.com.github.bazelbuild.bazel.src.main.protobuf import crosstool_config_pb2 from tools.migration.ctoolchain_comparator_lib import compare_ctoolchains try: # Python 2 from cStringIO import StringIO except ImportError: # Python 3 from io import StringIO def make_toolchain(toolchain_proto): toolchain = crosstool_config_pb2.CToolchain() text_format.Merge(toolchain_proto, toolchain) return toolchain class CtoolchainComparatorLibTest(unittest.TestCase): def test_string_fields(self): first = make_toolchain(""" toolchain_identifier: "first-id" host_system_name: "first-host" target_system_name: "first-target" target_cpu: "first-cpu" target_libc: "first-libc" compiler: "first-compiler" abi_version: "first-abi" abi_libc_version: "first-abi-libc" builtin_sysroot: "sysroot" """) second = make_toolchain(""" toolchain_identifier: "second-id" host_system_name: "second-host" target_system_name: "second-target" target_cpu: "second-cpu" target_libc: "second-libc" compiler: "second-compiler" abi_version: "second-abi" abi_libc_version: "second-abi-libc" cc_target_os: "os" """) error_toolchain_identifier = ( "Difference in 'toolchain_identifier' field:\n" "Value before change:\t'first-id'\n" "Value after change:\t'second-id'\n" ) error_host_system_name = ( "Difference in 'host_system_name' field:\n" "Value before change:\t'first-host'\n" "Value after change:\t'second-host'\n" ) error_target_system_name = ( "Difference in 'target_system_name' field:\n" "Value before change:\t'first-target'\n" "Value after change:\t'second-target'\n" ) error_target_cpu = ( "Difference in 'target_cpu' field:\n" "Value before change:\t'first-cpu'\n" "Value after change:\t'second-cpu'\n" ) error_target_libc = ( "Difference in 'target_libc' field:\n" "Value before change:\t'first-libc'\n" "Value after change:\t'second-libc'\n" ) error_compiler = ( "Difference in 'compiler' field:\n" "Value before change:\t'first-compiler'\n" "Value after change:\t'second-compiler'\n" ) error_abi_version = ( "Difference in 'abi_version' field:\n" "Value before change:\t'first-abi'\n" "Value after change:\t'second-abi'\n" ) error_abi_libc_version = ( "Difference in 'abi_libc_version' field:\n" "Value before change:\t'first-abi-libc'\n" "Value after change:\t'second-abi-libc'\n" ) error_builtin_sysroot = ( "Difference in 'builtin_sysroot' field:\n" "Value before change is set to 'sysroot'\n" "Value after change is not set\n" ) error_cc_target_os = ( "Difference in 'cc_target_os' field:\n" "Value before change is not set\n" "Value after change is set to 'os'\n" ) mock_stdout = StringIO() with mock.patch("sys.stdout", mock_stdout): compare_ctoolchains(first, second) self.assertIn(error_toolchain_identifier, mock_stdout.getvalue()) self.assertIn(error_host_system_name, mock_stdout.getvalue()) self.assertIn(error_target_system_name, mock_stdout.getvalue()) self.assertIn(error_target_cpu, mock_stdout.getvalue()) self.assertIn(error_target_libc, mock_stdout.getvalue()) self.assertIn(error_compiler, mock_stdout.getvalue()) self.assertIn(error_abi_version, mock_stdout.getvalue()) self.assertIn(error_abi_libc_version, mock_stdout.getvalue()) self.assertIn(error_builtin_sysroot, mock_stdout.getvalue()) self.assertIn(error_cc_target_os, mock_stdout.getvalue()) def test_tool_path(self): first = make_toolchain(""" tool_path { name: "only_first" path: "/a/b/c" } tool_path { name: "paths_differ" path: "/path/first" } """) second = make_toolchain(""" tool_path { name: "paths_differ" path: "/path/second" } tool_path { name: "only_second_1" path: "/a/b/c" } tool_path { name: "only_second_2" path: "/a/b/c" } """) error_only_first = ( "* List before change contains entries for the " "following tools that the list after the change " "doesn't:\n[only_first]\n" ) error_only_second = ( "* List after change contains entries for the " "following tools that the list before the change " "doesn't:\n" "[\n" "\tonly_second_1\n" "\tonly_second_2\n" "]\n" ) error_paths_differ = ( "* Path for tool 'paths_differ' differs before and " "after the change:\n" "Value before change:\t'/path/first'\n" "Value after change:\t'/path/second'\n" ) mock_stdout = StringIO() with mock.patch("sys.stdout", mock_stdout): compare_ctoolchains(first, second) self.assertIn(error_only_first, mock_stdout.getvalue()) self.assertIn(error_only_second, mock_stdout.getvalue()) self.assertIn(error_paths_differ, mock_stdout.getvalue()) def test_make_variable(self): first = make_toolchain(""" make_variable { name: "only_first" value: "val" } make_variable { name: "value_differs" value: "first_value" } """) second = make_toolchain(""" make_variable { name: "value_differs" value: "second_value" } make_variable { name: "only_second_1" value: "val" } make_variable { name: "only_second_2" value: "val" } """) error_only_first = ( "* List before change contains entries for the " "following variables that the list after the " "change doesn't:\n[only_first]\n" ) error_only_second = ( "* List after change contains entries for the " "following variables that the list before the " "change doesn't:\n" "[\n" "\tonly_second_1\n" "\tonly_second_2\n" "]\n" ) error_value_differs = ( "* Value for variable 'value_differs' differs before" " and after the change:\n" "Value before change:\t'first_value'\n" "Value after change:\t'second_value'\n" ) mock_stdout = StringIO() with mock.patch("sys.stdout", mock_stdout): compare_ctoolchains(first, second) self.assertIn(error_only_first, mock_stdout.getvalue()) self.assertIn(error_only_second, mock_stdout.getvalue()) self.assertIn(error_value_differs, mock_stdout.getvalue()) def test_cxx_builtin_include_directories(self): first = make_toolchain(""" cxx_builtin_include_directory: "a/b/c" cxx_builtin_include_directory: "d/e/f" """) second = make_toolchain(""" cxx_builtin_include_directory: "d/e/f" cxx_builtin_include_directory: "a/b/c" """) expect_error = ( "Difference in 'cxx_builtin_include_directory' field:\n" "List of elements before change:\n" "[\n" "\ta/b/c\n" "\td/e/f\n" "]\n" "List of elements after change:\n" "[\n" "\td/e/f\n" "\ta/b/c\n" "]\n" ) mock_stdout = StringIO() with mock.patch("sys.stdout", mock_stdout): compare_ctoolchains(first, second) self.assertIn(expect_error, mock_stdout.getvalue()) def test_artifact_name_pattern(self): first = make_toolchain(""" artifact_name_pattern { category_name: 'object_file' prefix: '' extension: '.obj1' } artifact_name_pattern { category_name: 'executable' prefix: 'first' extension: '.exe' } artifact_name_pattern { category_name: 'dynamic_library' prefix: '' extension: '.dll' } """) second = make_toolchain(""" artifact_name_pattern { category_name: 'object_file' prefix: '' extension: '.obj2' } artifact_name_pattern { category_name: 'static_library' prefix: '' extension: '.lib' } artifact_name_pattern { category_name: 'executable' prefix: 'second' extension: '.exe' } artifact_name_pattern { category_name: 'interface_library' prefix: '' extension: '.if.lib' } """) error_only_first = ( "* List before change contains entries for the " "following categories that the list after the " "change doesn't:\n[dynamic_library]\n" ) error_only_second = ( "* List after change contains entries for the " "following categories that the list before the " "change doesn't:\n" "[\n" "\tinterface_library\n" "\tstatic_library\n" "]\n" ) error_extension_differs = ( "* Value for category 'object_file' differs " "before and after the change:\n" "Value before change:" "\tprefix:''" "\textension:'.obj1'\n" "Value after change:" "\tprefix:''" "\textension:'.obj2'\n" ) error_prefix_differs = ( "* Value for category 'executable' differs " "before and after the change:\n" "Value before change:" "\tprefix:'first'" "\textension:'.exe'\n" "Value after change:" "\tprefix:'second'" "\textension:'.exe'\n" ) mock_stdout = StringIO() with mock.patch("sys.stdout", mock_stdout): compare_ctoolchains(first, second) self.assertIn(error_only_first, mock_stdout.getvalue()) self.assertIn(error_only_second, mock_stdout.getvalue()) self.assertIn(error_extension_differs, mock_stdout.getvalue()) self.assertIn(error_prefix_differs, mock_stdout.getvalue()) def test_features_not_ordered(self): first = make_toolchain(""" feature { name: 'feature1' } feature { name: 'feature2' } """) second = make_toolchain(""" feature { name: 'feature2' } feature { name: 'feature1' } """) mock_stdout = StringIO() with mock.patch("sys.stdout", mock_stdout): compare_ctoolchains(first, second) self.assertIn("Features not in right order", mock_stdout.getvalue()) def test_features_missing(self): first = make_toolchain(""" feature { name: 'feature1' } """) second = make_toolchain(""" feature { name: 'feature2' } """) error_only_first = ( "* List before change contains entries for the " "following features that the list after the " "change doesn't:\n[feature1]\n" ) error_only_second = ( "* List after change contains entries for the " "following features that the list before the " "change doesn't:\n[feature2]\n" ) mock_stdout = StringIO() with mock.patch("sys.stdout", mock_stdout): compare_ctoolchains(first, second) self.assertIn(error_only_first, mock_stdout.getvalue()) self.assertIn(error_only_second, mock_stdout.getvalue()) def test_feature_enabled(self): first = make_toolchain(""" feature { name: 'feature' enabled: true } """) second = make_toolchain(""" feature { name: 'feature' enabled: false } """) mock_stdout = StringIO() with mock.patch("sys.stdout", mock_stdout): compare_ctoolchains(first, second) self.assertIn( "* Feature 'feature' differs before and after", mock_stdout.getvalue() ) def test_feature_provides(self): first = make_toolchain(""" feature { name: 'feature' provides: 'a' } """) second = make_toolchain(""" feature { name: 'feature' provides: 'b' } """) mock_stdout = StringIO() with mock.patch("sys.stdout", mock_stdout): compare_ctoolchains(first, second) self.assertIn( "* Feature 'feature' differs before and after the change:", mock_stdout.getvalue(), ) def test_feature_provides_preserves_order(self): first = make_toolchain(""" feature { name: 'feature' provides: 'a' provides: 'b' } """) second = make_toolchain(""" feature { name: 'feature' provides: 'b' provides: 'a' } """) mock_stdout = StringIO() with mock.patch("sys.stdout", mock_stdout): compare_ctoolchains(first, second) self.assertIn( "* Feature 'feature' differs before and after the change:", mock_stdout.getvalue(), ) def test_feature_implies(self): first = make_toolchain(""" feature { name: 'feature' implies: 'a' } """) second = make_toolchain(""" feature { name: 'feature' } """) mock_stdout = StringIO() with mock.patch("sys.stdout", mock_stdout): compare_ctoolchains(first, second) self.assertIn( "* Feature 'feature' differs before and after the change:", mock_stdout.getvalue(), ) def test_feature_implies_preserves_order(self): first = make_toolchain(""" feature { name: 'feature' implies: 'a' implies: 'b' } """) second = make_toolchain(""" feature { name: 'feature' implies: 'b' implies: 'a' } """) mock_stdout = StringIO() with mock.patch("sys.stdout", mock_stdout): compare_ctoolchains(first, second) self.assertIn( "* Feature 'feature' differs before and after the change:", mock_stdout.getvalue(), ) def test_feature_requires_preserves_list_order(self): first = make_toolchain(""" feature { name: 'feature' requires: { feature: 'feature1' } requires: { feature: 'feature2' } } """) second = make_toolchain(""" feature { name: 'feature' requires: { feature: 'feature2' } requires: { feature: 'feature1' } } """) mock_stdout = StringIO() with mock.patch("sys.stdout", mock_stdout): compare_ctoolchains(first, second) self.assertIn( "* Feature 'feature' differs before and after the change:", mock_stdout.getvalue(), ) def test_feature_requires_ignores_required_features_order(self): first = make_toolchain(""" feature { name: 'feature' requires: { feature: 'feature1' feature: 'feature2' } } """) second = make_toolchain(""" feature { name: 'feature' requires: { feature: 'feature2' feature: 'feature1' } } """) mock_stdout = StringIO() with mock.patch("sys.stdout", mock_stdout): compare_ctoolchains(first, second) self.assertIn("No difference", mock_stdout.getvalue()) def test_feature_requires_differs(self): first = make_toolchain(""" feature { name: 'feature' requires: { feature: 'feature1' } } """) second = make_toolchain(""" feature { name: 'feature' requires: { feature: 'feature2' } } """) mock_stdout = StringIO() with mock.patch("sys.stdout", mock_stdout): compare_ctoolchains(first, second) self.assertIn( "* Feature 'feature' differs before and after the change:", mock_stdout.getvalue(), ) def test_action_config_ignores_requires(self): first = make_toolchain(""" action_config { config_name: 'config' requires: { feature: 'feature1' } } """) second = make_toolchain(""" action_config { config_name: 'config' requires: { feature: 'feature2' } } """) mock_stdout = StringIO() with mock.patch("sys.stdout", mock_stdout): compare_ctoolchains(first, second) self.assertIn("No difference", mock_stdout.getvalue()) def test_env_set_actions_differ(self): first = make_toolchain(""" feature { name: 'feature' env_set { action: 'a1' } } """) second = make_toolchain(""" feature { name: 'feature' env_set: { action: 'a1' action: 'a2' } } """) mock_stdout = StringIO() with mock.patch("sys.stdout", mock_stdout): compare_ctoolchains(first, second) self.assertIn( "* Feature 'feature' differs before and after the change:", mock_stdout.getvalue(), ) def test_env_set_ignores_actions_order(self): first = make_toolchain(""" feature { name: 'feature' env_set { action: 'a2' action: 'a1' } } """) second = make_toolchain(""" feature { name: 'feature' env_set: { action: 'a1' action: 'a2' } } """) mock_stdout = StringIO() with mock.patch("sys.stdout", mock_stdout): compare_ctoolchains(first, second) self.assertIn("No difference", mock_stdout.getvalue()) def test_env_set_env_entries_not_ordered(self): first = make_toolchain(""" feature { name: 'feature' env_set { env_entry { key: 'k1' value: 'v1' } env_entry { key: 'k2' value: 'v2' } } } """) second = make_toolchain(""" feature { name: 'feature' env_set { env_entry { key: 'k2' value: 'v2' } env_entry { key: 'k1' value: 'v1' } } } """) mock_stdout = StringIO() with mock.patch("sys.stdout", mock_stdout): compare_ctoolchains(first, second) self.assertIn( "* Feature 'feature' differs before and after the change:", mock_stdout.getvalue(), ) def test_env_set_env_entries_differ(self): first = make_toolchain(""" feature { name: 'feature' env_set { env_entry { key: 'k1' value: 'value_first' } } } """) second = make_toolchain(""" feature { name: 'feature' env_set { env_entry { key: 'k1' value: 'value_second' } } } """) mock_stdout = StringIO() with mock.patch("sys.stdout", mock_stdout): compare_ctoolchains(first, second) self.assertIn( "* Feature 'feature' differs before and after the change:", mock_stdout.getvalue(), ) def test_feature_preserves_env_set_order(self): first = make_toolchain(""" feature { name: 'feature' env_set { env_entry { key: 'first' value: 'first' } } env_set { env_entry { key: 'second' value: 'second' } } } """) second = make_toolchain(""" feature { name: 'feature' env_set { env_entry { key: 'second' value: 'second' } } env_set { env_entry { key: 'first' value: 'first' } } } """) mock_stdout = StringIO() with mock.patch("sys.stdout", mock_stdout): compare_ctoolchains(first, second) self.assertIn( "* Feature 'feature' differs before and after the change:", mock_stdout.getvalue(), ) def test_action_config_ignores_env_set(self): first = make_toolchain(""" action_config { config_name: 'config' env_set { env_entry { key: 'k1' value: 'value_first' } } } """) second = make_toolchain(""" action_config { config_name: 'config' env_set { env_entry { key: 'k1' value: 'value_second' } } } """) mock_stdout = StringIO() with mock.patch("sys.stdout", mock_stdout): compare_ctoolchains(first, second) self.assertIn("No difference", mock_stdout.getvalue()) def test_env_set_ignores_with_feature_set_order(self): first = make_toolchain(""" feature { name: 'feature' env_set{ with_feature { feature: 'feature1' } with_feature { not_feature: 'feature2' } } } """) second = make_toolchain(""" feature { name: 'feature' env_set { with_feature { not_feature: 'feature2' } with_feature { feature: 'feature1' } } } """) mock_stdout = StringIO() with mock.patch("sys.stdout", mock_stdout): compare_ctoolchains(first, second) self.assertIn("No difference", mock_stdout.getvalue()) def test_env_set_ignores_with_feature_set_lists_order(self): first = make_toolchain(""" feature { name: 'feature' env_set{ with_feature { feature: 'feature1' feature: 'feature2' not_feature: 'not_feature1' not_feature: 'not_feature2' } } } """) second = make_toolchain(""" feature { name: 'feature' env_set{ with_feature { feature: 'feature2' feature: 'feature1' not_feature: 'not_feature2' not_feature: 'not_feature1' } } } """) mock_stdout = StringIO() with mock.patch("sys.stdout", mock_stdout): compare_ctoolchains(first, second) self.assertIn("No difference", mock_stdout.getvalue()) def test_flag_set_ignores_actions_order(self): first = make_toolchain(""" feature { name: 'feature' flag_set { action: 'a1' action: 'a2' } } """) second = make_toolchain(""" feature { name: 'feature' flag_set { action: 'a2' action: 'a1' } } """) mock_stdout = StringIO() with mock.patch("sys.stdout", mock_stdout): compare_ctoolchains(first, second) self.assertIn("No difference", mock_stdout.getvalue()) def test_action_config_flag_set_actions_ignored(self): first = make_toolchain(""" action_config { config_name: 'config' flag_set { action: 'a1' } } """) second = make_toolchain(""" action_config { config_name: 'config' flag_set { action: 'a2' } } """) mock_stdout = StringIO() with mock.patch("sys.stdout", mock_stdout): compare_ctoolchains(first, second) self.assertIn("No difference", mock_stdout.getvalue()) def test_flag_set_ignores_with_feature_set_order(self): first = make_toolchain(""" feature { name: 'feature' flag_set { with_feature { feature: 'feature1' } with_feature { not_feature: 'feature2' } } } action_config { config_name: 'config' flag_set { with_feature { feature: 'feature1' } with_feature { not_feature: 'feature2' } } } """) second = make_toolchain(""" feature { name: 'feature' flag_set { with_feature { not_feature: 'feature2' } with_feature { feature: 'feature1' } } } action_config { config_name: 'config' flag_set { with_feature { not_feature: 'feature2' } with_feature { feature: 'feature1' } } } """) mock_stdout = StringIO() with mock.patch("sys.stdout", mock_stdout): compare_ctoolchains(first, second) self.assertIn("No difference", mock_stdout.getvalue()) def test_flag_set_ignores_with_feature_set_lists_order(self): first = make_toolchain(""" feature { name: 'feature' flag_set{ with_feature { feature: 'feature1' feature: 'feature2' not_feature: 'not_feature1' not_feature: 'not_feature2' } } } action_config { config_name: 'config' flag_set{ with_feature { feature: 'feature1' feature: 'feature2' not_feature: 'not_feature1' not_feature: 'not_feature2' } } } """) second = make_toolchain(""" feature { name: 'feature' flag_set{ with_feature { feature: 'feature2' feature: 'feature1' not_feature: 'not_feature2' not_feature: 'not_feature1' } } } action_config { config_name: 'config' flag_set{ with_feature { feature: 'feature2' feature: 'feature1' not_feature: 'not_feature2' not_feature: 'not_feature1' } } } """) mock_stdout = StringIO() with mock.patch("sys.stdout", mock_stdout): compare_ctoolchains(first, second) self.assertIn("No difference", mock_stdout.getvalue()) def test_flag_set_preserves_flag_group_order(self): first = make_toolchain(""" feature { name: 'feature' flag_set { flag_group { flag: 'a' } flag_group { flag: 'b' } } } action_config { config_name: 'config' flag_set { flag_group { flag: 'a' } flag_group { flag: 'b' } } } """) second = make_toolchain(""" feature { name: 'feature' flag_set { flag_group { flag: 'b' } flag_group { flag: 'a' } } } action_config { config_name: 'config' flag_set { flag_group { flag: 'b' } flag_group { flag: 'a' } } } """) mock_stdout = StringIO() with mock.patch("sys.stdout", mock_stdout): compare_ctoolchains(first, second) self.assertIn( "* Feature 'feature' differs before and after", mock_stdout.getvalue() ) self.assertIn( "* Action config 'config' differs before and after", mock_stdout.getvalue(), ) def test_flag_group_preserves_flags_order(self): first = make_toolchain(""" feature { name: 'feature' flag_set{ flag_group { flag: 'flag1' flag: 'flag2' } } } action_config { config_name: 'config' flag_set{ flag_group { flag: 'flag1' flag: 'flag2' } } } """) second = make_toolchain(""" feature { name: 'feature' flag_set{ flag_group { flag: 'flag2' flag: 'flag1' } } } action_config { config_name: 'config' flag_set{ flag_group { flag: 'flag2' flag: 'flag1' } } } """) mock_stdout = StringIO() with mock.patch("sys.stdout", mock_stdout): compare_ctoolchains(first, second) self.assertIn( "* Feature 'feature' differs before and after", mock_stdout.getvalue() ) self.assertIn( "* Action config 'config' differs before and after", mock_stdout.getvalue(), ) def test_flag_group_iterate_over_differs(self): first = make_toolchain(""" feature { name: 'feature' flag_set{ flag_group { iterate_over: 'a' } } } action_config { config_name: 'config' flag_set{ flag_group { iterate_over: 'a' } } } """) second = make_toolchain(""" feature { name: 'feature' flag_set{ flag_group { iterate_over: 'b' } } } action_config { config_name: 'config' flag_set{ flag_group { iterate_over: 'b' } } } """) mock_stdout = StringIO() with mock.patch("sys.stdout", mock_stdout): compare_ctoolchains(first, second) self.assertIn( "* Feature 'feature' differs before and after", mock_stdout.getvalue() ) self.assertIn( "* Action config 'config' differs before and after", mock_stdout.getvalue(), ) def test_flag_group_expand_if_true_differs(self): first = make_toolchain(""" feature { name: 'feature' flag_set{ flag_group { expand_if_true: 'a' } } } action_config { config_name: 'config' flag_set{ flag_group { expand_if_true: 'a' } } } """) second = make_toolchain(""" feature { name: 'feature' flag_set{ flag_group { expand_if_true: 'b' } } } action_config { config_name: 'config' flag_set{ flag_group { expand_if_true: 'b' } } } """) mock_stdout = StringIO() with mock.patch("sys.stdout", mock_stdout): compare_ctoolchains(first, second) self.assertIn( "* Feature 'feature' differs before and after", mock_stdout.getvalue() ) self.assertIn( "* Action config 'config' differs before and after", mock_stdout.getvalue(), ) def test_flag_group_expand_if_false_differs(self): first = make_toolchain(""" feature { name: 'feature' flag_set{ flag_group { expand_if_false: 'a' } } } action_config { config_name: 'config' flag_set{ flag_group { expand_if_false: 'a' } } } """) second = make_toolchain(""" feature { name: 'feature' flag_set{ flag_group { expand_if_false: 'b' } } } action_config { config_name: 'config' flag_set{ flag_group { expand_if_false: 'b' } } } """) mock_stdout = StringIO() with mock.patch("sys.stdout", mock_stdout): compare_ctoolchains(first, second) self.assertIn( "* Feature 'feature' differs before and after", mock_stdout.getvalue() ) self.assertIn( "* Action config 'config' differs before and after", mock_stdout.getvalue(), ) def test_flag_group_expand_if_all_available_differs(self): first = make_toolchain(""" feature { name: 'feature' flag_set{ flag_group { expand_if_all_available: 'a' } } } action_config { config_name: 'config' flag_set{ flag_group { expand_if_all_available: 'a' } } } """) second = make_toolchain(""" feature { name: 'feature' flag_set{ flag_group { expand_if_all_available: 'b' } } } action_config { config_name: 'config' flag_set{ flag_group { expand_if_all_available: 'b' } } } """) mock_stdout = StringIO() with mock.patch("sys.stdout", mock_stdout): compare_ctoolchains(first, second) self.assertIn( "* Feature 'feature' differs before and after", mock_stdout.getvalue() ) self.assertIn( "* Action config 'config' differs before and after", mock_stdout.getvalue(), ) def test_flag_group_expand_if_none_available_differs(self): first = make_toolchain(""" feature { name: 'feature' flag_set{ flag_group { expand_if_none_available: 'a' } } } action_config { config_name: 'config' flag_set{ flag_group { expand_if_none_available: 'a' } } } """) second = make_toolchain(""" feature { name: 'feature' flag_set{ flag_group { expand_if_none_available: 'b' } } } action_config { config_name: 'config' flag_set{ flag_group { expand_if_none_available: 'b' } } } """) mock_stdout = StringIO() with mock.patch("sys.stdout", mock_stdout): compare_ctoolchains(first, second) self.assertIn( "* Feature 'feature' differs before and after", mock_stdout.getvalue() ) self.assertIn( "* Action config 'config' differs before and after", mock_stdout.getvalue(), ) def test_flag_group_expand_if_all_available_ignores_order(self): first = make_toolchain(""" feature { name: 'feature' flag_set{ flag_group { expand_if_all_available: 'a' expand_if_all_available: 'b' } } } action_config { config_name: 'config' flag_set{ flag_group { expand_if_all_available: 'a' expand_if_all_available: 'b' } } } """) second = make_toolchain(""" feature { name: 'feature' flag_set{ flag_group { expand_if_all_available: 'b' expand_if_all_available: 'a' } } } action_config { config_name: 'config' flag_set{ flag_group { expand_if_all_available: 'b' expand_if_all_available: 'a' } } } """) mock_stdout = StringIO() with mock.patch("sys.stdout", mock_stdout): compare_ctoolchains(first, second) self.assertIn("No difference", mock_stdout.getvalue()) def test_flag_group_expand_if_none_available_ignores_order(self): first = make_toolchain(""" feature { name: 'feature' flag_set{ flag_group { expand_if_none_available: 'a' expand_if_none_available: 'b' } } } action_config { config_name: 'config' flag_set{ flag_group { expand_if_none_available: 'a' expand_if_none_available: 'b' } } } """) second = make_toolchain(""" feature { name: 'feature' flag_set{ flag_group { expand_if_none_available: 'b' expand_if_none_available: 'a' } } } action_config { config_name: 'config' flag_set{ flag_group { expand_if_none_available: 'b' expand_if_none_available: 'a' } } } """) mock_stdout = StringIO() with mock.patch("sys.stdout", mock_stdout): compare_ctoolchains(first, second) self.assertIn("No difference", mock_stdout.getvalue()) def test_flag_group_expand_if_equal_differs(self): first = make_toolchain(""" feature { name: 'feature' flag_set{ flag_group { expand_if_equal { variable: 'first' value: 'val' } } } } action_config { config_name: 'config' flag_set{ flag_group { expand_if_equal { variable: 'first' value: 'val' } } } } """) second = make_toolchain(""" feature { name: 'feature' flag_set{ flag_group { expand_if_equal { variable: 'second' value: 'val' } } } } action_config { config_name: 'config' flag_set{ flag_group { expand_if_equal { variable: 'second' value: 'val' } } } } """) mock_stdout = StringIO() with mock.patch("sys.stdout", mock_stdout): compare_ctoolchains(first, second) self.assertIn( "* Feature 'feature' differs before and after", mock_stdout.getvalue() ) self.assertIn( "* Action config 'config' differs before and after", mock_stdout.getvalue(), ) def test_flag_group_flag_groups_differ(self): first = make_toolchain(""" feature { name: 'feature' flag_set{ flag_group { flag_group { flag: 'a' flag: 'b' } } } } action_config { config_name: 'config' flag_set{ flag_group { flag_group { flag: 'a' flag: 'b' } } } } """) second = make_toolchain(""" feature { name: 'feature' flag_set{ flag_group { flag_group { flag: 'b' flag: 'a' } } } } action_config { config_name: 'config' flag_set{ flag_group { flag_group { flag: 'b' flag: 'a' } } } } """) mock_stdout = StringIO() with mock.patch("sys.stdout", mock_stdout): compare_ctoolchains(first, second) self.assertIn( "* Feature 'feature' differs before and after", mock_stdout.getvalue() ) self.assertIn( "* Action config 'config' differs before and after", mock_stdout.getvalue(), ) def test_action_configs_not_ordered(self): first = make_toolchain(""" action_config { config_name: 'action1' } action_config { config_name: 'action2' } """) second = make_toolchain(""" action_config { config_name: 'action2' } action_config { config_name: 'action1' } """) mock_stdout = StringIO() with mock.patch("sys.stdout", mock_stdout): compare_ctoolchains(first, second) self.assertIn("Action configs not in right order", mock_stdout.getvalue()) def test_action_configs_missing(self): first = make_toolchain(""" action_config { config_name: 'action1' } """) second = make_toolchain(""" action_config { config_name: 'action2' } """) error_only_first = ( "* List before change contains entries for the " "following action_configs that the list after the " "change doesn't:\n[action1]\n" ) error_only_second = ( "* List after change contains entries for the " "following action_configs that the list before the " "change doesn't:\n[action2]\n" ) mock_stdout = StringIO() with mock.patch("sys.stdout", mock_stdout): compare_ctoolchains(first, second) self.assertIn(error_only_first, mock_stdout.getvalue()) self.assertIn(error_only_second, mock_stdout.getvalue()) def test_action_config_enabled(self): first = make_toolchain(""" action_config { config_name: 'config' enabled: true } """) second = make_toolchain(""" action_config { config_name: 'config' enabled: false } """) mock_stdout = StringIO() with mock.patch("sys.stdout", mock_stdout): compare_ctoolchains(first, second) self.assertIn( "* Action config 'config' differs before and after", mock_stdout.getvalue(), ) def test_action_config_action_name(self): first = make_toolchain(""" action_config { config_name: 'config' action_name: 'config1' } """) second = make_toolchain(""" action_config { config_name: 'config' action_name: 'config2' } """) mock_stdout = StringIO() with mock.patch("sys.stdout", mock_stdout): compare_ctoolchains(first, second) self.assertIn( "* Action config 'config' differs before and after", mock_stdout.getvalue(), ) def test_action_config_tool_tool_path_differs(self): first = make_toolchain(""" action_config { config_name: 'config' tool { tool_path: 'path1' } } """) second = make_toolchain(""" action_config { config_name: 'config' tool { tool_path: 'path2' } } """) mock_stdout = StringIO() with mock.patch("sys.stdout", mock_stdout): compare_ctoolchains(first, second) self.assertIn( "* Action config 'config' differs before and after", mock_stdout.getvalue(), ) def test_action_config_tool_execution_requirements_differ(self): first = make_toolchain(""" action_config { config_name: 'config' tool { execution_requirement: 'a' } } """) second = make_toolchain(""" action_config { config_name: 'config' tool { execution_requirement: 'b' } } """) mock_stdout = StringIO() with mock.patch("sys.stdout", mock_stdout): compare_ctoolchains(first, second) self.assertIn( "* Action config 'config' differs before and after", mock_stdout.getvalue(), ) def test_action_config_tool_execution_requirements_ignores_order(self): first = make_toolchain(""" action_config { config_name: 'config' tool { execution_requirement: 'a' execution_requirement: 'b' } } """) second = make_toolchain(""" action_config { config_name: 'config' tool { execution_requirement: 'b' execution_requirement: 'a' } } """) mock_stdout = StringIO() with mock.patch("sys.stdout", mock_stdout): compare_ctoolchains(first, second) self.assertIn("No difference", mock_stdout.getvalue()) def test_action_config_implies_differs(self): first = make_toolchain(""" action_config { config_name: 'config' implies: 'a' } """) second = make_toolchain(""" action_config { config_name: 'config' implies: 'b' } """) mock_stdout = StringIO() with mock.patch("sys.stdout", mock_stdout): compare_ctoolchains(first, second) self.assertIn( "* Action config 'config' differs before and after", mock_stdout.getvalue(), ) def test_action_config_implies_preserves_order(self): first = make_toolchain(""" action_config { config_name: 'config' implies: 'a' implies: 'b' } """) second = make_toolchain(""" action_config { config_name: 'config' implies: 'b' implies: 'a' } """) mock_stdout = StringIO() with mock.patch("sys.stdout", mock_stdout): compare_ctoolchains(first, second) self.assertIn( "* Action config 'config' differs before and after", mock_stdout.getvalue(), ) def test_unused_tool_path(self): first = make_toolchain(""" tool_path { name: "empty" path: "" } """) second = make_toolchain(""" tool_path { name: "empty" path: "NOT_USED" } """) mock_stdout = StringIO() with mock.patch("sys.stdout", mock_stdout): compare_ctoolchains(first, second) self.assertIn("No difference", mock_stdout.getvalue()) def test_unused_tool_path_in_tool(self): first = make_toolchain(""" action_config { config_name: 'config' tool { tool_path: '' } } """) second = make_toolchain(""" action_config { config_name: 'config' tool { tool_path: 'NOT_USED' } } """) mock_stdout = StringIO() with mock.patch("sys.stdout", mock_stdout): compare_ctoolchains(first, second) self.assertIn("No difference", mock_stdout.getvalue()) if __name__ == "__main__": unittest.main() ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������rules_cc-0.0.11/tools/migration/ctoolchain_compare.bzl����������������������������������������������0000664�0000000�0000000�00000003400�14700725615�0023067�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""A test rule that compares two CToolchains in proto format.""" def _impl(ctx): toolchain_config_proto = ctx.actions.declare_file(ctx.label.name + "_toolchain_config.proto") ctx.actions.write( toolchain_config_proto, ctx.attr.toolchain_config[CcToolchainConfigInfo].proto, ) script = ("%s --before='%s' --after='%s' --toolchain_identifier='%s'" % ( ctx.executable._comparator.short_path, ctx.file.crosstool.short_path, toolchain_config_proto.short_path, ctx.attr.toolchain_identifier, )) test_executable = ctx.actions.declare_file(ctx.label.name) ctx.actions.write(test_executable, script, is_executable = True) runfiles = ctx.runfiles(files = [toolchain_config_proto, ctx.file.crosstool]) runfiles = runfiles.merge(ctx.attr._comparator[DefaultInfo].default_runfiles) return DefaultInfo(runfiles = runfiles, executable = test_executable) cc_toolchains_compare_test = rule( implementation = _impl, attrs = { "crosstool": attr.label( mandatory = True, allow_single_file = True, doc = "Location of the CROSSTOOL file", ), "toolchain_config": attr.label( mandatory = True, providers = [CcToolchainConfigInfo], doc = ("Starlark rule that replaces the CROSSTOOL file functionality " + "for the CToolchain with the given identifier"), ), "toolchain_identifier": attr.string( mandatory = True, doc = "identifier of the CToolchain that is being compared", ), "_comparator": attr.label( default = ":ctoolchain_comparator", executable = True, cfg = "exec", ), }, test = True, ) ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������rules_cc-0.0.11/tools/migration/legacy_fields_migration_lib.py��������������������������������������0000664�0000000�0000000�00000050343�14700725615�0024600�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Module providing migrate_legacy_fields function. migrate_legacy_fields takes parsed CROSSTOOL proto and migrates it (inplace) to use only the features. Tracking issue: https://github.com/bazelbuild/bazel/issues/5187 Since C++ rules team is working on migrating CROSSTOOL from text proto into Starlark, we advise CROSSTOOL owners to wait for the CROSSTOOL -> Starlark migrator before they invest too much time into fixing their pipeline. Tracking issue for the Starlark effort is https://github.com/bazelbuild/bazel/issues/5380. """ from third_party.com.github.bazelbuild.bazel.src.main.protobuf import crosstool_config_pb2 ALL_CC_COMPILE_ACTIONS = [ "assemble", "preprocess-assemble", "linkstamp-compile", "c-compile", "c++-compile", "c++-header-parsing", "c++-module-compile", "c++-module-codegen", "lto-backend", "clif-match" ] ALL_OBJC_COMPILE_ACTIONS = [ "objc-compile", "objc++-compile" ] ALL_CXX_COMPILE_ACTIONS = [ action for action in ALL_CC_COMPILE_ACTIONS if action not in ["c-compile", "preprocess-assemble", "assemble"] ] ALL_CC_LINK_ACTIONS = [ "c++-link-executable", "c++-link-dynamic-library", "c++-link-nodeps-dynamic-library" ] ALL_OBJC_LINK_ACTIONS = [ "objc-executable", "objc++-executable", ] DYNAMIC_LIBRARY_LINK_ACTIONS = [ "c++-link-dynamic-library", "c++-link-nodeps-dynamic-library" ] NODEPS_DYNAMIC_LIBRARY_LINK_ACTIONS = ["c++-link-nodeps-dynamic-library"] TRANSITIVE_DYNAMIC_LIBRARY_LINK_ACTIONS = ["c++-link-dynamic-library"] TRANSITIVE_LINK_ACTIONS = ["c++-link-executable", "c++-link-dynamic-library"] CC_LINK_EXECUTABLE = ["c++-link-executable"] def compile_actions(toolchain): """Returns compile actions for cc or objc rules.""" if _is_objc_toolchain(toolchain): return ALL_CC_COMPILE_ACTIONS + ALL_OBJC_COMPILE_ACTIONS else: return ALL_CC_COMPILE_ACTIONS def link_actions(toolchain): """Returns link actions for cc or objc rules.""" if _is_objc_toolchain(toolchain): return ALL_CC_LINK_ACTIONS + ALL_OBJC_LINK_ACTIONS else: return ALL_CC_LINK_ACTIONS def executable_link_actions(toolchain): """Returns transitive link actions for cc or objc rules.""" if _is_objc_toolchain(toolchain): return CC_LINK_EXECUTABLE + ALL_OBJC_LINK_ACTIONS else: return CC_LINK_EXECUTABLE def _is_objc_toolchain(toolchain): return any(ac.action_name == "objc-compile" for ac in toolchain.action_config) # Map converting from LinkingMode to corresponding feature name LINKING_MODE_TO_FEATURE_NAME = { "FULLY_STATIC": "fully_static_link", "MOSTLY_STATIC": "static_linking_mode", "DYNAMIC": "dynamic_linking_mode", "MOSTLY_STATIC_LIBRARIES": "static_linking_mode_nodeps_library", } def migrate_legacy_fields(crosstool): """Migrates parsed crosstool (inplace) to not use legacy fields.""" crosstool.ClearField("default_toolchain") for toolchain in crosstool.toolchain: _ = [_migrate_expand_if_all_available(f) for f in toolchain.feature] _ = [_migrate_expand_if_all_available(ac) for ac in toolchain.action_config] _ = [_migrate_repeated_expands(f) for f in toolchain.feature] _ = [_migrate_repeated_expands(ac) for ac in toolchain.action_config] if (toolchain.dynamic_library_linker_flag or _contains_dynamic_flags(toolchain)) and not _get_feature( toolchain, "supports_dynamic_linker"): feature = toolchain.feature.add() feature.name = "supports_dynamic_linker" feature.enabled = True if toolchain.supports_start_end_lib and not _get_feature( toolchain, "supports_start_end_lib"): feature = toolchain.feature.add() feature.name = "supports_start_end_lib" feature.enabled = True if toolchain.supports_interface_shared_objects and not _get_feature( toolchain, "supports_interface_shared_libraries"): feature = toolchain.feature.add() feature.name = "supports_interface_shared_libraries" feature.enabled = True if toolchain.supports_embedded_runtimes and not _get_feature( toolchain, "static_link_cpp_runtimes"): feature = toolchain.feature.add() feature.name = "static_link_cpp_runtimes" feature.enabled = True if toolchain.needsPic and not _get_feature(toolchain, "supports_pic"): feature = toolchain.feature.add() feature.name = "supports_pic" feature.enabled = True if toolchain.supports_fission and not _get_feature( toolchain, "per_object_debug_info"): # feature { # name: "per_object_debug_info" # enabled: true # flag_set { # action: "assemble" # action: "preprocess-assemble" # action: "c-compile" # action: "c++-compile" # action: "c++-module-codegen" # action: "lto-backend" # flag_group { # expand_if_all_available: 'is_using_fission'", # flag: "-gsplit-dwarf" # } # } # } feature = toolchain.feature.add() feature.name = "per_object_debug_info" feature.enabled = True flag_set = feature.flag_set.add() flag_set.action[:] = [ "c-compile", "c++-compile", "c++-module-codegen", "assemble", "preprocess-assemble", "lto-backend" ] flag_group = flag_set.flag_group.add() flag_group.expand_if_all_available[:] = ["is_using_fission"] flag_group.flag[:] = ["-gsplit-dwarf"] if toolchain.objcopy_embed_flag and not _get_feature( toolchain, "objcopy_embed_flags"): feature = toolchain.feature.add() feature.name = "objcopy_embed_flags" feature.enabled = True flag_set = feature.flag_set.add() flag_set.action[:] = ["objcopy_embed_data"] flag_group = flag_set.flag_group.add() flag_group.flag[:] = toolchain.objcopy_embed_flag action_config = toolchain.action_config.add() action_config.action_name = "objcopy_embed_data" action_config.config_name = "objcopy_embed_data" action_config.enabled = True tool = action_config.tool.add() tool.tool_path = _find_tool_path(toolchain, "objcopy") if toolchain.ld_embed_flag and not _get_feature( toolchain, "ld_embed_flags"): feature = toolchain.feature.add() feature.name = "ld_embed_flags" feature.enabled = True flag_set = feature.flag_set.add() flag_set.action[:] = ["ld_embed_data"] flag_group = flag_set.flag_group.add() flag_group.flag[:] = toolchain.ld_embed_flag action_config = toolchain.action_config.add() action_config.action_name = "ld_embed_data" action_config.config_name = "ld_embed_data" action_config.enabled = True tool = action_config.tool.add() tool.tool_path = _find_tool_path(toolchain, "ld") # Create default_link_flags feature for linker_flag flag_sets = _extract_legacy_link_flag_sets_for(toolchain) if flag_sets: if _get_feature(toolchain, "default_link_flags"): continue if _get_feature(toolchain, "legacy_link_flags"): for f in toolchain.feature: if f.name == "legacy_link_flags": f.ClearField("flag_set") feature = f _rename_feature_in_toolchain(toolchain, "legacy_link_flags", "default_link_flags") break else: feature = _prepend_feature(toolchain) feature.name = "default_link_flags" feature.enabled = True _add_flag_sets(feature, flag_sets) # Create default_compile_flags feature for compiler_flag, cxx_flag flag_sets = _extract_legacy_compile_flag_sets_for(toolchain) if flag_sets and not _get_feature(toolchain, "default_compile_flags"): if _get_feature(toolchain, "legacy_compile_flags"): for f in toolchain.feature: if f.name == "legacy_compile_flags": f.ClearField("flag_set") feature = f _rename_feature_in_toolchain(toolchain, "legacy_compile_flags", "default_compile_flags") break else: feature = _prepend_feature(toolchain) feature.enabled = True feature.name = "default_compile_flags" _add_flag_sets(feature, flag_sets) # Unfiltered cxx flags have to have their own special feature. # "unfiltered_compile_flags" is a well-known (by Bazel) feature name that is # excluded from nocopts filtering. if toolchain.unfiltered_cxx_flag: # If there already is a feature named unfiltered_compile_flags, the # crosstool is already migrated for unfiltered_compile_flags if _get_feature(toolchain, "unfiltered_compile_flags"): for f in toolchain.feature: if f.name == "unfiltered_compile_flags": for flag_set in f.flag_set: for flag_group in flag_set.flag_group: if flag_group.iterate_over == "unfiltered_compile_flags": flag_group.ClearField("iterate_over") flag_group.ClearField("expand_if_all_available") flag_group.ClearField("flag") flag_group.flag[:] = toolchain.unfiltered_cxx_flag else: if not _get_feature(toolchain, "user_compile_flags"): feature = toolchain.feature.add() feature.name = "user_compile_flags" feature.enabled = True flag_set = feature.flag_set.add() flag_set.action[:] = compile_actions(toolchain) flag_group = flag_set.flag_group.add() flag_group.expand_if_all_available[:] = ["user_compile_flags"] flag_group.iterate_over = "user_compile_flags" flag_group.flag[:] = ["%{user_compile_flags}"] if not _get_feature(toolchain, "sysroot"): sysroot_actions = compile_actions(toolchain) + link_actions(toolchain) sysroot_actions.remove("assemble") feature = toolchain.feature.add() feature.name = "sysroot" feature.enabled = True flag_set = feature.flag_set.add() flag_set.action[:] = sysroot_actions flag_group = flag_set.flag_group.add() flag_group.expand_if_all_available[:] = ["sysroot"] flag_group.flag[:] = ["--sysroot=%{sysroot}"] feature = toolchain.feature.add() feature.name = "unfiltered_compile_flags" feature.enabled = True flag_set = feature.flag_set.add() flag_set.action[:] = compile_actions(toolchain) flag_group = flag_set.flag_group.add() flag_group.flag[:] = toolchain.unfiltered_cxx_flag # clear fields toolchain.ClearField("debian_extra_requires") toolchain.ClearField("gcc_plugin_compiler_flag") toolchain.ClearField("ar_flag") toolchain.ClearField("ar_thin_archives_flag") toolchain.ClearField("gcc_plugin_header_directory") toolchain.ClearField("mao_plugin_header_directory") toolchain.ClearField("supports_normalizing_ar") toolchain.ClearField("supports_thin_archives") toolchain.ClearField("supports_incremental_linker") toolchain.ClearField("supports_dsym") toolchain.ClearField("supports_gold_linker") toolchain.ClearField("default_python_top") toolchain.ClearField("default_python_version") toolchain.ClearField("python_preload_swigdeps") toolchain.ClearField("needsPic") toolchain.ClearField("compilation_mode_flags") toolchain.ClearField("linking_mode_flags") toolchain.ClearField("unfiltered_cxx_flag") toolchain.ClearField("ld_embed_flag") toolchain.ClearField("objcopy_embed_flag") toolchain.ClearField("supports_start_end_lib") toolchain.ClearField("supports_interface_shared_objects") toolchain.ClearField("supports_fission") toolchain.ClearField("supports_embedded_runtimes") toolchain.ClearField("compiler_flag") toolchain.ClearField("cxx_flag") toolchain.ClearField("linker_flag") toolchain.ClearField("dynamic_library_linker_flag") toolchain.ClearField("static_runtimes_filegroup") toolchain.ClearField("dynamic_runtimes_filegroup") # Enable features that were previously enabled by Bazel default_features = [ "dependency_file", "random_seed", "module_maps", "module_map_home_cwd", "header_module_compile", "include_paths", "pic", "preprocessor_define" ] for feature_name in default_features: feature = _get_feature(toolchain, feature_name) if feature: feature.enabled = True def _find_tool_path(toolchain, tool_name): """Returns the tool path of the tool with the given name.""" for tool in toolchain.tool_path: if tool.name == tool_name: return tool.path return None def _add_flag_sets(feature, flag_sets): """Add flag sets into a feature.""" for flag_set in flag_sets: with_feature = flag_set[0] actions = flag_set[1] flags = flag_set[2] expand_if_all_available = flag_set[3] not_feature = None if len(flag_set) >= 5: not_feature = flag_set[4] flag_set = feature.flag_set.add() if with_feature is not None: flag_set.with_feature.add().feature[:] = [with_feature] if not_feature is not None: flag_set.with_feature.add().not_feature[:] = [not_feature] flag_set.action[:] = actions flag_group = flag_set.flag_group.add() flag_group.expand_if_all_available[:] = expand_if_all_available flag_group.flag[:] = flags return feature def _extract_legacy_compile_flag_sets_for(toolchain): """Get flag sets for default_compile_flags feature.""" result = [] if toolchain.compiler_flag: result.append( [None, compile_actions(toolchain), toolchain.compiler_flag, []]) # Migrate compiler_flag from compilation_mode_flags for cmf in toolchain.compilation_mode_flags: mode = crosstool_config_pb2.CompilationMode.Name(cmf.mode).lower() # coverage mode has been a noop since a while if mode == "coverage": continue if (cmf.compiler_flag or cmf.cxx_flag) and not _get_feature(toolchain, mode): feature = toolchain.feature.add() feature.name = mode if cmf.compiler_flag: result.append([mode, compile_actions(toolchain), cmf.compiler_flag, []]) if toolchain.cxx_flag: result.append([None, ALL_CXX_COMPILE_ACTIONS, toolchain.cxx_flag, []]) # Migrate compiler_flag/cxx_flag from compilation_mode_flags for cmf in toolchain.compilation_mode_flags: mode = crosstool_config_pb2.CompilationMode.Name(cmf.mode).lower() # coverage mode has been a noop since a while if mode == "coverage": continue if cmf.cxx_flag: result.append([mode, ALL_CXX_COMPILE_ACTIONS, cmf.cxx_flag, []]) return result def _extract_legacy_link_flag_sets_for(toolchain): """Get flag sets for default_link_flags feature.""" result = [] # Migrate linker_flag if toolchain.linker_flag: result.append([None, link_actions(toolchain), toolchain.linker_flag, []]) # Migrate linker_flags from compilation_mode_flags for cmf in toolchain.compilation_mode_flags: mode = crosstool_config_pb2.CompilationMode.Name(cmf.mode).lower() # coverage mode has beed a noop since a while if mode == "coverage": continue if cmf.linker_flag and not _get_feature(toolchain, mode): feature = toolchain.feature.add() feature.name = mode if cmf.linker_flag: result.append([mode, link_actions(toolchain), cmf.linker_flag, []]) # Migrate linker_flags from linking_mode_flags for lmf in toolchain.linking_mode_flags: mode = crosstool_config_pb2.LinkingMode.Name(lmf.mode) feature_name = LINKING_MODE_TO_FEATURE_NAME.get(mode) # if the feature is already there, we don't migrate, lmf is not used if _get_feature(toolchain, feature_name): continue if lmf.linker_flag: feature = toolchain.feature.add() feature.name = feature_name if mode == "DYNAMIC": result.append( [None, NODEPS_DYNAMIC_LIBRARY_LINK_ACTIONS, lmf.linker_flag, []]) result.append([ None, TRANSITIVE_DYNAMIC_LIBRARY_LINK_ACTIONS, lmf.linker_flag, [], "static_link_cpp_runtimes", ]) result.append([ feature_name, executable_link_actions(toolchain), lmf.linker_flag, [] ]) elif mode == "MOSTLY_STATIC": result.append( [feature_name, CC_LINK_EXECUTABLE, lmf.linker_flag, []]) else: result.append( [feature_name, link_actions(toolchain), lmf.linker_flag, []]) if toolchain.dynamic_library_linker_flag: result.append([ None, DYNAMIC_LIBRARY_LINK_ACTIONS, toolchain.dynamic_library_linker_flag, [] ]) if toolchain.test_only_linker_flag: result.append([ None, link_actions(toolchain), toolchain.test_only_linker_flag, ["is_cc_test"] ]) return result def _prepend_feature(toolchain): """Create a new feature and make it be the first in the toolchain.""" features = toolchain.feature toolchain.ClearField("feature") new_feature = toolchain.feature.add() toolchain.feature.extend(features) return new_feature def _get_feature(toolchain, name): """Returns feature with a given name or None.""" for feature in toolchain.feature: if feature.name == name: return feature return None def _migrate_expand_if_all_available(message): """Move expand_if_all_available field to flag_groups.""" for flag_set in message.flag_set: if flag_set.expand_if_all_available: for flag_group in flag_set.flag_group: new_vars = ( flag_group.expand_if_all_available[:] + flag_set.expand_if_all_available[:]) flag_group.expand_if_all_available[:] = new_vars flag_set.ClearField("expand_if_all_available") def _migrate_repeated_expands(message): """Replace repeated legacy fields with nesting.""" todo_queue = [] for flag_set in message.flag_set: todo_queue.extend(flag_set.flag_group) while todo_queue: flag_group = todo_queue.pop() todo_queue.extend(flag_group.flag_group) if len(flag_group.expand_if_all_available) <= 1 and len( flag_group.expand_if_none_available) <= 1: continue current_children = flag_group.flag_group current_flags = flag_group.flag flag_group.ClearField("flag_group") flag_group.ClearField("flag") new_flag_group = flag_group.flag_group.add() new_flag_group.flag_group.extend(current_children) new_flag_group.flag.extend(current_flags) if len(flag_group.expand_if_all_available) > 1: expands_to_move = flag_group.expand_if_all_available[1:] flag_group.expand_if_all_available[:] = [ flag_group.expand_if_all_available[0] ] new_flag_group.expand_if_all_available.extend(expands_to_move) if len(flag_group.expand_if_none_available) > 1: expands_to_move = flag_group.expand_if_none_available[1:] flag_group.expand_if_none_available[:] = [ flag_group.expand_if_none_available[0] ] new_flag_group.expand_if_none_available.extend(expands_to_move) todo_queue.append(new_flag_group) todo_queue.append(flag_group) def _contains_dynamic_flags(toolchain): for lmf in toolchain.linking_mode_flags: mode = crosstool_config_pb2.LinkingMode.Name(lmf.mode) if mode == "DYNAMIC": return True return False def _rename_feature_in_toolchain(toolchain, from_name, to_name): for f in toolchain.feature: _rename_feature_in(f, from_name, to_name) for a in toolchain.action_config: _rename_feature_in(a, from_name, to_name) def _rename_feature_in(msg, from_name, to_name): if from_name in msg.implies: msg.implies.remove(from_name) for requires in msg.requires: if from_name in requires.feature: requires.feature.remove(from_name) requires.feature.extend([to_name]) for flag_set in msg.flag_set: for with_feature in flag_set.with_feature: if from_name in with_feature.feature: with_feature.feature.remove(from_name) with_feature.feature.extend([to_name]) if from_name in with_feature.not_feature: with_feature.not_feature.remove(from_name) with_feature.not_feature.extend([to_name]) for env_set in msg.env_set: for with_feature in env_set.with_feature: if from_name in with_feature.feature: with_feature.feature.remove(from_name) with_feature.feature.extend([to_name]) if from_name in with_feature.not_feature: with_feature.not_feature.remove(from_name) with_feature.not_feature.extend([to_name]) ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������rules_cc-0.0.11/tools/migration/legacy_fields_migration_lib_test.py���������������������������������0000664�0000000�0000000�00000144042�14700725615�0025637�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������import unittest from google.protobuf import text_format from third_party.com.github.bazelbuild.bazel.src.main.protobuf import crosstool_config_pb2 from tools.migration.legacy_fields_migration_lib import ALL_CC_COMPILE_ACTIONS from tools.migration.legacy_fields_migration_lib import ALL_OBJC_COMPILE_ACTIONS from tools.migration.legacy_fields_migration_lib import ALL_CXX_COMPILE_ACTIONS from tools.migration.legacy_fields_migration_lib import ALL_CC_LINK_ACTIONS from tools.migration.legacy_fields_migration_lib import ALL_OBJC_LINK_ACTIONS from tools.migration.legacy_fields_migration_lib import DYNAMIC_LIBRARY_LINK_ACTIONS from tools.migration.legacy_fields_migration_lib import NODEPS_DYNAMIC_LIBRARY_LINK_ACTIONS from tools.migration.legacy_fields_migration_lib import TRANSITIVE_LINK_ACTIONS from tools.migration.legacy_fields_migration_lib import TRANSITIVE_DYNAMIC_LIBRARY_LINK_ACTIONS from tools.migration.legacy_fields_migration_lib import CC_LINK_EXECUTABLE from tools.migration.legacy_fields_migration_lib import migrate_legacy_fields def assert_has_feature(self, toolchain, name): self.assertTrue(any(feature.name == name for feature in toolchain.feature)) def make_crosstool(string): crosstool = crosstool_config_pb2.CrosstoolRelease() text_format.Merge("major_version: '123' minor_version: '456'", crosstool) toolchain = crosstool.toolchain.add() text_format.Merge(string, toolchain) return crosstool def migrate_to_string(crosstool): migrate_legacy_fields(crosstool) return to_string(crosstool) def to_string(crosstool): return text_format.MessageToString(crosstool) class LegacyFieldsMigrationLibTest(unittest.TestCase): def test_deletes_fields(self): crosstool = make_crosstool(""" debian_extra_requires: 'debian-1' gcc_plugin_compiler_flag: 'gcc_plugin_compiler_flag-1' ar_flag: 'ar_flag-1' ar_thin_archives_flag: 'ar_thin_archives_flag-1' gcc_plugin_header_directory: 'gcc_plugin_header_directory-1' mao_plugin_header_directory: 'mao_plugin_header_directory-1' default_python_top: 'default_python_top-1' default_python_version: 'default_python_version-1' python_preload_swigdeps: false supports_normalizing_ar: false supports_thin_archives: false supports_incremental_linker: false supports_dsym: false supports_gold_linker: false needsPic: false supports_start_end_lib: false supports_interface_shared_objects: false supports_fission: false supports_embedded_runtimes: false static_runtimes_filegroup: 'yolo' dynamic_runtimes_filegroup: 'yolo' """) output = migrate_to_string(crosstool) self.assertNotIn("debian_extra_requires", output) self.assertNotIn("gcc_plugin_compiler_flag", output) self.assertNotIn("ar_flag", output) self.assertNotIn("ar_thin_archives_flag", output) self.assertNotIn("gcc_plugin_header_directory", output) self.assertNotIn("mao_plugin_header_directory", output) self.assertNotIn("supports_normalizing_ar", output) self.assertNotIn("supports_thin_archives", output) self.assertNotIn("supports_incremental_linker", output) self.assertNotIn("supports_dsym", output) self.assertNotIn("default_python_top", output) self.assertNotIn("default_python_version", output) self.assertNotIn("python_preload_swigdeps", output) self.assertNotIn("supports_gold_linker", output) self.assertNotIn("needsPic", output) self.assertNotIn("supports_start_end_lib", output) self.assertNotIn("supports_interface_shared_objects", output) self.assertNotIn("supports_fission", output) self.assertNotIn("supports_embedded_runtimes", output) self.assertNotIn("static_runtimes_filegroup", output) self.assertNotIn("dynamic_runtimes_filegroup", output) def test_deletes_default_toolchains(self): crosstool = make_crosstool("") crosstool.default_toolchain.add() self.assertEqual(len(crosstool.default_toolchain), 1) migrate_legacy_fields(crosstool) self.assertEqual(len(crosstool.default_toolchain), 0) def test_replace_legacy_compile_flags(self): crosstool = make_crosstool(""" feature { name: 'foo' } feature { name: 'legacy_compile_flags' } compiler_flag: 'clang-flag-1' """) migrate_legacy_fields(crosstool) output = crosstool.toolchain[0] self.assertEqual(len(output.compiler_flag), 0) self.assertEqual(output.feature[0].name, "foo") self.assertEqual(output.feature[1].name, "default_compile_flags") self.assertEqual(output.feature[1].flag_set[0].action, ALL_CC_COMPILE_ACTIONS) self.assertEqual(output.feature[1].flag_set[0].flag_group[0].flag, ["clang-flag-1"]) def test_replace_legacy_compile_flags_in_action_configs(self): crosstool = make_crosstool(""" feature { name: 'foo' implies: 'legacy_compile_flags' requires: { feature: 'legacy_compile_flags' } flag_set { with_feature { feature: 'legacy_compile_flags' } with_feature { not_feature: 'legacy_compile_flags' } } env_set { with_feature { feature: 'legacy_compile_flags' } with_feature { not_feature: 'legacy_compile_flags' } } } feature { name: 'legacy_compile_flags' } action_config { action_name: 'foo' config_name: 'foo' implies: 'legacy_compile_flags' requires: { feature: 'legacy_compile_flags' } flag_set { with_feature { feature: 'legacy_compile_flags' } with_feature { not_feature: 'legacy_compile_flags' } } env_set { with_feature { feature: 'legacy_compile_flags' } with_feature { not_feature: 'legacy_compile_flags' } } } compiler_flag: 'clang-flag-1' """) migrate_legacy_fields(crosstool) output = crosstool.toolchain[0] self.assertEqual(output.action_config[0].action_name, "foo") self.assertEqual(output.action_config[0].implies, []) self.assertEqual(output.action_config[0].requires[0].feature, ["default_compile_flags"]) self.assertEqual( output.action_config[0].flag_set[0].with_feature[0].feature, ["default_compile_flags"]) self.assertEqual( output.action_config[0].flag_set[0].with_feature[1].not_feature, ["default_compile_flags"]) self.assertEqual(output.action_config[0].env_set[0].with_feature[0].feature, ["default_compile_flags"]) self.assertEqual( output.action_config[0].env_set[0].with_feature[1].not_feature, ["default_compile_flags"]) self.assertEqual(output.feature[0].name, "foo") self.assertEqual(output.feature[0].implies, []) self.assertEqual(output.feature[0].requires[0].feature, ["default_compile_flags"]) self.assertEqual(output.feature[0].flag_set[0].with_feature[0].feature, ["default_compile_flags"]) self.assertEqual(output.feature[0].flag_set[0].with_feature[1].not_feature, ["default_compile_flags"]) self.assertEqual(output.feature[0].env_set[0].with_feature[0].feature, ["default_compile_flags"]) self.assertEqual(output.feature[0].env_set[0].with_feature[1].not_feature, ["default_compile_flags"]) def test_replace_legacy_link_flags(self): crosstool = make_crosstool(""" feature { name: 'foo' } feature { name: 'legacy_link_flags' } linker_flag: 'ld-flag-1' """) migrate_legacy_fields(crosstool) output = crosstool.toolchain[0] self.assertEqual(len(output.compiler_flag), 0) self.assertEqual(output.feature[0].name, "foo") self.assertEqual(output.feature[1].name, "default_link_flags") self.assertEqual(output.feature[1].flag_set[0].action, ALL_CC_LINK_ACTIONS) self.assertEqual(output.feature[1].flag_set[0].flag_group[0].flag, ["ld-flag-1"]) def test_replace_legacy_link_flags_in_action_configs(self): crosstool = make_crosstool(""" feature { name: 'foo' implies: 'legacy_link_flags' requires: { feature: 'legacy_link_flags' } flag_set { with_feature { feature: 'legacy_link_flags' } with_feature { not_feature: 'legacy_link_flags' } } env_set { with_feature { feature: 'legacy_link_flags' } with_feature { not_feature: 'legacy_link_flags' } } } feature { name: 'legacy_link_flags' } action_config { action_name: 'foo' config_name: 'foo' implies: 'legacy_link_flags' requires: { feature: 'legacy_link_flags' } flag_set { with_feature { feature: 'legacy_link_flags' } with_feature { not_feature: 'legacy_link_flags' } } env_set { with_feature { feature: 'legacy_link_flags' } with_feature { not_feature: 'legacy_link_flags' } } } linker_flag: 'clang-flag-1' """) migrate_legacy_fields(crosstool) output = crosstool.toolchain[0] self.assertEqual(output.action_config[0].action_name, "foo") self.assertEqual(output.action_config[0].implies, []) self.assertEqual(output.action_config[0].requires[0].feature, ["default_link_flags"]) self.assertEqual( output.action_config[0].flag_set[0].with_feature[0].feature, ["default_link_flags"]) self.assertEqual( output.action_config[0].flag_set[0].with_feature[1].not_feature, ["default_link_flags"]) self.assertEqual(output.action_config[0].env_set[0].with_feature[0].feature, ["default_link_flags"]) self.assertEqual( output.action_config[0].env_set[0].with_feature[1].not_feature, ["default_link_flags"]) self.assertEqual(output.feature[0].name, "foo") self.assertEqual(output.feature[0].implies, []) self.assertEqual(output.feature[0].requires[0].feature, ["default_link_flags"]) self.assertEqual(output.feature[0].flag_set[0].with_feature[0].feature, ["default_link_flags"]) self.assertEqual(output.feature[0].flag_set[0].with_feature[1].not_feature, ["default_link_flags"]) self.assertEqual(output.feature[0].env_set[0].with_feature[0].feature, ["default_link_flags"]) self.assertEqual(output.feature[0].env_set[0].with_feature[1].not_feature, ["default_link_flags"]) def test_migrate_compiler_flags(self): crosstool = make_crosstool(""" compiler_flag: 'clang-flag-1' """) migrate_legacy_fields(crosstool) output = crosstool.toolchain[0] self.assertEqual(len(output.compiler_flag), 0) self.assertEqual(output.feature[0].name, "default_compile_flags") self.assertEqual(output.feature[0].flag_set[0].action, ALL_CC_COMPILE_ACTIONS) self.assertEqual(output.feature[0].flag_set[0].flag_group[0].flag, ["clang-flag-1"]) def test_migrate_compiler_flags_for_objc(self): crosstool = make_crosstool(""" action_config { action_name: "objc-compile" } compiler_flag: 'clang-flag-1' """) migrate_legacy_fields(crosstool) output = crosstool.toolchain[0] self.assertEqual(len(output.compiler_flag), 0) self.assertEqual(output.feature[0].name, "default_compile_flags") self.assertEqual(output.feature[0].flag_set[0].action, ALL_CC_COMPILE_ACTIONS + ALL_OBJC_COMPILE_ACTIONS) self.assertEqual(output.feature[0].flag_set[0].flag_group[0].flag, ["clang-flag-1"]) def test_migrate_cxx_flags(self): crosstool = make_crosstool(""" cxx_flag: 'clang-flag-1' """) migrate_legacy_fields(crosstool) output = crosstool.toolchain[0] self.assertEqual(len(output.cxx_flag), 0) self.assertEqual(output.feature[0].name, "default_compile_flags") self.assertEqual(output.feature[0].flag_set[0].action, ALL_CXX_COMPILE_ACTIONS) self.assertEqual(output.feature[0].flag_set[0].flag_group[0].flag, ["clang-flag-1"]) def test_compiler_flag_come_before_cxx_flags(self): crosstool = make_crosstool(""" compiler_flag: 'clang-flag-1' cxx_flag: 'clang-flag-2' """) migrate_legacy_fields(crosstool) output = crosstool.toolchain[0] self.assertEqual(output.feature[0].name, "default_compile_flags") self.assertEqual(output.feature[0].flag_set[0].action, ALL_CC_COMPILE_ACTIONS) self.assertEqual(output.feature[0].flag_set[1].action, ALL_CXX_COMPILE_ACTIONS) self.assertEqual(output.feature[0].flag_set[0].flag_group[0].flag, ["clang-flag-1"]) self.assertEqual(output.feature[0].flag_set[1].flag_group[0].flag, ["clang-flag-2"]) def test_migrate_linker_flags(self): crosstool = make_crosstool(""" linker_flag: 'linker-flag-1' """) migrate_legacy_fields(crosstool) output = crosstool.toolchain[0] self.assertEqual(len(output.linker_flag), 0) self.assertEqual(output.feature[0].name, "default_link_flags") self.assertEqual(output.feature[0].flag_set[0].action, ALL_CC_LINK_ACTIONS) self.assertEqual(output.feature[0].flag_set[0].flag_group[0].flag, ["linker-flag-1"]) def test_migrate_dynamic_library_linker_flags(self): crosstool = make_crosstool(""" dynamic_library_linker_flag: 'linker-flag-1' """) migrate_legacy_fields(crosstool) output = crosstool.toolchain[0] self.assertEqual(len(output.dynamic_library_linker_flag), 0) self.assertEqual(output.feature[0].name, "default_link_flags") self.assertEqual(output.feature[0].flag_set[0].action, DYNAMIC_LIBRARY_LINK_ACTIONS) self.assertEqual(output.feature[0].flag_set[0].flag_group[0].flag, ["linker-flag-1"]) def test_compilation_mode_flags(self): crosstool = make_crosstool(""" compiler_flag: "compile-flag-1" cxx_flag: "cxx-flag-1" linker_flag: "linker-flag-1" compilation_mode_flags { mode: OPT compiler_flag: "opt-flag-1" cxx_flag: "opt-flag-2" linker_flag: "opt-flag-3" } """) migrate_legacy_fields(crosstool) output = crosstool.toolchain[0] self.assertEqual(len(output.compilation_mode_flags), 0) assert_has_feature(self, output, "opt") self.assertEqual(output.feature[0].name, "default_compile_flags") self.assertEqual(output.feature[1].name, "default_link_flags") # flag set for compiler_flag fields self.assertEqual(len(output.feature[0].flag_set[0].with_feature), 0) self.assertEqual(output.feature[0].flag_set[0].flag_group[0].flag, ["compile-flag-1"]) # flag set for compiler_flag from compilation_mode_flags self.assertEqual(len(output.feature[0].flag_set[1].with_feature), 1) self.assertEqual(output.feature[0].flag_set[1].with_feature[0].feature[0], "opt") self.assertEqual(output.feature[0].flag_set[1].flag_group[0].flag, ["opt-flag-1"]) # flag set for cxx_flag fields self.assertEqual(len(output.feature[0].flag_set[2].with_feature), 0) self.assertEqual(output.feature[0].flag_set[2].flag_group[0].flag, ["cxx-flag-1"]) # flag set for cxx_flag from compilation_mode_flags self.assertEqual(len(output.feature[0].flag_set[3].with_feature), 1) self.assertEqual(output.feature[0].flag_set[3].with_feature[0].feature[0], "opt") self.assertEqual(output.feature[0].flag_set[3].flag_group[0].flag, ["opt-flag-2"]) # default_link_flags, flag set for linker_flag self.assertEqual(len(output.feature[1].flag_set[0].with_feature), 0) self.assertEqual(output.feature[1].flag_set[0].flag_group[0].flag, ["linker-flag-1"]) # default_link_flags, flag set for linker_flag from # compilation_mode_flags self.assertEqual(len(output.feature[1].flag_set[1].with_feature), 1) self.assertEqual(output.feature[1].flag_set[1].with_feature[0].feature[0], "opt") self.assertEqual(output.feature[1].flag_set[1].flag_group[0].flag, ["opt-flag-3"]) def test_linking_mode_flags(self): crosstool = make_crosstool(""" linker_flag: "linker-flag-1" compilation_mode_flags { mode: DBG linker_flag: "dbg-flag-1" } linking_mode_flags { mode: MOSTLY_STATIC linker_flag: "mostly-static-flag-1" } """) migrate_legacy_fields(crosstool) output = crosstool.toolchain[0] self.assertEqual(len(output.compilation_mode_flags), 0) self.assertEqual(len(output.linking_mode_flags), 0) # flag set for linker_flag self.assertEqual(len(output.feature[0].flag_set[0].with_feature), 0) self.assertEqual(output.feature[0].flag_set[0].flag_group[0].flag, ["linker-flag-1"]) # flag set for compilation_mode_flags self.assertEqual(len(output.feature[0].flag_set[1].with_feature), 1) self.assertEqual(output.feature[0].flag_set[1].with_feature[0].feature[0], "dbg") self.assertEqual(output.feature[0].flag_set[1].flag_group[0].flag, ["dbg-flag-1"]) # flag set for linking_mode_flags self.assertEqual(len(output.feature[0].flag_set[2].with_feature), 1) self.assertEqual(output.feature[0].flag_set[2].action, CC_LINK_EXECUTABLE) self.assertEqual(output.feature[0].flag_set[2].with_feature[0].feature[0], "static_linking_mode") self.assertEqual(output.feature[0].flag_set[2].flag_group[0].flag, ["mostly-static-flag-1"]) def test_coverage_compilation_mode_ignored(self): crosstool = make_crosstool(""" compilation_mode_flags { mode: COVERAGE compiler_flag: "coverage-flag-1" cxx_flag: "coverage-flag-2" linker_flag: "coverage-flag-3" } """) output = migrate_to_string(crosstool) self.assertNotIn("compilation_mode_flags", output) self.assertNotIn("coverage-flag-1", output) self.assertNotIn("coverage-flag-2", output) self.assertNotIn("coverage-flag-3", output) self.assertNotIn("COVERAGE", output) def test_supports_dynamic_linker_when_dynamic_library_linker_flag_is_used( self): crosstool = make_crosstool(""" dynamic_library_linker_flag: "foo" """) migrate_legacy_fields(crosstool) output = crosstool.toolchain[0] self.assertEqual(output.feature[0].name, "default_link_flags") self.assertEqual(output.feature[1].name, "supports_dynamic_linker") self.assertEqual(output.feature[1].enabled, True) def test_supports_dynamic_linker_is_added_when_DYNAMIC_present(self): crosstool = make_crosstool(""" linking_mode_flags { mode: DYNAMIC } """) migrate_legacy_fields(crosstool) output = crosstool.toolchain[0] self.assertEqual(output.feature[0].name, "supports_dynamic_linker") self.assertEqual(output.feature[0].enabled, True) def test_supports_dynamic_linker_is_not_added_when_present(self): crosstool = make_crosstool(""" feature { name: "supports_dynamic_linker" enabled: false } """) migrate_legacy_fields(crosstool) output = crosstool.toolchain[0] self.assertEqual(output.feature[0].name, "supports_dynamic_linker") self.assertEqual(output.feature[0].enabled, False) def test_all_linker_flag_ordering(self): crosstool = make_crosstool(""" linker_flag: 'linker-flag-1' compilation_mode_flags { mode: OPT linker_flag: 'cmf-flag-2' } linking_mode_flags { mode: MOSTLY_STATIC linker_flag: 'lmf-flag-3' } linking_mode_flags { mode: DYNAMIC linker_flag: 'lmf-dynamic-flag-4' } dynamic_library_linker_flag: 'dl-flag-5' test_only_linker_flag: 'to-flag-6' """) migrate_legacy_fields(crosstool) output = crosstool.toolchain[0] self.assertEqual(output.feature[0].name, "default_link_flags") self.assertEqual(output.feature[0].enabled, True) self.assertEqual(output.feature[0].flag_set[0].action[:], ALL_CC_LINK_ACTIONS) self.assertEqual(output.feature[0].flag_set[0].flag_group[0].flag[:], ["linker-flag-1"]) self.assertEqual(output.feature[0].flag_set[1].action[:], ALL_CC_LINK_ACTIONS) self.assertEqual(output.feature[0].flag_set[1].with_feature[0].feature[0], "opt") self.assertEqual(output.feature[0].flag_set[1].flag_group[0].flag, ["cmf-flag-2"]) self.assertEqual(output.feature[0].flag_set[2].action, CC_LINK_EXECUTABLE) self.assertEqual(output.feature[0].flag_set[2].with_feature[0].feature[0], "static_linking_mode") self.assertEqual(output.feature[0].flag_set[2].flag_group[0].flag, ["lmf-flag-3"]) self.assertEqual(len(output.feature[0].flag_set[3].with_feature), 0) self.assertEqual(output.feature[0].flag_set[3].flag_group[0].flag, ["lmf-dynamic-flag-4"]) self.assertEqual(output.feature[0].flag_set[3].action, NODEPS_DYNAMIC_LIBRARY_LINK_ACTIONS) self.assertEqual( output.feature[0].flag_set[4].with_feature[0].not_feature[0], "static_link_cpp_runtimes") self.assertEqual(output.feature[0].flag_set[4].flag_group[0].flag, ["lmf-dynamic-flag-4"]) self.assertEqual(output.feature[0].flag_set[4].action, TRANSITIVE_DYNAMIC_LIBRARY_LINK_ACTIONS) self.assertEqual(output.feature[0].flag_set[5].with_feature[0].feature[0], "dynamic_linking_mode") self.assertEqual(output.feature[0].flag_set[5].flag_group[0].flag, ["lmf-dynamic-flag-4"]) self.assertEqual(output.feature[0].flag_set[5].action, CC_LINK_EXECUTABLE) self.assertEqual(output.feature[0].flag_set[6].flag_group[0].flag, ["dl-flag-5"]) self.assertEqual(output.feature[0].flag_set[6].action, DYNAMIC_LIBRARY_LINK_ACTIONS) self.assertEqual(output.feature[0].flag_set[7].flag_group[0].flag, ["to-flag-6"]) self.assertEqual(output.feature[0].flag_set[7].action, ALL_CC_LINK_ACTIONS) self.assertEqual( output.feature[0].flag_set[7].flag_group[0].expand_if_all_available, ["is_cc_test"]) def test_all_linker_flag_objc_actions(self): crosstool = make_crosstool(""" action_config { action_name: "objc-compile" } linker_flag: 'linker-flag-1' compilation_mode_flags { mode: OPT linker_flag: 'cmf-flag-2' } linking_mode_flags { mode: MOSTLY_STATIC linker_flag: 'lmf-flag-3' } dynamic_library_linker_flag: 'dl-flag-5' test_only_linker_flag: 'to-flag-6' """) migrate_legacy_fields(crosstool) output = crosstool.toolchain[0] self.assertEqual(output.feature[0].name, "default_link_flags") self.assertEqual(output.feature[0].flag_set[0].action[:], ALL_CC_LINK_ACTIONS + ALL_OBJC_LINK_ACTIONS) self.assertEqual(output.feature[0].flag_set[1].action[:], ALL_CC_LINK_ACTIONS + ALL_OBJC_LINK_ACTIONS) self.assertEqual(output.feature[0].flag_set[2].action[:], CC_LINK_EXECUTABLE) self.assertEqual(output.feature[0].flag_set[3].action[:], DYNAMIC_LIBRARY_LINK_ACTIONS) self.assertEqual(output.feature[0].flag_set[4].action[:], ALL_CC_LINK_ACTIONS + ALL_OBJC_LINK_ACTIONS) def test_linking_mode_features_are_not_added_when_present(self): crosstool = make_crosstool(""" linking_mode_flags { mode: DYNAMIC linker_flag: 'dynamic-flag' } linking_mode_flags { mode: FULLY_STATIC linker_flag: 'fully-static-flag' } linking_mode_flags { mode: MOSTLY_STATIC linker_flag: 'mostly-static-flag' } linking_mode_flags { mode: MOSTLY_STATIC_LIBRARIES linker_flag: 'mostly-static-libraries-flag' } feature { name: "static_linking_mode" } feature { name: "dynamic_linking_mode" } feature { name: "static_linking_mode_nodeps_library" } feature { name: "fully_static_link" } """) output = migrate_to_string(crosstool) self.assertNotIn("linking_mode_flags", output) self.assertNotIn("DYNAMIC", output) self.assertNotIn("MOSTLY_STATIC", output) self.assertNotIn("MOSTLY_STATIC_LIBRARIES", output) self.assertNotIn("MOSTLY_STATIC_LIBRARIES", output) self.assertNotIn("dynamic-flag", output) self.assertNotIn("fully-static-flag", output) self.assertNotIn("mostly-static-flag", output) self.assertNotIn("mostly-static-libraries-flag", output) def test_unfiltered_require_user_compile_flags_and_sysroot(self): crosstool = make_crosstool(""" feature { name: 'preexisting_feature' } unfiltered_cxx_flag: 'unfiltered-flag-1' """) migrate_legacy_fields(crosstool) output = crosstool.toolchain[0] # all these features are added after features that are already present in # the crosstool self.assertEqual(output.feature[0].name, "preexisting_feature") self.assertEqual(output.feature[1].name, "user_compile_flags") self.assertEqual(output.feature[2].name, "sysroot") self.assertEqual(output.feature[3].name, "unfiltered_compile_flags") def test_user_compile_flags_not_migrated_when_present(self): crosstool = make_crosstool(""" unfiltered_cxx_flag: 'unfiltered-flag-1' feature { name: 'user_compile_flags' } feature { name: 'preexisting_feature' } """) migrate_legacy_fields(crosstool) output = crosstool.toolchain[0] self.assertEqual(output.feature[0].name, "user_compile_flags") self.assertEqual(output.feature[1].name, "preexisting_feature") self.assertEqual(output.feature[2].name, "sysroot") self.assertEqual(output.feature[3].name, "unfiltered_compile_flags") def test_sysroot_not_migrated_when_present(self): crosstool = make_crosstool(""" unfiltered_cxx_flag: 'unfiltered-flag-1' feature { name: 'sysroot' } feature { name: 'preexisting_feature' } """) migrate_legacy_fields(crosstool) output = crosstool.toolchain[0] self.assertEqual(output.feature[0].name, "sysroot") self.assertEqual(output.feature[1].name, "preexisting_feature") self.assertEqual(output.feature[2].name, "user_compile_flags") self.assertEqual(output.feature[3].name, "unfiltered_compile_flags") def test_user_compile_flags(self): crosstool = make_crosstool(""" unfiltered_cxx_flag: 'unfiltered-flag-1' """) migrate_legacy_fields(crosstool) output = crosstool.toolchain[0] self.assertEqual(output.feature[0].name, "user_compile_flags") self.assertEqual(output.feature[0].enabled, True) self.assertEqual(output.feature[0].flag_set[0].action, ALL_CC_COMPILE_ACTIONS) self.assertEqual( output.feature[0].flag_set[0].flag_group[0].expand_if_all_available, ["user_compile_flags"]) self.assertEqual(output.feature[0].flag_set[0].flag_group[0].iterate_over, "user_compile_flags") self.assertEqual(output.feature[0].flag_set[0].flag_group[0].flag, ["%{user_compile_flags}"]) def test_sysroot(self): sysroot_actions = ALL_CC_COMPILE_ACTIONS + ALL_CC_LINK_ACTIONS sysroot_actions.remove("assemble") self.assertTrue("assemble" not in sysroot_actions) crosstool = make_crosstool(""" unfiltered_cxx_flag: 'unfiltered-flag-1' """) migrate_legacy_fields(crosstool) output = crosstool.toolchain[0] self.assertEqual(output.feature[1].name, "sysroot") self.assertEqual(output.feature[1].enabled, True) self.assertEqual(output.feature[1].flag_set[0].action, sysroot_actions) self.assertEqual( output.feature[1].flag_set[0].flag_group[0].expand_if_all_available, ["sysroot"]) self.assertEqual(output.feature[1].flag_set[0].flag_group[0].flag, ["--sysroot=%{sysroot}"]) def test_unfiltered_compile_flags_is_not_added_when_already_present(self): crosstool = make_crosstool(""" unfiltered_cxx_flag: 'unfiltered-flag-1' feature { name: 'something_else' } feature { name: 'unfiltered_compile_flags' } feature { name: 'something_else_2' } """) migrate_legacy_fields(crosstool) output = crosstool.toolchain[0] self.assertEqual(output.feature[0].name, "something_else") self.assertEqual(output.feature[1].name, "unfiltered_compile_flags") self.assertEqual(len(output.feature[1].flag_set), 0) self.assertEqual(output.feature[2].name, "something_else_2") def test_unfiltered_compile_flags_is_not_edited_if_old_variant_present(self): crosstool = make_crosstool(""" unfiltered_cxx_flag: 'unfiltered-flag-1' feature { name: 'unfiltered_compile_flags' flag_set { action: 'c-compile' flag_group { flag: 'foo-flag-1' } } } """) migrate_legacy_fields(crosstool) output = crosstool.toolchain[0] self.assertEqual(output.feature[0].name, "unfiltered_compile_flags") self.assertEqual(len(output.feature[0].flag_set), 1) self.assertEqual(output.feature[0].flag_set[0].action, ["c-compile"]) self.assertEqual(output.feature[0].flag_set[0].flag_group[0].flag, ["foo-flag-1"]) def test_use_of_unfiltered_compile_flags_var_is_removed_and_replaced(self): crosstool = make_crosstool(""" unfiltered_cxx_flag: 'unfiltered-flag-1' feature { name: 'unfiltered_compile_flags' flag_set { action: 'c-compile' flag_group { flag: 'foo-flag-1' } } flag_set { action: 'c++-compile' flag_group { flag: 'bar-flag-1' } flag_group { expand_if_all_available: 'unfiltered_compile_flags' iterate_over: 'unfiltered_compile_flags' flag: '%{unfiltered_compile_flags}' } flag_group { flag: 'bar-flag-2' } } flag_set { action: 'c-compile' flag_group { flag: 'foo-flag-2' } } } """) migrate_legacy_fields(crosstool) output = crosstool.toolchain[0] self.assertEqual(output.feature[0].name, "unfiltered_compile_flags") self.assertEqual(output.feature[0].flag_set[0].action, ["c-compile"]) self.assertEqual(output.feature[0].flag_set[0].flag_group[0].flag, ["foo-flag-1"]) self.assertEqual(output.feature[0].flag_set[1].action, ["c++-compile"]) self.assertEqual(output.feature[0].flag_set[1].flag_group[0].flag, ["bar-flag-1"]) self.assertEqual(output.feature[0].flag_set[1].flag_group[1].flag, ["unfiltered-flag-1"]) self.assertEqual(output.feature[0].flag_set[1].flag_group[2].flag, ["bar-flag-2"]) self.assertEqual(output.feature[0].flag_set[2].action, ["c-compile"]) self.assertEqual(output.feature[0].flag_set[2].flag_group[0].flag, ["foo-flag-2"]) def test_unfiltered_compile_flags_is_added_at_the_end(self): crosstool = make_crosstool(""" feature { name: 'something_else' } unfiltered_cxx_flag: 'unfiltered-flag-1' """) migrate_legacy_fields(crosstool) output = crosstool.toolchain[0] self.assertEqual(output.feature[0].name, "something_else") self.assertEqual(output.feature[1].name, "user_compile_flags") self.assertEqual(output.feature[2].name, "sysroot") self.assertEqual(output.feature[3].name, "unfiltered_compile_flags") self.assertEqual(output.feature[3].flag_set[0].action, ALL_CC_COMPILE_ACTIONS) self.assertEqual(output.feature[3].flag_set[0].flag_group[0].flag, ["unfiltered-flag-1"]) def test_unfiltered_compile_flags_are_not_added_for_objc(self): crosstool = make_crosstool(""" action_config { action_name: "obc-compile" } feature { name: 'something_else' } unfiltered_cxx_flag: 'unfiltered-flag-1' """) migrate_legacy_fields(crosstool) output = crosstool.toolchain[0] self.assertEqual(output.feature[3].name, "unfiltered_compile_flags") self.assertEqual(output.feature[3].flag_set[0].action, ALL_CC_COMPILE_ACTIONS) self.assertEqual(output.feature[3].flag_set[0].flag_group[0].flag, ["unfiltered-flag-1"]) def test_default_link_flags_is_added_first(self): crosstool = make_crosstool(""" linker_flag: 'linker-flag-1' feature { name: 'something_else' } """) migrate_legacy_fields(crosstool) output = crosstool.toolchain[0] self.assertEqual(output.feature[0].name, "default_link_flags") self.assertEqual(output.feature[0].enabled, True) self.assertEqual(output.feature[0].flag_set[0].flag_group[0].flag, ["linker-flag-1"]) def test_default_link_flags_is_not_added_when_already_present(self): crosstool = make_crosstool(""" linker_flag: 'linker-flag-1' feature { name: 'something_else' } feature { name: 'default_link_flags' } """) migrate_legacy_fields(crosstool) output = crosstool.toolchain[0] self.assertEqual(output.feature[0].name, "something_else") self.assertEqual(output.feature[1].name, "default_link_flags") def test_default_compile_flags_is_not_added_when_no_reason_to(self): crosstool = make_crosstool(""" feature { name: 'something_else' } """) migrate_legacy_fields(crosstool) output = crosstool.toolchain[0] self.assertEqual(output.feature[0].name, "something_else") self.assertEqual(len(output.feature), 1) def test_default_compile_flags_is_first(self): crosstool = make_crosstool(""" compiler_flag: 'compiler-flag-1' feature { name: 'something_else' } """) migrate_legacy_fields(crosstool) output = crosstool.toolchain[0] self.assertEqual(output.feature[0].name, "default_compile_flags") self.assertEqual(output.feature[0].enabled, True) self.assertEqual(output.feature[0].flag_set[0].flag_group[0].flag, ["compiler-flag-1"]) def test_default_compile_flags_not_added_when_present(self): crosstool = make_crosstool(""" compiler_flag: 'compiler-flag-1' feature { name: 'something_else' } feature { name: 'default_compile_flags' } """) migrate_legacy_fields(crosstool) output = crosstool.toolchain[0] self.assertEqual(output.feature[0].name, "something_else") self.assertEqual(output.feature[1].name, "default_compile_flags") self.assertEqual(len(output.feature[1].flag_set), 0) def test_supports_start_end_lib_migrated(self): crosstool = make_crosstool("supports_start_end_lib: true") migrate_legacy_fields(crosstool) output = crosstool.toolchain[0] self.assertEqual(output.feature[0].name, "supports_start_end_lib") self.assertEqual(output.feature[0].enabled, True) def test_supports_start_end_lib_not_migrated_on_false(self): crosstool = make_crosstool("supports_start_end_lib: false") migrate_legacy_fields(crosstool) output = crosstool.toolchain[0] self.assertEqual(len(output.feature), 0) def test_supports_start_end_lib_not_migrated_when_already_present(self): crosstool = make_crosstool(""" supports_start_end_lib: true feature { name: "supports_start_end_lib" enabled: false } """) migrate_legacy_fields(crosstool) output = crosstool.toolchain[0] self.assertEqual(output.feature[0].name, "supports_start_end_lib") self.assertEqual(output.feature[0].enabled, False) def test_supports_interface_shared_libraries_migrated(self): crosstool = make_crosstool("supports_interface_shared_objects: true") migrate_legacy_fields(crosstool) output = crosstool.toolchain[0] self.assertEqual(output.feature[0].name, "supports_interface_shared_libraries") self.assertEqual(output.feature[0].enabled, True) def test_supports_interface_shared_libraries_not_migrated_on_false(self): crosstool = make_crosstool("supports_interface_shared_objects: false") migrate_legacy_fields(crosstool) output = crosstool.toolchain[0] self.assertEqual(len(output.feature), 0) def test_supports_interface_shared_libraries_not_migrated_when_present(self): crosstool = make_crosstool(""" supports_interface_shared_objects: true feature { name: "supports_interface_shared_libraries" enabled: false } """) migrate_legacy_fields(crosstool) output = crosstool.toolchain[0] self.assertEqual(output.feature[0].name, "supports_interface_shared_libraries") self.assertEqual(output.feature[0].enabled, False) def test_supports_embedded_runtimes_migrated(self): crosstool = make_crosstool("supports_embedded_runtimes: true") migrate_legacy_fields(crosstool) output = crosstool.toolchain[0] self.assertEqual(output.feature[0].name, "static_link_cpp_runtimes") self.assertEqual(output.feature[0].enabled, True) def test_supports_embedded_runtimes_not_migrated_on_false(self): crosstool = make_crosstool("supports_embedded_runtimes: false") migrate_legacy_fields(crosstool) output = crosstool.toolchain[0] self.assertEqual(len(output.feature), 0) def test_supports_embedded_runtimes_not_migrated_when_already_present(self): crosstool = make_crosstool(""" supports_embedded_runtimes: true feature { name: "static_link_cpp_runtimes" enabled: false } """) migrate_legacy_fields(crosstool) output = crosstool.toolchain[0] self.assertEqual(output.feature[0].name, "static_link_cpp_runtimes") self.assertEqual(output.feature[0].enabled, False) def test_needs_pic_migrated(self): crosstool = make_crosstool("needsPic: true") migrate_legacy_fields(crosstool) output = crosstool.toolchain[0] self.assertEqual(output.feature[0].name, "supports_pic") self.assertEqual(output.feature[0].enabled, True) def test_needs_pic_not_migrated_on_false(self): crosstool = make_crosstool("needsPic: false") migrate_legacy_fields(crosstool) output = crosstool.toolchain[0] self.assertEqual(len(output.feature), 0) def test_needs_pic_not_migrated_when_already_present(self): crosstool = make_crosstool(""" needsPic: true feature { name: "supports_pic" enabled: false } """) migrate_legacy_fields(crosstool) output = crosstool.toolchain[0] self.assertEqual(output.feature[0].name, "supports_pic") self.assertEqual(output.feature[0].enabled, False) def test_supports_fission_migrated(self): crosstool = make_crosstool("supports_fission: true") migrate_legacy_fields(crosstool) output = crosstool.toolchain[0] self.assertEqual(output.feature[0].name, "per_object_debug_info") self.assertEqual(output.feature[0].enabled, True) self.assertEqual( output.feature[0].flag_set[0].flag_group[0].expand_if_all_available, ["is_using_fission"]) def test_supports_fission_not_migrated_on_false(self): crosstool = make_crosstool("supports_fission: false") migrate_legacy_fields(crosstool) output = crosstool.toolchain[0] self.assertEqual(len(output.feature), 0) def test_supports_fission_not_migrated_when_already_present(self): crosstool = make_crosstool(""" supports_fission: true feature { name: "per_object_debug_info" enabled: false } """) migrate_legacy_fields(crosstool) output = crosstool.toolchain[0] self.assertEqual(output.feature[0].name, "per_object_debug_info") self.assertEqual(output.feature[0].enabled, False) def test_migrating_objcopy_embed_flag(self): crosstool = make_crosstool(""" tool_path { name: "objcopy" path: "foo/objcopy" } objcopy_embed_flag: "a" objcopy_embed_flag: "b" """) migrate_legacy_fields(crosstool) output = crosstool.toolchain[0] self.assertEqual(output.feature[0].name, "objcopy_embed_flags") self.assertEqual(output.feature[0].enabled, True) self.assertEqual(output.feature[0].flag_set[0].action[:], ["objcopy_embed_data"]) self.assertEqual(output.feature[0].flag_set[0].flag_group[0].flag[:], ["a", "b"]) self.assertEqual(len(output.objcopy_embed_flag), 0) self.assertEqual(output.action_config[0].action_name, "objcopy_embed_data") self.assertEqual(output.action_config[0].tool[0].tool_path, "foo/objcopy") def test_not_migrating_objcopy_embed_flag_when_feature_present(self): crosstool = make_crosstool(""" objcopy_embed_flag: "a" objcopy_embed_flag: "b" feature { name: "objcopy_embed_flags" } """) migrate_legacy_fields(crosstool) output = crosstool.toolchain[0] self.assertEqual(output.feature[0].name, "objcopy_embed_flags") self.assertEqual(output.feature[0].enabled, False) def test_migrating_ld_embed_flag(self): crosstool = make_crosstool(""" tool_path { name: "ld" path: "foo/ld" } ld_embed_flag: "a" ld_embed_flag: "b" """) migrate_legacy_fields(crosstool) output = crosstool.toolchain[0] self.assertEqual(output.feature[0].name, "ld_embed_flags") self.assertEqual(output.feature[0].enabled, True) self.assertEqual(output.feature[0].flag_set[0].action[:], ["ld_embed_data"]) self.assertEqual(output.feature[0].flag_set[0].flag_group[0].flag[:], ["a", "b"]) self.assertEqual(len(output.ld_embed_flag), 0) self.assertEqual(output.action_config[0].action_name, "ld_embed_data") self.assertEqual(output.action_config[0].tool[0].tool_path, "foo/ld") def test_not_migrating_objcopy_embed_flag_when_feature_present(self): crosstool = make_crosstool(""" objcopy_embed_flag: "a" objcopy_embed_flag: "b" feature { name: "objcopy_embed_flags" } """) migrate_legacy_fields(crosstool) output = crosstool.toolchain[0] self.assertEqual(output.feature[0].name, "objcopy_embed_flags") self.assertEqual(output.feature[0].enabled, False) def test_migrate_expand_if_all_available_from_flag_sets(self): crosstool = make_crosstool(""" action_config { action_name: 'something' config_name: 'something' flag_set { expand_if_all_available: 'foo' flag_group { flag: '%{foo}' } flag_group { flag: 'bar' } } } feature { name: 'something_else' flag_set { action: 'c-compile' expand_if_all_available: 'foo' flag_group { flag: '%{foo}' } flag_group { flag: 'bar' } } } """) migrate_legacy_fields(crosstool) output = crosstool.toolchain[0] self.assertEqual(output.action_config[0].action_name, "something") self.assertEqual(len(output.action_config[0].flag_set), 1) self.assertEqual( len(output.action_config[0].flag_set[0].expand_if_all_available), 0) self.assertEqual(len(output.action_config[0].flag_set[0].flag_group), 2) self.assertEqual( output.action_config[0].flag_set[0].flag_group[0] .expand_if_all_available, ["foo"]) self.assertEqual( output.action_config[0].flag_set[0].flag_group[1] .expand_if_all_available, ["foo"]) self.assertEqual(output.feature[0].name, "something_else") self.assertEqual(len(output.feature[0].flag_set), 1) self.assertEqual( len(output.feature[0].flag_set[0].expand_if_all_available), 0) self.assertEqual(len(output.feature[0].flag_set[0].flag_group), 2) self.assertEqual( output.feature[0].flag_set[0].flag_group[0].expand_if_all_available, ["foo"]) self.assertEqual( output.feature[0].flag_set[0].flag_group[1].expand_if_all_available, ["foo"]) def test_enable_previously_default_features(self): default_features = [ "dependency_file", "random_seed", "module_maps", "module_map_home_cwd", "header_module_compile", "include_paths", "pic", "preprocessor_define" ] crosstool = make_crosstool(""" feature { name: "dependency_file" } feature { name: "random_seed" } feature { name: "module_maps" } feature { name: "module_map_home_cwd" } feature { name: "header_module_compile" } feature { name: "include_paths" } feature { name: "pic" } feature { name: "preprocessor_define" } """) migrate_legacy_fields(crosstool) output = crosstool.toolchain[0] for i in range(0, 8): self.assertEqual(output.feature[i].name, default_features[i]) self.assertTrue(output.feature[i].enabled) def test_migrate_repeated_expand_if_all_available_from_flag_groups(self): crosstool = make_crosstool(""" action_config { action_name: 'something' config_name: 'something' flag_set { flag_group { expand_if_all_available: 'foo' expand_if_all_available: 'bar' flag: '%{foo}' } flag_group { expand_if_none_available: 'foo' expand_if_none_available: 'bar' flag: 'bar' } } } feature { name: 'something_else' flag_set { action: 'c-compile' flag_group { expand_if_all_available: 'foo' expand_if_all_available: 'bar' flag: '%{foo}' } flag_group { expand_if_none_available: 'foo' expand_if_none_available: 'bar' flag: 'bar' } } } """) migrate_legacy_fields(crosstool) output = crosstool.toolchain[0] self.assertEqual(output.action_config[0].action_name, "something") self.assertEqual(len(output.action_config[0].flag_set), 1) self.assertEqual( len(output.action_config[0].flag_set[0].expand_if_all_available), 0) self.assertEqual(len(output.action_config[0].flag_set[0].flag_group), 2) self.assertEqual( output.action_config[0].flag_set[0].flag_group[0] .expand_if_all_available, ["foo"]) self.assertEqual( output.action_config[0].flag_set[0].flag_group[0].flag_group[0] .expand_if_all_available, ["bar"]) self.assertEqual( output.action_config[0].flag_set[0].flag_group[1] .expand_if_none_available, ["foo"]) self.assertEqual( output.action_config[0].flag_set[0].flag_group[1].flag_group[0] .expand_if_none_available, ["bar"]) self.assertEqual(output.feature[0].name, "something_else") self.assertEqual(len(output.feature[0].flag_set), 1) self.assertEqual( len(output.feature[0].flag_set[0].expand_if_all_available), 0) self.assertEqual(len(output.feature[0].flag_set[0].flag_group), 2) self.assertEqual( output.feature[0].flag_set[0].flag_group[0].expand_if_all_available, ["foo"]) self.assertEqual( output.feature[0].flag_set[0].flag_group[0].flag_group[0] .expand_if_all_available, ["bar"]) self.assertEqual( output.feature[0].flag_set[0].flag_group[1].expand_if_none_available, ["foo"]) self.assertEqual( output.feature[0].flag_set[0].flag_group[1].flag_group[0] .expand_if_none_available, ["bar"]) def test_migrate_repeated_expands_from_nested_flag_groups(self): crosstool = make_crosstool(""" feature { name: 'something' flag_set { action: 'c-compile' flag_group { flag_group { expand_if_all_available: 'foo' expand_if_all_available: 'bar' flag: '%{foo}' } } flag_group { flag_group { expand_if_all_available: 'foo' expand_if_all_available: 'bar' expand_if_none_available: 'foo' expand_if_none_available: 'bar' flag: '%{foo}' } } } } """) migrate_legacy_fields(crosstool) output = crosstool.toolchain[0] self.assertEqual(output.feature[0].name, "something") self.assertEqual(len(output.feature[0].flag_set[0].flag_group), 2) self.assertEqual( len(output.feature[0].flag_set[0].flag_group[0].expand_if_all_available ), 0) self.assertEqual( output.feature[0].flag_set[0].flag_group[0].flag_group[0] .expand_if_all_available, ["foo"]) self.assertEqual( output.feature[0].flag_set[0].flag_group[0].flag_group[0].flag_group[0] .expand_if_all_available, ["bar"]) self.assertEqual( output.feature[0].flag_set[0].flag_group[0].flag_group[0].flag_group[0] .flag, ["%{foo}"]) self.assertEqual( output.feature[0].flag_set[0].flag_group[1].flag_group[0] .expand_if_all_available, ["foo"]) self.assertEqual( output.feature[0].flag_set[0].flag_group[1].flag_group[0] .expand_if_none_available, ["foo"]) self.assertEqual( output.feature[0].flag_set[0].flag_group[1].flag_group[0].flag_group[0] .expand_if_none_available, ["bar"]) self.assertEqual( output.feature[0].flag_set[0].flag_group[1].flag_group[0].flag_group[0] .expand_if_all_available, ["bar"]) self.assertEqual( output.feature[0].flag_set[0].flag_group[1].flag_group[0].flag_group[0] .flag, ["%{foo}"]) if __name__ == "__main__": unittest.main() ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������rules_cc-0.0.11/tools/migration/legacy_fields_migrator.py�������������������������������������������0000664�0000000�0000000�00000004567�14700725615�0023614�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Script migrating legacy CROSSTOOL fields into features. This script migrates the CROSSTOOL to use only the features to describe C++ command lines. It is intended to be added as a last step of CROSSTOOL generation pipeline. Since it doesn't retain comments, we assume CROSSTOOL owners will want to migrate their pipeline manually. """ # Tracking issue: https://github.com/bazelbuild/bazel/issues/5187 # # Since C++ rules team is working on migrating CROSSTOOL from text proto into # Starlark, we advise CROSSTOOL owners to wait for the CROSSTOOL -> Starlark # migrator before they invest too much time into fixing their pipeline. Tracking # issue for the Starlark effort is # https://github.com/bazelbuild/bazel/issues/5380. from absl import app from absl import flags from google.protobuf import text_format from third_party.com.github.bazelbuild.bazel.src.main.protobuf import crosstool_config_pb2 from tools.migration.legacy_fields_migration_lib import migrate_legacy_fields import os flags.DEFINE_string("input", None, "Input CROSSTOOL file to be migrated") flags.DEFINE_string("output", None, "Output path where to write migrated CROSSTOOL.") flags.DEFINE_boolean("inline", None, "Overwrite --input file") def main(unused_argv): crosstool = crosstool_config_pb2.CrosstoolRelease() input_filename = flags.FLAGS.input output_filename = flags.FLAGS.output inline = flags.FLAGS.inline if not input_filename: raise app.UsageError("ERROR --input unspecified") if not output_filename and not inline: raise app.UsageError("ERROR --output unspecified and --inline not passed") if output_filename and inline: raise app.UsageError("ERROR both --output and --inline passed") with open(to_absolute_path(input_filename), "r") as f: input_text = f.read() text_format.Merge(input_text, crosstool) migrate_legacy_fields(crosstool) output_text = text_format.MessageToString(crosstool) resolved_output_filename = to_absolute_path( input_filename if inline else output_filename) with open(resolved_output_filename, "w") as f: f.write(output_text) def to_absolute_path(path): path = os.path.expanduser(path) if os.path.isabs(path): return path else: if "BUILD_WORKING_DIRECTORY" in os.environ: return os.path.join(os.environ["BUILD_WORKING_DIRECTORY"], path) else: return path if __name__ == "__main__": app.run(main) �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������