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#include "llvm/Support/CommandLine.h" 27 28#include "rs_cc_options.h" 29#include "slang.h" 30#include "slang_assert.h" 31 32#include <cstdlib> 33#include <string> 34#include <utility> 35#include <vector> 36 37enum { 38 OPT_INVALID = 0, // This is not an option ID. 39#define PREFIX(NAME, VALUE) 40#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ 41 HELPTEXT, METAVAR) \ 42 OPT_##ID, 43#include "RSCCOptions.inc" 44 LastOption 45#undef OPTION 46#undef PREFIX 47}; 48 49#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE; 50#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ 51 HELPTEXT, METAVAR) 52#include "RSCCOptions.inc" 53#undef OPTION 54#undef PREFIX 55 56static const llvm::opt::OptTable::Info RSCCInfoTable[] = { 57#define PREFIX(NAME, VALUE) 58#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ 59 HELPTEXT, METAVAR) \ 60 { \ 61 PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, llvm::opt::Option::KIND##Class, \ 62 PARAM, FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS \ 63 } \ 64 , 65#include "RSCCOptions.inc" 66#undef OPTION 67#undef PREFIX 68}; 69 70namespace { 71 72class RSCCOptTable : public llvm::opt::OptTable { 73 public: 74 RSCCOptTable() 75 : OptTable(RSCCInfoTable, 76 sizeof(RSCCInfoTable) / sizeof(RSCCInfoTable[0])) {} 77}; 78} 79 80namespace slang { 81 82llvm::opt::OptTable *createRSCCOptTable() { return new RSCCOptTable(); } 83 84// This function is similar to 85// clang/lib/Frontend/CompilerInvocation::CreateFromArgs. 86bool ParseArguments(const llvm::ArrayRef<const char *> &ArgsIn, 87 llvm::SmallVectorImpl<const char *> &Inputs, 88 RSCCOptions &Opts, clang::DiagnosticOptions &DiagOpts, 89 llvm::cl::StringSaver &StringSaver) { 90 // We use a different diagnostic engine for argument parsing from the rest of 91 // the work. This mimics what's done in clang. I believe it is so the 92 // argument parsing errors are well formatted while the full errors can be 93 // influenced by command line arguments. 94 llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> ArgumentParseDiagOpts( 95 new clang::DiagnosticOptions()); 96 llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> DiagIDs( 97 new clang::DiagnosticIDs()); 98 DiagnosticBuffer DiagsBuffer; 99 clang::DiagnosticsEngine DiagEngine(DiagIDs, &*ArgumentParseDiagOpts, 100 &DiagsBuffer, false); 101 102 // Populate a vector with the command line arguments, expanding command files 103 // that have been included via the '@' argument. 104 llvm::SmallVector<const char *, 256> ArgVector; 105 ArgVector.append(ArgsIn.begin(), ArgsIn.end()); 106 llvm::cl::ExpandResponseFiles(StringSaver, llvm::cl::TokenizeGNUCommandLine, 107 ArgVector, false); 108 109 std::unique_ptr<llvm::opt::OptTable> OptParser(createRSCCOptTable()); 110 unsigned MissingArgIndex = 0; 111 unsigned MissingArgCount = 0; 112 std::unique_ptr<llvm::opt::InputArgList> Args( 113 OptParser->ParseArgs(ArgVector.begin() + 1, ArgVector.end(), 114 MissingArgIndex, MissingArgCount)); 115 116 // Check for missing argument error. 117 if (MissingArgCount) { 118 DiagEngine.Report(clang::diag::err_drv_missing_argument) 119 << Args->getArgString(MissingArgIndex) << MissingArgCount; 120 } 121 122 // Issue errors on unknown arguments. 123 for (llvm::opt::arg_iterator it = Args->filtered_begin(OPT_UNKNOWN), 124 ie = Args->filtered_end(); 125 it != ie; ++it) { 126 DiagEngine.Report(clang::diag::err_drv_unknown_argument) 127 << (*it)->getAsString(*Args); 128 } 129 130 DiagOpts.IgnoreWarnings = Args->hasArg(OPT_w); 131 DiagOpts.Warnings = Args->getAllArgValues(OPT_W); 132 133 for (llvm::opt::ArgList::const_iterator it = Args->begin(), ie = Args->end(); 134 it != ie; ++it) { 135 const llvm::opt::Arg *A = *it; 136 if (A->getOption().getKind() == llvm::opt::Option::InputClass) 137 Inputs.push_back(A->getValue()); 138 } 139 140 Opts.mIncludePaths = Args->getAllArgValues(OPT_I); 141 142 Opts.mBitcodeOutputDir = Args->getLastArgValue(OPT_o); 143 144 if (const llvm::opt::Arg *A = Args->getLastArg(OPT_M_Group)) { 145 switch (A->getOption().getID()) { 146 case OPT_M: { 147 Opts.mEmitDependency = true; 148 Opts.mOutputType = Slang::OT_Dependency; 149 break; 150 } 151 case OPT_MD: { 152 Opts.mEmitDependency = true; 153 Opts.mOutputType = Slang::OT_Bitcode; 154 break; 155 } 156 default: { slangAssert(false && "Invalid option in M group!"); } 157 } 158 } 159 160 if (const llvm::opt::Arg *A = Args->getLastArg(OPT_Output_Type_Group)) { 161 switch (A->getOption().getID()) { 162 case OPT_emit_asm: { 163 Opts.mOutputType = Slang::OT_Assembly; 164 break; 165 } 166 case OPT_emit_llvm: { 167 Opts.mOutputType = Slang::OT_LLVMAssembly; 168 break; 169 } 170 case OPT_emit_bc: { 171 Opts.mOutputType = Slang::OT_Bitcode; 172 break; 173 } 174 case OPT_emit_nothing: { 175 Opts.mOutputType = Slang::OT_Nothing; 176 break; 177 } 178 default: { slangAssert(false && "Invalid option in output type group!"); } 179 } 180 } 181 182 if (Opts.mEmitDependency && ((Opts.mOutputType != Slang::OT_Bitcode) && 183 (Opts.mOutputType != Slang::OT_Dependency))) 184 DiagEngine.Report(clang::diag::err_drv_argument_not_allowed_with) 185 << Args->getLastArg(OPT_M_Group)->getAsString(*Args) 186 << Args->getLastArg(OPT_Output_Type_Group)->getAsString(*Args); 187 188 Opts.mAllowRSPrefix = Args->hasArg(OPT_allow_rs_prefix); 189 190 Opts.mJavaReflectionPathBase = 191 Args->getLastArgValue(OPT_java_reflection_path_base); 192 Opts.mJavaReflectionPackageName = 193 Args->getLastArgValue(OPT_java_reflection_package_name); 194 195 Opts.mRSPackageName = Args->getLastArgValue(OPT_rs_package_name); 196 197 llvm::StringRef BitcodeStorageValue = 198 Args->getLastArgValue(OPT_bitcode_storage); 199 if (BitcodeStorageValue == "ar") 200 Opts.mBitcodeStorage = BCST_APK_RESOURCE; 201 else if (BitcodeStorageValue == "jc") 202 Opts.mBitcodeStorage = BCST_JAVA_CODE; 203 else if (!BitcodeStorageValue.empty()) 204 DiagEngine.Report(clang::diag::err_drv_invalid_value) 205 << OptParser->getOptionName(OPT_bitcode_storage) << BitcodeStorageValue; 206 207 llvm::opt::Arg *lastBitwidthArg = Args->getLastArg(OPT_m32, OPT_m64); 208 if (Args->hasArg(OPT_reflect_cpp)) { 209 Opts.mBitcodeStorage = BCST_CPP_CODE; 210 // mJavaReflectionPathBase can be set for C++ reflected builds. 211 // Set it to the standard mBitcodeOutputDir (via -o) by default. 212 if (Opts.mJavaReflectionPathBase.empty()) { 213 Opts.mJavaReflectionPathBase = Opts.mBitcodeOutputDir; 214 } 215 216 // Check for bitwidth arguments. 217 if (lastBitwidthArg) { 218 if (lastBitwidthArg->getOption().matches(OPT_m32)) { 219 Opts.mBitWidth = 32; 220 } else { 221 Opts.mBitWidth = 64; 222 } 223 } 224 } else if (lastBitwidthArg) { 225 // -m32/-m64 are forbidden for non-C++ reflection paths. 226 DiagEngine.Report( 227 DiagEngine.getCustomDiagID(clang::DiagnosticsEngine::Error, 228 "cannot use -m32/-m64 without specifying " 229 "C++ reflection (-reflect-c++)")); 230 } 231 232 Opts.mDependencyOutputDir = 233 Args->getLastArgValue(OPT_output_dep_dir, Opts.mBitcodeOutputDir); 234 Opts.mAdditionalDepTargets = Args->getAllArgValues(OPT_additional_dep_target); 235 236 Opts.mShowHelp = Args->hasArg(OPT_help); 237 Opts.mShowVersion = Args->hasArg(OPT_version); 238 Opts.mDebugEmission = Args->hasArg(OPT_emit_g); 239 Opts.mVerbose = Args->hasArg(OPT_verbose); 240 241 // If we are emitting both 32-bit and 64-bit bitcode, we must embed it. 242 243 size_t OptLevel = 244 clang::getLastArgIntValue(*Args, OPT_optimization_level, 3, DiagEngine); 245 246 Opts.mOptimizationLevel = 247 OptLevel == 0 ? llvm::CodeGenOpt::None : llvm::CodeGenOpt::Aggressive; 248 249 Opts.mTargetAPI = 250 clang::getLastArgIntValue(*Args, OPT_target_api, RS_VERSION, DiagEngine); 251 252 if (Opts.mTargetAPI == 0) { 253 Opts.mTargetAPI = UINT_MAX; 254 } 255 256 Opts.mEmit3264 = 257 (Opts.mTargetAPI >= 21) && (Opts.mBitcodeStorage != BCST_CPP_CODE); 258 if (Opts.mEmit3264) { 259 Opts.mBitcodeStorage = BCST_JAVA_CODE; 260 } 261 262 if (DiagEngine.hasErrorOccurred()) { 263 llvm::errs() << DiagsBuffer.str(); 264 return false; 265 } 266 267 return true; 268} 269} 270