brintos

brintos / llvm-project-archived public Read only

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