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 36#include <assert.h> 37#include <iostream> 38#include <llvm/Support/raw_ostream.h> 39#include <llvm/Support/CommandLine.h> 40#include <llvm/Support/Host.h> 41#include <llvm/Support/ManagedStatic.h> 42#include <clang/AST/ASTContext.h> 43#include <clang/AST/ASTConsumer.h> 44#include <clang/Basic/FileSystemOptions.h> 45#include <clang/Basic/FileManager.h> 46#include <clang/Basic/TargetOptions.h> 47#include <clang/Basic/TargetInfo.h> 48#include <clang/Basic/Version.h> 49#include <clang/Driver/Compilation.h> 50#include <clang/Driver/Driver.h> 51#include <clang/Driver/Tool.h> 52#include <clang/Frontend/CompilerInstance.h> 53#include <clang/Frontend/CompilerInvocation.h> 54#ifdef HAVE_BASIC_DIAGNOSTICOPTIONS_H 55#include <clang/Basic/DiagnosticOptions.h> 56#else 57#include <clang/Frontend/DiagnosticOptions.h> 58#endif 59#include <clang/Frontend/TextDiagnosticPrinter.h> 60#include <clang/Frontend/Utils.h> 61#include <clang/Lex/HeaderSearch.h> 62#include <clang/Lex/Preprocessor.h> 63#include <clang/Parse/ParseAST.h> 64#include <clang/Sema/Sema.h> 65 66#include "extract_interface.h" 67#include "python.h" 68 69using namespace std; 70using namespace clang; 71using namespace clang::driver; 72 73static llvm::cl::opt<string> InputFilename(llvm::cl::Positional, 74 llvm::cl::Required, llvm::cl::desc("<input file>")); 75static llvm::cl::list<string> Includes("I", 76 llvm::cl::desc("Header search path"), 77 llvm::cl::value_desc("path"), llvm::cl::Prefix); 78 79static const char *ResourceDir = CLANG_PREFIX"/lib/clang/"CLANG_VERSION_STRING; 80 81/* Does decl have an attribute of the following form? 82 * 83 * __attribute__((annotate("name"))) 84 */ 85bool has_annotation(Decl *decl, const char *name) 86{ 87 if (!decl->hasAttrs()) 88 return false; 89 90 AttrVec attrs = decl->getAttrs(); 91 for (AttrVec::const_iterator i = attrs.begin() ; i != attrs.end(); ++i) { 92 const AnnotateAttr *ann = dyn_cast<AnnotateAttr>(*i); 93 if (!ann) 94 continue; 95 if (ann->getAnnotation().str() == name) 96 return true; 97 } 98 99 return false; 100} 101 102/* Is decl marked as exported? 103 */ 104static bool is_exported(Decl *decl) 105{ 106 return has_annotation(decl, "isl_export"); 107} 108 109/* Collect all types and functions that are annotated "isl_export" 110 * in "types" and "function". 111 * 112 * We currently only consider single declarations. 113 */ 114struct MyASTConsumer : public ASTConsumer { 115 set<RecordDecl *> types; 116 set<FunctionDecl *> functions; 117 118 virtual HandleTopLevelDeclReturn HandleTopLevelDecl(DeclGroupRef D) { 119 Decl *decl; 120 121 if (!D.isSingleDecl()) 122 return HandleTopLevelDeclContinue; 123 decl = D.getSingleDecl(); 124 if (!is_exported(decl)) 125 return HandleTopLevelDeclContinue; 126 switch (decl->getKind()) { 127 case Decl::Record: 128 types.insert(cast<RecordDecl>(decl)); 129 break; 130 case Decl::Function: 131 functions.insert(cast<FunctionDecl>(decl)); 132 break; 133 default: 134 break; 135 } 136 return HandleTopLevelDeclContinue; 137 } 138}; 139 140#ifdef USE_ARRAYREF 141 142#ifdef HAVE_CXXISPRODUCTION 143static Driver *construct_driver(const char *binary, DiagnosticsEngine &Diags) 144{ 145 return new Driver(binary, llvm::sys::getDefaultTargetTriple(), 146 "", false, false, Diags); 147} 148#elif defined(HAVE_ISPRODUCTION) 149static Driver *construct_driver(const char *binary, DiagnosticsEngine &Diags) 150{ 151 return new Driver(binary, llvm::sys::getDefaultTargetTriple(), 152 "", false, Diags); 153} 154#else 155static Driver *construct_driver(const char *binary, DiagnosticsEngine &Diags) 156{ 157 return new Driver(binary, llvm::sys::getDefaultTargetTriple(), 158 "", Diags); 159} 160#endif 161 162/* Create a CompilerInvocation object that stores the command line 163 * arguments constructed by the driver. 164 * The arguments are mainly useful for setting up the system include 165 * paths on newer clangs and on some platforms. 166 */ 167static CompilerInvocation *construct_invocation(const char *filename, 168 DiagnosticsEngine &Diags) 169{ 170 const char *binary = CLANG_PREFIX"/bin/clang"; 171 const llvm::OwningPtr<Driver> driver(construct_driver(binary, Diags)); 172 std::vector<const char *> Argv; 173 Argv.push_back(binary); 174 Argv.push_back(filename); 175 const llvm::OwningPtr<Compilation> compilation( 176 driver->BuildCompilation(llvm::ArrayRef<const char *>(Argv))); 177 JobList &Jobs = compilation->getJobs(); 178 179 Command *cmd = cast<Command>(*Jobs.begin()); 180 if (strcmp(cmd->getCreator().getName(), "clang")) 181 return NULL; 182 183 const ArgStringList *args = &cmd->getArguments(); 184 185 CompilerInvocation *invocation = new CompilerInvocation; 186 CompilerInvocation::CreateFromArgs(*invocation, args->data() + 1, 187 args->data() + args->size(), 188 Diags); 189 return invocation; 190} 191 192#else 193 194static CompilerInvocation *construct_invocation(const char *filename, 195 DiagnosticsEngine &Diags) 196{ 197 return NULL; 198} 199 200#endif 201 202#ifdef HAVE_BASIC_DIAGNOSTICOPTIONS_H 203 204static TextDiagnosticPrinter *construct_printer(void) 205{ 206 return new TextDiagnosticPrinter(llvm::errs(), new DiagnosticOptions()); 207} 208 209#else 210 211static TextDiagnosticPrinter *construct_printer(void) 212{ 213 DiagnosticOptions DO; 214 return new TextDiagnosticPrinter(llvm::errs(), DO); 215} 216 217#endif 218 219#ifdef CREATETARGETINFO_TAKES_POINTER 220 221static TargetInfo *create_target_info(CompilerInstance *Clang, 222 DiagnosticsEngine &Diags) 223{ 224 TargetOptions &TO = Clang->getTargetOpts(); 225 TO.Triple = llvm::sys::getDefaultTargetTriple(); 226 return TargetInfo::CreateTargetInfo(Diags, &TO); 227} 228 229#else 230 231static TargetInfo *create_target_info(CompilerInstance *Clang, 232 DiagnosticsEngine &Diags) 233{ 234 TargetOptions &TO = Clang->getTargetOpts(); 235 TO.Triple = llvm::sys::getDefaultTargetTriple(); 236 return TargetInfo::CreateTargetInfo(Diags, TO); 237} 238 239#endif 240 241#ifdef CREATEDIAGNOSTICS_TAKES_ARG 242 243static void create_diagnostics(CompilerInstance *Clang) 244{ 245 Clang->createDiagnostics(0, NULL, construct_printer()); 246} 247 248#else 249 250static void create_diagnostics(CompilerInstance *Clang) 251{ 252 Clang->createDiagnostics(construct_printer()); 253} 254 255#endif 256 257#ifdef ADDPATH_TAKES_4_ARGUMENTS 258 259void add_path(HeaderSearchOptions &HSO, string Path) 260{ 261 HSO.AddPath(Path, frontend::Angled, false, false); 262} 263 264#else 265 266void add_path(HeaderSearchOptions &HSO, string Path) 267{ 268 HSO.AddPath(Path, frontend::Angled, true, false, false); 269} 270 271#endif 272 273int main(int argc, char *argv[]) 274{ 275 llvm::cl::ParseCommandLineOptions(argc, argv); 276 277 CompilerInstance *Clang = new CompilerInstance(); 278 create_diagnostics(Clang); 279 DiagnosticsEngine &Diags = Clang->getDiagnostics(); 280 Diags.setSuppressSystemWarnings(true); 281 CompilerInvocation *invocation = 282 construct_invocation(InputFilename.c_str(), Diags); 283 if (invocation) 284 Clang->setInvocation(invocation); 285 Clang->createFileManager(); 286 Clang->createSourceManager(Clang->getFileManager()); 287 TargetInfo *target = create_target_info(Clang, Diags); 288 Clang->setTarget(target); 289 CompilerInvocation::setLangDefaults(Clang->getLangOpts(), IK_C, 290 LangStandard::lang_unspecified); 291 HeaderSearchOptions &HSO = Clang->getHeaderSearchOpts(); 292 LangOptions &LO = Clang->getLangOpts(); 293 PreprocessorOptions &PO = Clang->getPreprocessorOpts(); 294 HSO.ResourceDir = ResourceDir; 295 296 for (int i = 0; i < Includes.size(); ++i) 297 add_path(HSO, Includes[i]); 298 299 PO.addMacroDef("__isl_give=__attribute__((annotate(\"isl_give\")))"); 300 PO.addMacroDef("__isl_keep=__attribute__((annotate(\"isl_keep\")))"); 301 PO.addMacroDef("__isl_take=__attribute__((annotate(\"isl_take\")))"); 302 PO.addMacroDef("__isl_export=__attribute__((annotate(\"isl_export\")))"); 303 PO.addMacroDef("__isl_constructor=__attribute__((annotate(\"isl_constructor\"))) __attribute__((annotate(\"isl_export\")))"); 304 PO.addMacroDef("__isl_subclass(super)=__attribute__((annotate(\"isl_subclass(\" #super \")\"))) __attribute__((annotate(\"isl_export\")))"); 305 306 Clang->createPreprocessor(); 307 Preprocessor &PP = Clang->getPreprocessor(); 308 309 PP.getBuiltinInfo().InitializeBuiltins(PP.getIdentifierTable(), LO); 310 311 const FileEntry *file = Clang->getFileManager().getFile(InputFilename); 312 assert(file); 313 Clang->getSourceManager().createMainFileID(file); 314 315 Clang->createASTContext(); 316 MyASTConsumer consumer; 317 Sema *sema = new Sema(PP, Clang->getASTContext(), consumer); 318 319 Diags.getClient()->BeginSourceFile(LO, &PP); 320 ParseAST(*sema); 321 Diags.getClient()->EndSourceFile(); 322 323 generate_python(consumer.types, consumer.functions); 324 325 delete sema; 326 delete Clang; 327 llvm::llvm_shutdown(); 328 329 return 0; 330} 331