diff --git a/toolchain/driver/BUILD b/toolchain/driver/BUILD index ff22e3c9b0fd5..e1c3c78feaa8a 100644 --- a/toolchain/driver/BUILD +++ b/toolchain/driver/BUILD @@ -17,6 +17,25 @@ filegroup( ]), ) +cc_test( + name = "carbon_runner_test", + size = "small", + srcs = ["carbon_runner_test.cpp"], + deps = [ + ":driver", + ":llvm_runner", + ":runtimes_cache", + "//common:all_llvm_targets", + "//common:raw_string_ostream", + "//testing/base:gtest_main", + "//testing/base:capture_std_streams", + "//testing/base:global_exe_path", + "//toolchain/install:install_paths", + "@googletest//:gtest", + "@llvm-project//llvm:TargetParser", + ], +) + cc_library( name = "clang_runner", srcs = ["clang_runner.cpp"], @@ -102,6 +121,8 @@ cc_library( srcs = [ "build_runtimes_subcommand.cpp", "build_runtimes_subcommand.h", + "carbon_runner.cpp", + "carbon_runner.h", "clang_subcommand.cpp", "clang_subcommand.h", "codegen_options.cpp", diff --git a/toolchain/driver/build_runtimes_subcommand.cpp b/toolchain/driver/build_runtimes_subcommand.cpp index d186848b5ab34..e3581bb45bfaf 100644 --- a/toolchain/driver/build_runtimes_subcommand.cpp +++ b/toolchain/driver/build_runtimes_subcommand.cpp @@ -4,9 +4,12 @@ #include "toolchain/driver/build_runtimes_subcommand.h" +#include #include +#include "common/error.h" #include "llvm/TargetParser/Triple.h" +#include "toolchain/driver/carbon_runner.h" #include "toolchain/driver/clang_runner.h" namespace Carbon { @@ -42,7 +45,10 @@ generation flags, and used explicitly when linking. }; BuildRuntimesSubcommand::BuildRuntimesSubcommand() - : DriverSubcommand(SubcommandInfo) {} + : BuildRuntimesSubcommand({}) {} + +BuildRuntimesSubcommand::BuildRuntimesSubcommand(BuildRuntimesOptions options) + : DriverSubcommand(SubcommandInfo), options_(std::move(options)) {} auto BuildRuntimesSubcommand::Run(DriverEnv& driver_env) -> DriverResult { // Don't run Clang when fuzzing, it is known to not be reliable under fuzzing @@ -68,9 +74,6 @@ auto BuildRuntimesSubcommand::Run(DriverEnv& driver_env) -> DriverResult { auto BuildRuntimesSubcommand::RunInternal(DriverEnv& driver_env) -> ErrorOr { - ClangRunner runner(driver_env.installation, driver_env.fs, - driver_env.vlog_stream); - Runtimes::Cache::Features features = { .target = options_.codegen_options.target.str()}; @@ -92,8 +95,17 @@ auto BuildRuntimesSubcommand::RunInternal(DriverEnv& driver_env) : Runtimes::Make(explicit_output_path, driver_env.vlog_stream)); CARBON_ASSIGN_OR_RETURN(auto tmp_dir, Filesystem::MakeTmpDir()); - return runner.BuildTargetResourceDir(features, runtimes, tmp_dir.abs_path(), - *driver_env.thread_pool); + ClangRunner clang_runner(driver_env.installation, driver_env.fs, + driver_env.vlog_stream); + + CARBON_RETURN_IF_ERROR(clang_runner.BuildTargetResourceDir( + features, runtimes, tmp_dir.abs_path(), *driver_env.thread_pool)); + + CarbonRunner carbon_runner(&driver_env); + + CARBON_RETURN_IF_ERROR(carbon_runner.BuildCoreLibraries(features, runtimes)); + + return runtimes.base_path(); } } // namespace Carbon diff --git a/toolchain/driver/build_runtimes_subcommand.h b/toolchain/driver/build_runtimes_subcommand.h index 510de758e4195..aa768ef9896e6 100644 --- a/toolchain/driver/build_runtimes_subcommand.h +++ b/toolchain/driver/build_runtimes_subcommand.h @@ -8,6 +8,7 @@ #include "common/command_line.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" +#include "toolchain/driver/carbon_runner.h" #include "toolchain/driver/codegen_options.h" #include "toolchain/driver/driver_env.h" #include "toolchain/driver/driver_subcommand.h" @@ -26,6 +27,8 @@ struct BuildRuntimesOptions { // Implements the link subcommand of the driver. class BuildRuntimesSubcommand : public DriverSubcommand { + friend CarbonRunner; + public: explicit BuildRuntimesSubcommand(); @@ -36,6 +39,9 @@ class BuildRuntimesSubcommand : public DriverSubcommand { auto Run(DriverEnv& driver_env) -> DriverResult override; private: + // For manual construction of subcommands. + explicit BuildRuntimesSubcommand(BuildRuntimesOptions options); + auto RunInternal(DriverEnv& driver_env) -> ErrorOr; BuildRuntimesOptions options_; diff --git a/toolchain/driver/carbon_runner.cpp b/toolchain/driver/carbon_runner.cpp new file mode 100644 index 0000000000000..c8dd3ffaab13b --- /dev/null +++ b/toolchain/driver/carbon_runner.cpp @@ -0,0 +1,169 @@ +// 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 "toolchain/driver/carbon_runner.h" + +#include +#include + +#include "common/error.h" +#include "common/filesystem.h" +#include "common/vlog.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Object/ArchiveWriter.h" +#include "llvm/Support/FormatAdapters.h" +#include "llvm/Support/VirtualFileSystem.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/TargetParser/Triple.h" +#include "toolchain/driver/build_runtimes_subcommand.h" +#include "toolchain/driver/compile_subcommand.h" +#include "toolchain/driver/driver.h" +#include "toolchain/driver/driver_env.h" +#include "toolchain/driver/driver_subcommand.h" +#include "toolchain/driver/link_subcommand.h" +#include "toolchain/driver/runtimes_cache.h" +#include "toolchain/driver/tool_runner_base.h" +#include "toolchain/install/install_paths.h" + +namespace Carbon { + +CarbonRunner::CarbonRunner(DriverEnv* driver_env) + : ToolRunnerBase(driver_env->installation, driver_env->vlog_stream), + driver_env_(driver_env) {} + +auto CarbonRunner::BuildCoreLibraries(const Runtimes::Cache::Features& features, + Runtimes& runtimes) + -> ErrorOr { + std::filesystem::path core_a_path = "carbon_core.a"; + + // Build directory for core libs. + CARBON_ASSIGN_OR_RETURN(auto build_dir, + runtimes.Build(Runtimes::CoreLibraries)); + if (std::holds_alternative(build_dir)) { + // Found cached build. + return std::get(std::move(build_dir)) / core_a_path; + } + + std::string target = features.target; + llvm::Triple target_triple(target); + + CARBON_VLOG("Building Carbon core libraries for target '{0}'", target); + + // Create temporary directory. + CARBON_ASSIGN_OR_RETURN(auto tmp_path, Filesystem::MakeTmpDir()); + CARBON_ASSIGN_OR_RETURN(Filesystem::Dir tmp_dir, + Filesystem::Cwd().OpenDir(tmp_path.abs_path())); + + // Collect Core source files. + std::filesystem::path core_src_dir = installation_->core_package(); + llvm::SmallVector core_src_files; + + for (const auto& entry : + std::filesystem::recursive_directory_iterator(core_src_dir)) { + const auto& src_path = entry.path(); + if (std::filesystem::is_regular_file(src_path) && + src_path.extension() == ".carbon") { + core_src_files.push_back(src_path); + } + } + + // Copy files into the temporary directory. + llvm::SmallVector tmp_src_files; + for (const auto& core_src_file : core_src_files) { + // Add parent directories. + std::filesystem::path relative_core_src_file = + core_src_file.lexically_relative(core_src_dir); + if (relative_core_src_file.has_parent_path()) { + CARBON_RETURN_IF_ERROR( + tmp_dir.CreateDirectories(relative_core_src_file.parent_path())); + } + + std::filesystem::path tmp_src_file = + tmp_path.abs_path() / relative_core_src_file; + + // Add to files for compiling. + tmp_src_files.push_back(tmp_src_file); + + // Copy file. + std::error_code ec = llvm::sys::fs::copy_file( + std::filesystem::absolute(core_src_file).string(), + tmp_src_file.string()); + if (ec) { + return Error(ec.message()); + } + } + + // Compile object files. + DriverResult result = + Compile(tmp_src_files, Lower::OptimizationLevel::Debug, target_triple, + /*prelude_import=*/false); + if (!result.success) { + return Error("Failed to compile Core libraries."); + } + + // Collect Core object files. + llvm::SmallVector objs; + + for (const auto& entry : + std::filesystem::recursive_directory_iterator(tmp_path.abs_path())) { + const auto& obj_path = entry.path(); + if (std::filesystem::is_regular_file(obj_path) && + obj_path.extension() == ".o") { + auto obj_result = llvm::NewArchiveMember::getFile(obj_path.native(), + /*Deterministic=*/true); + CARBON_CHECK(obj_result, "TODO: Diagnose this: {0}", + llvm::fmt_consume(obj_result.takeError())); + objs.push_back(std::move(*obj_result)); + } + } + + // Build archive. + auto builder = std::get(std::move(build_dir)); + + CARBON_ASSIGN_OR_RETURN( + Filesystem::WriteFile core_a_file, + builder.dir().OpenWriteOnly(core_a_path, Filesystem::CreateAlways)); + + { + llvm::raw_fd_ostream core_a_os = core_a_file.WriteStream(); + llvm::Error archive_err = llvm::writeArchiveToStream( + core_a_os, objs, llvm::SymtabWritingMode::NormalSymtab, + target_triple.isOSDarwin() ? llvm::object::Archive::K_DARWIN + : llvm::object::Archive::K_GNU, + /*Deterministic=*/true, /*Thin=*/false); + // The presence of an error is `true`. + if (archive_err) { + return Error(llvm::toString(std::move(archive_err))); + } + } + CARBON_RETURN_IF_ERROR(std::move(core_a_file).Close()); + + CARBON_ASSIGN_OR_RETURN(std::filesystem::path cached_core_path, + std::move(builder).Commit()); + + return cached_core_path / core_a_path; +} + +auto CarbonRunner::Compile( + llvm::SmallVector input_filenames, + Lower::OptimizationLevel opt_level, llvm::Triple target, + bool prelude_import) -> DriverResult { + // Convert to StringRef vector for options. + llvm::SmallVector input_filename_refs; + for (const auto& filename : input_filenames) { + // Keep StringRef valid by using c_str() and length(). + input_filename_refs.push_back( + llvm::StringRef(filename.c_str(), filename.string().length())); + } + + CompileOptions options = {.opt_level = opt_level, + .codegen_options = {.target = target.str()}, + .input_filenames = input_filename_refs, + .prelude_import = prelude_import}; + CompileSubcommand subcommand(std::move(options)); + return subcommand.Run(*driver_env_); +} + +} // namespace Carbon diff --git a/toolchain/driver/carbon_runner.h b/toolchain/driver/carbon_runner.h new file mode 100644 index 0000000000000..3f6d473c690dd --- /dev/null +++ b/toolchain/driver/carbon_runner.h @@ -0,0 +1,42 @@ +// 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 + +#ifndef CARBON_TOOLCHAIN_DRIVER_CARBON_RUNNER_H_ +#define CARBON_TOOLCHAIN_DRIVER_CARBON_RUNNER_H_ + +#include + +#include "common/error.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/TargetParser/Triple.h" +#include "toolchain/driver/codegen_options.h" +#include "toolchain/driver/driver_env.h" +#include "toolchain/driver/driver_subcommand.h" +#include "toolchain/driver/tool_runner_base.h" +#include "toolchain/lower/options.h" + +namespace Carbon { + +// Helper class for cross-subcommand functionality. +// Allows type-safe calls of subcommands. +// TODO: May need to be adjusted once caching is refactored. +class CarbonRunner : ToolRunnerBase { + public: + explicit CarbonRunner(DriverEnv* driver_env); + + // TODO: Will need to be changed when compile subcommand is revised. + auto BuildCoreLibraries(const Runtimes::Cache::Features& features, + Runtimes& runtimes) -> ErrorOr; + + private: + auto Compile(llvm::SmallVector input_filenames, + Lower::OptimizationLevel opt_level, llvm::Triple target, + bool prelude_import) -> DriverResult; + + DriverEnv* driver_env_; +}; +} // namespace Carbon + +#endif // CARBON_TOOLCHAIN_DRIVER_CARBON_RUNNER_H_ diff --git a/toolchain/driver/carbon_runner_test.cpp b/toolchain/driver/carbon_runner_test.cpp new file mode 100644 index 0000000000000..d927660f403b1 --- /dev/null +++ b/toolchain/driver/carbon_runner_test.cpp @@ -0,0 +1,146 @@ +// 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 "toolchain/driver/carbon_runner.h" + +#include +#include + +#include +#include +#include + +#include "common/check.h" +#include "common/raw_string_ostream.h" +#include "llvm/TargetParser/Host.h" +#include "llvm/TargetParser/Triple.h" +#include "testing/base/capture_std_streams.h" +#include "testing/base/global_exe_path.h" +#include "toolchain/driver/driver_env.h" +#include "toolchain/driver/llvm_runner.h" +#include "toolchain/install/install_paths.h" + +namespace Carbon { +namespace { + +using ::testing::HasSubstr; +using ::testing::StrEq; + +class CarbonRunnerTest : public ::testing::Test { + public: + llvm::IntrusiveRefCntPtr vfs_ = + llvm::vfs::getRealFileSystem(); + RawStringOstream test_output_stream_; + RawStringOstream test_error_stream_; + + InstallPaths install_paths_ = + InstallPaths::MakeForBazelRunfiles(Testing::GetExePath()); + DriverEnv driver_env_ = DriverEnv( + vfs_, &install_paths_, + /*input_stream=*/nullptr, &test_output_stream_, &test_error_stream_, + /*fuzzing*/ false, /*enable_leaking=*/false); + + Runtimes::Cache runtimes_cache_ = + *Runtimes::Cache::MakeSystem(*driver_env_.installation); +}; + +TEST_F(CarbonRunnerTest, BuildCoreLibrariesX8664Linux) { + CarbonRunner runner(&driver_env_); + + // Build Core libs for x86_64-unknown-linux-gnu. + std::string target = "x86_64-unknown-linux-gnu"; + llvm::Triple target_triple(target); + Runtimes::Cache::Features features = {.target = target}; + auto runtimes = *runtimes_cache_.Lookup(features); + auto build_result = runner.BuildCoreLibraries(features, runtimes); + ASSERT_TRUE(build_result.ok()) << build_result.error(); + std::filesystem::path archive_path = std::move(*build_result); + + // Check that the Core archive exists and contains a relevant symbol by + // running the `llvm-nm` tool over it. Using `nm` rather than directly + // inspecting the objects is a bit awkward, but lets us easily ignore the + // wrapping in an archive file. + LLVMRunner llvm_runner(driver_env_.installation, &llvm::errs()); + std::string out; + std::string err; + EXPECT_TRUE(Testing::CallWithCapturedOutput(out, err, [&] { + return llvm_runner.Run(LLVMTool::Nm, {archive_path.native()}); + })); + + // Check that we found a symbol from the core libraries. + EXPECT_THAT(out, HasSubstr("T _CRange.Core\n")); + + EXPECT_THAT(test_output_stream_.TakeStr(), StrEq("")); + EXPECT_THAT(test_error_stream_.TakeStr(), StrEq("")); +} + +TEST_F(CarbonRunnerTest, BuildCoreLibrariesAarch64Darwin) { + CarbonRunner runner(&driver_env_); + + // Build Core libs for aarch64-apple-darwin. + std::string target = "aarch64-apple-darwin"; + llvm::Triple target_triple(target); + Runtimes::Cache::Features features = {.target = target}; + auto runtimes = *runtimes_cache_.Lookup(features); + auto build_result = runner.BuildCoreLibraries(features, runtimes); + ASSERT_TRUE(build_result.ok()) << build_result.error(); + std::filesystem::path archive_path = std::move(*build_result); + + // Check that the Core archive exists and contains a relevant symbol by + // running the `llvm-nm` tool over it. Using `nm` rather than directly + // inspecting the objects is a bit awkward, but lets us easily ignore the + // wrapping in an archive file. + LLVMRunner llvm_runner(driver_env_.installation, &llvm::errs()); + std::string out; + std::string err; + EXPECT_TRUE(Testing::CallWithCapturedOutput(out, err, [&] { + return llvm_runner.Run(LLVMTool::Nm, {archive_path.native()}); + })); + + // Check that we found a symbol from the core libraries. + EXPECT_THAT(out, HasSubstr("T __CRange.Core\n")); + + EXPECT_THAT(test_output_stream_.TakeStr(), StrEq("")); + EXPECT_THAT(test_error_stream_.TakeStr(), StrEq("")); +} + +TEST_F(CarbonRunnerTest, RepeatedBuild) { + // Repeated "builds" (one from scratch and one cached) should point to the + // same file. + std::filesystem::path archive_path1; + std::filesystem::path archive_path2; + + // Two runners should be able to point to the same driver_env. + { + CarbonRunner runner(&driver_env_); + + std::string target = llvm::sys::getDefaultTargetTriple(); + llvm::Triple target_triple(target); + Runtimes::Cache::Features features = {.target = target}; + auto runtimes = *runtimes_cache_.Lookup(features); + auto build_result = runner.BuildCoreLibraries(features, runtimes); + ASSERT_TRUE(build_result.ok()) << build_result.error(); + archive_path1 = std::move(*build_result); + } + { + CarbonRunner runner(&driver_env_); + + std::string target = llvm::sys::getDefaultTargetTriple(); + llvm::Triple target_triple(target); + Runtimes::Cache::Features features = {.target = target}; + auto runtimes = *runtimes_cache_.Lookup(features); + auto build_result = runner.BuildCoreLibraries(features, runtimes); + ASSERT_TRUE(build_result.ok()) << build_result.error(); + archive_path2 = std::move(*build_result); + } + + ASSERT_TRUE(archive_path1 == archive_path2) + << "Different paths: " << archive_path1 << ", " << archive_path2 << "\n"; + + EXPECT_THAT(test_output_stream_.TakeStr(), StrEq("")); + EXPECT_THAT(test_error_stream_.TakeStr(), StrEq("")); +} + +} // namespace +} // namespace Carbon diff --git a/toolchain/driver/clang_subcommand.cpp b/toolchain/driver/clang_subcommand.cpp index 3959452eb091b..8db9536d0f76e 100644 --- a/toolchain/driver/clang_subcommand.cpp +++ b/toolchain/driver/clang_subcommand.cpp @@ -5,6 +5,7 @@ #include "toolchain/driver/clang_subcommand.h" #include +#include #include "llvm/TargetParser/Host.h" #include "toolchain/driver/clang_runner.h" @@ -63,7 +64,10 @@ results in an indirect Clang invocation. )""", }; -ClangSubcommand::ClangSubcommand() : DriverSubcommand(SubcommandInfo) {} +ClangSubcommand::ClangSubcommand() : ClangSubcommand({}) {} + +ClangSubcommand::ClangSubcommand(ClangOptions options) + : DriverSubcommand(SubcommandInfo), options_(std::move(options)) {} // TODO: This lacks a lot of features from the main driver code. We may need to // add more. diff --git a/toolchain/driver/clang_subcommand.h b/toolchain/driver/clang_subcommand.h index 9bca679ef7035..aef3cfbb06a8d 100644 --- a/toolchain/driver/clang_subcommand.h +++ b/toolchain/driver/clang_subcommand.h @@ -8,6 +8,7 @@ #include "common/command_line.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" +#include "toolchain/driver/carbon_runner.h" #include "toolchain/driver/driver_env.h" #include "toolchain/driver/driver_subcommand.h" @@ -26,6 +27,8 @@ struct ClangOptions { // Implements the clang subcommand of the driver. class ClangSubcommand : public DriverSubcommand { + friend CarbonRunner; + public: explicit ClangSubcommand(); @@ -36,6 +39,9 @@ class ClangSubcommand : public DriverSubcommand { auto Run(DriverEnv& driver_env) -> DriverResult override; private: + // For manual construction of subcommands. + explicit ClangSubcommand(ClangOptions options); + ClangOptions options_; }; diff --git a/toolchain/driver/codegen_options.h b/toolchain/driver/codegen_options.h index 503258ec3d974..4ebc1ab14e42d 100644 --- a/toolchain/driver/codegen_options.h +++ b/toolchain/driver/codegen_options.h @@ -18,7 +18,7 @@ struct CodegenOptions { auto Build(CommandLine::CommandBuilder& b) -> void; std::string host = llvm::sys::getDefaultTargetTriple(); - llvm::StringRef target; + llvm::StringRef target = host; }; } // namespace Carbon diff --git a/toolchain/driver/compile_subcommand.cpp b/toolchain/driver/compile_subcommand.cpp index 95aa8ed040837..be4254ec104e6 100644 --- a/toolchain/driver/compile_subcommand.cpp +++ b/toolchain/driver/compile_subcommand.cpp @@ -386,7 +386,10 @@ can be written to standard output as these phases progress. )""", }; -CompileSubcommand::CompileSubcommand() : DriverSubcommand(SubcommandInfo) {} +CompileSubcommand::CompileSubcommand() : CompileSubcommand({}) {} + +CompileSubcommand::CompileSubcommand(CompileOptions options) + : DriverSubcommand(SubcommandInfo), options_(std::move(options)) {} // Returns a string for printing the phase in a diagnostic. static auto PhaseToString(CompileOptions::Phase phase) -> std::string { diff --git a/toolchain/driver/compile_subcommand.h b/toolchain/driver/compile_subcommand.h index f467924de1d19..03b28338cb4b4 100644 --- a/toolchain/driver/compile_subcommand.h +++ b/toolchain/driver/compile_subcommand.h @@ -11,6 +11,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "toolchain/check/check.h" +#include "toolchain/driver/carbon_runner.h" #include "toolchain/driver/codegen_options.h" #include "toolchain/driver/driver_env.h" #include "toolchain/driver/driver_subcommand.h" @@ -39,8 +40,9 @@ struct CompileOptions { Lower::OptimizationLevel opt_level = Lower::OptimizationLevel::Debug; CodegenOptions codegen_options; - Phase phase; - Check::CheckParseTreesOptions::DumpSemIRRanges dump_sem_ir_ranges; + Phase phase = Phase::CodeGen; + Check::CheckParseTreesOptions::DumpSemIRRanges dump_sem_ir_ranges = + Check::CheckParseTreesOptions::DumpSemIRRanges::IfPresent; llvm::StringRef output_filename; llvm::SmallVector input_filenames; @@ -72,6 +74,8 @@ struct CompileOptions { // Implements the compile subcommand of the driver. class CompileSubcommand : public DriverSubcommand { + friend CarbonRunner; + public: explicit CompileSubcommand(); @@ -82,6 +86,9 @@ class CompileSubcommand : public DriverSubcommand { auto Run(DriverEnv& driver_env) -> DriverResult override; private: + // For manual construction of subcommands. + explicit CompileSubcommand(CompileOptions options); + // Does custom validation of the compile-subcommand options structure beyond // what the command line parsing library supports. Diagnoses and returns false // on failure. diff --git a/toolchain/driver/format_subcommand.cpp b/toolchain/driver/format_subcommand.cpp index 4d96b239cfbc3..58dd767ea5479 100644 --- a/toolchain/driver/format_subcommand.cpp +++ b/toolchain/driver/format_subcommand.cpp @@ -5,6 +5,7 @@ #include "toolchain/driver/format_subcommand.h" #include +#include #include "common/raw_string_ostream.h" #include "toolchain/base/shared_value_stores.h" @@ -50,7 +51,10 @@ Format Carbon source code. )""", }; -FormatSubcommand::FormatSubcommand() : DriverSubcommand(SubcommandInfo) {} +FormatSubcommand::FormatSubcommand() : FormatSubcommand({}) {} + +FormatSubcommand::FormatSubcommand(FormatOptions options) + : DriverSubcommand(SubcommandInfo), options_(std::move(options)) {} auto FormatSubcommand::Run(DriverEnv& driver_env) -> DriverResult { DriverResult result = {.success = true}; diff --git a/toolchain/driver/format_subcommand.h b/toolchain/driver/format_subcommand.h index 9d07b7d8da41c..a70d09b456439 100644 --- a/toolchain/driver/format_subcommand.h +++ b/toolchain/driver/format_subcommand.h @@ -6,6 +6,7 @@ #define CARBON_TOOLCHAIN_DRIVER_FORMAT_SUBCOMMAND_H_ #include "common/command_line.h" +#include "toolchain/driver/carbon_runner.h" #include "toolchain/driver/driver_env.h" #include "toolchain/driver/driver_subcommand.h" @@ -23,6 +24,8 @@ struct FormatOptions { // Implements the format subcommand of the driver. class FormatSubcommand : public DriverSubcommand { + friend CarbonRunner; + public: explicit FormatSubcommand(); @@ -33,6 +36,9 @@ class FormatSubcommand : public DriverSubcommand { auto Run(DriverEnv& driver_env) -> DriverResult override; private: + // For manual construction of subcommands. + explicit FormatSubcommand(FormatOptions options); + FormatOptions options_; }; diff --git a/toolchain/driver/link_subcommand.cpp b/toolchain/driver/link_subcommand.cpp index 04c3ddd4741a1..4ab6024ad2684 100644 --- a/toolchain/driver/link_subcommand.cpp +++ b/toolchain/driver/link_subcommand.cpp @@ -4,7 +4,12 @@ #include "toolchain/driver/link_subcommand.h" +#include +#include + +#include "common/error.h" #include "llvm/TargetParser/Triple.h" +#include "toolchain/driver/carbon_runner.h" #include "toolchain/driver/clang_runner.h" namespace Carbon { @@ -80,9 +85,29 @@ TODO: Support linking against binary libraries. )""", }; -LinkSubcommand::LinkSubcommand() : DriverSubcommand(SubcommandInfo) {} +LinkSubcommand::LinkSubcommand() : LinkSubcommand({}) {} + +LinkSubcommand::LinkSubcommand(LinkOptions options) + : DriverSubcommand(SubcommandInfo), options_(std::move(options)) {} auto LinkSubcommand::Run(DriverEnv& driver_env) -> DriverResult { + ErrorOr run_result = RunInternal(driver_env); + + if (!run_result.ok()) { + // This is not a Clang failure, but a failure to even run Clang, so we need + // to diagnose it here. + CARBON_DIAGNOSTIC(FailureRunningClangToLink, Error, + "failure running `clang` to perform linking: {0}", + std::string); + driver_env.emitter.Emit(FailureRunningClangToLink, + run_result.error().message()); + } + + // Successfully ran Clang to perform the link, return its result. + return {.success = *run_result}; +} + +auto LinkSubcommand::RunInternal(DriverEnv& driver_env) -> ErrorOr { // TODO: Currently we use the Clang driver to link. This works well on Unix // OSes but we likely need to directly build logic to invoke `link.exe` on // Windows where `cl.exe` doesn't typically cover that logic. @@ -115,25 +140,28 @@ auto LinkSubcommand::Run(DriverEnv& driver_env) -> DriverResult { clang_args.push_back("-o"); clang_args.push_back(options_.output_filename); + + // Build Carbon Core archive. + CarbonRunner carbon_runner(&driver_env); + Runtimes::Cache::Features features = { + .target = std::string(options_.codegen_options.target)}; + CARBON_ASSIGN_OR_RETURN(Runtimes runtimes, + driver_env.runtimes_cache.Lookup(features)); + + CARBON_ASSIGN_OR_RETURN(std::filesystem::path core_archive, + carbon_runner.BuildCoreLibraries(features, runtimes)); + std::string core_archive_arg = core_archive; + + clang_args.push_back(core_archive_arg); + + // Add objects to link. clang_args.append(options_.object_filenames.begin(), options_.object_filenames.end()); ClangRunner runner(driver_env.installation, driver_env.fs, driver_env.vlog_stream); - ErrorOr run_result = runner.Run(clang_args, driver_env.runtimes_cache, - *driver_env.thread_pool); - if (!run_result.ok()) { - // This is not a Clang failure, but a failure to even run Clang, so we need - // to diagnose it here. - CARBON_DIAGNOSTIC(FailureRunningClangToLink, Error, - "failure running `clang` to perform linking: {0}", - std::string); - driver_env.emitter.Emit(FailureRunningClangToLink, - run_result.error().message()); - return {.success = false}; - } - // Successfully ran Clang to perform the link, return its result. - return {.success = *run_result}; + return runner.Run(clang_args, driver_env.runtimes_cache, + *driver_env.thread_pool); } } // namespace Carbon diff --git a/toolchain/driver/link_subcommand.h b/toolchain/driver/link_subcommand.h index 5eb127629b073..2001493305eb9 100644 --- a/toolchain/driver/link_subcommand.h +++ b/toolchain/driver/link_subcommand.h @@ -6,8 +6,10 @@ #define CARBON_TOOLCHAIN_DRIVER_LINK_SUBCOMMAND_H_ #include "common/command_line.h" +#include "common/error.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" +#include "toolchain/driver/carbon_runner.h" #include "toolchain/driver/codegen_options.h" #include "toolchain/driver/driver_env.h" #include "toolchain/driver/driver_subcommand.h" @@ -27,6 +29,8 @@ struct LinkOptions { // Implements the link subcommand of the driver. class LinkSubcommand : public DriverSubcommand { + friend CarbonRunner; + public: explicit LinkSubcommand(); @@ -37,6 +41,11 @@ class LinkSubcommand : public DriverSubcommand { auto Run(DriverEnv& driver_env) -> DriverResult override; private: + // For manual construction of subcommands. + explicit LinkSubcommand(LinkOptions options); + + auto RunInternal(DriverEnv& driver_env) -> ErrorOr; + LinkOptions options_; }; diff --git a/toolchain/driver/lld_subcommand.cpp b/toolchain/driver/lld_subcommand.cpp index 768d9cf5616df..13cd44fd88c26 100644 --- a/toolchain/driver/lld_subcommand.cpp +++ b/toolchain/driver/lld_subcommand.cpp @@ -5,6 +5,7 @@ #include "toolchain/driver/lld_subcommand.h" #include +#include #include "llvm/TargetParser/Host.h" #include "llvm/TargetParser/Triple.h" @@ -85,7 +86,10 @@ syntaxes, as well as testing and debugging of the underlying tool. )""", }; -LldSubcommand::LldSubcommand() : DriverSubcommand(SubcommandInfo) {} +LldSubcommand::LldSubcommand() : LldSubcommand({}) {} + +LldSubcommand::LldSubcommand(LldOptions options) + : DriverSubcommand(SubcommandInfo), options_(std::move(options)) {} // TODO: This lacks a lot of features from the main driver code. We may need to // add more. diff --git a/toolchain/driver/lld_subcommand.h b/toolchain/driver/lld_subcommand.h index 24569cae695dd..ac05fdee17d11 100644 --- a/toolchain/driver/lld_subcommand.h +++ b/toolchain/driver/lld_subcommand.h @@ -8,6 +8,7 @@ #include "common/command_line.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" +#include "toolchain/driver/carbon_runner.h" #include "toolchain/driver/driver_env.h" #include "toolchain/driver/driver_subcommand.h" @@ -36,6 +37,8 @@ struct LldOptions { // Implements the LLD subcommand of the driver. class LldSubcommand : public DriverSubcommand { + friend CarbonRunner; + public: explicit LldSubcommand(); @@ -46,6 +49,9 @@ class LldSubcommand : public DriverSubcommand { auto Run(DriverEnv& driver_env) -> DriverResult override; private: + // For manual construction of subcommands. + explicit LldSubcommand(LldOptions options); + LldOptions options_; }; diff --git a/toolchain/driver/llvm_subcommand.cpp b/toolchain/driver/llvm_subcommand.cpp index db2551423335f..0a7c414368215 100644 --- a/toolchain/driver/llvm_subcommand.cpp +++ b/toolchain/driver/llvm_subcommand.cpp @@ -4,6 +4,8 @@ #include "toolchain/driver/llvm_subcommand.h" +#include + #include "common/command_line.h" #include "llvm/TargetParser/Host.h" #include "llvm/TargetParser/Triple.h" @@ -57,7 +59,10 @@ Arguments passed to the LLVM tool. b.RequiresSubcommand(); } -LLVMSubcommand::LLVMSubcommand() : DriverSubcommand(SubcommandInfo) {} +LLVMSubcommand::LLVMSubcommand() : LLVMSubcommand({}) {} + +LLVMSubcommand::LLVMSubcommand(LLVMOptions options) + : DriverSubcommand(SubcommandInfo), options_(std::move(options)) {} auto LLVMSubcommand::Run(DriverEnv& driver_env) -> DriverResult { LLVMRunner runner(driver_env.installation, driver_env.vlog_stream); diff --git a/toolchain/driver/llvm_subcommand.h b/toolchain/driver/llvm_subcommand.h index a17f8899129e9..dc8ad5fdc9007 100644 --- a/toolchain/driver/llvm_subcommand.h +++ b/toolchain/driver/llvm_subcommand.h @@ -9,6 +9,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "toolchain/base/llvm_tools.h" +#include "toolchain/driver/carbon_runner.h" #include "toolchain/driver/driver_env.h" #include "toolchain/driver/driver_subcommand.h" @@ -34,6 +35,8 @@ struct LLVMOptions { // // This provides access to the full collection of LLVM command line tools. class LLVMSubcommand : public DriverSubcommand { + friend CarbonRunner; + public: explicit LLVMSubcommand(); @@ -51,6 +54,9 @@ class LLVMSubcommand : public DriverSubcommand { auto Run(DriverEnv& driver_env) -> DriverResult override; private: + // For manual construction of subcommands. + explicit LLVMSubcommand(LLVMOptions options); + LLVMOptions options_; }; diff --git a/toolchain/driver/runtimes_cache.h b/toolchain/driver/runtimes_cache.h index c8d06c2ae9465..88427c81096a4 100644 --- a/toolchain/driver/runtimes_cache.h +++ b/toolchain/driver/runtimes_cache.h @@ -46,6 +46,7 @@ class Runtimes { enum Component { ClangResourceDir, + CoreLibraries, NumComponents, }; @@ -136,6 +137,8 @@ class Runtimes { switch (component) { case ClangResourceDir: return "clang_resource_dir"; + case CoreLibraries: + return "core_libraries"; case NumComponents: CARBON_FATAL("Invalid component"); }