Home | History | Annotate | Download | only in slang
      1 /*
      2  * Copyright 2014, The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *     http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "clang/Basic/DiagnosticOptions.h"
     18 #include "clang/Driver/DriverDiagnostic.h"
     19 #include "clang/Driver/Options.h"
     20 #include "clang/Frontend/Utils.h"
     21 
     22 #include "llvm/Option/Arg.h"
     23 #include "llvm/Option/ArgList.h"
     24 #include "llvm/Option/Option.h"
     25 #include "llvm/Option/OptTable.h"
     26 
     27 #include "rs_cc_options.h"
     28 #include "slang.h"
     29 #include "slang_assert.h"
     30 
     31 #include <cstdlib>
     32 #include <string>
     33 #include <utility>
     34 #include <vector>
     35 
     36 enum {
     37   OPT_INVALID = 0,  // This is not an option ID.
     38 #define PREFIX(NAME, VALUE)
     39 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
     40                HELPTEXT, METAVAR)                                             \
     41   OPT_##ID,
     42 #include "RSCCOptions.inc"
     43   LastOption
     44 #undef OPTION
     45 #undef PREFIX
     46 };
     47 
     48 #define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
     49 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
     50                HELPTEXT, METAVAR)
     51 #include "RSCCOptions.inc"
     52 #undef OPTION
     53 #undef PREFIX
     54 
     55 static const llvm::opt::OptTable::Info RSCCInfoTable[] = {
     56 #define PREFIX(NAME, VALUE)
     57 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM,  \
     58                HELPTEXT, METAVAR)                                              \
     59   {                                                                            \
     60     PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, llvm::opt::Option::KIND##Class, \
     61         PARAM, FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS                      \
     62   }                                                                            \
     63   ,
     64 #include "RSCCOptions.inc"
     65 #undef OPTION
     66 #undef PREFIX
     67 };
     68 
     69 namespace {
     70 
     71 class RSCCOptTable : public llvm::opt::OptTable {
     72  public:
     73   RSCCOptTable()
     74       : OptTable(RSCCInfoTable,
     75                  sizeof(RSCCInfoTable) / sizeof(RSCCInfoTable[0])) {}
     76 };
     77 }
     78 
     79 llvm::opt::OptTable *slang::createRSCCOptTable() { return new RSCCOptTable(); }
     80 
     81 void slang::ParseArguments(llvm::SmallVectorImpl<const char *> &ArgVector,
     82                            llvm::SmallVectorImpl<const char *> &Inputs,
     83                            slang::RSCCOptions &Opts,
     84                            clang::DiagnosticsEngine &DiagEngine) {
     85   if (ArgVector.size() > 1) {
     86     const char **ArgBegin = ArgVector.data() + 1;
     87     const char **ArgEnd = ArgVector.data() + ArgVector.size();
     88     unsigned MissingArgIndex, MissingArgCount;
     89     std::unique_ptr<llvm::opt::OptTable> OptParser(slang::createRSCCOptTable());
     90     std::unique_ptr<llvm::opt::InputArgList> Args(OptParser->ParseArgs(
     91         ArgBegin, ArgEnd, MissingArgIndex, MissingArgCount));
     92 
     93     // Check for missing argument error.
     94     if (MissingArgCount)
     95       DiagEngine.Report(clang::diag::err_drv_missing_argument)
     96           << Args->getArgString(MissingArgIndex) << MissingArgCount;
     97 
     98     clang::DiagnosticOptions DiagOpts;
     99     DiagOpts.IgnoreWarnings = Args->hasArg(OPT_w);
    100     DiagOpts.Warnings = Args->getAllArgValues(OPT_W);
    101     clang::ProcessWarningOptions(DiagEngine, DiagOpts);
    102 
    103     // Issue errors on unknown arguments.
    104     for (llvm::opt::arg_iterator it = Args->filtered_begin(OPT_UNKNOWN),
    105                                  ie = Args->filtered_end();
    106          it != ie; ++it)
    107       DiagEngine.Report(clang::diag::err_drv_unknown_argument)
    108           << (*it)->getAsString(*Args);
    109 
    110     for (llvm::opt::ArgList::const_iterator it = Args->begin(),
    111                                             ie = Args->end();
    112          it != ie; ++it) {
    113       const llvm::opt::Arg *A = *it;
    114       if (A->getOption().getKind() == llvm::opt::Option::InputClass)
    115         Inputs.push_back(A->getValue());
    116     }
    117 
    118     Opts.mIncludePaths = Args->getAllArgValues(OPT_I);
    119 
    120     Opts.mBitcodeOutputDir = Args->getLastArgValue(OPT_o);
    121 
    122     if (const llvm::opt::Arg *A = Args->getLastArg(OPT_M_Group)) {
    123       switch (A->getOption().getID()) {
    124         case OPT_M: {
    125           Opts.mEmitDependency = true;
    126           Opts.mOutputType = slang::Slang::OT_Dependency;
    127           break;
    128         }
    129         case OPT_MD: {
    130           Opts.mEmitDependency = true;
    131           Opts.mOutputType = slang::Slang::OT_Bitcode;
    132           break;
    133         }
    134         default: { slangAssert(false && "Invalid option in M group!"); }
    135       }
    136     }
    137 
    138     if (const llvm::opt::Arg *A = Args->getLastArg(OPT_Output_Type_Group)) {
    139       switch (A->getOption().getID()) {
    140         case OPT_emit_asm: {
    141           Opts.mOutputType = slang::Slang::OT_Assembly;
    142           break;
    143         }
    144         case OPT_emit_llvm: {
    145           Opts.mOutputType = slang::Slang::OT_LLVMAssembly;
    146           break;
    147         }
    148         case OPT_emit_bc: {
    149           Opts.mOutputType = slang::Slang::OT_Bitcode;
    150           break;
    151         }
    152         case OPT_emit_nothing: {
    153           Opts.mOutputType = slang::Slang::OT_Nothing;
    154           break;
    155         }
    156         default: {
    157           slangAssert(false && "Invalid option in output type group!");
    158         }
    159       }
    160     }
    161 
    162     if (Opts.mEmitDependency &&
    163         ((Opts.mOutputType != slang::Slang::OT_Bitcode) &&
    164          (Opts.mOutputType != slang::Slang::OT_Dependency)))
    165       DiagEngine.Report(clang::diag::err_drv_argument_not_allowed_with)
    166           << Args->getLastArg(OPT_M_Group)->getAsString(*Args)
    167           << Args->getLastArg(OPT_Output_Type_Group)->getAsString(*Args);
    168 
    169     Opts.mAllowRSPrefix = Args->hasArg(OPT_allow_rs_prefix);
    170 
    171     Opts.mJavaReflectionPathBase =
    172         Args->getLastArgValue(OPT_java_reflection_path_base);
    173     Opts.mJavaReflectionPackageName =
    174         Args->getLastArgValue(OPT_java_reflection_package_name);
    175 
    176     Opts.mRSPackageName = Args->getLastArgValue(OPT_rs_package_name);
    177 
    178     llvm::StringRef BitcodeStorageValue =
    179         Args->getLastArgValue(OPT_bitcode_storage);
    180     if (BitcodeStorageValue == "ar")
    181       Opts.mBitcodeStorage = slang::BCST_APK_RESOURCE;
    182     else if (BitcodeStorageValue == "jc")
    183       Opts.mBitcodeStorage = slang::BCST_JAVA_CODE;
    184     else if (!BitcodeStorageValue.empty())
    185       DiagEngine.Report(clang::diag::err_drv_invalid_value)
    186           << OptParser->getOptionName(OPT_bitcode_storage)
    187           << BitcodeStorageValue;
    188 
    189     llvm::opt::Arg *lastBitwidthArg = Args->getLastArg(OPT_m32, OPT_m64);
    190     if (Args->hasArg(OPT_reflect_cpp)) {
    191       Opts.mBitcodeStorage = slang::BCST_CPP_CODE;
    192       // mJavaReflectionPathBase can be set for C++ reflected builds.
    193       // Set it to the standard mBitcodeOutputDir (via -o) by default.
    194       if (Opts.mJavaReflectionPathBase.empty()) {
    195         Opts.mJavaReflectionPathBase = Opts.mBitcodeOutputDir;
    196       }
    197 
    198       // Check for bitwidth arguments.
    199       if (lastBitwidthArg) {
    200         if (lastBitwidthArg->getOption().matches(OPT_m32)) {
    201           Opts.mBitWidth = 32;
    202         } else {
    203           Opts.mBitWidth = 64;
    204         }
    205       }
    206     } else if (lastBitwidthArg) {
    207       // -m32/-m64 are forbidden for non-C++ reflection paths.
    208       DiagEngine.Report(DiagEngine.getCustomDiagID(
    209           clang::DiagnosticsEngine::Error,
    210           "cannot use -m32/-m64 without specifying C++ reflection (-reflect-c++)"));
    211     }
    212 
    213     Opts.mDependencyOutputDir =
    214         Args->getLastArgValue(OPT_output_dep_dir, Opts.mBitcodeOutputDir);
    215     Opts.mAdditionalDepTargets =
    216         Args->getAllArgValues(OPT_additional_dep_target);
    217 
    218     Opts.mShowHelp = Args->hasArg(OPT_help);
    219     Opts.mShowVersion = Args->hasArg(OPT_version);
    220     Opts.mDebugEmission = Args->hasArg(OPT_emit_g);
    221     Opts.mVerbose = Args->hasArg(OPT_verbose);
    222 
    223     // If we are emitting both 32-bit and 64-bit bitcode, we must embed it.
    224 
    225     size_t OptLevel =
    226         clang::getLastArgIntValue(*Args, OPT_optimization_level, 3, DiagEngine);
    227 
    228     Opts.mOptimizationLevel =
    229         OptLevel == 0 ? llvm::CodeGenOpt::None : llvm::CodeGenOpt::Aggressive;
    230 
    231     Opts.mTargetAPI = clang::getLastArgIntValue(*Args, OPT_target_api,
    232                                                 RS_VERSION, DiagEngine);
    233 
    234     if (Opts.mTargetAPI == 0) {
    235       Opts.mTargetAPI = UINT_MAX;
    236     }
    237 
    238     Opts.mEmit3264 = (Opts.mTargetAPI >= 21) && (Opts.mBitcodeStorage != slang::BCST_CPP_CODE);
    239     if (Opts.mEmit3264) {
    240         Opts.mBitcodeStorage = slang::BCST_JAVA_CODE;
    241     }
    242   }
    243 }
    244