Index: cfe/trunk/include/clang/Driver/Driver.h =================================================================== --- cfe/trunk/include/clang/Driver/Driver.h +++ cfe/trunk/include/clang/Driver/Driver.h @@ -61,6 +61,12 @@ CLMode } Mode; + enum SaveTempsMode { + SaveTempsNone, + SaveTempsCwd, + SaveTempsObj + } SaveTemps; + public: // Diag - Forwarding function for diagnostics. DiagnosticBuilder Diag(unsigned DiagID) const { @@ -232,6 +238,9 @@ InstalledDir = Value; } + bool isSaveTempsEnabled() const { return SaveTemps != SaveTempsNone; } + bool isSaveTempsObj() const { return SaveTemps == SaveTempsObj; } + /// @} /// @name Primary Functionality /// @{ Index: cfe/trunk/include/clang/Driver/Options.td =================================================================== --- cfe/trunk/include/clang/Driver/Options.td +++ cfe/trunk/include/clang/Driver/Options.td @@ -1454,7 +1454,10 @@ def rpath : Separate<["-"], "rpath">, Flags<[LinkerInput]>; def rtlib_EQ : Joined<["-", "--"], "rtlib=">; def r : Flag<["-"], "r">; +def save_temps_EQ : Joined<["-", "--"], "save-temps=">, Flags<[DriverOption]>, + HelpText<"Save intermediate compilation results.">; def save_temps : Flag<["-", "--"], "save-temps">, Flags<[DriverOption]>, + Alias, AliasArgs<["cwd"]>, HelpText<"Save intermediate compilation results">; def via_file_asm : Flag<["-", "--"], "via-file-asm">, InternalDebugOpt, HelpText<"Write assembly to file for input to assemble jobs">; Index: cfe/trunk/lib/Driver/Driver.cpp =================================================================== --- cfe/trunk/lib/Driver/Driver.cpp +++ cfe/trunk/lib/Driver/Driver.cpp @@ -44,19 +44,17 @@ 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); @@ -364,6 +362,13 @@ 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(A->getValue()) + .Case("cwd", SaveTempsCwd) + .Case("obj", SaveTempsObj) + .Default(SaveTempsCwd); + } + // Perform the default argument translations. DerivedArgList *TranslatedArgs = TranslateInputArgs(*Args); @@ -504,7 +509,7 @@ // 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) @@ -612,7 +617,7 @@ 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(&FailingCommand->getSource()); C.CleanupFileMap(C.getResultFiles(), JA, true); @@ -1471,8 +1476,8 @@ } } -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; @@ -1481,7 +1486,7 @@ // 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) && @@ -1512,8 +1517,7 @@ 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; } @@ -1529,7 +1533,7 @@ if (Inputs->size() == 1 && isa(*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(); @@ -1577,7 +1581,7 @@ const ActionList *Inputs = &A->getInputs(); const JobAction *JA = cast(A); - const Tool *T = SelectToolForJob(C, TC, JA, Inputs); + const Tool *T = SelectToolForJob(C, isSaveTempsEnabled(), TC, JA, Inputs); if (!T) return; @@ -1708,7 +1712,7 @@ } // 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); @@ -1780,11 +1784,20 @@ 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); Index: cfe/trunk/lib/Driver/Tools.cpp =================================================================== --- cfe/trunk/lib/Driver/Tools.cpp +++ cfe/trunk/lib/Driver/Tools.cpp @@ -4495,7 +4495,7 @@ // With -save-temps, we want to save the unoptimized bitcode output from the // CompileJobAction, so disable optimizations if they are not already // disabled. - if (Args.hasArg(options::OPT_save_temps) && !OptDisabled && + if (C.getDriver().isSaveTempsEnabled() && !OptDisabled && isa(JA)) CmdArgs.push_back("-disable-llvm-optzns"); Index: cfe/trunk/test/Driver/save-temps.c =================================================================== --- cfe/trunk/test/Driver/save-temps.c +++ cfe/trunk/test/Driver/save-temps.c @@ -5,7 +5,18 @@ // 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 \ @@ -20,11 +31,47 @@ // 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"