examples/PrintFunctionNames/PrintFunctionNames.cpp | 68 +++--- examples/PrintFunctionNames/PrintFunctionNames.exports | 2 +- examples/PrintFunctionNames/README.txt | 12 +- include/clang/Basic/Plugin.h | 95 +++++++++ include/clang/Driver/CC1Options.td | 4 + include/clang/Driver/Options.td | 2 + include/clang/Frontend/FrontendOptions.h | 7 + lib/Driver/Tools.cpp | 4 + lib/Frontend/CompilerInvocation.cpp | 40 ++++ lib/FrontendTool/ExecuteCompilerInvocation.cpp | 163 ++++++++++++++++- 10 files changed, 352 insertions(+), 45 deletions(-)
# HG changeset patch # User Joshua Cranmer <[email protected]> # Date 1325721797 21600 # Node ID 32744ae33da253c873d464209c97a76441d25c59 # Parent 78b3e55ff7624825022225734078ec56a0e8b535 [mq]: clang-plugin diff --git a/examples/PrintFunctionNames/PrintFunctionNames.cpp b/examples/PrintFunctionNames/PrintFunctionNames.cpp --- a/examples/PrintFunctionNames/PrintFunctionNames.cpp +++ b/examples/PrintFunctionNames/PrintFunctionNames.cpp @@ -7,65 +7,59 @@ // //===----------------------------------------------------------------------===// // // Example clang plugin which simply prints the names of all the top-level decls // in the input file. // //===----------------------------------------------------------------------===// -#include "clang/Frontend/FrontendPluginRegistry.h" +#include "clang/Basic/Plugin.h" +#include "clang/Basic/Version.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/AST.h" -#include "clang/Frontend/CompilerInstance.h" #include "llvm/Support/raw_ostream.h" using namespace clang; namespace { - +static int NumFuncs = 0; class PrintFunctionsConsumer : public ASTConsumer { public: virtual bool HandleTopLevelDecl(DeclGroupRef DG) { for (DeclGroupRef::iterator i = DG.begin(), e = DG.end(); i != e; ++i) { const Decl *D = *i; - if (const NamedDecl *ND = dyn_cast<NamedDecl>(D)) + if (const NamedDecl *ND = dyn_cast<NamedDecl>(D)) { llvm::errs() << "top-level-decl: \"" << ND->getNameAsString() << "\"\n"; + ++NumFuncs; + } } return true; } }; -class PrintFunctionNamesAction : public PluginASTAction { -protected: - ASTConsumer *CreateASTConsumer(CompilerInstance &CI, llvm::StringRef) { - return new PrintFunctionsConsumer(); - } - - bool ParseArgs(const CompilerInstance &CI, - const std::vector<std::string>& args) { - for (unsigned i = 0, e = args.size(); i != e; ++i) { - llvm::errs() << "PrintFunctionNames arg = " << args[i] << "\n"; - - // Example error handling. - if (args[i] == "-an-error") { - DiagnosticsEngine &D = CI.getDiagnostics(); - unsigned DiagID = D.getCustomDiagID( - DiagnosticsEngine::Error, "invalid argument '" + args[i] + "'"); - D.Report(DiagID); - return false; - } - } - if (args.size() && args[0] == "help") - PrintHelp(llvm::errs()); - - return true; - } - void PrintHelp(llvm::raw_ostream& ros) { - ros << "Help for PrintFunctionNames plugin goes here\n"; - } - -}; - } -static FrontendPluginRegistry::Add<PrintFunctionNamesAction> -X("print-fns", "print function names"); +extern "C" { + +bool clang_plugin_init(int argc, plugin::PluginArg *argv, + plugin::Version *version) { + if (version->major != CLANG_VERSION_MAJOR || + version->minor != CLANG_VERSION_MINOR) + return false; + + llvm::errs() << "Number of arguments: " << argc << '\n'; + for (int i = 0; i < argc; i++) + llvm::errs() << "Plugin argument: arg " << argv[i].name + << " is set to value " << argv[i].value << '\n'; + return true; +} + +void clang_plugin_begin_file(llvm::StringRef fileName, + plugin::PluginFileCallbacks *callbacks) { + llvm::errs() << "Found when compiling " << fileName << ":\n"; + callbacks->astConsumer = new PrintFunctionsConsumer(); +} + +void clang_plugin_destroy() { + llvm::errs() << "Total functions found: " << NumFuncs << '\n'; +} +} diff --git a/examples/PrintFunctionNames/PrintFunctionNames.exports b/examples/PrintFunctionNames/PrintFunctionNames.exports --- a/examples/PrintFunctionNames/PrintFunctionNames.exports +++ b/examples/PrintFunctionNames/PrintFunctionNames.exports @@ -1,1 +1,1 @@ -_ZN4llvm8Registry* +clang_plugin_* diff --git a/examples/PrintFunctionNames/README.txt b/examples/PrintFunctionNames/README.txt --- a/examples/PrintFunctionNames/README.txt +++ b/examples/PrintFunctionNames/README.txt @@ -1,16 +1,16 @@ This is a simple example demonstrating how to use clang's facility for providing AST consumers using a plugin. Build the plugin by running `make` in this directory. Once the plugin is built, you can run it using: -- Linux: -$ clang -cc1 -load ../../Debug+Asserts/lib/libPrintFunctionNames.so -plugin print-fns some-input-file.c -$ clang -cc1 -load ../../Debug+Asserts/lib/libPrintFunctionNames.so -plugin print-fns -plugin-arg-print-fns help -plugin-arg-print-fns --example-argument some-input-file.c -$ clang -cc1 -load ../../Debug+Asserts/lib/libPrintFunctionNames.so -plugin print-fns -plugin-arg-print-fns -an-error some-input-file.c +$ clang -cc1 -fplugin=../../Debug+Asserts/lib/libPrintFunctionNames.so some-input-file.c +$ clang -cc1 -fplugin=../../Debug+Asserts/lib/libPrintFunctionNames.so -fplugin-arg-libPrintFunctionNames-example=some-input some-input-file.c +$ clang -cc1 -fp-load ../../Debug+Asserts/lib/libPrintFunctionNames.so -fplugin-arg-iibPrintFunctionNames-example2 some-input-file.c Mac: -$ clang -cc1 -load ../../Debug+Asserts/lib/libPrintFunctionNames.dylib -plugin print-fns some-input-file.c -$ clang -cc1 -load ../../Debug+Asserts/lib/libPrintFunctionNames.dylib -plugin print-fns -plugin-arg-print-fns help -plugin-arg-print-fns --example-argument some-input-file.c -$ clang -cc1 -load ../../Debug+Asserts/lib/libPrintFunctionNames.dylib -plugin print-fns -plugin-arg-print-fns -an-error some-input-file.c +$ clang -cc1 -fplugin=../../Debug+Asserts/lib/libPrintFunctionNames.dylib some-input-file.c +$ clang -cc1 -fplugin=../../Debug+Asserts/lib/libPrintFunctionNames.dylib -fplugin-arg-libPrintFunctionNames-example=some-input some-input-file.c +$ clang -cc1 -fp-load ../../Debug+Asserts/lib/libPrintFunctionNames.dylio -fplugin-arg-iibPrintFunctionNames-example2 some-input-file.c diff --git a/include/clang/Basic/Plugin.h b/include/clang/Basic/Plugin.h new file mode 100644 --- /dev/null +++ b/include/clang/Basic/Plugin.h @@ -0,0 +1,95 @@ +//===--- Plugin.h -----------------------------------------------*- C++ -*_===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_PLUGIN_H +#define LLVM_CLANG_BASIC_PLUGIN_H + +#include "llvm/ADT/StringRef.h" + +namespace llvm { + class StringRef; +} + +namespace clang { + + class ASTConsumer; + class PPCallbacks; + class DiagnosticConsumer; + +namespace plugin { + +struct PluginArg { + const char *name; + const char *value; +}; + +struct Version { + unsigned major; + unsigned minor; + unsigned subminor; +}; + +struct PluginFileCallbacks { + ASTConsumer *astConsumer; + PPCallbacks *ppCallback; + DiagnosticConsumer *diagnostics; +}; + +extern "C" { + +/** + * Callback to initialize the plugin. + * + * \note This is the only function whose ABI compatibility is guaranteed to + * remain stable. All plugins should verify that the version passed into + * this function is the same version that they were compiled with and + * abort if this is not the case. To detect the version compiled with, + * include clang/Basic/Version.h and check CLANG_VERSION_MAJOR and + * CLANG_VERSION_MINOR. + * + * \arg argc The number of arguments in the argv array + * \arg argv An array of the arguments passed to this plugin from the + * command line. + * \arg version The version of the compiler being called. + * \return Whether or not the plugin initialization succeeded. If initialization + * fails, the compilation process is terminated. + */ +extern bool clang_plugin_init(int argc, PluginArg *argv, Version *version); + +/** + * Callback that is called before a function is compiled. + * + * Before this function is called, the callbacks object will have all of its + * pointers set to null. All non-null callbacks will be deleted by the compiler + * internally, so one should always return a new pointer for every file. + * + * \arg fileName The name of the function being called. + * \arg callbacks The pointer to the callbacks that this plugin will define for + * this file. + */ +extern void clang_plugin_begin_file(llvm::StringRef fileName, + PluginFileCallbacks *callbacks); + +/** + * Callback that is called after a function has been compiled. + * + * \arg fileName The name of the function being called. + */ +extern void clang_plugin_end_file(llvm::StringRef fileName); + +/** + * Callback that is called after all functions have been compiled. + */ +extern void clang_plugin_destroy(); +} + +} // namespace plugin +} // namespace clang + +#endif diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td --- a/include/clang/Driver/CC1Options.td +++ b/include/clang/Driver/CC1Options.td @@ -362,16 +362,20 @@ def load : Separate<"-load">, MetaVarNam HelpText<"Load the named plugin (dynamic shared object)">; def plugin : Separate<"-plugin">, MetaVarName<"<name>">, HelpText<"Use the named plugin action instead of the default action (use \"help\" to list available options)">; def plugin_arg : JoinedAndSeparate<"-plugin-arg-">, MetaVarName<"<name> <arg>">, HelpText<"Pass <arg> to plugin <name>">; def add_plugin : Separate<"-add-plugin">, MetaVarName<"<name>">, HelpText<"Use the named plugin action in addition to the default action">; +def fplugin : Joined<"-fplugin=">, + HelpText<"Load the named compiler plugin">; +def fplugin_arg : Joined<"-fplugin-arg-">, + HelpText<"Pass <arg> to plugin <name>">; def resource_dir : Separate<"-resource-dir">, HelpText<"The directory which holds the compiler resource files">; def version : Flag<"-version">, HelpText<"Print the compiler version">; def _version : Flag<"--version">, Alias<version>; def Action_Group : OptionGroup<"<action group>">; let Group = Action_Group in { diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td --- a/include/clang/Driver/Options.td +++ b/include/clang/Driver/Options.td @@ -483,16 +483,18 @@ def foutput_class_dir_EQ : Joined<"-fout def fpack_struct : Flag<"-fpack-struct">, Group<f_Group>; def fno_pack_struct : Flag<"-fno-pack-struct">, Group<f_Group>; def fpack_struct_EQ : Joined<"-fpack-struct=">, Group<f_Group>; def fpascal_strings : Flag<"-fpascal-strings">, Group<f_Group>; def fpch_preprocess : Flag<"-fpch-preprocess">, Group<f_Group>; def fpic : Flag<"-fpic">, Group<f_Group>; def fpie : Flag<"-fpie">, Group<f_Group>, Flags<[NoArgumentUnused]>; def fno_pie : Flag<"-fno-pie">, Group<f_Group>, Flags<[NoArgumentUnused]>; +def fplugin : Joined<"-fplugin=">, Group<f_Group>; +def fplugin_arg : Joined<"-fplugin-arg-">, Group<f_Group>; def fprofile_arcs : Flag<"-fprofile-arcs">, Group<f_Group>; def fprofile_generate : Flag<"-fprofile-generate">, Group<f_Group>; def framework : Separate<"-framework">, Flags<[LinkerInput]>; def frandom_seed_EQ : Joined<"-frandom-seed=">, Group<clang_ignored_f_Group>; def frtti : Flag<"-frtti">, Group<f_Group>; def fsched_interblock : Flag<"-fsched-interblock">, Group<clang_ignored_f_Group>; def fshort_enums : Flag<"-fshort-enums">, Group<f_Group>; def freorder_blocks : Flag<"-freorder-blocks">, Group<clang_ignored_f_Group>; diff --git a/include/clang/Frontend/FrontendOptions.h b/include/clang/Frontend/FrontendOptions.h --- a/include/clang/Frontend/FrontendOptions.h +++ b/include/clang/Frontend/FrontendOptions.h @@ -146,16 +146,23 @@ public: std::vector<std::string> AddPluginActions; /// Args to pass to the additional plugins std::vector<std::vector<std::string> > AddPluginArgs; /// The list of plugins to load. std::vector<std::string> Plugins; + /// The list of compiler plugins to load. + std::vector<std::string> CompilerPlugins; + + /// Argments for the above compiler plugins + std::vector<std::vector<std::pair<std::string, std::string> > > + CompilerPluginArgs; + /// \brief The list of AST files to merge. std::vector<std::string> ASTMergeFiles; /// \brief A list of arguments to forward to LLVM's option processing; this /// should only be used for debugging and experimental features. std::vector<std::string> LLVMArgs; /// \brief File name of the file that will provide record layouts diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp --- a/lib/Driver/Tools.cpp +++ b/lib/Driver/Tools.cpp @@ -1376,16 +1376,20 @@ void Clang::ConstructJob(Compilation &C, CmdArgs.push_back("-w"); // Add -Xanalyzer arguments when running as analyzer. Args.AddAllArgValues(CmdArgs, options::OPT_Xanalyzer); } CheckCodeGenerationOptions(D, Args); + // Pass through plugins + Args.AddAllArgs(CmdArgs, options::OPT_fplugin); + Args.AddAllArgs(CmdArgs, options::OPT_fplugin_arg); + // Perform argument translation for LLVM backend. This // takes some care in reconciling with llvm-gcc. The // issue is that llvm-gcc translates these options based on // the values in cc1, whereas we are processing based on // the driver arguments. // This comes from the default translation the driver + cc1 // would do to enable flag_pic. diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -1395,16 +1395,56 @@ static InputKind ParseFrontendArgs(Front for (int i = 0, e = Opts.AddPluginActions.size(); i != e; ++i) { for (arg_iterator it = Args.filtered_begin(OPT_plugin_arg), end = Args.filtered_end(); it != end; ++it) { if ((*it)->getValue(Args, 0) == Opts.AddPluginActions[i]) Opts.AddPluginArgs[i].push_back((*it)->getValue(Args, 1)); } } + Opts.CompilerPlugins = Args.getAllArgValues(OPT_fplugin); + Opts.CompilerPluginArgs.resize(Opts.CompilerPlugins.size()); + + // Parse the plugin arguments + std::vector<std::pair<std::string, std::string> > ParsedPluginArgs; + for (arg_iterator it = Args.filtered_begin(OPT_fplugin_arg), + end = Args.filtered_end(); it != end; ++it) { + std::string value = (*it)->getValue(Args); + size_t boundary = value.find('-'); + if (boundary == std::string::npos) { + Diags.Report(diag::err_drv_unknown_argument) << value; + continue; + } + ParsedPluginArgs.push_back(std::pair<std::string, std::string>( + value.substr(0, boundary), value.substr(boundary + 1))); + } + + // Add the plugin arguments to a parsedPluginArgs + for (int i = 0, e = Opts.CompilerPlugins.size(); i != e; ++i) { + std::string base = llvm::sys::path::stem(Opts.CompilerPlugins[i]); + for (std::vector<std::pair<std::string, std::string> >::iterator + it = ParsedPluginArgs.begin(), end = ParsedPluginArgs.end(); + it != end; ++it) { + if (it->first == base) { + std::string argpair = it->second; + size_t boundary = argpair.find("="); + // Treat no '=' as an arg with no value + if (boundary == std::string::npos) { + Opts.CompilerPluginArgs[i].push_back( + std::pair<std::string, std::string>(argpair, "")); + } else { + Opts.CompilerPluginArgs[i].push_back( + std::pair<std::string, std::string>(argpair.substr(0, boundary), + argpair.substr(boundary + 1))); + } + } + } + } + + if (const Arg *A = Args.getLastArg(OPT_code_completion_at)) { Opts.CodeCompletionAt = ParsedSourceLocation::FromString(A->getValue(Args)); if (Opts.CodeCompletionAt.FileName.empty()) Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << A->getValue(Args); } Opts.DisableFree = Args.hasArg(OPT_disable_free); diff --git a/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/lib/FrontendTool/ExecuteCompilerInvocation.cpp --- a/lib/FrontendTool/ExecuteCompilerInvocation.cpp +++ b/lib/FrontendTool/ExecuteCompilerInvocation.cpp @@ -10,29 +10,137 @@ // This file holds ExecuteCompilerInvocation(). It is split into its own file to // minimize the impact of pulling in essentially everything else in Clang. // //===----------------------------------------------------------------------===// #include "clang/FrontendTool/Utils.h" #include "clang/StaticAnalyzer/Frontend/FrontendActions.h" #include "clang/ARCMigrate/ARCMTActions.h" +#include "clang/Basic/Plugin.h" +#include "clang/Basic/Version.inc" #include "clang/CodeGen/CodeGenAction.h" #include "clang/Driver/CC1Options.h" #include "clang/Driver/OptTable.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Frontend/ChainedDiagnosticConsumer.h" #include "clang/Frontend/CompilerInvocation.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendActions.h" #include "clang/Frontend/FrontendDiagnostic.h" #include "clang/Frontend/FrontendPluginRegistry.h" +#include "clang/Frontend/MultiplexConsumer.h" #include "clang/Rewrite/FrontendActions.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/DynamicLibrary.h" using namespace clang; +namespace { + class Plugin { + llvm::sys::DynamicLibrary PluginLibrary; + clang::plugin::PluginFileCallbacks callbacks; + public: + Plugin(llvm::sys::DynamicLibrary library) : PluginLibrary(library) {} + clang::plugin::PluginFileCallbacks *getCallbacks() { return &callbacks; } + intptr_t getFunctionCall(const char *name) { + return (intptr_t)PluginLibrary.getAddressOfSymbol(name); + } + + typedef void (*BeginFileType)(StringRef, clang::plugin::PluginFileCallbacks*); + typedef void (*EndFileFnTy)(StringRef); + typedef void (*DestroyTy)(); + }; + class PluginWrapperAction : public WrapperFrontendAction { + std::vector<Plugin> plugins; + std::string CurrentFile; + public: + PluginWrapperAction(FrontendAction *WrappedAction, + std::vector<Plugin> &plugins) + : WrapperFrontendAction(WrappedAction), plugins(plugins) {} + + virtual bool BeginSourceFileAction(CompilerInstance &CI, + StringRef Filename); + virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, + StringRef InFile); + virtual void EndSourceFileAction(); + + virtual ~PluginWrapperAction(); + }; +} + +bool PluginWrapperAction::BeginSourceFileAction(CompilerInstance &CI, + StringRef Filename) { + if (!WrapperFrontendAction::BeginSourceFileAction(CI, Filename)) + return false; + + CurrentFile = Filename; + for (std::vector<Plugin>::iterator it = plugins.begin(); it != plugins.end(); + ++it) { + // Retrieve the callbacks, and clear all of the values to NULL + clang::plugin::PluginFileCallbacks *callbacks = it->getCallbacks(); + memset(callbacks, 0, sizeof(clang::plugin::PluginFileCallbacks)); + + // Get the callbacks from the plugin + Plugin::BeginFileType beginFunc = (Plugin::BeginFileType)it->getFunctionCall( + "clang_plugin_begin_file"); + if (!beginFunc) + continue; + beginFunc(Filename, callbacks); + + // ASTConsumer is handled by GetASTConsumer; others are handled now + if (callbacks->ppCallback) + CI.getPreprocessor().addPPCallbacks(callbacks->ppCallback); + if (callbacks->diagnostics) + { + // The front end has already run this, so let's do this now. + callbacks->diagnostics->BeginSourceFile(CI.getLangOpts(), + &CI.getPreprocessor()); + CI.getDiagnostics().setClient(new ChainedDiagnosticConsumer( + &CI.getDiagnosticClient(), callbacks->diagnostics)); + } + } + + return true; +} + +ASTConsumer *PluginWrapperAction::CreateASTConsumer(CompilerInstance &CI, + StringRef InFile) { + std::vector<ASTConsumer*> Consumers(1, + WrapperFrontendAction::CreateASTConsumer(CI, InFile)); + for (std::vector<Plugin>::iterator it = plugins.begin(); it != plugins.end(); + ++it) { + if (ASTConsumer *consumer = it->getCallbacks()->astConsumer) { + Consumers.push_back(consumer); + } + } + return new MultiplexConsumer(Consumers); +} + +void PluginWrapperAction::EndSourceFileAction() +{ + WrapperFrontendAction::EndSourceFileAction(); + for (std::vector<Plugin>::iterator it = plugins.begin(); it != plugins.end(); + ++it) { + Plugin::EndFileFnTy EndFileFunc = + (Plugin::EndFileFnTy)it->getFunctionCall("clang_plugin_end_file"); + if (EndFileFunc) + EndFileFunc(CurrentFile); + } +} + +PluginWrapperAction::~PluginWrapperAction() { + for (std::vector<Plugin>::iterator it = plugins.begin(); it != plugins.end(); + ++it) { + Plugin::DestroyTy destroyFunc = (Plugin::DestroyTy) + it->getFunctionCall("clang_plugin_destroy"); + if (destroyFunc) + destroyFunc(); + } +} + static FrontendAction *CreateFrontendBaseAction(CompilerInstance &CI) { using namespace clang::frontend; switch (CI.getFrontendOpts().ProgramAction) { case ASTDump: return new ASTDumpAction(); case ASTDumpXML: return new ASTDumpXMLAction(); case ASTPrint: return new ASTPrintAction(); case ASTView: return new ASTViewAction(); @@ -141,16 +249,68 @@ bool clang::ExecuteCompilerInvocation(Co e = Clang->getFrontendOpts().Plugins.size(); i != e; ++i) { const std::string &Path = Clang->getFrontendOpts().Plugins[i]; std::string Error; if (llvm::sys::DynamicLibrary::LoadLibraryPermanently(Path.c_str(), &Error)) Clang->getDiagnostics().Report(diag::err_fe_unable_to_load_plugin) << Path << Error; } + std::vector<Plugin> plugins; + for (unsigned i = 0, + e = Clang->getFrontendOpts().CompilerPlugins.size(); i != e; ++i) { + const std::string &Path = Clang->getFrontendOpts().CompilerPlugins[i]; + + // Try loading the library + std::string Error; + llvm::sys::DynamicLibrary plugin = + llvm::sys::DynamicLibrary::getPermanentLibrary(Path.c_str(), &Error); + if (!plugin.isValid()) { + Clang->getDiagnostics().Report(diag::err_fe_unable_to_load_plugin) + << Path << Error; + continue; + } + + // If the library has been loaded, it's time to run plugin_init. + // Construct the version + clang::plugin::Version pluginVersion = { + CLANG_VERSION_MAJOR, + CLANG_VERSION_MINOR, +#ifdef CLANG_VERSION_PATCHLEVEL + CLANG_VERSION_PATCHLEVEL +#else + 0 +#endif + }; + + // Construct the arguments + std::vector<std::pair<std::string, std::string> > &pluginArgs = + Clang->getFrontendOpts().CompilerPluginArgs[i]; + plugin::PluginArg *args = new plugin::PluginArg[pluginArgs.size()]; + for (unsigned i = 0; i < pluginArgs.size(); i++) { + args[i].name = pluginArgs[i].first.c_str(); + args[i].value = pluginArgs[i].second.c_str(); + } + typedef bool (*init_func)(int argc, clang::plugin::PluginArg *argv, + clang::plugin::Version *version); + init_func plugin_init = (init_func)(intptr_t) + plugin.getAddressOfSymbol("clang_plugin_init"); + if (!plugin_init) { + Clang->getDiagnostics().Report(diag::err_fe_unable_to_load_plugin) + << Path << "Could not find clang_plugin_init"; + } else if (!plugin_init(pluginArgs.size(), args, &pluginVersion)) { + Clang->getDiagnostics().Report(diag::err_fe_unable_to_load_plugin) + << Path << "Plugin initialization failed"; + } else { + plugins.push_back(Plugin(plugin)); + } + + delete [] args; + } + // Honor -mllvm. // // FIXME: Remove this, one day. // This should happen AFTER plugins have been loaded! if (!Clang->getFrontendOpts().LLVMArgs.empty()) { unsigned NumArgs = Clang->getFrontendOpts().LLVMArgs.size(); const char **Args = new const char*[NumArgs + 2]; Args[0] = "clang (LLVM option parsing)"; @@ -166,17 +326,18 @@ bool clang::ExecuteCompilerInvocation(Co ento::printCheckerHelp(llvm::outs(), Clang->getFrontendOpts().Plugins); return 0; } // If there were errors in processing arguments, don't do anything else. bool Success = false; if (!Clang->getDiagnostics().hasErrorOccurred()) { // Create and execute the frontend action. - OwningPtr<FrontendAction> Act(CreateFrontendAction(*Clang)); + OwningPtr<FrontendAction> Act( + new PluginWrapperAction(CreateFrontendAction(*Clang), plugins)); if (Act) { Success = Clang->ExecuteAction(*Act); if (Clang->getFrontendOpts().DisableFree) Act.take(); } } return Success; _______________________________________________ cfe-commits mailing list [email protected] http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
