From cc44eec4a2f354453ab71cf5a070b287fbcf0486 Mon Sep 17 00:00:00 2001 From: Paul Robinson <paul_robinson@playstation.sony.com> Date: Mon, 27 Apr 2015 18:14:32 +0000 Subject: [PATCH] Support generating NMake/Jom-style depfiles. NMake is a Make-like builder that comes with Microsoft Visual Studio. Jom (https://wiki.qt.io/Jom) is an NMake-compatible build tool. Dependency files for NMake/Jom need to use double-quotes to wrap filespecs containing special characters, instead of the backslash escapes that GNU Make wants. Adds the -MV option, which specifies to use double-quotes as needed instead of backslash escapes when writing the dependency file. Differential Revision: http://reviews.llvm.org/D9260 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@235903 91177308-0d34-0410-b5e6-96231b3b80d8 --- docs/UsersManual.rst | 19 +++++++++++++ include/clang/Driver/Options.td | 2 ++ .../clang/Frontend/DependencyOutputOptions.h | 9 +++++- lib/Driver/Tools.cpp | 1 + lib/Frontend/CompilerInvocation.cpp | 2 ++ lib/Frontend/DependencyFile.cpp | 28 +++++++++++++++---- test/Frontend/dependency-gen-escaping.c | 9 ++++++ 7 files changed, 64 insertions(+), 6 deletions(-) diff --git a/docs/UsersManual.rst b/docs/UsersManual.rst index bf8ce78036f..3f1b864d518 100644 --- a/docs/UsersManual.rst +++ b/docs/UsersManual.rst @@ -589,6 +589,25 @@ Current limitations translated from debug annotations. That translation can be lossy, which results in some remarks having no location information. +Other Options +------------- +Clang options that that don't fit neatly into other categories. + +.. option:: -MV + + When emitting a dependency file, use formatting conventions appropriate + for NMake or Jom. Ignored unless another option causes Clang to emit a + dependency file. + +When Clang emits a dependency file (e.g., you supplied the -M option) +most filenames can be written to the file without any special formatting. +Different Make tools will treat different sets of characters as "special" +and use different conventions for telling the Make tool that the character +is actually part of the filename. Normally Clang uses backslash to "escape" +a special character, which is the convention used by GNU Make. The -MV +option tells Clang to put double-quotes around the entire filename, which +is the convention used by NMake and Jom. + Language and Target-Independent Features ======================================== diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td index ab80b0910a7..b0eb0de804d 100644 --- a/include/clang/Driver/Options.td +++ b/include/clang/Driver/Options.td @@ -250,6 +250,8 @@ def MQ : JoinedOrSeparate<["-"], "MQ">, Group<M_Group>, Flags<[CC1Option]>, HelpText<"Specify name of main file output to quote in depfile">; def MT : JoinedOrSeparate<["-"], "MT">, Group<M_Group>, Flags<[CC1Option]>, HelpText<"Specify name of main file output in depfile">; +def MV : Flag<["-"], "MV">, Group<M_Group>, Flags<[CC1Option]>, + HelpText<"Use NMake/Jom format for the depfile">; def Mach : Flag<["-"], "Mach">; def O0 : Flag<["-"], "O0">, Group<O_Group>, Flags<[CC1Option]>; def O4 : Flag<["-"], "O4">, Group<O_Group>, Flags<[CC1Option]>; diff --git a/include/clang/Frontend/DependencyOutputOptions.h b/include/clang/Frontend/DependencyOutputOptions.h index 5da14597b64..2221b54cf85 100644 --- a/include/clang/Frontend/DependencyOutputOptions.h +++ b/include/clang/Frontend/DependencyOutputOptions.h @@ -15,6 +15,9 @@ namespace clang { +/// DependencyOutputFormat - Format for the compiler dependency file. +enum class DependencyOutputFormat { Make, NMake }; + /// DependencyOutputOptions - Options for controlling the compiler dependency /// file generation. class DependencyOutputOptions { @@ -27,7 +30,10 @@ public: unsigned AddMissingHeaderDeps : 1; ///< Add missing headers to dependency list unsigned PrintShowIncludes : 1; ///< Print cl.exe style /showIncludes info. unsigned IncludeModuleFiles : 1; ///< Include module file dependencies. - + + /// The format for the dependency file. + DependencyOutputFormat OutputFormat; + /// The file to write dependency output to. std::string OutputFile; @@ -55,6 +61,7 @@ public: AddMissingHeaderDeps = 0; PrintShowIncludes = 0; IncludeModuleFiles = 0; + OutputFormat = DependencyOutputFormat::Make; } }; diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp index 3053d9bde7d..526968cf41b 100644 --- a/lib/Driver/Tools.cpp +++ b/lib/Driver/Tools.cpp @@ -338,6 +338,7 @@ void Clang::AddPreprocessingOptions(Compilation &C, } Args.AddLastArg(CmdArgs, options::OPT_MP); + Args.AddLastArg(CmdArgs, options::OPT_MV); // Convert all -MQ <target> args to -MT <quoted target> for (arg_iterator it = Args.filtered_begin(options::OPT_MT, diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index da1a088097e..2a80b07beec 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -661,6 +661,8 @@ static void ParseDependencyOutputArgs(DependencyOutputOptions &Opts, Opts.DOTOutputFile = Args.getLastArgValue(OPT_dependency_dot); Opts.ModuleDependencyOutputDir = Args.getLastArgValue(OPT_module_dependency_dir); + if (Args.hasArg(OPT_MV)) + Opts.OutputFormat = DependencyOutputFormat::NMake; } bool clang::ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args, diff --git a/lib/Frontend/DependencyFile.cpp b/lib/Frontend/DependencyFile.cpp index 6ea8f5193ef..6bea22ed592 100644 --- a/lib/Frontend/DependencyFile.cpp +++ b/lib/Frontend/DependencyFile.cpp @@ -150,6 +150,8 @@ class DFGImpl : public PPCallbacks { bool AddMissingHeaderDeps; bool SeenMissingHeader; bool IncludeModuleFiles; + DependencyOutputFormat OutputFormat; + private: bool FileMatchesDepCriteria(const char *Filename, SrcMgr::CharacteristicKind FileType); @@ -162,7 +164,8 @@ public: PhonyTarget(Opts.UsePhonyTargets), AddMissingHeaderDeps(Opts.AddMissingHeaderDeps), SeenMissingHeader(false), - IncludeModuleFiles(Opts.IncludeModuleFiles) {} + IncludeModuleFiles(Opts.IncludeModuleFiles), + OutputFormat(Opts.OutputFormat) {} void FileChanged(SourceLocation Loc, FileChangeReason Reason, SrcMgr::CharacteristicKind FileType, @@ -290,8 +293,23 @@ void DFGImpl::AddFilename(StringRef Filename) { } /// PrintFilename - GCC escapes spaces, # and $, but apparently not ' or " or -/// other scary characters. -static void PrintFilename(raw_ostream &OS, StringRef Filename) { +/// other scary characters. NMake/Jom has a different set of scary characters, +/// but wraps filespecs in double-quotes to avoid misinterpreting them; +/// https://msdn.microsoft.com/en-us/library/dd9y37ha.aspx for NMake info, +/// https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx +/// for Windows file-naming info. +static void PrintFilename(raw_ostream &OS, StringRef Filename, + DependencyOutputFormat OutputFormat) { + if (OutputFormat == DependencyOutputFormat::NMake) { + // Add quotes if needed. These are the characters listed as "special" to + // NMake, that are legal in a Windows filespec, and that could cause + // misinterpretation of the dependency string. + if (Filename.find_first_of(" #${}^!") != StringRef::npos) + OS << '\"' << Filename << '\"'; + else + OS << Filename; + return; + } for (unsigned i = 0, e = Filename.size(); i != e; ++i) { if (Filename[i] == ' ' || Filename[i] == '#') OS << '\\'; @@ -354,7 +372,7 @@ void DFGImpl::OutputDependencyFile() { Columns = 2; } OS << ' '; - PrintFilename(OS, *I); + PrintFilename(OS, *I, OutputFormat); Columns += N + 1; } OS << '\n'; @@ -365,7 +383,7 @@ void DFGImpl::OutputDependencyFile() { for (std::vector<std::string>::iterator I = Files.begin() + 1, E = Files.end(); I != E; ++I) { OS << '\n'; - PrintFilename(OS, *I); + PrintFilename(OS, *I, OutputFormat); OS << ":\n"; } } diff --git a/test/Frontend/dependency-gen-escaping.c b/test/Frontend/dependency-gen-escaping.c index 551df989588..f8adadc45bf 100644 --- a/test/Frontend/dependency-gen-escaping.c +++ b/test/Frontend/dependency-gen-escaping.c @@ -4,13 +4,22 @@ // RUN: echo > '%t.dir/ .h' // RUN: echo > '%t.dir/$$.h' // RUN: echo > '%t.dir/##.h' +// RUN: echo > '%t.dir/normal.h' // RUN: cd %t.dir // RUN: %clang -MD -MF - %s -fsyntax-only -I. | FileCheck -strict-whitespace %s +// RUN: %clang -MD -MF - -MV %s -fsyntax-only -I. | FileCheck -strict-whitespace %s --check-prefix=QUOTE // CHECK: \ \ \ \ .h // CHECK: $$$$.h // CHECK: \#\#.h +// QUOTE: " .h" +// QUOTE: "$$.h" +// QUOTE: "##.h" +// QUOTE-NOT: " +// QUOTE: normal.h +// QUOTE-NOT: " #include " .h" #include "$$.h" #include "##.h" +#include "normal.h" -- GitLab