using namespace clang;
using namespace llvm::opt;
-Driver::Driver(StringRef ClangExecutable,
- StringRef DefaultTargetTriple,
+Driver::Driver(StringRef ClangExecutable, StringRef DefaultTargetTriple,
DiagnosticsEngine &Diags)
- : Opts(createDriverOptTable()), Diags(Diags), Mode(GCCMode),
- ClangExecutable(ClangExecutable), SysRoot(DEFAULT_SYSROOT),
- UseStdLib(true), DefaultTargetTriple(DefaultTargetTriple),
- DriverTitle("clang LLVM compiler"),
- CCPrintOptionsFilename(nullptr), CCPrintHeadersFilename(nullptr),
- CCLogDiagnosticsFilename(nullptr),
- CCCPrintBindings(false),
- CCPrintHeaders(false), CCLogDiagnostics(false),
- CCGenDiagnostics(false), CCCGenericGCCName(""), CheckInputsExist(true),
- CCCUsePCH(true), SuppressMissingInputWarning(false) {
+ : Opts(createDriverOptTable()), Diags(Diags), Mode(GCCMode),
+ SaveTemps(SaveTempsNone), ClangExecutable(ClangExecutable),
+ SysRoot(DEFAULT_SYSROOT), UseStdLib(true),
+ DefaultTargetTriple(DefaultTargetTriple),
+ DriverTitle("clang LLVM compiler"), CCPrintOptionsFilename(nullptr),
+ CCPrintHeadersFilename(nullptr), CCLogDiagnosticsFilename(nullptr),
+ CCCPrintBindings(false), CCPrintHeaders(false), CCLogDiagnostics(false),
+ CCGenDiagnostics(false), CCCGenericGCCName(""), CheckInputsExist(true),
+ CCCUsePCH(true), SuppressMissingInputWarning(false) {
Name = llvm::sys::path::stem(ClangExecutable);
Dir = llvm::sys::path::parent_path(ClangExecutable);
if (const Arg *A = Args->getLastArg(options::OPT_resource_dir))
ResourceDir = A->getValue();
+ if (const Arg *A = Args->getLastArg(options::OPT_save_temps_EQ)) {
+ SaveTemps = llvm::StringSwitch<SaveTempsMode>(A->getValue())
+ .Case("cwd", SaveTempsCwd)
+ .Case("obj", SaveTempsObj)
+ .Default(SaveTempsCwd);
+ }
+
// Perform the default argument translations.
DerivedArgList *TranslatedArgs = TranslateInputArgs(*Args);
// If any of the preprocessing commands failed, clean up and exit.
if (!FailingCommands.empty()) {
- if (!C.getArgs().hasArg(options::OPT_save_temps))
+ if (!isSaveTempsEnabled())
C.CleanupFileList(C.getTempFiles(), true);
Diag(clang::diag::note_drv_command_failed_diag_msg)
const Command *FailingCommand = it->second;
// Remove result files if we're not saving temps.
- if (!C.getArgs().hasArg(options::OPT_save_temps)) {
+ if (!isSaveTempsEnabled()) {
const JobAction *JA = cast<JobAction>(&FailingCommand->getSource());
C.CleanupFileMap(C.getResultFiles(), JA, true);
}
}
-static const Tool *SelectToolForJob(Compilation &C, const ToolChain *TC,
- const JobAction *JA,
+static const Tool *SelectToolForJob(Compilation &C, bool SaveTemps,
+ const ToolChain *TC, const JobAction *JA,
const ActionList *&Inputs) {
const Tool *ToolForJob = nullptr;
// compiler input.
if (TC->useIntegratedAs() &&
- !C.getArgs().hasArg(options::OPT_save_temps) &&
+ !SaveTemps &&
!C.getArgs().hasArg(options::OPT_via_file_asm) &&
!C.getArgs().hasArg(options::OPT__SLASH_FA) &&
!C.getArgs().hasArg(options::OPT__SLASH_Fa) &&
const Tool *Compiler = TC->SelectTool(*CompileJA);
if (!Compiler)
return nullptr;
- if (!Compiler->canEmitIR() ||
- !C.getArgs().hasArg(options::OPT_save_temps)) {
+ if (!Compiler->canEmitIR() || !SaveTemps) {
Inputs = &(*Inputs)[0]->getInputs();
ToolForJob = Compiler;
}
if (Inputs->size() == 1 && isa<PreprocessJobAction>(*Inputs->begin()) &&
!C.getArgs().hasArg(options::OPT_no_integrated_cpp) &&
!C.getArgs().hasArg(options::OPT_traditional_cpp) &&
- !C.getArgs().hasArg(options::OPT_save_temps) &&
+ !SaveTemps &&
!C.getArgs().hasArg(options::OPT_rewrite_objc) &&
ToolForJob->hasIntegratedCPP())
Inputs = &(*Inputs)[0]->getInputs();
const ActionList *Inputs = &A->getInputs();
const JobAction *JA = cast<JobAction>(A);
- const Tool *T = SelectToolForJob(C, TC, JA, Inputs);
+ const Tool *T = SelectToolForJob(C, isSaveTempsEnabled(), TC, JA, Inputs);
if (!T)
return;
}
// Output to a temporary file?
- if ((!AtTopLevel && !C.getArgs().hasArg(options::OPT_save_temps) &&
+ if ((!AtTopLevel && !isSaveTempsEnabled() &&
!C.getArgs().hasArg(options::OPT__SLASH_Fo)) ||
CCGenDiagnostics) {
StringRef Name = llvm::sys::path::filename(BaseInput);
NamedOutput = C.getArgs().MakeArgString(Suffixed.c_str());
}
+ // Prepend object file path if -save-temps=obj
+ if (!AtTopLevel && isSaveTempsObj() && C.getArgs().hasArg(options::OPT_o) &&
+ JA.getType() != types::TY_PCH) {
+ Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o);
+ SmallString<128> TempPath(FinalOutput->getValue());
+ llvm::sys::path::remove_filename(TempPath);
+ StringRef OutputFileName = llvm::sys::path::filename(NamedOutput);
+ llvm::sys::path::append(TempPath, OutputFileName);
+ NamedOutput = C.getArgs().MakeArgString(TempPath.c_str());
+ }
+
// If we're saving temps and the temp file conflicts with the input file,
// then avoid overwriting input file.
- if (!AtTopLevel && C.getArgs().hasArg(options::OPT_save_temps) &&
- NamedOutput == BaseName) {
-
+ if (!AtTopLevel && isSaveTempsEnabled() && NamedOutput == BaseName) {
bool SameFile = false;
SmallString<256> Result;
llvm::sys::fs::current_path(Result);
// CHECK: "-o" "save-temps.bc"
// CHECK: "-o" "save-temps.s"
// CHECK: "-o" "save-temps.o"
-// CHECK: "-o" "a.out"
+// CHECK: "-o" "a.out"
+
+// Check -save-temps=cwd which should work the same as -save-temps above
+//
+// RUN: %clang -target x86_64-apple-darwin -save-temps=cwd -arch x86_64 %s -### 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CWD
+// CWD: "-o" "save-temps.i"
+// CWD: "-disable-llvm-optzns"
+// CWD: "-o" "save-temps.bc"
+// CWD: "-o" "save-temps.s"
+// CWD: "-o" "save-temps.o"
+// CWD: "-o" "a.out"
// Check for a single clang cc1 invocation when NOT using -save-temps.
// RUN: %clang -target x86_64-apple-darwin -arch x86_64 -S %s -### 2>&1 \
// MULT-ARCH: "-o" "save-temps-i386.bc"
// MULT-ARCH: "-o" "save-temps-i386.s"
// MULT-ARCH: "-o" "save-temps-i386.o"
-// MULT-ARCH: "-o" "a.out-i386"
+// MULT-ARCH: "-o" "a.out-i386"
// MULT-ARCH: "-o" "save-temps-x86_64.i"
// MULT-ARCH: "-o" "save-temps-x86_64.bc"
// MULT-ARCH: "-o" "save-temps-x86_64.s"
// MULT-ARCH: "-o" "save-temps-x86_64.o"
-// MULT-ARCH: "-o" "a.out-x86_64"
+// MULT-ARCH: "-o" "a.out-x86_64"
// MULT-ARCH: lipo
// MULT-ARCH: "-create" "-output" "a.out" "a.out-i386" "a.out-x86_64"
+
+// RUN: %clang -target x86_64-apple-darwin -save-temps=cwd -arch i386 -arch x86_64 %s -### 2>&1 \
+// RUN: | FileCheck %s -check-prefix=MULT-ARCH-CWD
+// MULT-ARCH-CWD: "-o" "save-temps-i386.i"
+// MULT-ARCH-CWD: "-o" "save-temps-i386.bc"
+// MULT-ARCH-CWD: "-o" "save-temps-i386.s"
+// MULT-ARCH-CWD: "-o" "save-temps-i386.o"
+// MULT-ARCH-CWD: "-o" "a.out-i386"
+// MULT-ARCH-CWD: "-o" "save-temps-x86_64.i"
+// MULT-ARCH-CWD: "-o" "save-temps-x86_64.bc"
+// MULT-ARCH-CWD: "-o" "save-temps-x86_64.s"
+// MULT-ARCH-CWD: "-o" "save-temps-x86_64.o"
+// MULT-ARCH-CWD: "-o" "a.out-x86_64"
+// MULT-ARCH-CWD: lipo
+// MULT-ARCH-CWD: "-create" "-output" "a.out" "a.out-i386" "a.out-x86_64"
+
+// Check that temp files are saved in the same directory as the output file
+// regardless of whether -o is specified.
+//
+// RUN: %clang -target x86_64-apple-darwin -save-temps=obj -o obj/dir/a.out -arch x86_64 %s -### 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK-OBJ
+// CHECK-OBJ: "-o" "obj/dir{{/|\\\\}}save-temps.i"
+// CHECK-OBJ: "-disable-llvm-optzns"
+// CHECK-OBJ: "-o" "obj/dir{{/|\\\\}}save-temps.bc"
+// CHECK-OBJ: "-o" "obj/dir{{/|\\\\}}save-temps.s"
+// CHECK-OBJ: "-o" "obj/dir{{/|\\\\}}save-temps.o"
+// CHECK-OBJ: "-o" "obj/dir{{/|\\\\}}a.out"
+//
+// RUN: %clang -target x86_64-apple-darwin -save-temps=obj -arch x86_64 %s -### 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK-OBJ-NOO
+// CHECK-OBJ-NOO: "-o" "save-temps.i"
+// CHECK-OBJ-NOO: "-disable-llvm-optzns"
+// CHECK-OBJ-NOO: "-o" "save-temps.bc"
+// CHECK-OBJ-NOO: "-o" "save-temps.s"
+// CHECK-OBJ-NOO: "-o" "save-temps.o"
+// CHECK-OBJ-NOO: "-o" "a.out"