From: Hans Wennborg Date: Tue, 6 Aug 2013 22:11:28 +0000 (+0000) Subject: clang-cl: Implement support for the /Fo option X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=ab50ccd7f756a1e617ebd32471ba9565bb240d37;p=clang clang-cl: Implement support for the /Fo option This implements support for the /Fo option, which is used to set the filename or output dir for object files. Differential Revision: http://llvm-reviews.chandlerc.com/D1302 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@187820 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticDriverKinds.td b/include/clang/Basic/DiagnosticDriverKinds.td index 266e2f0f76..866bb41dba 100644 --- a/include/clang/Basic/DiagnosticDriverKinds.td +++ b/include/clang/Basic/DiagnosticDriverKinds.td @@ -33,6 +33,8 @@ def err_drv_use_of_Z_option : Error< "unsupported use of internal gcc -Z option '%0'">; def err_drv_output_argument_with_multiple_files : Error< "cannot specify -o when generating multiple output files">; +def err_drv_obj_file_argument_with_multiple_sources : Error< + "cannot specify '%0%1' when compiling multiple source files">; def err_no_external_windows_assembler : Error< "there is no external assembler we can use on windows">; def err_drv_unable_to_remove_file : Error< @@ -133,6 +135,9 @@ def warn_drv_assuming_mfloat_abi_is : Warning< "unknown platform, assuming -mfloat-abi=%0">; def warn_ignoring_ftabstop_value : Warning< "ignoring invalid -ftabstop value '%0', using default value %1">; +def warn_drv_overriding_fo_option : Warning< + "overriding '%0%1' option with '%2%3'">, + InGroup>; def warn_drv_overriding_t_option : Warning< "overriding '%0' option with '%1'">, InGroup>; diff --git a/include/clang/Driver/CLCompatOptions.td b/include/clang/Driver/CLCompatOptions.td index 5a3ad805ce..b29fc8802d 100644 --- a/include/clang/Driver/CLCompatOptions.td +++ b/include/clang/Driver/CLCompatOptions.td @@ -83,6 +83,9 @@ def _SLASH_Zs : CLFlag<"Zs">, HelpText<"Syntax-check only">, // Non-aliases: +def _SLASH_Fo : CLJoined<"Fo">, + HelpText<"Set output object file, or directory (ends in / or \\)">, + MetaVarName<"">; def _SLASH_Tc : CLJoinedOrSeparate<"Tc">, HelpText<"Specify a C source file">, MetaVarName<"">; def _SLASH_TC : CLFlag<"TC">, HelpText<"Treat all source files as C">; @@ -106,7 +109,6 @@ def _SLASH_Zc_wchar_t : CLIgnoredFlag<"Zc:wchar_t">; def _SLASH_EH : CLJoined<"EH">; def _SLASH_Fd : CLJoined<"Fd">; -def _SLASH_Fo : CLJoined<"Fo">; def _SLASH_fp : CLJoined<"fp">; def _SLASH_Gd : CLFlag<"Gd">; def _SLASH_GL : CLFlag<"GL">; diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp index 84e5fe2cfb..729b9afe62 100644 --- a/lib/Driver/Driver.cpp +++ b/lib/Driver/Driver.cpp @@ -357,6 +357,30 @@ Compilation *Driver::BuildCompilation(ArrayRef ArgList) { InputList Inputs; BuildInputs(C->getDefaultToolChain(), C->getArgs(), Inputs); + if (Arg *A = C->getArgs().getLastArg(options::OPT__SLASH_Fo)) { + // Check for multiple /Fo arguments. + for (arg_iterator it = C->getArgs().filtered_begin(options::OPT__SLASH_Fo), + ie = C->getArgs().filtered_end(); it != ie; ++it) { + if (*it != A) { + Diag(clang::diag::warn_drv_overriding_fo_option) + << (*it)->getSpelling() << (*it)->getValue() + << A->getSpelling() << A->getValue(); + } + } + + StringRef V = A->getValue(); + if (V == "") { + // It has to have a value. + Diag(clang::diag::err_drv_missing_argument) << A->getSpelling() << 1; + C->getArgs().eraseArg(options::OPT__SLASH_Fo); + } else if (Inputs.size() > 1 && !llvm::sys::path::is_separator(V.back())) { + // Check whether /Fo tries to name an output file for multiple inputs. + Diag(clang::diag::err_drv_obj_file_argument_with_multiple_sources) + << A->getSpelling() << V; + C->getArgs().eraseArg(options::OPT__SLASH_Fo); + } + } + // Construct the list of abstract actions to perform for this compilation. On // Darwin target OSes this uses the driver-driver and universal actions. if (TC.getTriple().isOSDarwin()) @@ -1559,7 +1583,8 @@ const char *Driver::GetNamedOutputPath(Compilation &C, return "-"; // Output to a temporary file? - if ((!AtTopLevel && !C.getArgs().hasArg(options::OPT_save_temps)) || + if ((!AtTopLevel && !C.getArgs().hasArg(options::OPT_save_temps) && + !C.getArgs().hasArg(options::OPT__SLASH_Fo)) || CCGenDiagnostics) { StringRef Name = llvm::sys::path::filename(BaseInput); std::pair Split = Name.split('.'); @@ -1579,7 +1604,28 @@ const char *Driver::GetNamedOutputPath(Compilation &C, // Determine what the derived output name should be. const char *NamedOutput; - if (JA.getType() == types::TY_Image) { + + if (JA.getType() == types::TY_Object && + C.getArgs().hasArg(options::OPT__SLASH_Fo)) { + // The /Fo flag decides the object filename. + StringRef Val = C.getArgs().getLastArg(options::OPT__SLASH_Fo)->getValue(); + SmallString<128> Filename = Val; + + if (llvm::sys::path::is_separator(Val.back())) { + // If /Fo names a dir, output to BaseName in that dir. + llvm::sys::path::append(Filename, BaseName); + } + if (!llvm::sys::path::has_extension(Val)) { + // If /Fo doesn't provide a filename with an extension, we set it. + if (llvm::sys::path::has_extension(Filename.str())) + Filename = Filename.substr(0, Filename.rfind(".")); + Filename.append("."); + // FIXME: For clang-cl, we want .obj rather than .o for object files. + Filename.append(types::getTypeTempSuffix(types::TY_Object)); + } + + NamedOutput = C.getArgs().MakeArgString(Filename.c_str()); + } else if (JA.getType() == types::TY_Image) { if (MultipleArchs && BoundArch) { SmallString<128> Output(DefaultImageName.c_str()); Output += "-"; diff --git a/test/Driver/cl-Fo.c b/test/Driver/cl-Fo.c new file mode 100644 index 0000000000..b820f0dcef --- /dev/null +++ b/test/Driver/cl-Fo.c @@ -0,0 +1,34 @@ +// Don't attempt slash switches on msys bash. +// REQUIRES: shell-preserves-root + +// Note: %s must be preceded by --, otherwise it may be interpreted as a +// command-line option, e.g. on Mac where %s is commonly under /Users. + +// RUN: %clang_cl /Foa -### -- %s 2>&1 | FileCheck -check-prefix=CHECK-NAME %s +// CHECK-NAME: "-o" "a.o" + +// RUN: %clang_cl /Foa.ext /Fob.ext -### -- %s 2>&1 | FileCheck -check-prefix=CHECK-NAMEEXT %s +// CHECK-NAMEEXT: warning: overriding '/Foa.ext' option with '/Fob.ext' +// CHECK-NAMEEXT: "-o" "b.ext" + +// RUN: %clang_cl /Fofoo.dir/ -### -- %s 2>&1 | FileCheck -check-prefix=CHECK-DIR %s +// CHECK-DIR: "-o" "foo.dir{{[/\\]+}}cl-Fo.o" + +// RUN: %clang_cl /Fofoo.dir/a -### -- %s 2>&1 | FileCheck -check-prefix=CHECK-DIRNAME %s +// CHECK-DIRNAME: "-o" "foo.dir{{[/\\]+}}a.o" + +// RUN: %clang_cl /Fofoo.dir/a.ext -### -- %s 2>&1 | FileCheck -check-prefix=CHECK-DIRNAMEEXT %s +// CHECK-DIRNAMEEXT: "-o" "foo.dir{{[/\\]+}}a.ext" + +// RUN: %clang_cl /Fo.. -### -- %s 2>&1 | FileCheck -check-prefix=CHECK-CRAZY %s +// CHECK-CRAZY: "-o" "...o" + + +// RUN: %clang_cl /Fo -### 2>&1 | FileCheck -check-prefix=CHECK-MISSINGARG %s +// CHECK-MISSINGARG: error: argument to '/Fo' is missing (expected 1 value) + +// RUN: %clang_cl /Foa.obj -### -- %s %s 2>&1 | FileCheck -check-prefix=CHECK-MULTIPLESOURCEERROR %s +// CHECK-MULTIPLESOURCEERROR: error: cannot specify '/Foa.obj' when compiling multiple source files + +// RUN: %clang_cl /Fomydir/ -### -- %s %s 2>&1 | FileCheck -check-prefix=CHECK-MULTIPLESOURCEOK %s +// CHECK-MULTIPLESOURCEOK: "-o" "mydir{{[/\\]+}}cl-Fo.o" diff --git a/test/Driver/cl-options.c b/test/Driver/cl-options.c index ca286f739d..ba1c1f3014 100644 --- a/test/Driver/cl-options.c +++ b/test/Driver/cl-options.c @@ -88,7 +88,7 @@ // Unsupported but parsed options. Check that we don't error on them. // (/Zs is for syntax-only) -// RUN: %clang_cl /Zs /EHsc /Fdfoo /Fobar /fp:precise /Gd /GL /GL- -- %s 2>&1 +// RUN: %clang_cl /Zs /EHsc /Fdfoo /fp:precise /Gd /GL /GL- -- %s 2>&1 // RUN: %clang_cl /Zs /Gm /Gm- /GS /Gy /Gy- /GZ /MD /MT /MDd /MTd /Oi -- %s 2>&1 // RUN: %clang_cl /Zs /RTC1 /wfoo /Zc:wchar_t- -- %s 2>&1 // RUN: %clang_cl /Zs /ZI /Zi /showIncludes -- %s 2>&1