Add support for -target-api <n> to llvm-rs-cc.

Change-Id: Ieaef83fae55f84e87a9301b377633ac658a724b6
diff --git a/Android.mk b/Android.mk
index 7d1f240..ef0c476 100644
--- a/Android.mk
+++ b/Android.mk
@@ -32,7 +32,7 @@
   # See build/core/version_defaults.mk for more information about this.
   RS_VERSION := "(1 + $(PLATFORM_SDK_VERSION))"
 endif
-local_cflags_for_slang += -DRS_VERSION=\"$(RS_VERSION)\"
+local_cflags_for_slang += -DRS_VERSION=$(RS_VERSION)
 
 static_libraries_needed_by_slang := \
 	libLLVMLinker   \
diff --git a/RSCCOptions.td b/RSCCOptions.td
index af8c028..00e5700 100644
--- a/RSCCOptions.td
+++ b/RSCCOptions.td
@@ -37,6 +37,10 @@
 def triple_EQ : Joined<"-triple=">, Alias<triple>;
 def _triple : Separate<"-t">, Alias<triple>;
 
+def target_api : Separate<"-target-api">,
+  HelpText<"Specify target API level (e.g. 14)">;
+def target_api_EQ : Joined<"-target-api=">, Alias<target_api>;
+
 //===----------------------------------------------------------------------===//
 // Header Search Options
 //===----------------------------------------------------------------------===//
diff --git a/llvm-rs-cc.cpp b/llvm-rs-cc.cpp
index e22ae1e..be851d3 100644
--- a/llvm-rs-cc.cpp
+++ b/llvm-rs-cc.cpp
@@ -138,12 +138,15 @@
   unsigned mShowHelp : 1;  // Show the -help text.
   unsigned mShowVersion : 1;  // Show the -version text.
 
+  unsigned int mTargetAPI;
+
   RSCCOptions() {
     mOutputType = slang::Slang::OT_Bitcode;
     mBitcodeStorage = slang::BCST_APK_RESOURCE;
     mOutputDep = 0;
     mShowHelp = 0;
     mShowVersion = 0;
+    mTargetAPI = RS_VERSION;
   }
 };
 
@@ -261,6 +264,10 @@
 
     Opts.mShowHelp = Args->hasArg(OPT_help);
     Opts.mShowVersion = Args->hasArg(OPT_version);
+
+    Opts.mTargetAPI = Args->getLastArgIntValue(OPT_target_api,
+                                               RS_VERSION,
+                                               Diags);
   }
 
   return;
@@ -417,6 +424,7 @@
                                          Opts.mBitcodeStorage,
                                          Opts.mAllowRSPrefix,
                                          Opts.mOutputDep,
+                                         Opts.mTargetAPI,
                                          Opts.mJavaReflectionPathBase,
                                          Opts.mJavaReflectionPackageName);
   llvm::errs() << Compiler->getErrorMessage();
diff --git a/slang_rs.cpp b/slang_rs.cpp
index 708080f..983bd67 100644
--- a/slang_rs.cpp
+++ b/slang_rs.cpp
@@ -18,6 +18,7 @@
 
 #include <cstring>
 #include <list>
+#include <sstream>
 #include <string>
 #include <utility>
 #include <vector>
@@ -178,20 +179,23 @@
                            "type '%0' in different translation unit (%1 v.s. "
                            "%2) has incompatible type definition");
 
+  mDiagErrorTargetAPIRange = Diag.getCustomDiagID(clang::Diagnostic::Error,
+      "target API level '%0' is out of range ('%1' - '%2')");
+
   return;
 }
 
 void SlangRS::initPreprocessor() {
   clang::Preprocessor &PP = getPreprocessor();
 
-  std::string RSH;
-  RSH.append("#define RS_VERSION " RS_VERSION "\n");
+  std::stringstream RSH;
+  RSH << "#define RS_VERSION " << mTargetAPI << std::endl;
 #define RS_HEADER_ENTRY(name, default_included)  \
   if (default_included) \
-    RSH.append("#include \"" #name "."RS_HEADER_SUFFIX "\"\n");
+    RSH << "#include \"" #name "." RS_HEADER_SUFFIX "\"" << std::endl;
   ENUM_RS_HEADER()
 #undef RS_HEADER_ENTRY
-  PP.setPredefines(RSH);
+  PP.setPredefines(RSH.str());
 
   return;
 }
@@ -217,7 +221,8 @@
                          OS,
                          OT,
                          getSourceManager(),
-                         mAllowRSPrefix);
+                         mAllowRSPrefix,
+                         mTargetAPI);
 }
 
 bool SlangRS::IsRSHeaderFile(const char *File) {
@@ -237,7 +242,8 @@
   return IsRSHeaderFile(llvm::sys::path::filename(PLoc.getFilename()).data());
 }
 
-SlangRS::SlangRS() : Slang(), mRSContext(NULL), mAllowRSPrefix(false) {
+SlangRS::SlangRS() : Slang(), mRSContext(NULL), mAllowRSPrefix(false),
+    mTargetAPI(0) {
   return;
 }
 
@@ -248,6 +254,7 @@
     const std::vector<std::string> &AdditionalDepTargets,
     Slang::OutputType OutputType, BitCodeStorageType BitcodeStorage,
     bool AllowRSPrefix, bool OutputDep,
+    unsigned int TargetAPI,
     const std::string &JavaReflectionPathBase,
     const std::string &JavaReflectionPackageName) {
   if (IOFiles.empty())
@@ -272,6 +279,15 @@
 
   mAllowRSPrefix = AllowRSPrefix;
 
+  mTargetAPI = TargetAPI;
+  if (mTargetAPI < RS_MINIMUM_TARGET_API ||
+      mTargetAPI > RS_MAXIMUM_TARGET_API) {
+    getDiagnostics().Report(mDiagErrorTargetAPIRange) << mTargetAPI
+                                                      << RS_MINIMUM_TARGET_API
+                                                      << RS_MAXIMUM_TARGET_API;
+    return false;
+  }
+
   for (unsigned i = 0, e = IOFiles.size(); i != e; i++) {
     InputFile = IOFileIter->first;
     OutputFile = IOFileIter->second;
diff --git a/slang_rs.h b/slang_rs.h
index 6ec4d02..87957e5 100644
--- a/slang_rs.h
+++ b/slang_rs.h
@@ -28,6 +28,16 @@
 
 #include "slang_rs_reflect_utils.h"
 
+// Define minimum and maximum target API versions. These correspond to the same
+// API levels used by the standard Android SDK.
+//
+// 12 - Honeycomb MR1
+// 13 - Honeycomb MR2
+// 14 - Ice Cream Sandwich
+// ...
+#define RS_MINIMUM_TARGET_API 12
+#define RS_MAXIMUM_TARGET_API RS_VERSION
+
 namespace clang {
   class FunctionDecl;
 }
@@ -43,9 +53,12 @@
 
   bool mAllowRSPrefix;
 
+  unsigned int mTargetAPI;
+
   // Custom diagnostic identifiers
   unsigned mDiagErrorInvalidOutputDepParameter;
   unsigned mDiagErrorODR;
+  unsigned mDiagErrorTargetAPIRange;
 
   // Collect generated filenames (without the .java) for dependency generation
   std::vector<std::string> mGeneratedFileNames;
@@ -126,6 +139,7 @@
                const std::vector<std::string> &AdditionalDepTargets,
                Slang::OutputType OutputType, BitCodeStorageType BitcodeStorage,
                bool AllowRSPrefix, bool OutputDep,
+               unsigned int TargetAPI,
                const std::string &JavaReflectionPathBase,
                const std::string &JavaReflectionPackageName);
 
diff --git a/slang_rs_backend.cpp b/slang_rs_backend.cpp
index f07be08..0149195 100644
--- a/slang_rs_backend.cpp
+++ b/slang_rs_backend.cpp
@@ -49,7 +49,8 @@
                      llvm::raw_ostream *OS,
                      Slang::OutputType OT,
                      clang::SourceManager &SourceMgr,
-                     bool AllowRSPrefix)
+                     bool AllowRSPrefix,
+                     unsigned int TargetAPI)
     : Backend(Diags,
               CodeGenOpts,
               TargetOpts,
@@ -59,6 +60,7 @@
       mContext(Context),
       mSourceMgr(SourceMgr),
       mAllowRSPrefix(AllowRSPrefix),
+      mTargetAPI(TargetAPI),
       mExportVarMetadata(NULL),
       mExportFuncMetadata(NULL),
       mExportTypeMetadata(NULL),
diff --git a/slang_rs_backend.h b/slang_rs_backend.h
index 3288987..8361439 100644
--- a/slang_rs_backend.h
+++ b/slang_rs_backend.h
@@ -47,6 +47,8 @@
 
   bool mAllowRSPrefix;
 
+  unsigned int mTargetAPI;
+
   llvm::NamedMDNode *mExportVarMetadata;
   llvm::NamedMDNode *mExportFuncMetadata;
   llvm::NamedMDNode *mExportTypeMetadata;
@@ -73,7 +75,8 @@
             llvm::raw_ostream *OS,
             Slang::OutputType OT,
             clang::SourceManager &SourceMgr,
-            bool AllowRSPrefix);
+            bool AllowRSPrefix,
+            unsigned int TargetAPI);
 
   virtual ~RSBackend();
 };