Files
swift-mirror/lib/Driver/ToolChains.cpp
Robert Widmann 859b87fd8c Move The Last Pieces for Cross-Module Incremental Builds
We're going to play a dirty, dirty trick - but it'll make our users'
lives better in the end so stick with me here.

In order to build up an incremental compilation, we need two sources of
dependency information:

1) "Priors" - Swiftdeps with dependency information from the past
   build(s)
2) "Posteriors" - Swiftdeps with dependencies from after we rebuild the
   file or module or whatever

With normal swift files built in incremental mode, the priors are given by the
swiftdeps files which are generated parallel to a swift file and usually
placed in the build directory alongside the object files. Because we
have entries in the output file map, we can always know where these
swiftdeps files are. The priors are integrated by the driver and then
the build is scheduled. As the build runs and jobs complete, their
swiftdeps are reloaded and re-integrated. The resulting changes are then
traversed and more jobs are scheduled if necessary. These give us the
posteriors we desire.

A module flips this on its head. The swiftdeps information serialized
in a module functions as the *posterior* since the driver consuming the
module has no way of knowing how to rebuild the module, and because its
dependencies are, for all intents and purposes, fixed in time. The
missing piece of the puzzle is the priors. That is, we need some way of
knowing what the "past" interface of the module looked like so we can
compare it to the "present" interface. Moreover, we need to always know
where to look for these priors.

We solve this problem by serializing a file alongside the build record:
the "external" build record. This is given by a... creative encoding
of multiple source file dependency graphs into a single source file
dependency graph. The rough structure of this is:

   SourceFile => interface <BUILD_RECORD>.external
   | - Incremental External Dependency => interface <MODULE_1>.swiftmodule
   | | - <dependency> ...
   | | - <dependency> ...
   | | - <dependency> ...
   | - Incremental External Dependency => interface <MODULE_2>.swiftmodule
   | | - <dependency> ...
   | | - <dependency> ...
   | - Incremental External Dependency => interface <MODULE_3>.swiftmodule
   | - ...

Sorta, `cat`'ing a bunch of source file dependency graphs together but
with incremental external dependency nodes acting as glue.

Now for the trick:

We have to unpack this structure and integrate it to get our priors.
This is easy. The tricky bit comes in integrate itself. Because the
top-level source file node points directly at the external build record,
not the original swift modules that defined these dependency nodes, we
swap the key it wants to use (the external build record) for the
incremental external dependency acting as the "parent" of the dependency
node. We do this by following the arc we carefully laid down in the
structure above.

For rdar://69595010
Goes a long way towards rdar://48955139, rdar://64238133
2020-12-10 18:45:21 -08:00

1429 lines
54 KiB
C++

//===--- ToolChains.cpp - Job invocations (general and per-platform) ------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#include "ToolChains.h"
#include "swift/Basic/Dwarf.h"
#include "swift/Basic/LLVM.h"
#include "swift/Basic/Platform.h"
#include "swift/Basic/Range.h"
#include "swift/Basic/STLExtras.h"
#include "swift/Basic/TaskQueue.h"
#include "swift/Config.h"
#include "swift/Driver/Compilation.h"
#include "swift/Driver/Driver.h"
#include "swift/Driver/Job.h"
#include "swift/Frontend/Frontend.h"
#include "swift/Option/Options.h"
#include "clang/Basic/Version.h"
#include "clang/Driver/Util.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Option/Arg.h"
#include "llvm/Option/ArgList.h"
#include "llvm/ProfileData/InstrProf.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/Program.h"
using namespace swift;
using namespace swift::driver;
using namespace llvm::opt;
bool ToolChain::JobContext::shouldUseInputFileList() const {
return getTopLevelInputFiles().size() > C.getFilelistThreshold();
}
bool ToolChain::JobContext::shouldUsePrimaryInputFileListInFrontendInvocation()
const {
return InputActions.size() > C.getFilelistThreshold();
}
bool ToolChain::JobContext::shouldUseMainOutputFileListInFrontendInvocation()
const {
return Output.getPrimaryOutputFilenames().size() > C.getFilelistThreshold();
}
bool ToolChain::JobContext::
shouldUseSupplementaryOutputFileMapInFrontendInvocation() const {
static const unsigned UpperBoundOnSupplementaryOutputFileTypes =
file_types::TY_INVALID;
return InputActions.size() * UpperBoundOnSupplementaryOutputFileTypes >
C.getFilelistThreshold();
}
bool ToolChain::JobContext::shouldFilterFrontendInputsByType() const {
// FIXME: SingleCompile has not filtered its inputs in the past and now people
// rely upon that. But we would like the compilation modes to be consistent.
return OI.CompilerMode != OutputInfo::Mode::SingleCompile;
}
void ToolChain::addInputsOfType(ArgStringList &Arguments,
ArrayRef<const Action *> Inputs,
file_types::ID InputType,
const char *PrefixArgument) const {
for (auto &Input : Inputs) {
if (Input->getType() != InputType)
continue;
if (PrefixArgument)
Arguments.push_back(PrefixArgument);
Arguments.push_back(cast<InputAction>(Input)->getInputArg().getValue());
}
}
void ToolChain::addInputsOfType(ArgStringList &Arguments,
ArrayRef<const Job *> Jobs,
const llvm::opt::ArgList &Args,
file_types::ID InputType,
const char *PrefixArgument) const {
for (const Job *Cmd : Jobs) {
auto output = Cmd->getOutput().getAnyOutputForType(InputType);
if (!output.empty()) {
if (PrefixArgument)
Arguments.push_back(PrefixArgument);
Arguments.push_back(Args.MakeArgString(output));
}
}
}
void ToolChain::addPrimaryInputsOfType(ArgStringList &Arguments,
ArrayRef<const Job *> Jobs,
const llvm::opt::ArgList &Args,
file_types::ID InputType,
const char *PrefixArgument) const {
for (const Job *Cmd : Jobs) {
auto &outputInfo = Cmd->getOutput();
if (outputInfo.getPrimaryOutputType() == InputType) {
for (auto Output : outputInfo.getPrimaryOutputFilenames()) {
if (PrefixArgument)
Arguments.push_back(PrefixArgument);
Arguments.push_back(Args.MakeArgString(Output));
}
}
}
}
static bool addOutputsOfType(ArgStringList &Arguments,
CommandOutput const &Output,
const llvm::opt::ArgList &Args,
file_types::ID OutputType,
const char *PrefixArgument = nullptr) {
bool Added = false;
for (auto Output : Output.getAdditionalOutputsForType(OutputType)) {
assert(!Output.empty());
if (PrefixArgument)
Arguments.push_back(PrefixArgument);
Arguments.push_back(Args.MakeArgString(Output));
Added = true;
}
return Added;
}
static void addLTOArgs(const OutputInfo &OI, ArgStringList &arguments) {
switch (OI.LTOVariant) {
case OutputInfo::LTOKind::None:
break;
case OutputInfo::LTOKind::LLVMThin:
arguments.push_back("-lto=llvm-thin");
break;
case OutputInfo::LTOKind::LLVMFull:
arguments.push_back("-lto=llvm-full");
break;
}
}
void ToolChain::addCommonFrontendArgs(const OutputInfo &OI,
const CommandOutput &output,
const ArgList &inputArgs,
ArgStringList &arguments) const {
// Only pass -target to the REPL or immediate modes if it was explicitly
// specified on the command line.
switch (OI.CompilerMode) {
case OutputInfo::Mode::REPL:
case OutputInfo::Mode::Immediate:
if (!inputArgs.hasArg(options::OPT_target))
break;
LLVM_FALLTHROUGH;
case OutputInfo::Mode::StandardCompile:
case OutputInfo::Mode::SingleCompile:
case OutputInfo::Mode::BatchModeCompile:
arguments.push_back("-target");
arguments.push_back(inputArgs.MakeArgString(Triple.str()));
break;
}
if (const Arg *variant = inputArgs.getLastArg(options::OPT_target_variant)) {
arguments.push_back("-target-variant");
std::string normalized = llvm::Triple::normalize(variant->getValue());
arguments.push_back(inputArgs.MakeArgString(normalized));
}
// Enable address top-byte ignored in the ARM64 backend.
if (Triple.getArch() == llvm::Triple::aarch64) {
arguments.push_back("-Xllvm");
arguments.push_back("-aarch64-use-tbi");
}
// Enable or disable ObjC interop appropriately for the platform
if (Triple.isOSDarwin()) {
arguments.push_back("-enable-objc-interop");
} else {
arguments.push_back("-disable-objc-interop");
}
// Add flags for C++ interop.
if (inputArgs.hasArg(options::OPT_enable_experimental_cxx_interop)) {
arguments.push_back("-enable-cxx-interop");
}
if (const Arg *arg =
inputArgs.getLastArg(options::OPT_experimental_cxx_stdlib)) {
arguments.push_back("-Xcc");
arguments.push_back(
inputArgs.MakeArgString(Twine("-stdlib=") + arg->getValue()));
}
// Handle the CPU and its preferences.
inputArgs.AddLastArg(arguments, options::OPT_target_cpu);
if (!OI.SDKPath.empty()) {
arguments.push_back("-sdk");
arguments.push_back(inputArgs.MakeArgString(OI.SDKPath));
}
if (llvm::sys::Process::StandardErrHasColors()) {
arguments.push_back("-color-diagnostics");
}
inputArgs.AddAllArgs(arguments, options::OPT_I);
inputArgs.AddAllArgs(arguments, options::OPT_F, options::OPT_Fsystem);
inputArgs.AddAllArgs(arguments, options::OPT_vfsoverlay);
inputArgs.AddLastArg(arguments, options::OPT_AssertConfig);
inputArgs.AddLastArg(arguments, options::OPT_autolink_force_load);
inputArgs.AddLastArg(arguments,
options::OPT_color_diagnostics,
options::OPT_no_color_diagnostics);
inputArgs.AddLastArg(arguments, options::OPT_fixit_all);
inputArgs.AddLastArg(arguments,
options::OPT_warn_swift3_objc_inference_minimal,
options::OPT_warn_swift3_objc_inference_complete);
inputArgs.AddLastArg(arguments, options::OPT_warn_implicit_overrides);
inputArgs.AddLastArg(arguments, options::OPT_typo_correction_limit);
inputArgs.AddLastArg(arguments, options::OPT_enable_app_extension);
inputArgs.AddLastArg(arguments, options::OPT_enable_library_evolution);
inputArgs.AddLastArg(arguments, options::OPT_require_explicit_availability);
inputArgs.AddLastArg(arguments, options::OPT_require_explicit_availability_target);
inputArgs.AddLastArg(arguments, options::OPT_enable_testing);
inputArgs.AddLastArg(arguments, options::OPT_enable_private_imports);
inputArgs.AddLastArg(arguments, options::OPT_g_Group);
inputArgs.AddLastArg(arguments, options::OPT_debug_info_format);
inputArgs.AddLastArg(arguments, options::OPT_import_underlying_module);
inputArgs.AddLastArg(arguments, options::OPT_module_cache_path);
inputArgs.AddLastArg(arguments, options::OPT_module_link_name);
inputArgs.AddLastArg(arguments, options::OPT_nostdimport);
inputArgs.AddLastArg(arguments, options::OPT_parse_stdlib);
inputArgs.AddLastArg(arguments, options::OPT_resource_dir);
inputArgs.AddLastArg(arguments, options::OPT_solver_memory_threshold);
inputArgs.AddLastArg(arguments, options::OPT_value_recursion_threshold);
inputArgs.AddLastArg(arguments, options::OPT_warn_swift3_objc_inference);
inputArgs.AddLastArg(arguments, options::OPT_Rpass_EQ);
inputArgs.AddLastArg(arguments, options::OPT_Rpass_missed_EQ);
inputArgs.AddLastArg(arguments, options::OPT_suppress_warnings);
inputArgs.AddLastArg(arguments, options::OPT_profile_generate);
inputArgs.AddLastArg(arguments, options::OPT_profile_use);
inputArgs.AddLastArg(arguments, options::OPT_profile_coverage_mapping);
inputArgs.AddAllArgs(arguments, options::OPT_warnings_as_errors,
options::OPT_no_warnings_as_errors);
inputArgs.AddLastArg(arguments, options::OPT_sanitize_EQ);
inputArgs.AddLastArg(arguments, options::OPT_sanitize_recover_EQ);
inputArgs.AddLastArg(arguments, options::OPT_sanitize_coverage_EQ);
inputArgs.AddLastArg(arguments, options::OPT_static);
inputArgs.AddLastArg(arguments, options::OPT_swift_version);
inputArgs.AddLastArg(arguments, options::OPT_enforce_exclusivity_EQ);
inputArgs.AddLastArg(arguments, options::OPT_stats_output_dir);
inputArgs.AddLastArg(arguments, options::OPT_trace_stats_events);
inputArgs.AddLastArg(arguments, options::OPT_profile_stats_events);
inputArgs.AddLastArg(arguments, options::OPT_profile_stats_entities);
inputArgs.AddLastArg(arguments,
options::OPT_solver_shrink_unsolved_threshold);
inputArgs.AddLastArg(arguments, options::OPT_O_Group);
inputArgs.AddLastArg(arguments, options::OPT_RemoveRuntimeAsserts);
inputArgs.AddLastArg(arguments, options::OPT_AssumeSingleThreaded);
inputArgs.AddLastArg(arguments,
options::OPT_emit_fine_grained_dependency_sourcefile_dot_files);
inputArgs.AddLastArg(arguments, options::OPT_package_description_version);
inputArgs.AddLastArg(arguments, options::OPT_locale);
inputArgs.AddLastArg(arguments, options::OPT_localization_path);
inputArgs.AddLastArg(arguments, options::OPT_serialize_diagnostics_path);
inputArgs.AddLastArg(arguments, options::OPT_debug_diagnostic_names);
inputArgs.AddLastArg(arguments, options::OPT_print_educational_notes);
inputArgs.AddLastArg(arguments, options::OPT_diagnostic_style);
inputArgs.AddLastArg(arguments,
options::OPT_enable_experimental_concise_pound_file);
inputArgs.AddLastArg(
arguments,
options::OPT_enable_fuzzy_forward_scan_trailing_closure_matching,
options::OPT_disable_fuzzy_forward_scan_trailing_closure_matching);
inputArgs.AddLastArg(arguments,
options::OPT_verify_incremental_dependencies);
// Pass on any build config options
inputArgs.AddAllArgs(arguments, options::OPT_D);
// Pass on file paths that should be remapped in debug info.
inputArgs.AddAllArgs(arguments, options::OPT_debug_prefix_map);
inputArgs.AddAllArgs(arguments, options::OPT_coverage_prefix_map);
// Pass through the values passed to -Xfrontend.
inputArgs.AddAllArgValues(arguments, options::OPT_Xfrontend);
// Pass on module names whose symbols should be embeded in tbd.
inputArgs.AddAllArgs(arguments, options::OPT_embed_tbd_for_module);
if (auto *A = inputArgs.getLastArg(options::OPT_working_directory)) {
// Add -Xcc -working-directory before any other -Xcc options to ensure it is
// overridden by an explicit -Xcc -working-directory, although having a
// different working directory is probably incorrect.
SmallString<128> workingDirectory(A->getValue());
llvm::sys::fs::make_absolute(workingDirectory);
arguments.push_back("-Xcc");
arguments.push_back("-working-directory");
arguments.push_back("-Xcc");
arguments.push_back(inputArgs.MakeArgString(workingDirectory));
}
addLTOArgs(OI, arguments);
// -g implies -enable-anonymous-context-mangled-names, because the extra
// metadata aids debugging.
if (inputArgs.hasArg(options::OPT_g)) {
// But don't add the option in optimized builds: it would prevent dead code
// stripping of unused metadata.
auto OptArg = inputArgs.getLastArgNoClaim(options::OPT_O_Group);
if (!OptArg || OptArg->getOption().matches(options::OPT_Onone))
arguments.push_back("-enable-anonymous-context-mangled-names");
}
// Pass through any subsystem flags.
inputArgs.AddAllArgs(arguments, options::OPT_Xllvm);
inputArgs.AddAllArgs(arguments, options::OPT_Xcc);
}
static void addRuntimeLibraryFlags(const OutputInfo &OI,
ArgStringList &Arguments) {
if (!OI.RuntimeVariant)
return;
const OutputInfo::MSVCRuntime RT = OI.RuntimeVariant.getValue();
Arguments.push_back("-autolink-library");
Arguments.push_back("oldnames");
Arguments.push_back("-autolink-library");
switch (RT) {
case OutputInfo::MSVCRuntime::MultiThreaded:
Arguments.push_back("libcmt");
break;
case OutputInfo::MSVCRuntime::MultiThreadedDebug:
Arguments.push_back("libcmtd");
break;
case OutputInfo::MSVCRuntime::MultiThreadedDLL:
Arguments.push_back("msvcrt");
break;
case OutputInfo::MSVCRuntime::MultiThreadedDebugDLL:
Arguments.push_back("msvcrtd");
break;
}
// NOTE(compnerd) we do not support /ML and /MLd
Arguments.push_back("-Xcc");
Arguments.push_back("-D_MT");
if (RT == OutputInfo::MSVCRuntime::MultiThreadedDLL ||
RT == OutputInfo::MSVCRuntime::MultiThreadedDebugDLL) {
Arguments.push_back("-Xcc");
Arguments.push_back("-D_DLL");
}
}
ToolChain::InvocationInfo
ToolChain::constructInvocation(const CompileJobAction &job,
const JobContext &context) const {
InvocationInfo II{SWIFT_EXECUTABLE_NAME};
ArgStringList &Arguments = II.Arguments;
II.allowsResponseFiles = true;
for (auto &s : getDriver().getSwiftProgramArgs())
Arguments.push_back(s.c_str());
Arguments.push_back("-frontend");
{
// Determine the frontend mode option.
const char *FrontendModeOption = context.computeFrontendModeForCompile();
assert(FrontendModeOption != nullptr &&
"No frontend mode option specified!");
Arguments.push_back(FrontendModeOption);
}
context.addFrontendInputAndOutputArguments(Arguments, II.FilelistInfos);
// Forward migrator flags.
if (auto DataPath =
context.Args.getLastArg(options::OPT_api_diff_data_file)) {
Arguments.push_back("-api-diff-data-file");
Arguments.push_back(DataPath->getValue());
}
if (auto DataDir = context.Args.getLastArg(options::OPT_api_diff_data_dir)) {
Arguments.push_back("-api-diff-data-dir");
Arguments.push_back(DataDir->getValue());
}
if (context.Args.hasArg(options::OPT_dump_usr)) {
Arguments.push_back("-dump-usr");
}
if (context.Args.hasArg(options::OPT_parse_stdlib))
Arguments.push_back("-disable-objc-attr-requires-foundation-module");
addCommonFrontendArgs(context.OI, context.Output, context.Args, Arguments);
addRuntimeLibraryFlags(context.OI, Arguments);
// Pass along an -import-objc-header arg, replacing the argument with the name
// of any input PCH to the current action if one is present.
if (context.Args.hasArgNoClaim(options::OPT_import_objc_header)) {
bool ForwardAsIs = true;
bool bridgingPCHIsEnabled =
context.Args.hasFlag(options::OPT_enable_bridging_pch,
options::OPT_disable_bridging_pch, true);
bool usePersistentPCH = bridgingPCHIsEnabled &&
context.Args.hasArg(options::OPT_pch_output_dir);
if (!usePersistentPCH) {
for (auto *IJ : context.Inputs) {
if (!IJ->getOutput().getAnyOutputForType(file_types::TY_PCH).empty()) {
Arguments.push_back("-import-objc-header");
addInputsOfType(Arguments, context.Inputs, context.Args,
file_types::TY_PCH);
ForwardAsIs = false;
break;
}
}
}
if (ForwardAsIs) {
context.Args.AddLastArg(Arguments, options::OPT_import_objc_header);
}
if (usePersistentPCH) {
context.Args.AddLastArg(Arguments, options::OPT_pch_output_dir);
switch (context.OI.CompilerMode) {
case OutputInfo::Mode::StandardCompile:
case OutputInfo::Mode::BatchModeCompile:
// In the 'multiple invocations for each file' mode we don't need to
// validate the PCH every time, it has been validated with the initial
// -emit-pch invocation.
Arguments.push_back("-pch-disable-validation");
break;
case OutputInfo::Mode::Immediate:
case OutputInfo::Mode::REPL:
case OutputInfo::Mode::SingleCompile:
break;
}
}
}
if (context.Args.hasArg(options::OPT_parse_as_library) ||
context.Args.hasArg(options::OPT_emit_library))
Arguments.push_back("-parse-as-library");
context.Args.AddLastArg(Arguments, options::OPT_parse_sil);
Arguments.push_back("-module-name");
Arguments.push_back(context.Args.MakeArgString(context.OI.ModuleName));
if (context.Args.hasArg(options::OPT_CrossModuleOptimization)) {
Arguments.push_back("-cross-module-optimization");
}
file_types::ID remarksFileType = file_types::TY_YAMLOptRecord;
// If a specific format is specified for the remarks, forward that as is.
if (auto remarksFormat =
context.Args.getLastArg(options::OPT_save_optimization_record_EQ)) {
Arguments.push_back(context.Args.MakeArgString(
Twine("-save-optimization-record=") + remarksFormat->getValue()));
// If that's the case, add the proper output file for the type.
if (llvm::Expected<file_types::ID> fileType =
remarkFileTypeFromArgs(context.Args))
remarksFileType = *fileType;
else
consumeError(fileType.takeError()); // Don't report errors here. This will
// be reported later anyway.
}
addOutputsOfType(Arguments, context.Output, context.Args, remarksFileType,
"-save-optimization-record-path");
if (auto remarksFilter = context.Args.getLastArg(
options::OPT_save_optimization_record_passes)) {
Arguments.push_back("-save-optimization-record-passes");
Arguments.push_back(remarksFilter->getValue());
}
if (context.Args.hasArg(options::OPT_migrate_keep_objc_visibility)) {
Arguments.push_back("-migrate-keep-objc-visibility");
}
addOutputsOfType(Arguments, context.Output, context.Args,
file_types::TY_Remapping, "-emit-remap-file-path");
if (context.OI.numThreads > 0) {
Arguments.push_back("-num-threads");
Arguments.push_back(
context.Args.MakeArgString(Twine(context.OI.numThreads)));
}
// Add the output file argument if necessary.
if (context.Output.getPrimaryOutputType() != file_types::TY_Nothing) {
if (context.shouldUseMainOutputFileListInFrontendInvocation()) {
Arguments.push_back("-output-filelist");
Arguments.push_back(context.getTemporaryFilePath("outputs", ""));
II.FilelistInfos.push_back({Arguments.back(),
context.Output.getPrimaryOutputType(),
FilelistInfo::WhichFiles::Output});
} else {
for (auto FileName : context.Output.getPrimaryOutputFilenames()) {
Arguments.push_back("-o");
Arguments.push_back(context.Args.MakeArgString(FileName));
}
}
}
if (context.Args.hasArg(options::OPT_embed_bitcode_marker))
Arguments.push_back("-embed-bitcode-marker");
// For `-index-file` mode add `-disable-typo-correction`, since the errors
// will be ignored and it can be expensive to do typo-correction.
if (job.getType() == file_types::TY_IndexData) {
Arguments.push_back("-disable-typo-correction");
}
if (context.Args.hasArg(options::OPT_index_store_path)) {
context.Args.AddLastArg(Arguments, options::OPT_index_store_path);
if (!context.Args.hasArg(options::OPT_index_ignore_system_modules))
Arguments.push_back("-index-system-modules");
}
if (context.Args.hasArg(options::OPT_debug_info_store_invocation) ||
shouldStoreInvocationInDebugInfo()) {
Arguments.push_back("-debug-info-store-invocation");
}
if (context.Args.hasArg(
options::OPT_disable_autolinking_runtime_compatibility)) {
Arguments.push_back("-disable-autolinking-runtime-compatibility");
}
if (auto arg = context.Args.getLastArg(
options::OPT_runtime_compatibility_version)) {
Arguments.push_back("-runtime-compatibility-version");
Arguments.push_back(arg->getValue());
}
if (context.Args.hasArg(options::OPT_track_system_dependencies)) {
Arguments.push_back("-track-system-dependencies");
}
if (context.Args.hasFlag(options::OPT_static_executable,
options::OPT_no_static_executable, false) ||
context.Args.hasFlag(options::OPT_static_stdlib,
options::OPT_no_static_stdlib, false)) {
Arguments.push_back("-use-static-resource-dir");
}
context.Args.AddLastArg(
Arguments,
options::
OPT_disable_autolinking_runtime_compatibility_dynamic_replacements);
return II;
}
const char *ToolChain::JobContext::computeFrontendModeForCompile() const {
switch (OI.CompilerMode) {
case OutputInfo::Mode::StandardCompile:
case OutputInfo::Mode::SingleCompile:
case OutputInfo::Mode::BatchModeCompile:
break;
case OutputInfo::Mode::Immediate:
case OutputInfo::Mode::REPL:
llvm_unreachable("REPL and immediate modes handled elsewhere");
}
switch (Output.getPrimaryOutputType()) {
case file_types::TY_Object:
return "-c";
case file_types::TY_PCH:
return "-emit-pch";
case file_types::TY_ASTDump:
return "-dump-ast";
case file_types::TY_RawSIL:
return "-emit-silgen";
case file_types::TY_SIL:
return "-emit-sil";
case file_types::TY_RawSIB:
return "-emit-sibgen";
case file_types::TY_SIB:
return "-emit-sib";
case file_types::TY_LLVM_IR:
return "-emit-ir";
case file_types::TY_LLVM_BC:
return "-emit-bc";
case file_types::TY_ClangModuleFile:
return "-emit-pcm";
case file_types::TY_Assembly:
return "-S";
case file_types::TY_SwiftModuleFile:
// Since this is our primary output, we need to specify the option here.
return "-emit-module";
case file_types::TY_ImportedModules:
return "-emit-imported-modules";
case file_types::TY_JSONDependencies:
return "-scan-dependencies";
case file_types::TY_JSONFeatures:
return "-emit-supported-features";
case file_types::TY_IndexData:
return "-typecheck";
case file_types::TY_Remapping:
return "-update-code";
case file_types::TY_Nothing:
// We were told to output nothing, so get the last mode option and use that.
if (const Arg *A = Args.getLastArg(options::OPT_modes_Group))
return A->getSpelling().data();
else
llvm_unreachable("We were told to perform a standard compile, "
"but no mode option was passed to the driver.");
case file_types::TY_Swift:
case file_types::TY_dSYM:
case file_types::TY_AutolinkFile:
case file_types::TY_Dependencies:
case file_types::TY_SwiftModuleDocFile:
case file_types::TY_SerializedDiagnostics:
case file_types::TY_ObjCHeader:
case file_types::TY_Image:
case file_types::TY_SwiftDeps:
case file_types::TY_ExternalSwiftDeps:
case file_types::TY_SwiftRanges:
case file_types::TY_CompiledSource:
case file_types::TY_ModuleTrace:
case file_types::TY_TBD:
case file_types::TY_YAMLOptRecord:
case file_types::TY_BitstreamOptRecord:
case file_types::TY_SwiftModuleInterfaceFile:
case file_types::TY_PrivateSwiftModuleInterfaceFile:
case file_types::TY_SwiftModuleSummaryFile:
case file_types::TY_SwiftSourceInfoFile:
case file_types::TY_SwiftCrossImportDir:
case file_types::TY_SwiftOverlayFile:
llvm_unreachable("Output type can never be primary output.");
case file_types::TY_INVALID:
llvm_unreachable("Invalid type ID");
}
llvm_unreachable("unhandled output type");
}
void ToolChain::JobContext::addFrontendInputAndOutputArguments(
ArgStringList &Arguments, std::vector<FilelistInfo> &FilelistInfos) const {
switch (OI.CompilerMode) {
case OutputInfo::Mode::StandardCompile:
assert(InputActions.size() == 1 &&
"Standard-compile mode takes exactly one input (the primary file)");
break;
case OutputInfo::Mode::BatchModeCompile:
case OutputInfo::Mode::SingleCompile:
break;
case OutputInfo::Mode::Immediate:
case OutputInfo::Mode::REPL:
llvm_unreachable("REPL and immediate modes handled elsewhere");
}
const bool UseFileList = shouldUseInputFileList();
const bool MayHavePrimaryInputs = OI.mightHaveExplicitPrimaryInputs(Output);
const bool UsePrimaryFileList =
MayHavePrimaryInputs &&
shouldUsePrimaryInputFileListInFrontendInvocation();
const bool FilterInputsByType = shouldFilterFrontendInputsByType();
const bool UseSupplementaryOutputFileList =
shouldUseSupplementaryOutputFileMapInFrontendInvocation();
assert((C.getFilelistThreshold() != Compilation::NEVER_USE_FILELIST ||
!UseFileList && !UsePrimaryFileList &&
!UseSupplementaryOutputFileList) &&
"No filelists are used if FilelistThreshold=NEVER_USE_FILELIST");
if (UseFileList) {
Arguments.push_back("-filelist");
Arguments.push_back(getAllSourcesPath());
}
if (UsePrimaryFileList) {
Arguments.push_back("-primary-filelist");
Arguments.push_back(getTemporaryFilePath("primaryInputs", ""));
FilelistInfos.push_back({Arguments.back(), file_types::TY_Swift,
FilelistInfo::WhichFiles::SourceInputActions});
}
if (!UseFileList || !UsePrimaryFileList) {
addFrontendCommandLineInputArguments(MayHavePrimaryInputs, UseFileList,
UsePrimaryFileList, FilterInputsByType,
Arguments);
}
if (UseSupplementaryOutputFileList) {
Arguments.push_back("-supplementary-output-file-map");
Arguments.push_back(getTemporaryFilePath("supplementaryOutputs", ""));
FilelistInfos.push_back({Arguments.back(), file_types::TY_INVALID,
FilelistInfo::WhichFiles::SupplementaryOutput});
} else {
addFrontendSupplementaryOutputArguments(Arguments);
}
}
void ToolChain::JobContext::addFrontendCommandLineInputArguments(
const bool mayHavePrimaryInputs, const bool useFileList,
const bool usePrimaryFileList, const bool filterByType,
ArgStringList &arguments) const {
llvm::DenseSet<StringRef> primaries;
if (mayHavePrimaryInputs) {
for (const Action *A : InputActions) {
const auto *IA = cast<InputAction>(A);
const llvm::opt::Arg &InArg = IA->getInputArg();
primaries.insert(InArg.getValue());
}
}
// -index-file compilations are weird. They are processed as SingleCompiles
// (WMO), but must indicate that there is one primary file, designated by
// -index-file-path.
if (Arg *A = Args.getLastArg(options::OPT_index_file_path)) {
assert(primaries.empty() &&
"index file jobs should be treated as single (WMO) compiles");
primaries.insert(A->getValue());
}
for (auto inputPair : getTopLevelInputFiles()) {
if (filterByType && !file_types::isPartOfSwiftCompilation(inputPair.first))
continue;
const char *inputName = inputPair.second->getValue();
const bool isPrimary = primaries.count(inputName);
if (isPrimary && !usePrimaryFileList) {
arguments.push_back("-primary-file");
arguments.push_back(inputName);
}
if ((!isPrimary || usePrimaryFileList) && !useFileList)
arguments.push_back(inputName);
}
}
void ToolChain::JobContext::addFrontendSupplementaryOutputArguments(
ArgStringList &arguments) const {
// FIXME: Get these and other argument strings from the same place for both
// driver and frontend.
addOutputsOfType(arguments, Output, Args, file_types::ID::TY_SwiftModuleFile,
"-emit-module-path");
addOutputsOfType(arguments, Output, Args, file_types::TY_SwiftModuleDocFile,
"-emit-module-doc-path");
addOutputsOfType(arguments, Output, Args, file_types::TY_SwiftSourceInfoFile,
"-emit-module-source-info-path");
addOutputsOfType(arguments, Output, Args,
file_types::ID::TY_SwiftModuleInterfaceFile,
"-emit-module-interface-path");
addOutputsOfType(arguments, Output, Args,
file_types::ID::TY_PrivateSwiftModuleInterfaceFile,
"-emit-private-module-interface-path");
addOutputsOfType(arguments, Output, Args,
file_types::TY_SerializedDiagnostics,
"-serialize-diagnostics-path");
if (addOutputsOfType(arguments, Output, Args, file_types::ID::TY_ObjCHeader,
"-emit-objc-header-path")) {
assert(OI.CompilerMode == OutputInfo::Mode::SingleCompile &&
"The Swift tool should only emit an Obj-C header in single compile"
"mode!");
}
addOutputsOfType(arguments, Output, Args, file_types::TY_Dependencies,
"-emit-dependencies-path");
addOutputsOfType(arguments, Output, Args, file_types::TY_SwiftDeps,
"-emit-reference-dependencies-path");
addOutputsOfType(arguments, Output, Args, file_types::TY_SwiftRanges,
"-emit-swift-ranges-path");
addOutputsOfType(arguments, Output, Args, file_types::TY_CompiledSource,
"-emit-compiled-source-path");
addOutputsOfType(arguments, Output, Args, file_types::TY_ModuleTrace,
"-emit-loaded-module-trace-path");
addOutputsOfType(arguments, Output, Args, file_types::TY_TBD,
"-emit-tbd-path");
addOutputsOfType(arguments, Output, Args,
file_types::TY_SwiftModuleSummaryFile,
"-emit-module-summary-path");
}
ToolChain::InvocationInfo
ToolChain::constructInvocation(const InterpretJobAction &job,
const JobContext &context) const {
assert(context.OI.CompilerMode == OutputInfo::Mode::Immediate);
InvocationInfo II{SWIFT_EXECUTABLE_NAME};
ArgStringList &Arguments = II.Arguments;
II.allowsResponseFiles = true;
for (auto &s : getDriver().getSwiftProgramArgs())
Arguments.push_back(s.c_str());
Arguments.push_back("-frontend");
Arguments.push_back("-interpret");
assert(context.Inputs.empty() &&
"The Swift frontend does not expect to be fed any input Jobs!");
for (const Action *A : context.InputActions) {
cast<InputAction>(A)->getInputArg().render(context.Args, Arguments);
}
if (context.Args.hasArg(options::OPT_parse_stdlib))
Arguments.push_back("-disable-objc-attr-requires-foundation-module");
addCommonFrontendArgs(context.OI, context.Output, context.Args, Arguments);
addRuntimeLibraryFlags(context.OI, Arguments);
context.Args.AddLastArg(Arguments, options::OPT_import_objc_header);
context.Args.AddLastArg(Arguments, options::OPT_parse_sil);
Arguments.push_back("-module-name");
Arguments.push_back(context.Args.MakeArgString(context.OI.ModuleName));
context.Args.AddAllArgs(Arguments, options::OPT_l, options::OPT_framework);
// The immediate arguments must be last.
context.Args.AddLastArg(Arguments, options::OPT__DASH_DASH);
return II;
}
ToolChain::InvocationInfo
ToolChain::constructInvocation(const BackendJobAction &job,
const JobContext &context) const {
assert(context.Args.hasArg(options::OPT_embed_bitcode));
ArgStringList Arguments;
for (auto &s : getDriver().getSwiftProgramArgs())
Arguments.push_back(s.c_str());
Arguments.push_back("-frontend");
// Determine the frontend mode option.
const char *FrontendModeOption = nullptr;
switch (context.OI.CompilerMode) {
case OutputInfo::Mode::StandardCompile:
case OutputInfo::Mode::SingleCompile: {
switch (context.Output.getPrimaryOutputType()) {
case file_types::TY_Object:
FrontendModeOption = "-c";
break;
case file_types::TY_LLVM_IR:
FrontendModeOption = "-emit-ir";
break;
case file_types::TY_LLVM_BC:
FrontendModeOption = "-emit-bc";
break;
case file_types::TY_Assembly:
FrontendModeOption = "-S";
break;
case file_types::TY_Nothing:
// We were told to output nothing, so get the last mode option and use
// that.
if (const Arg *A = context.Args.getLastArg(options::OPT_modes_Group))
FrontendModeOption = A->getSpelling().data();
else
llvm_unreachable("We were told to perform a standard compile, "
"but no mode option was passed to the driver.");
break;
case file_types::TY_ImportedModules:
case file_types::TY_TBD:
case file_types::TY_SwiftModuleFile:
case file_types::TY_ASTDump:
case file_types::TY_RawSIL:
case file_types::TY_RawSIB:
case file_types::TY_SIL:
case file_types::TY_SIB:
case file_types::TY_PCH:
case file_types::TY_ClangModuleFile:
case file_types::TY_IndexData:
case file_types::TY_JSONDependencies:
case file_types::TY_JSONFeatures:
llvm_unreachable("Cannot be output from backend job");
case file_types::TY_Swift:
case file_types::TY_dSYM:
case file_types::TY_AutolinkFile:
case file_types::TY_Dependencies:
case file_types::TY_SwiftModuleDocFile:
case file_types::TY_SerializedDiagnostics:
case file_types::TY_ObjCHeader:
case file_types::TY_Image:
case file_types::TY_SwiftDeps:
case file_types::TY_ExternalSwiftDeps:
case file_types::TY_SwiftRanges:
case file_types::TY_CompiledSource:
case file_types::TY_Remapping:
case file_types::TY_ModuleTrace:
case file_types::TY_YAMLOptRecord:
case file_types::TY_BitstreamOptRecord:
case file_types::TY_SwiftModuleInterfaceFile:
case file_types::TY_PrivateSwiftModuleInterfaceFile:
case file_types::TY_SwiftModuleSummaryFile:
case file_types::TY_SwiftSourceInfoFile:
case file_types::TY_SwiftCrossImportDir:
case file_types::TY_SwiftOverlayFile:
llvm_unreachable("Output type can never be primary output.");
case file_types::TY_INVALID:
llvm_unreachable("Invalid type ID");
}
break;
}
case OutputInfo::Mode::BatchModeCompile:
case OutputInfo::Mode::Immediate:
case OutputInfo::Mode::REPL:
llvm_unreachable("invalid mode for backend job");
}
assert(FrontendModeOption != nullptr && "No frontend mode option specified!");
Arguments.push_back(FrontendModeOption);
// Add input arguments.
switch (context.OI.CompilerMode) {
case OutputInfo::Mode::StandardCompile: {
assert(context.Inputs.size() == 1 && "The backend expects one input!");
Arguments.push_back("-primary-file");
const Job *Cmd = context.Inputs.front();
Arguments.push_back(context.Args.MakeArgString(
Cmd->getOutput().getPrimaryOutputFilename()));
break;
}
case OutputInfo::Mode::SingleCompile: {
assert(context.Inputs.size() == 1 && "The backend expects one input!");
Arguments.push_back("-primary-file");
const Job *Cmd = context.Inputs.front();
// In multi-threaded compilation, the backend job must select the correct
// output file of the compilation job.
auto OutNames = Cmd->getOutput().getPrimaryOutputFilenames();
Arguments.push_back(
context.Args.MakeArgString(OutNames[job.getInputIndex()]));
break;
}
case OutputInfo::Mode::BatchModeCompile:
case OutputInfo::Mode::Immediate:
case OutputInfo::Mode::REPL:
llvm_unreachable("invalid mode for backend job");
}
// Add flags implied by -embed-bitcode.
Arguments.push_back("-embed-bitcode");
// -embed-bitcode only supports a restricted set of flags.
Arguments.push_back("-target");
Arguments.push_back(context.Args.MakeArgString(getTriple().str()));
// Enable address top-byte ignored in the ARM64 backend.
if (getTriple().getArch() == llvm::Triple::aarch64) {
Arguments.push_back("-Xllvm");
Arguments.push_back("-aarch64-use-tbi");
}
// Handle the CPU and its preferences.
context.Args.AddLastArg(Arguments, options::OPT_target_cpu);
// Enable optimizations, but disable all LLVM-IR-level transformations.
context.Args.AddLastArg(Arguments, options::OPT_O_Group);
Arguments.push_back("-disable-llvm-optzns");
context.Args.AddLastArg(Arguments, options::OPT_parse_stdlib);
Arguments.push_back("-module-name");
Arguments.push_back(context.Args.MakeArgString(context.OI.ModuleName));
// Add the output file argument if necessary.
if (context.Output.getPrimaryOutputType() != file_types::TY_Nothing) {
for (auto FileName : context.Output.getPrimaryOutputFilenames()) {
Arguments.push_back("-o");
Arguments.push_back(context.Args.MakeArgString(FileName));
}
}
return {SWIFT_EXECUTABLE_NAME, Arguments};
}
ToolChain::InvocationInfo
ToolChain::constructInvocation(const MergeModuleJobAction &job,
const JobContext &context) const {
InvocationInfo II{SWIFT_EXECUTABLE_NAME};
ArgStringList &Arguments = II.Arguments;
II.allowsResponseFiles = true;
for (auto &s : getDriver().getSwiftProgramArgs())
Arguments.push_back(s.c_str());
Arguments.push_back("-frontend");
Arguments.push_back("-merge-modules");
Arguments.push_back("-emit-module");
if (context.shouldUseInputFileList()) {
Arguments.push_back("-filelist");
Arguments.push_back(context.getTemporaryFilePath("inputs", ""));
II.FilelistInfos.push_back({Arguments.back(),
file_types::TY_SwiftModuleFile,
FilelistInfo::WhichFiles::InputJobs});
addInputsOfType(Arguments, context.InputActions,
file_types::TY_SwiftModuleFile);
} else {
size_t origLen = Arguments.size();
(void)origLen;
addInputsOfType(Arguments, context.Inputs, context.Args,
file_types::TY_SwiftModuleFile);
addInputsOfType(Arguments, context.InputActions,
file_types::TY_SwiftModuleFile);
assert(Arguments.size() - origLen >=
context.Inputs.size() + context.InputActions.size() ||
context.OI.CompilerOutputType == file_types::TY_Nothing);
assert((Arguments.size() - origLen == context.Inputs.size() ||
context.OI.CompilerOutputType == file_types::TY_Nothing ||
!context.InputActions.empty()) &&
"every input to MergeModule must generate a swiftmodule");
}
// Tell all files to parse as library, which is necessary to load them as
// serialized ASTs.
Arguments.push_back("-parse-as-library");
// Disable SIL optimization passes; we've already optimized the code in each
// partial mode.
Arguments.push_back("-disable-diagnostic-passes");
Arguments.push_back("-disable-sil-perf-optzns");
addCommonFrontendArgs(context.OI, context.Output, context.Args, Arguments);
addRuntimeLibraryFlags(context.OI, Arguments);
addOutputsOfType(Arguments, context.Output, context.Args,
file_types::TY_SwiftModuleDocFile, "-emit-module-doc-path");
addOutputsOfType(Arguments, context.Output, context.Args,
file_types::TY_SwiftSourceInfoFile,
"-emit-module-source-info-path");
addOutputsOfType(Arguments, context.Output, context.Args,
file_types::ID::TY_SwiftModuleInterfaceFile,
"-emit-module-interface-path");
addOutputsOfType(Arguments, context.Output, context.Args,
file_types::ID::TY_PrivateSwiftModuleInterfaceFile,
"-emit-private-module-interface-path");
addOutputsOfType(Arguments, context.Output, context.Args,
file_types::TY_SerializedDiagnostics,
"-serialize-diagnostics-path");
addOutputsOfType(Arguments, context.Output, context.Args,
file_types::TY_ObjCHeader, "-emit-objc-header-path");
addOutputsOfType(Arguments, context.Output, context.Args, file_types::TY_TBD,
"-emit-tbd-path");
context.Args.AddLastArg(Arguments, options::OPT_import_objc_header);
context.Args.AddLastArg(
Arguments,
options::OPT_enable_experimental_cross_module_incremental_build);
Arguments.push_back("-module-name");
Arguments.push_back(context.Args.MakeArgString(context.OI.ModuleName));
assert(context.Output.getPrimaryOutputType() ==
file_types::TY_SwiftModuleFile &&
"The MergeModule tool only produces swiftmodule files!");
Arguments.push_back("-o");
Arguments.push_back(
context.Args.MakeArgString(context.Output.getPrimaryOutputFilename()));
return II;
}
ToolChain::InvocationInfo
ToolChain::constructInvocation(const VerifyModuleInterfaceJobAction &job,
const JobContext &context) const {
InvocationInfo II{SWIFT_EXECUTABLE_NAME};
ArgStringList &Arguments = II.Arguments;
II.allowsResponseFiles = true;
for (auto &s : getDriver().getSwiftProgramArgs())
Arguments.push_back(s.c_str());
Arguments.push_back("-frontend");
Arguments.push_back("-typecheck-module-from-interface");
size_t sizeBefore = Arguments.size();
addInputsOfType(Arguments, context.Inputs, context.Args, job.getInputType());
(void)sizeBefore;
assert(Arguments.size() - sizeBefore == 1 &&
"should verify exactly one module interface per job");
addCommonFrontendArgs(context.OI, context.Output, context.Args, Arguments);
addRuntimeLibraryFlags(context.OI, Arguments);
addOutputsOfType(Arguments, context.Output, context.Args,
file_types::TY_SerializedDiagnostics,
"-serialize-diagnostics-path");
context.Args.AddLastArg(Arguments, options::OPT_import_objc_header);
Arguments.push_back("-module-name");
Arguments.push_back(context.Args.MakeArgString(context.OI.ModuleName));
return II;
}
ToolChain::InvocationInfo
ToolChain::constructInvocation(const ModuleWrapJobAction &job,
const JobContext &context) const {
InvocationInfo II{SWIFT_EXECUTABLE_NAME};
ArgStringList &Arguments = II.Arguments;
II.allowsResponseFiles = true;
for (auto &s : getDriver().getSwiftProgramArgs())
Arguments.push_back(s.c_str());
Arguments.push_back("-modulewrap");
addInputsOfType(Arguments, context.Inputs, context.Args,
file_types::TY_SwiftModuleFile);
addInputsOfType(Arguments, context.InputActions,
file_types::TY_SwiftModuleFile);
assert(Arguments.size() == 2 &&
"ModuleWrap expects exactly one merged swiftmodule as input");
assert(context.Output.getPrimaryOutputType() == file_types::TY_Object &&
"The -modulewrap mode only produces object files");
Arguments.push_back("-target");
Arguments.push_back(context.Args.MakeArgString(getTriple().str()));
Arguments.push_back("-o");
Arguments.push_back(
context.Args.MakeArgString(context.Output.getPrimaryOutputFilename()));
return II;
}
ToolChain::InvocationInfo
ToolChain::constructInvocation(const REPLJobAction &job,
const JobContext &context) const {
assert(context.Inputs.empty());
assert(context.InputActions.empty());
bool useLLDB;
switch (job.getRequestedMode()) {
case REPLJobAction::Mode::Integrated:
useLLDB = false;
break;
case REPLJobAction::Mode::RequireLLDB:
useLLDB = true;
break;
case REPLJobAction::Mode::PreferLLDB:
useLLDB = !findProgramRelativeToSwift("lldb").empty();
break;
}
ArgStringList FrontendArgs;
for (auto &s : getDriver().getSwiftProgramArgs())
FrontendArgs.push_back(s.c_str());
addCommonFrontendArgs(context.OI, context.Output, context.Args, FrontendArgs);
addRuntimeLibraryFlags(context.OI, FrontendArgs);
context.Args.AddLastArg(FrontendArgs, options::OPT_import_objc_header);
context.Args.AddAllArgs(FrontendArgs, options::OPT_l, options::OPT_framework,
options::OPT_L);
if (!useLLDB) {
FrontendArgs.insert(FrontendArgs.begin(), {"-frontend", "-repl"});
FrontendArgs.push_back("-module-name");
FrontendArgs.push_back(context.Args.MakeArgString(context.OI.ModuleName));
return {SWIFT_EXECUTABLE_NAME, FrontendArgs};
}
// Squash important frontend options into a single argument for LLDB.
std::string SingleArg = "--repl=";
{
llvm::raw_string_ostream os(SingleArg);
Job::printArguments(os, FrontendArgs);
}
ArgStringList Arguments;
Arguments.push_back(context.Args.MakeArgString(std::move(SingleArg)));
return {"lldb", Arguments};
}
ToolChain::InvocationInfo
ToolChain::constructInvocation(const GenerateDSYMJobAction &job,
const JobContext &context) const {
assert(context.Inputs.size() == 1);
assert(context.InputActions.empty());
assert(context.Output.getPrimaryOutputType() == file_types::TY_dSYM);
ArgStringList Arguments;
auto inputPath =
context.Inputs.front()->getOutput().getPrimaryOutputFilename();
Arguments.push_back(context.Args.MakeArgString(inputPath));
Arguments.push_back("-o");
Arguments.push_back(
context.Args.MakeArgString(context.Output.getPrimaryOutputFilename()));
return {"dsymutil", Arguments};
}
ToolChain::InvocationInfo
ToolChain::constructInvocation(const VerifyDebugInfoJobAction &job,
const JobContext &context) const {
assert(context.Inputs.size() == 1);
assert(context.InputActions.empty());
// This mirrors the clang driver's --verify-debug-info option.
ArgStringList Arguments;
Arguments.push_back("--verify");
Arguments.push_back("--debug-info");
Arguments.push_back("--eh-frame");
Arguments.push_back("--quiet");
auto inputPath =
context.Inputs.front()->getOutput().getPrimaryOutputFilename();
Arguments.push_back(context.Args.MakeArgString(inputPath));
return {"dwarfdump", Arguments};
}
ToolChain::InvocationInfo
ToolChain::constructInvocation(const GeneratePCHJobAction &job,
const JobContext &context) const {
assert(context.Inputs.empty());
assert(context.InputActions.size() == 1);
assert((!job.isPersistentPCH() &&
context.Output.getPrimaryOutputType() == file_types::TY_PCH) ||
(job.isPersistentPCH() &&
context.Output.getPrimaryOutputType() == file_types::TY_Nothing));
InvocationInfo II{SWIFT_EXECUTABLE_NAME};
ArgStringList &Arguments = II.Arguments;
II.allowsResponseFiles = true;
for (auto &s : getDriver().getSwiftProgramArgs())
Arguments.push_back(s.c_str());
Arguments.push_back("-frontend");
addCommonFrontendArgs(context.OI, context.Output, context.Args, Arguments);
addRuntimeLibraryFlags(context.OI, Arguments);
addOutputsOfType(Arguments, context.Output, context.Args,
file_types::TY_SerializedDiagnostics,
"-serialize-diagnostics-path");
addInputsOfType(Arguments, context.InputActions, file_types::TY_ObjCHeader);
context.Args.AddLastArg(Arguments, options::OPT_index_store_path);
if (job.isPersistentPCH()) {
Arguments.push_back("-emit-pch");
Arguments.push_back("-pch-output-dir");
Arguments.push_back(context.Args.MakeArgString(job.getPersistentPCHDir()));
} else {
Arguments.push_back("-emit-pch");
Arguments.push_back("-o");
Arguments.push_back(
context.Args.MakeArgString(context.Output.getPrimaryOutputFilename()));
}
return II;
}
ToolChain::InvocationInfo
ToolChain::constructInvocation(const AutolinkExtractJobAction &job,
const JobContext &context) const {
llvm_unreachable("autolink extraction not implemented for this toolchain");
}
ToolChain::InvocationInfo
ToolChain::constructInvocation(const DynamicLinkJobAction &job,
const JobContext &context) const {
llvm_unreachable("linking not implemented for this toolchain");
}
ToolChain::InvocationInfo
ToolChain::constructInvocation(const StaticLinkJobAction &job,
const JobContext &context) const {
llvm_unreachable("archiving not implemented for this toolchain");
}
void ToolChain::addPathEnvironmentVariableIfNeeded(
Job::EnvironmentVector &env, const char *name, const char *separator,
options::ID optionID, const ArgList &args,
ArrayRef<std::string> extraEntries) const {
auto linkPathOptions = args.filtered(optionID);
if (linkPathOptions.begin() == linkPathOptions.end() && extraEntries.empty())
return;
std::string newPaths;
interleave(linkPathOptions,
[&](const Arg *arg) { newPaths.append(arg->getValue()); },
[&] { newPaths.append(separator); });
for (auto extraEntry : extraEntries) {
if (!newPaths.empty())
newPaths.append(separator);
newPaths.append(extraEntry.data(), extraEntry.size());
}
if (auto currentPaths = llvm::sys::Process::GetEnv(name)) {
newPaths.append(separator);
newPaths.append(currentPaths.getValue());
}
env.emplace_back(name, args.MakeArgString(newPaths));
}
void ToolChain::addLinkRuntimeLib(const ArgList &Args, ArgStringList &Arguments,
StringRef LibName) const {
SmallString<128> P;
getClangLibraryPath(Args, P);
llvm::sys::path::append(P, LibName);
Arguments.push_back(Args.MakeArgString(P));
}
void ToolChain::getClangLibraryPath(const ArgList &Args,
SmallString<128> &LibPath) const {
const llvm::Triple &T = getTriple();
getResourceDirPath(LibPath, Args, /*Shared=*/true);
// Remove platform name.
llvm::sys::path::remove_filename(LibPath);
llvm::sys::path::append(LibPath, "clang", "lib",
T.isOSDarwin() ? "darwin"
: getPlatformNameForTriple(T));
}
/// Get the runtime library link path, which is platform-specific and found
/// relative to the compiler.
void ToolChain::getResourceDirPath(SmallVectorImpl<char> &resourceDirPath,
const llvm::opt::ArgList &args,
bool shared) const {
if (const Arg *A = args.getLastArg(options::OPT_resource_dir)) {
StringRef value = A->getValue();
resourceDirPath.append(value.begin(), value.end());
} else if (!getTriple().isOSDarwin() && args.hasArg(options::OPT_sdk)) {
StringRef value = args.getLastArg(options::OPT_sdk)->getValue();
resourceDirPath.append(value.begin(), value.end());
llvm::sys::path::append(resourceDirPath, "usr");
CompilerInvocation::appendSwiftLibDir(resourceDirPath, shared);
} else {
auto programPath = getDriver().getSwiftProgramPath();
CompilerInvocation::computeRuntimeResourcePathFromExecutablePath(
programPath, shared, resourceDirPath);
}
StringRef libSubDir = getPlatformNameForTriple(getTriple());
if (tripleIsMacCatalystEnvironment(getTriple()))
libSubDir = "maccatalyst";
llvm::sys::path::append(resourceDirPath, libSubDir);
}
// Get the secondary runtime library link path given the primary path.
// The compiler will look for runtime libraries in the secondary path if they
// can't be found in the primary path.
void ToolChain::getSecondaryResourceDirPath(
SmallVectorImpl<char> &secondaryResourceDirPath,
StringRef primaryPath) const {
if (!tripleIsMacCatalystEnvironment(getTriple()))
return;
// For macCatalyst, the secondary runtime library path is the macOS library
// path. The compiler will find zippered libraries here.
secondaryResourceDirPath.append(primaryPath.begin(), primaryPath.end());
// Remove '/maccatalyst' and replace with 'macosx'.
llvm::sys::path::remove_filename(secondaryResourceDirPath);
llvm::sys::path::append(secondaryResourceDirPath, "macosx");
}
void ToolChain::getRuntimeLibraryPaths(SmallVectorImpl<std::string> &runtimeLibPaths,
const llvm::opt::ArgList &args,
StringRef SDKPath, bool shared) const {
SmallString<128> scratchPath;
getResourceDirPath(scratchPath, args, shared);
runtimeLibPaths.push_back(std::string(scratchPath.str()));
// If there's a secondary resource dir, add it too.
scratchPath.clear();
getSecondaryResourceDirPath(scratchPath, runtimeLibPaths[0]);
if (!scratchPath.empty())
runtimeLibPaths.push_back(std::string(scratchPath.str()));
if (!SDKPath.empty()) {
if (!scratchPath.empty()) {
// If we added the secondary resource dir, we also need the iOSSupport
// directory.
scratchPath = SDKPath;
llvm::sys::path::append(scratchPath, "System", "iOSSupport");
llvm::sys::path::append(scratchPath, "usr", "lib", "swift");
runtimeLibPaths.push_back(std::string(scratchPath.str()));
}
scratchPath = SDKPath;
llvm::sys::path::append(scratchPath, "usr", "lib", "swift");
runtimeLibPaths.push_back(std::string(scratchPath.str()));
}
}
const char *ToolChain::getClangLinkerDriver(
const llvm::opt::ArgList &Args) const {
// We don't use `clang++` unconditionally because we want to avoid pulling in
// a C++ standard library if it's not needed, in particular because the
// standard library that `clang++` selects by default may not be the one that
// is desired.
const char *LinkerDriver =
Args.hasArg(options::OPT_enable_experimental_cxx_interop) ? "clang++"
: "clang";
if (const Arg *A = Args.getLastArg(options::OPT_tools_directory)) {
StringRef toolchainPath(A->getValue());
// If there is a linker driver in the toolchain folder, use that instead.
if (auto tool = llvm::sys::findProgramByName(LinkerDriver, {toolchainPath}))
LinkerDriver = Args.MakeArgString(tool.get());
}
return LinkerDriver;
}
bool ToolChain::sanitizerRuntimeLibExists(const ArgList &args,
StringRef sanitizerName,
bool shared) const {
SmallString<128> sanitizerLibPath;
getClangLibraryPath(args, sanitizerLibPath);
llvm::sys::path::append(sanitizerLibPath,
sanitizerRuntimeLibName(sanitizerName, shared));
return llvm::sys::fs::exists(sanitizerLibPath.str());
}