Added module map generation option.

llvm-svn: 192703
diff --git a/clang-tools-extra/modularize/Modularize.cpp b/clang-tools-extra/modularize/Modularize.cpp
index 1debe93..e9c2cf7 100644
--- a/clang-tools-extra/modularize/Modularize.cpp
+++ b/clang-tools-extra/modularize/Modularize.cpp
@@ -90,6 +90,25 @@
 //
 // See PreprocessorTracker.cpp for additional details.
 //
+// Modularize also has an option ("-module-map-path=module.map") that will
+// skip the checks, and instead act as a module.map generation assistant,
+// generating a module map file based on the header list.  An optional
+// "-root-module=(rootName)" argument can specify a root module to be
+// created in the generated module.map file.  Note that you will likely
+// need to edit this file to suit the needs of your headers.
+//
+// An example command line for generating a module.map file:
+//
+//   modularize -module-map-path=module.map -root-module=myroot headerlist.txt
+//
+// Note that if the headers in the header list have partial paths, sub-modules
+// will be created for the subdirectires involved, assuming that the
+// subdirectories contain headers to be grouped into a module, but still with
+// individual modules for the headers in the subdirectory.
+//
+// See the ModuleAssistant.cpp file comments for additional details about the
+// implementation of the assistant mode.
+//
 // Future directions:
 //
 // Basically, we want to add new checks for whatever we can check with respect
@@ -134,8 +153,6 @@
 #include "clang/Tooling/CompilationDatabase.h"
 #include "clang/Tooling/Tooling.h"
 #include "llvm/ADT/OwningPtr.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/StringMap.h"
 #include "llvm/Config/config.h"
 #include "llvm/Option/Arg.h"
 #include "llvm/Option/ArgList.h"
@@ -150,6 +167,7 @@
 #include <iterator>
 #include <string>
 #include <vector>
+#include "Modularize.h"
 #include "PreprocessorTracker.h"
 
 using namespace clang;
@@ -178,8 +196,24 @@
         " If not specified,"
         " the files are considered to be relative to the header list file."));
 
-typedef SmallVector<std::string, 4> DependentsVector;
-typedef StringMap<DependentsVector> DependencyMap;
+// Option for assistant mode, telling modularize to output a module map
+// based on the headers list, and where to put it.
+cl::opt<std::string> ModuleMapPath(
+    "module-map-path", cl::init(""),
+    cl::desc("Turn on module map output and specify output path or file name."
+             " If no path is specified and if prefix option is specified,"
+             " use prefix for file path."));
+
+// Option for assistant mode, telling modularize to output a module map
+// based on the headers list, and where to put it.
+cl::opt<std::string>
+RootModule("root-module", cl::init(""),
+           cl::desc("Specify the name of the root module."));
+
+// Save the program name for error messages.
+const char *Argv0;
+// Save the command line for comments.
+std::string CommandLine;
 
 // Read the header list file and collect the header file names and
 // optional dependencies.
@@ -651,6 +685,16 @@
 
 int main(int Argc, const char **Argv) {
 
+  // Save program name for error messages.
+  Argv0 = Argv[0];
+
+  // Save program arguments for use in module.map comment.
+  CommandLine = sys::path::stem(sys::path::filename(Argv0));
+  for (int ArgIndex = 1; ArgIndex < Argc; ArgIndex++) {
+    CommandLine.append(" ");
+    CommandLine.append(Argv[ArgIndex]);
+  }
+
   // This causes options to be parsed.
   cl::ParseCommandLineOptions(Argc, Argv, "modularize.\n");
 
@@ -670,6 +714,14 @@
     return 1;
   }
 
+  // If we are in assistant mode, output the module map and quit.
+  if (ModuleMapPath[0]) {
+    if (!createModuleMap(ModuleMapPath, Headers, Dependencies, HeaderPrefix,
+                         RootModule))
+      return 1; // Failed.
+    return 0;   // Success - Skip checks in assistant mode.
+  }
+
   // Create the compilation database.
   SmallString<256> PathBuf;
   sys::fs::current_path(PathBuf);