Add "-M" dependency generation to Slang.

Change-Id: I26d1daf1005de7b3ad297fba5ad0d85a1aab1e45
diff --git a/Android.mk b/Android.mk
index fd7b60f..7c2b9ff 100644
--- a/Android.mk
+++ b/Android.mk
@@ -104,6 +104,7 @@
 	libclangLex	\
 	libclangCodeGen	\
 	libclangBasic	\
+	libclangFrontend	\
 	libLLVMSupport	\
 	libLLVMSystem
 
diff --git a/slang.cpp b/slang.cpp
index 725b7c1..2744b05 100644
--- a/slang.cpp
+++ b/slang.cpp
@@ -14,6 +14,10 @@
 #include "clang/Basic/TargetInfo.h"
 #include "clang/Basic/TargetOptions.h"
 
+#include "clang/Frontend/DependencyOutputOptions.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
+#include "clang/Frontend/Utils.h"
+
 #include "clang/Lex/Preprocessor.h"
 #include "clang/Lex/HeaderSearch.h"
 
@@ -277,11 +281,12 @@
 bool Slang::setOutput(const char *OutputFile) {
   std::string Error;
 
-  _mkdir_given_a_file(OutputFile);
 
   switch (mOT) {
+    case OT_Dependency:
     case OT_Assembly:
     case OT_LLVMAssembly: {
+      _mkdir_given_a_file(OutputFile);
       mOS.reset(new llvm::raw_fd_ostream(OutputFile, Error, 0));
       break;
     }
@@ -290,13 +295,16 @@
       break;
     }
     case OT_Object:
-    case OT_Bitcode:
-    default: {
+    case OT_Bitcode: {
+      _mkdir_given_a_file(OutputFile);
       mOS.reset(new llvm::raw_fd_ostream(OutputFile,
                                          Error,
                                          llvm::raw_fd_ostream::F_Binary));
       break;
     }
+    default:
+      llvm_unreachable("Unknown compiler output type");
+      break;
   }
 
   if (!Error.empty()) {
@@ -311,7 +319,48 @@
   return true;
 }
 
+bool Slang::setDepTargetBC(const char *targetBCFile) {
+  mDepTargetBCFileName = targetBCFile;
+
+  return true;
+}
+
+int Slang::generateDepFile() {
+  if((mDiagnostics->getNumErrors() > 0) || (mOS.get() == NULL))
+    return mDiagnostics->getNumErrors();
+
+  /* Initialize options for generating dependency file */
+  clang::DependencyOutputOptions DepOpts;
+  DepOpts.IncludeSystemHeaders = 1;
+  DepOpts.OutputFile = mOutputFileName;
+  DepOpts.Targets.push_back(mDepTargetBCFileName);
+
+  /* Per-compilation needed initialization */
+  createPreprocessor();
+  AttachDependencyFileGen(*mPP.get(), DepOpts);
+
+  /* Inform the diagnostic client we are processing a source file */
+  mDiagClient->BeginSourceFile(LangOpts, mPP.get());
+
+  /* Go through the source file (no operations necessary) */
+  clang::Token Tok;
+  mPP->EnterMainSourceFile();
+  do {
+    mPP->Lex(Tok);
+  } while (Tok.isNot(clang::tok::eof));
+
+  mPP->EndSourceFile();
+
+  /* Clean up after compilation */
+  mPP.reset();
+
+  return mDiagnostics->getNumErrors();
+}
+
 int Slang::compile() {
+  if (mOT == OT_Dependency)
+    return generateDepFile();
+
   if ((mDiagnostics->getNumErrors() > 0) || (mOS.get() == NULL))
     return mDiagnostics->getNumErrors();
 
diff --git a/slang.h b/slang.h
index 84b94d3..a528a6c 100644
--- a/slang.h
+++ b/slang.h
@@ -46,6 +46,7 @@
 
  public:
   typedef enum {
+    OT_Dependency,
     OT_Assembly,
     OT_LLVMAssembly,
     OT_Bitcode,
@@ -92,6 +93,7 @@
   // Input file name
   std::string mInputFileName;
   std::string mOutputFileName;
+  std::string mDepTargetBCFileName;
 
   OutputType mOT;
 
@@ -147,6 +149,9 @@
     return mOutputFileName;
   }
 
+  bool setDepTargetBC(const char *targetBCFile);
+
+  int generateDepFile();
   int compile();
 
   inline const char *getErrorMessage() { return mDiagClient->str().c_str(); }
diff --git a/slang_driver.cpp b/slang_driver.cpp
index a3cbdba..34426fa 100644
--- a/slang_driver.cpp
+++ b/slang_driver.cpp
@@ -189,6 +189,7 @@
 
 static std::string* InputFileNames;
 static std::string* OutputFileNames;
+static std::string* DepTargetBCFileNames;
 
 // Where to store the bc file.
 // possible values:
@@ -213,6 +214,7 @@
     { "emit-llvm",       no_argument, (int*) &OutputFileType, Slang::OT_LLVMAssembly },
     { "emit-bc",         no_argument, (int*) &OutputFileType, Slang::OT_Bitcode },
     { "emit-asm",        no_argument, NULL, 'S' },
+    { "emit-dep",        no_argument, (int*) &OutputFileType, Slang::OT_Dependency },
     { "emit-obj",        no_argument, NULL, 'c' },
     { "emit-nothing",    no_argument, (int*) &OutputFileType, Slang::OT_Nothing },
 
@@ -271,8 +273,11 @@
 extern int opterr;
 static int FileCount;
 
-static int AddOutputFileSuffix(std::string &pathFile) {
-  switch (OutputFileType) {
+static int AddFileSuffix(std::string &pathFile, Slang::OutputType type) {
+  switch (type) {
+    case Slang::OT_Dependency:
+      pathFile += ".d";
+      break;
     case Slang::OT_Assembly:
       pathFile += ".S";
       break;
@@ -311,6 +316,7 @@
 
   InputFileNames = NULL;
   OutputFileNames = NULL;
+  DepTargetBCFileNames = NULL;
 
   Verbose = false;
   FeatureEnabledList[0] = NULL;
@@ -328,8 +334,12 @@
   /* Turn off the error message output by getopt_long */
   opterr = 0;
 
-  while((ch = getopt_long(Argc, Argv, "Schvo:u:t:j:p:I:s:", SlangOpts, NULL)) != -1) {
+  while((ch = getopt_long(Argc, Argv, "MSchvo:u:t:j:p:I:s:", SlangOpts, NULL)) != -1) {
     switch(ch) {
+      case 'M':
+        OutputFileType = Slang::OT_Dependency;
+        break;
+
       case 'S':
         OutputFileType = Slang::OT_Assembly;
         break;
@@ -479,12 +489,14 @@
   FileCount = Argc;
   InputFileNames = new std::string[FileCount];
   OutputFileNames = new std::string[FileCount];
+  DepTargetBCFileNames = new std::string[FileCount];
   int count;
   for (count = 0; count < FileCount; count++) {
     InputFileNames[count].assign(Argv[optind + count]);
 
     if ( OutputPathName && !strcmp(OutputPathName, "-") ) {
       OutputFileNames[count].assign("stdout");
+      DepTargetBCFileNames[count].assign("stdout");
       continue;
     }
 
@@ -497,14 +509,23 @@
     }
     _outF += slang::RSSlangReflectUtils::BCFileNameFromRSFileName(
         InputFileNames[count].c_str());
+    std::string _outD(_outF);
 
-    int status = AddOutputFileSuffix(_outF);
+    int status = AddFileSuffix(_outF, OutputFileType);
+
     if (status < 0) {
       return false;
     } else if (!status) {
       OutputFileNames[count].assign("/dev/null");
+      DepTargetBCFileNames[count].assign("/dev/null");
     } else {
       OutputFileNames[count].assign(_outF);
+      if (OutputFileType == Slang::OT_Dependency) {
+        if (AddFileSuffix(_outD, Slang::OT_Bitcode) <= 0) {
+          return false;
+        }
+        DepTargetBCFileNames[count].assign(_outD);
+      }
     }
   }
 
@@ -532,6 +553,7 @@
 
     cout << "Output to: " << ((strcmp(OutputPathName, "-")) ? OutputPathName : "(standard output)") << ", type: ";
     switch(OutputFileType) {
+      case Slang::OT_Dependency: cout << "Dependencies"; break;
       case Slang::OT_Assembly: cout << "Target Assembly"; break;
       case Slang::OT_LLVMAssembly: cout << "LLVM Assembly"; break;
       case Slang::OT_Bitcode: cout << "Bitcode"; break;
@@ -710,6 +732,7 @@
       std::string beforeLink;
       if (NoLink) {
         SLANG_CALL_AND_CHECK( slang->setOutput(OutputFileNames[count].c_str()) );
+        SLANG_CALL_AND_CHECK( slang->setDepTargetBC(DepTargetBCFileNames[count].c_str()) );
       } else {
         std::string stem = slang::RSSlangReflectUtils::BCFileNameFromRSFileName(
             InputFileNames[count].c_str());
@@ -725,6 +748,7 @@
 
         beforeLink.assign(tmpFileName);
         SLANG_CALL_AND_CHECK( slang->setOutput(beforeLink.c_str()) );
+        SLANG_CALL_AND_CHECK( slang->setDepTargetBC(beforeLink.c_str()) );
       }
 
       SLANG_CALL_AND_CHECK( slang->compile() <= 0 );
@@ -733,11 +757,14 @@
       if(slang->getErrorMessage())
         cout << slang->getErrorMessage();
 
-      SLANG_CALL_AND_CHECK( slang->reflectToJavaPath(JavaReflectionPathName) );
-
       char realPackageName[0x100];
-      SLANG_CALL_AND_CHECK( slang->reflectToJava(JavaReflectionPackageName,
-                            realPackageName, sizeof(realPackageName)));
+
+      if (OutputFileType != Slang::OT_Dependency) {
+        SLANG_CALL_AND_CHECK( slang->reflectToJavaPath(JavaReflectionPathName) );
+
+        SLANG_CALL_AND_CHECK( slang->reflectToJava(JavaReflectionPackageName,
+                              realPackageName, sizeof(realPackageName)));
+      }
 
       if (NoLink) {
         goto generate_bitcode_accessor;
@@ -839,7 +866,7 @@
   OUTPUT_OPTION("-o", "--output-obj-path=<PATH>", "Write compilation output at this path ('-' means stdout)");
   OUTPUT_OPTION("-j", "--output-java-reflection-class=<PACKAGE NAME>", "Output reflection of exportables in the native domain into Java");
   OUTPUT_OPTION("-p", "--output-java-reflection-path=<PATH>", "Write reflection output at this path");
-  OUTPUT_OPTION("-I", "--include-path=<PATH>", "Add a hearder search path");
+  OUTPUT_OPTION("-I", "--include-path=<PATH>", "Add a header search path");
   OUTPUT_OPTION("-s", "--bitcode-storage=<VALUE>", "Where to store the bc file. 'ar' means apk resource, 'jc' means Java code.");
 
   cout << endl;
@@ -849,6 +876,7 @@
   OUTPUT_OPTION(NULL, "--emit-llvm", "Set output type to LLVM assembly (.ll)");
   OUTPUT_OPTION(NULL, "--emit-bc", "Set output type to Bitcode (.bc) (Default)");
   OUTPUT_OPTION("-S", "--emit-asm", "Set output type to target assmbly code (.S)");
+  OUTPUT_OPTION("-M", "--emit-dep", "Set output type to Make dependency (.d)");
   OUTPUT_OPTION("-c", "--emit-obj", "Set output type to target object file (.o)");
   OUTPUT_OPTION(NULL, "--emit-nothing", "Output nothing");