D语言中国主页  D语言编辑器SciTE4D   DWin库 D语言官方网站
D语言编译器1.x最新版 OpenSource   Tango   webnews  Wiki

查看完整版本: 用D语言编写Ruby扩展

yidabu 2007-4-28 18:25

用D语言编写Ruby扩展

用D语言编写Ruby扩展知识若不分享 实在没有意义 http://www.d-programming-language-china.org 20070428点击下面网址查看原文:http://www.d-programming-language-china.org        by:        qiezi        from:        http://qiezi.javaeye.com/blog/26632        关键字:        ruby 扩展        Ruby语言的官方解释程序是使用C语言开发的,一般用C语言来编写扩展。D语言和C语言是二进制兼容的,所以可以使用D语言编写Ruby扩展。        一、移植C库到D的一般过程        C使用头文件来处理符号依赖,在D里面链接外部库文件时,要使用extern (C)声明来引入符号,这是一个转换过程。        如何转换一个C头文件到D文件?D文档的htomodule.html有详尽说明。一般的转换过程如下:        1、运行预处理程序处理掉头文件里面的宏。        2、删除经过预处理以后的多余信息。由于C的头文件包含,每个头文件经过预处理以后都会包含一些重复内容,我们需要剔除这部分内容,通过查找行号即可完成。( 本文出处: http://www.d-programming-language-china.org )        3、转换相应声明到D声明,这一步可以使用一个c2h程序来完成。        注意预处理程序处理完毕以后,宏函数以及宏定义的常量会被去除,这可能不是你想要的,所以最好的办法可能是手工转换。        另一种调用是在D里面调用动态链接库,这需要你使用implib工具从动态链接库产生一个.lib导入库文件,然后生成D声明,再编译链接即可。如果是在linux下使用共享库,则只需要编写D声明文件,然后直接链接即可。        二、调用C库        转换完毕以后,就可以调用了。如果你只是要测试一下,就可以只声明使用过的外部函数、变量即可。( 本文出处: http://www.d-programming-language-china.org )        例如我们要编写Programming Ruby里面的一个Ruby Extension例子,相应的D代码如下:        [Copy to clipboard] [ - ]CODE:                                //    test.d                module test;                                import ruby;                                extern (C)                VALUE t_init(VALUE self)                {                    VALUE arr    =    rb_ary_new();                    rb_iv_set(self,    " @arr " , arr);                    return    self;                }                                extern (C)                VALUE t_add(VALUE self, VALUE anObject)                {                    VALUE arr    =    rb_iv_get(self,    " @arr " );                    rb_ary_push(arr, anObject);                    return    arr;                }                                                extern (C){                                VALUE cTest;                                alias VALUE( * func_type)();                                export    void    Init_Test()                {                    cTest    =    rb_define_class( " Test " , rb_cObject);                    rb_define_method(cTest,    " initialize " , cast(func_type) & t_init,    0 );                    rb_define_method(cTest,    " add " , cast(func_type) & t_add,    1 );                }                                }    //    extern(C)                和C代码很相似。由于我们只使用了几个外部函数、变量,所以只需要声明这几个符号即可:        [Copy to clipboard] [ - ]CODE:                                //    ruby.d                module ruby;                                extern    (C){                    alias    ulong    VALUE;                    VALUE rb_cObject;                    VALUE rb_ary_new ();                    VALUE rb_ary_push (VALUE, VALUE);                    VALUE rb_iv_set (VALUE,    char * , VALUE);                    VALUE rb_iv_get (VALUE,    char * );                    VALUE rb_define_class (    char * ,VALUE);                     void    rb_define_method (VALUE,    char * ,VALUE( * )(), int );                }                三、生成动态链接库(Windows DLL)或共享库(Linux so文件)        D语言在Windows上编写DLL,除了要有D源文件以外,还要有DLL定义文件:        [Copy to clipboard] [ - ]CODE:                                //    test.def                LIBRARY    Test                DESCRIPTION    ' Test written in D '                                EXETYPE    NT                CODE    PRELOAD DISCARDABLE                DATA    PRELOAD SINGLE                这是一个通用的格式,只是一些描述信息,因为D中可以使用export关键字导出符号,所以不需要在这里声明导出函数,只有在编写COM DLL时才会增加其它一些信息。( 本文出处: http://www.d-programming-language-china.org )        另外由于D语言要初始化GC以及其它一些信息,所以还需要在DllMain里面调用初始化及终止代码。由于不同平台的初始化过程不完全相同,这里我简单封闭了一下不同平台的初始化代码:( 本文出处: http://www.d-programming-language-china.org )        [Copy to clipboard] [ - ]CODE:                                //    os/library.d                module os.library;                                extern (C){                    void    gc_init();                    void    gc_term();                    version(Windows)    void    _minit();                    void    _moduleCtor();                    void    _moduleDtor();                    void    _moduleUnitTests();                    version(linux)    void    _STI_monitor_staticctor();                    version(linux)    void    _STI_critical_init();                    version(linux)    void    _STD_monitor_staticdtor();                    version(linux)    void    _STD_critical_term();                }                                extern (C)                void    d_init()                {                    //    writefln("Start init D runtime");                    version(linux) _STI_monitor_staticctor();                    version(linux) _STI_critical_init();                    gc_init();                    version(Windows) _minit();                    _moduleCtor();                    _moduleUnitTests();                    //    writefln("init finished");                }                                extern (C)                void    d_fini()                {                    //    writefln("Start term D runtime");                    _moduleDtor();                    gc_term();                    version(linux) _STD_critical_term();                    version(linux) _STD_monitor_staticdtor();                    //    writefln("term finished");                }                现在可以为Windows编写初始化及终止代码:        [Copy to clipboard] [ - ]CODE:                                //    os/dll.d                module os.dll;                                private    import os.library;                private    import std.c.windows.windows;                                HINSTANCE g_hInst;                                extern    (Windows)                BOOL DllMain(HINSTANCE hInstance, ULONG ulReason, LPVOID pvReserved)                {                    switch    (ulReason)                    {                     case    DLL_PROCESS_ATTACH:                        d_init();                        break ;                                     case    DLL_PROCESS_DETACH:                        d_fini();                        break ;                                     case    DLL_THREAD_ATTACH:                     case    DLL_THREAD_DETACH:                        //    Multiple threads not supported yet                        return    false ;                    }                    g_hInst = hInstance;                    return    true ;                }                由于Linux共享库并没有标准的入口函数(或是我不知道它),这里使用gcc扩展的初始、终止代码,不过是以C语言实现的:        [Copy to clipboard] [ - ]CODE:                                //    os/so.c                #include    < ruby.h >                static    void    so_init( void ) __attribute__((constructor));                static    void    so_fini( void ) __attribute__((destructor));                                extern    void    d_init( void );                extern    void    d_fini( void );                                void    so_init( void )                {                    d_init();                }                                void    so_fini( void )                {                    d_fini();                }                现在可以尝试编译链接,在Linux上编译命令如下:        [Copy to clipboard] [ - ]CODE:                                gcc    - o os / so.o    - c os / so.c    - I    / usr / lib / ruby / 1.8 / i686 - linux                gdc    - o Test.so test.d os / so.o ruby.d    - shared    - fPIC    - lruby                你可以在irb下测试:( 本文出处: http://www.d-programming-language-china.org )        require        ' Test '        test        =        Test. new        test.add( 1 )        test.add( 2 )        test.add( " a " )        可以看到add总是返回一个array,与期望结果一致。        使用gdc是因为dmd在linux上无法生成共享库。        在Windows上的编译命令如下:        dmd        - oftest.dll test.d test.def ruby18.lib os / dll.d os / library.d        ruby18.lib是使用implib从msvcrt-ruby18.dll导出的,这个编译过程很顺利,不过不幸的是它运行有一些问题,大概是一些初始值错误,我暂时还没有找到原因。或许也应该尝试一下gdc,不过我不知道如何从.DLL文件导出一个gdc支持的ELF格式的导入库文件。( 本文出处: http://www.d-programming-language-china.org )        四、项目打算        打算建立一个rubyd项目,除了转换ruby头文件以外,还要作一些扩展,比如转换D类到ruby类,这方面已有借鉴,比如dsource.org上的pyd项目。        由于以前在建立项目方面有过失败经历(asgard项目由于兴趣转移和其它原因比如语法丑陋等而未能进行),这次还是保守一些,先完成D声明的转换,我已经使用工具转换了所有头文件,不过正如前面所说,宏函数和宏常量都丢失了,所以需要重新手工转换。        五、其它问题        1、如何从.DLL文件导出一个gdc支持的ELF格式的导入库文件?如果你知道可以告诉我,先谢过了。( 本文出处: http://www.d-programming-language-china.org )        2、dmd生成可执行文件问题不大,生成动态链接库或共享库有很大缺陷,特别是不能生成共享库,我可不想再找一个只能再Windows上正常运行的编译器。如何让它改进这些方面?        3、gdc使用dmd前端和gcc后端,应该会成熟一些,不过一般会比dmd前端版本稍低,而且gdc发布版本不是很频繁,大概4-5个dmd版本才会有一个gdc版本(初略计算),所以一些新特性不能够及时加入进来。        最后更新:2006-11-28 17:56        06:17        |        永久链接        |        浏览 (366)        |        评论 (0)        |        收藏        |        D        |        发布在 D语言 圈子( lastupdate:20070428 最新文章请访问http://www.d-programming-language-china.org )关于一大步成功社区:yidabu提倡在交流中学习,在分享中提高收集感兴趣的知识,写下心得,通过网络与别人一起分享理解一点就实践一步,收获什么就分享什么,成功就是这样一点点一步步累积起来的网络只是一个工具,只有自己身心提高才是实实在在的。d-programming-language-china.org为大家提供一个学习交流各种知识的平台
页: [1]
查看完整版本: 用D语言编写Ruby扩展