D語言 用D語言編寫Ruby擴充套件

2021-08-29 04:22:08 字數 3803 閱讀 2669

ruby語言的官方解釋程式是使用c語言開發的,一般用c語言來編寫擴充套件。d語言和c語言是二進位制相容的,所以可以使用d語言編寫ruby擴充套件。

一、移植c庫到d的一般過程

c使用標頭檔案來處理符號依賴,在d裡面鏈結外部庫檔案時,要使用extern (c)宣告來引入符號,這是乙個轉換過程。

如何轉換乙個c標頭檔案到d檔案?d文件的htomodule.html有詳盡說明。一般的轉換過程如下:

1、執行預處理程式處理掉頭檔案裡面的巨集。

2、刪除經過預處理以後的多餘資訊。由於c的標頭檔案包含,每個標頭檔案經過預處理以後都會包含一些重複內容,我們需要剔除這部分內容,通過查詢行號即可完成。

3、轉換相應宣告到d宣告,這一步可以使用乙個c2h程式來完成。

注意預處理程式處理完畢以後,巨集函式以及巨集定義的常量會被去除,這可能不是你想要的,所以最好的辦法可能是手工轉換。

另一種呼叫是在d裡面呼叫動態鏈結庫,這需要你使用implib工具從動態鏈結庫產生乙個.lib導入庫檔案,然後生成d宣告,再編譯鏈結即可。如果是在linux下使用共享庫,則只需要編寫d宣告檔案,然後直接鏈結即可。

二、呼叫c庫

轉換完畢以後,就可以呼叫了。如果你只是要測試一下,就可以只宣告使用過的外部函式、變數即可。

例如我們要編寫programming ruby裡面的乙個ruby extension例子,相應的d**如下:

module test;

import ruby;

extern

(c)value t_init(value self)

extern

(c)value t_add(value self, value anobject)

extern

(c)}  

//extern(c)

和c**很相似。由於我們只使用了幾個外部函式、變數,所以只需要宣告這幾個符號即可:

module ruby;

extern

(c)

三、生成動態鏈結庫(windows dll)或共享庫(linux so檔案)

d語言在windows上編寫dll,除了要有d原始檔以外,還要有dll定義檔案:

eflibrary         test

description     

'test written in d

'exetype  nt

code            preload discardable

data            preload single

這是乙個通用的格式,只是一些描述資訊,因為d中可以使用export關鍵字匯出符號,所以不需要在這裡宣告匯出函式,只有在編寫com dll時才會增加其它一些資訊。

另外由於d語言要初始化gc以及其它一些資訊,所以還需要在dllmain裡面呼叫初始化及終止**。由於不同平台的初始化過程不完全相同,這裡我簡單封閉了一下不同平台的初始化**:

//os/library.d

module os.library;

extern

(c)extern

(c)void

d_init()

extern

(c)void

d_fini()

現在可以為windows編寫初始化及終止**:

//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)

g_hinst

=hinstance;

return

true;}

由於linux共享庫並沒有標準的入口函式(或是我不知道它),這裡使用gcc擴充套件的初始、終止**,不過是以c語言實現的:

//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

)void

so_fini(

void)

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下測試:

require 

'test

'test 

=test.

newtest.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格式的導入庫檔案。

四、專案打算

打算建立乙個rubyd專案,除了轉換ruby標頭檔案以外,還要作一些擴充套件,比如轉換d類到ruby類,這方面已有借鑑,比如dsource.org上的pyd專案。

由於以前在建立專案方面有過失敗經歷(asgard專案由於興趣轉移和其它原因比如語法醜陋等而未能進行),這次還是保守一些,先完成d宣告的轉換,我已經使用工具轉換了所有標頭檔案,不過正如前面所說,巨集函式和巨集常量都丟失了,所以需要重新手工轉換。

五、其它問題

1、如何從.dll檔案匯出乙個gdc支援的elf格式的導入庫檔案?如果你知道可以告訴我,先謝過了。

2、dmd生成可執行檔案問題不大,生成動態鏈結庫或共享庫有很大缺陷,特別是不能生成共享庫,我可不想再找乙個只能再windows上正常執行的編譯器。如何讓它改進這些方面?

3、gdc使用dmd前端和gcc後端,應該會成熟一些,不過一般會比dmd前端版本稍低,而且gdc發布版本不是很頻繁,大概4-5個dmd版本才會有乙個gdc版本(初略計算),所以一些新特性不能夠及時加入進來。

D 語言編寫CGI程式

編寫main.d,內容如下 import arsd.cgi void yourfunction cgi cgi mixin genericmain yourfunction 用命令編譯程式,得到可執行程式main dmd main.d cgi.d 直接執行main,可以看到輸出的是http響應。ca...

1 verilog語言編寫D觸發器

2.1.1本節目錄 1 本節目錄 2 fpga簡介 3 verilog簡介 4 verilog語言編寫d觸發器 5 本節結束。fpga field programmable gate array 是在pal gal等可程式設計器件的基礎上進一步發展的產物。它是作為專用積體電路 asic 領域中的一種...

用D語言解面試題6

看了 效率是窮舉法的1000倍以上。有乙個整數n,寫乙個函式f n 返回0到n之間出現的 1 的個數。比如f 13 6,現在f 1 1,問下乙個最大的f n n的n是什麼?module fn import std.stdio import std.math import std.datetime i...