├── .bazelrc ├── .bazelversion ├── .gitignore ├── BUILD.bazel ├── CODEOWNERS ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE.txt ├── README.md ├── SECURITY.md ├── WORKSPACE ├── thirdparty ├── BUILD.bazel ├── clang │ ├── BUILD.bazel │ ├── clang_darwin.BUILD │ ├── clang_linux.BUILD │ └── clang_windows.BUILD ├── gtest │ └── gtest.BUILD ├── macos_cmdtools │ ├── BUILD.bazel │ ├── WORKSPACE │ └── extract.sh ├── macos_sdk │ ├── BUILD.bazel │ ├── WORKSPACE │ └── download_and_extract.sh ├── msvc │ └── BUILD.bazel ├── posix_system_library │ ├── BUILD.bazel │ └── posix_library_wrapper.bzl └── windows_sdk │ └── BUILD.bazel └── toolchain ├── BUILD.bazel ├── clang ├── clang_hyper_features.bzl ├── clang_posix_toolchain_config_base.bzl ├── clang_toolchain_actions.bzl ├── darwin │ ├── clang_darwin_toolchain_config.bzl │ ├── platform_constants.bzl │ └── wrapper-scripts │ │ └── cc-wrapper.sh ├── hermetic_default_defines.h ├── linux │ ├── clang_linux_toolchain_config.bzl │ ├── wrapper_llvm_dwp.sh │ └── wrapper_profdata.sh └── windows │ ├── BUILD.bazel │ ├── cc_toolchain_config.bzl │ ├── hyper.natvis │ ├── long_paths.manifest │ └── manifest_resource.rc ├── helper ├── BUILD.bazel ├── condition_helpers.bzl ├── context_helpers.bzl ├── file_helpers.bzl ├── foreign_build_rpath_fixer_helper.bzl ├── function_helpers.bzl ├── label_helpers.bzl ├── list_helpers.bzl ├── platform_helpers.bzl ├── runfiles_helpers.bzl └── tests │ ├── condition_helpers_tests.bzl │ ├── file_helpers_tests.bzl │ ├── function_helpers_tests.bzl │ ├── label_helpers_tests.bzl │ ├── list_helpers_tests.bzl │ └── runfiles_helpers_test.bzl ├── platforms ├── BUILD.bazel ├── package_variables.bzl ├── platform_mappings └── platform_with_config_setting.bzl ├── rules ├── BUILD.bazel ├── dsym.bzl ├── exported_symbols.bzl ├── generatesymbolfile.py ├── hyper_cc.bzl ├── sysroot │ ├── BUILD.bazel │ ├── centos_sysroot.BUILD │ ├── centos_sysroot.bzl │ └── extract_rpm_file_and_fix_symlinks.py └── universal_binary.bzl ├── settings └── BUILD.bazel └── tests ├── app_with_transitive_deps ├── BUILD.bazel └── main.cpp ├── application_with_library ├── BUILD.bazel └── main.cpp ├── cpp_version_check ├── BUILD.bazel └── main.cpp ├── library_depending_on_other_library ├── BUILD.bazel ├── hello_world.cpp └── hello_world.hpp ├── sanitizers ├── BUILD.bazel ├── address │ ├── BUILD.bazel │ └── intentional_overflow.cpp ├── fuzzer │ ├── BUILD.bazel │ └── basic_fuzzer.cpp ├── memory │ ├── BUILD.bazel │ └── intentional_uninitialized_usage.cpp ├── sanitizer_test.bzl ├── sanitizer_test.py └── thread │ ├── BUILD.bazel │ └── intentional_data_race.cpp ├── simple_application ├── BUILD.bazel └── main.cpp ├── simple_gtest ├── BUILD.bazel ├── simple_gtest_main.cpp └── simple_gtest_tests.cpp └── simple_library ├── BUILD.bazel ├── lib.cpp └── lib.h /.bazelrc: -------------------------------------------------------------------------------- 1 | # General Bazel config 2 | common --noenable_bzlmod 3 | common --enable_platform_specific_config 4 | 5 | # Configurations related to C++ compilation 6 | build --incompatible_enable_cc_toolchain_resolution 7 | 8 | # Enable the `force_pic` build variable. 9 | # This indicates that position-independent code (PIC) and position-independent executables (PIE) should be generated. 10 | build --force_pic 11 | # Enable fission by default on Linux and always download dwo files 12 | build:linux --fission=yes --experimental_remote_download_regex=.*\.dwo 13 | 14 | # Use a platform specific crosstool top to prevent failures like. 15 | # '@local_config_cc//:toolchain' does not contain a toolchain for cpu 'k8|darwin|windows_64'. 16 | # This is a temporary workaround until the legacy crosstool has been removed entirely from Bazel. 17 | build --crosstool_top="//toolchain:clang_toolchain_suite" 18 | build --platform_mappings=toolchain/platforms/platform_mappings 19 | build --experimental_output_directory_naming_scheme=diff_against_baseline 20 | 21 | # Add a sanitizers flag to the build so we can skip targets that are not compatible with sanitizers 22 | build:sanitizer --//bazel/settings:sanitizer --config=slow_lane 23 | 24 | # Create a config for common Sanitizer flags, ASAN and UBSAN work well together so they are enabled together 25 | build:ub-asan --features=address_sanitizer --features=undefined_behavior_sanitizer --config=sanitizer --platform_suffix=ub-asan 26 | build:tsan --features=thread_sanitizer --config=sanitizer --platform_suffix=tsan 27 | build:msan --features=memory_sanitizer --config=sanitizer --platform_suffix=msan 28 | 29 | # These are OS specific and do not hurt anything in unsanitized runs. Sadly, each of the sanitizers requires their own settings. 30 | # The env should apply to both run & build as run inherits from build 31 | build:linux --action_env=ASAN_SYMBOLIZER_PATH=./external/clang_linux/bin/llvm-symbolizer --action_env=MSAN_SYMBOLIZER_PATH=./external/clang_linux/bin/llvm-symbolizer --action_env=TSAN_OPTIONS=external_symbolizer_path=./external/clang_linux/bin/llvm-symbolizer 32 | build:macos --action_env=ASAN_SYMBOLIZER_PATH=./external/clang_darwin/bin/llvm-symbolizer --action_env=MSAN_SYMBOLIZER_PATH=./external/clang_darwin/bin/llvm-symbolizer --action_env=TSAN_OPTIONS=external_symbolizer_path=./external/clang_darwin/bin/llvm-symbolizer 33 | 34 | # Build fuzzers with sanitizers 35 | build:fuzzer --config=ub-asan 36 | build:fuzzer --features=fuzzer-no-link 37 | -------------------------------------------------------------------------------- /.bazelversion: -------------------------------------------------------------------------------- 1 | 7.3.1 -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bazel-* 2 | .vscode/* 3 | thirdparty/macos_sdk/* 4 | thirdparty/macos_cmdtools/* 5 | 6 | !thirdparty/macos_sdk/WORKSPACE 7 | !thirdparty/macos_sdk/BUILD.bazel 8 | !thirdparty/macos_sdk/download_and_extract.sh 9 | !thirdparty/macos_cmdtools/WORKSPACE 10 | !thirdparty/macos_cmdtools/BUILD.bazel 11 | !thirdparty/macos_cmdtools/extract.sh 12 | 13 | .DS_Store 14 | 15 | bazelisk-windows-amd64.exe 16 | -------------------------------------------------------------------------------- /BUILD.bazel: -------------------------------------------------------------------------------- 1 | filegroup( 2 | name = "empty_filegroup", 3 | srcs = [], 4 | visibility = ["//visibility:public"], 5 | ) 6 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Comment line immediately above ownership line is reserved for related other information. Please be careful while editing. 2 | #ECCN:Open Source 5D002 3 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Salesforce Open Source Community Code of Conduct 2 | 3 | ## About the Code of Conduct 4 | 5 | Equality is a core value at Salesforce. We believe a diverse and inclusive 6 | community fosters innovation and creativity, and are committed to building a 7 | culture where everyone feels included. 8 | 9 | Salesforce open-source projects are committed to providing a friendly, safe, and 10 | welcoming environment for all, regardless of gender identity and expression, 11 | sexual orientation, disability, physical appearance, body size, ethnicity, nationality, 12 | race, age, religion, level of experience, education, socioeconomic status, or 13 | other similar personal characteristics. 14 | 15 | The goal of this code of conduct is to specify a baseline standard of behavior so 16 | that people with different social values and communication styles can work 17 | together effectively, productively, and respectfully in our open source community. 18 | It also establishes a mechanism for reporting issues and resolving conflicts. 19 | 20 | All questions and reports of abusive, harassing, or otherwise unacceptable behavior 21 | in a Salesforce open-source project may be reported by contacting the Salesforce 22 | Open Source Conduct Committee at ossconduct@salesforce.com. 23 | 24 | ## Our Pledge 25 | 26 | In the interest of fostering an open and welcoming environment, we as 27 | contributors and maintainers pledge to making participation in our project and 28 | our community a harassment-free experience for everyone, regardless of gender 29 | identity and expression, sexual orientation, disability, physical appearance, 30 | body size, ethnicity, nationality, race, age, religion, level of experience, education, 31 | socioeconomic status, or other similar personal characteristics. 32 | 33 | ## Our Standards 34 | 35 | Examples of behavior that contributes to creating a positive environment 36 | include: 37 | 38 | * Using welcoming and inclusive language 39 | * Being respectful of differing viewpoints and experiences 40 | * Gracefully accepting constructive criticism 41 | * Focusing on what is best for the community 42 | * Showing empathy toward other community members 43 | 44 | Examples of unacceptable behavior by participants include: 45 | 46 | * The use of sexualized language or imagery and unwelcome sexual attention or 47 | advances 48 | * Personal attacks, insulting/derogatory comments, or trolling 49 | * Public or private harassment 50 | * Publishing, or threatening to publish, others' private information—such as 51 | a physical or electronic address—without explicit permission 52 | * Other conduct which could reasonably be considered inappropriate in a 53 | professional setting 54 | * Advocating for or encouraging any of the above behaviors 55 | 56 | ## Our Responsibilities 57 | 58 | Project maintainers are responsible for clarifying the standards of acceptable 59 | behavior and are expected to take appropriate and fair corrective action in 60 | response to any instances of unacceptable behavior. 61 | 62 | Project maintainers have the right and responsibility to remove, edit, or 63 | reject comments, commits, code, wiki edits, issues, and other contributions 64 | that are not aligned with this Code of Conduct, or to ban temporarily or 65 | permanently any contributor for other behaviors that they deem inappropriate, 66 | threatening, offensive, or harmful. 67 | 68 | ## Scope 69 | 70 | This Code of Conduct applies both within project spaces and in public spaces 71 | when an individual is representing the project or its community. Examples of 72 | representing a project or community include using an official project email 73 | address, posting via an official social media account, or acting as an appointed 74 | representative at an online or offline event. Representation of a project may be 75 | further defined and clarified by project maintainers. 76 | 77 | ## Enforcement 78 | 79 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 80 | reported by contacting the Salesforce Open Source Conduct Committee 81 | at ossconduct@salesforce.com. All complaints will be reviewed and investigated 82 | and will result in a response that is deemed necessary and appropriate to the 83 | circumstances. The committee is obligated to maintain confidentiality with 84 | regard to the reporter of an incident. Further details of specific enforcement 85 | policies may be posted separately. 86 | 87 | Project maintainers who do not follow or enforce the Code of Conduct in good 88 | faith may face temporary or permanent repercussions as determined by other 89 | members of the project's leadership and the Salesforce Open Source Conduct 90 | Committee. 91 | 92 | ## Attribution 93 | 94 | This Code of Conduct is adapted from the [Contributor Covenant][contributor-covenant-home], 95 | version 1.4, available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html. 96 | It includes adaptions and additions from [Go Community Code of Conduct][golang-coc], 97 | [CNCF Code of Conduct][cncf-coc], and [Microsoft Open Source Code of Conduct][microsoft-coc]. 98 | 99 | This Code of Conduct is licensed under the [Creative Commons Attribution 3.0 License][cc-by-3-us]. 100 | 101 | [contributor-covenant-home]: https://www.contributor-covenant.org (https://www.contributor-covenant.org/) 102 | [golang-coc]: https://golang.org/conduct 103 | [cncf-coc]: https://github.com/cncf/foundation/blob/master/code-of-conduct.md 104 | [microsoft-coc]: https://opensource.microsoft.com/codeofconduct/ 105 | [cc-by-3-us]: https://creativecommons.org/licenses/by/3.0/us/ -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guide For bazel-cpp-toolchain 2 | 3 | This page lists the operational governance model of this project, as well as the recommendations and requirements for how to best contribute to this repository. We strive to obey these as best as possible. As always, thanks for contributing – we hope these guidelines make it easier and shed some light on our approach and processes. 4 | 5 | # Governance Model 6 | 7 | ## Published but not supported 8 | 9 | The intent and goal of open sourcing this project is because it may contain useful or interesting code/concepts that we wish to share with the larger open source community. Although occasional work may be done on it, we will not be looking for or soliciting contributions. 10 | 11 | # Issues, requests & ideas 12 | 13 | Use GitHub Issues page to submit issues, enhancement requests and discuss ideas. 14 | 15 | ### Bug Reports and Fixes 16 | - If you find a bug, please search for it in the [Issues](https://github.com/salesforce-misc/bazel-cpp-toolchain/issues), and if it isn't already tracked, 17 | [create a new issue](https://github.com/salesforce-misc/bazel-cpp-toolchain/issues/new). Fill out the "Bug Report" section of the issue template. Even if an Issue is closed, feel free to comment and add details, it will still 18 | be reviewed. 19 | - Issues that have already been identified as a bug (note: able to reproduce) will be labelled `bug`. 20 | - If you'd like to submit a fix for a bug, [send a Pull Request](#creating_a_pull_request) and mention the Issue number. 21 | - Include tests that isolate the bug and verifies that it was fixed. 22 | 23 | ### New Features 24 | - If you'd like to add new functionality to this project, describe the problem you want to solve in a [new Issue](https://github.com/salesforce-misc/bazel-cpp-toolchain/issues/new). 25 | - Issues that have been identified as a feature request will be labelled `enhancement`. 26 | - If you'd like to implement the new feature, please wait for feedback from the project 27 | maintainers before spending too much time writing the code. In some cases, `enhancement`s may 28 | not align well with the project objectives at the time. 29 | 30 | ### Tests, Documentation, Miscellaneous 31 | - If you'd like to improve the tests, you want to make the documentation clearer, you have an 32 | alternative implementation of something that may have advantages over the way its currently 33 | done, or you have any other change, we would be happy to hear about it! 34 | - If its a trivial change, go ahead and [send a Pull Request](#creating_a_pull_request) with the changes you have in mind. 35 | - If not, [open an Issue](https://github.com/salesforce-misc/bazel-cpp-toolchain/issues/new) to discuss the idea first. 36 | 37 | If you're new to our project and looking for some way to make your first contribution, look for 38 | Issues labelled `good first contribution`. 39 | 40 | # Contribution Checklist 41 | 42 | - [x] Clean, simple, well styled code 43 | - [x] Commits should be atomic and messages must be descriptive. Related issues should be mentioned by Issue number. 44 | - [x] Comments 45 | - Module-level & function-level comments. 46 | - Comments on complex blocks of code or algorithms (include references to sources). 47 | - [x] Tests 48 | - The test suite, if provided, must be complete and pass 49 | - Increase code coverage, not versa. 50 | - Use any of our testkits that contains a bunch of testing facilities you would need. For example: `import com.salesforce.op.test._` and borrow inspiration from existing tests. 51 | - [x] Dependencies 52 | - Minimize number of dependencies. 53 | - Prefer Apache 2.0, BSD3, MIT, ISC and MPL licenses. 54 | - [x] Reviews 55 | - Changes must be approved via peer code review 56 | 57 | # Creating a Pull Request 58 | 59 | 1. **Ensure the bug/feature was not already reported** by searching on GitHub under Issues. If none exists, create a new issue so that other contributors can keep track of what you are trying to add/fix and offer suggestions (or let you know if there is already an effort in progress). 60 | 3. **Clone** the forked repo to your machine. 61 | 4. **Create** a new branch to contain your work (e.g. `git br fix-issue-11`) 62 | 4. **Commit** changes to your own branch. 63 | 5. **Push** your work back up to your fork. (e.g. `git push fix-issue-11`) 64 | 6. **Submit** a Pull Request against the `main` branch and refer to the issue(s) you are fixing. Try not to pollute your pull request with unintended changes. Keep it simple and small. 65 | 7. **Sign** the Salesforce CLA (you will be prompted to do so when submitting the Pull Request) 66 | 67 | > **NOTE**: Be sure to [sync your fork](https://help.github.com/articles/syncing-a-fork/) before making a pull request. 68 | 69 | 70 | # Code of Conduct 71 | Please follow our [Code of Conduct](CODE_OF_CONDUCT.md). 72 | 73 | # License 74 | By contributing your code, you agree to license your contribution under the terms of our project [LICENSE](LICENSE.txt) and to sign the [Salesforce CLA](https://cla.salesforce.com/sign-cla) 75 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Apache License Version 2.0 2 | 3 | Copyright (c) 2023 Salesforce, Inc. 4 | All rights reserved. 5 | 6 | Apache License 7 | Version 2.0, January 2004 8 | http://www.apache.org/licenses/ 9 | 10 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 11 | 12 | 1. Definitions. 13 | 14 | "License" shall mean the terms and conditions for use, reproduction, 15 | and distribution as defined by Sections 1 through 9 of this document. 16 | 17 | "Licensor" shall mean the copyright owner or entity authorized by 18 | the copyright owner that is granting the License. 19 | 20 | "Legal Entity" shall mean the union of the acting entity and all 21 | other entities that control, are controlled by, or are under common 22 | control with that entity. For the purposes of this definition, 23 | "control" means (i) the power, direct or indirect, to cause the 24 | direction or management of such entity, whether by contract or 25 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 26 | outstanding shares, or (iii) beneficial ownership of such entity. 27 | 28 | "You" (or "Your") shall mean an individual or Legal Entity 29 | exercising permissions granted by this License. 30 | 31 | "Source" form shall mean the preferred form for making modifications, 32 | including but not limited to software source code, documentation 33 | source, and configuration files. 34 | 35 | "Object" form shall mean any form resulting from mechanical 36 | transformation or translation of a Source form, including but 37 | not limited to compiled object code, generated documentation, 38 | and conversions to other media types. 39 | 40 | "Work" shall mean the work of authorship, whether in Source or 41 | Object form, made available under the License, as indicated by a 42 | copyright notice that is included in or attached to the work 43 | (an example is provided in the Appendix below). 44 | 45 | "Derivative Works" shall mean any work, whether in Source or Object 46 | form, that is based on (or derived from) the Work and for which the 47 | editorial revisions, annotations, elaborations, or other modifications 48 | represent, as a whole, an original work of authorship. For the purposes 49 | of this License, Derivative Works shall not include works that remain 50 | separable from, or merely link (or bind by name) to the interfaces of, 51 | the Work and Derivative Works thereof. 52 | 53 | "Contribution" shall mean any work of authorship, including 54 | the original version of the Work and any modifications or additions 55 | to that Work or Derivative Works thereof, that is intentionally 56 | submitted to Licensor for inclusion in the Work by the copyright owner 57 | or by an individual or Legal Entity authorized to submit on behalf of 58 | the copyright owner. For the purposes of this definition, "submitted" 59 | means any form of electronic, verbal, or written communication sent 60 | to the Licensor or its representatives, including but not limited to 61 | communication on electronic mailing lists, source code control systems, 62 | and issue tracking systems that are managed by, or on behalf of, the 63 | Licensor for the purpose of discussing and improving the Work, but 64 | excluding communication that is conspicuously marked or otherwise 65 | designated in writing by the copyright owner as "Not a Contribution." 66 | 67 | "Contributor" shall mean Licensor and any individual or Legal Entity 68 | on behalf of whom a Contribution has been received by Licensor and 69 | subsequently incorporated within the Work. 70 | 71 | 2. Grant of Copyright License. Subject to the terms and conditions of 72 | this License, each Contributor hereby grants to You a perpetual, 73 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 74 | copyright license to reproduce, prepare Derivative Works of, 75 | publicly display, publicly perform, sublicense, and distribute the 76 | Work and such Derivative Works in Source or Object form. 77 | 78 | 3. Grant of Patent License. Subject to the terms and conditions of 79 | this License, each Contributor hereby grants to You a perpetual, 80 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 81 | (except as stated in this section) patent license to make, have made, 82 | use, offer to sell, sell, import, and otherwise transfer the Work, 83 | where such license applies only to those patent claims licensable 84 | by such Contributor that are necessarily infringed by their 85 | Contribution(s) alone or by combination of their Contribution(s) 86 | with the Work to which such Contribution(s) was submitted. If You 87 | institute patent litigation against any entity (including a 88 | cross-claim or counterclaim in a lawsuit) alleging that the Work 89 | or a Contribution incorporated within the Work constitutes direct 90 | or contributory patent infringement, then any patent licenses 91 | granted to You under this License for that Work shall terminate 92 | as of the date such litigation is filed. 93 | 94 | 4. Redistribution. You may reproduce and distribute copies of the 95 | Work or Derivative Works thereof in any medium, with or without 96 | modifications, and in Source or Object form, provided that You 97 | meet the following conditions: 98 | 99 | (a) You must give any other recipients of the Work or 100 | Derivative Works a copy of this License; and 101 | 102 | (b) You must cause any modified files to carry prominent notices 103 | stating that You changed the files; and 104 | 105 | (c) You must retain, in the Source form of any Derivative Works 106 | that You distribute, all copyright, patent, trademark, and 107 | attribution notices from the Source form of the Work, 108 | excluding those notices that do not pertain to any part of 109 | the Derivative Works; and 110 | 111 | (d) If the Work includes a "NOTICE" text file as part of its 112 | distribution, then any Derivative Works that You distribute must 113 | include a readable copy of the attribution notices contained 114 | within such NOTICE file, excluding those notices that do not 115 | pertain to any part of the Derivative Works, in at least one 116 | of the following places: within a NOTICE text file distributed 117 | as part of the Derivative Works; within the Source form or 118 | documentation, if provided along with the Derivative Works; or, 119 | within a display generated by the Derivative Works, if and 120 | wherever such third-party notices normally appear. The contents 121 | of the NOTICE file are for informational purposes only and 122 | do not modify the License. You may add Your own attribution 123 | notices within Derivative Works that You distribute, alongside 124 | or as an addendum to the NOTICE text from the Work, provided 125 | that such additional attribution notices cannot be construed 126 | as modifying the License. 127 | 128 | You may add Your own copyright statement to Your modifications and 129 | may provide additional or different license terms and conditions 130 | for use, reproduction, or distribution of Your modifications, or 131 | for any such Derivative Works as a whole, provided Your use, 132 | reproduction, and distribution of the Work otherwise complies with 133 | the conditions stated in this License. 134 | 135 | 5. Submission of Contributions. Unless You explicitly state otherwise, 136 | any Contribution intentionally submitted for inclusion in the Work 137 | by You to the Licensor shall be under the terms and conditions of 138 | this License, without any additional terms or conditions. 139 | Notwithstanding the above, nothing herein shall supersede or modify 140 | the terms of any separate license agreement you may have executed 141 | with Licensor regarding such Contributions. 142 | 143 | 6. Trademarks. This License does not grant permission to use the trade 144 | names, trademarks, service marks, or product names of the Licensor, 145 | except as required for reasonable and customary use in describing the 146 | origin of the Work and reproducing the content of the NOTICE file. 147 | 148 | 7. Disclaimer of Warranty. Unless required by applicable law or 149 | agreed to in writing, Licensor provides the Work (and each 150 | Contributor provides its Contributions) on an "AS IS" BASIS, 151 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 152 | implied, including, without limitation, any warranties or conditions 153 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 154 | PARTICULAR PURPOSE. You are solely responsible for determining the 155 | appropriateness of using or redistributing the Work and assume any 156 | risks associated with Your exercise of permissions under this License. 157 | 158 | 8. Limitation of Liability. In no event and under no legal theory, 159 | whether in tort (including negligence), contract, or otherwise, 160 | unless required by applicable law (such as deliberate and grossly 161 | negligent acts) or agreed to in writing, shall any Contributor be 162 | liable to You for damages, including any direct, indirect, special, 163 | incidental, or consequential damages of any character arising as a 164 | result of this License or out of the use or inability to use the 165 | Work (including but not limited to damages for loss of goodwill, 166 | work stoppage, computer failure or malfunction, or any and all 167 | other commercial damages or losses), even if such Contributor 168 | has been advised of the possibility of such damages. 169 | 170 | 9. Accepting Warranty or Additional Liability. While redistributing 171 | the Work or Derivative Works thereof, You may choose to offer, 172 | and charge a fee for, acceptance of support, warranty, indemnity, 173 | or other liability obligations and/or rights consistent with this 174 | License. However, in accepting such obligations, You may act only 175 | on Your own behalf and on Your sole responsibility, not on behalf 176 | of any other Contributor, and only if You agree to indemnify, 177 | defend, and hold each Contributor harmless for any liability 178 | incurred by, or claims asserted against, such Contributor by reason 179 | of your accepting any such warranty or additional liability. 180 | 181 | END OF TERMS AND CONDITIONS 182 | 183 | APPENDIX: How to apply the Apache License to your work. 184 | 185 | To apply the Apache License to your work, attach the following 186 | boilerplate notice, with the fields enclosed by brackets "{}" 187 | replaced with your own identifying information. (Don't include 188 | the brackets!) The text should be enclosed in the appropriate 189 | comment syntax for the file format. We also recommend that a 190 | file or class name and description of purpose be included on the 191 | same "printed page" as the copyright notice for easier 192 | identification within third-party archives. 193 | 194 | Copyright {yyyy} {name of copyright owner} 195 | 196 | Licensed under the Apache License, Version 2.0 (the "License"); 197 | you may not use this file except in compliance with the License. 198 | You may obtain a copy of the License at 199 | 200 | http://www.apache.org/licenses/LICENSE-2.0 201 | 202 | Unless required by applicable law or agreed to in writing, software 203 | distributed under the License is distributed on an "AS IS" BASIS, 204 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 205 | See the License for the specific language governing permissions and 206 | limitations under the License. 207 | 208 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # bazel-cpp-toolchain 2 | 3 | *Example repository for the [Utilizing Bazel for Cross-Platform and Cross-Architecture Compilation and Testing](https://sched.co/1h6SU) talk at [BazelCon 24](https://events.linuxfoundation.org/bazelcon/) by Axel Uhlig & Marcel Kost at Salesforce. ([Recording](https://www.youtube.com/watch?v=E3DCwQzRPJA))* 4 | 5 | This repository shows the setup of a fully hermetic [Bazel C++ Toolchain](https://bazel.build/docs/cc-toolchain-config-reference) and how it can be used to achieve cool things like multi-OS support, cross-compiling and creating macOS universal binaries just with native Bazel features. The code in this repository is not maintained. 6 | 7 | The toolchain in this repository is used to build the [Hyper database](https://tableau.github.io/hyper-db/) that powers the backend of [Tableau](https://tableau.com/) as well as [Salesforce Data Cloud](https://salesforce.com/data). The name `hyper` therefore is used in many places in the code. 8 | 9 | ## About the Toolchain 10 | 11 | Main features: 12 | * Cross-OS support (Windows, Linux, macOS) 13 | * Cross-architecture support (x86-64 by default, aarch64 on macOS) 14 | * Fully hermetic: 15 | * Uses explicit sysroot/SDK on all platforms 16 | * Disables non-hermetic compiler behaviour like default includes and link search paths 17 | 18 | Additional features: 19 | * C++23 support 20 | * libstdc++ support 21 | * Compiler flags for security hardening 22 | * Automatic centos7 sysroot creation from rpm packages 23 | * Toolchain tests: Set of small hello-world projects to test different toolchain features 24 | * Sanitizer Support 25 | * Fuzzer support (LLVM libFuzzer) 26 | * Rules to create [Universal Binaries](https://developer.apple.com/documentation/apple-silicon/building-a-universal-macos-binary) on macOS 27 | * Debug symbol handling 28 | 29 | ## Setup 30 | 31 | For legal reason this repository unfortunately doesn't include pre-built clang packages and OS-specific SDKs on macOS and Windows. To build the targets in all configurations, these have to be provided manually. 32 | 33 | This section explains the steps necessary to provide all missing parts: 34 | 35 | ### Compiler 36 | 37 | This C++ toolchain uses [clang](https://clang.llvm.org/) for all operating systems. It expects clang to be linked statically (to run independent from the host system version) and the package to contain libstdc++ for all desired target architectures. We highly recommend to go the extra mile and build such a clang package yourself. 38 | 39 | To make it easier to test this toolchain code, **by default the [pre-build packages from LLVM](https://github.com/llvm/llvm-project/releases) are used**, but these are not statically linked and only contain libstdc++ for the host platform. Therefore the universal binary example doesn't work unless different clang packages are provided. 40 | 41 | ### OS-dependent sysroot/SDKs 42 | 43 | #### Linux 44 | On Linux the C++ toolchain creates a centos7 sysroot on the fly by downloading and extracting rpm packages. However, this example repository doesn't ship a hermetic python toolchain and thus requires Python 3 and a few libaries to be available on the host system. If you have a hermetic python toolchain, you can plug it into the `centos_sysroot()` instance in the `MODULE.bazel` file. 45 | 46 | **Requirements on the host system** 47 | - `python3` 48 | - The pip packages `rpmfile` and `zstandard` 49 | 50 | #### macOS 51 | The C++ toolchain for macOS requires the macOS SDK and the macOS Command Line Tools. Unfortunately both are available for download only with an Apple login and therefore can't be pulled automatically. For the C++ toolchain to work on macOS, you need to manually download and extract those two packages. 52 | For your own setup we suggest to mirror the two packages internally and let Bazel consume them via `http_archive` like the other packages. 53 | 54 | **macOS 13.3 SDK** 55 | * Run `thirdparty/macos_sdk/download_and_extract.sh` to download and extract the package automatically (This downloads the SDK from https://github.com/alexey-lysiuk/macos-sdk) 56 | * __or__ Extract it manually from XCode and copy the files to `thirdparty/macos_sdk`. 57 | Note: You have to manually delete the `System/Library/Frameworks/Ruby.framework/Versions/2.6/Headers/ruby/ruby` folder from the package, since it contains a cyclic symlink and which annoys Bazel. 58 | 59 | **Command Line Tools for Xcode 15.3** 60 | * Download "Command Line Tools for Xcode 15.3" from the Apple website (https://developer.apple.com/xcode/resources/), mount it and copy the `.pkg` file to `thirdparty/macos_cmdtools`. 61 | * Run `thirdparty/macos_cmdtools/extract.sh` to extract the package. 62 | 63 | #### Windows 64 | On Windows the C++ toolchain requires the Windows SDK, which also needs to be downloaded and extracted manually. 65 | 66 | **Windows SDK 10.0.22621** 67 | * Download from the [Windows website](https://developer.microsoft.com/en-us/windows/downloads/windows-sdk/) 68 | * Install on a host system 69 | * Copy folders to `thirdparty/windows_sdk` 70 | 71 | **Microsoft Visual C++ Redistributable Version 14.39.33519** 72 | * Download from the [MSVC Website](https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist?view=msvc-170#latest-microsoft-visual-c-redistributable-version) 73 | * Install on a host system 74 | * Copy folders to `thirdparty/msvc` 75 | 76 | ## How to contribute 77 | 78 | ### Required tools 79 | 80 | 1. [bazelisk](https://github.com/bazelbuild/bazelisk) 81 | 1. [buildifier](https://github.com/bazelbuild/buildtools/tree/main/buildifier) 82 | 83 | ### How to verify your changes 84 | 85 | 1. Formatting: `buildifier -r .` 86 | 1. Test: `bazelisk test //...` 87 | 88 | ## Questions 89 | 90 | If you have questions, feel free to reach out to the authors of the talk in the [Bazel Slack Workspace](https://slack.bazel.build/). 91 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | ## Security 2 | 3 | Please report any security issue to [security@salesforce.com](mailto:security@salesforce.com) 4 | as soon as it is discovered. This library limits its runtime dependencies in 5 | order to reduce the total cost of ownership as much as can be, but all consumers 6 | should remain vigilant and have their security stakeholders review all third-party 7 | products (3PP) like this one and their dependencies. -------------------------------------------------------------------------------- /WORKSPACE: -------------------------------------------------------------------------------- 1 | load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") 2 | 3 | # ------------------------------------- 4 | # rules_cc 5 | 6 | http_archive( 7 | name = "rules_cc", 8 | sha256 = "2037875b9a4456dce4a79d112a8ae885bbc4aad968e6587dca6e64f3a0900cdf", 9 | strip_prefix = "rules_cc-0.0.9", 10 | urls = ["https://github.com/bazelbuild/rules_cc/releases/download/0.0.9/rules_cc-0.0.9.tar.gz"], 11 | ) 12 | 13 | # ------------------------------------- 14 | # rules_python 15 | 16 | http_archive( 17 | name = "rules_python", 18 | sha256 = "be04b635c7be4604be1ef20542e9870af3c49778ce841ee2d92fcb42f9d9516a", 19 | strip_prefix = "rules_python-0.35.0", 20 | url = "https://github.com/bazelbuild/rules_python/releases/download/0.35.0/rules_python-0.35.0.tar.gz", 21 | ) 22 | 23 | load("@rules_python//python:repositories.bzl", "py_repositories") 24 | 25 | py_repositories() 26 | 27 | # ------------------------------------- 28 | # rules_pkg 29 | 30 | http_archive( 31 | name = "rules_pkg", 32 | sha256 = "d20c951960ed77cb7b341c2a59488534e494d5ad1d30c4818c736d57772a9fef", 33 | urls = [ 34 | "https://github.com/bazelbuild/rules_pkg/releases/download/1.0.1/rules_pkg-1.0.1.tar.gz", 35 | ], 36 | ) 37 | 38 | load("@rules_pkg//:deps.bzl", "rules_pkg_dependencies") 39 | 40 | rules_pkg_dependencies() 41 | 42 | # ------------------------------------- 43 | # Linux Sysroot 44 | 45 | # The centos_sysroot depends on the python interpreter and the rpmfile pip package 46 | # and must therefore occur after the setup of python and the initialization of the pip modules 47 | load("//toolchain/rules/sysroot:centos_sysroot.bzl", "centos_sysroot") 48 | 49 | centos_sysroot( 50 | name = "sysroot_linux", 51 | python_interpreter = None, # if you have a hermetic python toolchain you can plug it in here 52 | rpm_packages = { 53 | "https://archive.kernel.org/centos-vault/7.9.2009/os/x86_64/Packages/gcc-4.8.5-44.el7.x86_64.rpm": "186d9bdbb568d08c4d8b2f9a2c0fce952c2ac80ef5989806116df61c7cbc5a22", 54 | "https://archive.kernel.org/centos-vault/7.9.2009/os/x86_64/Packages/glibc-2.17-317.el7.x86_64.rpm": "49eb081de1ddd13f5440abdbb3b42cdd01d11b74d624793ae1b80a1cf432551b", 55 | "https://archive.kernel.org/centos-vault/7.9.2009/os/x86_64/Packages/glibc-devel-2.17-317.el7.x86_64.rpm": "57e04523b12c9aa5a0632cbfa2ff13e33f1ecec5e6bd0b609a77d9c24cebf8c4", 56 | "https://archive.kernel.org/centos-vault/7.9.2009/os/x86_64/Packages/glibc-headers-2.17-317.el7.x86_64.rpm": "b7e4e19b362cbd73e09e6ee5eff3d70dbeb7cc2c702a927b8f646f324d4ec4a3", 57 | "https://archive.kernel.org/centos-vault/7.9.2009/os/x86_64/Packages/kernel-headers-3.10.0-1160.el7.x86_64.rpm": "81b4e4f401d2402736ceba4627eaafd5b615c2cc45aa4d4f941ea79562045139", 58 | }, 59 | ) 60 | 61 | # ------------------------------------- 62 | # macOS SDK 63 | 64 | # TODO: Extract "macOS 13.3 SDK" from XCode or download it from https://github.com/alexey-lysiuk/macos-sdk and extract it to 65 | # thirdparty/macos_sdk. 66 | # Note: You have to manually delete the System/Library/Frameworks/Ruby.framework/Versions/2.6/Headers/ruby/ruby 67 | # folder from the package, since it contains a cyclic symlink and which annoys Bazel. 68 | local_repository( 69 | name = "macos_sdk", 70 | path = "thirdparty/macos_sdk", 71 | ) 72 | 73 | # TODO: Download "Command Line Tools for Xcode 15.3" from the Apple website (https://developer.apple.com/xcode/resources/) 74 | # and extract them to thirdparty/macos_cmdtools. 75 | local_repository( 76 | name = "macos_cmdtools", 77 | path = "thirdparty/macos_cmdtools", 78 | ) 79 | 80 | # ------------------------------------- 81 | # Windows SDK 82 | 83 | # Microsoft Visual C++ toolchain 84 | # TODO: Download "MSVC 14.39.33519" from https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist?view=msvc-170#latest-microsoft-visual-c-redistributable-version 85 | # and extract it into thirdparty/msvc 86 | local_repository( 87 | name = "msvc", 88 | path = "thirdparty/msvc", 89 | ) 90 | 91 | # Microsoft Windows SDK 92 | # TODO: Download "Windows SDK 10.0.22621" from https://developer.microsoft.com/en-us/windows/downloads/windows-sdk/ 93 | # and extract it into thirdparty/windows_sdk 94 | local_repository( 95 | name = "windows_sdk", 96 | path = "thirdparty/windows_sdk", 97 | ) 98 | 99 | # ------------------------------------- 100 | # Clang 101 | 102 | # Custom statically clang 17.0.6 including libc++ 103 | http_archive( 104 | name = "clang_linux", 105 | build_file = "@//thirdparty:clang/clang_linux.BUILD", 106 | sha256 = "54ec30358afcc9fb8aa74307db3046f5187f9fb89fb37064cdde906e062ebf36", 107 | strip_prefix = "clang+llvm-18.1.8-x86_64-linux-gnu-ubuntu-18.04", 108 | urls = ["https://github.com/llvm/llvm-project/releases/download/llvmorg-18.1.8/clang+llvm-18.1.8-x86_64-linux-gnu-ubuntu-18.04.tar.xz"], 109 | ) 110 | 111 | # Custom statically clang 17.0.6 including libc++ for both x64 and arm 112 | http_archive( 113 | name = "clang_darwin", 114 | build_file = "@//thirdparty:clang/clang_darwin.BUILD", 115 | sha256 = "4573b7f25f46d2a9c8882993f091c52f416c83271db6f5b213c93f0bd0346a10", 116 | strip_prefix = "clang+llvm-18.1.8-arm64-apple-macos11", 117 | urls = ["https://github.com/llvm/llvm-project/releases/download/llvmorg-18.1.8/clang+llvm-18.1.8-arm64-apple-macos11.tar.xz"], 118 | ) 119 | 120 | # Custom statically clang 17.0.6 including libc++ 121 | http_archive( 122 | name = "clang_windows", 123 | build_file = "@//thirdparty:clang/clang_windows.BUILD", 124 | sha256 = "78ef87e8e0abb34e8463faf612f0d4100818d5181f7e1b1a23b64f677ba74de4", 125 | urls = ["https://github.com/llvm/llvm-project/releases/download/llvmorg-18.1.8/clang+llvm-18.1.8-x86_64-pc-windows-msvc.tar.xz"], 126 | ) 127 | 128 | # ------------------------------------- 129 | # Google test 130 | 131 | # Common variables to define googltest and googlemock dependencies 132 | GTEST_VERSION = "1.15.2" 133 | 134 | GTEST_SHA256 = "7b42b4d6ed48810c5362c265a17faebe90dc2373c885e5216439d37927f02926" 135 | 136 | GTEST_URL = "https://github.com/google/googletest/archive/refs/tags/v" + GTEST_VERSION + ".tar.gz" 137 | 138 | http_archive( 139 | name = "googletest", 140 | build_file = "@//thirdparty:gtest/gtest.BUILD", 141 | sha256 = GTEST_SHA256, 142 | strip_prefix = "googletest-" + GTEST_VERSION + "/googletest", 143 | url = GTEST_URL, 144 | ) 145 | 146 | # ------------------------------------- 147 | # Register toolchains 148 | 149 | register_toolchains( 150 | "//toolchain:cc-toolchain-clang-windows-x64-x64", 151 | "//toolchain:cc-toolchain-clang-linux-x64-x64", 152 | "//toolchain:cc-toolchain-clang-macos-any-x64", 153 | "//toolchain:cc-toolchain-clang-macos-any-arm", 154 | ) 155 | -------------------------------------------------------------------------------- /thirdparty/BUILD.bazel: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/salesforce-misc/bazel-cpp-toolchain/0b969b47abd885828ece8006c62e5d7eaa006467/thirdparty/BUILD.bazel -------------------------------------------------------------------------------- /thirdparty/clang/BUILD.bazel: -------------------------------------------------------------------------------- 1 | alias( 2 | name = "all_files", 3 | actual = select({ 4 | "@//toolchain/platforms:is_windows": "@clang_windows//:all_files", 5 | "@//toolchain/platforms:is_linux": "@clang_linux//:all_files", 6 | "@//toolchain/platforms:is_macos": "@clang_darwin//:all_files", 7 | }), 8 | visibility = ["//visibility:public"], 9 | ) 10 | 11 | alias( 12 | name = "clang", 13 | actual = select({ 14 | "@//toolchain/platforms:is_linux": "@clang_linux//:bin_aliases", 15 | "@//toolchain/platforms:is_macos": "@clang_darwin//:bin_aliases", 16 | "@//toolchain/platforms:is_windows": "@clang_windows//:clang", 17 | }), 18 | visibility = ["//visibility:public"], 19 | ) 20 | 21 | # Sanitizer support files, e.g. symbolizer for crash reports 22 | alias( 23 | name = "sanitizer_support", 24 | actual = select({ 25 | "@//toolchain/platforms:is_linux": "@clang_linux//:sanitizer_support", 26 | "@//toolchain/platforms:is_macos": "@clang_darwin//:sanitizer_support", 27 | "@//toolchain/platforms:is_windows": "@clang_windows//:sanitizer_support", 28 | }), 29 | visibility = ["//visibility:public"], 30 | ) 31 | -------------------------------------------------------------------------------- /thirdparty/clang/clang_darwin.BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//visibility:public"]) 2 | 3 | filegroup( 4 | name = "all_files", 5 | srcs = glob(["**/*"]), 6 | ) 7 | 8 | filegroup( 9 | name = "clang", 10 | srcs = ["bin/clang"], 11 | ) 12 | 13 | filegroup( 14 | name = "ld", 15 | srcs = ["bin/lld"], 16 | visibility = ["//visibility:public"], 17 | ) 18 | 19 | filegroup( 20 | name = "dsymutil", 21 | srcs = ["bin/dsymutil"], 22 | visibility = ["//visibility:public"], 23 | ) 24 | 25 | filegroup( 26 | name = "bin_aliases", 27 | srcs = [ 28 | "bin/clang", 29 | "bin/clang++", 30 | "bin/clang-cpp", 31 | "bin/ld.lld", 32 | "bin/ld64.lld", 33 | "bin/lld-link", 34 | "bin/llvm-ranlib", 35 | "bin/llvm-readelf", 36 | "bin/llvm-strip", 37 | ], 38 | data = [ 39 | ":clang", 40 | ":ld", 41 | ":ranlib", 42 | ":readelf", 43 | ], 44 | ) 45 | 46 | filegroup( 47 | name = "includes", 48 | srcs = glob([ 49 | "include/c++/v1/**", 50 | "lib/clang/*/include/**", 51 | "lib/clang/*/share/*_ignorelist.txt", 52 | ]), 53 | ) 54 | 55 | filegroup( 56 | name = "libsan", 57 | srcs = glob( 58 | [ 59 | "lib/clang/*/lib/**/*san*_osx_dynamic.dylib", 60 | ], 61 | ), 62 | ) 63 | 64 | filegroup( 65 | name = "lib", 66 | srcs = glob( 67 | [ 68 | "lib/lib*.a", 69 | "lib/lib*.dylib", 70 | "lib/clang/*/lib/**/*.a", 71 | "lib/clang/*/lib/**/*.dylib", 72 | ], 73 | exclude = [ 74 | "lib/libLLVM*.a", 75 | "lib/libclang*.a", 76 | "lib/liblld*.a", 77 | "lib/libLLVM*.dylib", 78 | "lib/libclang*.dylib", 79 | "lib/liblld*.dylib", 80 | ], 81 | ), 82 | ) 83 | 84 | filegroup( 85 | name = "cpp_static_runtime_libraries", 86 | srcs = [ 87 | "lib/libc++.a", 88 | "lib/libc++abi.a", 89 | "lib/libc++experimental.a", 90 | ], 91 | ) 92 | 93 | filegroup( 94 | name = "cpp_dynamic_runtime_libraries", 95 | srcs = [ 96 | # libs and their symlinks/aliases 97 | "lib/libc++.1.0.dylib", 98 | "lib/libc++.1.dylib", 99 | "lib/libc++.dylib", 100 | "lib/libc++abi.1.0.dylib", 101 | "lib/libc++abi.1.dylib", 102 | "lib/libc++abi.dylib", 103 | ], 104 | ) 105 | 106 | filegroup( 107 | name = "compiler_components", 108 | srcs = [ 109 | ":bin_aliases", 110 | ":clang", 111 | ":includes", 112 | ":sanitizer_support", 113 | ], 114 | ) 115 | 116 | filegroup( 117 | name = "ar", 118 | srcs = ["bin/llvm-ar"], 119 | ) 120 | 121 | filegroup( 122 | name = "as", 123 | srcs = ["bin/llvm-as"], 124 | ) 125 | 126 | filegroup( 127 | name = "nm", 128 | srcs = ["bin/llvm-nm"], 129 | ) 130 | 131 | filegroup( 132 | name = "objcopy", 133 | srcs = ["bin/llvm-objcopy"], 134 | ) 135 | 136 | filegroup( 137 | name = "objdump", 138 | srcs = ["bin/llvm-objdump"], 139 | ) 140 | 141 | filegroup( 142 | name = "clang_tidy", 143 | srcs = ["bin/clang-tidy"], 144 | ) 145 | 146 | filegroup( 147 | name = "clang_format", 148 | srcs = ["bin/clang-format"], 149 | ) 150 | 151 | filegroup( 152 | name = "clang_apply_replacements", 153 | srcs = ["bin/clang-apply-replacements"], 154 | ) 155 | 156 | filegroup( 157 | name = "dwp", 158 | srcs = ["bin/llvm-dwp"], 159 | ) 160 | 161 | filegroup( 162 | name = "ranlib", 163 | srcs = ["bin/llvm-ar"], 164 | ) 165 | 166 | filegroup( 167 | name = "readelf", 168 | srcs = ["bin/llvm-readobj"], 169 | ) 170 | 171 | filegroup( 172 | name = "binutils_components", 173 | srcs = glob(["bin/*"]), 174 | ) 175 | 176 | filegroup( 177 | name = "linker_components", 178 | srcs = [ 179 | ":ar", 180 | ":bin_aliases", 181 | ":clang", 182 | ":ld", 183 | ":lib", 184 | ], 185 | ) 186 | 187 | filegroup( 188 | name = "sanitizer_support", 189 | srcs = [ 190 | "bin/llvm-symbolizer", 191 | # ASAN is linked dynamically on macOS, thus we need to add the dynamic ASAN library to the sandbox. 192 | "@clang_darwin//:libsan", 193 | ] + glob(["lib/clang/*/share/*_ignorelist.txt"]), 194 | ) 195 | 196 | filegroup( 197 | name = "all_components", 198 | srcs = [ 199 | ":binutils_components", 200 | ":compiler_components", 201 | ":linker_components", 202 | ], 203 | ) 204 | 205 | filegroup( 206 | name = "llvm_cvtres", 207 | srcs = [ 208 | "bin/llvm-cvtres", 209 | ], 210 | visibility = ["//visibility:public"], 211 | ) 212 | 213 | filegroup( 214 | name = "llvm_rc", 215 | srcs = [ 216 | "bin/llvm-rc", 217 | ], 218 | visibility = ["//visibility:public"], 219 | ) 220 | 221 | filegroup( 222 | name = "llvm-lipo", 223 | srcs = [ 224 | "bin/llvm-lipo", 225 | ], 226 | visibility = ["//visibility:public"], 227 | ) 228 | -------------------------------------------------------------------------------- /thirdparty/clang/clang_linux.BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//visibility:public"]) 2 | 3 | filegroup( 4 | name = "all_files", 5 | srcs = glob(["**/*"]) 6 | ) 7 | 8 | filegroup( 9 | name = "clang", 10 | srcs = ["bin/clang"], 11 | ) 12 | 13 | filegroup( 14 | name = "ld", 15 | srcs = ["bin/lld"], 16 | ) 17 | 18 | filegroup( 19 | name = "clang_tidy", 20 | srcs = ["bin/clang-tidy"], 21 | ) 22 | 23 | filegroup( 24 | name = "clang_format", 25 | srcs = ["bin/clang-format"], 26 | ) 27 | 28 | filegroup( 29 | name = "clang_apply_replacements", 30 | srcs = ["bin/clang-apply-replacements"], 31 | ) 32 | 33 | filegroup( 34 | name = "dsymutil", 35 | srcs = ["bin/dsymutil"], 36 | ) 37 | 38 | filegroup( 39 | name = "bin_aliases", 40 | srcs = [ 41 | "bin/clang", 42 | "bin/clang++", 43 | "bin/clang-cpp", 44 | "bin/ld.lld", 45 | "bin/ld64.lld", 46 | "bin/lld-link", 47 | "bin/llvm-readelf", 48 | "bin/llvm-ranlib", 49 | "bin/llvm-strip", 50 | ], 51 | data = [ 52 | ":clang", 53 | ":ld", 54 | ":readelf", 55 | ":ranlib", 56 | ":strip", 57 | ], 58 | ) 59 | 60 | 61 | filegroup( 62 | name = "includes", 63 | srcs = glob([ 64 | "include/c++/v1/**", 65 | "include/x86_64-unknown-linux-gnu/c++/v1/**", 66 | "lib/clang/*/include/**", 67 | ]), 68 | ) 69 | 70 | filegroup( 71 | name = "lib", 72 | srcs = glob( 73 | [ 74 | # Various `libclang_rt` libraries 75 | "lib/clang/*/lib/**/*.a", 76 | "lib/clang/*/lib/**/*.so", 77 | # libc++, libunwind, ... 78 | "lib/x86_64-unknown-linux-gnu/lib*.a", 79 | "lib/x86_64-unknown-linux-gnu/lib*.so", 80 | "lib/x86_64-unknown-linux-gnu/lib*.so.1", 81 | "lib/x86_64-unknown-linux-gnu/lib*.so.1.0", 82 | ], 83 | ), 84 | ) 85 | 86 | filegroup( 87 | name = "cpp_static_runtime_libraries", 88 | srcs = [ 89 | # The symbol export of these three libraries is manually excluded in the Linux linker call. 90 | # bazel/toolchain/clang/linux/clang_linux_toolchain_config.bzl 91 | # Plase adapt accordingly if any changes are made here. 92 | "lib/x86_64-unknown-linux-gnu/libc++.a", 93 | "lib/x86_64-unknown-linux-gnu/libc++experimental.a", 94 | "lib/x86_64-unknown-linux-gnu/libc++abi.a", 95 | "lib/x86_64-unknown-linux-gnu/libunwind.a" 96 | ], 97 | ) 98 | 99 | filegroup( 100 | name = "cpp_dynamic_runtime_libraries", 101 | srcs = [ 102 | # libs and their symlinks/aliases 103 | "lib/x86_64-unknown-linux-gnu/libc++.so.1", 104 | "lib/x86_64-unknown-linux-gnu/libc++.so.1.0", 105 | "lib/x86_64-unknown-linux-gnu/libc++abi.so.1", 106 | "lib/x86_64-unknown-linux-gnu/libc++abi.so.1.0", 107 | "lib/x86_64-unknown-linux-gnu/libunwind.so.1", 108 | "lib/x86_64-unknown-linux-gnu/libunwind.so.1.0" 109 | ], 110 | ) 111 | 112 | filegroup( 113 | name = "compiler_components", 114 | srcs = [ 115 | ":clang", 116 | ":includes", 117 | # needed by clang binary for execution 118 | ":cpp_dynamic_runtime_libraries", 119 | ":bin_aliases", 120 | ":sanitizer_support", 121 | ], 122 | ) 123 | 124 | filegroup( 125 | name = "ar", 126 | srcs = ["bin/llvm-ar"], 127 | ) 128 | 129 | filegroup( 130 | name = "as", 131 | srcs = ["bin/llvm-as"], 132 | ) 133 | 134 | filegroup( 135 | name = "nm", 136 | srcs = ["bin/llvm-nm"], 137 | ) 138 | 139 | filegroup( 140 | name = "objcopy", 141 | srcs = ["bin/llvm-objcopy"], 142 | ) 143 | 144 | filegroup( 145 | name = "objdump", 146 | srcs = ["bin/llvm-objdump"], 147 | ) 148 | 149 | filegroup( 150 | name = "dwp", 151 | srcs = ["bin/llvm-dwp"], 152 | ) 153 | 154 | filegroup( 155 | name = "ranlib", 156 | srcs = ["bin/llvm-ar"], 157 | ) 158 | 159 | filegroup( 160 | name = "readelf", 161 | srcs = ["bin/llvm-readelf"], 162 | data = [":lib", ":readobj"], 163 | ) 164 | 165 | filegroup( 166 | name = "readobj", 167 | srcs = ["bin/llvm-readobj"], 168 | ) 169 | 170 | filegroup( 171 | name = "strip", 172 | srcs = [ "bin/llvm-strip" ], 173 | ) 174 | 175 | filegroup( 176 | name = "binutils_components", 177 | srcs = glob(["bin/*"]), 178 | ) 179 | 180 | filegroup( 181 | name = "linker_components", 182 | srcs = [ 183 | ":ar", 184 | ":clang", 185 | ":ld", 186 | ":lib", 187 | ":bin_aliases" 188 | ], 189 | ) 190 | 191 | filegroup( 192 | name = "all_components", 193 | srcs = [ 194 | ":binutils_components", 195 | ":compiler_components", 196 | ":linker_components", 197 | ], 198 | ) 199 | 200 | filegroup( 201 | name = "sanitizer_support", 202 | srcs = [ 203 | "bin/llvm-symbolizer", 204 | # Make runtime libraries available in sandbox 205 | ":cpp_dynamic_runtime_libraries", 206 | ] + glob(["lib/clang/*/share/*_ignorelist.txt"]), 207 | ) 208 | 209 | filegroup( 210 | name = "llvm_cvtres", 211 | srcs = [ 212 | "bin/llvm-cvtres", 213 | ], 214 | ) 215 | 216 | filegroup( 217 | name = "llvm_rc", 218 | srcs = [ 219 | "bin/llvm-rc", 220 | ], 221 | ) 222 | -------------------------------------------------------------------------------- /thirdparty/clang/clang_windows.BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//visibility:public"]) 2 | 3 | filegroup( 4 | name = "all_files", 5 | srcs = glob(["**/*"]) 6 | ) 7 | 8 | filegroup( 9 | name = "clang_cl", 10 | srcs = [ 11 | "bin/clang-cl.exe", 12 | ], 13 | ) 14 | 15 | filegroup( 16 | name = "clang", 17 | srcs = [ 18 | "bin/clang.exe", 19 | ], 20 | ) 21 | 22 | filegroup( 23 | name = "lld_link", 24 | srcs = [ 25 | "bin/lld-link.exe", 26 | ], 27 | visibility = ["//visibility:public"], 28 | ) 29 | 30 | filegroup( 31 | name = "clang_tidy", 32 | srcs = ["bin/clang-tidy.exe"], 33 | ) 34 | 35 | filegroup( 36 | name = "clang_format", 37 | srcs = ["bin/clang-format.exe"], 38 | ) 39 | 40 | filegroup( 41 | name = "clang_apply_replacements", 42 | srcs = ["bin/clang-apply-replacements.exe"], 43 | ) 44 | 45 | 46 | filegroup( 47 | name = "llvm_lib", 48 | srcs = [ 49 | "bin/llvm-lib.exe", 50 | ], 51 | visibility = ["//visibility:public"], 52 | ) 53 | 54 | filegroup( 55 | name = "llvm_rc", 56 | srcs = [ 57 | "bin/llvm-rc.exe", 58 | ], 59 | visibility = ["//visibility:public"], 60 | ) 61 | 62 | filegroup( 63 | name = "strip", 64 | srcs = [ 65 | "bin/llvm-strip.exe", 66 | ], 67 | visibility = ["//visibility:public"], 68 | ) 69 | 70 | filegroup( 71 | name = "sanitizer_support", 72 | srcs = [], 73 | ) 74 | 75 | filegroup( 76 | name = "llvm_cvtres", 77 | srcs = [ 78 | "bin/llvm-cvtres.exe", 79 | ], 80 | visibility = ["//visibility:public"], 81 | ) 82 | 83 | filegroup( 84 | name = "compiler_specific_headers", 85 | srcs = glob( 86 | ["lib/clang/*/include/**/*.h"], 87 | ), 88 | visibility = ["//visibility:public"], 89 | ) 90 | 91 | filegroup( 92 | name = "all_toolchain_components", 93 | srcs = [ 94 | ":clang_cl", 95 | ":lld_link", 96 | ":llvm_lib", 97 | ], 98 | ) 99 | 100 | filegroup( 101 | name = "dsymutil", 102 | srcs = ["bin/dsymutil.exe"], 103 | visibility = ["//visibility:public"], 104 | ) 105 | -------------------------------------------------------------------------------- /thirdparty/gtest/gtest.BUILD: -------------------------------------------------------------------------------- 1 | load("@rules_cc//cc:defs.bzl", "cc_library") 2 | 3 | cc_library( 4 | name = "gtest", 5 | srcs = [ 6 | "src/gtest-all.cc", 7 | "src/gtest-internal-inl.h", 8 | ], 9 | hdrs = glob(["include/gtest/**/*.h"]), 10 | copts = [ 11 | "-Wno-zero-as-null-pointer-constant", 12 | "-Wno-missing-declarations", 13 | "-Wno-undef", 14 | "-Wno-unused-member-function", 15 | "-Wno-suggest-override", 16 | "-Wno-shift-sign-overflow", 17 | ], 18 | includes = ["include"], 19 | # disables building gtest as a shared library 20 | # in case you want to build it as a shared library you have to additionally set the following define: GTEST_CREATE_SHARED_LIBRARY 21 | linkstatic = True, 22 | textual_hdrs = [ 23 | "src/gtest-assertion-result.cc", 24 | "src/gtest-death-test.cc", 25 | "src/gtest-filepath.cc", 26 | "src/gtest-matchers.cc", 27 | "src/gtest-port.cc", 28 | "src/gtest-printers.cc", 29 | "src/gtest-test-part.cc", 30 | "src/gtest-typed-test.cc", 31 | "src/gtest.cc", 32 | ], 33 | visibility = ["//visibility:public"], 34 | deps = [ 35 | "@//thirdparty/posix_system_library:math_library", 36 | ], 37 | ) 38 | 39 | cc_library( 40 | name = "gtest_main", 41 | srcs = [ 42 | "src/gtest_main.cc", 43 | ], 44 | visibility = ["//visibility:public"], 45 | deps = ["gtest"], 46 | ) -------------------------------------------------------------------------------- /thirdparty/macos_cmdtools/BUILD.bazel: -------------------------------------------------------------------------------- 1 | filegroup( 2 | name = "all_files", 3 | srcs = glob(["**/*"]), 4 | visibility = ["//visibility:public"], 5 | ) 6 | 7 | filegroup( 8 | name = "libraries", 9 | srcs = glob(["usr/lib/**/*.dylib"]), 10 | visibility = ["//visibility:public"], 11 | ) 12 | 13 | filegroup( 14 | name = "ld", 15 | srcs = ["usr/bin/ld"], 16 | visibility = ["//visibility:public"], 17 | ) 18 | 19 | filegroup( 20 | name = "strip", 21 | srcs = ["usr/bin/strip"], 22 | visibility = ["//visibility:public"], 23 | ) 24 | 25 | filegroup( 26 | name = "install_name_tool", 27 | srcs = ["usr/bin/install_name_tool"], 28 | visibility = ["//visibility:public"], 29 | ) 30 | 31 | # We need a separate filegroup for the 32 | # binary such that it can be reused 33 | # in rule attributes that are restricted 34 | # to a single file 35 | filegroup( 36 | name = "dsymutil_binary", 37 | srcs = ["usr/bin/dsymutil"], 38 | visibility = ["//visibility:public"], 39 | ) 40 | 41 | filegroup( 42 | name = "dsymutil_additional_libraries", 43 | srcs = [":libraries"], 44 | visibility = ["//visibility:public"], 45 | ) 46 | 47 | # We need a separate filegroup for the 48 | # binary such that it can be reused 49 | # in rule attributes that are restricted 50 | # to a single file 51 | filegroup( 52 | name = "otool", 53 | srcs = ["usr/bin/llvm-otool"], 54 | data = [ 55 | "usr/bin/llvm-objdump", 56 | ":libraries", 57 | ], 58 | visibility = ["//visibility:public"], 59 | ) 60 | -------------------------------------------------------------------------------- /thirdparty/macos_cmdtools/WORKSPACE: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/salesforce-misc/bazel-cpp-toolchain/0b969b47abd885828ece8006c62e5d7eaa006467/thirdparty/macos_cmdtools/WORKSPACE -------------------------------------------------------------------------------- /thirdparty/macos_cmdtools/extract.sh: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | 3 | set +e 4 | 5 | # Expects "Command Line Tools.pkg" to be present in this folder 6 | # Doesn't delete original package after extraction 7 | 8 | # Create temp dirs 9 | mkdir tmp out 10 | 11 | # Exract 12 | xar -xf "Command Line Tools.pkg" -C ./tmp 13 | for file in ./tmp/*.pkg; do 14 | pbzx -n "$file/Payload" | (cd ./out && cpio -i) 15 | done 16 | mv out/Library/Developer/CommandLineTools/usr . 17 | 18 | # Cleanup 19 | rm -rf tmp out 20 | -------------------------------------------------------------------------------- /thirdparty/macos_sdk/WORKSPACE: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/salesforce-misc/bazel-cpp-toolchain/0b969b47abd885828ece8006c62e5d7eaa006467/thirdparty/macos_sdk/WORKSPACE -------------------------------------------------------------------------------- /thirdparty/macos_sdk/download_and_extract.sh: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | 3 | set +e 4 | 5 | # Download 6 | wget https://github.com/alexey-lysiuk/macos-sdk/releases/download/13.3/MacOSX13.3.tar.xz 7 | 8 | # Extract 9 | tar -xvf MacOSX13.3.tar.xz 10 | mv MacOSX13.3.sdk/* . 11 | 12 | # Remove ruby folder because a cyclic symlink confuses Bazel 13 | rm -rf System/Library/Frameworks/Ruby.framework/Versions/2.6/Headers/ruby/ruby 14 | 15 | # Cleanup 16 | rm -rf MacOSX13.3.sdk 17 | rm MacOSX13.3.tar.xz 18 | -------------------------------------------------------------------------------- /thirdparty/msvc/BUILD.bazel: -------------------------------------------------------------------------------- 1 | filegroup( 2 | name = "all_files", 3 | srcs = glob(["**/*"]), 4 | visibility = ["//visibility:public"], 5 | ) 6 | 7 | # The code that initializes the CRT is in one of several libraries, 8 | # based on whether the CRT library is statically or dynamically linked, 9 | # or native, managed, or mixed code. 10 | # This code handles CRT startup, internal per-thread data initialization, 11 | # and termination. It is specific to the version of the compiler used. 12 | # This library is always statically linked, even when using a dynamically linked UCRT. 13 | # Below are the libraries that implement CRT initialization and termination. 14 | 15 | filegroup( 16 | name = "dynamic_no_debug_runtime_library_import_library", 17 | srcs = ["lib/x64/msvcrt.lib"], 18 | visibility = ["//visibility:public"], 19 | ) 20 | 21 | filegroup( 22 | name = "dynamic_debug_runtime_library_import_library", 23 | srcs = ["lib/x64/msvcrtd.lib"], 24 | visibility = ["//visibility:public"], 25 | ) 26 | 27 | filegroup( 28 | name = "static_no_debug_runtime_library", 29 | srcs = ["lib/x64/libcmt.lib"], 30 | visibility = ["//visibility:public"], 31 | ) 32 | 33 | filegroup( 34 | name = "static_debug_runtime_library", 35 | srcs = ["lib/x64/libcmtd.lib"], 36 | visibility = ["//visibility:public"], 37 | ) 38 | 39 | # Concurrency Runtime, shipped via Visual Studio. Required for parallel containers and algorithms such as 40 | # concurrency::parallel_for. Also, the STL requires this DLL on Windows XP to power synchronization primitives, 41 | # because Windows XP does not have condition variables. 42 | ################################ Concurrent Library ############################ 43 | 44 | filegroup( 45 | name = "dynamic_no_debug_concurrent_import_library", 46 | srcs = ["lib/x64/concrt.lib"], 47 | visibility = ["//visibility:public"], 48 | ) 49 | 50 | filegroup( 51 | name = "dynamic_debug_concurrent_import_library", 52 | srcs = ["lib/x64/concrtd.lib"], 53 | visibility = ["//visibility:public"], 54 | ) 55 | 56 | filegroup( 57 | name = "static_no_debug_concurrent_library", 58 | srcs = ["lib/x64/libconcrt.lib"], 59 | visibility = ["//visibility:public"], 60 | ) 61 | 62 | filegroup( 63 | name = "static_debug_concurrent_library", 64 | srcs = ["lib/x64/libconcrtd.lib"], 65 | visibility = ["//visibility:public"], 66 | ) 67 | 68 | # The vcruntime library contains Visual C++ CRT implementation-specific code, 69 | # such as exception handling and debugging support, runtime checks and type information, 70 | # implementation details and certain extended library functions. 71 | # The vcruntime library is specific to the version of the compiler used. 72 | 73 | # Static vcruntime library 74 | # It corresponds to the /Mt compiler flag 75 | filegroup( 76 | name = "static_no_debug_vcruntime_library", 77 | srcs = ["lib/x64/libvcruntime.lib"], 78 | visibility = ["//visibility:public"], 79 | ) 80 | 81 | # Static debug vcruntime library 82 | # It corresponds to the /Mtd compiler flag 83 | filegroup( 84 | name = "static_debug_vcruntime_library", 85 | srcs = ["lib/x64/libvcruntimed.lib"], 86 | visibility = ["//visibility:public"], 87 | ) 88 | 89 | # DLL import library for the dynamic vcruntime library 90 | # It corresponds to the /MD compiler flag 91 | filegroup( 92 | name = "no_debug_vcruntime_import_library", 93 | srcs = ["lib/x64/vcruntime.lib"], 94 | visibility = ["//visibility:public"], 95 | ) 96 | 97 | # DLL import library for the debug dynamic vcruntime library 98 | # It corresponds to the /MDd compiler flag 99 | filegroup( 100 | name = "debug_vcruntime_import_library", 101 | srcs = ["lib/x64/vcruntimed.lib"], 102 | visibility = ["//visibility:public"], 103 | ) 104 | 105 | filegroup( 106 | name = "msvc_headers", 107 | srcs = glob(["include/**/*"]), 108 | visibility = ["//visibility:public"], 109 | ) 110 | 111 | # C++ Standard Library 112 | # When you build a release version of your project, one of the basic C run-time libraries 113 | # (libcmt.lib, msvcmrt.lib, msvcrt.lib) is linked by default, depending on the compiler option you choose 114 | # (multithreaded, DLL, /clr). 115 | # If you include one of the C++ Standard Library header files in your code, a C++ Standard Library will 116 | # be linked in automatically by Visual C++ at compile time. 117 | 118 | filegroup( 119 | name = "no_debug_static_cpp_standard_library", 120 | srcs = ["lib/x64/libcpmt.lib"], 121 | visibility = ["//visibility:public"], 122 | ) 123 | 124 | filegroup( 125 | name = "debug_static_cpp_standard_library", 126 | # The 1 is important as it corresponds to iterator debug level 1 127 | # Explicitly selecting the specific libcpmtd will become obsolete 128 | # as soon as we let the compiler frontend decide on the required library 129 | srcs = ["lib/x64/libcpmtd1.lib"], 130 | visibility = ["//visibility:public"], 131 | ) 132 | 133 | filegroup( 134 | name = "no_debug_dynamic_cpp_standard_library_import_library", 135 | srcs = ["lib/x64/msvcprt.lib"], 136 | visibility = ["//visibility:public"], 137 | ) 138 | 139 | filegroup( 140 | name = "debug_dynamic_cpp_standard_library_import_library", 141 | srcs = ["lib/x64/msvcprtd.lib"], 142 | visibility = ["//visibility:public"], 143 | ) 144 | 145 | ################################################################################################# 146 | 147 | # For compatibility between product versions, the library OLDNAMES.LIB maps old names to new names. 148 | # For instance, open maps to _open. You must explicitly link with OLDNAMES.LIB only when you compile 149 | # with the following combinations of command-line options: /link (linker-control), /NOD (no default-library search), and /Ze 150 | 151 | filegroup( 152 | name = "oldnames_lib", 153 | srcs = ["lib/x64/oldnames.lib"], 154 | visibility = ["//visibility:public"], 155 | ) 156 | 157 | cc_import( 158 | name = "atl-imported-static-library", 159 | static_library = "atlmfc/lib/x64/atls.lib", 160 | ) 161 | -------------------------------------------------------------------------------- /thirdparty/posix_system_library/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("//thirdparty/posix_system_library:posix_library_wrapper.bzl", "posix_library_wrapper") 2 | 3 | posix_library_wrapper( 4 | name = "math_library", 5 | link_flag = "-lm", 6 | ) 7 | 8 | posix_library_wrapper( 9 | name = "pthread_library", 10 | link_flag = "-pthread", 11 | ) 12 | 13 | posix_library_wrapper( 14 | name = "dynamic_loader", 15 | link_flag = "-ldl", 16 | ) 17 | -------------------------------------------------------------------------------- /thirdparty/posix_system_library/posix_library_wrapper.bzl: -------------------------------------------------------------------------------- 1 | load("@rules_cc//cc:defs.bzl", "cc_library") 2 | load("//toolchain/helper:condition_helpers.bzl", "list_not_for") 3 | 4 | def posix_library_wrapper(name, link_flag): 5 | cc_library( 6 | name = name, 7 | linkopts = list_not_for( 8 | ["//toolchain/platforms:is_windows"], 9 | [link_flag], 10 | ), 11 | visibility = ["//visibility:public"], 12 | ) 13 | -------------------------------------------------------------------------------- /thirdparty/windows_sdk/BUILD.bazel: -------------------------------------------------------------------------------- 1 | filegroup( 2 | name = "all_files", 3 | srcs = glob(["**/*"]), 4 | visibility = ["//visibility:public"], 5 | ) 6 | 7 | # The Universal CRT (UCRT) contains the functions and globals exported by 8 | # the standard C99 C Run-time Library (CRT) library 9 | 10 | # Static universal c runtime. 11 | # It corresponds to the /MT compiler flag 12 | filegroup( 13 | name = "no_debug_static_ucrt", 14 | srcs = ["Lib/ucrt/x64/libucrt.lib"], 15 | visibility = ["//visibility:public"], 16 | ) 17 | 18 | # Debug version of the static universal c runtime. 19 | # It corresponds to the /MTd compiler flag 20 | filegroup( 21 | name = "debug_static_ucrt", 22 | srcs = ["Lib/ucrt/x64/libucrtd.lib"], 23 | visibility = ["//visibility:public"], 24 | ) 25 | 26 | filegroup( 27 | name = "windows_sdk_shared_headers", 28 | srcs = glob(["Include/shared/**/*"]), 29 | visibility = ["//visibility:public"], 30 | ) 31 | 32 | filegroup( 33 | name = "windows_sdk_ucrt_headers", 34 | srcs = glob(["Include/ucrt/**/*"]), 35 | visibility = ["//visibility:public"], 36 | ) 37 | 38 | filegroup( 39 | name = "windows_sdk_um_headers", 40 | srcs = glob(["Include/um/**/*"]), 41 | visibility = ["//visibility:public"], 42 | ) 43 | 44 | filegroup( 45 | name = "windows_sdk_winrt_headers", 46 | srcs = glob(["Include/winrt/**/*"]), 47 | visibility = ["//visibility:public"], 48 | ) 49 | 50 | cc_import( 51 | name = "Ws2_32", 52 | # The file is actually WS2_32.LIB however bazel does not recognize the file ending .LIB but only .lib 53 | interface_library = "Lib/um/x64/WS2_32.lib", 54 | system_provided = True, 55 | visibility = ["//visibility:public"], 56 | ) 57 | 58 | cc_import( 59 | name = "WSock32", 60 | # The file is actually WSock32.Lib however bazel does not recognize the file ending .Lib but only .lib 61 | interface_library = "Lib/um/x64/WSock32.lib", 62 | system_provided = True, 63 | visibility = ["//visibility:public"], 64 | ) 65 | 66 | cc_import( 67 | name = "PowrProf", 68 | interface_library = "Lib/um/x64/PowrProf.lib", 69 | system_provided = True, 70 | visibility = ["//visibility:public"], 71 | ) 72 | 73 | cc_import( 74 | name = "DbgHelp", 75 | interface_library = "Lib/um/x64/DbgHelp.lib", 76 | system_provided = True, 77 | visibility = ["//visibility:public"], 78 | ) 79 | 80 | cc_import( 81 | name = "Iphlp", 82 | interface_library = "Lib/um/x64/Iphlpapi.lib", 83 | system_provided = True, 84 | visibility = ["//visibility:public"], 85 | ) 86 | 87 | cc_import( 88 | name = "Crypt", 89 | interface_library = "Lib/um/x64/Crypt32.lib", 90 | system_provided = True, 91 | visibility = ["//visibility:public"], 92 | ) 93 | 94 | cc_import( 95 | name = "BCrypt", 96 | interface_library = "Lib/um/x64/bcrypt.lib", 97 | system_provided = True, 98 | visibility = ["//visibility:public"], 99 | ) 100 | 101 | cc_import( 102 | name = "Shlwapi", 103 | interface_library = "Lib/um/x64/Shlwapi.lib", 104 | system_provided = True, 105 | visibility = ["//visibility:public"], 106 | ) 107 | 108 | cc_import( 109 | name = "Winmm", 110 | interface_library = "Lib/um/x64/Winmm.lib", 111 | system_provided = True, 112 | visibility = ["//visibility:public"], 113 | ) 114 | 115 | cc_import( 116 | name = "Version", 117 | interface_library = "Lib/um/x64/Version.lib", 118 | system_provided = True, 119 | visibility = ["//visibility:public"], 120 | ) 121 | 122 | cc_import( 123 | name = "Pdh", 124 | interface_library = "Lib/um/x64/Pdh.lib", 125 | system_provided = True, 126 | visibility = ["//visibility:public"], 127 | ) 128 | 129 | cc_library( 130 | name = "windows_api", 131 | visibility = ["//visibility:public"], 132 | deps = [ 133 | ":advapi32_interface_library", 134 | ":gdi32_interface_library", 135 | ":kernel32_interface_library", 136 | ":ole32_interface_library", 137 | ":runtimeobject_library", 138 | ":secur32_interface_library", 139 | ":shell32_interface_library", 140 | ":user32_interface_library", 141 | ], 142 | ) 143 | 144 | cc_import( 145 | name = "kernel32_interface_library", 146 | # The file is actually kernel32.Lib however bazel does not recognize the file ending .LIB but only .lib 147 | interface_library = "Lib/um/x64/kernel32.lib", 148 | system_provided = True, 149 | ) 150 | 151 | cc_import( 152 | name = "advapi32_interface_library", 153 | # The file is actually advapi32.Lib however bazel does not recognize the file ending .LIB but only .lib 154 | interface_library = "Lib/um/x64/advapi32.lib", 155 | system_provided = True, 156 | visibility = ["//visibility:public"], 157 | ) 158 | 159 | cc_import( 160 | name = "user32_interface_library", 161 | interface_library = "Lib/um/x64/user32.lib", 162 | system_provided = True, 163 | ) 164 | 165 | cc_import( 166 | name = "gdi32_interface_library", 167 | interface_library = "Lib/um/x64/gdi32.lib", 168 | system_provided = True, 169 | ) 170 | 171 | cc_import( 172 | name = "ole32_interface_library", 173 | interface_library = "Lib/um/x64/ole32.lib", 174 | system_provided = True, 175 | ) 176 | 177 | cc_import( 178 | name = "shell32_interface_library", 179 | interface_library = "Lib/um/x64/Shell32.lib", 180 | system_provided = True, 181 | visibility = ["//visibility:public"], 182 | ) 183 | 184 | cc_import( 185 | name = "secur32_interface_library", 186 | interface_library = "Lib/um/x64/Secur32.lib", 187 | system_provided = True, 188 | ) 189 | 190 | cc_import( 191 | name = "runtimeobject_library", 192 | interface_library = "Lib/um/x64/runtimeobject.lib", 193 | system_provided = True, 194 | ) 195 | -------------------------------------------------------------------------------- /toolchain/clang/clang_hyper_features.bzl: -------------------------------------------------------------------------------- 1 | load( 2 | "@bazel_tools//tools/cpp:cc_toolchain_config_lib.bzl", 3 | "feature", 4 | "flag_group", 5 | "flag_set", 6 | "with_feature_set", 7 | ) 8 | load( 9 | "//toolchain:clang/clang_toolchain_actions.bzl", 10 | "all_compile_actions", 11 | ) 12 | load( 13 | "//toolchain/helper:platform_helpers.bzl", 14 | "PLATFORM_WINDOWS", 15 | ) 16 | 17 | def create_hyper_features(platform): 18 | features = [ 19 | _create_hyper_warning_flags_feature(platform), 20 | _create_hyper_cxx20_compat(), 21 | _create_hyper_platform_defines(platform), 22 | ] 23 | return features 24 | 25 | def _create_hyper_warning_flags_feature(platform): 26 | flag_sets = [ 27 | flag_set( 28 | actions = all_compile_actions, 29 | flag_groups = [ 30 | flag_group( 31 | flags = [ 32 | "-Wc++11-narrowing", 33 | "-Wcast-qual", 34 | "-Wdelete-non-virtual-dtor", 35 | "-Wdocumentation", 36 | "-Wenum-compare", 37 | "-Wextra-semi", 38 | "-Wformat", 39 | "-Wformat-security", 40 | "-Wimplicit-fallthrough", 41 | "-Wmissing-declarations", 42 | "-Wmissing-include-dirs", 43 | "-Wnon-virtual-dtor", 44 | "-Wold-style-cast", 45 | "-Woverloaded-virtual", 46 | "-Wpointer-arith", 47 | "-Wself-assign", 48 | "-Wshadow", 49 | "-Wshift-sign-overflow", 50 | "-Wsuggest-override", 51 | "-Wuninitialized", 52 | "-Wunreachable-code", 53 | "-Wunreachable-code-aggressive", 54 | "-Wunreachable-code-return", 55 | "-Wunused", 56 | "-Wunused-const-variable", 57 | "-Wunused-exception-parameter", 58 | "-Wunused-function", 59 | "-Wfloat-conversion", 60 | # Disabled warnings 61 | "-Wno-unqualified-std-cast-call", # In Hyper, we rather freely use `using namespace std;`. We don't want to be warned about it. 62 | # Enable additional [[nodiscard]] annotations in the standard library 63 | "-D_LIBCPP_ENABLE_NODISCARD", 64 | # Remove non-standardized transitive includes from the standard library 65 | "-D_LIBCPP_REMOVE_TRANSITIVE_INCLUDES", 66 | ], 67 | ), 68 | ], 69 | ), 70 | ] 71 | 72 | if platform == PLATFORM_WINDOWS: 73 | flag_sets.append(flag_set( 74 | actions = all_compile_actions, 75 | flag_groups = [ 76 | flag_group( 77 | flags = ["/W4"], 78 | ), 79 | ], 80 | )) 81 | else: 82 | flag_sets.append(flag_set( 83 | actions = all_compile_actions, 84 | flag_groups = [ 85 | flag_group( 86 | flags = [ 87 | # -Wextra and -Wall are not required on Windows 88 | "-Wextra", 89 | "-Wall", 90 | # Enable thread safety analysis when not on Windows 91 | "-Wthread-safety", 92 | # Enable thread safety annotations for std::mutex and std::lock_guard. Our Windows toolchain lacks these annotations 93 | "-D_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS", 94 | ], 95 | ), 96 | ], 97 | )) 98 | 99 | return feature( 100 | name = "hyper_warning_flags", 101 | enabled = False, 102 | flag_sets = flag_sets, 103 | ) 104 | 105 | def _create_hyper_cxx20_compat(): 106 | """ We need these flags to ensure our code keeps working with C++23 107 | """ 108 | return feature( 109 | name = "hyper_cxx20_compat", 110 | flag_sets = [ 111 | flag_set( 112 | actions = all_compile_actions, 113 | flag_groups = [ 114 | flag_group( 115 | flags = [ 116 | "-D_SILENCE_CXX20_OLD_SHARED_PTR_ATOMIC_SUPPORT_DEPRECATION_WARNING", 117 | "-D_SILENCE_CXX20_U8PATH_DEPRECATION_WARNING", 118 | ], 119 | ), 120 | ], 121 | # C++23 is the default, thus we always apply the defines if no other c++ mode is set 122 | with_features = [with_feature_set(not_features = ["c++11", "c++14"])], 123 | ), 124 | ], 125 | ) 126 | 127 | def _create_hyper_platform_defines(platform): 128 | if platform == PLATFORM_WINDOWS: 129 | return feature( 130 | name = "hyper_platform_defines", 131 | enabled = True, 132 | flag_sets = [ 133 | flag_set( 134 | actions = all_compile_actions, 135 | flag_groups = [ 136 | flag_group( 137 | flags = [ 138 | # Exclude less common Windows API declarations (such as Cryptography, DDE, RPC, Shell, and Windows Sockets) from by default. 139 | "-DWIN32_LEAN_AND_MEAN", 140 | # Prevent from defining min/max macros. 141 | "-DNOMINMAX", 142 | # Enable Unicode support in the Windows API and the CRT. 143 | # Use the Unicode versions of the Windows API declarations instead of the Windows code page versions. 144 | # See [Conventions for Function Prototypes](https://msdn.microsoft.com/en-us/library/windows/desktop/dd317766(v=vs.85).aspx). 145 | "-DUNICODE", 146 | "-D_UNICODE", 147 | ], 148 | ), 149 | ], 150 | ), 151 | ], 152 | ) 153 | else: 154 | return feature(name = "hyper_platform_defines") 155 | -------------------------------------------------------------------------------- /toolchain/clang/clang_toolchain_actions.bzl: -------------------------------------------------------------------------------- 1 | load("@bazel_tools//tools/build_defs/cc:action_names.bzl", "ACTION_NAMES") 2 | 3 | # Commented out actions are currently not used by us and therefore 4 | # not supported. 5 | # 6 | # CLIF is a google tool for creating C++ wrappers, but not all language 7 | # generators are publicly available. The action clif_match extracts the language 8 | # agnostic model for a given C++ header. We don't need this, so all occurencies 9 | # of ACTIONS_NAMES.clif_match in this file have been removed. 10 | # 11 | # Toolchain doesn't contain objective C support, objc* actions have been removed. 12 | # 13 | # This toolchain currently does not have support for c++ modules. 14 | # This implies that the toolchain does not have support for the following actions: 15 | # cpp_header_parsing, cpp_module_compile and cpp_module_codegen 16 | # 17 | # Currently this toolchain does not have support for linkstamp_compile. 18 | # For details please see: https://github.com/bazelbuild/bazel/issues/6997 19 | # 20 | # We also deliberately omitted the objcopy_embed_data action and the accompanying feature, 21 | # as the objcopy_embed_data action is not even contained in the ACTION_NAMES struct. 22 | 23 | compile_actions_without_assemble = [ 24 | ACTION_NAMES.c_compile, 25 | ACTION_NAMES.cpp_compile, 26 | ACTION_NAMES.preprocess_assemble, 27 | #ACTION_NAMES.linkstamp_compile, 28 | #ACTION_NAMES.cpp_header_parsing, 29 | #ACTION_NAMES.cpp_module_compile, 30 | #ACTION_NAMES.cpp_module_codegen, 31 | #ACTION_NAMES.lto_backend, 32 | ] 33 | 34 | all_compile_actions = compile_actions_without_assemble + [ACTION_NAMES.assemble] 35 | 36 | all_cpp_compile_actions = [ 37 | ACTION_NAMES.cpp_compile, 38 | #ACTION_NAMES.linkstamp_compile, 39 | #ACTION_NAMES.cpp_header_parsing, 40 | #ACTION_NAMES.cpp_module_compile, 41 | #ACTION_NAMES.cpp_module_codegen, 42 | ] 43 | 44 | preprocessor_compile_actions = [ 45 | ACTION_NAMES.c_compile, 46 | ACTION_NAMES.cpp_compile, 47 | ACTION_NAMES.preprocess_assemble, 48 | #ACTION_NAMES.linkstamp_compile, 49 | #ACTION_NAMES.cpp_header_parsing, 50 | #ACTION_NAMES.cpp_module_compile, 51 | ] 52 | 53 | codegen_compile_actions = [ 54 | ACTION_NAMES.c_compile, 55 | ACTION_NAMES.cpp_compile, 56 | ACTION_NAMES.assemble, 57 | ACTION_NAMES.preprocess_assemble, 58 | #ACTION_NAMES.linkstamp_compile, 59 | #ACTION_NAMES.cpp_module_codegen, 60 | #ACTION_NAMES.lto_backend, 61 | ] 62 | 63 | all_link_actions = [ 64 | ACTION_NAMES.cpp_link_executable, 65 | ACTION_NAMES.cpp_link_dynamic_library, 66 | ACTION_NAMES.cpp_link_nodeps_dynamic_library, 67 | ] 68 | 69 | # We keep the LTO actions list, even if we don't support LTO right now, 70 | # to preserve the information in which features it is needed. 71 | lto_index_actions = [ 72 | # ACTION_NAMES.lto_index_for_dynamic_library, 73 | # ACTION_NAMES.lto_index_for_nodeps_dynamic_library, 74 | # ACTION_NAMES.lto_index_for_executable, 75 | ] 76 | -------------------------------------------------------------------------------- /toolchain/clang/darwin/clang_darwin_toolchain_config.bzl: -------------------------------------------------------------------------------- 1 | # =========================================================================== 2 | # Clang Linux Toolchain 3 | # =========================================================================== 4 | 5 | #inspired by https://github.com/grailbio/bazel-toolchain 6 | 7 | load("//toolchain:clang/clang_hyper_features.bzl", "create_hyper_features") 8 | load( 9 | "//toolchain:clang/clang_posix_toolchain_config_base.bzl", 10 | "create_compile_flags_for_include_paths", 11 | "create_posix_action_configs", 12 | "create_posix_default_features", 13 | "create_toolchain_cxx_builtin_include_directories", 14 | ) 15 | load("//toolchain/helper:context_helpers.bzl", "file_attribute_to_toolpath") 16 | load("//toolchain/helper:file_helpers.bzl", "get_common_root_dir") 17 | load("//toolchain/helper:platform_helpers.bzl", "PLATFORM_MACOS") 18 | 19 | # --------------------------------------------------------------------------- 20 | # Toolchain implementation 21 | # --------------------------------------------------------------------------- 22 | 23 | include_paths = [ 24 | "external/clang_darwin/include/c++/v1", 25 | "external/clang_darwin/include", 26 | "%{sysroot}/System/Library/Frameworks", 27 | ] 28 | 29 | # clang resource directory, containing non-gnu headers and clang-specific libraries (part of the clang package) 30 | clang_resource_directory = "external/clang_darwin/lib/clang/18" 31 | 32 | def create_platform_specific_link_flags(macosx_version_min, sdk_version): 33 | return [ 34 | "-headerpad_max_install_names", 35 | # Set the macOS deployment target to meet the specified official minimum requirements. 36 | "-Wl,-platform_version,macos,{macosx_version_min},{sdk_version},".format(macosx_version_min = macosx_version_min, sdk_version = sdk_version), 37 | # Sets the oso_prefix to the current working directory. 38 | # By setting the oso_prefix all paths in the final binary's OSO stabs are relatizived according to the provided directory. 39 | # If we do not relativize these OSO stabs the point to archive and object files in the current sandbox that won't 40 | # exist after the current compiler invocation. 41 | # Relativizing these paths allows us to use the dsymutil tool in a new sandbox containing the same libraries 42 | # and object files used to initially link the binary to generate the actual .dSYM file containing 43 | # the debug symbols of the resulting binary. 44 | # 45 | # The "%%pwd%%" itself is resolved by the cc-wrapper.sh script 46 | # with the current working directory as "." is not recognized 47 | # by the mac os ld linker. 48 | # The %% is used 49 | "-Wl,-oso_prefix,%%pwd%%/", 50 | ] 51 | 52 | def create_platform_specific_compile_flags(macosx_version_min): 53 | return [ 54 | "-mmacosx-version-min=" + macosx_version_min, 55 | # %%pwd%% is expanded by the cc-wrapper.sh to the current working directory 56 | # This has two benefits. First, the path is locally reproducible (the command is the same on all machines). 57 | # Second the path is globally reproducible (the absolute path is stripped from the output). 58 | # Globally means that the same paths are embedded regardless of the machine and sandbox the build was executed on. 59 | # Locally means that no absolute paths are part of the command line. E.g. if we would directly use the absolute path 60 | # to the working directory the commandline would be different for each checkout directory and caching would be impossible 61 | "-ffile-prefix-map=%%pwd%%=.", 62 | ] + create_compile_flags_for_include_paths(include_paths) 63 | 64 | def _impl(ctx): 65 | clang_wrapper_path = "clang/darwin/wrapper-scripts/cc-wrapper.sh" 66 | darwin_toolchain_files = ctx.attr.sysroot.files.to_list() 67 | 68 | return cc_common.create_cc_toolchain_config_info( 69 | features = create_posix_default_features( 70 | default_defines = ctx.file._default_defines, 71 | ld = ctx.file.ld, 72 | sysroot_enabled = True, 73 | shared_flag = "-dynamiclib", 74 | supports_start_end_lib = False, 75 | dynamic_lookup_for_undefined_symbols = True, 76 | supported_instruction_set_extensions = ctx.attr.supported_instruction_set_extensions, 77 | default_instruction_set_extensions = ctx.attr.default_instruction_set_extensions, 78 | runtime_library_search_directories_base = "@loader_path", 79 | clang_resource_directory = clang_resource_directory, 80 | target_architecture_triple = ctx.attr.target_architecture_triple, 81 | target_base_cpu = ctx.attr.target_base_cpu, 82 | platform_specific_compile_flags = create_platform_specific_compile_flags(ctx.attr.macosx_version_min), 83 | platform_specific_link_flags = create_platform_specific_link_flags(ctx.attr.macosx_version_min, ctx.attr.sdk_version), 84 | platform_specifc_link_flags_for_position_independent_executables = ["-Wl,-pie"], 85 | whole_archive_linker_flag = "-force_load", 86 | no_whole_archive_linker_flag = None, 87 | solib_name_flag = "-Wl,-install_name,@rpath/", 88 | additional_features = create_hyper_features(PLATFORM_MACOS), 89 | ), 90 | action_configs = create_posix_action_configs( 91 | ar_path = file_attribute_to_toolpath(ctx, ctx.file.ar), 92 | clang_path = clang_wrapper_path, 93 | strip_path = file_attribute_to_toolpath(ctx, ctx.file.strip), 94 | ), 95 | ctx = ctx, 96 | toolchain_identifier = "clang-darwin", 97 | host_system_name = "unused", 98 | target_system_name = ctx.attr.target_architecture_triple, 99 | target_cpu = "darwin", 100 | target_libc = "macosx", 101 | compiler = "clang", 102 | abi_version = "darwin_x86_64", 103 | abi_libc_version = "darwin_x86_64", 104 | cxx_builtin_include_directories = create_toolchain_cxx_builtin_include_directories(include_paths) + 105 | [clang_resource_directory + "/include"], 106 | builtin_sysroot = get_common_root_dir(darwin_toolchain_files) if darwin_toolchain_files else None, 107 | ) 108 | 109 | # --------------------------------------------------------------------------- 110 | # Toolchain rule declaration 111 | # --------------------------------------------------------------------------- 112 | 113 | darwin_toolchain_config = rule( 114 | implementation = _impl, 115 | provides = [CcToolchainConfigInfo], 116 | attrs = { 117 | "_default_defines": attr.label( 118 | allow_single_file = True, 119 | default = "//toolchain:clang/hermetic_default_defines.h", 120 | ), 121 | "ar": attr.label( 122 | mandatory = True, 123 | allow_single_file = True, 124 | ), 125 | "clang": attr.label( 126 | mandatory = True, 127 | allow_single_file = True, 128 | ), 129 | "ld": attr.label( 130 | mandatory = True, 131 | allow_single_file = True, 132 | ), 133 | "sysroot": attr.label( 134 | mandatory = True, 135 | ), 136 | "strip": attr.label( 137 | mandatory = True, 138 | allow_single_file = True, 139 | ), 140 | "macosx_version_min": attr.string( 141 | mandatory = True, 142 | ), 143 | "sdk_version": attr.string( 144 | mandatory = True, 145 | doc = """ 146 | Pass `-sdk_version` to the linker so that binaries will correctly indicate the SDK they were linked against. 147 | Note: Binaries will contain `sdk ` in the LC_VERSION_MIN_MACOSX or LC_BUILD_VERSION load commands. 148 | Note: Can't use `-platform_version ` here due to conflicts with `-mmacosx-version-min`. 149 | """, 150 | ), 151 | "target_architecture_triple": attr.string( 152 | mandatory = True, 153 | doc = """Target architecture triple (set by `--target=`), defining target architecture, vendor and OS""", 154 | ), 155 | "target_base_cpu": attr.string( 156 | # While on x86-64 this value can be derived from the target triple, that doesn't work on arm 157 | doc = """Target processor base architecture (set by `-march=`), used to disable instruction set extensions""", 158 | ), 159 | "supported_instruction_set_extensions": attr.string_list( 160 | doc = "List of supported instructions set extensions (set by `-m`)", 161 | default = [], 162 | ), 163 | "default_instruction_set_extensions": attr.string_list( 164 | doc = "List of default instructions set extensions", 165 | default = [], 166 | ), 167 | }, 168 | ) 169 | -------------------------------------------------------------------------------- /toolchain/clang/darwin/platform_constants.bzl: -------------------------------------------------------------------------------- 1 | MACOS_VERSION_MIN = "10.13" 2 | -------------------------------------------------------------------------------- /toolchain/clang/darwin/wrapper-scripts/cc-wrapper.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright 2015 The Bazel Authors. All rights reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | # Ship the environment to the C++ action 18 | # 19 | 20 | set -eu 21 | 22 | # Set-up the environment 23 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" 24 | 25 | 26 | # Call the C++ compiler. 27 | if [[ "${PATH}:" == *"external/clang_darwin/bin:"* ]]; then 28 | # GoCompile sets the PATH to the directory containing the linker, and changes CWD. 29 | clang "$@" 30 | else 31 | # Call the C++ compiler 32 | export RELATIVE_PATH=external/clang_darwin/bin/clang 33 | 34 | if test -f ${RELATIVE_PATH}; then 35 | # Replace occurrences of %pwd% in the provided arguments with the path to the current working directory. 36 | # Example use cases are the -Wl,-oso_prefix or the -fdebug-prefix-map that need to resolve absolute paths 37 | # to paths relative to the current sandbox. 38 | # Keep in mind that %%pwd%% has to be used inside the toolchain configuration as the % charachter has to be 39 | # escaped by using %%. 40 | # 41 | # Without relativizing, the absolute paths would point to files in the current sandbox. 42 | # These absolute paths would be invalid immediately after the current invocation. 43 | ${RELATIVE_PATH} "${@//%pwd%/$(pwd)}" 44 | else 45 | # if it cannot be found (e.g. in case of the external cmake rule try to resolve the binary from the current location of the script 46 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" 47 | EXECROOT=$(cd $DIR/../../../../../ && pwd) 48 | CLANG_TOOlCHAIN_DIR=$(cd $DIR/../../ && pwd) 49 | ${EXECROOT}/${RELATIVE_PATH} -I${CLANG_TOOlCHAIN_DIR} "$@" 50 | fi 51 | fi 52 | -------------------------------------------------------------------------------- /toolchain/clang/hermetic_default_defines.h: -------------------------------------------------------------------------------- 1 | #pragma clang diagnostic push 2 | #pragma clang diagnostic ignored "-Wbuiltin-macro-redefined" 3 | 4 | #undef __DATE__ 5 | #undef __TIMESTAMP__ 6 | #undef __TIME__ 7 | 8 | #define __DATE__ "redacted" 9 | #define __TIMESTAMP__ "redacted" 10 | #define __TIME__ "redacted" 11 | 12 | #pragma clang diagnostic pop 13 | -------------------------------------------------------------------------------- /toolchain/clang/linux/clang_linux_toolchain_config.bzl: -------------------------------------------------------------------------------- 1 | # =========================================================================== 2 | # Clang Linux Toolchain 3 | # =========================================================================== 4 | 5 | #inspired by https://github.com/grailbio/bazel-toolchain 6 | 7 | load( 8 | "@bazel_tools//tools/cpp:cc_toolchain_config_lib.bzl", 9 | "tool_path", 10 | ) 11 | load("//toolchain:clang/clang_hyper_features.bzl", "create_hyper_features") 12 | load( 13 | "//toolchain:clang/clang_posix_toolchain_config_base.bzl", 14 | "create_compile_flags_for_include_paths", 15 | "create_posix_action_configs", 16 | "create_posix_default_features", 17 | "create_toolchain_cxx_builtin_include_directories", 18 | ) 19 | load("//toolchain/helper:context_helpers.bzl", "file_attribute_to_toolpath") 20 | load("//toolchain/helper:file_helpers.bzl", "get_common_root_dir") 21 | load("//toolchain/helper:platform_helpers.bzl", "PLATFORM_LINUX") 22 | 23 | # --------------------------------------------------------------------------- 24 | # Toolchain implementation 25 | # --------------------------------------------------------------------------- 26 | 27 | include_paths = [ 28 | "external/clang_linux/include/x86_64-unknown-linux-gnu/c++/v1", 29 | "external/clang_linux/include/c++/v1", 30 | ] 31 | 32 | # clang resource directory, containing non-gnu headers and clang-specific libraries (part of the clang package) 33 | clang_resource_directory = "external/clang_linux/lib/clang/18" 34 | clang_builtin_includes = clang_resource_directory + "/include" 35 | 36 | platform_specific_link_flags = [ 37 | # Make build-id non-random 38 | "-Wl,--build-id=md5", 39 | 40 | # When generating an executable or shared library, mark it to tell the dynamic linker to resolve all symbols when 41 | # the program is started, or when the shared library is linked to using dlopen, instead of deferring function call 42 | # resolution to the point when the function is first called. 43 | "-Wl,-z,relro", 44 | "-Wl,-z,now", 45 | 46 | # Use `-Wl,--as-needed` to ensure that the DT_NEEDED tags in the .dynamic section reflect _exactly_ the dynamic 47 | # libraries that are actually needed. 48 | "-Wl,--as-needed", 49 | 50 | # C++ Standard Library: Use the static version of `libc++` (actual linkind happening through `static_runtime_lib` toolchain config) 51 | # To avoid surprises, we want to be very explicit here and override Clang's complex built-in behavior. 52 | # Note: The `--exclude-libs` linker arguments prevent global symbols in the specified archive libraries from being 53 | # automatically exported by the linked binaries. We generally don't want our binaries to re-export 54 | # C++ standard library symbols. 55 | "-Wl,--exclude-libs,libc++.a", 56 | "-Wl,--exclude-libs,libc++abi.a", 57 | 58 | # Unwind Library: Use the LLVM `libunwind.a` from our Clang package instead of GCC's `libgcc_eh.a` (actual linkind happening through `static_runtime_lib` toolchain config) 59 | # Note: The `--unwindlib=none` prevents Clang from automatically linking to `libunwind.so` or `libgcc_s.so`. 60 | # Note: --unwindlib is relevant only on Linux. On macOS, adding --unwindlib would cause -Wunused-command-line-argument to produce a warning. 61 | "--unwindlib=none", 62 | "-Wl,--exclude-libs,libunwind.a", 63 | ] 64 | 65 | linux_debug_prefix_map_compile_flags = [ 66 | # This maps absolute source paths (e.g. to map debugging symbols or in asserts) to the current execution root 67 | "-ffile-prefix-map=/proc/self/cwd=.", 68 | ] 69 | 70 | def _impl(ctx): 71 | default_defines_include_path = ctx.file._default_defines.path[0:-len(ctx.file._default_defines.basename)] 72 | platform_specific_compile_flags = create_compile_flags_for_include_paths(include_paths + [default_defines_include_path]) + linux_debug_prefix_map_compile_flags 73 | sysroot_files = ctx.attr.sysroot.files.to_list() 74 | 75 | # We must list all tool_paths even if most of them are unused as the tools are specified in the corresponding actions 76 | tool_paths = [ 77 | tool_path(name = "ar", path = "/bin/false"), 78 | tool_path(name = "compat-ld", path = "/bin/false"), 79 | tool_path(name = "cpp", path = "/bin/false"), 80 | tool_path(name = "dwp", path = ctx.attr.llvm_dwp), 81 | tool_path(name = "gcc", path = "/bin/false"), 82 | tool_path(name = "ld", path = "/bin/false"), 83 | tool_path(name = "nm", path = "/bin/false"), 84 | tool_path(name = "objcopy", path = "/bin/false"), 85 | tool_path(name = "objdump", path = "/bin/false"), 86 | tool_path(name = "strip", path = "/bin/false"), 87 | ] 88 | 89 | return cc_common.create_cc_toolchain_config_info( 90 | features = create_posix_default_features( 91 | default_defines = ctx.file._default_defines, 92 | ld = ctx.file.ld, 93 | sysroot_enabled = True, 94 | shared_flag = "-shared", 95 | supports_start_end_lib = True, 96 | dynamic_lookup_for_undefined_symbols = False, 97 | supported_instruction_set_extensions = ctx.attr.supported_instruction_set_extensions, 98 | default_instruction_set_extensions = ctx.attr.default_instruction_set_extensions, 99 | runtime_library_search_directories_base = "$ORIGIN", 100 | clang_resource_directory = clang_resource_directory, 101 | target_architecture_triple = ctx.attr.target_architecture_triple, 102 | target_base_cpu = ctx.attr.target_base_cpu, 103 | platform_specific_compile_flags = platform_specific_compile_flags, 104 | platform_specific_link_flags = platform_specific_link_flags, 105 | platform_specifc_link_flags_for_position_independent_executables = ["-pie"], 106 | whole_archive_linker_flag = "--whole-archive", 107 | no_whole_archive_linker_flag = "--no-whole-archive", 108 | solib_name_flag = "-Wl,-soname,", 109 | additional_features = create_hyper_features(PLATFORM_LINUX), 110 | ), 111 | action_configs = create_posix_action_configs( 112 | ar_path = file_attribute_to_toolpath(ctx, ctx.file.ar), 113 | clang_path = file_attribute_to_toolpath(ctx, ctx.file.clang), 114 | strip_path = file_attribute_to_toolpath(ctx, ctx.file.strip), 115 | ), 116 | ctx = ctx, 117 | toolchain_identifier = "clang-linux", 118 | host_system_name = "x86_64", 119 | target_system_name = "x86_64-unknown-linux-gnu", 120 | target_cpu = "k8", 121 | target_libc = "unknown", 122 | compiler = "clang", 123 | abi_version = "clang", 124 | abi_libc_version = "glibc_unknown", 125 | tool_paths = tool_paths, 126 | cxx_builtin_include_directories = create_toolchain_cxx_builtin_include_directories(include_paths) + [clang_builtin_includes, default_defines_include_path], 127 | builtin_sysroot = get_common_root_dir(sysroot_files) if sysroot_files else None, 128 | ) 129 | 130 | # --------------------------------------------------------------------------- 131 | # Toolchain rule declaration 132 | # --------------------------------------------------------------------------- 133 | 134 | linux_toolchain_config = rule( 135 | implementation = _impl, 136 | provides = [CcToolchainConfigInfo], 137 | attrs = { 138 | "_default_defines": attr.label( 139 | allow_single_file = True, 140 | default = "//toolchain:clang/hermetic_default_defines.h", 141 | ), 142 | "link_libs": attr.string_list(), 143 | "ar": attr.label( 144 | mandatory = True, 145 | allow_single_file = True, 146 | ), 147 | "clang": attr.label( 148 | mandatory = True, 149 | allow_single_file = True, 150 | ), 151 | "ld": attr.label( 152 | mandatory = True, 153 | allow_single_file = True, 154 | ), 155 | "llvm_dwp": attr.string( 156 | mandatory = True, 157 | ), 158 | "strip": attr.label( 159 | mandatory = True, 160 | allow_single_file = True, 161 | ), 162 | "target_architecture_triple": attr.string( 163 | mandatory = True, 164 | doc = """Target architecture triple (set by `--target=`), defining target architecture, vendor and OS""", 165 | ), 166 | "target_base_cpu": attr.string( 167 | # While on x86-64 this value can be derived from the target triple, that doesn't work on arm 168 | doc = """Target processor base architecture (set by `-march=`), used to disable instruction set extensions""", 169 | ), 170 | "supported_instruction_set_extensions": attr.string_list( 171 | doc = "List of supported instructions set extensions (set by `-m`)", 172 | mandatory = True, 173 | ), 174 | "default_instruction_set_extensions": attr.string_list( 175 | doc = "List of default instructions set extensions (set by `-m`)", 176 | mandatory = True, 177 | ), 178 | "sysroot": attr.label( 179 | doc = "The label to the sysroot that should be used by this toolchain.", 180 | ), 181 | }, 182 | ) 183 | -------------------------------------------------------------------------------- /toolchain/clang/linux/wrapper_llvm_dwp.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euo pipefail 3 | 4 | # The wrapper file is the recommended way to configure the tools when they are not supported by action_config yet: https://github.com/bazelbuild/bazel/issues/8438#issuecomment-594443436 5 | ./external/clang_linux/bin/llvm-dwp "$@" 6 | -------------------------------------------------------------------------------- /toolchain/clang/linux/wrapper_profdata.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euo pipefail 3 | 4 | # The wrapper file is the recommended way to configure the tools when they are not supported by action_config yet: https://github.com/bazelbuild/bazel/issues/8438#issuecomment-594443436 5 | ./external/clang_linux/bin/llvm-profdata "$@" 6 | -------------------------------------------------------------------------------- /toolchain/clang/windows/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@bazel_skylib//rules:copy_file.bzl", "copy_file") 2 | 3 | # Copy the file to the output so that the resource compiler puts the 4 | # generated resource right next to it in the output directory 5 | copy_file( 6 | name = "manifest_resource", 7 | src = ":manifest_resource.rc", 8 | out = "manifest_resource_copy.rc", 9 | ) 10 | 11 | filegroup( 12 | name = "windows_enable_pretty_printing", 13 | srcs = ["hyper.natvis"], 14 | visibility = ["//visibility:public"], 15 | ) 16 | -------------------------------------------------------------------------------- /toolchain/clang/windows/hyper.natvis: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 11 | 12 | {_Mypair._Myval2._Bx._Buf,na} 13 | {_Mypair._Myval2._Bx._Ptr,na} 14 | _Mypair._Myval2._Bx._Buf,na 15 | _Mypair._Myval2._Bx._Ptr,na 16 | 17 | size() 18 | capacity() 19 | _Mypair 20 | 21 | _Mypair._Myval2._Mysize 22 | _Mypair._Myval2._Bx._Buf 23 | _Mypair._Myval2._Bx._Ptr 24 | 25 | 26 | 27 | 28 | 29 | {{ size={_Mypair._Myval2._Mysize} }} 30 | 31 | _Mypair 32 | 33 | _Mypair._Myval2._Mysize 34 | _Mypair._Myval2._Map[(($i + _Mypair._Myval2._Myoff) / (sizeof(**_Mypair._Myval2._Map) <= 1 ? 16 : sizeof (**_Mypair._Myval2._Map) <= 2 ? 8 : sizeof (**_Mypair._Myval2._Map) <= 4 ? 4 : sizeof(**_Mypair._Myval2._Map) <= 8 ? 2 : 1)) % _Mypair._Myval2._Mapsize][($i + _Mypair._Myval2._Myoff) % (sizeof(**_Mypair._Myval2._Map) <= 1 ? 16 : sizeof (**_Mypair._Myval2._Map) <= 2 ? 8 : sizeof (**_Mypair._Myval2._Map) <= 4 ? 4 : sizeof(**_Mypair._Myval2._Map) <= 8 ? 2 : 1)] 35 | 36 | 37 | 38 | 39 | 40 | 41 | {{ size={_Mypair._Myval2._Mysize} }} 42 | 43 | _Mypair 44 | 45 | _Mypair._Myval2._Mysize 46 | _Mypair._Myval2._Myhead 47 | _Next 48 | _Myval 49 | 50 | 51 | 52 | 53 | 54 | 55 | &_Ptr->_Myval,na 56 | 57 | 58 | 59 | {*($T1 *)&_Storage._Value} 60 | 61 | 62 | -------------------------------------------------------------------------------- /toolchain/clang/windows/long_paths.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | true 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /toolchain/clang/windows/manifest_resource.rc: -------------------------------------------------------------------------------- 1 | 2 | // This is an automatically generated file 3 | //--------------------------------------------------------------------------- 4 | 1 24 "bazel/toolchain/clang/windows/long_paths.manifest" -------------------------------------------------------------------------------- /toolchain/helper/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load(":tests/condition_helpers_tests.bzl", "condition_helpers_test_suite") 2 | load(":tests/file_helpers_tests.bzl", "file_helpers_test_suite") 3 | load(":tests/function_helpers_tests.bzl", "function_helpers_test_suite") 4 | load(":tests/label_helpers_tests.bzl", "label_helpers_test_suite") 5 | load(":tests/list_helpers_tests.bzl", "list_helpers_test_suite") 6 | load(":tests/runfiles_helpers_test.bzl", "runfiles_helpers_test_suite") 7 | 8 | file_helpers_test_suite() 9 | 10 | label_helpers_test_suite() 11 | 12 | condition_helpers_test_suite() 13 | 14 | list_helpers_test_suite() 15 | 16 | runfiles_helpers_test_suite() 17 | 18 | function_helpers_test_suite() 19 | -------------------------------------------------------------------------------- /toolchain/helper/condition_helpers.bzl: -------------------------------------------------------------------------------- 1 | def list_for(conditions, list, dict_only = False): 2 | """ 3 | `list_for` is a convenience function, to simplify the creation of configurable attribute values (aka select) which for 4 | a set of conditions always assign the same value. 5 | For instance 6 | 7 | ``` 8 | list_for( 9 | ["//toolchain/platforms:is_linux", "//toolchain/platforms:is_macos"], 10 | [":my_posix_label"] 11 | ) 12 | ``` 13 | is converted into 14 | ``` 15 | select({ 16 | "//toolchain/platforms:is_linux": [":my_posix_label"] 17 | "//toolchain/platforms:is_macos": [":my_posix_label"] 18 | "//conditions:default": [] 19 | }) 20 | ``` 21 | 22 | :params conditions: the list of conditions for which the provided list should be available 23 | :params list: the list that should be available only under a certain set of conditions 24 | :params dict_only Determines if the returned conditions are wrapped in a select struct or not. 25 | Using a dictionary only becomes quite useful if you want to postprocess the condition later, because 26 | select structures are currently opaque structures and the encapsulated dictionary cannot be accessed 27 | by macros. 28 | :returns: The created condition. If dict_only is True the plain conditions as a dictionary. 29 | If dict_only is False, which is the default, the returned conditions are wrapped in a `select` struct 30 | """ 31 | mapping = {condition: list for condition in conditions} 32 | mapping["//conditions:default"] = [] 33 | return mapping if dict_only else select(mapping) 34 | 35 | def list_not_for(conditions, list, dict_only = False): 36 | """ 37 | `list_not_for` is a convenience function, that works like `list_for`, but adds a NOT to the conditions. 38 | """ 39 | mapping = {condition: [] for condition in conditions} 40 | mapping["//conditions:default"] = list 41 | return mapping if dict_only else select(mapping) 42 | -------------------------------------------------------------------------------- /toolchain/helper/context_helpers.bzl: -------------------------------------------------------------------------------- 1 | def file_attribute_to_toolpath(ctx, file_attribute): 2 | """ Generate a relative path pointing to the file from the given context. 3 | The returned path is not normalized! (There is no way to normalize paths in Starlark) 4 | """ 5 | path_to_root = "" 6 | 7 | for _ in ctx.label.package.split("/"): 8 | path_to_root = path_to_root + "../" 9 | 10 | return path_to_root + file_attribute.path 11 | -------------------------------------------------------------------------------- /toolchain/helper/file_helpers.bzl: -------------------------------------------------------------------------------- 1 | load(":platform_helpers.bzl", "is_windows") 2 | 3 | def get_common_directory_prefix(dirname1, dirname2): 4 | len1 = len(dirname1) 5 | len2 = len(dirname2) 6 | 7 | # Loop over the two strings until the first mismatching character is found (or until one string ends but the 8 | # other doesn't), maintaining `s` as the index of the last-seen common `/` separator. 9 | s = 0 10 | for i in range(0, min(len1, len2) + 1): 11 | # If the end of either string is reached, interpret the end as a trailing `/`. This way, it won't be treated as 12 | # a mismatch if one path ends with a trailing `/` but the other, otherwise identical path does not. 13 | c1 = dirname1[i] if (i < len1) else "/" 14 | c2 = dirname2[i] if (i < len2) else "/" 15 | if c1 != c2: 16 | break 17 | if c1 == "/": 18 | s = i 19 | 20 | # Shorten the path (does not matter which) to just before the last-common `/` separator. 21 | return dirname1[0:s] 22 | 23 | def get_common_root_path(paths): 24 | """ 25 | Returns the lowest common ancestor ("root path") of the given paths. 26 | 27 | Args: 28 | paths: The list of `path` objects or strings to analyze. 29 | 30 | Returns: 31 | string: The root path. 32 | """ 33 | 34 | # The root path is the result of "folding" all given paths with `get_common_directory_prefix()`. 35 | root = None 36 | for path in paths: 37 | root = path if not root else get_common_directory_prefix(path, root) 38 | return root 39 | 40 | # Note: See `detect_root.bzl` in `rules_foreign_cc` for a similar helper function. (Not worth importing, though.) 41 | def get_common_root_dir(files, path_property = "path"): 42 | """ 43 | Returns the path to the lowest common parent directory ("root dir") that contains the given files. 44 | 45 | Args: 46 | files: The list of `File` objects to analyze. 47 | 48 | Returns: 49 | string: The root dir. The path is always relative to the execution directory. 50 | """ 51 | 52 | return get_common_root_path([getattr(file, path_property) for file in files]) 53 | 54 | def stem(file): 55 | """ 56 | Given a file object, it returns its base filename with the suffix stripped. 57 | 58 | :param file: the file object to retrieve its stem from 59 | :return the stem of the file basename. This is the basename without its extension. 60 | """ 61 | return file.basename[0:-len("." + file.extension)] 62 | 63 | def to_windows_file_path(path): 64 | """ 65 | Replaces all slashses with backslashes 66 | """ 67 | return path.replace("/", "\\") 68 | 69 | def to_host_specific_path(ctx, platform_agnostic_path): 70 | """ 71 | Given a platform agnostic path that uses slashes as folder separators this function returns a path that uses the folder separator of the current host platform. 72 | 73 | Args: 74 | ctx: the current rule context 75 | platform_agnostic_path: the platform agnostic path that uses slashes as separator 76 | Returns: 77 | a path that uses the folder separator of the rule context's host platform 78 | """ 79 | return to_windows_file_path(platform_agnostic_path) if is_windows(ctx) else platform_agnostic_path 80 | 81 | def substitute_path_prefixes(path, substitutions): 82 | """ 83 | Substitute path prefixes. Perform at most one substitution. 84 | 85 | Args: 86 | path: Original path 87 | substitutions: List of tuples (`old`, `new`) so that if `parts` starts with `old`, this occurence of `old` will be replaced with `new`. 88 | Returns: 89 | Path with substitutions applied 90 | """ 91 | for old, new in substitutions: 92 | if (path.startswith(old)): 93 | return new + path[len(old):] 94 | return path 95 | -------------------------------------------------------------------------------- /toolchain/helper/foreign_build_rpath_fixer_helper.bzl: -------------------------------------------------------------------------------- 1 | def create_mac_postfix_script(mac_artifacts): 2 | postfix_script = "" 3 | install_name_tool = "/usr/bin/install_name_tool" 4 | for mac_artifact in mac_artifacts: 5 | for other_mac_artficat in mac_artifacts: 6 | if other_mac_artficat != mac_artifact: 7 | if postfix_script != "": 8 | postfix_script += " && " 9 | new_command = "%s -change %s @rpath/%s $INSTALLDIR/lib/%s" % (install_name_tool, other_mac_artficat, other_mac_artficat, mac_artifact) 10 | postfix_script += new_command 11 | return postfix_script 12 | -------------------------------------------------------------------------------- /toolchain/helper/function_helpers.bzl: -------------------------------------------------------------------------------- 1 | FunctionInfo = provider(fields = ["function_name", "starlark_file_declaring_function"], doc = "Provider of basic function information.") 2 | 3 | def function_info(function): 4 | """ 5 | Given a function `function`, we extract the information that can be extracted from its string representation 6 | and return it in a struct. 7 | 8 | :param function (macro): A Starlark function 9 | """ 10 | if function == None: 11 | fail(msg = "Provided None function parameter to function_info") 12 | 13 | # String representation of function has form: 14 | # Extract the fields we are interested in: 15 | function_keyword, function_name, from_keyword, starlark_file_declaring_function = str(function).lstrip("<").rstrip(">").split(" ") 16 | 17 | if function_keyword != "function" or from_keyword != "from": 18 | fail(msg = "The string representation of function could not be parsed, expected: format, got: " + str(function)) 19 | 20 | # Return these in a FunctionInfo 21 | return FunctionInfo( 22 | function_name = function_name, 23 | starlark_file_declaring_function = starlark_file_declaring_function, 24 | ) 25 | -------------------------------------------------------------------------------- /toolchain/helper/label_helpers.bzl: -------------------------------------------------------------------------------- 1 | load("//toolchain/helper:list_helpers.bzl", "unique_list") 2 | 3 | LabelInfo = provider( 4 | doc = " The LabelInfo provider is a structured way to present the information contained in a Bazel label. For details on the exact semantic of labels please have a look at: https://docs.bazel.build/versions/master/build-ref.html#labels", 5 | fields = { 6 | "repository_name": "The repository name of a label is everything including the @ before the '//'. If it is not specified in a labels string (e.g. package relative label, or labels starting with //), it is set to the repository name of the current BUILD.bazel file.", 7 | "package_name": "The package name of a label is everything starting right after the '//' and ending before the first colon ':'. In the case of package relative label string (e.g. :my_label) the package name is equivalent to the package of the current BUILD.bazel file.", 8 | "package_relative_target": "Ther package relative target of a label. If it is not specified in a label string the directory name of the current package is used. For instance for the label //my/special/sub/pa_ck_ag_e, the package relative target is 'pa_ck_ag_e'", 9 | }, 10 | ) 11 | 12 | def get_label_info(label): 13 | """ 14 | Given a valid label this function converts the label to its fully qualified name consisting of its absolute 15 | package name and the package relative label name. 16 | 17 | If a package relative label (e.g. :my_label or my_other_label) is provided it will be resolved to the package of the currently 18 | evaluated BUILD.bazel 19 | If a label is a short form label (e.g. //my_package/the_sub_package) the name of the target will be inferred from 20 | the last package component (e.g. package: //my_package/the_sub_package, target: the_sub_package) 21 | In all other cases the fully qualified label string will be split at the position of the last / to determine the 22 | label's package and the package relative target. 23 | 24 | :param label: The label to canonicalize 25 | :return package,target: returns a pair consisting of the label's fully qualified package name and its target name 26 | """ 27 | 28 | # Validate that a label only contains a single "//", which separates the repository from the package path 29 | if label.count("//") > 1: 30 | fail("Occurence of // is only allowed once inside a label") 31 | 32 | index_of_repository_separator = label.find("//") 33 | repository_name = label[0:index_of_repository_separator] if index_of_repository_separator > 0 else native.repository_name() 34 | 35 | # Validate repository name 36 | if not repository_name.startswith("@"): 37 | fail("Invalid repository name: {repository_name} in label: {label}".format(repository_name = repository_name, label = label)) 38 | 39 | # No package path and no repository name 40 | if index_of_repository_separator == -1: 41 | package_name = native.package_name() 42 | package_relative_target = label[label.find(":") + 1:] 43 | # Regular package 44 | 45 | else: 46 | repository_relative_label = label[index_of_repository_separator + 2:] 47 | 48 | # validate potential package name 49 | if repository_relative_label.startswith("/"): 50 | fail("Label: {label} is invalid, because package names are not allowed to start with a single slash.".format(label = label)) 51 | 52 | index_of_label_separator = repository_relative_label.find(":") 53 | if index_of_label_separator == -1: 54 | package_name = repository_relative_label 55 | package_relative_target = repository_relative_label[repository_relative_label.rfind("/") + 1:] 56 | else: 57 | package_name = repository_relative_label[0:index_of_label_separator] 58 | package_relative_target = repository_relative_label[index_of_label_separator + 1:] 59 | 60 | return LabelInfo( 61 | repository_name = repository_name, 62 | package_name = package_name, 63 | package_relative_target = package_relative_target, 64 | ) 65 | 66 | def unique_labels(list_of_labels): 67 | """ 68 | Given a list of labels this function returns a unique lists of fully qualified labels. 69 | To do so the method does the follow: 70 | 1. Convert the provided labels into fully qualified labels 71 | 2. Removes duplicated entries 72 | 73 | Whenever the input is not None a new list is returned 74 | If the input is None, None will be returned. 75 | 76 | Args: 77 | list_of_labels: A list of label strings 78 | Returns: 79 | A unique list of fully qualified label strings. 80 | """ 81 | 82 | # Early abort if list_of_labels is None 83 | # We do not early abort on empty lists to ensure that 84 | # always a new list is returned 85 | if list_of_labels == None: 86 | return list_of_labels 87 | 88 | return unique_list([convert_to_fully_qualified_label(label) for label in list_of_labels]) 89 | 90 | def convert_to_fully_qualified_label(label): 91 | """ 92 | Given a label this function returns the fully qualified counterpart of the label. 93 | For instance, if a inside package //bar/baz in the main repository a relative 94 | label :foo is provided this function converts it into the fully qualified representation @//bar/baz:foo. 95 | 96 | Args: 97 | label: The label to convert into its fully qualified counterpart 98 | Returns: 99 | The fully qualified label 100 | """ 101 | 102 | label_info = get_label_info(label) 103 | return "{repository_name}//{package_name}:{package_relative_target}".format( 104 | repository_name = label_info.repository_name, 105 | package_name = label_info.package_name, 106 | package_relative_target = label_info.package_relative_target, 107 | ) 108 | 109 | def extract_runfiles_relative_path(label): 110 | """ 111 | Given a label this function converts it into a relative path and takes care to remove a leading `@` if present 112 | """ 113 | label_info = get_label_info(label) 114 | 115 | repository_name_without_leading_at = label_info.repository_name[1:] 116 | 117 | if (label_info.package_name): 118 | return "{repository_name}/{package_name}/{package_relative_target}".format( 119 | repository_name = repository_name_without_leading_at, 120 | package_name = label_info.package_name, 121 | package_relative_target = label_info.package_relative_target, 122 | ) 123 | else: 124 | return "{repository_name}/{package_relative_target}".format( 125 | repository_name = repository_name_without_leading_at, 126 | package_relative_target = label_info.package_relative_target, 127 | ) 128 | -------------------------------------------------------------------------------- /toolchain/helper/list_helpers.bzl: -------------------------------------------------------------------------------- 1 | def unique_list(input_list): 2 | """ 3 | Given a list, returns a unique list. 4 | 5 | :param input_list: List of items to be deduplicated. 6 | """ 7 | if input_list == None: 8 | return None 9 | return dict(zip(input_list, input_list)).values() 10 | 11 | def is_unique_list(input_list): 12 | """ 13 | Given a list, returns True iff it is a unique list. 14 | 15 | :param input_list: List of items to be checked for uniqueness. 16 | """ 17 | if input_list == None: 18 | return None 19 | return len(input_list) == len(unique_list(input_list)) 20 | -------------------------------------------------------------------------------- /toolchain/helper/platform_helpers.bzl: -------------------------------------------------------------------------------- 1 | # Architectures and their extensions: https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html 2 | X86_64_TOOLCHAIN_SUPPORTED_INSTRUCTION_SET_EXTENSIONS = [ 3 | # Extensions of nehalem 4 | "sse", 5 | "sse2", 6 | "sse3", 7 | "ssse3", 8 | "sse4.1", 9 | "sse4.2", 10 | "popcnt", 11 | # cx16 required for 128bit atomics under POSIX 12 | "cx16", 13 | # Add more extensions here if needed 14 | ] 15 | 16 | X86_64_TOOLCHAIN_DEFAULT_INSTRUCTION_SET_EXTENSIONS = [ 17 | # Extensions that will be enabled by default (defining the default minspec of the project) 18 | "sse", 19 | "sse2", 20 | "sse3", 21 | "ssse3", 22 | "sse4.1", 23 | "sse4.2", 24 | "popcnt", 25 | "cx16", 26 | ] 27 | 28 | PLATFORM_LINUX = "@platforms//os:linux" 29 | PLATFORM_MACOS = "@platforms//os:macos" 30 | PLATFORM_WINDOWS = "@platforms//os:windows" 31 | 32 | def is_windows(ctx): 33 | # workaround for detecting windows 34 | # cf. https://github.com/bazelbuild/bazel/issues/2045 or 35 | return ctx.host_configuration.host_path_separator == ";" 36 | -------------------------------------------------------------------------------- /toolchain/helper/runfiles_helpers.bzl: -------------------------------------------------------------------------------- 1 | def collect_runfiles(ctx, data): 2 | """ 3 | Extract the runfiles from the data attribute. 4 | Useful as a replacement for collect_data. 5 | """ 6 | runfiles = ctx.runfiles() 7 | for data_dependency in data: 8 | runfiles = runfiles.merge(data_dependency[DefaultInfo].default_runfiles) 9 | runfiles = runfiles.merge(ctx.runfiles(transitive_files = data_dependency[DefaultInfo].files)) 10 | return runfiles 11 | -------------------------------------------------------------------------------- /toolchain/helper/tests/condition_helpers_tests.bzl: -------------------------------------------------------------------------------- 1 | load("@bazel_skylib//lib:unittest.bzl", "asserts", "unittest") 2 | load(":condition_helpers.bzl", "list_for") 3 | 4 | def condition_helpers_test_suite(): 5 | condition_helpers__list_for__dict_only__test( 6 | name = "condition_helpers__list_for__dict_only__test", 7 | ) 8 | condition_helpers__list_for__use_select__test( 9 | name = "condition_helpers__list_for__use_select__test", 10 | ) 11 | 12 | native.test_suite( 13 | name = "condition_helpers_tests", 14 | tests = [ 15 | ":condition_helpers__list_for__dict_only__test", 16 | ":condition_helpers__list_for__use_select__test", 17 | ], 18 | ) 19 | 20 | def _condition_helpers__list_for__use_select__test_impl(ctx): 21 | env = unittest.begin(ctx) 22 | 23 | asserts.equals(env, repr(select({ 24 | "//toolchain/platforms:is_windows": ["a", "b", "c"], 25 | "//conditions:default": [], 26 | })), repr(list_for(["//toolchain/platforms:is_windows"], ["a", "b", "c"]))) 27 | 28 | return unittest.end(env) 29 | 30 | def _condition_helpers__list_for__dict_only__test_impl(ctx): 31 | env = unittest.begin(ctx) 32 | 33 | asserts.equals(env, { 34 | "//toolchain/platforms:is_windows": ["a", "b", "c"], 35 | "//conditions:default": [], 36 | }, list_for(["//toolchain/platforms:is_windows"], ["a", "b", "c"], dict_only = True)) 37 | 38 | return unittest.end(env) 39 | 40 | condition_helpers__list_for__dict_only__test = unittest.make(_condition_helpers__list_for__dict_only__test_impl) 41 | condition_helpers__list_for__use_select__test = unittest.make(_condition_helpers__list_for__use_select__test_impl) 42 | -------------------------------------------------------------------------------- /toolchain/helper/tests/file_helpers_tests.bzl: -------------------------------------------------------------------------------- 1 | load("@bazel_skylib//lib:unittest.bzl", "asserts", "unittest") 2 | load(":file_helpers.bzl", "get_common_directory_prefix", "get_common_root_dir", "stem") 3 | 4 | def file_helpers_test_suite(): 5 | stem_test( 6 | name = "stem_test", 7 | ) 8 | 9 | get_common_directory_prefix_test( 10 | name = "get_common_directory_prefix_test", 11 | ) 12 | 13 | get_common_root_dir_test( 14 | name = "get_common_root_dir_test", 15 | ) 16 | 17 | native.test_suite( 18 | name = "file_helpers_tests", 19 | tests = [ 20 | ":stem_test", 21 | ":get_common_directory_prefix_test", 22 | ":get_common_root_dir_test", 23 | ], 24 | ) 25 | 26 | def _stem_test_impl(ctx): 27 | env = unittest.begin(ctx) 28 | dummy_file = struct( 29 | extension = "ext", 30 | basename = "myname.ext", 31 | ) 32 | 33 | asserts.equals(env, "myname", stem(dummy_file)) 34 | return unittest.end(env) 35 | 36 | stem_test = unittest.make(_stem_test_impl) 37 | 38 | def _get_common_directory_prefix_test_impl(ctx): 39 | env = unittest.begin(ctx) 40 | 41 | # Case: trivial "" or "/" paths; empty common prefix 42 | asserts.equals(env, "", get_common_directory_prefix("", "")) 43 | asserts.equals(env, "", get_common_directory_prefix("", "/")) 44 | asserts.equals(env, "", get_common_directory_prefix("/", "")) 45 | 46 | # Case: paths without a root `/` separator 47 | asserts.equals(env, "a", get_common_directory_prefix("a/bc", "a/b")) 48 | asserts.equals(env, "a", get_common_directory_prefix("a/b", "a/bc")) 49 | 50 | # Case: one path is the prefix of another path 51 | asserts.equals(env, "a/b", get_common_directory_prefix("a/b/c", "a/b")) 52 | asserts.equals(env, "a/b", get_common_directory_prefix("a/b", "a/b/c")) 53 | 54 | # Case: one path with a trailing separator; empty common prefix 55 | asserts.equals(env, "", get_common_directory_prefix("/abc", "/ab/")) 56 | asserts.equals(env, "", get_common_directory_prefix("/ab/", "/abc")) 57 | 58 | # Case: one path with a trailing separator; non-empty common prefix 59 | asserts.equals(env, "/a", get_common_directory_prefix("/a/bc", "/a/b/")) 60 | asserts.equals(env, "/a", get_common_directory_prefix("/a/b/", "/a/bc")) 61 | 62 | # Case: both with trailing separator; non-empty common prefix 63 | asserts.equals(env, "/r", get_common_directory_prefix("/r/abc/", "/r/ab/")) 64 | asserts.equals(env, "/r", get_common_directory_prefix("/r/ab/", "/r/abc/")) 65 | 66 | return unittest.end(env) 67 | 68 | get_common_directory_prefix_test = unittest.make(_get_common_directory_prefix_test_impl) 69 | 70 | def _get_common_root_dir_test_impl(ctx): 71 | env = unittest.begin(ctx) 72 | 73 | files = [ 74 | struct(path = "my/common/directory/suffixb/a.txt"), 75 | struct(path = "my/common/directory/suffixb/suffixc/c.txt"), 76 | struct(path = "my/common/directory/suffixa/d.txt"), 77 | ] 78 | 79 | asserts.equals(env, "my/common/directory", get_common_root_dir(files)) 80 | 81 | return unittest.end(env) 82 | 83 | get_common_root_dir_test = unittest.make(_get_common_root_dir_test_impl) 84 | -------------------------------------------------------------------------------- /toolchain/helper/tests/function_helpers_tests.bzl: -------------------------------------------------------------------------------- 1 | load("@bazel_skylib//lib:unittest.bzl", "asserts", "unittest") 2 | load(":function_helpers.bzl", "function_info") 3 | 4 | # Macro for testing function_info 5 | def f(): 6 | fail(msg = "This macro should never be executed") 7 | 8 | def function_helpers_test_suite(): 9 | # function_info tests 10 | function_helpers__function_info__function_input__test( 11 | name = "function_helpers__function_info__function_input__test", 12 | ) 13 | native.test_suite( 14 | name = "function_helpers_tests", 15 | tests = [ 16 | ":function_helpers__function_info__function_input__test", 17 | ], 18 | ) 19 | 20 | def _function_helpers__function_info__function_input__test_impl(ctx): 21 | env = unittest.begin(ctx) 22 | test_data = [ 23 | ("//toolchain/helper:tests/function_helpers_tests.bzl", f, "f"), 24 | ("//toolchain/helper:function_helpers.bzl", function_info, "function_info"), 25 | ] 26 | for module, function, function_string in test_data: 27 | asserts.equals(env, repr(function_string), repr(function_info(function).function_name)) 28 | asserts.equals(env, repr(module), repr(function_info(function).starlark_file_declaring_function)) 29 | return unittest.end(env) 30 | 31 | function_helpers__function_info__function_input__test = unittest.make(_function_helpers__function_info__function_input__test_impl) 32 | -------------------------------------------------------------------------------- /toolchain/helper/tests/list_helpers_tests.bzl: -------------------------------------------------------------------------------- 1 | load("@bazel_skylib//lib:unittest.bzl", "asserts", "unittest") 2 | load(":list_helpers.bzl", "is_unique_list", "unique_list") 3 | 4 | def list_helpers_test_suite(): 5 | # unique_list tests 6 | list_helpers__unique_list__empty_list__test( 7 | name = "list_helpers__unique_list__empty_list__test", 8 | ) 9 | list_helpers__unique_list__none_list__test( 10 | name = "list_helpers__unique_list__none_list__test", 11 | ) 12 | list_helpers__unique_list__single_item_list__test( 13 | name = "list_helpers__unique_list__single_item_list__test", 14 | ) 15 | list_helpers__unique_list__multi_item_list__test( 16 | name = "list_helpers__unique_list__multi_item_list__test", 17 | ) 18 | 19 | # is_unique_list tests 20 | list_helpers__is_unique_list__empty_list__test( 21 | name = "list_helpers__is_unique_list__empty_list__test", 22 | ) 23 | list_helpers__is_unique_list__none_list__test( 24 | name = "list_helpers__is_unique_list__none_list__test", 25 | ) 26 | list_helpers__is_unique_list__single_item_list__test( 27 | name = "list_helpers__is_unique_list__single_item_list__test", 28 | ) 29 | list_helpers__is_unique_list__multi_item_list__test( 30 | name = "list_helpers__is_unique_list__multi_item_list__test", 31 | ) 32 | 33 | native.test_suite( 34 | name = "list_helpers_tests", 35 | tests = [ 36 | ":list_helpers__unique_list__empty_list__test", 37 | ":list_helpers__unique_list__none_list__test", 38 | ":list_helpers__unique_list__single_item_list__test", 39 | ":list_helpers__unique_list__multi_item_list__test", 40 | ":list_helpers__is_unique_list__empty_list__test", 41 | ":list_helpers__is_unique_list__none_list__test", 42 | ":list_helpers__is_unique_list__single_item_list__test", 43 | ":list_helpers__is_unique_list__multi_item_list__test", 44 | ], 45 | ) 46 | 47 | def _list_helpers__unique_list__empty_list__test_impl(ctx): 48 | env = unittest.begin(ctx) 49 | asserts.equals(env, repr([]), repr(unique_list([]))) 50 | return unittest.end(env) 51 | 52 | def _list_helpers__unique_list__none_list__test_impl(ctx): 53 | env = unittest.begin(ctx) 54 | asserts.equals(env, repr(None), repr(unique_list(None))) 55 | return unittest.end(env) 56 | 57 | def _list_helpers__unique_list__single_item_list__test_impl(ctx): 58 | env = unittest.begin(ctx) 59 | for item in [None, "i", "j", "xyz", "42", -1, 0, 1]: 60 | asserts.equals(env, repr([item]), repr(unique_list([item]))) 61 | return unittest.end(env) 62 | 63 | def _list_helpers__unique_list__multi_item_list__test_impl(ctx): 64 | env = unittest.begin(ctx) 65 | items = [None, "i", "j", "xyz", "42", -1, 0, 1] 66 | [asserts.equals( 67 | env, 68 | repr([item_i] + ([item_j] if item_i != item_j else []) + ([item_k] if item_k != item_j and item_k != item_i else [])), 69 | repr(unique_list([item_i] * i + [item_j] * j + [item_k] * k)), 70 | ) for i in range(1, 5) for j in range(1, 5) for k in range(1, 5) for item_i in items for item_j in items for item_k in items] 71 | return unittest.end(env) 72 | 73 | def _list_helpers__is_unique_list__empty_list__test_impl(ctx): 74 | env = unittest.begin(ctx) 75 | asserts.equals(env, repr(True), repr(is_unique_list([]))) 76 | return unittest.end(env) 77 | 78 | def _list_helpers__is_unique_list__none_list__test_impl(ctx): 79 | env = unittest.begin(ctx) 80 | asserts.equals(env, repr(None), repr(is_unique_list(None))) 81 | return unittest.end(env) 82 | 83 | def _list_helpers__is_unique_list__single_item_list__test_impl(ctx): 84 | env = unittest.begin(ctx) 85 | for item in ["i", "j", "xyz", "42", -1, 0, 1]: 86 | asserts.equals(env, repr(True), repr(is_unique_list([item]))) 87 | return unittest.end(env) 88 | 89 | def _list_helpers__is_unique_list__multi_item_list__test_impl(ctx): 90 | env = unittest.begin(ctx) 91 | items = ["i", "j", "xyz", "42", -1, 0, 1] 92 | for until_index in range(len(items)): 93 | asserts.equals(env, repr(True), repr(is_unique_list(items[:until_index]))) 94 | return unittest.end(env) 95 | 96 | list_helpers__unique_list__empty_list__test = unittest.make(_list_helpers__unique_list__empty_list__test_impl) 97 | list_helpers__unique_list__none_list__test = unittest.make(_list_helpers__unique_list__none_list__test_impl) 98 | list_helpers__unique_list__single_item_list__test = unittest.make(_list_helpers__unique_list__single_item_list__test_impl) 99 | list_helpers__unique_list__multi_item_list__test = unittest.make(_list_helpers__unique_list__multi_item_list__test_impl) 100 | 101 | list_helpers__is_unique_list__empty_list__test = unittest.make(_list_helpers__is_unique_list__empty_list__test_impl) 102 | list_helpers__is_unique_list__none_list__test = unittest.make(_list_helpers__is_unique_list__none_list__test_impl) 103 | list_helpers__is_unique_list__single_item_list__test = unittest.make(_list_helpers__is_unique_list__single_item_list__test_impl) 104 | list_helpers__is_unique_list__multi_item_list__test = unittest.make(_list_helpers__is_unique_list__multi_item_list__test_impl) 105 | -------------------------------------------------------------------------------- /toolchain/helper/tests/runfiles_helpers_test.bzl: -------------------------------------------------------------------------------- 1 | load("@bazel_skylib//lib:unittest.bzl", "asserts", "unittest") 2 | load(":runfiles_helpers.bzl", "collect_runfiles") 3 | 4 | def _dummy(ctx): 5 | """ 6 | A dummy target containing a single file and a transitive file 7 | """ 8 | file_path = ctx.actions.declare_file("file_" + ctx.attr.index) 9 | ctx.actions.write(file_path, "") 10 | transitive_file_path = ctx.actions.declare_file("transitive_file_" + ctx.attr.index) 11 | ctx.actions.write(transitive_file_path, "") 12 | return DefaultInfo( 13 | files = depset([transitive_file_path]), 14 | runfiles = ctx.runfiles(files = [file_path]), 15 | ) 16 | 17 | dummy = rule(_dummy, attrs = {"index": attr.string()}) 18 | 19 | def runfiles_helpers_test_suite(): 20 | dummy(name = "local_target_1", index = "1") 21 | dummy(name = "local_target_2", index = "2") 22 | 23 | runfiles_helpers__data_runfiles__test( 24 | name = "runfiles_helpers__data_runfiles__test", 25 | data = [":local_target_1", ":local_target_2"], 26 | ) 27 | 28 | def _runfiles_helpers__data_runfiles__test(ctx): 29 | env = unittest.begin(ctx) 30 | runfiles = collect_runfiles(ctx, ctx.attr.data) 31 | 32 | # We check the repr of runfiles. This may fail in the future if bazel changes 33 | # the output. A test based on to_list might be more stable. 34 | asserts.equals( 35 | env, 36 | ("depset([, " + 37 | ", " + 38 | ", " + 39 | "], order = \"postorder\")"), 40 | repr(runfiles.files), 41 | ) 42 | return unittest.end(env) 43 | 44 | runfiles_helpers__data_runfiles__test = unittest.make( 45 | _runfiles_helpers__data_runfiles__test, 46 | {"data": attr.label_list(mandatory = True)}, 47 | ) 48 | -------------------------------------------------------------------------------- /toolchain/platforms/BUILD.bazel: -------------------------------------------------------------------------------- 1 | "Architecture and Operating Systen conditions and target definitions (used with --platform)" 2 | 3 | load("@bazel_skylib//lib:selects.bzl", "selects") 4 | load("//toolchain/platforms:platform_with_config_setting.bzl", "platform_with_config_setting") 5 | load("//toolchain/platforms:package_variables.bzl", "package_variables") 6 | # If you want to use the os+arch platform defines in selects, use the "is_<>" config settings created by the macro 7 | 8 | package(default_visibility = ["//visibility:public"]) 9 | 10 | package_variables( 11 | name = "default_zip_variables", 12 | substitutions = 13 | select({ 14 | "//bazel/platforms:is_windows_x64": { 15 | "os": "windows", 16 | "architecture": "x86_64", 17 | }, 18 | "//bazel/platforms:is_linux_x64": { 19 | "os": "linux", 20 | "architecture": "x86_64", 21 | }, 22 | "//bazel/platforms:is_macos_x64": { 23 | "os": "macos", 24 | "architecture": "x86_64", 25 | }, 26 | "//bazel/platforms:is_macos_arm": { 27 | "os": "macos", 28 | "architecture": "arm64", 29 | }, 30 | }) | 31 | select({ 32 | "//bazel/conditions:compilation_mode_opt": { 33 | "build_type": "release", 34 | }, 35 | "//conditions:default": { 36 | "build_type": "debug", 37 | }, 38 | }), 39 | visibility = ["//visibility:public"], 40 | ) 41 | 42 | alias( 43 | name = "is_windows", 44 | actual = "@platforms//os:windows", 45 | ) 46 | 47 | alias( 48 | name = "is_linux", 49 | actual = "@platforms//os:linux", 50 | ) 51 | 52 | alias( 53 | name = "is_macos", 54 | actual = "@platforms//os:macos", 55 | ) 56 | 57 | alias( 58 | name = "is_arm", 59 | actual = "@platforms//cpu:aarch64", 60 | ) 61 | 62 | alias( 63 | name = "is_x64", 64 | actual = "@platforms//cpu:x86_64", 65 | ) 66 | 67 | selects.config_setting_group( 68 | name = "is_posix", 69 | match_any = [ 70 | ":is_linux", 71 | ":is_macos", 72 | ], 73 | ) 74 | 75 | platform_with_config_setting( 76 | name = "linux_x64", 77 | constraint_values = [ 78 | "@platforms//os:linux", 79 | "@platforms//cpu:x86_64", 80 | ], 81 | ) 82 | 83 | platform_with_config_setting( 84 | name = "linux_arm", 85 | constraint_values = [ 86 | "@platforms//os:linux", 87 | "@platforms//cpu:aarch64", 88 | ], 89 | ) 90 | 91 | platform_with_config_setting( 92 | name = "windows_x64", 93 | constraint_values = [ 94 | "@platforms//os:windows", 95 | "@platforms//cpu:x86_64", 96 | ], 97 | ) 98 | 99 | platform_with_config_setting( 100 | name = "windows_arm", 101 | constraint_values = [ 102 | "@platforms//os:windows", 103 | "@platforms//cpu:aarch64", 104 | ], 105 | ) 106 | 107 | platform_with_config_setting( 108 | name = "macos_x64", 109 | constraint_values = [ 110 | "@platforms//os:macos", 111 | "@platforms//cpu:x86_64", 112 | ], 113 | ) 114 | 115 | platform_with_config_setting( 116 | name = "macos_arm", 117 | constraint_values = [ 118 | "@platforms//os:macos", 119 | "@platforms//cpu:aarch64", 120 | ], 121 | ) 122 | -------------------------------------------------------------------------------- /toolchain/platforms/package_variables.bzl: -------------------------------------------------------------------------------- 1 | load("@rules_pkg//pkg:providers.bzl", "PackageVariablesInfo") 2 | 3 | def _package_variables_impl(ctx): 4 | return PackageVariablesInfo(values = ctx.attr.substitutions) 5 | 6 | package_variables = rule( 7 | implementation = _package_variables_impl, 8 | attrs = { 9 | "substitutions": attr.string_dict( 10 | doc = "Substitutions for template expansion", 11 | ), 12 | }, 13 | ) 14 | -------------------------------------------------------------------------------- /toolchain/platforms/platform_mappings: -------------------------------------------------------------------------------- 1 | platforms: 2 | //toolchain/platforms:macos_x64 3 | --cpu=darwin 4 | 5 | //toolchain/platforms:macos_arm 6 | --cpu=darwin_aarch64 7 | 8 | //toolchain/platforms:linux_x64 9 | --cpu=k8 10 | 11 | //toolchain/platforms:windows_x64 12 | --cpu=x64_windows 13 | 14 | flags: 15 | --cpu=darwin 16 | //toolchain/platforms:macos_x64 17 | 18 | --cpu=darwin_aarch64 19 | //toolchain/platforms:macos_arm 20 | 21 | --cpu=k8 22 | //toolchain/platforms:linux_x64 23 | 24 | --cpu=x64_windows 25 | //toolchain/platforms:windows_x64 26 | -------------------------------------------------------------------------------- /toolchain/platforms/platform_with_config_setting.bzl: -------------------------------------------------------------------------------- 1 | # Macro to define a matching config setting for selects with every platform 2 | 3 | def platform_with_config_setting(name, constraint_values): 4 | native.platform( 5 | name = name, 6 | constraint_values = constraint_values, 7 | visibility = ["//visibility:public"], 8 | ) 9 | 10 | native.config_setting( 11 | name = "is_{name}".format(name = name), 12 | constraint_values = constraint_values, 13 | visibility = ["//visibility:public"], 14 | ) 15 | -------------------------------------------------------------------------------- /toolchain/rules/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_python//python:defs.bzl", "py_binary") 2 | 3 | # Helper target with the aim to access the requested operating system name (windows, linux or darwin) inside rule implementations. 4 | # 5 | # This alias is used as a hidden parameter in the os_information rule. 6 | # A global instance of the os_information is available at //toolchain/aliases:os 7 | # and allows other rule implementations to conveniently access the requested OS information. 8 | alias( 9 | name = "os_condition_alias", 10 | actual = select({ 11 | "//toolchain/platforms:is_macos": "//toolchain/platforms:is_macos", 12 | "//toolchain/platforms:is_linux": "//toolchain/platforms:is_linux", 13 | "//toolchain/platforms:is_windows": "//toolchain/platforms:is_windows", 14 | }), 15 | visibility = ["//visibility:public"], 16 | ) 17 | 18 | py_binary( 19 | name = "generatesymbolfile", 20 | srcs = ["generatesymbolfile.py"], 21 | main = "generatesymbolfile.py", 22 | python_version = "PY3", 23 | srcs_version = "PY3", 24 | visibility = ["//visibility:public"], 25 | ) 26 | 27 | # A helper alias that is required to resolve the proper dsymutils on all platforms 28 | alias( 29 | name = "platformspecific_dsym_utils", 30 | actual = select({ 31 | "//toolchain/platforms:is_macos": "@clang_darwin//:dsymutil", 32 | "//toolchain/platforms:is_linux": "@clang_linux//:dsymutil", 33 | "//toolchain/platforms:is_windows": "@clang_windows//:dsymutil", 34 | }), 35 | visibility = ["//visibility:public"], 36 | ) 37 | 38 | # These alias are required to resolve the proper tools for the rc_rules on all platforms 39 | alias( 40 | name = "llvm_rc", 41 | actual = select({ 42 | "//toolchain/platforms:is_macos": "@clang_darwin//:llvm_rc", 43 | "//toolchain/platforms:is_linux": "@clang_linux//:llvm_rc", 44 | "//toolchain/platforms:is_windows": "@clang_windows//:llvm_rc", 45 | }), 46 | visibility = ["//visibility:public"], 47 | ) 48 | 49 | alias( 50 | name = "llvm_cvtres", 51 | actual = select({ 52 | "//toolchain/platforms:is_macos": "@clang_darwin//:llvm_cvtres", 53 | "//toolchain/platforms:is_linux": "@clang_linux//:llvm_cvtres", 54 | "//toolchain/platforms:is_windows": "@clang_windows//:llvm_cvtres", 55 | }), 56 | visibility = ["//visibility:public"], 57 | ) 58 | -------------------------------------------------------------------------------- /toolchain/rules/dsym.bzl: -------------------------------------------------------------------------------- 1 | load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain") 2 | 3 | StaticLibrariesLinkerInputs = provider( 4 | fields = { 5 | "files": "the static libraries that have been used as an input on the link command line of a binary", 6 | }, 7 | ) 8 | 9 | def _link_inputs_aspect_impl(target, ctx): 10 | # Retrieve the C++ toolchain and determine the features that were used to build the provided binary 11 | cc_toolchain = find_cpp_toolchain(ctx) 12 | feature_configuration = cc_common.configure_features( 13 | ctx = ctx, 14 | cc_toolchain = cc_toolchain, 15 | requested_features = ctx.features + ctx.rule.attr.features, 16 | unsupported_features = ctx.disabled_features, 17 | ) 18 | 19 | # Determines if the pic or non pic static libraries were used to link the final binary 20 | needs_pic = cc_toolchain.needs_pic_for_dynamic_libraries(feature_configuration = feature_configuration) 21 | 22 | # Merges the cc_infos of the binaries transitive dependencies 23 | cc_info = cc_common.merge_cc_infos(cc_infos = [dep[CcInfo] for dep in ctx.rule.attr.deps]) 24 | #return for linker_input in cc_info.linking_context.linker_inputs 25 | 26 | dependent_static_libraries = [] 27 | for linker_input in cc_info.linking_context.linker_inputs.to_list(): 28 | for library_to_link in linker_input.libraries: 29 | if ctx.rule.attr.linkstatic or not library_to_link.dynamic_library: 30 | # Only add pic libraries if pic is enabled and they are actually available. 31 | # If pic is enabled but not static library with pic is available fall back to the non pic variant. 32 | if needs_pic and library_to_link.pic_static_library: 33 | dependent_static_libraries.append(library_to_link.pic_static_library) 34 | elif library_to_link.static_library: 35 | dependent_static_libraries.append(library_to_link.static_library) 36 | 37 | # Also add the toolchain's static runtime library if it was used for linking 38 | need_to_consider_runtime_library = ctx.rule.attr.linkstatic and cc_common.is_enabled(feature_configuration = feature_configuration, feature_name = "static_link_cpp_runtimes") 39 | runtime_libraries = [cc_toolchain.static_runtime_lib(feature_configuration = feature_configuration)] if need_to_consider_runtime_library else [] 40 | 41 | return StaticLibrariesLinkerInputs( 42 | files = depset( 43 | direct = dependent_static_libraries, 44 | transitive = runtime_libraries, 45 | ), 46 | ) 47 | 48 | _link_inputs_aspect = aspect( 49 | doc = """ 50 | This aspect allows to retrieve all static libraries that are used to link the binary the aspect is applied on. 51 | """, 52 | implementation = _link_inputs_aspect_impl, 53 | toolchains = ["@bazel_tools//tools/cpp:toolchain_type"], 54 | fragments = ["cpp"], 55 | ) 56 | 57 | def _dsym_impl(ctx): 58 | # The label is used as the name of the resulting .dSYM package 59 | dSYM_package_name = ctx.label.name 60 | 61 | # The file inside the .dSYM package that contains the actual dwarf debug symbols 62 | dsym_internal_path_to_dwarf_symbols = "Contents/Resources/DWARF/{binary_name}".format(binary_name = ctx.attr.binary.label.name) 63 | path_to_dwarf_symbols = "{dSYM_package_name}/{dsym_internal_path_to_dwarf_symbols}".format(dSYM_package_name = dSYM_package_name, dsym_internal_path_to_dwarf_symbols = dsym_internal_path_to_dwarf_symbols) 64 | 65 | dwarf_symbols_file = ctx.actions.declare_file(path_to_dwarf_symbols, sibling = ctx.executable.binary) 66 | 67 | # The +1 accounts for the slash separating the .dSYM directory name from the package's internal path to the symbol file 68 | path_to_dSYM_root_directory = dwarf_symbols_file.path[0:-(len(dsym_internal_path_to_dwarf_symbols) + 1)] 69 | 70 | # The plist file inside the .dSYM package 71 | plist_file = ctx.actions.declare_file("{dSYM_package_name}/Contents/Info.plist".format(dSYM_package_name = dSYM_package_name), sibling = ctx.executable.binary) 72 | 73 | # The static libraries that were used to link the provided binary and are referenced by the OSO stabs 74 | static_libraries_used_to_link_the_binary = ctx.attr.binary[StaticLibrariesLinkerInputs].files 75 | 76 | # The object files that were provided on the link command line of the provided binary and are referenced by the OSO stabs 77 | object_files_used_to_link_the_binary = ctx.attr.binary[OutputGroupInfo].compilation_outputs 78 | 79 | ctx.actions.run( 80 | executable = ctx.executable._dsymutil, 81 | arguments = [ctx.actions.args().add(ctx.executable.binary).add("-o").add(path_to_dSYM_root_directory)], 82 | outputs = [dwarf_symbols_file, plist_file], 83 | inputs = depset(direct = [ctx.executable.binary], transitive = [static_libraries_used_to_link_the_binary, object_files_used_to_link_the_binary]), 84 | ) 85 | return [DefaultInfo(files = depset(direct = [dwarf_symbols_file, plist_file]))] 86 | 87 | dsym = rule( 88 | implementation = _dsym_impl, 89 | doc = """ 90 | This rule is used to generate a .dSYM package containing the debug symbols for a mac os binary. 91 | Currently this is a missing feature in Bazel (please see Bazel issue 2537 https://github.com/bazelbuild/bazel/issues/2537) 92 | The name of resulting targets are identical to the name of the resulting package. 93 | Therefore, please follow the convention to name targets generated by this rule ".dSYM" 94 | """, 95 | attrs = { 96 | "binary": attr.label( 97 | doc = "The binary to generate debug symbols for.", 98 | cfg = "target", 99 | executable = True, 100 | providers = [CcInfo], 101 | aspects = [_link_inputs_aspect], 102 | ), 103 | "_dsymutil": attr.label( 104 | doc = "Internal attribute that holds the reference to the macos sdk's dsymutil.", 105 | cfg = "target", 106 | executable = True, 107 | default = "//toolchain/rules:platformspecific_dsym_utils", 108 | ), 109 | #"_dsymutil_libraries": attr.label( 110 | # doc = "Internal attribute that holds the reference to the required library for macos sdk's dsymutil.", 111 | # cfg = "target", 112 | # default = "//toolchain/rules:platformspecific_dsym_utils_additional_libraries", 113 | #), 114 | }, 115 | ) 116 | -------------------------------------------------------------------------------- /toolchain/rules/exported_symbols.bzl: -------------------------------------------------------------------------------- 1 | load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain") 2 | 3 | def _generate_platform_specific_symfile(ctx, mnemonic, output_type): 4 | """ Generates a platform-specific symfile """ 5 | filename = ctx.attr.name 6 | output_file = ctx.actions.declare_file(filename) 7 | 8 | ctx.actions.run( 9 | inputs = [ctx.file.sym_file], 10 | outputs = [output_file], 11 | executable = ctx.executable._conversion_script, 12 | mnemonic = mnemonic, 13 | progress_message = "Generating {output_type} \"{filename}\" from symfile \"{input_file_name}\"".format( 14 | output_type = output_type, 15 | filename = output_file.path, 16 | input_file_name = ctx.file.sym_file.path, 17 | ), 18 | arguments = [ctx.file.sym_file.path, output_file.path], 19 | ) 20 | return output_file 21 | 22 | def _generate_platform_specific_linker_parameter(ctx, additional_inputs, user_link_flags): 23 | """ Generates a platform-specific CcInfo with linking context """ 24 | cc_toolchain = find_cpp_toolchain(ctx) 25 | feature_configuration = cc_common.configure_features( 26 | ctx = ctx, 27 | cc_toolchain = cc_toolchain, 28 | requested_features = ctx.features + ctx.attr.features, 29 | unsupported_features = ctx.disabled_features, 30 | ) 31 | linker_input = cc_common.create_linker_input( 32 | owner = ctx.label, 33 | additional_inputs = depset(additional_inputs), 34 | user_link_flags = depset(user_link_flags), 35 | ) 36 | return CcInfo(linking_context = cc_common.create_linking_context(linker_inputs = depset(direct = [linker_input]))) 37 | 38 | def _platform_specific_symfile_rule(implementation, doc): 39 | """ Generates a rule to create platform specific symfiles """ 40 | return rule( 41 | implementation = implementation, 42 | doc = doc, 43 | attrs = { 44 | "sym_file": attr.label( 45 | allow_single_file = True, 46 | doc = ".sym file containing a list of symbols used to generate platform-specific exported symbols file", 47 | ), 48 | "_conversion_script": attr.label( 49 | default = Label("//toolchain/rules:generatesymbolfile"), 50 | executable = True, 51 | cfg = "exec", 52 | ), 53 | "_cc_toolchain": attr.label(default = Label("@bazel_tools//tools/cpp:current_cc_toolchain")), 54 | }, 55 | toolchains = ["@bazel_tools//tools/cpp:toolchain_type"], 56 | fragments = ["cpp"], 57 | ) 58 | 59 | def _linux_lds_script(ctx): 60 | """ Implementation of linux_lds_script """ 61 | lds_script = _generate_platform_specific_symfile(ctx, "LdsGenerate", "Linux Linker Script") 62 | 63 | return [ 64 | _generate_platform_specific_linker_parameter(ctx, [lds_script], [lds_script.path]), 65 | DefaultInfo(files = depset([lds_script])), 66 | ] 67 | 68 | def _linux_version_script(ctx): 69 | """ Implementation of linux_version_script """ 70 | linker_version_script = _generate_platform_specific_symfile(ctx, "VerGenerate", "Linux version") 71 | 72 | return [ 73 | _generate_platform_specific_linker_parameter(ctx, [linker_version_script], ["-Wl,--version-script,\"{linker_version_script}\"".format(linker_version_script = linker_version_script.path)]), 74 | DefaultInfo(files = depset([linker_version_script])), 75 | ] 76 | 77 | def _mac_exported_symbols_list(ctx): 78 | """ Implementation of mac_exported_symbols_list """ 79 | exported_symbols_list = _generate_platform_specific_symfile(ctx, "ExpGenerate", "Exported Symbols") 80 | 81 | return [ 82 | _generate_platform_specific_linker_parameter(ctx, [exported_symbols_list], ["-exported_symbols_list", exported_symbols_list.path]), 83 | DefaultInfo(files = depset([exported_symbols_list])), 84 | ] 85 | 86 | def _windows_def_file(ctx): 87 | """ Implementation of windows_def_file """ 88 | def_file = _generate_platform_specific_symfile(ctx, "DefGenerate", "Windows Module Definition File") 89 | 90 | return [ 91 | _generate_platform_specific_linker_parameter(ctx, [def_file], ["/DEF:{win_def_file}".format(win_def_file = def_file.path)]), 92 | DefaultInfo(files = depset([def_file])), 93 | ] 94 | 95 | linux_lds_script = _platform_specific_symfile_rule(implementation = _linux_lds_script, doc = "Rule to create a ld linker script file for Linux build (extension: .lds). The main purpose of the linker script is to describe how the sections in the input files should be mapped into the output file, and to control the memory layout of the output file.") 96 | linux_version_script = _platform_specific_symfile_rule(implementation = _linux_version_script, doc = "Rule to create a version script for Linux build (extension: .ver). Version scripts are only meaningful when creating shared libraries.") 97 | mac_exported_symbols = _platform_specific_symfile_rule(implementation = _mac_exported_symbols_list, doc = "Rule to create a symbols export file for MacOS build (extension: .exp). Stores symbol table data.") 98 | windows_def_file = _platform_specific_symfile_rule(implementation = _windows_def_file, doc = "Rule to create a Module-Definition file for Windows build (extension: .def). The file lists the exports and attributes of a program to be linked by an application linker.") 99 | -------------------------------------------------------------------------------- /toolchain/rules/generatesymbolfile.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # This script generates a platform-specific symbol file out of a given input .sym file. 3 | # The input sym file should contain a list of symbols to export on each line 4 | # ------------------------------------- 5 | import os 6 | import platform 7 | import sys 8 | 9 | 10 | def _generate_windows_def_file_content(symbol_list): 11 | """ Generate a .DEF file for exporting symbols on Windows 12 | 13 | https://docs.microsoft.com/en-us/cpp/build/exporting-from-a-dll-using-def-files?view=vs-2019 14 | """ 15 | output = "EXPORTS\n" 16 | 17 | for symbol in symbol_list: 18 | output += symbol + "\n" 19 | 20 | return output 21 | 22 | 23 | def _generate_mac_exported_symbols_list_file_content(symbol_list): 24 | """ Generate a exported_symbols list file for exporting symbols on Mac 25 | 26 | https://developer.apple.com/library/archive/documentation/DeveloperTools/Conceptual/DynamicLibraries/100-Articles/DynamicLibraryDesignGuidelines.html 27 | """ 28 | output = "" 29 | for symbol in symbol_list: 30 | output += "_" + symbol + "\n" 31 | return output 32 | 33 | 34 | def _generate_linux_version_script_content(symbol_list): 35 | """ Generate a version script for defining exported symbols on Linux 36 | 37 | https://www.gnu.org/software/gnulib/manual/html_node/LD-Version-Scripts.html 38 | """ 39 | output = "{\nglobal:\n" 40 | for symbol in symbol_list: 41 | output += symbol + ";\n" 42 | output += "\nlocal:\n*;\n};\n" 43 | return output 44 | 45 | 46 | def _generate_linux_ld_linker_script_content(symbol_list): 47 | """ Generate a linker script for defining exported symbols on Linux 48 | 49 | http://bravegnu.org/gnu-eprog/lds.html 50 | """ 51 | output = "" 52 | for symbol in symbol_list: 53 | output += f"EXTERN({symbol});\nASSERT(DEFINED({symbol}), \"Symbol {symbol} not available\");\n" 54 | return output 55 | 56 | 57 | def _generate_symbol_file(input_file_path, output_file_path): 58 | """ Read the symbol list file and create the proper symbol file for the platform in the output file path.""" 59 | symbol_list = [] 60 | with open(input_file_path, "r") as f: 61 | for line in f: 62 | symbol_list.append(line.rstrip()) 63 | 64 | file_extension = os.path.splitext(output_file_path)[1] 65 | 66 | if file_extension == ".def": 67 | file_content = _generate_windows_def_file_content(symbol_list) 68 | elif file_extension == ".exp": 69 | file_content = _generate_mac_exported_symbols_list_file_content(symbol_list) 70 | elif file_extension == ".ver": 71 | file_content = _generate_linux_version_script_content(symbol_list) 72 | elif file_extension == ".lds": 73 | file_content = _generate_linux_ld_linker_script_content(symbol_list) 74 | else: 75 | raise NotImplemented("Unknown file type: " + file_extension) 76 | 77 | with open(output_file_path, "w") as f: 78 | f.write(file_content) 79 | 80 | 81 | if __name__ == "__main__": 82 | import sys 83 | input_sym_file = sys.argv[1] 84 | output_file = sys.argv[2] 85 | _generate_symbol_file(input_sym_file, output_file) 86 | -------------------------------------------------------------------------------- /toolchain/rules/hyper_cc.bzl: -------------------------------------------------------------------------------- 1 | # Wrappers around the Bazel cc-rules that set specific properties for code we own. 2 | # All targets with code we own should use these macros instead of the native cc-rules. 3 | 4 | load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library", "cc_test") 5 | load("//toolchain/helper:condition_helpers.bzl", "list_for") 6 | load("//toolchain/helper:label_helpers.bzl", "get_label_info", "unique_labels") 7 | load("//toolchain/rules:dsym.bzl", "dsym") 8 | load("//toolchain/rules:exported_symbols.bzl", "linux_lds_script", "linux_version_script", "mac_exported_symbols", "windows_def_file") 9 | 10 | # Shared features across hyper cc targets 11 | HYPER_TOOLCHAIN_FEATURES = ["hyper_warning_flags", "hyper_cxx20_compat", "hyper_platform_defines", "-ignore_some_warnings_per_default"] 12 | 13 | def add_target_visibility(current, target): 14 | if "//visibility:public" in current: 15 | # Already visible to target 16 | return current 17 | if "//visibility:private" in current: 18 | # Instead of private we just change it to our target 19 | return [target] 20 | else: 21 | return current + [target] 22 | 23 | def hyper_cc_library( 24 | name, 25 | deps = [], 26 | implementation_deps = None, 27 | srcs = [], 28 | data = [], 29 | hdrs = [], 30 | alwayslink = False, 31 | compatible_with = [], 32 | copts = [], 33 | defines = [], 34 | deprecation = None, 35 | exec_compatible_with = [], 36 | features = [], 37 | includes = [], 38 | include_prefix = None, 39 | licenses = [], 40 | linkopts = [], 41 | linkstatic = True, 42 | local_defines = [], 43 | nocopts = None, 44 | restricted_to = None, 45 | strip_include_prefix = None, 46 | tags = [], 47 | target_compatible_with = None, 48 | testonly = False, 49 | textual_hdrs = [], 50 | toolchains = [], 51 | visibility = []): 52 | label_info = get_label_info(name) 53 | full_package_name = "//" + label_info.package_name + ":" + label_info.package_relative_target 54 | 55 | # Ensure that every default visbility binary can be included in the compilation_database.json 56 | visibility = add_target_visibility(visibility, "//:__pkg__") 57 | 58 | cc_library( 59 | name = name, 60 | deps = deps, 61 | implementation_deps = implementation_deps, 62 | srcs = srcs, 63 | data = data, 64 | hdrs = hdrs, 65 | alwayslink = alwayslink, 66 | compatible_with = compatible_with, 67 | copts = copts, 68 | defines = defines, 69 | deprecation = deprecation, 70 | exec_compatible_with = exec_compatible_with, 71 | features = HYPER_TOOLCHAIN_FEATURES + features, 72 | include_prefix = include_prefix, 73 | includes = includes, 74 | licenses = licenses, 75 | linkopts = linkopts, 76 | linkstatic = linkstatic, 77 | local_defines = local_defines, 78 | nocopts = nocopts, 79 | restricted_to = restricted_to, 80 | strip_include_prefix = strip_include_prefix, 81 | tags = tags + ["check-clang-tidy"], 82 | target_compatible_with = target_compatible_with, 83 | testonly = testonly, 84 | textual_hdrs = textual_hdrs, 85 | toolchains = toolchains, 86 | visibility = visibility, 87 | ) 88 | 89 | def hyper_cc_binary( 90 | name, 91 | deps = [], 92 | srcs = [], 93 | data = [], 94 | additional_linker_inputs = [], 95 | args = [], 96 | compatible_with = [], 97 | copts = [], 98 | defines = [], 99 | deprecation = None, 100 | exec_compatible_with = [], 101 | features = [], 102 | licenses = [], 103 | linkopts = [], 104 | linkshared = False, 105 | linkstatic = True, 106 | local_defines = [], 107 | malloc = None, 108 | nocopts = None, 109 | output_licenses = None, 110 | restricted_to = None, 111 | stamp = -1, 112 | tags = [], 113 | target_compatible_with = None, 114 | testonly = False, 115 | toolchains = [], 116 | visibility = [], 117 | sym_file = None): 118 | label_info = get_label_info(name) 119 | full_package_name = "//" + label_info.package_name + ":" + label_info.package_relative_target 120 | if sym_file: 121 | win_def_file = name + ".def" 122 | linux_linker_version_script = name + ".ver" 123 | darwin_exported_symbols_file = name + ".exp" 124 | linux_linker_script = name + ".lds" 125 | 126 | windows_def_file( 127 | name = win_def_file, 128 | sym_file = sym_file, 129 | target_compatible_with = ["@platforms//os:windows"], 130 | ) 131 | 132 | if linkshared: 133 | linux_version_script( 134 | name = linux_linker_version_script, 135 | sym_file = sym_file, 136 | target_compatible_with = ["@platforms//os:linux"], 137 | ) 138 | else: 139 | linux_lds_script( 140 | name = linux_linker_script, 141 | sym_file = sym_file, 142 | target_compatible_with = ["@platforms//os:linux"], 143 | ) 144 | 145 | mac_exported_symbols( 146 | name = darwin_exported_symbols_file, 147 | sym_file = sym_file, 148 | target_compatible_with = ["@platforms//os:osx"], 149 | ) 150 | 151 | deps = deps + (select({ 152 | "//toolchain/platforms:is_linux": [linux_linker_version_script if linkshared else linux_linker_script], 153 | "//toolchain/platforms:is_macos": [darwin_exported_symbols_file], 154 | "//toolchain/platforms:is_windows": [win_def_file] if not linkshared else [], 155 | }) if sym_file else []) + list_for(["//toolchain/platforms:is_windows"], ["//toolchain/toolchain/clang/windows:windows_enable_long_path_support"]) 156 | 157 | data = data + ["//thirdparty/clang:sanitizer_support"] 158 | 159 | # Ensure that non globally enforced binaries can be included in the compilation_database.json 160 | visibility = add_target_visibility(visibility, "//:__pkg__") 161 | 162 | win_def_file = select({ 163 | "//toolchain/platforms:is_linux": None, 164 | "//toolchain/platforms:is_macos": None, 165 | "//toolchain/platforms:is_windows": win_def_file, 166 | }) if linkshared and sym_file else None 167 | 168 | cc_binary( 169 | name = name, 170 | deps = deps, 171 | srcs = srcs, 172 | data = data, 173 | args = args, 174 | compatible_with = compatible_with, 175 | copts = copts, 176 | defines = defines, 177 | deprecation = deprecation, 178 | exec_compatible_with = exec_compatible_with, 179 | features = HYPER_TOOLCHAIN_FEATURES + features, 180 | includes = [], # We explicitly disallow the usage of the `includes` attribute 181 | licenses = licenses, 182 | linkshared = linkshared, 183 | linkstatic = linkstatic, 184 | local_defines = local_defines, 185 | malloc = malloc, 186 | nocopts = nocopts, 187 | output_licenses = output_licenses, 188 | restricted_to = restricted_to, 189 | stamp = stamp, 190 | target_compatible_with = target_compatible_with, 191 | tags = tags + ["check-clang-tidy"], 192 | testonly = testonly, 193 | toolchains = toolchains, 194 | visibility = visibility, 195 | additional_linker_inputs = additional_linker_inputs, 196 | linkopts = linkopts, 197 | win_def_file = win_def_file, 198 | ) 199 | 200 | # An additional target to generate the .dSYM files containing the binaries debug symbols on mac OS 201 | dsym( 202 | name = name + ".dSYM", 203 | binary = name, 204 | # We also need to set the testonly attribute here so it properly 205 | # works in conjuction with testonly binaries 206 | testonly = testonly, 207 | target_compatible_with = (target_compatible_with or []) + [ 208 | "@platforms//os:macos", 209 | ], 210 | # Also inherit the tags from the binary. 211 | # This is important to have the same sandboxing and also 212 | # to propagate tags like manual that disables building of the 213 | # dSYM along with the corresponding binary. 214 | tags = tags + ["manual"], 215 | visibility = visibility, 216 | ) 217 | 218 | def split_positive_negative_gtest_filters(pattern): 219 | """ gtest_filter has positive and negative patterns. 220 | These need to be always grouped, first all positive, then after a single '-' all negative patterns 221 | This function splits the pattern in positive and negative ones. """ 222 | if pattern.startswith("-"): 223 | return ("", pattern[1:]) 224 | 225 | index = pattern.find(":-") 226 | if index == -1: 227 | return (pattern, "") 228 | 229 | return (pattern[:index], pattern[index + 2:]) 230 | 231 | def filter_empty(list): 232 | return [x for x in list if x] 233 | 234 | def merge_gtest_filters(args, pattern): 235 | """ Add `pattern` as gtest filter to `args`. 236 | In case there are already gtest filter present, add `pattern` to any gtest filter argument in `args`. 237 | In case none are present, add a new argument with the filter. 238 | Positive patterns are prepended to existing filters, negative filters appended.""" 239 | merged_args = args 240 | if pattern: 241 | merged_args = [] 242 | pattern_merged = False 243 | for arg in args: 244 | if arg.startswith("--gtest_filter="): 245 | pattern_merged = True 246 | arg_positive, arg_negative = split_positive_negative_gtest_filters(arg[len("--gtest_filter="):]) 247 | pattern_positive, pattern_negative = split_positive_negative_gtest_filters(pattern) 248 | 249 | positive_args = ":".join(filter_empty([arg_positive, pattern_positive])) 250 | negative_args = ":".join(filter_empty([arg_negative, pattern_negative])) 251 | if negative_args: 252 | negative_args = "-" + negative_args 253 | merged_args.append("--gtest_filter=" + ":".join(filter_empty([positive_args, negative_args]))) 254 | else: 255 | merged_args.append(arg) 256 | if not pattern_merged: 257 | merged_args.append("--gtest_filter=" + pattern) 258 | return merged_args 259 | 260 | def hyper_cc_test( 261 | name, 262 | deps = [], 263 | srcs = [], 264 | data = [], 265 | additional_linker_inputs = [], 266 | args = [], 267 | env = {}, 268 | compatible_with = [], 269 | copts = [], 270 | defines = [], 271 | deprecation = None, 272 | exec_compatible_with = [], 273 | exec_properties = {}, 274 | features = [], 275 | flaky = False, 276 | licenses = [], 277 | linkopts = [], 278 | linkstatic = True, 279 | local = False, 280 | local_defines = [], 281 | malloc = None, 282 | nocopts = None, 283 | restricted_to = None, 284 | shard_count = None, 285 | size = "small", 286 | stamp = -1, 287 | tags = [], 288 | target_compatible_with = None, 289 | testonly = True, 290 | # Do not set a default timeout. 291 | # Otherwise this might lead to unexpectedly short timeouts when 292 | # specifiying larger size classes. 293 | # E.g. having short as a default timeout would also limit the timeout 294 | # in the case that someone specifies a test size of medium or larger. 295 | # This would be counter intuitive as it would be different 296 | # from Bazel's default behavior: https://docs.bazel.build/versions/main/test-encyclopedia.html#role-of-the-test-runner 297 | timeout = None, 298 | toolchains = [], 299 | visibility = [], 300 | split_fvt = False, # Create a separate target for FVT tests? 301 | fvt_timeout = None, # Apply a different timeout for FVT tests 302 | split_perf = False, # Create a separate target for Perf tests? 303 | perf_data = []): # Provide data dependency that is only required for perf target 304 | label_info = get_label_info(name) 305 | full_package_name = "//" + label_info.package_name + ":" + label_info.package_relative_target 306 | 307 | # Ensure that every default visbility binary can be included in the compilation_database.json 308 | visibility = add_target_visibility(visibility, "//:__pkg__") 309 | 310 | if len(perf_data) > 0 and not split_perf: 311 | fail("Split perf target was not requested, but perf only data dependency provided anyway") 312 | 313 | # Gtests that include `_FVT` in the name must only run in the fvt (functional verification test) 314 | # test group. When `split_fvt` is enabled, this generates an extra target with suffix `.fvt` and 315 | # adds a `--gtest_filter` that runs only fvt tests with the target. Additionally, `_FVT` tests are 316 | # excluded from the regular test runs. 317 | base_filter = "" 318 | if split_fvt and split_perf: 319 | base_filter = "-*_FVT*:*_Perf*" 320 | elif split_fvt: 321 | base_filter = "-*_FVT*" 322 | elif split_perf: 323 | base_filter = "-*_Perf*" 324 | 325 | test_groups = [([], "", base_filter, [], timeout)] 326 | if split_fvt: 327 | # If no explicit fvt_timeout was given, use the default timeout 328 | test_groups.append((["fvt"], "_FVT", "*_FVT*", [], fvt_timeout or timeout)) 329 | if split_perf: 330 | test_groups.append((["perf"], "_Perf", "*_Perf*", perf_data, timeout)) 331 | 332 | for (group_tags, suffix, pattern, specific_data_dependencies, timeout) in test_groups: 333 | merged_args = merge_gtest_filters(args, pattern) 334 | 335 | cc_test_args = dict( 336 | name = name + suffix, 337 | deps = deps, 338 | srcs = srcs, 339 | data = data + specific_data_dependencies + ["//thirdparty/clang:sanitizer_support"], 340 | args = merged_args, 341 | env = env, 342 | compatible_with = compatible_with, 343 | copts = copts, 344 | defines = defines, 345 | deprecation = deprecation, 346 | exec_compatible_with = exec_compatible_with, 347 | exec_properties = exec_properties, 348 | features = HYPER_TOOLCHAIN_FEATURES + features, 349 | flaky = flaky, 350 | includes = [], # We explicitly disallow the usage of the `includes` attribute 351 | licenses = licenses, 352 | linkstatic = linkstatic, 353 | linkopts = linkopts, 354 | local = local, 355 | local_defines = local_defines, 356 | malloc = malloc, 357 | nocopts = nocopts, 358 | restricted_to = restricted_to, 359 | size = size, 360 | stamp = stamp, 361 | # Only add the clang tidy tag once to avoid running clang tidy multiple times on the same files 362 | tags = tags + (["check-clang-tidy"] if suffix == "" else []) + group_tags, 363 | target_compatible_with = target_compatible_with, 364 | testonly = testonly, 365 | timeout = timeout, 366 | toolchains = toolchains, 367 | visibility = visibility, 368 | ) 369 | 370 | # Only set shard_count when we actually need it to allow bazel to determine a reasonable shard count automatically 371 | # This is done for gtests with the TEST_SHARD_STATUS_FILE automatically. https://docs.bazel.build/versions/master/test-encyclopedia.html#role-of-the-test-runner 372 | if shard_count != None: 373 | cc_test_args["shard_count"] = shard_count 374 | cc_test(**cc_test_args) 375 | 376 | # An additional target to generate the .dSYM files containing the binaries debug symbols on mac OS 377 | dsym( 378 | name = name + suffix + ".dSYM", 379 | binary = name, 380 | # We also need to set the testonly attribute here so it properly 381 | # works in conjuction with testonly binaries 382 | testonly = testonly, 383 | target_compatible_with = (target_compatible_with or []) + [ 384 | "@platforms//os:macos", 385 | ], 386 | # Also inherit the tags from the binary. 387 | # This is important to have the same sandboxing and also 388 | # to propagate tags like manual that disables building of the 389 | # dSYM along with the corresponding binary. 390 | tags = tags + ["manual"], 391 | ) 392 | -------------------------------------------------------------------------------- /toolchain/rules/sysroot/BUILD.bazel: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/salesforce-misc/bazel-cpp-toolchain/0b969b47abd885828ece8006c62e5d7eaa006467/toolchain/rules/sysroot/BUILD.bazel -------------------------------------------------------------------------------- /toolchain/rules/sysroot/centos_sysroot.BUILD: -------------------------------------------------------------------------------- 1 | filegroup( 2 | name = "all_files", 3 | srcs = glob(["**/*"], 4 | exclude = ["BUILD.bazel", "WORKSPACE"]), 5 | visibility = ["//visibility:public"], 6 | ) 7 | -------------------------------------------------------------------------------- /toolchain/rules/sysroot/centos_sysroot.bzl: -------------------------------------------------------------------------------- 1 | def _download_and_extract_rpm_file(repository_ctx, rpm_package_url, rpm_package_sha256): 2 | """ 3 | Given a provided RPM URL this method: 4 | 1. Downloads the given rpm file 5 | 2. Verifies its checksum 6 | 3. Extracts the package into a given target directory 7 | 4. Converts absolute symlinks of the extracted files to relative symlinks, such that no symlink points outside the sysroot 8 | """ 9 | if repository_ctx.attr.python_interpreter: 10 | path_to_python_interpreter = str(repository_ctx.path(repository_ctx.attr.python_interpreter)) 11 | else: 12 | path_to_python_interpreter = "python3" # luck shot in case there is no hermetic pyhton toolchain 13 | rpm_file_name = rpm_package_url.rpartition("/")[2] 14 | rpm_file_absolute_path = str(repository_ctx.path(rpm_file_name)) 15 | 16 | repository_ctx.download(url = rpm_package_url, output = rpm_file_absolute_path, sha256 = rpm_package_sha256) 17 | arguments = [ 18 | path_to_python_interpreter, 19 | str(repository_ctx.path(repository_ctx.attr._extract_rpm_file_and_fix_symlinks)), 20 | "--rpm_file", 21 | rpm_file_absolute_path, 22 | "--destination_folder", 23 | str(repository_ctx.path(".")), 24 | ] 25 | 26 | # Do not print the output of the script to standard out. 27 | # To enable it for debugging purposes set quite=False 28 | # In the default case Bazel prints the whole output to the command line if the 29 | # execution fails (non 0 return code) 30 | result = repository_ctx.execute(arguments, quiet = True) 31 | if result.return_code == 0: 32 | deletion_successful = repository_ctx.delete(rpm_file_absolute_path) 33 | if not deletion_successful: 34 | fail( 35 | "Could not clean up deleted rpm file {rpm_file}".format( 36 | rpm_file = str(repository_ctx.path(rpm_file_absolute_path)), 37 | ), 38 | ) 39 | else: 40 | rpm_file_absolute_path = repository_ctx.path(rpm_file_name) 41 | fail( 42 | "Could not extract rpm file: {rpm_file} downloaded from {url}.\nCall to {command} failed with {return_code}.\nStderr: {stderr}\nStdout: {stdout}".format( 43 | rpm_file = rpm_file_absolute_path, 44 | url = rpm_package_url, 45 | command = " ".join(arguments), 46 | return_code = result.return_code, 47 | stderr = result.stderr, 48 | stdout = result.stdout, 49 | ), 50 | ) 51 | 52 | def _centos_sysroot_impl(repository_ctx): 53 | # Iterates over the provided list of RPM packages and extracts them into a common output folder 54 | for rpm_package_url, rpm_package_sha256 in repository_ctx.attr.rpm_packages.items(): 55 | _download_and_extract_rpm_file( 56 | repository_ctx = repository_ctx, 57 | rpm_package_url = rpm_package_url, 58 | rpm_package_sha256 = rpm_package_sha256, 59 | ) 60 | 61 | # Generates the repositories root BUILD.bazel files as a copy of the provided default build file. 62 | repository_ctx.template("BUILD.bazel", repository_ctx.path(repository_ctx.attr._sysroot_build_file)) 63 | 64 | centos_sysroot = repository_rule( 65 | doc = """ 66 | This repository rule creates a hermetic sysroot consisting of the provided rpm packages. 67 | It purely extracts these rpm files (without running any scripts) and rearranges the contained 68 | symlinks such that no symlink points to a location outside of the sysroot's root folder 69 | """, 70 | implementation = _centos_sysroot_impl, 71 | attrs = { 72 | "_extract_rpm_file_and_fix_symlinks": attr.label(default = "//toolchain/rules/sysroot:extract_rpm_file_and_fix_symlinks.py", doc = "The tool for extracting the rpm files and fixing their symlinks."), 73 | "_sysroot_build_file": attr.label(default = "//toolchain/rules/sysroot:centos_sysroot.BUILD", doc = "The template build file for the sysroot's external repository."), 74 | "python_interpreter": attr.label(allow_single_file = True, doc = "The label of the python interpreter used to call the extraction script."), 75 | "rpm_packages": attr.string_dict(doc = "The list of rpm packages that are used to create the final sysroot. The keys in this dictionary represent the package's URL's. The values contain the corresponding sha256 checksums."), 76 | }, 77 | ) 78 | -------------------------------------------------------------------------------- /toolchain/rules/sysroot/extract_rpm_file_and_fix_symlinks.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import os 3 | import stat 4 | from pathlib import PurePosixPath, PurePath, Path 5 | from typing import Mapping 6 | 7 | import rpmfile 8 | 9 | 10 | class RpmFileMetaDataEntry: 11 | """ 12 | A helper class that stores the meta data of an entry in side the RPM file 13 | """ 14 | path: PurePosixPath 15 | file_mode: int 16 | potential_link_target: PurePosixPath 17 | 18 | def __init__(self, path: PurePosixPath, file_mode: int, potential_link_target: PurePosixPath): 19 | self.path = path 20 | self.file_mode = file_mode 21 | self.potential_link_target = potential_link_target 22 | 23 | def is_directory(self): 24 | return stat.S_ISDIR(self.file_mode) 25 | 26 | def is_symlink(self): 27 | return stat.S_ISLNK(self.file_mode) 28 | 29 | 30 | def _normalize_directory_name(directory: bytes) -> PurePosixPath: 31 | """ 32 | Ensures that we use platform agnostic forward slashes in the processed directory names 33 | :param directory: The raw bytes of the directory name encoded in utf-8 34 | :return: A relative posix Path representation of the provided directory 35 | """ 36 | return str(PurePosixPath(directory.decode("utf-8"))) 37 | 38 | 39 | def _to_uint16(signed_int): 40 | """ 41 | Helper method to convert the signed integer to its actually unsigned 16 bit representation 42 | """ 43 | return signed_int if signed_int > 0 else (signed_int + (1 << 16)) 44 | 45 | 46 | def _rpm_file_meta_data_table(rpm) -> Mapping[PurePosixPath, RpmFileMetaDataEntry]: 47 | """ 48 | Helper method that creates an index of the entries contained in the provided rpm file. 49 | This is important to interpret each entry in a proper way and to finally be able to extract 50 | these entries. 51 | """ 52 | base_names = rpm.headers.get("basenames") 53 | dirindexes = rpm.headers.get("dirindexes") 54 | file_modes = rpm.headers.get("filemodes") 55 | potential_link_targets = rpm.headers.get("filelinktos") 56 | rpm_entries: Mapping[str, RpmFileMetaDataEntry] = {} 57 | 58 | directories = [PurePosixPath(directory.decode("utf-8")) for directory in rpm.headers.get("dirnames")] 59 | 60 | for base_name, dirindex, file_mode, potential_link_target in zip(base_names, dirindexes, file_modes, 61 | potential_link_targets): 62 | path = directories[dirindex] / base_name.decode("utf-8") 63 | 64 | # RPMTAG_FILEMODES corresponds to the st_mode field of the stat struct and is an unsigend integer 65 | file_mode = _to_uint16(file_mode) 66 | link_target = PurePosixPath(potential_link_target.decode("utf-8")) if len(potential_link_target) > 0 else None 67 | 68 | rpm_entries[path] = RpmFileMetaDataEntry(path=path, file_mode=file_mode, potential_link_target=link_target) 69 | 70 | return rpm_entries 71 | 72 | 73 | def extract_rpm_file_and_fix_symlinks(rpm_file: Path, extraction_root: Path) -> None: 74 | """ 75 | Extracts all entries from the provided rpm file and changes absolute symlinks contained in the rpm 76 | file to be relative to the provided extraction_root. 77 | 78 | :param rpm_file: The rpm file that should be extracted 79 | :param extraction_root: The target folder to extract the entries of the rpm file to 80 | """ 81 | with rpmfile.open(str(rpm_file)) as rpm: 82 | rpm_meta_data_table: Mapping[PurePosixPath, RpmFileMetaDataEntry] = _rpm_file_meta_data_table(rpm=rpm) 83 | 84 | for index, entry in enumerate(rpm.getmembers()): 85 | meta_data_entry = rpm_meta_data_table[PurePosixPath("/") / entry.name] 86 | destination_path = extraction_root.joinpath(entry.name) 87 | destination_path.parent.mkdir(parents=True, exist_ok=True) 88 | if meta_data_entry.is_directory(): 89 | print("Creating directory: " + str(destination_path)) 90 | destination_path.mkdir(exist_ok=True) 91 | elif meta_data_entry.is_symlink(): 92 | if destination_path.exists(): 93 | print("Symlink already existed: " + str(destination_path)) 94 | continue 95 | 96 | potential_link_target = meta_data_entry.potential_link_target 97 | if potential_link_target.is_absolute(): 98 | relative_path_to_sysroot = os.path.relpath(extraction_root, destination_path.parent) 99 | link_target = PurePath(str(relative_path_to_sysroot) + "/" + str(potential_link_target)) 100 | else: 101 | link_target = potential_link_target 102 | print("Creating symlink: " + str(destination_path) + " -> " + str(link_target)) 103 | destination_path.symlink_to(link_target) 104 | else: 105 | print("Extracting file: " + str(destination_path)) 106 | with rpm.extractfile(entry.name) as rpmfileobj: 107 | with destination_path.open("wb") as outfile: 108 | outfile.write(rpmfileobj.read()) 109 | 110 | # Apply the file mode bits from the metadata entry. 111 | # This ensures that executables get the needed +x permissions. 112 | os.chmod(destination_path, meta_data_entry.file_mode) 113 | 114 | 115 | def parse_args(): 116 | parser = argparse.ArgumentParser(description=""" 117 | Changes all absolute symlinks in a sysroot to be relative to the sysroot 118 | e.g. 119 | The following symlink /usr/lib/my_lib.so -> /usr/lib/my_lib.so.1 120 | would be converted into 121 | /usr/lib/my_lib.so -> ../../usr/lib/my_lib.so.1 122 | """) 123 | parser.add_argument("--rpm_file", type=Path, help="The rpm file to extract.") 124 | parser.add_argument("--destination_folder", type=Path, help="The directory to extract the files to.") 125 | return parser.parse_args() 126 | 127 | 128 | if __name__ == "__main__": 129 | args = parse_args() 130 | extract_rpm_file_and_fix_symlinks(args.rpm_file, args.destination_folder) 131 | -------------------------------------------------------------------------------- /toolchain/rules/universal_binary.bzl: -------------------------------------------------------------------------------- 1 | # Rules for building macOS universal binaries, including the transition to build the same target for two architectures" 2 | 3 | def _output_name_from_ctx(ctx): 4 | """ Generates the output name of the binary from a context """ 5 | output_name = ctx.attr.output_name 6 | if not output_name: 7 | output_name = ctx.split_attr.dep["x64"][DefaultInfo].files_to_run.executable.basename 8 | return ctx.attr.output_prefix + output_name 9 | 10 | def _impl( 11 | settings, # @unused 12 | attr): # @unused 13 | return { 14 | "x64": { 15 | "//command_line_option:platforms": "//toolchain/platforms:macos_x64", 16 | "//command_line_option:cpu": "darwin", 17 | }, 18 | "arm": { 19 | "//command_line_option:platforms": "//toolchain/platforms:macos_arm", 20 | "//command_line_option:cpu": "darwin_aarch64", 21 | }, 22 | } 23 | 24 | universal_binary_transition = transition( 25 | implementation = _impl, 26 | inputs = [], 27 | outputs = ["//command_line_option:platforms", "//command_line_option:cpu"], 28 | ) 29 | 30 | def _rule_impl(ctx): 31 | target_file_name = _output_name_from_ctx(ctx) 32 | x64_binary = ctx.split_attr.dep["x64"][DefaultInfo].files_to_run.executable 33 | arm_binary = ctx.split_attr.dep["arm"][DefaultInfo].files_to_run.executable 34 | target_file = ctx.actions.declare_file(target_file_name) 35 | lipo_tool = ctx.executable._lipo_tool 36 | 37 | args = ctx.actions.args() 38 | args.add("-create") 39 | args.add("-output") 40 | args.add(target_file) 41 | args.add(x64_binary) 42 | args.add(arm_binary) 43 | 44 | ctx.actions.run( 45 | inputs = [x64_binary, arm_binary], 46 | outputs = [target_file], 47 | executable = lipo_tool, 48 | mnemonic = "GenerateUniversalBinary", 49 | progress_message = "Create Universal Binary \"{target_file_name}\"".format( 50 | target_file_name = target_file_name, 51 | ), 52 | arguments = [args], 53 | ) 54 | 55 | return DefaultInfo(files = depset([target_file]), executable = target_file) 56 | 57 | universal_binary = rule( 58 | implementation = _rule_impl, 59 | attrs = { 60 | "dep": attr.label( 61 | cfg = universal_binary_transition, 62 | ), 63 | "output_name": attr.string( 64 | default = "", 65 | doc = "The name/path of the binary to produce.", 66 | ), 67 | "output_prefix": attr.string( 68 | default = "", 69 | doc = "The prefix for the output path to use. Must end with a slash if you want to create the binary in a subdirectory.", 70 | ), 71 | "_lipo_tool": attr.label( 72 | executable = True, 73 | cfg = "exec", 74 | allow_files = True, 75 | default = Label("@clang_darwin//:llvm-lipo"), 76 | ), 77 | # This attribute is required to use transitions. 78 | # It allowlists usage of this rule. For more information, see 79 | # https://bazel.build/extending/config#user-defined-transitions 80 | "_allowlist_function_transition": attr.label( 81 | default = "@bazel_tools//tools/allowlists/function_transition_allowlist", 82 | ), 83 | }, 84 | ) 85 | -------------------------------------------------------------------------------- /toolchain/settings/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@bazel_skylib//rules:common_settings.bzl", "bool_flag", "string_flag") 2 | 3 | # The right way to react on user-input on the command line is to use Starlark configurations: 4 | # Starlark configurations are basically rules that can react on user input on the command line (arbitrary values). 5 | # These values can be set from the command line with `--//label/path:name=xyz`. 6 | # The Skylib provides rules for basic settings like bools, integers and strings that don't require conplex logic. 7 | # With `config_setting` a specific configuration value can be mapped to a condition to be used in `select`. 8 | 9 | # See these wiki pages for details: 10 | # https://docs.bazel.build/versions/master/configurable-attributes.html 11 | # https://docs.bazel.build/versions/master/skylark/config.html 12 | 13 | bool_flag( 14 | name = "sanitizer", 15 | build_setting_default = False, 16 | ) 17 | 18 | config_setting( 19 | name = "is_sanitizer", 20 | flag_values = {":sanitizer": "True"}, 21 | visibility = ["//visibility:public"], 22 | ) 23 | -------------------------------------------------------------------------------- /toolchain/tests/app_with_transitive_deps/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("//toolchain/rules:dsym.bzl", "dsym") 2 | 3 | cc_test( 4 | name = "app_with_transitive_static_deps", 5 | srcs = ["main.cpp"], 6 | linkstatic = True, 7 | visibility = ["//:__pkg__"], 8 | deps = ["//toolchain/tests/library_depending_on_other_library"], 9 | ) 10 | 11 | cc_test( 12 | name = "app_with_transitive_shared_deps", 13 | srcs = ["main.cpp"], 14 | linkstatic = False, 15 | tags = ["manual"], 16 | visibility = ["//:__pkg__"], 17 | deps = ["//toolchain/tests/library_depending_on_other_library"], 18 | ) 19 | -------------------------------------------------------------------------------- /toolchain/tests/app_with_transitive_deps/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | int main() { 6 | print_hello_library_world(); 7 | return 0; 8 | } 9 | -------------------------------------------------------------------------------- /toolchain/tests/application_with_library/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_pkg//pkg:pkg.bzl", "pkg_zip") 2 | load("@rules_pkg//pkg:mappings.bzl", "strip_prefix") 3 | 4 | cc_test( 5 | name = "application_with_static_library", 6 | srcs = ["main.cpp"], 7 | linkstatic = True, 8 | visibility = ["//:__pkg__"], 9 | deps = ["//toolchain/tests/simple_library"], 10 | ) 11 | 12 | cc_test( 13 | name = "application_with_shared_library", 14 | srcs = ["main.cpp"], 15 | linkstatic = False, 16 | tags = ["manual"], 17 | visibility = ["//:__pkg__"], 18 | deps = ["//toolchain/tests/simple_library"], 19 | ) 20 | 21 | pkg_zip( 22 | name = "example-package", 23 | srcs = [ 24 | ":application_with_shared_library", 25 | ], 26 | package_file_name = "example-package-{os}-{architecture}-{build_type}.zip", 27 | package_variables = "//toolchain/platforms:default_zip_variables", 28 | strip_prefix = strip_prefix.from_pkg(), 29 | visibility = ["//scripts:__subpackages__"], 30 | ) 31 | -------------------------------------------------------------------------------- /toolchain/tests/application_with_library/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | int main() { 6 | print("World"); 7 | return 0; 8 | } 9 | -------------------------------------------------------------------------------- /toolchain/tests/cpp_version_check/BUILD.bazel: -------------------------------------------------------------------------------- 1 | # For values of __cplusplus see https://en.cppreference.com/w/cpp/preprocessor/replace#Predefined_macros 2 | 3 | cc_test( 4 | name = "cpp_version_check_cpp11", 5 | srcs = ["main.cpp"], 6 | features = ["c++11"], 7 | linkstatic = True, 8 | local_defines = ["EXPECTED_CPP_VERSION=201103L"], 9 | # MSVC Compiler + Runtime don’t support explicit C++11 (even with clang-cl) 10 | target_compatible_with = ["@//toolchain/platforms:is_posix"], 11 | visibility = ["//:__pkg__"], 12 | ) 13 | 14 | cc_test( 15 | name = "cpp_version_check_cpp14", 16 | srcs = ["main.cpp"], 17 | features = ["c++14"], 18 | linkstatic = True, 19 | local_defines = ["EXPECTED_CPP_VERSION=201402L"], 20 | visibility = ["//:__pkg__"], 21 | ) 22 | 23 | cc_test( 24 | name = "cpp_version_check_cpp23", 25 | srcs = ["main.cpp"], 26 | features = ["c++23"], 27 | linkstatic = True, 28 | local_defines = ["EXPECTED_CPP_VERSION=202302L"], 29 | visibility = ["//:__pkg__"], 30 | ) 31 | 32 | cc_test( 33 | name = "cpp_version_check_default", 34 | srcs = ["main.cpp"], 35 | linkstatic = True, 36 | local_defines = ["EXPECTED_CPP_VERSION=202302L"], 37 | visibility = ["//:__pkg__"], 38 | ) 39 | -------------------------------------------------------------------------------- /toolchain/tests/cpp_version_check/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | auto expected_version = EXPECTED_CPP_VERSION; 6 | auto actual_version = __cplusplus; 7 | 8 | if (actual_version != expected_version) { 9 | std::cerr << "This test file was compiled with a different C++ version than speficied via the Bazel toolchain feature. This is probably caused by a bug in the toolchain." << std::endl; 10 | std::cerr << "Expected value of __cplusplus: " << expected_version << std::endl; 11 | std::cerr << "Actual value of __cplusplus: " << actual_version << std::endl; 12 | return 1; 13 | } 14 | return 0; 15 | } 16 | -------------------------------------------------------------------------------- /toolchain/tests/library_depending_on_other_library/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_cc//cc:defs.bzl", "cc_library") 2 | 3 | cc_library( 4 | name = "library_depending_on_other_library", 5 | srcs = ["hello_world.cpp"], 6 | hdrs = ["hello_world.hpp"], 7 | strip_include_prefix = "/toolchain/tests", 8 | visibility = [ 9 | "//:__pkg__", 10 | "//toolchain/tests:__subpackages__", 11 | ], 12 | deps = ["//toolchain/tests/simple_library"], 13 | ) 14 | -------------------------------------------------------------------------------- /toolchain/tests/library_depending_on_other_library/hello_world.cpp: -------------------------------------------------------------------------------- 1 | #include "library_depending_on_other_library/hello_world.hpp" 2 | 3 | #include 4 | 5 | void print_hello_library_world() { 6 | print("library World"); 7 | } 8 | -------------------------------------------------------------------------------- /toolchain/tests/library_depending_on_other_library/hello_world.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifdef _WIN32 4 | #define DLL_EXPORT __declspec(dllexport) 5 | #else 6 | #define DLL_EXPORT __attribute__((visibility("default"))) 7 | #endif 8 | 9 | DLL_EXPORT void print_hello_library_world(); 10 | -------------------------------------------------------------------------------- /toolchain/tests/sanitizers/BUILD.bazel: -------------------------------------------------------------------------------- 1 | exports_files(["sanitizer_test.py"]) 2 | -------------------------------------------------------------------------------- /toolchain/tests/sanitizers/address/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("//toolchain/tests/sanitizers:sanitizer_test.bzl", "sanitizer_test") 2 | 3 | # Expected output example 4 | # ================== 5 | # Without the ASAN symbolizer or proper symbols the stacks do not contain funciton information: 6 | # #0 0x2f4867 (bazel/bazel_user_root/fff4f35a9591257e13578c09f3d662aa/execroot/__main__/bazel-out/k8-fastbuild/bin/bazel/toolchain/tests/address_sanitizer_stack_trace/address_sanitizer_overflow+0x2f4867) 7 | # #1 0x2f493d (bazel/bazel_user_root/fff4f35a9591257e13578c09f3d662aa/execroot/__main__/bazel-out/k8-fastbuild/bin/bazel/toolchain/tests/address_sanitizer_stack_trace/address_sanitizer_overflow+0x2f493d) 8 | # 9 | # With the ASAN symbolizer and proper symbols we see this: 10 | # #0 0x2f4867 in overflow(int) (bazel/bazel_user_root/fff4f35a9591257e13578c09f3d662aa/execroot/__main__/bazel-out/k8-fastbuild/bin/bazel/toolchain/tests/address_sanitizer_stack_trace/address_sanitizer_overflow+0x2f4867) 11 | # #1 0x2f493d in main (bazel/bazel_user_root/fff4f35a9591257e13578c09f3d662aa/execroot/__main__/bazel-out/k8-fastbuild/bin/bazel/toolchain/tests/address_sanitizer_stack_trace/address_sanitizer_overflow+0x2f493d) 12 | sanitizer_test( 13 | name = "address", 14 | executable_cpp_sources = ["intentional_overflow.cpp"], 15 | expected_errors = [ 16 | "#0\\ 0[xX][0-9a-fA-F]+\\ in\\ overflow\\(int\\)", 17 | "#1\\ 0[xX][0-9a-fA-F]+\\ in main", 18 | ], 19 | # Specifically exclude other sanitizers so this test works with all targets and those configs 20 | # However, UB and ASAN should work together 21 | sanitizers = 22 | [ 23 | "address_sanitizer", 24 | "undefined_behavior_sanitizer", 25 | "-memory_sanitizer", 26 | "-thread_sanitizer", 27 | ], 28 | target_compatible_with = ["@//toolchain/platforms:is_posix"], 29 | ) 30 | -------------------------------------------------------------------------------- /toolchain/tests/sanitizers/address/intentional_overflow.cpp: -------------------------------------------------------------------------------- 1 | // Intentionally overflowing test to ensure we get stack traces 2 | // Based on https://github.com/google/sanitizers/wiki/AddressSanitizerExampleStackOutOfBounds 3 | // However, the overflow is moved to a second function to verify stack traces with ASAN 4 | __attribute__((optnone)) int overflow(int argc) { 5 | int stack_array[100]; 6 | stack_array[1] = 0; 7 | return stack_array[argc + 100]; // BOOM 8 | } 9 | 10 | __attribute__((optnone)) int main(int argc, [[maybe_unused]] char** argv) { 11 | return overflow(argc); 12 | } 13 | -------------------------------------------------------------------------------- /toolchain/tests/sanitizers/fuzzer/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("//toolchain/tests/sanitizers:sanitizer_test.bzl", "sanitizer_test") 2 | 3 | # Verify that when "fuzzer-no-link" is defined we hit the deadly signal abort 4 | sanitizer_test( 5 | name = "basic_fuzzer_with_fuzzer_no_link", 6 | executable_cpp_sources = ["basic_fuzzer.cpp"], 7 | expected_errors = [ 8 | "deadly signal", 9 | ], 10 | # Specifically exclude other sanitizers so this test works with all targets and those configs 11 | sanitizers = 12 | [ 13 | "address_sanitizer", 14 | "-undefined_behavior_sanitizer", 15 | "-memory_sanitizer", 16 | "-thread_sanitizer", 17 | "fuzzer", 18 | "fuzzer-no-link", 19 | ], 20 | target_compatible_with = ["@//toolchain/platforms:is_posix"], 21 | ) 22 | 23 | # Verify that when "fuzzer-no-link" is not defined we hit a buffer overflow instead 24 | sanitizer_test( 25 | name = "basic_fuzzer_without_fuzzer_no_link", 26 | executable_cpp_sources = ["basic_fuzzer.cpp"], 27 | expected_errors = [ 28 | "heap-buffer-overflow", 29 | ], 30 | # Specifically exclude other sanitizers so this test works with all targets and those configs 31 | sanitizers = 32 | [ 33 | "address_sanitizer", 34 | "-undefined_behavior_sanitizer", 35 | "-memory_sanitizer", 36 | "-thread_sanitizer", 37 | "fuzzer", 38 | "-fuzzer-no-link", # Don't define FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION 39 | ], 40 | target_compatible_with = ["@//toolchain/platforms:is_posix"], 41 | ) 42 | -------------------------------------------------------------------------------- /toolchain/tests/sanitizers/fuzzer/basic_fuzzer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | extern "C" int LLVMFuzzerTestOneInput([[maybe_unused]] const uint8_t* data, [[maybe_unused]] size_t size) { 5 | #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION 6 | abort(); 7 | #else 8 | return data[size + 1]; 9 | #endif 10 | } 11 | -------------------------------------------------------------------------------- /toolchain/tests/sanitizers/memory/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("//toolchain/tests/sanitizers:sanitizer_test.bzl", "sanitizer_test") 2 | 3 | # Expected output example 4 | # ================== 5 | # =15==WARNING: MemorySanitizer: use-of-uninitialized-value 6 | # #0 0x2ce20a in main (bazel/bazel_user_root/fff4f35a9591257e13578c09f3d662aa/execroot/__main__/bazel-out/k8-fastbuild/bin/toolchain/tests/memory_sanitizer_stack_trace/intentional_unitialized_usage+0x2ce20a) 7 | # #1 0x7f2dfea5bb96 in __libc_start_main /build/glibc-OTsEL5/glibc-2.27/csu/../csu/libc-start.c:310 8 | # #2 0x255029 in _start (bazel/bazel_user_root/fff4f35a9591257e13578c09f3d662aa/execroot/__main__/bazel-out/k8-fastbuild/bin/toolchain/tests/memory_sanitizer_stack_trace/intentional_unitialized_usage+0x255029) 9 | 10 | # SUMMARY: MemorySanitizer: use-of-uninitialized-value (bazel/bazel_user_root/fff4f35a9591257e13578c09f3d662aa/execroot/__main__/bazel-out/k8-fastbuild/bin/toolchain/tests/memory_sanitizer_stack_trace/intentional_unitialized_usage+0x2ce20a) in main 11 | sanitizer_test( 12 | name = "memory", 13 | executable_cpp_sources = ["intentional_uninitialized_usage.cpp"], 14 | expected_errors = [ 15 | "in\\ main", 16 | ], 17 | sanitizers = [ 18 | "-address_sanitizer", 19 | "-undefined_behavior_sanitizer", 20 | "memory_sanitizer", 21 | "-thread_sanitizer", 22 | ], 23 | target_compatible_with = ["//toolchain/platforms:is_linux"], 24 | ) 25 | -------------------------------------------------------------------------------- /toolchain/tests/sanitizers/memory/intentional_uninitialized_usage.cpp: -------------------------------------------------------------------------------- 1 | // Based on https://github.com/google/sanitizers/wiki/MemorySanitizer#using-memorysanitizer 2 | #include 3 | 4 | int main(int argc, [[maybe_unused]] char** argv) { 5 | int* a = new int[10]; 6 | a[5] = 0; 7 | if (a[argc]) 8 | printf("xx\n"); 9 | return 0; 10 | } 11 | -------------------------------------------------------------------------------- /toolchain/tests/sanitizers/sanitizer_test.bzl: -------------------------------------------------------------------------------- 1 | load("@rules_python//python:defs.bzl", "py_test") 2 | load("//toolchain/helper:condition_helpers.bzl", "list_for") 3 | load("//toolchain/rules:hyper_cc.bzl", "hyper_cc_binary") 4 | 5 | def sanitizer_test(name, executable_cpp_sources, expected_errors, sanitizers, target_compatible_with = []): 6 | binary_name = name + "_executable" 7 | hyper_cc_binary( 8 | name = binary_name, 9 | srcs = executable_cpp_sources, 10 | features = list_for(["//toolchain/platforms:is_linux", "//toolchain/platforms:is_macos"], sanitizers), 11 | target_compatible_with = target_compatible_with, 12 | ) 13 | 14 | test_arguments = ["--executable_path", "$(rootpath " + binary_name + ")"] 15 | for error in expected_errors: 16 | test_arguments += ["--expected_stack_line_regex", error] 17 | 18 | py_test( 19 | name = name, 20 | srcs = ["//toolchain/tests/sanitizers:sanitizer_test.py"], 21 | main = "//toolchain/tests/sanitizers:sanitizer_test.py", 22 | # ASAN is linked dynamically on macOS, thus we need to add the dynamic ASAN library to the sandbox 23 | data = [":" + binary_name] + select({ 24 | "//toolchain/platforms:is_macos": ["@clang_darwin//:libsan"], 25 | "//conditions:default": [], 26 | }), 27 | args = test_arguments, 28 | target_compatible_with = target_compatible_with, 29 | ) 30 | -------------------------------------------------------------------------------- /toolchain/tests/sanitizers/sanitizer_test.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import platform 3 | import re 4 | import subprocess 5 | 6 | from pathlib import Path 7 | from typing import List 8 | 9 | 10 | def check_sanitizer_output(executable: Path, expected_stack_line_regexes: List[str]): 11 | """ Verify that the executable fails and fails with the expected errors. This helps us verify that each sanitizer prints a developer friendly stack trace that is actionable. """ 12 | 13 | assert len(expected_stack_line_regexes) != 0 14 | assert platform.system() != "Windows", "The Bazel toolchain currently does not support sanitizers on Windows." 15 | 16 | try: 17 | subprocess.check_output([executable], stderr=subprocess.STDOUT) 18 | except subprocess.CalledProcessError as exc: 19 | # Process is expected to fail, save the output for verification 20 | output = exc.output.decode("utf-8") 21 | else: 22 | assert False, "Sanitizer didn't raise error." 23 | 24 | for expected_stack_line_regex in expected_stack_line_regexes: 25 | assert re.search(expected_stack_line_regex, output), f"Did not find error regex ({expected_stack_line_regex}) information in output.\nOutput:{output}" 26 | 27 | 28 | if __name__ == "__main__": 29 | parser = argparse.ArgumentParser() 30 | parser.add_argument('--executable_path') 31 | parser.add_argument('--expected_stack_line_regex', nargs='+') 32 | args = parser.parse_args() 33 | check_sanitizer_output(args.executable_path, args.expected_stack_line_regex) 34 | -------------------------------------------------------------------------------- /toolchain/tests/sanitizers/thread/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("//toolchain/tests/sanitizers:sanitizer_test.bzl", "sanitizer_test") 2 | 3 | # Expected output example 4 | # ================== 5 | # WARNING: ThreadSanitizer: data race (pid=15) 6 | # Write of size 4 at 0x000000d1e1b8 by thread T2: 7 | # #0 Thread2(void*) (intentional_data_race+0x2e9319) 8 | 9 | # Previous write of size 4 at 0x000000d1e1b8 by thread T1: 10 | # #0 Thread1(void*) (intentional_data_race+0x2e92b9) 11 | 12 | # Location is global 'Global' of size 4 at 0x000000d1e1b8 (intentional_data_race+0x000000d1e1b8) 13 | 14 | # Thread T2 (tid=18, running) created by main thread at: 15 | # #0 pthread_create (intentional_data_race+0x25a80b) 16 | # #1 main (intentional_data_race+0x2e9386) 17 | 18 | # Thread T1 (tid=17, finished) created by main thread at: 19 | # #0 pthread_create (intentional_data_race+0x25a80b) 20 | # #1 main (intentional_data_race+0x2e936b) 21 | 22 | # SUMMARY: ThreadSanitizer: data race (bazel/bazel_user_root/fff4f35a9591257e13578c09f3d662aa/execroot/__main__/bazel-out/k8-fastbuild/bin/toolchain/tests/sanitizers/thread/intentional_data_race+0x2e9319) in Thread2(void*) 23 | # ================== 24 | # ThreadSanitizer: reported 1 warnings 25 | sanitizer_test( 26 | name = "thread", 27 | executable_cpp_sources = ["intentional_data_race.cpp"], 28 | expected_errors = [ 29 | "#0 pthread_create", 30 | "#[0-9a-fA-F]\\ main", 31 | ], 32 | # Specifically exclude other sanitizers so this test works with all targets and those configs 33 | sanitizers = 34 | [ 35 | "-address_sanitizer", 36 | "-undefined_behavior_sanitizer", 37 | "-memory_sanitizer", 38 | "thread_sanitizer", 39 | ], 40 | target_compatible_with = ["@//toolchain/platforms:is_posix"], 41 | ) 42 | -------------------------------------------------------------------------------- /toolchain/tests/sanitizers/thread/intentional_data_race.cpp: -------------------------------------------------------------------------------- 1 | #ifndef CONFIG_WINDOWS 2 | #include 3 | #include 4 | // Uninitialized global 5 | int global; 6 | __attribute__((optnone)) int main() { 7 | // Creates race as access to global is not synchronized 8 | // Note: We perform updates for 500ms, because thread sanitizer has an intentional 9 | // trade-off between performance and some false negatives (see https://github.com/google/sanitizers/issues/1576). 10 | // If a single update is done by each thread, we'll see a few instances where the race is not detected. By doing many 11 | // updates, we reduce the false negative likelihood significantly 12 | const auto start = std::chrono::steady_clock::now(); 13 | std::thread t1([&] {do {++global;} while (std::chrono::steady_clock::now() - start < std::chrono::milliseconds{500}); }); 14 | std::thread t2([&] {do {--global;} while (std::chrono::steady_clock::now() - start < std::chrono::milliseconds{500}); }); 15 | t1.join(); 16 | t2.join(); 17 | return 0; 18 | } 19 | #else 20 | int main() { 21 | } 22 | #endif 23 | -------------------------------------------------------------------------------- /toolchain/tests/simple_application/BUILD.bazel: -------------------------------------------------------------------------------- 1 | # This is a small C++ "Hello World" application to easily test the C++ toolchain 2 | 3 | load("@bazel_skylib//rules:native_binary.bzl", "native_test") 4 | load("//toolchain/rules:universal_binary.bzl", "universal_binary") 5 | 6 | # Statically linked binary for test and for universal binary 7 | cc_binary( 8 | name = "simple_application_static", 9 | srcs = ["main.cpp"], 10 | linkstatic = True, 11 | visibility = ["//:__pkg__"], 12 | ) 13 | 14 | # Test for statically linked binary using the existing binary from above 15 | native_test( 16 | name = "simple_application_static_test", 17 | src = ":simple_application_static", 18 | out = "simple_application_static_test", 19 | visibility = ["//:__pkg__"], 20 | ) 21 | 22 | # Test for dynamically linked binary, built as part of the rule 23 | cc_test( 24 | name = "simple_application_link_dynamic", 25 | srcs = ["main.cpp"], 26 | linkstatic = False, 27 | tags = ["manual"], 28 | visibility = ["//:__pkg__"], 29 | ) 30 | 31 | # Universal binary using the statically linked binary 32 | universal_binary( 33 | name = "simple_application_universal", 34 | dep = ":simple_application_static", 35 | output_prefix = "universal/", 36 | target_compatible_with = ["@platforms//os:osx"], 37 | ) 38 | 39 | # Test for statically linked binary 40 | native_test( 41 | name = "simple_application_universal_test", 42 | src = ":simple_application_universal", 43 | out = "simple_application_universal_test", 44 | target_compatible_with = ["@platforms//os:osx"], 45 | visibility = ["//:__pkg__"], 46 | ) 47 | -------------------------------------------------------------------------------- /toolchain/tests/simple_application/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | std::cout << "Hello Excel!" << std::endl; 5 | return 0; 6 | } 7 | -------------------------------------------------------------------------------- /toolchain/tests/simple_gtest/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_cc//cc:defs.bzl", "cc_test") 2 | 3 | cc_test( 4 | name = "simple_gtest_dynamic_linking", 5 | size = "small", 6 | srcs = [ 7 | "simple_gtest_main.cpp", 8 | "simple_gtest_tests.cpp", 9 | ], 10 | linkstatic = 0, 11 | tags = ["manual"], 12 | visibility = ["//:__pkg__"], 13 | deps = [ 14 | "@googletest//:gtest", 15 | ], 16 | ) 17 | 18 | cc_test( 19 | name = "simple_gtest_static_linking", 20 | size = "small", 21 | srcs = [ 22 | "simple_gtest_main.cpp", 23 | "simple_gtest_tests.cpp", 24 | ], 25 | linkstatic = 1, 26 | visibility = ["//:__pkg__"], 27 | deps = [ 28 | "@googletest//:gtest", 29 | ], 30 | ) 31 | -------------------------------------------------------------------------------- /toolchain/tests/simple_gtest/simple_gtest_main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char* argv[]) { 4 | testing::InitGoogleTest(&argc, argv); 5 | return RUN_ALL_TESTS(); 6 | } 7 | -------------------------------------------------------------------------------- /toolchain/tests/simple_gtest/simple_gtest_tests.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | TEST(BAZEL_TOOLCHAIN_TESTS, SIMPLE_GTEST) { 4 | EXPECT_EQ(0, 0); 5 | } 6 | -------------------------------------------------------------------------------- /toolchain/tests/simple_library/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_cc//cc:defs.bzl", "cc_library") 2 | 3 | cc_library( 4 | name = "simple_library", 5 | srcs = ["lib.cpp"], 6 | hdrs = ["lib.h"], 7 | strip_include_prefix = "/toolchain/tests", 8 | visibility = [ 9 | "//:__pkg__", 10 | "//toolchain/tests:__subpackages__", 11 | ], 12 | ) 13 | -------------------------------------------------------------------------------- /toolchain/tests/simple_library/lib.cpp: -------------------------------------------------------------------------------- 1 | #include "simple_library/lib.h" 2 | 3 | #include 4 | 5 | void print(const char* message) { 6 | std::cout << "Print " << message << "!" << std::endl; 7 | } 8 | -------------------------------------------------------------------------------- /toolchain/tests/simple_library/lib.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifdef _WIN32 4 | #define DLL_EXPORT __declspec(dllexport) 5 | #else 6 | #define DLL_EXPORT __attribute__((visibility("default"))) 7 | #endif 8 | 9 | DLL_EXPORT void print(const char* message); 10 | --------------------------------------------------------------------------------