Search code examples
c++bazelbazel-cpp

LLVM and GCC toolchain selection


I am using the LLVM toolchain for Bazel (with Bazel 7.0.2 on Ubuntu 22.04) this way:

MODULE.bazel:

module(name = "gcc_llvm_test")

bazel_dep(name = "toolchains_llvm", version = "0.10.3")
git_override(
    module_name = "toolchains_llvm",
    commit = "bba94f8138ab454d70afcd263788b34e2801e2ba",
    remote = "https://github.com/bazel-contrib/toolchains_llvm.git",
)

bazel_dep(name = "rules_foreign_cc", version = "0.10.1")

llvm = use_extension("@toolchains_llvm//toolchain/extensions:llvm.bzl", "llvm")
llvm.toolchain(
   llvm_version = "16.0.0",
)

use_repo(llvm, "llvm_toolchain")

register_toolchains("@llvm_toolchain//:all")

BUILD.bazel:

cc_binary(
    name = "hello_world",
    srcs = ["main.cpp"],
)

main.cpp:

#include <iostream>
#include <string>
#include <sstream>

std::string ver_string(int a, int b, int c) {
  std::ostringstream ss;
  ss << a << '.' << b << '.' << c;
  return ss.str();
}

std::string true_cxx =
#ifdef __clang__
   "clang++";
#else
   "g++";
#endif

  std::string true_cxx_ver =
#ifdef __clang__
    ver_string(__clang_major__, __clang_minor__, __clang_patchlevel__);
#else
    ver_string(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__);
#endif

int main() {
    std::cout << "Hello, World!" << std::endl;

    std::cout << "true_cxx: " << true_cxx << std::endl;
    std::cout << "true_cxx_ver: " << true_cxx_ver << std::endl;
    return 0;
}

When I run bazel run //:hello_world I get the following output

Hello, World!
true_cxx: clang++
true_cxx_ver: 16.0.0

If I uncomment the line register_toolchains("@llvm_toolchain//:all") I get:

Hello, World!
true_cxx: g++
true_cxx_ver: 11.4.0

This makes perfect sense. How can I switch between both toolchains without having to comment the toolchain out? I think the desired solution would be a Bazel config placed in .bazelrc, e.g.

build:gcc --some_flags
build:clang16 --some_other_flags

In an earlier version of these toolchain rules and Bazel 6.0 I had this config:

build:clang14 --incompatible_enable_cc_toolchain_resolution

Running with --incompatible_enable_cc_toolchain_resolution selected LLVM/CLang compiler for me and without it, I had good old GCC. In Bazel 7.0.0 the flag is set by default. I am a bit unsure what now is the proper way to select a C++ toolchain. Any help is appreciated!


Solution

  • In a narrow sense, --noincompatible_enable_cc_toolchain_resolution will get you the pre-Bazel 7.0.0 default behavior, which sounds like you have configured to use GCC.

    If you want something that will continue working after the flag is removed (see bazel#7260 for the current status), you'll need to migrate to platforms. How to do that depends on which GCC toolchain you're using. Generally you need to:

    1. Ensure there's a constraint which each of your toolchains is target_compatible_with different values of
    2. Create platforms that are compatible with each of your toolchains using that constraint
    3. Specify the platform to build using the --platforms flag