drop C++ bindings
[isl.git] / interface / extract_interface.cc
blob11186887f9913c701c4d9eabc215b11b0efdeb8a
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.
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.
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.
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 */
34 #include "isl_config.h"
36 #include <assert.h>
37 #include <iostream>
38 #ifdef HAVE_ADT_OWNINGPTR_H
39 #include <llvm/ADT/OwningPtr.h>
40 #else
41 #include <memory>
42 #endif
43 #include <llvm/Support/raw_ostream.h>
44 #include <llvm/Support/CommandLine.h>
45 #include <llvm/Support/Host.h>
46 #include <llvm/Support/ManagedStatic.h>
47 #include <clang/AST/ASTContext.h>
48 #include <clang/AST/ASTConsumer.h>
49 #include <clang/Basic/FileSystemOptions.h>
50 #include <clang/Basic/FileManager.h>
51 #include <clang/Basic/TargetOptions.h>
52 #include <clang/Basic/TargetInfo.h>
53 #include <clang/Basic/Version.h>
54 #include <clang/Driver/Compilation.h>
55 #include <clang/Driver/Driver.h>
56 #include <clang/Driver/Tool.h>
57 #include <clang/Frontend/CompilerInstance.h>
58 #include <clang/Frontend/CompilerInvocation.h>
59 #ifdef HAVE_BASIC_DIAGNOSTICOPTIONS_H
60 #include <clang/Basic/DiagnosticOptions.h>
61 #else
62 #include <clang/Frontend/DiagnosticOptions.h>
63 #endif
64 #include <clang/Frontend/TextDiagnosticPrinter.h>
65 #include <clang/Frontend/Utils.h>
66 #include <clang/Lex/HeaderSearch.h>
67 #ifdef HAVE_LEX_PREPROCESSOROPTIONS_H
68 #include <clang/Lex/PreprocessorOptions.h>
69 #else
70 #include <clang/Frontend/PreprocessorOptions.h>
71 #endif
72 #include <clang/Lex/Preprocessor.h>
73 #include <clang/Parse/ParseAST.h>
74 #include <clang/Sema/Sema.h>
76 #include "extract_interface.h"
77 #include "generator.h"
78 #include "python.h"
80 using namespace std;
81 using namespace clang;
82 using namespace clang::driver;
84 #ifdef HAVE_ADT_OWNINGPTR_H
85 #define unique_ptr llvm::OwningPtr
86 #endif
88 static llvm::cl::opt<string> InputFilename(llvm::cl::Positional,
89 llvm::cl::Required, llvm::cl::desc("<input file>"));
90 static llvm::cl::list<string> Includes("I",
91 llvm::cl::desc("Header search path"),
92 llvm::cl::value_desc("path"), llvm::cl::Prefix);
94 static llvm::cl::opt<string> Language(llvm::cl::Required,
95 llvm::cl::ValueRequired, "language",
96 llvm::cl::desc("Bindings to generate"),
97 llvm::cl::value_desc("name"));
99 static const char *ResourceDir =
100 CLANG_PREFIX "/lib/clang/" CLANG_VERSION_STRING;
102 /* Does decl have an attribute of the following form?
104 * __attribute__((annotate("name")))
106 bool has_annotation(Decl *decl, const char *name)
108 if (!decl->hasAttrs())
109 return false;
111 AttrVec attrs = decl->getAttrs();
112 for (AttrVec::const_iterator i = attrs.begin() ; i != attrs.end(); ++i) {
113 const AnnotateAttr *ann = dyn_cast<AnnotateAttr>(*i);
114 if (!ann)
115 continue;
116 if (ann->getAnnotation().str() == name)
117 return true;
120 return false;
123 /* Is decl marked as exported?
125 static bool is_exported(Decl *decl)
127 return has_annotation(decl, "isl_export");
130 /* Collect all types and functions that are annotated "isl_export"
131 * in "exported_types" and "exported_function". Collect all function
132 * declarations in "functions".
134 * We currently only consider single declarations.
136 struct MyASTConsumer : public ASTConsumer {
137 set<RecordDecl *> exported_types;
138 set<FunctionDecl *> exported_functions;
139 set<FunctionDecl *> functions;
141 virtual HandleTopLevelDeclReturn HandleTopLevelDecl(DeclGroupRef D) {
142 Decl *decl;
144 if (!D.isSingleDecl())
145 return HandleTopLevelDeclContinue;
146 decl = D.getSingleDecl();
147 if (isa<FunctionDecl>(decl))
148 functions.insert(cast<FunctionDecl>(decl));
149 if (!is_exported(decl))
150 return HandleTopLevelDeclContinue;
151 switch (decl->getKind()) {
152 case Decl::Record:
153 exported_types.insert(cast<RecordDecl>(decl));
154 break;
155 case Decl::Function:
156 exported_functions.insert(cast<FunctionDecl>(decl));
157 break;
158 default:
159 break;
161 return HandleTopLevelDeclContinue;
165 #ifdef USE_ARRAYREF
167 #ifdef HAVE_CXXISPRODUCTION
168 static Driver *construct_driver(const char *binary, DiagnosticsEngine &Diags)
170 return new Driver(binary, llvm::sys::getDefaultTargetTriple(),
171 "", false, false, Diags);
173 #elif defined(HAVE_ISPRODUCTION)
174 static Driver *construct_driver(const char *binary, DiagnosticsEngine &Diags)
176 return new Driver(binary, llvm::sys::getDefaultTargetTriple(),
177 "", false, Diags);
179 #elif defined(DRIVER_CTOR_TAKES_DEFAULTIMAGENAME)
180 static Driver *construct_driver(const char *binary, DiagnosticsEngine &Diags)
182 return new Driver(binary, llvm::sys::getDefaultTargetTriple(),
183 "", Diags);
185 #else
186 static Driver *construct_driver(const char *binary, DiagnosticsEngine &Diags)
188 return new Driver(binary, llvm::sys::getDefaultTargetTriple(), Diags);
190 #endif
192 namespace clang { namespace driver { class Job; } }
194 /* Clang changed its API from 3.5 to 3.6 and once more in 3.7.
195 * We fix this with a simple overloaded function here.
197 struct ClangAPI {
198 static Job *command(Job *J) { return J; }
199 static Job *command(Job &J) { return &J; }
200 static Command *command(Command &C) { return &C; }
203 /* Create a CompilerInvocation object that stores the command line
204 * arguments constructed by the driver.
205 * The arguments are mainly useful for setting up the system include
206 * paths on newer clangs and on some platforms.
208 static CompilerInvocation *construct_invocation(const char *filename,
209 DiagnosticsEngine &Diags)
211 const char *binary = CLANG_PREFIX"/bin/clang";
212 const unique_ptr<Driver> driver(construct_driver(binary, Diags));
213 std::vector<const char *> Argv;
214 Argv.push_back(binary);
215 Argv.push_back(filename);
216 const unique_ptr<Compilation> compilation(
217 driver->BuildCompilation(llvm::ArrayRef<const char *>(Argv)));
218 JobList &Jobs = compilation->getJobs();
220 Command *cmd = cast<Command>(ClangAPI::command(*Jobs.begin()));
221 if (strcmp(cmd->getCreator().getName(), "clang"))
222 return NULL;
224 const ArgStringList *args = &cmd->getArguments();
226 CompilerInvocation *invocation = new CompilerInvocation;
227 CompilerInvocation::CreateFromArgs(*invocation, args->data() + 1,
228 args->data() + args->size(),
229 Diags);
230 return invocation;
233 #else
235 static CompilerInvocation *construct_invocation(const char *filename,
236 DiagnosticsEngine &Diags)
238 return NULL;
241 #endif
243 #ifdef HAVE_BASIC_DIAGNOSTICOPTIONS_H
245 static TextDiagnosticPrinter *construct_printer(void)
247 return new TextDiagnosticPrinter(llvm::errs(), new DiagnosticOptions());
250 #else
252 static TextDiagnosticPrinter *construct_printer(void)
254 DiagnosticOptions DO;
255 return new TextDiagnosticPrinter(llvm::errs(), DO);
258 #endif
260 #ifdef CREATETARGETINFO_TAKES_SHARED_PTR
262 static TargetInfo *create_target_info(CompilerInstance *Clang,
263 DiagnosticsEngine &Diags)
265 shared_ptr<TargetOptions> TO = Clang->getInvocation().TargetOpts;
266 TO->Triple = llvm::sys::getDefaultTargetTriple();
267 return TargetInfo::CreateTargetInfo(Diags, TO);
270 #elif defined(CREATETARGETINFO_TAKES_POINTER)
272 static TargetInfo *create_target_info(CompilerInstance *Clang,
273 DiagnosticsEngine &Diags)
275 TargetOptions &TO = Clang->getTargetOpts();
276 TO.Triple = llvm::sys::getDefaultTargetTriple();
277 return TargetInfo::CreateTargetInfo(Diags, &TO);
280 #else
282 static TargetInfo *create_target_info(CompilerInstance *Clang,
283 DiagnosticsEngine &Diags)
285 TargetOptions &TO = Clang->getTargetOpts();
286 TO.Triple = llvm::sys::getDefaultTargetTriple();
287 return TargetInfo::CreateTargetInfo(Diags, TO);
290 #endif
292 #ifdef CREATEDIAGNOSTICS_TAKES_ARG
294 static void create_diagnostics(CompilerInstance *Clang)
296 Clang->createDiagnostics(0, NULL, construct_printer());
299 #else
301 static void create_diagnostics(CompilerInstance *Clang)
303 Clang->createDiagnostics(construct_printer());
306 #endif
308 #ifdef CREATEPREPROCESSOR_TAKES_TUKIND
310 static void create_preprocessor(CompilerInstance *Clang)
312 Clang->createPreprocessor(TU_Complete);
315 #else
317 static void create_preprocessor(CompilerInstance *Clang)
319 Clang->createPreprocessor();
322 #endif
324 #ifdef ADDPATH_TAKES_4_ARGUMENTS
326 void add_path(HeaderSearchOptions &HSO, string Path)
328 HSO.AddPath(Path, frontend::Angled, false, false);
331 #else
333 void add_path(HeaderSearchOptions &HSO, string Path)
335 HSO.AddPath(Path, frontend::Angled, true, false, false);
338 #endif
340 #ifdef HAVE_SETMAINFILEID
342 static void create_main_file_id(SourceManager &SM, const FileEntry *file)
344 SM.setMainFileID(SM.createFileID(file, SourceLocation(),
345 SrcMgr::C_User));
348 #else
350 static void create_main_file_id(SourceManager &SM, const FileEntry *file)
352 SM.createMainFileID(file);
355 #endif
357 #ifdef SETLANGDEFAULTS_TAKES_5_ARGUMENTS
359 static void set_lang_defaults(CompilerInstance *Clang)
361 PreprocessorOptions &PO = Clang->getPreprocessorOpts();
362 TargetOptions &TO = Clang->getTargetOpts();
363 llvm::Triple T(TO.Triple);
364 CompilerInvocation::setLangDefaults(Clang->getLangOpts(), IK_C, T, PO,
365 LangStandard::lang_unspecified);
368 #else
370 static void set_lang_defaults(CompilerInstance *Clang)
372 CompilerInvocation::setLangDefaults(Clang->getLangOpts(), IK_C,
373 LangStandard::lang_unspecified);
376 #endif
378 #ifdef SETINVOCATION_TAKES_SHARED_PTR
380 static void set_invocation(CompilerInstance *Clang,
381 CompilerInvocation *invocation)
383 Clang->setInvocation(std::make_shared<CompilerInvocation>(*invocation));
386 #else
388 static void set_invocation(CompilerInstance *Clang,
389 CompilerInvocation *invocation)
391 Clang->setInvocation(invocation);
394 #endif
396 int main(int argc, char *argv[])
398 llvm::cl::ParseCommandLineOptions(argc, argv);
400 CompilerInstance *Clang = new CompilerInstance();
401 create_diagnostics(Clang);
402 DiagnosticsEngine &Diags = Clang->getDiagnostics();
403 Diags.setSuppressSystemWarnings(true);
404 CompilerInvocation *invocation =
405 construct_invocation(InputFilename.c_str(), Diags);
406 if (invocation)
407 set_invocation(Clang, invocation);
408 Clang->createFileManager();
409 Clang->createSourceManager(Clang->getFileManager());
410 TargetInfo *target = create_target_info(Clang, Diags);
411 Clang->setTarget(target);
412 set_lang_defaults(Clang);
413 HeaderSearchOptions &HSO = Clang->getHeaderSearchOpts();
414 LangOptions &LO = Clang->getLangOpts();
415 PreprocessorOptions &PO = Clang->getPreprocessorOpts();
416 HSO.ResourceDir = ResourceDir;
418 for (llvm::cl::list<string>::size_type i = 0; i < Includes.size(); ++i)
419 add_path(HSO, Includes[i]);
421 PO.addMacroDef("__isl_give=__attribute__((annotate(\"isl_give\")))");
422 PO.addMacroDef("__isl_keep=__attribute__((annotate(\"isl_keep\")))");
423 PO.addMacroDef("__isl_take=__attribute__((annotate(\"isl_take\")))");
424 PO.addMacroDef("__isl_export=__attribute__((annotate(\"isl_export\")))");
425 PO.addMacroDef("__isl_overload="
426 "__attribute__((annotate(\"isl_overload\"))) "
427 "__attribute__((annotate(\"isl_export\")))");
428 PO.addMacroDef("__isl_constructor=__attribute__((annotate(\"isl_constructor\"))) __attribute__((annotate(\"isl_export\")))");
429 PO.addMacroDef("__isl_subclass(super)=__attribute__((annotate(\"isl_subclass(\" #super \")\"))) __attribute__((annotate(\"isl_export\")))");
431 create_preprocessor(Clang);
432 Preprocessor &PP = Clang->getPreprocessor();
434 PP.getBuiltinInfo().initializeBuiltins(PP.getIdentifierTable(), LO);
436 const FileEntry *file = Clang->getFileManager().getFile(InputFilename);
437 assert(file);
438 create_main_file_id(Clang->getSourceManager(), file);
440 Clang->createASTContext();
441 MyASTConsumer consumer;
442 Sema *sema = new Sema(PP, Clang->getASTContext(), consumer);
444 Diags.getClient()->BeginSourceFile(LO, &PP);
445 ParseAST(*sema);
446 Diags.getClient()->EndSourceFile();
448 generator *gen = NULL;
449 if (Language.compare("python") == 0)
450 gen = new python_generator(consumer.exported_types,
451 consumer.exported_functions, consumer.functions);
452 else
453 cerr << "Language '" << Language << "' not recognized." << endl
454 << "Not generating bindings." << endl;
456 if (gen)
457 gen->generate();
459 delete sema;
460 delete Clang;
461 llvm::llvm_shutdown();
463 return 0;