Merge pull request #14746 from benlangmuir/working-directory

[driver] Add -working-directory option
This commit is contained in:
Ben Langmuir
2018-02-21 14:56:56 -08:00
committed by GitHub
9 changed files with 393 additions and 122 deletions

View File

@@ -556,8 +556,14 @@ Driver::buildCompilation(const ToolChain &TC,
bool ShowDriverTimeCompilation =
ArgList->hasArg(options::OPT_driver_time_compilation);
SmallString<128> workingDirectory;
if (auto *A = ArgList->getLastArg(options::OPT_working_directory)) {
workingDirectory = A->getValue();
llvm::sys::fs::make_absolute(workingDirectory);
}
std::unique_ptr<DerivedArgList> TranslatedArgList(
translateInputArgs(*ArgList));
translateInputAndPathArgs(*ArgList, workingDirectory));
validateArgs(Diags, *TranslatedArgList);
@@ -612,7 +618,8 @@ Driver::buildCompilation(const ToolChain &TC,
// REPL mode expects no input files, so suppress the error.
SuppressNoInputFilesError = true;
std::unique_ptr<OutputFileMap> OFM = buildOutputFileMap(*TranslatedArgList);
std::unique_ptr<OutputFileMap> OFM =
buildOutputFileMap(*TranslatedArgList, workingDirectory);
if (Diags.hadAnyError())
return nullptr;
@@ -708,7 +715,7 @@ Driver::buildCompilation(const ToolChain &TC,
return nullptr;
}
buildJobs(TopLevelActions, OI, OFM.get(), TC, *C);
buildJobs(TopLevelActions, OI, OFM.get(), workingDirectory, TC, *C);
if (DriverPrintDerivedOutputFileMap) {
C->getDerivedOutputFileMap().dump(llvm::outs(), true);
@@ -891,20 +898,48 @@ Driver::parseArgStrings(ArrayRef<const char *> Args) {
return ArgList;
}
DerivedArgList *Driver::translateInputArgs(const InputArgList &ArgList) const {
DerivedArgList *
Driver::translateInputAndPathArgs(const InputArgList &ArgList,
StringRef workingDirectory) const {
DerivedArgList *DAL = new DerivedArgList(ArgList);
auto addPath = [workingDirectory, DAL](Arg *A) {
assert(A->getNumValues() == 1 && "multiple values not handled");
StringRef path = A->getValue();
if (workingDirectory.empty() || path == "-" ||
llvm::sys::path::is_absolute(path)) {
DAL->append(A);
return;
}
SmallString<64> fullPath{workingDirectory};
llvm::sys::path::append(fullPath, path);
unsigned index = DAL->getBaseArgs().MakeIndex(fullPath);
Arg *newArg = new Arg(A->getOption(), A->getSpelling(), index,
DAL->getBaseArgs().getArgString(index), A);
DAL->AddSynthesizedArg(newArg);
DAL->append(newArg);
};
for (Arg *A : ArgList) {
if (A->getOption().hasFlag(options::ArgumentIsPath) ||
A->getOption().matches(options::OPT_INPUT)) {
addPath(A);
continue;
}
// If we're not in immediate mode, pick up inputs via the -- option.
if (driverKind != DriverKind::Interactive && A->getOption().matches(options::OPT__DASH_DASH)) {
A->claim();
for (unsigned i = 0, e = A->getNumValues(); i != e; ++i) {
DAL->append(makeInputArg(*DAL, *Opts, A->getValue(i)));
addPath(makeInputArg(*DAL, *Opts, A->getValue(i)));
}
continue;
}
DAL->append(A);
}
return DAL;
}
@@ -1662,13 +1697,14 @@ bool Driver::handleImmediateArgs(const ArgList &Args, const ToolChain &TC) {
}
std::unique_ptr<OutputFileMap>
Driver::buildOutputFileMap(const llvm::opt::DerivedArgList &Args) const {
Driver::buildOutputFileMap(const llvm::opt::DerivedArgList &Args,
StringRef workingDirectory) const {
const Arg *A = Args.getLastArg(options::OPT_output_file_map);
if (!A)
return nullptr;
// TODO: perform some preflight checks to ensure the file exists.
auto OFM = OutputFileMap::loadFromPath(A->getValue());
auto OFM = OutputFileMap::loadFromPath(A->getValue(), workingDirectory);
if (!OFM) {
// TODO: emit diagnostic with error string
Diags.diagnose(SourceLoc(), diag::error_unable_to_load_output_file_map);
@@ -1678,7 +1714,8 @@ Driver::buildOutputFileMap(const llvm::opt::DerivedArgList &Args) const {
void Driver::buildJobs(ArrayRef<const Action *> TopLevelActions,
const OutputInfo &OI, const OutputFileMap *OFM,
const ToolChain &TC, Compilation &C) const {
StringRef workingDirectory, const ToolChain &TC,
Compilation &C) const {
llvm::PrettyStackTraceString CrashInfo("Building compilation jobs");
const DerivedArgList &Args = C.getArgs();
@@ -1707,15 +1744,35 @@ void Driver::buildJobs(ArrayRef<const Action *> TopLevelActions,
for (const Action *A : TopLevelActions) {
if (auto *JA = dyn_cast<JobAction>(A)) {
(void)buildJobsForAction(C, JA, OI, OFM, TC, /*TopLevel*/true, JobCache);
(void)buildJobsForAction(C, JA, OI, OFM, workingDirectory, TC,
/*TopLevel=*/true, JobCache);
}
}
}
/// Form a filename based on \p base in \p result, optionally setting its
/// extension to \p newExt and in \p workingDirectory.
static void formFilenameFromBaseAndExt(StringRef base, StringRef newExt,
StringRef workingDirectory,
SmallVectorImpl<char> &result) {
if (workingDirectory.empty() || llvm::sys::path::is_absolute(base)) {
result.assign(base.begin(), base.end());
} else {
assert(!base.empty() && base != "-" && "unexpected basename");
result.assign(workingDirectory.begin(), workingDirectory.end());
llvm::sys::path::append(result, base);
}
if (!newExt.empty()) {
llvm::sys::path::replace_extension(result, newExt);
}
}
static Optional<StringRef> getOutputFilenameFromPathArgOrAsTopLevel(
const OutputInfo &OI, const llvm::opt::DerivedArgList &Args,
llvm::opt::OptSpecifier PathArg, types::ID ExpectedOutputType,
bool TreatAsTopLevelOutput, StringRef ext, llvm::SmallString<128> &Buffer) {
bool TreatAsTopLevelOutput, StringRef workingDirectory, StringRef ext,
llvm::SmallString<128> &Buffer) {
if (const Arg *A = Args.getLastArg(PathArg))
return StringRef(A->getValue());
@@ -1734,8 +1791,7 @@ static Optional<StringRef> getOutputFilenameFromPathArgOrAsTopLevel(
// A top-level output wasn't specified, so just output to
// <ModuleName>.<ext>.
Buffer = OI.ModuleName;
llvm::sys::path::replace_extension(Buffer, ext);
formFilenameFromBaseAndExt(OI.ModuleName, ext, workingDirectory, Buffer);
return Buffer.str();
}
@@ -1790,6 +1846,7 @@ static StringRef getOutputFilename(Compilation &C,
const JobAction *JA,
const OutputInfo &OI,
const TypeToPathMap *OutputMap,
StringRef workingDirectory,
const llvm::Triple &Triple,
const llvm::opt::DerivedArgList &Args,
bool AtTopLevel,
@@ -1813,8 +1870,8 @@ static StringRef getOutputFilename(Compilation &C,
if (isa<MergeModuleJobAction>(JA)) {
auto optFilename = getOutputFilenameFromPathArgOrAsTopLevel(
OI, Args, options::OPT_emit_module_path, types::TY_SwiftModuleFile,
OI.ShouldTreatModuleAsTopLevelOutput, SERIALIZED_MODULE_EXTENSION,
Buffer);
OI.ShouldTreatModuleAsTopLevelOutput, workingDirectory,
SERIALIZED_MODULE_EXTENSION, Buffer);
if (optFilename)
return *optFilename;
}
@@ -1859,15 +1916,19 @@ static StringRef getOutputFilename(Compilation &C,
return assignOutputName(C, JA, Diags, Buffer, BaseName,
ShouldPreserveOnSignal);
if (JA->getType() == types::TY_Image)
return baseNameForImage(JA, OI, Triple, Buffer, BaseInput, BaseName);
if (JA->getType() == types::TY_Image) {
SmallString<16> Base =
baseNameForImage(JA, OI, Triple, Buffer, BaseInput, BaseName);
formFilenameFromBaseAndExt(Base, /*newExt=*/"", workingDirectory, Buffer);
return Buffer.str();
}
StringRef Suffix = types::getTypeTempSuffix(JA->getType());
assert(Suffix.data() &&
"All types used for output should have a suffix.");
Buffer = llvm::sys::path::filename(BaseName);
llvm::sys::path::replace_extension(Buffer, Suffix);
formFilenameFromBaseAndExt(llvm::sys::path::filename(BaseName), Suffix,
workingDirectory, Buffer);
return Buffer.str();
}
@@ -1886,6 +1947,7 @@ static bool hasExistingAdditionalOutput(CommandOutput &output,
static void addAuxiliaryOutput(Compilation &C, CommandOutput &output,
types::ID outputType, const OutputInfo &OI,
const TypeToPathMap *outputMap,
StringRef workingDirectory,
StringRef outputPath = StringRef()) {
if (hasExistingAdditionalOutput(output, outputType, outputPath))
@@ -1910,8 +1972,10 @@ static void addAuxiliaryOutput(Compilation &C, CommandOutput &output,
path = output.getPrimaryOutputFilenames()[0];
else if (!output.getBaseInput(0).empty())
path = llvm::sys::path::stem(output.getBaseInput(0));
else
path = OI.ModuleName;
else {
formFilenameFromBaseAndExt(OI.ModuleName, /*newExt=*/"", workingDirectory,
path);
}
bool isTempFile = C.isTemporaryFile(path);
llvm::sys::path::replace_extension(path,
@@ -1922,12 +1986,10 @@ static void addAuxiliaryOutput(Compilation &C, CommandOutput &output,
}
}
static void addDiagFileOutputForPersistentPCHAction(Compilation &C,
const GeneratePCHJobAction *JA,
CommandOutput &output,
const OutputInfo &OI,
const TypeToPathMap *outputMap,
DiagnosticEngine &diags) {
static void addDiagFileOutputForPersistentPCHAction(
Compilation &C, const GeneratePCHJobAction *JA, CommandOutput &output,
const OutputInfo &OI, const TypeToPathMap *outputMap,
StringRef workingDirectory, DiagnosticEngine &diags) {
assert(JA->isPersistentPCH());
// For a persistent PCH we don't use an output, the frontend determines
@@ -1970,7 +2032,7 @@ static void addDiagFileOutputForPersistentPCHAction(Compilation &C,
if (!outPathBuf.empty()) {
addAuxiliaryOutput(C, output, types::TY_SerializedDiagnostics, OI,
outputMap, outPathBuf.str());
outputMap, workingDirectory, outPathBuf.str());
}
}
@@ -2022,10 +2084,9 @@ handleCompileJobCondition(Job *J, CompileJobAction::InputInfo inputInfo,
}
Job *Driver::buildJobsForAction(Compilation &C, const JobAction *JA,
const OutputInfo &OI,
const OutputFileMap *OFM,
const ToolChain &TC, bool AtTopLevel,
JobCacheMap &JobCache) const {
const OutputInfo &OI, const OutputFileMap *OFM,
StringRef workingDirectory, const ToolChain &TC,
bool AtTopLevel, JobCacheMap &JobCache) const {
PrettyStackTraceDriverAction CrashInfo("building jobs", JA);
@@ -2043,8 +2104,8 @@ Job *Driver::buildJobsForAction(Compilation &C, const JobAction *JA,
SmallVector<const Job *, 4> InputJobs;
for (const Action *Input : *JA) {
if (auto *InputJobAction = dyn_cast<JobAction>(Input)) {
InputJobs.push_back(buildJobsForAction(C, InputJobAction, OI, OFM,
TC, false, JobCache));
InputJobs.push_back(buildJobsForAction(
C, InputJobAction, OI, OFM, workingDirectory, TC, false, JobCache));
} else {
InputActions.push_back(Input);
}
@@ -2087,14 +2148,17 @@ Job *Driver::buildJobsForAction(Compilation &C, const JobAction *JA,
Output.get());
llvm::SmallString<128> Buf;
computeMainOutput(C, JA, OI, OFM, TC, AtTopLevel, InputActions, InputJobs,
OutputMap, BaseInput, PrimaryInput, Buf, Output.get());
OutputMap, workingDirectory, BaseInput, PrimaryInput, Buf,
Output.get());
if (OI.ShouldGenerateModule && isa<CompileJobAction>(JA))
chooseSwiftModuleOutputPath(C, OI, OFM, OutputMap, Output.get());
chooseSwiftModuleOutputPath(C, OI, OFM, OutputMap, workingDirectory,
Output.get());
if (OI.ShouldGenerateModule &&
(isa<CompileJobAction>(JA) || isa<MergeModuleJobAction>(JA)))
chooseSwiftModuleDocOutputPath(C, OutputMap, Output.get());
chooseSwiftModuleDocOutputPath(C, OutputMap, workingDirectory,
Output.get());
if (C.getArgs().hasArg(options::OPT_update_code) && isa<CompileJobAction>(JA))
chooseRemappingOutputPath(C, OutputMap, Output.get());
@@ -2102,22 +2166,25 @@ Job *Driver::buildJobsForAction(Compilation &C, const JobAction *JA,
if (isa<CompileJobAction>(JA) || isa<GeneratePCHJobAction>(JA)) {
// Choose the serialized diagnostics output path.
if (C.getArgs().hasArg(options::OPT_serialize_diagnostics))
chooseSerializedDiagnosticsPath(C, JA, OI, OutputMap, Output.get());
chooseSerializedDiagnosticsPath(C, JA, OI, OutputMap, workingDirectory,
Output.get());
}
if (isa<CompileJobAction>(JA))
chooseDependenciesOutputPaths(C, OI, OutputMap, Buf, Output.get());
chooseDependenciesOutputPaths(C, OI, OutputMap, workingDirectory, Buf,
Output.get());
if (C.getArgs().hasArg(options::OPT_save_optimization_record,
options::OPT_save_optimization_record_path))
chooseOptimizationRecordPath(C, OI, Buf, Output.get());
chooseOptimizationRecordPath(C, OI, workingDirectory, Buf, Output.get());
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))
chooseObjectiveCHeaderOutputPath(C, OI, OutputMap, Output.get());
chooseObjectiveCHeaderOutputPath(C, OI, OutputMap, workingDirectory,
Output.get());
// 4. Construct a Job which produces the right CommandOutput.
std::unique_ptr<Job> ownedJob = TC.constructJob(*JA, C, std::move(InputJobs),
@@ -2203,15 +2270,13 @@ Job *Driver::buildJobsForAction(Compilation &C, const JobAction *JA,
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, StringRef PrimaryInput,
llvm::SmallString<128> &Buf,
CommandOutput *Output) const {
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 workingDirectory, StringRef BaseInput, StringRef PrimaryInput,
llvm::SmallString<128> &Buf, CommandOutput *Output) const {
StringRef OutputFile;
if (OI.isMultiThreading() && isa<CompileJobAction>(JA) &&
types::isAfterLLVM(JA->getType())) {
@@ -2222,9 +2287,9 @@ void Driver::computeMainOutput(Compilation &C, const JobAction *JA,
if (OFM)
OMForInput = OFM->getOutputMapForInput(Base);
OutputFile = getOutputFilename(C, JA, OI, OMForInput, TC.getTriple(),
C.getArgs(), AtTopLevel, Base, Primary,
Diags, Buf);
OutputFile = getOutputFilename(C, JA, OI, OMForInput, workingDirectory,
TC.getTriple(), C.getArgs(), AtTopLevel,
Base, Primary, Diags, Buf);
Output->addPrimaryOutput(CommandInputPair{Base, Primary},
OutputFile);
};
@@ -2244,9 +2309,9 @@ void Driver::computeMainOutput(Compilation &C, const JobAction *JA,
}
} else {
// The common case: there is a single output file.
OutputFile =
getOutputFilename(C, JA, OI, OutputMap, TC.getTriple(), C.getArgs(),
AtTopLevel, BaseInput, PrimaryInput, Diags, Buf);
OutputFile = getOutputFilename(C, JA, OI, OutputMap, workingDirectory,
TC.getTriple(), C.getArgs(), AtTopLevel,
BaseInput, PrimaryInput, Diags, Buf);
Output->addPrimaryOutput(
CommandInputPair{BaseInput, PrimaryInput},
OutputFile);
@@ -2256,6 +2321,7 @@ void Driver::computeMainOutput(Compilation &C, const JobAction *JA,
void Driver::chooseSwiftModuleOutputPath(Compilation &C, const OutputInfo &OI,
const OutputFileMap *OFM,
const TypeToPathMap *OutputMap,
StringRef workingDirectory,
CommandOutput *Output) const {
if (hasExistingAdditionalOutput(*Output, types::TY_SwiftModuleFile))
@@ -2317,6 +2383,7 @@ void Driver::chooseSwiftModuleOutputPath(Compilation &C, const OutputInfo &OI,
void Driver::chooseSwiftModuleDocOutputPath(Compilation &C,
const TypeToPathMap *OutputMap,
StringRef workingDirectory,
CommandOutput *Output) const {
if (hasExistingAdditionalOutput(*Output, types::TY_SwiftModuleDocFile))
@@ -2374,15 +2441,16 @@ void Driver::chooseSerializedDiagnosticsPath(Compilation &C,
const JobAction *JA,
const OutputInfo &OI,
const TypeToPathMap *OutputMap,
StringRef workingDirectory,
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);
workingDirectory, Diags);
} else {
addAuxiliaryOutput(C, *Output, types::TY_SerializedDiagnostics, OI,
OutputMap);
OutputMap, workingDirectory);
}
// Remove any existing diagnostics files so that clients can detect their
@@ -2396,19 +2464,23 @@ void Driver::chooseSerializedDiagnosticsPath(Compilation &C,
void Driver::chooseDependenciesOutputPaths(Compilation &C, const OutputInfo &OI,
const TypeToPathMap *OutputMap,
StringRef workingDirectory,
llvm::SmallString<128> &Buf,
CommandOutput *Output) const {
if (C.getArgs().hasArg(options::OPT_emit_dependencies)) {
addAuxiliaryOutput(C, *Output, types::TY_Dependencies, OI, OutputMap);
addAuxiliaryOutput(C, *Output, types::TY_Dependencies, OI, OutputMap,
workingDirectory);
}
if (C.getIncrementalBuildEnabled()) {
addAuxiliaryOutput(C, *Output, types::TY_SwiftDeps, OI, OutputMap);
addAuxiliaryOutput(C, *Output, types::TY_SwiftDeps, OI, OutputMap,
workingDirectory);
}
chooseLoadedModuleTracePath(C, OI, Buf, Output);
chooseTBDPath(C, OI, Buf, Output);
chooseLoadedModuleTracePath(C, OI, workingDirectory, Buf, Output);
chooseTBDPath(C, OI, workingDirectory, Buf, Output);
}
void Driver::chooseLoadedModuleTracePath(Compilation &C, const OutputInfo &OI,
StringRef workingDirectory,
llvm::SmallString<128> &Buf,
CommandOutput *Output) const {
// The loaded-module-trace is the same for all compile jobs: all `import`
@@ -2433,7 +2505,7 @@ void Driver::chooseLoadedModuleTracePath(Compilation &C, const OutputInfo &OI,
filename = *getOutputFilenameFromPathArgOrAsTopLevel(
OI, C.getArgs(), options::OPT_emit_loaded_module_trace_path,
types::TY_ModuleTrace,
/*TreatAsTopLevelOutput=*/true, "trace.json", Buf);
/*TreatAsTopLevelOutput=*/true, workingDirectory, "trace.json", Buf);
}
Output->setAdditionalOutputForType(types::TY_ModuleTrace, filename);
@@ -2441,6 +2513,7 @@ void Driver::chooseLoadedModuleTracePath(Compilation &C, const OutputInfo &OI,
}
void Driver::chooseTBDPath(Compilation &C, const OutputInfo &OI,
StringRef workingDirectory,
llvm::SmallString<128> &Buf,
CommandOutput *Output) const {
if (C.getArgs().hasArg(options::OPT_emit_tbd, options::OPT_emit_tbd_path)) {
@@ -2451,7 +2524,7 @@ void Driver::chooseTBDPath(Compilation &C, const OutputInfo &OI,
} else {
auto filename = *getOutputFilenameFromPathArgOrAsTopLevel(
OI, C.getArgs(), options::OPT_emit_tbd_path, types::TY_TBD,
/*TreatAsTopLevelOutput=*/true, "tbd", Buf);
/*TreatAsTopLevelOutput=*/true, workingDirectory, "tbd", Buf);
Output->setAdditionalOutputForType(types::TY_TBD, filename);
}
@@ -2459,12 +2532,14 @@ void Driver::chooseTBDPath(Compilation &C, const OutputInfo &OI,
}
void Driver::chooseOptimizationRecordPath(Compilation &C, const OutputInfo &OI,
StringRef workingDirectory,
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);
types::TY_OptRecord, /*TreatAsTopLevelOutput=*/true, workingDirectory,
"opt.yaml", Buf);
Output->setAdditionalOutputForType(types::TY_OptRecord, filename);
} else
@@ -2475,6 +2550,7 @@ void Driver::chooseOptimizationRecordPath(Compilation &C, const OutputInfo &OI,
void Driver::chooseObjectiveCHeaderOutputPath(Compilation &C,
const OutputInfo &OI,
const TypeToPathMap *OutputMap,
StringRef workingDirectory,
CommandOutput *Output) const {
if (hasExistingAdditionalOutput(*Output, types::TY_ObjCHeader))
@@ -2498,7 +2574,7 @@ void Driver::chooseObjectiveCHeaderOutputPath(Compilation &C,
// 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);
/*output file map*/ nullptr, workingDirectory);
}
}