Ruby 最酷的功能之一就是使用 C/C++ 定義的應用程序編程接口 (API) 擴展它。Ruby 提供了 C 頭文件 ruby.h,它隨附提供了許多功能,可使用這些功能創建 Ruby 類、模塊和更多內容。除了頭文件,Ruby 還提供了其他幾個高層抽象來擴展基于本地 ruby.h 構建的 Ruby,本文要介紹的是 Ruby Interface for C++ Extensions 或 Rice。
創建 Ruby 擴展
在進行任何 Ruby 的 C API 或 Rice 擴展前,我想明確地介紹一下創建擴展的標準過程:
您具有一個或多個 C/C++ 源代碼,可使用它們構建共享庫。 如果您使用 Rice 創建擴展,則需要將代碼鏈接到 libruby.a 和 librice.a。 將共享庫復制到同一文件夾,并將該文件夾作為 RUBYLIB 環境變量的一部分。 在 Interactive Ruby (irb) prompt/ruby 腳本中使用常見的基于 require 的加載。如果共享庫名為 rubytest.so,只需鍵入 require 'rubytest' 即可加載共享庫。假設頭文件 ruby.h 位于 /usr/lib/ruby/1.8/include 中,Rice 頭文件位于 /usr/local/include/rice/include 中,并且擴展代碼位于文件 rubytest.cpp 中。 清單 1 顯示了如何編譯和加載代碼。
清單 1. 編譯和加載 Ruby 擴展
bash# g++ -c rubytest.cpp –g –Wall -I/usr/lib/ruby/1.8/include / -I/usr/local/include/rice/includebash# g++ -shared –o rubytest.so rubytest.o -L/usr/lib/ruby/1.8/lib / -L/usr/local/lib/rice/lib -lruby –lrice –ldl -lpthreadbash# cp rubytest.so /opt/testbash# export RUBYLIB=$RUBYLIB:/opt/testbash# irbirb> require 'rubytest'=> true
Hello World 程序
現在,您已經準備好使用 Rice 創建自己的首個 Hello World 程序。您使用名為 Test 的 Rice API 和名為 hello 的方法創建了一個類,用它來顯示字符串 "Hello, World!"。當 Ruby 解釋器加載擴展時,會調用函數 Init_<shared library name>。對于 清單 1 的 rubytest 擴展,此調用意味著 rubytest.cpp 已定義了函數 Init_rubytest。Rice 支持您使用 API define_class 創建自己的類。清單 2 顯示了相關代碼。
清單 2. 使用 Rice API 創建類
#include "rice/Class.hpp"extern "C"void Init_rubytest( ) { Class tmp_ = define_class("Test");}
當您在 irb 中編譯和加載清單 2 的代碼時,應得到 清單 3 所示的輸出。
清單 3. 測試使用 Rice 創建的類
irb> require ‘rubytest'=> trueirb> a = Test.new=> #<Test:0x1084a3928>irb> a.methods=> ["inspect", "tap", "clone", "public_methods", "__send__", "instance_variable_defined?", "equal?", "freeze", …]
注意,有幾個預定義的類方法可供使用,比如 inspect。出現這種情況是因為,定義的 Test 類隱式地衍生自 Object 類(每個 Ruby 類都衍生自 Object;實際上,Ruby 中的所有內容(包括數字)都是基類為 Object 的對象)。
新聞熱點
疑難解答