mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-24 19:50:14 +01:00
OwningArrayRef is being removed upstream, per https://github.com/llvm/llvm-project/pull/169126. This replaces uses with `SmallVector`. I've also made a separate commit which does init changes; these aren't strictly necessary, but I added to make it a little more idiomatic in spots. --------- Co-authored-by: Dana Jansens <danakj@orodu.net>
265 lines
8.7 KiB
C++
265 lines
8.7 KiB
C++
// 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;
|
|
}
|
|
}
|