1 /* 2 * Copyright 2010-2012, 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 <cstdlib> 18 #include <list> 19 #include <set> 20 #include <string> 21 #include <utility> 22 #include <vector> 23 24 #include "clang/Driver/Arg.h" 25 #include "clang/Driver/ArgList.h" 26 #include "clang/Driver/DriverDiagnostic.h" 27 #include "clang/Driver/Option.h" 28 #include "clang/Driver/OptTable.h" 29 30 #include "clang/Frontend/DiagnosticOptions.h" 31 #include "clang/Frontend/TextDiagnosticPrinter.h" 32 #include "clang/Frontend/Utils.h" 33 34 #include "llvm/ADT/SmallVector.h" 35 #include "llvm/ADT/IntrusiveRefCntPtr.h" 36 #include "llvm/ADT/OwningPtr.h" 37 38 #include "llvm/Support/CommandLine.h" 39 #include "llvm/Support/ManagedStatic.h" 40 #include "llvm/Support/MemoryBuffer.h" 41 #include "llvm/Support/Path.h" 42 #include "llvm/Support/raw_ostream.h" 43 #include "llvm/Support/system_error.h" 44 #include "llvm/Target/TargetMachine.h" 45 46 #include "slang.h" 47 #include "slang_assert.h" 48 #include "slang_diagnostic_buffer.h" 49 #include "slang_rs.h" 50 #include "slang_rs_reflect_utils.h" 51 52 // Class under clang::driver used are enumerated here. 53 using clang::driver::arg_iterator; 54 using clang::driver::options::DriverOption; 55 using clang::driver::Arg; 56 using clang::driver::ArgList; 57 using clang::driver::InputArgList; 58 using clang::driver::Option; 59 using clang::driver::OptTable; 60 using namespace clang::driver::options; 61 62 // SaveStringInSet, ExpandArgsFromBuf and ExpandArgv are all copied from 63 // $(CLANG_ROOT)/tools/driver/driver.cpp for processing argc/argv passed in 64 // main(). 65 static inline const char *SaveStringInSet(std::set<std::string> &SavedStrings, 66 llvm::StringRef S) { 67 return SavedStrings.insert(S).first->c_str(); 68 } 69 static void ExpandArgsFromBuf(const char *Arg, 70 llvm::SmallVectorImpl<const char*> &ArgVector, 71 std::set<std::string> &SavedStrings); 72 static void ExpandArgv(int argc, const char **argv, 73 llvm::SmallVectorImpl<const char*> &ArgVector, 74 std::set<std::string> &SavedStrings); 75 76 enum { 77 OPT_INVALID = 0, // This is not an option ID. 78 #define OPTION(NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \ 79 HELPTEXT, METAVAR) OPT_##ID, 80 #include "RSCCOptions.inc" 81 LastOption 82 #undef OPTION 83 }; 84 85 static const OptTable::Info RSCCInfoTable[] = { 86 #define OPTION(NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \ 87 HELPTEXT, METAVAR) \ 88 { NAME, HELPTEXT, METAVAR, Option::KIND##Class, PARAM, FLAGS, \ 89 OPT_##GROUP, OPT_##ALIAS }, 90 #include "RSCCOptions.inc" 91 }; 92 93 class RSCCOptTable : public OptTable { 94 public: 95 RSCCOptTable() 96 : OptTable(RSCCInfoTable, 97 sizeof(RSCCInfoTable) / sizeof(RSCCInfoTable[0])) { 98 } 99 }; 100 101 OptTable *createRSCCOptTable() { 102 return new RSCCOptTable(); 103 } 104 105 /////////////////////////////////////////////////////////////////////////////// 106 107 class RSCCOptions { 108 public: 109 // The include search paths 110 std::vector<std::string> mIncludePaths; 111 112 // The output directory, if any. 113 std::string mOutputDir; 114 115 // The output type 116 slang::Slang::OutputType mOutputType; 117 118 unsigned mAllowRSPrefix : 1; 119 120 // The name of the target triple to compile for. 121 std::string mTriple; 122 123 // The name of the target CPU to generate code for. 124 std::string mCPU; 125 126 // The list of target specific features to enable or disable -- this should 127 // be a list of strings starting with by '+' or '-'. 128 std::vector<std::string> mFeatures; 129 130 std::string mJavaReflectionPathBase; 131 132 std::string mJavaReflectionPackageName; 133 134 std::string mRSPackageName; 135 136 slang::BitCodeStorageType mBitcodeStorage; 137 138 unsigned mOutputDep : 1; 139 140 std::string mOutputDepDir; 141 142 std::vector<std::string> mAdditionalDepTargets; 143 144 unsigned mShowHelp : 1; // Show the -help text. 145 unsigned mShowVersion : 1; // Show the -version text. 146 147 unsigned int mTargetAPI; 148 149 // Enable emission of debugging symbols 150 unsigned mDebugEmission : 1; 151 152 // The optimization level used in CodeGen, and encoded in emitted bitcode 153 llvm::CodeGenOpt::Level mOptimizationLevel; 154 155 RSCCOptions() { 156 mOutputType = slang::Slang::OT_Bitcode; 157 // Triple/CPU/Features must be hard-coded to our chosen portable ABI. 158 mTriple = "armv7-none-linux-gnueabi"; 159 mCPU = ""; 160 slangAssert(mFeatures.empty()); 161 mFeatures.push_back("+long64"); 162 mBitcodeStorage = slang::BCST_APK_RESOURCE; 163 mOutputDep = 0; 164 mShowHelp = 0; 165 mShowVersion = 0; 166 mTargetAPI = RS_VERSION; 167 mDebugEmission = 0; 168 mOptimizationLevel = llvm::CodeGenOpt::Aggressive; 169 } 170 }; 171 172 // ParseArguments - 173 static void ParseArguments(llvm::SmallVectorImpl<const char*> &ArgVector, 174 llvm::SmallVectorImpl<const char*> &Inputs, 175 RSCCOptions &Opts, 176 clang::DiagnosticsEngine &DiagEngine) { 177 if (ArgVector.size() > 1) { 178 const char **ArgBegin = ArgVector.data() + 1; 179 const char **ArgEnd = ArgVector.data() + ArgVector.size(); 180 unsigned MissingArgIndex, MissingArgCount; 181 llvm::OwningPtr<OptTable> OptParser(createRSCCOptTable()); 182 llvm::OwningPtr<InputArgList> Args( 183 OptParser->ParseArgs(ArgBegin, ArgEnd, MissingArgIndex, MissingArgCount)); 184 185 // Check for missing argument error. 186 if (MissingArgCount) 187 DiagEngine.Report(clang::diag::err_drv_missing_argument) 188 << Args->getArgString(MissingArgIndex) << MissingArgCount; 189 190 clang::DiagnosticOptions DiagOpts; 191 DiagOpts.IgnoreWarnings = Args->hasArg(OPT_w); 192 DiagOpts.Warnings = Args->getAllArgValues(OPT_W); 193 clang::ProcessWarningOptions(DiagEngine, DiagOpts); 194 195 // Issue errors on unknown arguments. 196 for (arg_iterator it = Args->filtered_begin(OPT_UNKNOWN), 197 ie = Args->filtered_end(); it != ie; ++it) 198 DiagEngine.Report(clang::diag::err_drv_unknown_argument) 199 << (*it)->getAsString(*Args); 200 201 for (ArgList::const_iterator it = Args->begin(), ie = Args->end(); 202 it != ie; ++it) { 203 const Arg *A = *it; 204 if (A->getOption().getKind() == Option::InputClass) 205 Inputs.push_back(A->getValue(*Args)); 206 } 207 208 Opts.mIncludePaths = Args->getAllArgValues(OPT_I); 209 210 Opts.mOutputDir = Args->getLastArgValue(OPT_o); 211 212 if (const Arg *A = Args->getLastArg(OPT_M_Group)) { 213 switch (A->getOption().getID()) { 214 case OPT_M: { 215 Opts.mOutputDep = 1; 216 Opts.mOutputType = slang::Slang::OT_Dependency; 217 break; 218 } 219 case OPT_MD: { 220 Opts.mOutputDep = 1; 221 Opts.mOutputType = slang::Slang::OT_Bitcode; 222 break; 223 } 224 default: { 225 slangAssert(false && "Invalid option in M group!"); 226 } 227 } 228 } 229 230 if (const Arg *A = Args->getLastArg(OPT_Output_Type_Group)) { 231 switch (A->getOption().getID()) { 232 case OPT_emit_asm: { 233 Opts.mOutputType = slang::Slang::OT_Assembly; 234 break; 235 } 236 case OPT_emit_llvm: { 237 Opts.mOutputType = slang::Slang::OT_LLVMAssembly; 238 break; 239 } 240 case OPT_emit_bc: { 241 Opts.mOutputType = slang::Slang::OT_Bitcode; 242 break; 243 } 244 case OPT_emit_nothing: { 245 Opts.mOutputType = slang::Slang::OT_Nothing; 246 break; 247 } 248 default: { 249 slangAssert(false && "Invalid option in output type group!"); 250 } 251 } 252 } 253 254 if (Opts.mOutputDep && 255 ((Opts.mOutputType != slang::Slang::OT_Bitcode) && 256 (Opts.mOutputType != slang::Slang::OT_Dependency))) 257 DiagEngine.Report(clang::diag::err_drv_argument_not_allowed_with) 258 << Args->getLastArg(OPT_M_Group)->getAsString(*Args) 259 << Args->getLastArg(OPT_Output_Type_Group)->getAsString(*Args); 260 261 Opts.mAllowRSPrefix = Args->hasArg(OPT_allow_rs_prefix); 262 263 Opts.mJavaReflectionPathBase = 264 Args->getLastArgValue(OPT_java_reflection_path_base); 265 Opts.mJavaReflectionPackageName = 266 Args->getLastArgValue(OPT_java_reflection_package_name); 267 268 Opts.mRSPackageName = Args->getLastArgValue(OPT_rs_package_name); 269 270 llvm::StringRef BitcodeStorageValue = 271 Args->getLastArgValue(OPT_bitcode_storage); 272 if (BitcodeStorageValue == "ar") 273 Opts.mBitcodeStorage = slang::BCST_APK_RESOURCE; 274 else if (BitcodeStorageValue == "jc") 275 Opts.mBitcodeStorage = slang::BCST_JAVA_CODE; 276 else if (!BitcodeStorageValue.empty()) 277 DiagEngine.Report(clang::diag::err_drv_invalid_value) 278 << OptParser->getOptionName(OPT_bitcode_storage) 279 << BitcodeStorageValue; 280 281 if (Args->hasArg(OPT_reflect_cpp)) { 282 Opts.mBitcodeStorage = slang::BCST_CPP_CODE; 283 } 284 285 Opts.mOutputDepDir = 286 Args->getLastArgValue(OPT_output_dep_dir, Opts.mOutputDir); 287 Opts.mAdditionalDepTargets = 288 Args->getAllArgValues(OPT_additional_dep_target); 289 290 Opts.mShowHelp = Args->hasArg(OPT_help); 291 Opts.mShowVersion = Args->hasArg(OPT_version); 292 Opts.mDebugEmission = Args->hasArg(OPT_emit_g); 293 294 size_t OptLevel = Args->getLastArgIntValue(OPT_optimization_level, 295 3, 296 DiagEngine); 297 298 Opts.mOptimizationLevel = OptLevel == 0 ? llvm::CodeGenOpt::None 299 : llvm::CodeGenOpt::Aggressive; 300 301 Opts.mTargetAPI = Args->getLastArgIntValue(OPT_target_api, 302 RS_VERSION, 303 DiagEngine); 304 } 305 306 return; 307 } 308 309 static const char *DetermineOutputFile(const std::string &OutputDir, 310 const char *InputFile, 311 slang::Slang::OutputType OutputType, 312 std::set<std::string> &SavedStrings) { 313 if (OutputType == slang::Slang::OT_Nothing) 314 return "/dev/null"; 315 316 std::string OutputFile(OutputDir); 317 318 // Append '/' to Opts.mOutputDir if not presents 319 if (!OutputFile.empty() && 320 (OutputFile[OutputFile.size() - 1]) != OS_PATH_SEPARATOR) 321 OutputFile.append(1, OS_PATH_SEPARATOR); 322 323 if (OutputType == slang::Slang::OT_Dependency) { 324 // The build system wants the .d file name stem to be exactly the same as 325 // the source .rs file, instead of the .bc file. 326 OutputFile.append(slang::RSSlangReflectUtils::GetFileNameStem(InputFile)); 327 } else { 328 OutputFile.append( 329 slang::RSSlangReflectUtils::BCFileNameFromRSFileName(InputFile)); 330 } 331 332 switch (OutputType) { 333 case slang::Slang::OT_Dependency: { 334 OutputFile.append(".d"); 335 break; 336 } 337 case slang::Slang::OT_Assembly: { 338 OutputFile.append(".S"); 339 break; 340 } 341 case slang::Slang::OT_LLVMAssembly: { 342 OutputFile.append(".ll"); 343 break; 344 } 345 case slang::Slang::OT_Object: { 346 OutputFile.append(".o"); 347 break; 348 } 349 case slang::Slang::OT_Bitcode: { 350 OutputFile.append(".bc"); 351 break; 352 } 353 case slang::Slang::OT_Nothing: 354 default: { 355 slangAssert(false && "Invalid output type!"); 356 } 357 } 358 359 return SaveStringInSet(SavedStrings, OutputFile); 360 } 361 362 #define str(s) #s 363 #define wrap_str(s) str(s) 364 static void llvm_rs_cc_VersionPrinter() { 365 llvm::raw_ostream &OS = llvm::outs(); 366 OS << "llvm-rs-cc: Renderscript compiler\n" 367 << " (http://developer.android.com/guide/topics/renderscript)\n" 368 << " based on LLVM (http://llvm.org):\n"; 369 OS << " Built " << __DATE__ << " (" << __TIME__ ").\n"; 370 OS << " Target APIs: " << SLANG_MINIMUM_TARGET_API << " - " 371 << SLANG_MAXIMUM_TARGET_API; 372 OS << "\n Build type: " << wrap_str(TARGET_BUILD_VARIANT); 373 #ifndef __DISABLE_ASSERTS 374 OS << " with assertions"; 375 #endif 376 OS << ".\n"; 377 return; 378 } 379 #undef wrap_str 380 #undef str 381 382 int main(int argc, const char **argv) { 383 std::set<std::string> SavedStrings; 384 llvm::SmallVector<const char*, 256> ArgVector; 385 RSCCOptions Opts; 386 llvm::SmallVector<const char*, 16> Inputs; 387 std::string Argv0; 388 389 atexit(llvm::llvm_shutdown); 390 391 ExpandArgv(argc, argv, ArgVector, SavedStrings); 392 393 // Argv0 394 Argv0 = llvm::sys::path::stem(ArgVector[0]); 395 396 // Setup diagnostic engine 397 slang::DiagnosticBuffer *DiagClient = new slang::DiagnosticBuffer(); 398 399 llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> DiagIDs( 400 new clang::DiagnosticIDs()); 401 402 clang::DiagnosticsEngine DiagEngine(DiagIDs, DiagClient, true); 403 404 slang::Slang::GlobalInitialization(); 405 406 ParseArguments(ArgVector, Inputs, Opts, DiagEngine); 407 408 // Exits when there's any error occurred during parsing the arguments 409 if (DiagEngine.hasErrorOccurred()) { 410 llvm::errs() << DiagClient->str(); 411 return 1; 412 } 413 414 if (Opts.mShowHelp) { 415 llvm::OwningPtr<OptTable> OptTbl(createRSCCOptTable()); 416 OptTbl->PrintHelp(llvm::outs(), Argv0.c_str(), 417 "Renderscript source compiler"); 418 return 0; 419 } 420 421 if (Opts.mShowVersion) { 422 llvm_rs_cc_VersionPrinter(); 423 return 0; 424 } 425 426 // No input file 427 if (Inputs.empty()) { 428 DiagEngine.Report(clang::diag::err_drv_no_input_files); 429 llvm::errs() << DiagClient->str(); 430 return 1; 431 } 432 433 // Prepare input data for RS compiler. 434 std::list<std::pair<const char*, const char*> > IOFiles; 435 std::list<std::pair<const char*, const char*> > DepFiles; 436 437 llvm::OwningPtr<slang::SlangRS> Compiler(new slang::SlangRS()); 438 439 Compiler->init(Opts.mTriple, Opts.mCPU, Opts.mFeatures, &DiagEngine, 440 DiagClient); 441 442 for (int i = 0, e = Inputs.size(); i != e; i++) { 443 const char *InputFile = Inputs[i]; 444 const char *OutputFile = 445 DetermineOutputFile(Opts.mOutputDir, InputFile, 446 Opts.mOutputType, SavedStrings); 447 448 if (Opts.mOutputDep) { 449 const char *BCOutputFile, *DepOutputFile; 450 451 if (Opts.mOutputType == slang::Slang::OT_Bitcode) 452 BCOutputFile = OutputFile; 453 else 454 BCOutputFile = DetermineOutputFile(Opts.mOutputDepDir, 455 InputFile, 456 slang::Slang::OT_Bitcode, 457 SavedStrings); 458 459 if (Opts.mOutputType == slang::Slang::OT_Dependency) 460 DepOutputFile = OutputFile; 461 else 462 DepOutputFile = DetermineOutputFile(Opts.mOutputDepDir, 463 InputFile, 464 slang::Slang::OT_Dependency, 465 SavedStrings); 466 467 DepFiles.push_back(std::make_pair(BCOutputFile, DepOutputFile)); 468 } 469 470 IOFiles.push_back(std::make_pair(InputFile, OutputFile)); 471 } 472 473 // Let's rock! 474 int CompileFailed = !Compiler->compile(IOFiles, 475 DepFiles, 476 Opts.mIncludePaths, 477 Opts.mAdditionalDepTargets, 478 Opts.mOutputType, 479 Opts.mBitcodeStorage, 480 Opts.mAllowRSPrefix, 481 Opts.mOutputDep, 482 Opts.mTargetAPI, 483 Opts.mDebugEmission, 484 Opts.mOptimizationLevel, 485 Opts.mJavaReflectionPathBase, 486 Opts.mJavaReflectionPackageName, 487 Opts.mRSPackageName); 488 489 Compiler->reset(); 490 491 return CompileFailed; 492 } 493 494 /////////////////////////////////////////////////////////////////////////////// 495 496 // ExpandArgsFromBuf - 497 static void ExpandArgsFromBuf(const char *Arg, 498 llvm::SmallVectorImpl<const char*> &ArgVector, 499 std::set<std::string> &SavedStrings) { 500 const char *FName = Arg + 1; 501 llvm::OwningPtr<llvm::MemoryBuffer> MemBuf; 502 if (llvm::MemoryBuffer::getFile(FName, MemBuf)) { 503 // Unable to open the file 504 ArgVector.push_back(SaveStringInSet(SavedStrings, Arg)); 505 return; 506 } 507 508 const char *Buf = MemBuf->getBufferStart(); 509 char InQuote = ' '; 510 std::string CurArg; 511 512 for (const char *P = Buf; ; ++P) { 513 if (*P == '\0' || (isspace(*P) && InQuote == ' ')) { 514 if (!CurArg.empty()) { 515 if (CurArg[0] != '@') { 516 ArgVector.push_back(SaveStringInSet(SavedStrings, CurArg)); 517 } else { 518 ExpandArgsFromBuf(CurArg.c_str(), ArgVector, SavedStrings); 519 } 520 521 CurArg = ""; 522 } 523 if (*P == '\0') 524 break; 525 else 526 continue; 527 } 528 529 if (isspace(*P)) { 530 if (InQuote != ' ') 531 CurArg.push_back(*P); 532 continue; 533 } 534 535 if (*P == '"' || *P == '\'') { 536 if (InQuote == *P) 537 InQuote = ' '; 538 else if (InQuote == ' ') 539 InQuote = *P; 540 else 541 CurArg.push_back(*P); 542 continue; 543 } 544 545 if (*P == '\\') { 546 ++P; 547 if (*P != '\0') 548 CurArg.push_back(*P); 549 continue; 550 } 551 CurArg.push_back(*P); 552 } 553 } 554 555 // ExpandArgsFromBuf - 556 static void ExpandArgv(int argc, const char **argv, 557 llvm::SmallVectorImpl<const char*> &ArgVector, 558 std::set<std::string> &SavedStrings) { 559 for (int i = 0; i < argc; ++i) { 560 const char *Arg = argv[i]; 561 if (Arg[0] != '@') { 562 ArgVector.push_back(SaveStringInSet(SavedStrings, std::string(Arg))); 563 continue; 564 } 565 566 ExpandArgsFromBuf(Arg, ArgVector, SavedStrings); 567 } 568 } 569