Merge pull request #14034 from graydon/batch-mode-driver-work
NFC: Batch mode driver work
diff --git a/include/swift/Driver/Driver.h b/include/swift/Driver/Driver.h
index 67bf54a..b6285f5 100644
--- a/include/swift/Driver/Driver.h
+++ b/include/swift/Driver/Driver.h
@@ -21,6 +21,7 @@
#include "swift/Basic/LLVM.h"
#include "swift/Basic/OptionSet.h"
#include "swift/Basic/Sanitizers.h"
+#include "swift/Driver/OutputFileMap.h"
#include "swift/Driver/Types.h"
#include "swift/Driver/Util.h"
#include "llvm/ADT/DenseMap.h"
@@ -45,6 +46,7 @@
class DiagnosticEngine;
namespace driver {
class Action;
+ class CommandOutput;
class Compilation;
class Job;
class JobAction;
@@ -263,6 +265,53 @@
const ToolChain &TC, bool AtTopLevel,
JobCacheMap &JobCache) const;
+private:
+ void computeMainOutput(Compilation &C, const JobAction *JA,
+ const OutputInfo &OI, const OutputFileMap *OFM,
+ const ToolChain &TC, bool AtTopLevel,
+ SmallVectorImpl<const Action *> &InputActions,
+ SmallVectorImpl<const Job *> &InputJobs,
+ const TypeToPathMap *OutputMap, StringRef BaseInput,
+ llvm::SmallString<128> &Buf,
+ CommandOutput *Output) const;
+
+ void chooseSwiftModuleOutputPath(Compilation &C, const OutputInfo &OI,
+ const OutputFileMap *OFM,
+ const TypeToPathMap *OutputMap,
+ CommandOutput *Output) const;
+
+ void chooseSwiftModuleDocOutputPath(Compilation &C,
+ const TypeToPathMap *OutputMap,
+ CommandOutput *Output) const;
+ void chooseRemappingOutputPath(Compilation &C, const TypeToPathMap *OutputMap,
+ CommandOutput *Output) const;
+
+ void chooseSerializedDiagnosticsPath(Compilation &C, const JobAction *JA,
+ const OutputInfo &OI,
+ const TypeToPathMap *OutputMap,
+ CommandOutput *Output) const;
+
+ void chooseDependenciesOutputPaths(Compilation &C, const OutputInfo &OI,
+ const TypeToPathMap *OutputMap,
+ llvm::SmallString<128> &Buf,
+ CommandOutput *Output) const;
+
+ void chooseSaveOptimizationPath(Compilation &C, const OutputInfo &OI,
+ llvm::SmallString<128> &Buf,
+ CommandOutput *Output) const;
+
+ void chooseObjectiveCHeaderOutputPath(Compilation &C, const OutputInfo &OI,
+ const TypeToPathMap *OutputMap,
+ CommandOutput *Output) const;
+
+ void chooseLoadedModuleTracePath(Compilation &C, const OutputInfo &OI,
+ llvm::SmallString<128> &Buf,
+ CommandOutput *Output) const;
+
+ void chooseTBDPath(Compilation &C, const OutputInfo &OI,
+ llvm::SmallString<128> &Buf, CommandOutput *Output) const;
+
+public:
/// Handle any arguments which should be treated before building actions or
/// binding tools.
///
diff --git a/include/swift/Driver/Job.h b/include/swift/Driver/Job.h
index 1839506..a562111 100644
--- a/include/swift/Driver/Job.h
+++ b/include/swift/Driver/Job.h
@@ -115,7 +115,7 @@
EnvironmentVector ExtraEnvironment;
/// Whether the job wants a list of input or output files created.
- FilelistInfo FilelistFileInfo;
+ std::vector<FilelistInfo> FilelistFileInfos;
/// The modification time of the main input file, if any.
llvm::sys::TimePoint<> InputModTime = llvm::sys::TimePoint<>::max();
@@ -127,12 +127,12 @@
const char *Executable,
llvm::opt::ArgStringList Arguments,
EnvironmentVector ExtraEnvironment = {},
- FilelistInfo Info = {})
+ std::vector<FilelistInfo> Infos = {})
: SourceAndCondition(&Source, Condition::Always),
Inputs(std::move(Inputs)), Output(std::move(Output)),
Executable(Executable), Arguments(std::move(Arguments)),
ExtraEnvironment(std::move(ExtraEnvironment)),
- FilelistFileInfo(std::move(Info)) {}
+ FilelistFileInfos(std::move(Infos)) {}
const JobAction &getSource() const {
return *SourceAndCondition.getPointer();
@@ -140,7 +140,7 @@
const char *getExecutable() const { return Executable; }
const llvm::opt::ArgStringList &getArguments() const { return Arguments; }
- FilelistInfo getFilelistInfo() const { return FilelistFileInfo; }
+ ArrayRef<FilelistInfo> getFilelistInfos() const { return FilelistFileInfos; }
ArrayRef<const Job *> getInputs() const { return Inputs; }
const CommandOutput &getOutput() const { return *Output; }
diff --git a/include/swift/Driver/ToolChain.h b/include/swift/Driver/ToolChain.h
index 1b79835..98f43a7 100644
--- a/include/swift/Driver/ToolChain.h
+++ b/include/swift/Driver/ToolChain.h
@@ -90,7 +90,7 @@
const char *ExecutableName;
llvm::opt::ArgStringList Arguments;
std::vector<std::pair<const char *, const char *>> ExtraEnvironment;
- FilelistInfo FilelistInfo;
+ std::vector<FilelistInfo> FilelistInfos;
InvocationInfo(const char *name, llvm::opt::ArgStringList args = {},
decltype(ExtraEnvironment) extraEnv = {})
diff --git a/include/swift/Driver/Util.h b/include/swift/Driver/Util.h
index b7b27b3..ad9f32f 100644
--- a/include/swift/Driver/Util.h
+++ b/include/swift/Driver/Util.h
@@ -43,8 +43,9 @@
/// The Compilation is responsible for generating this file before running
/// the Job this info is attached to.
struct FilelistInfo {
- enum WhichFiles : bool {
+ enum class WhichFiles : unsigned {
Input,
+ PrimaryInputs,
Output
};
diff --git a/lib/Driver/Compilation.cpp b/lib/Driver/Compilation.cpp
index 50da198..93ce244 100644
--- a/lib/Driver/Compilation.cpp
+++ b/lib/Driver/Compilation.cpp
@@ -787,40 +787,51 @@
}
static bool writeFilelistIfNecessary(const Job *job, DiagnosticEngine &diags) {
- FilelistInfo filelistInfo = job->getFilelistInfo();
- if (filelistInfo.path.empty())
- return true;
+ bool ok = true;
+ for (const FilelistInfo &filelistInfo : job->getFilelistInfos()) {
+ if (filelistInfo.path.empty())
+ return true;
- std::error_code error;
- llvm::raw_fd_ostream out(filelistInfo.path, error, llvm::sys::fs::F_None);
- if (out.has_error()) {
- out.clear_error();
- diags.diagnose(SourceLoc(), diag::error_unable_to_make_temporary_file,
- error.message());
- return false;
- }
-
- if (filelistInfo.whichFiles == FilelistInfo::Input) {
- // FIXME: Duplicated from ToolChains.cpp.
- for (const Job *input : job->getInputs()) {
- const CommandOutput &outputInfo = input->getOutput();
- if (outputInfo.getPrimaryOutputType() == filelistInfo.type) {
- for (auto &output : outputInfo.getPrimaryOutputFilenames())
- out << output << "\n";
- } else {
- auto &output = outputInfo.getAnyOutputForType(filelistInfo.type);
- if (!output.empty())
- out << output << "\n";
- }
+ std::error_code error;
+ llvm::raw_fd_ostream out(filelistInfo.path, error, llvm::sys::fs::F_None);
+ if (out.has_error()) {
+ out.clear_error();
+ diags.diagnose(SourceLoc(), diag::error_unable_to_make_temporary_file,
+ error.message());
+ ok = false;
+ continue;
}
- } else {
- const CommandOutput &outputInfo = job->getOutput();
- assert(outputInfo.getPrimaryOutputType() == filelistInfo.type);
- for (auto &output : outputInfo.getPrimaryOutputFilenames())
- out << output << "\n";
- }
- return true;
+ switch (filelistInfo.whichFiles) {
+ case FilelistInfo::WhichFiles::Input:
+ // FIXME: Duplicated from ToolChains.cpp.
+ for (const Job *input : job->getInputs()) {
+ const CommandOutput &outputInfo = input->getOutput();
+ if (outputInfo.getPrimaryOutputType() == filelistInfo.type) {
+ for (auto &output : outputInfo.getPrimaryOutputFilenames())
+ out << output << "\n";
+ } else {
+ auto &output = outputInfo.getAnyOutputForType(filelistInfo.type);
+ if (!output.empty())
+ out << output << "\n";
+ }
+ }
+ break;
+ case FilelistInfo::WhichFiles::PrimaryInputs:
+ for (const Action *A : job->getSource().getInputs()) {
+ const auto *IA = cast<InputAction>(A);
+ out << IA->getInputArg().getValue() << "\n";
+ }
+ break;
+ case FilelistInfo::WhichFiles::Output:
+ const CommandOutput &outputInfo = job->getOutput();
+ assert(outputInfo.getPrimaryOutputType() == filelistInfo.type);
+ for (auto &output : outputInfo.getPrimaryOutputFilenames())
+ out << output << "\n";
+ break;
+ }
+ }
+ return ok;
}
int Compilation::performJobsImpl(bool &abnormalExit) {
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
index 336feda..30132fc 100644
--- a/lib/Driver/Driver.cpp
+++ b/lib/Driver/Driver.cpp
@@ -1736,6 +1736,50 @@
return None;
}
+static StringRef assignOutputName(Compilation &C, const JobAction *JA,
+ DiagnosticEngine &Diags,
+ llvm::SmallString<128> &Buffer,
+ StringRef BaseName,
+ PreserveOnSignal ShouldPreserveOnSignal) {
+ // We should output to a temporary file, since we're not at the top level
+ // (or are generating a bridging PCH, which is currently always a temp).
+ StringRef Stem = llvm::sys::path::stem(BaseName);
+ StringRef Suffix = types::getTypeTempSuffix(JA->getType());
+ std::error_code EC = llvm::sys::fs::createTemporaryFile(Stem, Suffix, Buffer);
+ if (EC) {
+ Diags.diagnose(SourceLoc(), diag::error_unable_to_make_temporary_file,
+ EC.message());
+ return {};
+ }
+ C.addTemporaryFile(Buffer.str(), ShouldPreserveOnSignal);
+
+ return Buffer.str();
+}
+
+static StringRef baseNameForImage(const JobAction *JA, const OutputInfo &OI,
+ const llvm::Triple &Triple,
+ llvm::SmallString<128> &Buffer,
+ StringRef BaseInput, StringRef BaseName) {
+ if (JA->size() == 1 && OI.ModuleNameIsFallback && BaseInput != "-")
+ return llvm::sys::path::stem(BaseInput);
+ auto link = dyn_cast<LinkJobAction>(JA);
+ if (!link)
+ return BaseName;
+ if (link->getKind() != LinkKind::DynamicLibrary)
+ return BaseName;
+
+ Buffer = Triple.isOSWindows() ? "" : "lib";
+ Buffer.append(BaseName);
+
+ if (Triple.isOSDarwin())
+ Buffer.append(".dylib");
+ else if (Triple.isOSWindows())
+ Buffer.append(".dll");
+ else
+ Buffer.append(".so");
+ return Buffer.str();
+}
+
static StringRef getOutputFilename(Compilation &C,
const JobAction *JA,
const OutputInfo &OI,
@@ -1805,47 +1849,12 @@
BaseName = OI.ModuleName;
// We don't yet have a name, assign one.
- if (!AtTopLevel) {
- // We should output to a temporary file, since we're not at the top level
- // (or are generating a bridging PCH, which is currently always a temp).
- StringRef Stem = llvm::sys::path::stem(BaseName);
- StringRef Suffix = types::getTypeTempSuffix(JA->getType());
- std::error_code EC =
- llvm::sys::fs::createTemporaryFile(Stem, Suffix, Buffer);
- if (EC) {
- Diags.diagnose(SourceLoc(),
- diag::error_unable_to_make_temporary_file,
- EC.message());
- return {};
- }
- C.addTemporaryFile(Buffer.str(), ShouldPreserveOnSignal);
+ if (!AtTopLevel)
+ return assignOutputName(C, JA, Diags, Buffer, BaseName,
+ ShouldPreserveOnSignal);
- return Buffer.str();
- }
-
-
- if (JA->getType() == types::TY_Image) {
- if (JA->size() == 1 && OI.ModuleNameIsFallback && BaseInput != "-")
- BaseName = llvm::sys::path::stem(BaseInput);
- if (auto link = dyn_cast<LinkJobAction>(JA)) {
- if (link->getKind() == LinkKind::DynamicLibrary) {
- if (Triple.isOSWindows())
- Buffer = "";
- else
- Buffer = "lib";
- Buffer.append(BaseName);
- if (Triple.isOSDarwin())
- Buffer.append(".dylib");
- else if (Triple.isOSWindows())
- Buffer.append(".dll");
- else
- Buffer.append(".so");
- return Buffer.str();
- }
- }
- return BaseName;
- }
-
+ if (JA->getType() == types::TY_Image)
+ return baseNameForImage(JA, OI, Triple, Buffer, BaseInput, BaseName);
StringRef Suffix = types::getTypeTempSuffix(JA->getType());
assert(Suffix.data() &&
@@ -2042,250 +2051,38 @@
std::unique_ptr<CommandOutput> Output(new CommandOutput(JA->getType()));
llvm::SmallString<128> Buf;
- StringRef OutputFile;
+ computeMainOutput(C, JA, OI, OFM, TC, AtTopLevel, InputActions, InputJobs,
+ OutputMap, BaseInput, Buf, Output.get());
- if (OI.isMultiThreading() && isa<CompileJobAction>(JA) &&
- types::isAfterLLVM(JA->getType())) {
- // Multi-threaded compilation: A single frontend command produces multiple
- // output file: one for each input files.
- auto OutputFunc = [&](StringRef Input) {
- const TypeToPathMap *OMForInput = nullptr;
- if (OFM)
- OMForInput = OFM->getOutputMapForInput(Input);
+ if (OI.ShouldGenerateModule && isa<CompileJobAction>(JA))
+ chooseSwiftModuleOutputPath(C, OI, OFM, OutputMap, Output.get());
- OutputFile = getOutputFilename(C, JA, OI, OMForInput, TC.getTriple(),
- C.getArgs(), AtTopLevel, Input, InputJobs,
- Diags, Buf);
- Output->addPrimaryOutput(OutputFile, Input);
- };
- // Add an output file for each input action.
- for (const Action *A : InputActions) {
- const InputAction *IA = cast<InputAction>(A);
- OutputFunc(IA->getInputArg().getValue());
-
- }
- // Add an output file for each input job.
- for (const Job *job : InputJobs) {
- OutputFunc(job->getOutput().getBaseInput(0));
- }
- } else {
- // The common case: there is a single output file.
- OutputFile = getOutputFilename(C, JA, OI, OutputMap, TC.getTriple(),
- C.getArgs(), AtTopLevel, BaseInput,
- InputJobs, Diags, Buf);
- Output->addPrimaryOutput(OutputFile, BaseInput);
- }
-
- // Choose the swiftmodule output path.
- if (OI.ShouldGenerateModule && isa<CompileJobAction>(JA)) {
- StringRef OFMModuleOutputPath;
- if (OutputMap) {
- auto iter = OutputMap->find(types::TY_SwiftModuleFile);
- if (iter != OutputMap->end())
- OFMModuleOutputPath = iter->second;
- }
-
- const Arg *A = C.getArgs().getLastArg(options::OPT_emit_module_path);
- if (!OFMModuleOutputPath.empty()) {
- // Prefer a path from the OutputMap.
- Output->setAdditionalOutputForType(types::TY_SwiftModuleFile,
- OFMModuleOutputPath);
- } else if (A && OI.CompilerMode == OutputInfo::Mode::SingleCompile) {
- // We're performing a single compilation (and thus no merge module step),
- // so prefer to use -emit-module-path, if present.
- Output->setAdditionalOutputForType(types::TY_SwiftModuleFile,
- A->getValue());
- } else if (OI.CompilerMode == OutputInfo::Mode::SingleCompile &&
- OI.ShouldTreatModuleAsTopLevelOutput) {
- // We're performing a single compile and don't have -emit-module-path,
- // but have been told to treat the module as a top-level output.
- // Determine an appropriate path.
- if (const Arg *A = C.getArgs().getLastArg(options::OPT_o)) {
- // Put the module next to the top-level output.
- llvm::SmallString<128> Path(A->getValue());
- llvm::sys::path::remove_filename(Path);
- llvm::sys::path::append(Path, OI.ModuleName);
- llvm::sys::path::replace_extension(Path, SERIALIZED_MODULE_EXTENSION);
- Output->setAdditionalOutputForType(types::TY_SwiftModuleFile, Path);
- } else {
- // A top-level output wasn't specified, so just output to
- // <ModuleName>.swiftmodule.
- llvm::SmallString<128> Path(OI.ModuleName);
- llvm::sys::path::replace_extension(Path, SERIALIZED_MODULE_EXTENSION);
- Output->setAdditionalOutputForType(types::TY_SwiftModuleFile, Path);
- }
- } else {
- // We're only generating the module as an intermediate, so put it next
- // to the primary output of the compile command.
- llvm::SmallString<128> Path(Output->getPrimaryOutputFilenames()[0]);
- bool isTempFile = C.isTemporaryFile(Path);
- llvm::sys::path::replace_extension(Path, SERIALIZED_MODULE_EXTENSION);
- Output->setAdditionalOutputForType(types::ID::TY_SwiftModuleFile, Path);
- if (isTempFile)
- C.addTemporaryFile(Path);
- }
- }
-
- // Choose the swiftdoc output path.
if (OI.ShouldGenerateModule &&
- (isa<CompileJobAction>(JA) || isa<MergeModuleJobAction>(JA))) {
- StringRef OFMModuleDocOutputPath;
- if (OutputMap) {
- auto iter = OutputMap->find(types::TY_SwiftModuleDocFile);
- if (iter != OutputMap->end())
- OFMModuleDocOutputPath = iter->second;
- }
- if (!OFMModuleDocOutputPath.empty()) {
- // Prefer a path from the OutputMap.
- Output->setAdditionalOutputForType(types::TY_SwiftModuleDocFile,
- OFMModuleDocOutputPath);
- } else {
- // Otherwise, put it next to the swiftmodule file.
- llvm::SmallString<128> Path(
- Output->getAnyOutputForType(types::TY_SwiftModuleFile));
- bool isTempFile = C.isTemporaryFile(Path);
- llvm::sys::path::replace_extension(Path,
- SERIALIZED_MODULE_DOC_EXTENSION);
- Output->setAdditionalOutputForType(types::TY_SwiftModuleDocFile, Path);
- if (isTempFile)
- C.addTemporaryFile(Path);
- }
- }
+ (isa<CompileJobAction>(JA) || isa<MergeModuleJobAction>(JA)))
+ chooseSwiftModuleDocOutputPath(C, OutputMap, Output.get());
- if (C.getArgs().hasArg(options::OPT_update_code) &&
- isa<CompileJobAction>(JA)) {
- StringRef OFMFixitsOutputPath;
- if (OutputMap) {
- auto iter = OutputMap->find(types::TY_Remapping);
- if (iter != OutputMap->end())
- OFMFixitsOutputPath = iter->second;
- }
- if (!OFMFixitsOutputPath.empty()) {
- Output->setAdditionalOutputForType(types::ID::TY_Remapping,
- OFMFixitsOutputPath);
- } else {
- llvm::SmallString<128> Path(Output->getPrimaryOutputFilenames()[0]);
- bool isTempFile = C.isTemporaryFile(Path);
- llvm::sys::path::replace_extension(Path, "remap");
- Output->setAdditionalOutputForType(types::ID::TY_Remapping, Path);
- if (isTempFile)
- C.addTemporaryFile(Path);
- }
- }
+ if (C.getArgs().hasArg(options::OPT_update_code) && isa<CompileJobAction>(JA))
+ chooseRemappingOutputPath(C, OutputMap, Output.get());
if (isa<CompileJobAction>(JA) || isa<GeneratePCHJobAction>(JA)) {
// Choose the serialized diagnostics output path.
- if (C.getArgs().hasArg(options::OPT_serialize_diagnostics)) {
- auto pchJA = dyn_cast<GeneratePCHJobAction>(JA);
- if (pchJA && pchJA->isPersistentPCH()) {
- addDiagFileOutputForPersistentPCHAction(C, pchJA, *Output, OI,
- OutputMap, Diags);
- } else {
- addAuxiliaryOutput(C, *Output, types::TY_SerializedDiagnostics, OI,
- OutputMap);
- }
-
- // Remove any existing diagnostics files so that clients can detect their
- // presence to determine if a command was run.
- StringRef OutputPath =
- Output->getAnyOutputForType(types::TY_SerializedDiagnostics);
- if (llvm::sys::fs::is_regular_file(OutputPath))
- llvm::sys::fs::remove(OutputPath);
- }
+ if (C.getArgs().hasArg(options::OPT_serialize_diagnostics))
+ chooseSerializedDiagnosticsPath(C, JA, OI, OutputMap, Output.get());
}
- if (isa<CompileJobAction>(JA)) {
- // Choose the dependencies file output path.
- if (C.getArgs().hasArg(options::OPT_emit_dependencies)) {
- addAuxiliaryOutput(C, *Output, types::TY_Dependencies, OI, OutputMap);
- }
- if (C.getIncrementalBuildEnabled()) {
- addAuxiliaryOutput(C, *Output, types::TY_SwiftDeps, OI, OutputMap);
- }
-
- // The loaded-module-trace is the same for all compile jobs: all `import`
- // statements are processed, even ones from non-primary files. Thus, only
- // one of those jobs needs to emit the file, and we can get it to write
- // straight to the desired final location.
- auto tracePathEnvVar = getenv("SWIFT_LOADED_MODULE_TRACE_FILE");
- auto shouldEmitTrace =
- tracePathEnvVar ||
- C.getArgs().hasArg(options::OPT_emit_loaded_module_trace,
- options::OPT_emit_loaded_module_trace_path);
-
- if (shouldEmitTrace &&
- C.requestPermissionForFrontendToEmitLoadedModuleTrace()) {
- StringRef filename;
- // Prefer the environment variable.
- if (tracePathEnvVar)
- filename = StringRef(tracePathEnvVar);
- else {
- // By treating this as a top-level output, the return value always
- // exists.
- filename = *getOutputFilenameFromPathArgOrAsTopLevel(
- OI, C.getArgs(), options::OPT_emit_loaded_module_trace_path,
- types::TY_ModuleTrace,
- /*TreatAsTopLevelOutput=*/true, "trace.json", Buf);
- }
-
- Output->setAdditionalOutputForType(types::TY_ModuleTrace, filename);
- }
-
- if (C.getArgs().hasArg(options::OPT_emit_tbd, options::OPT_emit_tbd_path)) {
- if (OI.CompilerMode != OutputInfo::Mode::SingleCompile) {
- llvm::outs() << "TBD emission has been disabled, because it requires a "
- << "single compiler invocation: consider enabling the "
- << "-whole-module-optimization flag.\n";
- } else {
- auto filename = *getOutputFilenameFromPathArgOrAsTopLevel(
- OI, C.getArgs(), options::OPT_emit_tbd_path, types::TY_TBD,
- /*TreatAsTopLevelOutput=*/true, "tbd", Buf);
-
- Output->setAdditionalOutputForType(types::TY_TBD, filename);
- }
- }
- }
+ if (isa<CompileJobAction>(JA))
+ chooseDependenciesOutputPaths(C, OI, OutputMap, Buf, Output.get());
if (C.getArgs().hasArg(options::OPT_save_optimization_record,
- options::OPT_save_optimization_record_path)) {
- if (OI.CompilerMode == OutputInfo::Mode::SingleCompile) {
- auto filename = *getOutputFilenameFromPathArgOrAsTopLevel(
- OI, C.getArgs(), options::OPT_save_optimization_record_path,
- types::TY_OptRecord, /*TreatAsTopLevelOutput=*/true, "opt.yaml", Buf);
+ options::OPT_save_optimization_record_path))
+ chooseSaveOptimizationPath(C, OI, Buf, Output.get());
- Output->setAdditionalOutputForType(types::TY_OptRecord, filename);
- } else
- // FIXME: We should use the OutputMap in this case.
- Diags.diagnose({}, diag::warn_opt_remark_disabled);
- }
-
- // Choose the Objective-C header output path.
if ((isa<MergeModuleJobAction>(JA) ||
(isa<CompileJobAction>(JA) &&
OI.CompilerMode == OutputInfo::Mode::SingleCompile)) &&
C.getArgs().hasArg(options::OPT_emit_objc_header,
- options::OPT_emit_objc_header_path)) {
- StringRef ObjCHeaderPath;
- if (OutputMap) {
- auto iter = OutputMap->find(types::TY_ObjCHeader);
- if (iter != OutputMap->end())
- ObjCHeaderPath = iter->second;
- }
-
- if (ObjCHeaderPath.empty())
- if (auto A = C.getArgs().getLastArg(options::OPT_emit_objc_header_path))
- ObjCHeaderPath = A->getValue();
-
- if (!ObjCHeaderPath.empty()) {
- Output->setAdditionalOutputForType(types::TY_ObjCHeader, ObjCHeaderPath);
- } else {
- // Put the header next to the primary output file.
- // FIXME: That's not correct if the user /just/ passed -emit-header
- // and not -emit-module.
- addAuxiliaryOutput(C, *Output, types::TY_ObjCHeader, OI,
- /*output file map*/nullptr);
- }
- }
+ options::OPT_emit_objc_header_path))
+ chooseObjectiveCHeaderOutputPath(C, OI, OutputMap, Output.get());
// 4. Construct a Job which produces the right CommandOutput.
std::unique_ptr<Job> ownedJob = TC.constructJob(*JA, C, std::move(InputJobs),
@@ -2371,6 +2168,274 @@
return J;
}
+void Driver::computeMainOutput(Compilation &C, const JobAction *JA,
+ const OutputInfo &OI, const OutputFileMap *OFM,
+ const ToolChain &TC, bool AtTopLevel,
+ SmallVectorImpl<const Action *> &InputActions,
+ SmallVectorImpl<const Job *> &InputJobs,
+ const TypeToPathMap *OutputMap,
+ StringRef BaseInput, llvm::SmallString<128> &Buf,
+ CommandOutput *Output) const {
+ StringRef OutputFile;
+ if (OI.isMultiThreading() && isa<CompileJobAction>(JA) &&
+ types::isAfterLLVM(JA->getType())) {
+ // Multi-threaded compilation: A single frontend command produces multiple
+ // output file: one for each input files.
+ auto OutputFunc = [&](StringRef Input) {
+ const TypeToPathMap *OMForInput = nullptr;
+ if (OFM)
+ OMForInput = OFM->getOutputMapForInput(Input);
+
+ OutputFile = getOutputFilename(C, JA, OI, OMForInput, TC.getTriple(),
+ C.getArgs(), AtTopLevel, Input, InputJobs,
+ Diags, Buf);
+ Output->addPrimaryOutput(OutputFile, Input);
+ };
+ // Add an output file for each input action.
+ for (const Action *A : InputActions) {
+ const InputAction *IA = cast<InputAction>(A);
+ OutputFunc(IA->getInputArg().getValue());
+ }
+ // Add an output file for each input job.
+ for (const Job *job : InputJobs) {
+ OutputFunc(job->getOutput().getBaseInput(0));
+ }
+ } else {
+ // The common case: there is a single output file.
+ OutputFile =
+ getOutputFilename(C, JA, OI, OutputMap, TC.getTriple(), C.getArgs(),
+ AtTopLevel, BaseInput, InputJobs, Diags, Buf);
+ Output->addPrimaryOutput(OutputFile, BaseInput);
+ }
+}
+
+void Driver::chooseSwiftModuleOutputPath(Compilation &C, const OutputInfo &OI,
+ const OutputFileMap *OFM,
+ const TypeToPathMap *OutputMap,
+ CommandOutput *Output) const {
+ StringRef OFMModuleOutputPath;
+ if (OutputMap) {
+ auto iter = OutputMap->find(types::TY_SwiftModuleFile);
+ if (iter != OutputMap->end())
+ OFMModuleOutputPath = iter->second;
+ }
+
+ const Arg *A = C.getArgs().getLastArg(options::OPT_emit_module_path);
+ if (!OFMModuleOutputPath.empty()) {
+ // Prefer a path from the OutputMap.
+ Output->setAdditionalOutputForType(types::TY_SwiftModuleFile,
+ OFMModuleOutputPath);
+ } else if (A && OI.CompilerMode == OutputInfo::Mode::SingleCompile) {
+ // We're performing a single compilation (and thus no merge module step),
+ // so prefer to use -emit-module-path, if present.
+ Output->setAdditionalOutputForType(types::TY_SwiftModuleFile,
+ A->getValue());
+ } else if (OI.CompilerMode == OutputInfo::Mode::SingleCompile &&
+ OI.ShouldTreatModuleAsTopLevelOutput) {
+ // We're performing a single compile and don't have -emit-module-path,
+ // but have been told to treat the module as a top-level output.
+ // Determine an appropriate path.
+ if (const Arg *A = C.getArgs().getLastArg(options::OPT_o)) {
+ // Put the module next to the top-level output.
+ llvm::SmallString<128> Path(A->getValue());
+ llvm::sys::path::remove_filename(Path);
+ llvm::sys::path::append(Path, OI.ModuleName);
+ llvm::sys::path::replace_extension(Path, SERIALIZED_MODULE_EXTENSION);
+ Output->setAdditionalOutputForType(types::TY_SwiftModuleFile, Path);
+ } else {
+ // A top-level output wasn't specified, so just output to
+ // <ModuleName>.swiftmodule.
+ llvm::SmallString<128> Path(OI.ModuleName);
+ llvm::sys::path::replace_extension(Path, SERIALIZED_MODULE_EXTENSION);
+ Output->setAdditionalOutputForType(types::TY_SwiftModuleFile, Path);
+ }
+ } else {
+ // We're only generating the module as an intermediate, so put it next
+ // to the primary output of the compile command.
+ llvm::SmallString<128> Path(Output->getPrimaryOutputFilenames()[0]);
+ bool isTempFile = C.isTemporaryFile(Path);
+ llvm::sys::path::replace_extension(Path, SERIALIZED_MODULE_EXTENSION);
+ Output->setAdditionalOutputForType(types::ID::TY_SwiftModuleFile, Path);
+ if (isTempFile)
+ C.addTemporaryFile(Path);
+ }
+}
+
+void Driver::chooseSwiftModuleDocOutputPath(Compilation &C,
+ const TypeToPathMap *OutputMap,
+ CommandOutput *Output) const {
+ StringRef OFMModuleDocOutputPath;
+ if (OutputMap) {
+ auto iter = OutputMap->find(types::TY_SwiftModuleDocFile);
+ if (iter != OutputMap->end())
+ OFMModuleDocOutputPath = iter->second;
+ }
+ if (!OFMModuleDocOutputPath.empty()) {
+ // Prefer a path from the OutputMap.
+ Output->setAdditionalOutputForType(types::TY_SwiftModuleDocFile,
+ OFMModuleDocOutputPath);
+ } else {
+ // Otherwise, put it next to the swiftmodule file.
+ llvm::SmallString<128> Path(
+ Output->getAnyOutputForType(types::TY_SwiftModuleFile));
+ bool isTempFile = C.isTemporaryFile(Path);
+ llvm::sys::path::replace_extension(Path, SERIALIZED_MODULE_DOC_EXTENSION);
+ Output->setAdditionalOutputForType(types::TY_SwiftModuleDocFile, Path);
+ if (isTempFile)
+ C.addTemporaryFile(Path);
+ }
+}
+
+void Driver::chooseRemappingOutputPath(Compilation &C,
+ const TypeToPathMap *OutputMap,
+ CommandOutput *Output) const {
+ StringRef OFMFixitsOutputPath;
+ if (OutputMap) {
+ auto iter = OutputMap->find(types::TY_Remapping);
+ if (iter != OutputMap->end())
+ OFMFixitsOutputPath = iter->second;
+ }
+ if (!OFMFixitsOutputPath.empty()) {
+ Output->setAdditionalOutputForType(types::ID::TY_Remapping,
+ OFMFixitsOutputPath);
+ } else {
+ llvm::SmallString<128> Path(Output->getPrimaryOutputFilenames()[0]);
+ bool isTempFile = C.isTemporaryFile(Path);
+ llvm::sys::path::replace_extension(Path, "remap");
+ Output->setAdditionalOutputForType(types::ID::TY_Remapping, Path);
+ if (isTempFile)
+ C.addTemporaryFile(Path);
+ }
+}
+
+void Driver::chooseSerializedDiagnosticsPath(Compilation &C,
+ const JobAction *JA,
+ const OutputInfo &OI,
+ const TypeToPathMap *OutputMap,
+ CommandOutput *Output) const {
+ if (C.getArgs().hasArg(options::OPT_serialize_diagnostics)) {
+ auto pchJA = dyn_cast<GeneratePCHJobAction>(JA);
+ if (pchJA && pchJA->isPersistentPCH()) {
+ addDiagFileOutputForPersistentPCHAction(C, pchJA, *Output, OI, OutputMap,
+ Diags);
+ } else {
+ addAuxiliaryOutput(C, *Output, types::TY_SerializedDiagnostics, OI,
+ OutputMap);
+ }
+
+ // Remove any existing diagnostics files so that clients can detect their
+ // presence to determine if a command was run.
+ StringRef OutputPath =
+ Output->getAnyOutputForType(types::TY_SerializedDiagnostics);
+ if (llvm::sys::fs::is_regular_file(OutputPath))
+ llvm::sys::fs::remove(OutputPath);
+ }
+}
+
+void Driver::chooseDependenciesOutputPaths(Compilation &C, const OutputInfo &OI,
+ const TypeToPathMap *OutputMap,
+ llvm::SmallString<128> &Buf,
+ CommandOutput *Output) const {
+ if (C.getArgs().hasArg(options::OPT_emit_dependencies)) {
+ addAuxiliaryOutput(C, *Output, types::TY_Dependencies, OI, OutputMap);
+ }
+ if (C.getIncrementalBuildEnabled()) {
+ addAuxiliaryOutput(C, *Output, types::TY_SwiftDeps, OI, OutputMap);
+ }
+ chooseLoadedModuleTracePath(C, OI, Buf, Output);
+ chooseTBDPath(C, OI, Buf, Output);
+}
+
+void Driver::chooseLoadedModuleTracePath(Compilation &C, const OutputInfo &OI,
+ llvm::SmallString<128> &Buf,
+ CommandOutput *Output) const {
+ // The loaded-module-trace is the same for all compile jobs: all `import`
+ // statements are processed, even ones from non-primary files. Thus, only
+ // one of those jobs needs to emit the file, and we can get it to write
+ // straight to the desired final location.
+ auto tracePathEnvVar = getenv("SWIFT_LOADED_MODULE_TRACE_FILE");
+ auto shouldEmitTrace =
+ tracePathEnvVar ||
+ C.getArgs().hasArg(options::OPT_emit_loaded_module_trace,
+ options::OPT_emit_loaded_module_trace_path);
+
+ if (shouldEmitTrace &&
+ C.requestPermissionForFrontendToEmitLoadedModuleTrace()) {
+ StringRef filename;
+ // Prefer the environment variable.
+ if (tracePathEnvVar)
+ filename = StringRef(tracePathEnvVar);
+ else {
+ // By treating this as a top-level output, the return value always
+ // exists.
+ filename = *getOutputFilenameFromPathArgOrAsTopLevel(
+ OI, C.getArgs(), options::OPT_emit_loaded_module_trace_path,
+ types::TY_ModuleTrace,
+ /*TreatAsTopLevelOutput=*/true, "trace.json", Buf);
+ }
+
+ Output->setAdditionalOutputForType(types::TY_ModuleTrace, filename);
+ }
+}
+
+void Driver::chooseTBDPath(Compilation &C, const OutputInfo &OI,
+ llvm::SmallString<128> &Buf,
+ CommandOutput *Output) const {
+ if (C.getArgs().hasArg(options::OPT_emit_tbd, options::OPT_emit_tbd_path)) {
+ if (OI.CompilerMode != OutputInfo::Mode::SingleCompile) {
+ llvm::outs() << "TBD emission has been disabled, because it requires a "
+ << "single compiler invocation: consider enabling the "
+ << "-whole-module-optimization flag.\n";
+ } else {
+ auto filename = *getOutputFilenameFromPathArgOrAsTopLevel(
+ OI, C.getArgs(), options::OPT_emit_tbd_path, types::TY_TBD,
+ /*TreatAsTopLevelOutput=*/true, "tbd", Buf);
+
+ Output->setAdditionalOutputForType(types::TY_TBD, filename);
+ }
+ }
+}
+
+void Driver::chooseSaveOptimizationPath(Compilation &C, const OutputInfo &OI,
+ llvm::SmallString<128> &Buf,
+ CommandOutput *Output) const {
+ if (OI.CompilerMode == OutputInfo::Mode::SingleCompile) {
+ auto filename = *getOutputFilenameFromPathArgOrAsTopLevel(
+ OI, C.getArgs(), options::OPT_save_optimization_record_path,
+ types::TY_OptRecord, /*TreatAsTopLevelOutput=*/true, "opt.yaml", Buf);
+
+ Output->setAdditionalOutputForType(types::TY_OptRecord, filename);
+ } else
+ // FIXME: We should use the OutputMap in this case.
+ Diags.diagnose({}, diag::warn_opt_remark_disabled);
+}
+
+void Driver::chooseObjectiveCHeaderOutputPath(Compilation &C,
+ const OutputInfo &OI,
+ const TypeToPathMap *OutputMap,
+ CommandOutput *Output) const {
+ StringRef ObjCHeaderPath;
+ if (OutputMap) {
+ auto iter = OutputMap->find(types::TY_ObjCHeader);
+ if (iter != OutputMap->end())
+ ObjCHeaderPath = iter->second;
+ }
+
+ if (ObjCHeaderPath.empty())
+ if (auto A = C.getArgs().getLastArg(options::OPT_emit_objc_header_path))
+ ObjCHeaderPath = A->getValue();
+
+ if (!ObjCHeaderPath.empty()) {
+ Output->setAdditionalOutputForType(types::TY_ObjCHeader, ObjCHeaderPath);
+ } else {
+ // Put the header next to the primary output file.
+ // FIXME: That's not correct if the user /just/ passed -emit-header
+ // and not -emit-module.
+ addAuxiliaryOutput(C, *Output, types::TY_ObjCHeader, OI,
+ /*output file map*/ nullptr);
+ }
+}
+
static unsigned printActions(const Action *A,
llvm::DenseMap<const Action *, unsigned> &Ids) {
if (Ids.count(A))
diff --git a/lib/Driver/ToolChain.cpp b/lib/Driver/ToolChain.cpp
index 0ab96f2..0e95833 100644
--- a/lib/Driver/ToolChain.cpp
+++ b/lib/Driver/ToolChain.cpp
@@ -121,7 +121,7 @@
executablePath,
std::move(invocationInfo.Arguments),
std::move(invocationInfo.ExtraEnvironment),
- std::move(invocationInfo.FilelistInfo));
+ std::move(invocationInfo.FilelistInfos));
}
std::string
diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp
index 8071960..65152ec 100644
--- a/lib/Driver/ToolChains.cpp
+++ b/lib/Driver/ToolChains.cpp
@@ -485,9 +485,9 @@
context.Output.getPrimaryOutputFilenames().size() > TOO_MANY_FILES) {
Arguments.push_back("-output-filelist");
Arguments.push_back(context.getTemporaryFilePath("outputs", ""));
- II.FilelistInfo = {Arguments.back(),
- context.Output.getPrimaryOutputType(),
- FilelistInfo::Output};
+ II.FilelistInfos.push_back({Arguments.back(),
+ context.Output.getPrimaryOutputType(),
+ FilelistInfo::WhichFiles::Output});
} else {
for (auto &FileName : context.Output.getPrimaryOutputFilenames()) {
Arguments.push_back("-o");
@@ -693,8 +693,8 @@
context.Inputs.size() > TOO_MANY_FILES) {
Arguments.push_back("-filelist");
Arguments.push_back(context.getTemporaryFilePath("inputs", ""));
- II.FilelistInfo = {Arguments.back(), types::TY_SwiftModuleFile,
- FilelistInfo::Input};
+ II.FilelistInfos.push_back({Arguments.back(), types::TY_SwiftModuleFile,
+ FilelistInfo::WhichFiles::Input});
addInputsOfType(Arguments, context.InputActions, types::TY_SwiftModuleFile);
} else {
@@ -1249,7 +1249,8 @@
context.Inputs.size() > TOO_MANY_FILES) {
Arguments.push_back("-filelist");
Arguments.push_back(context.getTemporaryFilePath("inputs", "LinkFileList"));
- II.FilelistInfo = {Arguments.back(), types::TY_Object, FilelistInfo::Input};
+ II.FilelistInfos.push_back(
+ {Arguments.back(), types::TY_Object, FilelistInfo::WhichFiles::Input});
} else {
addPrimaryInputsOfType(Arguments, context.Inputs, types::TY_Object);
}