mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 22:02:55 +01:00
Consolidate default Clang argument handling (#6545)
This unifies the default Clang arguments between the `clang` subcommand, the `link` subcommand, and the `ClangInvocation` built for C++ interop. This sets the stage to integrate either pre-built or on-demand runtimes flags for both of these. However, this PR should have very little practical difference. The biggest functional change is wrapping the default arguments in flags to allow unused flags so that we can build a collection of flags viable across compile and link.
This commit is contained in:
@@ -4,8 +4,16 @@
|
||||
|
||||
#include "toolchain/base/clang_invocation.h"
|
||||
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
|
||||
#include "clang/Frontend/CompilerInstance.h"
|
||||
#include "clang/Frontend/Utils.h"
|
||||
#include "common/string_helpers.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Support/FormatVariadic.h"
|
||||
|
||||
namespace Carbon {
|
||||
|
||||
@@ -60,23 +68,36 @@ class ClangDriverDiagnosticConsumer : public clang::DiagnosticConsumer {
|
||||
|
||||
} // namespace
|
||||
|
||||
static auto BuildClangInvocationImpl(
|
||||
Diagnostics::NoLocEmitter& emitter,
|
||||
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> fs,
|
||||
llvm::ArrayRef<std::string> clang_path_and_args)
|
||||
auto BuildClangInvocation(Diagnostics::Consumer& consumer,
|
||||
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> fs,
|
||||
const InstallPaths& install_paths,
|
||||
llvm::StringRef target_str,
|
||||
llvm::ArrayRef<llvm::StringRef> extra_args)
|
||||
-> std::unique_ptr<clang::CompilerInvocation> {
|
||||
Diagnostics::ErrorTrackingConsumer error_tracker(consumer);
|
||||
Diagnostics::NoLocEmitter emitter(&error_tracker);
|
||||
|
||||
ClangDriverDiagnosticConsumer diagnostics_consumer(&emitter);
|
||||
|
||||
llvm::SmallVector<std::string> args;
|
||||
args.push_back("--start-no-unused-arguments");
|
||||
AppendDefaultClangArgs(install_paths, target_str, args);
|
||||
args.push_back("--end-no-unused-arguments");
|
||||
args.append({
|
||||
llvm::formatv("--target={0}", target_str).str(),
|
||||
|
||||
// Add our include file name as the input file, and force it to be
|
||||
// interpreted as C++.
|
||||
"-x",
|
||||
"c++",
|
||||
IncludesFileName,
|
||||
});
|
||||
|
||||
// The clang driver inconveniently wants an array of `const char*`, so convert
|
||||
// the arguments.
|
||||
llvm::SmallVector<const char*> driver_args(llvm::map_range(
|
||||
clang_path_and_args, [](const std::string& str) { return str.c_str(); }));
|
||||
|
||||
// Add our include file name as the input file, and force it to be interpreted
|
||||
// as C++.
|
||||
driver_args.push_back("-x");
|
||||
driver_args.push_back("c++");
|
||||
driver_args.push_back(IncludesFileName);
|
||||
llvm::OwningArrayRef<char> cstr_arg_storage;
|
||||
llvm::SmallVector<const char*> cstr_args = BuildCStrArgs(
|
||||
install_paths.clang_path().native(), args, extra_args, cstr_arg_storage);
|
||||
|
||||
// Build a diagnostics engine. Note that we don't have any diagnostic options
|
||||
// yet; they're produced by running the driver.
|
||||
@@ -88,19 +109,8 @@ static auto BuildClangInvocationImpl(
|
||||
|
||||
// Ask the driver to process the arguments and build a corresponding clang
|
||||
// frontend invocation.
|
||||
return clang::createInvocation(driver_args,
|
||||
{.Diags = driver_diags, .VFS = fs});
|
||||
}
|
||||
|
||||
auto BuildClangInvocation(Diagnostics::Consumer& consumer,
|
||||
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> fs,
|
||||
llvm::ArrayRef<std::string> clang_path_and_args)
|
||||
-> std::unique_ptr<clang::CompilerInvocation> {
|
||||
Diagnostics::ErrorTrackingConsumer error_tracker(consumer);
|
||||
Diagnostics::NoLocEmitter emitter(&error_tracker);
|
||||
|
||||
// Forward to the implementation to avoid exposing `import_cpp` outside check.
|
||||
auto invocation = BuildClangInvocationImpl(emitter, fs, clang_path_and_args);
|
||||
auto invocation =
|
||||
clang::createInvocation(cstr_args, {.Diags = driver_diags, .VFS = fs});
|
||||
|
||||
// If Clang produced an error, throw away its invocation.
|
||||
if (error_tracker.seen_error()) {
|
||||
@@ -110,4 +120,49 @@ auto BuildClangInvocation(Diagnostics::Consumer& consumer,
|
||||
return invocation;
|
||||
}
|
||||
|
||||
auto AppendDefaultClangArgs(const InstallPaths& /*install_paths*/,
|
||||
llvm::StringRef target_str,
|
||||
llvm::SmallVectorImpl<std::string>& args) -> void {
|
||||
args.append({
|
||||
// Enable PIE by default, but allow it to be overridden by Clang
|
||||
// arguments. Clang's default is configurable, but we'd like our
|
||||
// defaults to be more stable.
|
||||
// TODO: Decide if we want this.
|
||||
"-fPIE",
|
||||
|
||||
// Override the default linker to use.
|
||||
"-fuse-ld=lld",
|
||||
});
|
||||
|
||||
// Add target-specific flags.
|
||||
llvm::Triple triple(target_str);
|
||||
switch (triple.getOS()) {
|
||||
case llvm::Triple::Darwin:
|
||||
case llvm::Triple::MacOSX:
|
||||
// On macOS we need to set the sysroot to a viable SDK. Currently, this
|
||||
// hard codes the path to be the unversioned symlink. The prefix is also
|
||||
// hard coded in Homebrew and so this seems likely to work reasonably
|
||||
// well. Homebrew and I suspect the Xcode Clang both have this hard coded
|
||||
// at build time, so this seems reasonably safe but we can revisit if/when
|
||||
// needed.
|
||||
args.push_back(
|
||||
"--sysroot=/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk");
|
||||
|
||||
// We also need to insist on a modern linker, otherwise the driver tries
|
||||
// too old and deprecated flags. The specific number here comes from an
|
||||
// inspection of the Clang driver source code to understand where features
|
||||
// were enabled, and this appears to be the latest version to control
|
||||
// driver behavior.
|
||||
//
|
||||
// TODO: We should replace this with use of `lld` eventually.
|
||||
args.push_back("-mlinker-version=705");
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO: Add flags for the installed runtimes using `install_paths`.
|
||||
}
|
||||
|
||||
} // namespace Carbon
|
||||
|
||||
Reference in New Issue
Block a user