[Driver] Allow passing all source files in a filelist.

Generate frontend commands with -filelist in them. This isn't actually
implemented yet, but we can start testing at this point.

Part 1 of https://bugs.swift.org/browse/SR-280.
This commit is contained in:
Jordan Rose
2016-01-12 16:43:21 -08:00
parent 67eaab6a4e
commit b45a69ef09
8 changed files with 123 additions and 31 deletions

View File

@@ -78,6 +78,12 @@ private:
/// A list of input files and their associated types.
InputFileList InputFilesWithTypes;
/// When non-null, a temporary file containing all input .swift files.
/// Used for large compilations to avoid overflowing argv.
///
/// This is a pointer to a string whose data is held in #TempFilePaths.
std::string AllSourceFilesPath;
/// Temporary files that should be cleaned up after the compilation finishes.
///
/// These apply whether the compilation succeeds or fails.
@@ -194,6 +200,15 @@ public:
LastBuildTime = time;
}
/// Requests the path to a file containing all input source files. This can
/// be shared across jobs.
///
/// If this is never called, the Compilation does not bother generating such
/// a file.
///
/// \sa types::isPartOfSwiftCompilation
const std::string &getAllSourcesPath() const;
/// Asks the Compilation to perform the Jobs which it knows about.
/// \returns result code for the Compilation's Jobs; 0 indicates success and
/// -2 indicates that one of the Compilation's Jobs crashed during execution

View File

@@ -50,13 +50,32 @@ protected:
constexpr static const char * const SWIFT_EXECUTABLE_NAME = "swift";
/// Packs together the supplementary information about the job being created.
struct JobContext {
class JobContext {
private:
const Compilation &C;
public:
ArrayRef<const Job *> Inputs;
const CommandOutput &Output;
ArrayRef<const Action *> InputActions;
const llvm::opt::ArgList &Args;
ArrayRef<InputPair> TopLevelInputFiles;
const CommandOutput &Output;
const OutputInfo &OI;
/// The arguments to the driver. Can also be used to create new strings with
/// the same lifetime.
///
/// This just caches C.getArgs().
const llvm::opt::ArgList &Args;
public:
JobContext(const Compilation &C, ArrayRef<const Job *> Inputs,
ArrayRef<const Action *> InputActions,
const CommandOutput &Output, const OutputInfo &OI);
/// Forwards to Compilation::getInputFiles.
ArrayRef<InputPair> getTopLevelInputFiles() const;
/// Forwards to Compilation::getAllSourcesPath.
const std::string &getAllSourcesPath() const;
};
/// Packs together information chosen by toolchains to create jobs.
@@ -126,11 +145,10 @@ public:
/// This method dispatches to the various \c constructInvocation methods,
/// which may be overridden by platform-specific subclasses.
std::unique_ptr<Job> constructJob(const JobAction &JA,
const Compilation &C,
SmallVectorImpl<const Job *> &&inputs,
std::unique_ptr<CommandOutput> output,
const ActionList &inputActions,
const llvm::opt::ArgList &args,
ArrayRef<InputPair> topLevelInputFiles,
std::unique_ptr<CommandOutput> output,
const OutputInfo &OI) const;
/// Return the default language type to use for the given extension.

View File

@@ -88,6 +88,8 @@ def driver_use_frontend_path : Separate<["-"], "driver-use-frontend-path">,
def driver_show_incremental : Flag<["-"], "driver-show-incremental">,
InternalDebugOpt,
HelpText<"With -v, dump information about why files are being rebuilt">;
def driver_use_filelists : Flag<["-"], "driver-use-filelists">,
InternalDebugOpt, HelpText<"Pass input files as filelists whenever possible">;
def driver_always_rebuild_dependents :
Flag<["-"], "driver-always-rebuild-dependents">, InternalDebugOpt,

View File

@@ -618,3 +618,23 @@ int Compilation::performJobs() {
return result;
}
const std::string &Compilation::getAllSourcesPath() const {
auto *mutableThis = const_cast<Compilation *>(this);
if (AllSourceFilesPath.empty()) {
SmallString<128> Buffer;
std::error_code EC =
llvm::sys::fs::createTemporaryFile("sources", "", Buffer);
if (EC) {
Diags.diagnose(SourceLoc(),
diag::error_unable_to_make_temporary_file,
EC.message());
// FIXME: This should not take down the entire process.
llvm::report_fatal_error("unable to create list of input sources");
}
mutableThis->addTemporaryFile(Buffer.str());
mutableThis->AllSourceFilesPath = TempFilePaths.back();
}
return AllSourceFilesPath;
}

View File

@@ -1855,10 +1855,9 @@ Job *Driver::buildJobsForAction(Compilation &C, const JobAction *JA,
}
// 4. Construct a Job which produces the right CommandOutput.
std::unique_ptr<Job> ownedJob = TC.constructJob(*JA, std::move(InputJobs),
std::move(Output),
InputActions, C.getArgs(),
C.getInputFiles(), OI);
std::unique_ptr<Job> ownedJob = TC.constructJob(*JA, C, std::move(InputJobs),
InputActions,
std::move(Output), OI);
Job *J = C.addJob(std::move(ownedJob));
// If we track dependencies for this job, we may be able to avoid running it.

View File

@@ -18,7 +18,7 @@
//===----------------------------------------------------------------------===//
#include "swift/Driver/ToolChain.h"
#include "swift/Driver/Compilation.h"
#include "swift/Driver/Driver.h"
#include "swift/Driver/Job.h"
#include "llvm/Option/ArgList.h"
@@ -33,16 +33,29 @@ using namespace llvm::opt;
const char * const ToolChain::SWIFT_EXECUTABLE_NAME;
ToolChain::JobContext::JobContext(const Compilation &C,
ArrayRef<const Job *> Inputs,
ArrayRef<const Action *> InputActions,
const CommandOutput &Output,
const OutputInfo &OI)
: C(C), Inputs(Inputs), InputActions(InputActions), Output(Output),
OI(OI), Args(C.getArgs()) {}
ArrayRef<InputPair> ToolChain::JobContext::getTopLevelInputFiles() const {
return C.getInputFiles();
}
const std::string &ToolChain::JobContext::getAllSourcesPath() const {
return C.getAllSourcesPath();
}
std::unique_ptr<Job>
ToolChain::constructJob(const JobAction &JA,
const Compilation &C,
SmallVectorImpl<const Job *> &&inputs,
std::unique_ptr<CommandOutput> output,
const ActionList &inputActions,
const llvm::opt::ArgList &args,
ArrayRef<InputPair> topLevelInputFiles,
std::unique_ptr<CommandOutput> output,
const OutputInfo &OI) const {
JobContext context{inputs, *output, inputActions, args, topLevelInputFiles,
OI};
JobContext context{C, inputs, inputActions, *output, OI};
auto invocationInfo = [&]() -> InvocationInfo {
switch (JA.getKind()) {
@@ -71,12 +84,12 @@ ToolChain::constructJob(const JobAction &JA,
std::string relativePath =
findProgramRelativeToSwift(invocationInfo.ExecutableName);
if (!relativePath.empty()) {
executablePath = args.MakeArgString(relativePath);
executablePath = C.getArgs().MakeArgString(relativePath);
} else {
auto systemPath =
llvm::sys::findProgramByName(invocationInfo.ExecutableName);
if (systemPath) {
executablePath = args.MakeArgString(systemPath.get());
executablePath = C.getArgs().MakeArgString(systemPath.get());
} else {
// For debugging purposes.
executablePath = invocationInfo.ExecutableName;

View File

@@ -39,6 +39,8 @@ using namespace llvm::opt;
/// The name of the Swift migrator binary.
static const char * const SWIFT_UPDATE_NAME = "swift-update";
/// The limit for passing a list of files on the command line.
static const size_t TOO_MANY_FILES = 128;
static void addInputsOfType(ArgStringList &Arguments,
ArrayRef<const Action *> Inputs,
@@ -242,9 +244,16 @@ ToolChain::constructInvocation(const CompileJobAction &job,
auto *IA = cast<InputAction>(context.InputActions[0]);
const Arg &PrimaryInputArg = IA->getInputArg();
bool FoundPrimaryInput = false;
for (auto inputPair : context.TopLevelInputFiles) {
if (context.Args.hasArg(options::OPT_driver_use_filelists) ||
context.getTopLevelInputFiles().size() > TOO_MANY_FILES) {
Arguments.push_back("-filelist");
Arguments.push_back(context.getAllSourcesPath().c_str());
Arguments.push_back("-primary-file");
PrimaryInputArg.render(context.Args, Arguments);
} else {
bool FoundPrimaryInput = false;
for (auto inputPair : context.getTopLevelInputFiles()) {
if (!types::isPartOfSwiftCompilation(inputPair.first))
continue;
@@ -256,12 +265,19 @@ ToolChain::constructInvocation(const CompileJobAction &job,
}
Arguments.push_back(inputPair.second->getValue());
}
}
break;
}
case OutputInfo::Mode::SingleCompile: {
if (context.Args.hasArg(options::OPT_driver_use_filelists) ||
context.InputActions.size() > TOO_MANY_FILES) {
Arguments.push_back("-filelist");
Arguments.push_back(context.getAllSourcesPath().c_str());
} else {
for (const Action *A : context.InputActions) {
cast<InputAction>(A)->getInputArg().render(context.Args, Arguments);
}
}
break;
}

View File

@@ -35,6 +35,8 @@
// RUN: cp %s %t
// RUN: not %swiftc_driver -driver-print-jobs -c -target x86_64-apple-macosx10.9 %s %t/driver-compile.swift 2>&1 | FileCheck -check-prefix DUPLICATE-NAME %s
// RUN: %swiftc_driver -driver-print-jobs -c -target x86_64-apple-macosx10.9 %s %S/../Inputs/empty.swift -module-name main -driver-use-filelists 2>&1 | FileCheck -check-prefix=FILELIST %s
// RUN: rm -rf %t && mkdir -p %t/DISTINCTIVE-PATH/usr/bin/
// RUN: ln %swift_driver_plain %t/DISTINCTIVE-PATH/usr/bin/swiftc
// RUN: ln -s "swiftc" %t/DISTINCTIVE-PATH/usr/bin/swift-update
@@ -102,6 +104,13 @@
// DUPLICATE-NAME: error: filename "driver-compile.swift" used twice: '{{.*}}test/Driver/driver-compile.swift' and '{{.*}}driver-compile.swift'
// DUPLICATE-NAME: note: filenames are used to distinguish private declarations with the same name
// FILELIST: bin/swift
// FILELIST: -filelist [[SOURCES:["]?[^ ]+sources[^ ]*["]?]]
// FILELIST: -primary-file {{.*/(driver-compile.swift|empty.swift)}}
// FILELIST-NEXT: bin/swift
// FILELIST: -filelist [[SOURCES]]
// FILELIST: -primary-file {{.*/(driver-compile.swift|empty.swift)}}
// UPDATE-CODE: DISTINCTIVE-PATH/usr/bin/swift-update
// UPDATE-CODE: -c{{ }}
// UPDATE-CODE: -o {{.+}}.remap