Code::Blocks中Plugin的实现原理

Generic-plugin转载另一篇不错的代码分析文章,首先Bryan@cbforge(cbforge at gmail dot com)通过阅读CB源代码针对插件的实现有如下一些补充:

1)CB在系统初始化时,在InitFrame时调用MainFrame::ScanForPlugins来调用PluginManager的接口函数实现插件初始化;

2)除了本例中的binary ,CB还支持 ,这是一个轻量级的插件功能,通过来支持;

3) compiler/debugger 实现了对其他编译器、调试器的统一接口;

以下是转载内容:

 

快乐虾 http://blog.csdn.net/lights_joy/    lights@hb165.com

本文适用于 codeblocks-8.02 欢迎转载,但请保留作者信息

1.1    加载
Codeblocks将放在可执行文件目录下的share\CodeBlocks\plugins子目录中,全部以的形式存在。在codeblock启动时会调用如下函数:

int PluginManager::ScanForPlugins(const wxString& path)

{

…………………………………..

    wxDir dir(path);

    wxString filename;

    wxString failed;

    bool ok = dir.GetFirst(&filename, PluginsMask, wxDIR_FILES);

    while (ok)

    {

…………………….

        // load manifest

        m_pCurrentlyLoadingManifestDoc = 0;

        if (ReadManifestFile(filename))

        {

            if (LoadPlugin(path + _T(’/') + filename))

                ++count;

            else

                failed << _T(’\n’) << filename;

        }

        delete m_pCurrentlyLoadingManifestDoc;

        m_pCurrentlyLoadingManifestDoc = 0;

        ok = dir.GetNext(&filename);

}

…………………………………..

}

在上述代码中,将首先读取与同名的manifest,其实它就是一个放在share/codeblocks子目录下的同名zip文件,这个zip文件中两个文件:manifest.xml和configuration.xrc,其实这两个文件都是XML文档,manifest.xml描述了这个插件的功能,作者等信息,而另一个文件则是一些配置信息。

在读取manifest成功后将调用LoadPlugin函数:

bool PluginManager::LoadPlugin(const wxString& pluginName)

{

    // clear registration temporary vector

    m_RegisteredPlugins.clear();

    // load library

    m_CurrentlyLoadingFilename = pluginName;

    m_pCurrentlyLoadingLib = LibLoader::LoadLibrary(pluginName);

    if (!m_pCurrentlyLoadingLib->IsLoaded())

    {

        Manager::Get()->GetLogManager()->LogError(F(_T("%s: not loaded (missing symbols?)"), pluginName.c_str()));

        LibLoader::RemoveLibrary(m_pCurrentlyLoadingLib);

        m_pCurrentlyLoadingLib = 0;

        m_CurrentlyLoadingFilename.Clear();

        return false;

    }

    // by now, the library has loaded and its global variables are initialized.

    // this means it has already called RegisterPlugin()

    // now we can actually create the (s) instance(s) :)

    // try to load the (s)

    std::vector<PluginRegistration>::iterator it;

    for (it = m_RegisteredPlugins.begin(); it != m_RegisteredPlugins.end(); ++it)

    {

        PluginRegistration& pr = *it;

        cbPlugin* plug = 0L;

        try

        {

            plug = pr.createProc();

        }

        catch (cbException& exception)

        {

            exception.ShowErrorMessage(false);

            continue;

        }

        // all done; add it to our list

        PluginElement* plugElem = new PluginElement;

        plugElem->fileName = m_CurrentlyLoadingFilename;

        plugElem->info = pr.info;

        plugElem->library = m_pCurrentlyLoadingLib;

        plugElem->freeProc = pr.freeProc;

        plugElem-> = plug;

        m_Plugins.Add(plugElem);

        SetupLocaleDomain(pr.name);

        Manager::Get()->GetLogManager()->DebugLog(F(_T("%s: loaded"), pr.name.c_str()));

    }

    if (m_RegisteredPlugins.empty())

    {

        // no plugins loaded from this library, but it’s not an error

        LibLoader::RemoveLibrary(m_pCurrentlyLoadingLib);

    }

    m_pCurrentlyLoadingLib = 0;

    m_CurrentlyLoadingFilename.Clear();

    return true;

}

这个函数首先调用LibLoader::LoadLibrary加载,实际上它就是使用LoadLibrary这个API来加载

在加载完成后,按照注释的说明,这个中应该调用RegisterPlugin函数进行自我注册,这其中当然包括创建实例这样回调函数,然后上述函数很自然地使用这样的回调函数创建的实例。然后用一个PluginElement来描述它,这个plugElem将用于主界面的菜单等位置。

从上述代码还可以看出,插件至少应该能创建一个cbPlugin的实例。

1.2    插件注册
从调用过程的注释可以知道,在加载时,它应该能够调用RegisterPlugin向codeblock进行注册,下面以astyle这个插件为例看看它的注册过程。

在这个插件中定义了一个全局变量:

namespace

{

    PluginRegistrant<> reg(_T(""));

}

除此之外没有其它东西可以在加载时执行代码,看看PluginRegistrant这个类:

/** @brief registration object.

  *

  * Use this class to register your new with Code::Blocks.

  * All you have to do is instantiate a PluginRegistrant object.

  * @par

  * Example code to use in one of your ’s source files (supposedly called "MyPlugin"):

  * @code

  * namespace

  * {

  *     PluginRegistrant<MyPlugin> registration("MyPlugin");

  * }

  * @endcode

  */

template<class T> class PluginRegistrant

{

    public:

        /// @param name The ’s name.

        PluginRegistrant(const wxString& name)

        {

            Manager::Get()->GetPluginManager()->RegisterPlugin(name, // ’s name

                                                                &CreatePlugin, // creation

                                                                &FreePlugin, // destruction

                                                                &SDKVersion); // SDK version

        }

        static cbPlugin* CreatePlugin()

        {

            return new T;

        }

        static void FreePlugin(cbPlugin* )

        {

            delete ;

        }

        static void SDKVersion(int* major, int* minor, int* release)

        {

            if (major) *major = PLUGIN_SDK_VERSION_MAJOR;

            if (minor) *minor = PLUGIN_SDK_VERSION_MINOR;

            if (release) *release = PLUGIN_SDK_VERSION_RELEASE;

        }

};

由此可见,在主程序加载后还将调用PluginRegistrant ::CreatePlugin这个回调函数,而这个回调函数将创建一个的实例。

1.3    功能实现
仍以astyle为例进行分析。Codeblocks将分为几类:

cbCompilerPlugin

cbDebuggerPlugin

cbToolPlugin

cbMimePlugin

cbCodeCompletionPlugin

cbWizardPlugin

astyle要完成代码格式化的功能,因而它选择了cbToolPlugin进行扩展:

class : public cbToolPlugin

{

  public:

    ();

    ~();

    int Configure();

    int GetConfigurationGroup() const { return cgEditor; }

    cbConfigurationPanel* GetConfigurationPanel(wxWindow* parent);

    int Execute();

    void OnAttach(); // fires when the is attached to the application

    void OnRelease(bool appShutDown); // fires when the is released from the application

};

呵呵,看着好像挺简单的。

Share and Enjoy:
  • Print this article!
  • Digg
  • Sphinn
  • del.icio.us
  • Facebook
  • Mixx
  • Google Bookmarks
  • LinkedIn
  • Live
  • MySpace
  • RSS
  • Slashdot
  • Technorati
  • TwitThis

Related posts:

  1. CodeLite Plugin Internal(1) – IPlugin interface
  2. CodeLite Plugin Internal(2)-Load: 插件加载分析
  3. CodeBlocks下SDL编译成功实例
  4. Setting up Code::Blocks to work with SDL - 多媒体编程库
  5. AVL树Source Code
  6. C::B IDE Plugin插件简介
  7. C::B IDE的命令行参数
  8. Debugging with Code::Blocks
  9. wxWidget 类型转换(wxString, wxdatatime)
  10. Singleton模式

1 comment to Code::Blocks中Plugin的实现原理

Leave a Reply

 

 

 

You can use these HTML tags

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

*
To prove you're a person (not a spam script), type the security word shown in the picture. Click on the picture to hear an audio file of the word.
Click to hear an audio file of the anti-spam word

Contact us

Admin: Bryan Wu