1 /* 2 * Copyright 2011 Sven Verdoolaege. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above 12 * copyright notice, this list of conditions and the following 13 * disclaimer in the documentation and/or other materials provided 14 * with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY SVEN VERDOOLAEGE ''AS IS'' AND ANY 17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SVEN VERDOOLAEGE OR 20 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 23 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * The views and conclusions contained in the software and documentation 29 * are those of the authors and should not be interpreted as 30 * representing official policies, either expressed or implied, of 31 * Sven Verdoolaege. 32 */ 33 34 #include "isl_config.h" 35 #undef PACKAGE 36 37 #include <assert.h> 38 #include <iostream> 39 #include <stdlib.h> 40 #ifdef HAVE_ADT_OWNINGPTR_H 41 #include <llvm/ADT/OwningPtr.h> 42 #else 43 #include <memory> 44 #endif 45 #ifdef HAVE_LLVM_OPTION_ARG_H 46 #include <llvm/Option/Arg.h> 47 #endif 48 #include <llvm/Support/raw_ostream.h> 49 #include <llvm/Support/CommandLine.h> 50 #ifdef HAVE_TARGETPARSER_HOST_H 51 #include <llvm/TargetParser/Host.h> 52 #else 53 #include <llvm/Support/Host.h> 54 #endif 55 #include <llvm/Support/ManagedStatic.h> 56 #include <clang/AST/ASTContext.h> 57 #include <clang/AST/ASTConsumer.h> 58 #include <clang/Basic/Builtins.h> 59 #include <clang/Basic/FileSystemOptions.h> 60 #include <clang/Basic/FileManager.h> 61 #include <clang/Basic/TargetOptions.h> 62 #include <clang/Basic/TargetInfo.h> 63 #include <clang/Basic/Version.h> 64 #include <clang/Driver/Compilation.h> 65 #include <clang/Driver/Driver.h> 66 #include <clang/Driver/Tool.h> 67 #include <clang/Frontend/CompilerInstance.h> 68 #include <clang/Frontend/CompilerInvocation.h> 69 #ifdef HAVE_BASIC_DIAGNOSTICOPTIONS_H 70 #include <clang/Basic/DiagnosticOptions.h> 71 #else 72 #include <clang/Frontend/DiagnosticOptions.h> 73 #endif 74 #include <clang/Frontend/TextDiagnosticPrinter.h> 75 #include <clang/Frontend/Utils.h> 76 #include <clang/Lex/HeaderSearch.h> 77 #ifdef HAVE_LEX_PREPROCESSOROPTIONS_H 78 #include <clang/Lex/PreprocessorOptions.h> 79 #else 80 #include <clang/Frontend/PreprocessorOptions.h> 81 #endif 82 #include <clang/Lex/Preprocessor.h> 83 #include <clang/Parse/ParseAST.h> 84 #include <clang/Sema/Sema.h> 85 86 #include "extract_interface.h" 87 #include "generator.h" 88 #include "python.h" 89 #include "plain_cpp.h" 90 #include "cpp_conversion.h" 91 #include "template_cpp.h" 92 93 using namespace std; 94 using namespace clang; 95 using namespace clang::driver; 96 #ifdef HAVE_LLVM_OPTION_ARG_H 97 using namespace llvm::opt; 98 #endif 99 100 #ifdef HAVE_ADT_OWNINGPTR_H 101 #define unique_ptr llvm::OwningPtr 102 #endif 103 104 static llvm::cl::opt<string> InputFilename(llvm::cl::Positional, 105 llvm::cl::Required, llvm::cl::desc("<input file>")); 106 static llvm::cl::list<string> Includes("I", 107 llvm::cl::desc("Header search path"), 108 llvm::cl::value_desc("path"), llvm::cl::Prefix); 109 110 static llvm::cl::opt<string> OutputLanguage(llvm::cl::Required, 111 llvm::cl::ValueRequired, "language", 112 llvm::cl::desc("Bindings to generate"), 113 llvm::cl::value_desc("name")); 114 115 static const char *ResourceDir = 116 CLANG_PREFIX "/lib/clang/" CLANG_VERSION_STRING; 117 118 /* Does decl have an attribute of the following form? 119 * 120 * __attribute__((annotate("name"))) 121 */ 122 bool has_annotation(Decl *decl, const char *name) 123 { 124 if (!decl->hasAttrs()) 125 return false; 126 127 AttrVec attrs = decl->getAttrs(); 128 for (AttrVec::const_iterator i = attrs.begin() ; i != attrs.end(); ++i) { 129 const AnnotateAttr *ann = dyn_cast<AnnotateAttr>(*i); 130 if (!ann) 131 continue; 132 if (ann->getAnnotation().str() == name) 133 return true; 134 } 135 136 return false; 137 } 138 139 /* Is decl marked as exported? 140 */ 141 static bool is_exported(Decl *decl) 142 { 143 return has_annotation(decl, "isl_export"); 144 } 145 146 /* Collect all types and functions that are annotated "isl_export" 147 * in "exported_types" and "exported_function". Collect all function 148 * declarations in "functions". 149 * 150 * We currently only consider single declarations. 151 */ 152 struct MyASTConsumer : public ASTConsumer { 153 set<RecordDecl *> exported_types; 154 set<FunctionDecl *> exported_functions; 155 set<FunctionDecl *> functions; 156 157 virtual HandleTopLevelDeclReturn HandleTopLevelDecl(DeclGroupRef D) { 158 Decl *decl; 159 160 if (!D.isSingleDecl()) 161 return HandleTopLevelDeclContinue; 162 decl = D.getSingleDecl(); 163 if (isa<FunctionDecl>(decl)) 164 functions.insert(cast<FunctionDecl>(decl)); 165 if (!is_exported(decl)) 166 return HandleTopLevelDeclContinue; 167 switch (decl->getKind()) { 168 case Decl::Record: 169 exported_types.insert(cast<RecordDecl>(decl)); 170 break; 171 case Decl::Function: 172 exported_functions.insert(cast<FunctionDecl>(decl)); 173 break; 174 default: 175 break; 176 } 177 return HandleTopLevelDeclContinue; 178 } 179 }; 180 181 #ifdef USE_ARRAYREF 182 183 #ifdef HAVE_CXXISPRODUCTION 184 static Driver *construct_driver(const char *binary, DiagnosticsEngine &Diags) 185 { 186 return new Driver(binary, llvm::sys::getDefaultTargetTriple(), 187 "", false, false, Diags); 188 } 189 #elif defined(HAVE_ISPRODUCTION) 190 static Driver *construct_driver(const char *binary, DiagnosticsEngine &Diags) 191 { 192 return new Driver(binary, llvm::sys::getDefaultTargetTriple(), 193 "", false, Diags); 194 } 195 #elif defined(DRIVER_CTOR_TAKES_DEFAULTIMAGENAME) 196 static Driver *construct_driver(const char *binary, DiagnosticsEngine &Diags) 197 { 198 return new Driver(binary, llvm::sys::getDefaultTargetTriple(), 199 "", Diags); 200 } 201 #else 202 static Driver *construct_driver(const char *binary, DiagnosticsEngine &Diags) 203 { 204 return new Driver(binary, llvm::sys::getDefaultTargetTriple(), Diags); 205 } 206 #endif 207 208 namespace clang { namespace driver { class Job; } } 209 210 /* Clang changed its API from 3.5 to 3.6 and once more in 3.7. 211 * We fix this with a simple overloaded function here. 212 */ 213 struct ClangAPI { 214 static Job *command(Job *J) { return J; } 215 static Job *command(Job &J) { return &J; } 216 static Command *command(Command &C) { return &C; } 217 }; 218 219 #ifdef CREATE_FROM_ARGS_TAKES_ARRAYREF 220 221 /* Call CompilerInvocation::CreateFromArgs with the right arguments. 222 * In this case, an ArrayRef<const char *>. 223 */ 224 static void create_from_args(CompilerInvocation &invocation, 225 const ArgStringList *args, DiagnosticsEngine &Diags) 226 { 227 CompilerInvocation::CreateFromArgs(invocation, *args, Diags); 228 } 229 230 #else 231 232 /* Call CompilerInvocation::CreateFromArgs with the right arguments. 233 * In this case, two "const char *" pointers. 234 */ 235 static void create_from_args(CompilerInvocation &invocation, 236 const ArgStringList *args, DiagnosticsEngine &Diags) 237 { 238 CompilerInvocation::CreateFromArgs(invocation, args->data() + 1, 239 args->data() + args->size(), 240 Diags); 241 } 242 243 #endif 244 245 #ifdef CLANG_SYSROOT 246 /* Set sysroot if required. 247 * 248 * If CLANG_SYSROOT is defined, then set it to this value. 249 */ 250 static void set_sysroot(ArgStringList &args) 251 { 252 args.push_back("-isysroot"); 253 args.push_back(CLANG_SYSROOT); 254 } 255 #else 256 /* Set sysroot if required. 257 * 258 * If CLANG_SYSROOT is not defined, then it does not need to be set. 259 */ 260 static void set_sysroot(ArgStringList &args) 261 { 262 } 263 #endif 264 265 /* Create a CompilerInvocation object that stores the command line 266 * arguments constructed by the driver. 267 * The arguments are mainly useful for setting up the system include 268 * paths on newer clangs and on some platforms. 269 */ 270 static CompilerInvocation *construct_invocation(const char *filename, 271 DiagnosticsEngine &Diags) 272 { 273 const char *binary = CLANG_PREFIX"/bin/clang"; 274 const unique_ptr<Driver> driver(construct_driver(binary, Diags)); 275 std::vector<const char *> Argv; 276 Argv.push_back(binary); 277 Argv.push_back(filename); 278 const unique_ptr<Compilation> compilation( 279 driver->BuildCompilation(llvm::ArrayRef<const char *>(Argv))); 280 JobList &Jobs = compilation->getJobs(); 281 282 Command *cmd = cast<Command>(ClangAPI::command(*Jobs.begin())); 283 if (strcmp(cmd->getCreator().getName(), "clang")) 284 return NULL; 285 286 ArgStringList args = cmd->getArguments(); 287 set_sysroot(args); 288 289 CompilerInvocation *invocation = new CompilerInvocation; 290 create_from_args(*invocation, &args, Diags); 291 return invocation; 292 } 293 294 #else 295 296 static CompilerInvocation *construct_invocation(const char *filename, 297 DiagnosticsEngine &Diags) 298 { 299 return NULL; 300 } 301 302 #endif 303 304 #ifdef HAVE_BASIC_DIAGNOSTICOPTIONS_H 305 306 static TextDiagnosticPrinter *construct_printer(void) 307 { 308 return new TextDiagnosticPrinter(llvm::errs(), new DiagnosticOptions()); 309 } 310 311 #else 312 313 static TextDiagnosticPrinter *construct_printer(void) 314 { 315 DiagnosticOptions DO; 316 return new TextDiagnosticPrinter(llvm::errs(), DO); 317 } 318 319 #endif 320 321 #ifdef CREATETARGETINFO_TAKES_SHARED_PTR 322 323 static TargetInfo *create_target_info(CompilerInstance *Clang, 324 DiagnosticsEngine &Diags) 325 { 326 shared_ptr<TargetOptions> TO = Clang->getInvocation().TargetOpts; 327 TO->Triple = llvm::sys::getDefaultTargetTriple(); 328 return TargetInfo::CreateTargetInfo(Diags, TO); 329 } 330 331 #elif defined(CREATETARGETINFO_TAKES_POINTER) 332 333 static TargetInfo *create_target_info(CompilerInstance *Clang, 334 DiagnosticsEngine &Diags) 335 { 336 TargetOptions &TO = Clang->getTargetOpts(); 337 TO.Triple = llvm::sys::getDefaultTargetTriple(); 338 return TargetInfo::CreateTargetInfo(Diags, &TO); 339 } 340 341 #else 342 343 static TargetInfo *create_target_info(CompilerInstance *Clang, 344 DiagnosticsEngine &Diags) 345 { 346 TargetOptions &TO = Clang->getTargetOpts(); 347 TO.Triple = llvm::sys::getDefaultTargetTriple(); 348 return TargetInfo::CreateTargetInfo(Diags, TO); 349 } 350 351 #endif 352 353 #ifdef CREATEDIAGNOSTICS_TAKES_ARG 354 355 static void create_diagnostics(CompilerInstance *Clang) 356 { 357 Clang->createDiagnostics(0, NULL, construct_printer()); 358 } 359 360 #else 361 362 static void create_diagnostics(CompilerInstance *Clang) 363 { 364 Clang->createDiagnostics(construct_printer()); 365 } 366 367 #endif 368 369 #ifdef CREATEPREPROCESSOR_TAKES_TUKIND 370 371 static void create_preprocessor(CompilerInstance *Clang) 372 { 373 Clang->createPreprocessor(TU_Complete); 374 } 375 376 #else 377 378 static void create_preprocessor(CompilerInstance *Clang) 379 { 380 Clang->createPreprocessor(); 381 } 382 383 #endif 384 385 #ifdef ADDPATH_TAKES_4_ARGUMENTS 386 387 /* Add "Path" to the header search options. 388 * 389 * Do not take into account sysroot, i.e., set ignoreSysRoot to true. 390 */ 391 void add_path(HeaderSearchOptions &HSO, string Path) 392 { 393 HSO.AddPath(Path, frontend::Angled, false, true); 394 } 395 396 #else 397 398 /* Add "Path" to the header search options. 399 * 400 * Do not take into account sysroot, i.e., set IsSysRootRelative to false. 401 */ 402 void add_path(HeaderSearchOptions &HSO, string Path) 403 { 404 HSO.AddPath(Path, frontend::Angled, true, false, false); 405 } 406 407 #endif 408 409 #ifdef HAVE_SETMAINFILEID 410 411 static void create_main_file_id(SourceManager &SM, const FileEntry *file) 412 { 413 SM.setMainFileID(SM.createFileID(file, SourceLocation(), 414 SrcMgr::C_User)); 415 } 416 417 #else 418 419 static void create_main_file_id(SourceManager &SM, const FileEntry *file) 420 { 421 SM.createMainFileID(file); 422 } 423 424 #endif 425 426 #ifdef SETLANGDEFAULTS_TAKES_5_ARGUMENTS 427 428 #include "set_lang_defaults_arg4.h" 429 430 static void set_lang_defaults(CompilerInstance *Clang) 431 { 432 PreprocessorOptions &PO = Clang->getPreprocessorOpts(); 433 TargetOptions &TO = Clang->getTargetOpts(); 434 llvm::Triple T(TO.Triple); 435 SETLANGDEFAULTS::setLangDefaults(Clang->getLangOpts(), IK_C, T, 436 setLangDefaultsArg4(PO), 437 LangStandard::lang_unspecified); 438 } 439 440 #else 441 442 static void set_lang_defaults(CompilerInstance *Clang) 443 { 444 CompilerInvocation::setLangDefaults(Clang->getLangOpts(), IK_C, 445 LangStandard::lang_unspecified); 446 } 447 448 #endif 449 450 #ifdef SETINVOCATION_TAKES_SHARED_PTR 451 452 static void set_invocation(CompilerInstance *Clang, 453 CompilerInvocation *invocation) 454 { 455 Clang->setInvocation(std::make_shared<CompilerInvocation>(*invocation)); 456 } 457 458 #else 459 460 static void set_invocation(CompilerInstance *Clang, 461 CompilerInvocation *invocation) 462 { 463 Clang->setInvocation(invocation); 464 } 465 466 #endif 467 468 /* Helper function for ignore_error that only gets enabled if T 469 * (which is either const FileEntry * or llvm::ErrorOr<const FileEntry *>) 470 * has getError method, i.e., if it is llvm::ErrorOr<const FileEntry *>. 471 */ 472 template <class T> 473 static const FileEntry *ignore_error_helper(const T obj, int, 474 int[1][sizeof(obj.getError())]) 475 { 476 return *obj; 477 } 478 479 /* Helper function for ignore_error that is always enabled, 480 * but that only gets selected if the variant above is not enabled, 481 * i.e., if T is const FileEntry *. 482 */ 483 template <class T> 484 static const FileEntry *ignore_error_helper(const T obj, long, void *) 485 { 486 return obj; 487 } 488 489 /* Given either a const FileEntry * or a llvm::ErrorOr<const FileEntry *>, 490 * extract out the const FileEntry *. 491 */ 492 template <class T> 493 static const FileEntry *ignore_error(const T obj) 494 { 495 return ignore_error_helper(obj, 0, NULL); 496 } 497 498 /* Return the FileEntry corresponding to the given file name 499 * in the given compiler instances, ignoring any error. 500 */ 501 static const FileEntry *getFile(CompilerInstance *Clang, std::string Filename) 502 { 503 return ignore_error(Clang->getFileManager().getFile(Filename)); 504 } 505 506 /* Create an interface generator for the selected language and 507 * then use it to generate the interface. 508 */ 509 static void generate(MyASTConsumer &consumer, SourceManager &SM) 510 { 511 generator *gen; 512 513 if (OutputLanguage.compare("python") == 0) { 514 gen = new python_generator(SM, consumer.exported_types, 515 consumer.exported_functions, consumer.functions); 516 } else if (OutputLanguage.compare("cpp") == 0) { 517 gen = new plain_cpp_generator(SM, consumer.exported_types, 518 consumer.exported_functions, consumer.functions); 519 } else if (OutputLanguage.compare("cpp-checked") == 0) { 520 gen = new plain_cpp_generator(SM, consumer.exported_types, 521 consumer.exported_functions, consumer.functions, true); 522 } else if (OutputLanguage.compare("cpp-checked-conversion") == 0) { 523 gen = new cpp_conversion_generator(SM, consumer.exported_types, 524 consumer.exported_functions, consumer.functions); 525 } else if (OutputLanguage.compare("template-cpp") == 0) { 526 gen = new template_cpp_generator(SM, consumer.exported_types, 527 consumer.exported_functions, consumer.functions); 528 } else { 529 cerr << "Language '" << OutputLanguage 530 << "' not recognized." << endl 531 << "Not generating bindings." << endl; 532 exit(EXIT_FAILURE); 533 } 534 535 gen->generate(); 536 } 537 538 int main(int argc, char *argv[]) 539 { 540 llvm::cl::ParseCommandLineOptions(argc, argv); 541 542 CompilerInstance *Clang = new CompilerInstance(); 543 create_diagnostics(Clang); 544 DiagnosticsEngine &Diags = Clang->getDiagnostics(); 545 Diags.setSuppressSystemWarnings(true); 546 TargetInfo *target = create_target_info(Clang, Diags); 547 Clang->setTarget(target); 548 set_lang_defaults(Clang); 549 CompilerInvocation *invocation = 550 construct_invocation(InputFilename.c_str(), Diags); 551 if (invocation) 552 set_invocation(Clang, invocation); 553 Clang->createFileManager(); 554 Clang->createSourceManager(Clang->getFileManager()); 555 HeaderSearchOptions &HSO = Clang->getHeaderSearchOpts(); 556 LangOptions &LO = Clang->getLangOpts(); 557 PreprocessorOptions &PO = Clang->getPreprocessorOpts(); 558 HSO.ResourceDir = ResourceDir; 559 560 for (llvm::cl::list<string>::size_type i = 0; i < Includes.size(); ++i) 561 add_path(HSO, Includes[i]); 562 563 PO.addMacroDef("__isl_give=__attribute__((annotate(\"isl_give\")))"); 564 PO.addMacroDef("__isl_keep=__attribute__((annotate(\"isl_keep\")))"); 565 PO.addMacroDef("__isl_take=__attribute__((annotate(\"isl_take\")))"); 566 PO.addMacroDef("__isl_export=__attribute__((annotate(\"isl_export\")))"); 567 PO.addMacroDef("__isl_overload=" 568 "__attribute__((annotate(\"isl_overload\"))) " 569 "__attribute__((annotate(\"isl_export\")))"); 570 PO.addMacroDef("__isl_constructor=__attribute__((annotate(\"isl_constructor\"))) __attribute__((annotate(\"isl_export\")))"); 571 PO.addMacroDef("__isl_subclass(super)=__attribute__((annotate(\"isl_subclass(\" #super \")\"))) __attribute__((annotate(\"isl_export\")))"); 572 573 create_preprocessor(Clang); 574 Preprocessor &PP = Clang->getPreprocessor(); 575 576 PP.getBuiltinInfo().initializeBuiltins(PP.getIdentifierTable(), LO); 577 578 const FileEntry *file = getFile(Clang, InputFilename); 579 assert(file); 580 create_main_file_id(Clang->getSourceManager(), file); 581 582 Clang->createASTContext(); 583 MyASTConsumer consumer; 584 Sema *sema = new Sema(PP, Clang->getASTContext(), consumer); 585 586 Diags.getClient()->BeginSourceFile(LO, &PP); 587 ParseAST(*sema); 588 Diags.getClient()->EndSourceFile(); 589 590 generate(consumer, Clang->getSourceManager()); 591 592 delete sema; 593 delete Clang; 594 llvm::llvm_shutdown(); 595 596 if (Diags.hasErrorOccurred()) 597 return EXIT_FAILURE; 598 return EXIT_SUCCESS; 599 } 600