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