[心得] 用 Go 撰寫 Ruby gem消失

看板Ruby作者時間8年前 (2016/10/24 09:57), 8年前編輯推噓2(202)
留言4則, 3人參與, 最新討論串1/1
最近版工在把玩 Golang 這個新玩具 後來發現到可以用 Golang 寫 Ruby gem,就上來分享一下 這個功能可以實現,主要有兩點: 1. Go 在 1.5 版後可以輸出給 C/C++ 使用的 shared library 2. Ruby 可透過 FFI 模組讀取 shared library 其他的就是一些實作時的細節,請見下文。 首先,我們寫一個簡單的 Go 程式: package main import "C" //export DoubleIt func DoubleIt(x int) int { return x * 2 } func main() {} 然後,將其編譯成 shared library: $ go build -o libdoubler.so -buildmode=c-shared 會得到 libdoubler.h 和 libdoubler.so 這兩個檔案,可以後續給 C/C++ 使用 如果要給 Ruby 使用,需要用 FFI 這個模組讀取 shared library,以下是範例: require 'ffi' module Lib extend FFI::Library ffi_lib 'c' ffi_lib './libdoubler.so' attach_function :DoubleIt, [:int], :int end puts Lib.DoubleIt(2) 接下來,我們要把這個過程寫成 gem。 我們這裡僅描述重點,其他的細節請自行參考這裡: https://github.com/cwchentw/doubler 傳統的 Ruby extension gem,使用 C/C++ 或 Java,較少使用 Golang 所以,我們要自行撰寫 extconf.rb,以便 gem 自動編譯 shared library 以下是例子: require 'mkmf' # For find_executable method # You should check 1) Go environment exists and 2) Go version >= 1.5 # Check whether go command exists here if find_executable('go').nil? then abort <<NO_GO No Go environment installed NO_GO end # Implement code to check Go version # We didn't check the version of Go here. # In a formal gem, you should check that. # Finally, call related go command to build shared library system "go build -o libdoubler.so -buildmode=c-shared main.go" 本來,mkmf 模組為會我們製作 Makefile 然而,這個功能是給 C/C++ 用的,我們用不到 在這裡,我們做一個沒功能的 Makefile,以騙過 gem all: true install: true 最後,撰寫相關的 gemspec 即可 Gem::Specification.new do |s| s.name = "doubler" s.version = "0.1.0" s.licenses = ["MIT"] s.summary = "A Demo Ruby Gem with Golang" s.author = "Michael Chen" s.email = "somebody@example.com" s.extensions = %w[ext/doubler/extconf.rb] files = Dir.glob("ext/**/*") + Dir.glob("lib/**/*.rb") s.files = files s.homepage = "https://github.com/cwchentw/doubler" end 經實測,Golang 輸出的函數,可以處理基本的數據,像是 int, float, string 等 但是,對於 array, map, struct 等進階的資料類型則無法有效傳遞 以目前來說,大概就是把少數複雜的運算步驟,轉給 Go 程式去運算 如果要在 C/C++ 層級處理複雜的資料類型和運算 一個就是回歸 Ruby C API,但是這樣就享受不到寫 Golang 的便利 一個就是將資料轉為 JSON 字串,在 Golang 和 Ruby 間傳遞 但是,這樣效率可能不好,有興趣的朋友可自行嘗試 分享給有需要的 Rubyist -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 211.72.12.139 ※ 文章網址: https://www.ptt.cc/bbs/Ruby/M.1477274255.A.16C.html ※ 編輯: Neisseria (211.72.12.139), 10/24/2016 09:58:39 ※ 編輯: Neisseria (211.72.12.139), 10/24/2016 09:59:56

10/24 12:34, , 1F
感謝分享
10/24 12:34, 1F

10/24 14:57, , 2F
詳細推
10/24 14:57, 2F

11/05 07:06, , 3F
其實你也可以 prebuild 各 ARCH 的直接塞到 gem 裡面
11/05 07:06, 3F

11/05 07:07, , 4F
再判斷平台 load 對應的 .so 就好,這樣安裝者就不用裝 go
11/05 07:07, 4F
的確是這樣沒錯,感謝提醒 ※ 編輯: Neisseria (59.115.76.160), 11/05/2016 09:50:44
文章代碼(AID): #1O3MgF5i (Ruby)
文章代碼(AID): #1O3MgF5i (Ruby)