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 37 enum { 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 56 static 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 70 namespace { 71 72 class RSCCOptTable : public llvm::opt::OptTable { 73 public: 74 RSCCOptTable() 75 : OptTable(llvm::makeArrayRef(RSCCInfoTable)) {} 76 }; 77 } 78 79 namespace slang { 80 81 llvm::opt::OptTable *createRSCCOptTable() { return new RSCCOptTable(); } 82 83 // This function is similar to 84 // clang/lib/Frontend/CompilerInvocation::CreateFromArgs. 85 bool ParseArguments(const llvm::ArrayRef<const char *> &ArgsIn, 86 llvm::SmallVectorImpl<const char *> &Inputs, 87 RSCCOptions &Opts, clang::DiagnosticOptions &DiagOpts, 88 llvm::StringSaver &StringSaver) { 89 // We use a different diagnostic engine for argument parsing from the rest of 90 // the work. This mimics what's done in clang. I believe it is so the 91 // argument parsing errors are well formatted while the full errors can be 92 // influenced by command line arguments. 93 llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> ArgumentParseDiagOpts( 94 new clang::DiagnosticOptions()); 95 llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> DiagIDs( 96 new clang::DiagnosticIDs()); 97 DiagnosticBuffer DiagsBuffer; 98 clang::DiagnosticsEngine DiagEngine(DiagIDs, &*ArgumentParseDiagOpts, 99 &DiagsBuffer, false); 100 101 // Populate a vector with the command line arguments, expanding command files 102 // that have been included via the '@' argument. 103 llvm::SmallVector<const char *, 256> ArgVector; 104 // Skip over the command name, or we will mistakenly process it as a source file. 105 ArgVector.append(ArgsIn.slice(1).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 llvm::opt::InputArgList Args = 113 OptParser->ParseArgs(ArgVector, MissingArgIndex, MissingArgCount); 114 115 // Check for missing argument error. 116 if (MissingArgCount) { 117 DiagEngine.Report(clang::diag::err_drv_missing_argument) 118 << Args.getArgString(MissingArgIndex) << MissingArgCount; 119 } 120 121 // Issue errors on unknown arguments. 122 for (llvm::opt::arg_iterator it = Args.filtered_begin(OPT_UNKNOWN), 123 ie = Args.filtered_end(); 124 it != ie; ++it) { 125 DiagEngine.Report(clang::diag::err_drv_unknown_argument) 126 << (*it)->getAsString(Args); 127 } 128 129 DiagOpts.IgnoreWarnings = Args.hasArg(OPT_w); 130 DiagOpts.Warnings = Args.getAllArgValues(OPT_W); 131 132 // Always turn off warnings for empty initializers, since we really want to 133 // employ/encourage this extension for zero-initialization of structures. 134 DiagOpts.Warnings.push_back("no-gnu-empty-initializer"); 135 136 for (llvm::opt::ArgList::const_iterator it = Args.begin(), ie = Args.end(); 137 it != ie; ++it) { 138 const llvm::opt::Arg *A = *it; 139 if (A->getOption().getKind() == llvm::opt::Option::InputClass) 140 Inputs.push_back(A->getValue()); 141 } 142 143 Opts.mIncludePaths = Args.getAllArgValues(OPT_I); 144 145 Opts.mBitcodeOutputDir = Args.getLastArgValue(OPT_o); 146 147 if (const llvm::opt::Arg *A = Args.getLastArg(OPT_M_Group)) { 148 switch (A->getOption().getID()) { 149 case OPT_M: { 150 Opts.mEmitDependency = true; 151 Opts.mOutputType = Slang::OT_Dependency; 152 break; 153 } 154 case OPT_MD: { 155 Opts.mEmitDependency = true; 156 Opts.mOutputType = Slang::OT_Bitcode; 157 break; 158 } 159 case OPT_MP: { 160 Opts.mEmitDependency = true; 161 Opts.mOutputType = Slang::OT_Bitcode; 162 Opts.mEmitPhonyDependency = true; 163 break; 164 } 165 default: { slangAssert(false && "Invalid option in M group!"); } 166 } 167 } 168 169 if (const llvm::opt::Arg *A = Args.getLastArg(OPT_Output_Type_Group)) { 170 switch (A->getOption().getID()) { 171 case OPT_emit_asm: { 172 Opts.mOutputType = Slang::OT_Assembly; 173 break; 174 } 175 case OPT_emit_llvm: { 176 Opts.mOutputType = Slang::OT_LLVMAssembly; 177 break; 178 } 179 case OPT_emit_bc: { 180 Opts.mOutputType = Slang::OT_Bitcode; 181 break; 182 } 183 case OPT_emit_nothing: { 184 Opts.mOutputType = Slang::OT_Nothing; 185 break; 186 } 187 default: { slangAssert(false && "Invalid option in output type group!"); } 188 } 189 } 190 191 if (Opts.mEmitDependency && ((Opts.mOutputType != Slang::OT_Bitcode) && 192 (Opts.mOutputType != Slang::OT_Dependency))) 193 DiagEngine.Report(clang::diag::err_drv_argument_not_allowed_with) 194 << Args.getLastArg(OPT_M_Group)->getAsString(Args) 195 << Args.getLastArg(OPT_Output_Type_Group)->getAsString(Args); 196 197 Opts.mAllowRSPrefix = Args.hasArg(OPT_allow_rs_prefix); 198 199 Opts.mJavaReflectionPathBase = 200 Args.getLastArgValue(OPT_java_reflection_path_base); 201 Opts.mJavaReflectionPackageName = 202 Args.getLastArgValue(OPT_java_reflection_package_name); 203 204 Opts.mRSPackageName = Args.getLastArgValue(OPT_rs_package_name); 205 206 llvm::StringRef BitcodeStorageValue = 207 Args.getLastArgValue(OPT_bitcode_storage); 208 if (BitcodeStorageValue == "ar") 209 Opts.mBitcodeStorage = BCST_APK_RESOURCE; 210 else if (BitcodeStorageValue == "jc") 211 Opts.mBitcodeStorage = BCST_JAVA_CODE; 212 else if (!BitcodeStorageValue.empty()) 213 DiagEngine.Report(clang::diag::err_drv_invalid_value) 214 << OptParser->getOptionName(OPT_bitcode_storage) << BitcodeStorageValue; 215 216 llvm::opt::Arg *lastBitwidthArg = Args.getLastArg(OPT_m32, OPT_m64); 217 if (Args.hasArg(OPT_reflect_cpp)) { 218 Opts.mBitcodeStorage = BCST_CPP_CODE; 219 // mJavaReflectionPathBase can be set for C++ reflected builds. 220 // Set it to the standard mBitcodeOutputDir (via -o) by default. 221 if (Opts.mJavaReflectionPathBase.empty()) { 222 Opts.mJavaReflectionPathBase = Opts.mBitcodeOutputDir; 223 } 224 225 // Check for bitwidth arguments. 226 if (lastBitwidthArg) { 227 if (lastBitwidthArg->getOption().matches(OPT_m32)) { 228 Opts.mBitWidth = 32; 229 } else { 230 Opts.mBitWidth = 64; 231 } 232 } 233 } else if (lastBitwidthArg) { 234 // -m32/-m64 are forbidden for non-C++ reflection paths for non-eng builds 235 // (they would make it too easy for a developer to accidentally create and 236 // release an APK that has 32-bit or 64-bit bitcode but not both). 237 #ifdef __ENABLE_INTERNAL_OPTIONS 238 if (lastBitwidthArg->getOption().matches(OPT_m32)) { 239 Opts.mBitWidth = 32; 240 } else { 241 Opts.mBitWidth = 64; 242 } 243 Opts.mEmit3264 = false; 244 #else 245 DiagEngine.Report( 246 DiagEngine.getCustomDiagID(clang::DiagnosticsEngine::Error, 247 "cannot use -m32/-m64 without specifying " 248 "C++ reflection (-reflect-c++)")); 249 #endif 250 } 251 252 Opts.mDependencyOutputDir = 253 Args.getLastArgValue(OPT_output_dep_dir, Opts.mBitcodeOutputDir); 254 Opts.mAdditionalDepTargets = Args.getAllArgValues(OPT_additional_dep_target); 255 256 Opts.mShowHelp = Args.hasArg(OPT_help); 257 Opts.mShowVersion = Args.hasArg(OPT_version); 258 Opts.mDebugEmission = Args.hasArg(OPT_emit_g); 259 Opts.mVerbose = Args.hasArg(OPT_verbose); 260 Opts.mASTPrint = Args.hasArg(OPT_ast_print); 261 262 // Delegate options 263 264 std::vector<std::string> DelegatedStrings; 265 for (int Opt : std::vector<unsigned>{OPT_debug, OPT_print_after_all, OPT_print_before_all}) { 266 if (Args.hasArg(Opt)) { 267 // TODO: Don't assume that the option begins with "-"; determine this programmatically instead. 268 DelegatedStrings.push_back(std::string("-") + std::string(OptParser->getOptionName(Opt))); 269 slangAssert(OptParser->getOptionKind(Opt) == llvm::opt::Option::FlagClass); 270 } 271 } 272 if (DelegatedStrings.size()) { 273 std::vector<const char *> DelegatedCStrs; 274 DelegatedCStrs.push_back(*ArgVector.data()); // program name 275 std::for_each(DelegatedStrings.cbegin(), DelegatedStrings.cend(), 276 [&DelegatedCStrs](const std::string &String) { DelegatedCStrs.push_back(String.c_str()); }); 277 llvm::cl::ParseCommandLineOptions(DelegatedCStrs.size(), DelegatedCStrs.data()); 278 } 279 280 // If we are emitting both 32-bit and 64-bit bitcode, we must embed it. 281 282 size_t OptLevel = 283 clang::getLastArgIntValue(Args, OPT_optimization_level, 3, DiagEngine); 284 285 Opts.mOptimizationLevel = 286 OptLevel == 0 ? llvm::CodeGenOpt::None : llvm::CodeGenOpt::Aggressive; 287 288 Opts.mTargetAPI = 289 clang::getLastArgIntValue(Args, OPT_target_api, RS_VERSION, DiagEngine); 290 291 if (Opts.mTargetAPI == 0) { 292 Opts.mTargetAPI = UINT_MAX; 293 } else if (Opts.mTargetAPI == SLANG_N_MR1_TARGET_API || 294 Opts.mTargetAPI == SLANG_O_TARGET_API || 295 Opts.mTargetAPI == SLANG_O_MR1_TARGET_API || 296 Opts.mTargetAPI == SLANG_P_TARGET_API) { 297 // Bug: http://b/35767071 298 // No new APIs for N_MR1, O, O_MR1 and P, convert to N. 299 Opts.mTargetAPI = SLANG_N_TARGET_API; 300 } 301 302 if ((Opts.mTargetAPI < 21) || (Opts.mBitcodeStorage == BCST_CPP_CODE)) 303 Opts.mEmit3264 = false; 304 if (Opts.mEmit3264) 305 Opts.mBitcodeStorage = BCST_JAVA_CODE; 306 307 if (DiagEngine.hasErrorOccurred()) { 308 llvm::errs() << DiagsBuffer.str(); 309 return false; 310 } 311 312 return true; 313 } 314 } 315