| // Copyright 2023 The Bazel Authors. All rights reserved. | |
| // | |
| // Licensed under the Apache License, Version 2.0 (the "License"); | |
| // you may not use this file except in compliance with the License. | |
| // You may obtain a copy of the License at | |
| // | |
| // http://www.apache.org/licenses/LICENSE-2.0 | |
| // | |
| // Unless required by applicable law or agreed to in writing, software | |
| // distributed under the License is distributed on an "AS IS" BASIS, | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| // See the License for the specific language governing permissions and | |
| // limitations under the License. | |
| #include <iostream> | |
| #define STRINGIFY(x) #x | |
| #define TO_STRING(x) STRINGIFY(x) | |
| #ifdef COMPILER | |
| namespace { | |
| constexpr bool StrEq(const char* a, const char* b) { | |
| return *a == *b && (*a == '\0' || StrEq(a + 1, b + 1)); | |
| } | |
| // The compiler //cc/compiler:compiler reports, i.e. the `compiler` attribute | |
| // of the resolved cc_toolchain_config. | |
| constexpr const char* kDeclaredCompiler = TO_STRING(COMPILER); | |
| #if defined(__clang__) | |
| constexpr bool kIsClang = true; | |
| #else | |
| constexpr bool kIsClang = false; | |
| #endif | |
| // clang-cl emulates the MSVC command line and ABI, so it defines _MSC_VER as | |
| // well as __clang__. cl.exe defines only _MSC_VER. | |
| #if defined(_MSC_VER) | |
| constexpr bool kIsMsvcCompatible = true; | |
| #else | |
| constexpr bool kIsMsvcCompatible = false; | |
| #endif | |
| // Cross-check the declared compiler against what really compiled this file, so | |
| // a toolchain cannot claim one compiler while running another. This is what | |
| // catches USE_CLANG_CL=1 swapping the toolchain over to clang-cl while it | |
| // still declares itself msvc-cl. | |
| // | |
| // Stated as implications keyed off the declared name rather than deriving an | |
| // expected name from the macros: that way only the two labels this repo emits | |
| // are constrained, and any other value -- a third-party toolchain's, or one | |
| // that does not match a //cc/compiler config_setting at all -- is left alone | |
| // instead of failing the build. | |
| static_assert(!StrEq(kDeclaredCompiler, "msvc-cl") || !kIsClang, | |
| "Toolchain declares msvc-cl, but clang compiled this file."); | |
| static_assert(!StrEq(kDeclaredCompiler, "clang-cl") || | |
| (kIsClang && kIsMsvcCompatible), | |
| "Toolchain declares clang-cl, but clang in MSVC-compatible mode " | |
| "is not what compiled this file."); | |
| } // namespace | |
| #endif // COMPILER | |
| int main() { | |
| std::cout << "Hello, " << TO_STRING(COMPILER) << "!" << std::endl; | |
| } |