| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264 |
- // Part of the Carbon Language project, under the Apache License v2.0 with LLVM
- // Exceptions. See /LICENSE for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- #include <unistd.h>
- #include <cstdlib>
- #include <cstring>
- #include <filesystem>
- #include <memory>
- #include <optional>
- #include <string>
- #include <system_error>
- #include <utility>
- #include "common/bazel_working_dir.h"
- #include "common/check.h"
- #include "common/command_line.h"
- #include "common/error.h"
- #include "common/exe_path.h"
- #include "common/filesystem.h"
- #include "common/init_llvm.h"
- #include "common/raw_string_ostream.h"
- #include "common/version.h"
- #include "llvm/ADT/ArrayRef.h"
- #include "llvm/ADT/STLExtras.h"
- #include "llvm/ADT/SmallVector.h"
- #include "llvm/ADT/StringRef.h"
- #include "llvm/Support/FormatVariadic.h"
- #include "llvm/Support/ThreadPool.h"
- #include "llvm/Support/Threading.h"
- #include "llvm/Support/VirtualFileSystem.h"
- #include "llvm/Support/raw_ostream.h"
- #include "llvm/TargetParser/Triple.h"
- #include "toolchain/base/install_paths.h"
- #include "toolchain/driver/clang_runner.h"
- #include "toolchain/driver/clang_runtimes.h"
- #include "toolchain/driver/codegen_options.h"
- #include "toolchain/driver/runtimes_cache.h"
- #include "tools/cpp/runfiles/runfiles.h"
- namespace Carbon {
- namespace {
- struct Options {
- static const CommandLine::CommandInfo Info;
- auto Build(CommandLine::CommandBuilder& b) -> void;
- bool verbose = false;
- bool force = false;
- bool threads = true;
- llvm::StringRef directory;
- CodegenOptions codegen_options;
- };
- } // namespace
- // Note that this is not constexpr so that it can include information generated
- // in separate translation units and potentially overridden at link time in the
- // version string.
- const CommandLine::CommandInfo Options::Info = {
- .name = "bazel_build_clang_runtimes",
- .version = Version::ToolchainInfo,
- .help = R"""(
- A dedicated tool for use with Bazel to build Carbon's _Clang_ runtimes.
- This works similarly to the Carbon `build-runtimes` subcommand with some key
- differences:
- 1) It only builds the Clang runtimes, not any Carbon-specific runtimes. This is
- important due to the next point...
- 2) It is a stand-alone command with minimal dependencies on Carbon to allow
- Bazel to cache the Clang-based runtimes across most changes to the Carbon
- toolchain when the LLVM version stays the same.
- 3) It removes any symlinks in the built runtimes tree into other parts of the
- installation that are not generated by this command. This allows a Bazel rule
- to re-create those in using Bazel-specific logic that connects those parts of
- the runtimes tree to their respective inputs.
- )""",
- };
- auto Options::Build(CommandLine::CommandBuilder& b) -> void {
- b.AddFlag(
- {
- .name = "verbose",
- .short_name = "v",
- .help = "Enable verbose logging to the stderr stream.",
- },
- [&](CommandLine::FlagBuilder& arg_b) { arg_b.Set(&verbose); });
- b.AddFlag(
- {
- .name = "force",
- .help = R"""(
- Force re-creating the provided output path from scratch
- This will **remove** the provided output path and re-create it from scratch.
- )""",
- },
- [&](CommandLine::FlagBuilder& arg_b) { arg_b.Set(&force); });
- b.AddFlag(
- {
- .name = "threads",
- .help = R"""(
- Controls whether threads are used to build runtimes.
- When enabled (the default), Carbon will try to build runtime libraries using
- threads to parallelize the operation. How many threads is controlled
- automatically by the system.
- Disabling threads ensures a single threaded build of the runtimes which can help
- when there are errors or other output.
- )""",
- },
- [&](auto& arg_b) {
- arg_b.Default(true);
- arg_b.Set(&threads);
- });
- codegen_options.Build(b);
- b.AddStringPositionalArg(
- {
- .name = "output-directory",
- .help = R"""(
- The directory to populate with runtime libraries suitable for the selected code
- generation options.
- )""",
- },
- [&](auto& arg_b) {
- arg_b.Required(true);
- arg_b.Set(&directory);
- });
- b.Do([] {});
- }
- static auto MakeInstallPaths(const std::filesystem::path& exe_path)
- -> InstallPaths {
- CARBON_CHECK(*Filesystem::Cwd().Access(exe_path,
- Filesystem::AccessCheckFlags::Execute),
- "Invoked with a non-executable `argv[0]`: {0}", exe_path);
- return InstallPaths::MakeForBazelRunfiles(exe_path.native());
- }
- static auto GetClangPath(const std::filesystem::path& exe_path)
- -> std::filesystem::path {
- std::string runtimes_error;
- using bazel::tools::cpp::runfiles::Runfiles;
- std::unique_ptr<Runfiles> runfiles(
- Runfiles::Create(exe_path.native(), &runtimes_error));
- CARBON_CHECK(runfiles != nullptr, "Failed to find runtimes tree: {0}",
- runtimes_error);
- std::filesystem::path clang_path =
- runfiles->Rlocation("llvm-project/clang/clang");
- CARBON_CHECK(!clang_path.empty());
- CARBON_CHECK(*Filesystem::Cwd().Access(clang_path));
- return clang_path;
- }
- static auto ParseOptions(int argc, char** argv) -> ErrorOr<Options> {
- Options options;
- llvm::SmallVector<llvm::StringRef> args(
- llvm::ArrayRef<char*>(argv, argc).drop_front());
- CARBON_ASSIGN_OR_RETURN(
- auto result, CommandLine::Parse(args, llvm::outs(), Options::Info,
- [&](CommandLine::CommandBuilder& b) {
- options.Build(b);
- }));
- if (result == CommandLine::ParseResult::MetaSuccess) {
- // Exit immediately with success if this was just a meta invocation.
- #if !defined(__APPLE__)
- std::quick_exit(0);
- #else
- // No `std::quick_exit` on macOS, despite the standard including it.
- _Exit(0);
- #endif
- }
- return options;
- }
- // The actual `main` implementation. Can return an exit code or an `Error`
- // (which causes EXIT_FAILURE).
- //
- // Note that this is primarily an internal utility for use with a specific set
- // of Bazel rules, and so many errors are directly `CARBON_CHECK`-ed instead of
- // propagated. Only basic command line errors are propagated using the `Error`
- // side of the return. Other errors in the execution environment are `CHECK`-ed
- // to provide useful backtraces when debugging.
- static auto Main(int argc, char** argv) -> ErrorOr<int> {
- InitLLVM init_llvm(argc, argv);
- if (argc < 1) {
- return Error("Invoked without command line arguments");
- }
- std::filesystem::path exe_path = argv[0];
- exe_path = SetWorkingDirForBazelRun(exe_path);
- const auto install_paths = MakeInstallPaths(exe_path);
- CARBON_ASSIGN_OR_RETURN(Options options, ParseOptions(argc, argv));
- std::filesystem::path clang_path = GetClangPath(exe_path);
- auto fs = llvm::vfs::getRealFileSystem();
- llvm::raw_ostream* vlog_stream = options.verbose ? &llvm::errs() : nullptr;
- ClangRunner runner(&install_paths, fs, vlog_stream, std::move(clang_path));
- Runtimes::Cache::Features features = {
- .target = options.codegen_options.target.str()};
- llvm::SingleThreadExecutor single_thread({.ThreadsRequested = 1});
- std::optional<llvm::DefaultThreadPool> threads;
- llvm::ThreadPoolInterface* thread_pool = &single_thread;
- if (options.threads) {
- threads.emplace(llvm::optimal_concurrency());
- thread_pool = &*threads;
- }
- auto runtimes = *Runtimes::Make(options.directory.str(), vlog_stream);
- if (options.force) {
- // Remove existing runtimes to force a rebuild.
- runtimes.Remove(Runtimes::ClangResourceDir).Check();
- runtimes.Remove(Runtimes::LibUnwind).Check();
- runtimes.Remove(Runtimes::Libcxx).Check();
- }
- ClangResourceDirBuilder resource_dir_builder(
- &runner, thread_pool, llvm::Triple(features.target), &runtimes);
- ClangArchiveRuntimesBuilder<Runtimes::LibUnwind> lib_unwind_builder(
- &runner, thread_pool, llvm::Triple(features.target), &runtimes);
- ClangArchiveRuntimesBuilder<Runtimes::Libcxx> libcxx_builder(
- &runner, thread_pool, llvm::Triple(features.target), &runtimes);
- std::filesystem::path resource_dir_path =
- *std::move(resource_dir_builder).Wait();
- std::move(lib_unwind_builder).Wait().Check();
- std::move(libcxx_builder).Wait().Check();
- // Now remove the `include` symlink from the resource_dir. We'll re-create
- // this tree in the Bazel rule, as the symlink currently is an absolute
- // (non-hermetic) path. We want Bazel to manage this directory with links to
- // the actual input files.
- Filesystem::Dir resource_dir = *Filesystem::Cwd().OpenDir(resource_dir_path);
- resource_dir.Unlink("include").Check();
- return EXIT_SUCCESS;
- }
- } // namespace Carbon
- auto main(int argc, char** argv) -> int {
- auto result = Carbon::Main(argc, argv);
- if (result.ok()) {
- return *result;
- } else {
- llvm::errs() << "error: " << result.error() << "\n";
- return EXIT_FAILURE;
- }
- }
|