Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> Ruby

Hướng dẫn từng bước: Xây dựng C Extension cho Ruby để tăng hiệu suất & tích hợp

Viết C extension cho phép bạn tương tác với Ruby từ C.

Bạn có thể muốn làm điều này nếu có một phương thức quan trọng cụ thể bạn muốn tối ưu hóa bằng tốc độ của C, hoặc nếu bạn muốn tạo giao diện giữa thư viện C và Ruby.

Một giải pháp thay thế là dùng module FFI.

Bây giờ:

Hãy khám phá cách viết C extension!

C Extension đầu tiên của bạn

Tạo file tên extconf.rb với nội dung sau:

require 'mkmf'
create_header
create_makefile 'foobar'

Sau đó chạy ruby extconf.rb sẽ tạo một vài file cho bạn (Makefile & extconf.h). Đừng thay đổi các file này.

Bây giờ tạo foobar.c, tên này đến từ dòng create_makefile trong extconf.rb. Bạn có thể thay đổi nó nếu muốn nhưng nó phải khớp với tên file .c của bạn để hoạt động.

Bên trong foobar.c bạn thêm điều này:

#include "ruby.h"
#include "extconf.h"
void Init_foobar() {
  // Mã C của bạn ở đây
}

Đây là khung xương cơ bản của C extension. Lưu ý bạn phải dùng tên bạn khai báo trên extconf.rb cộng với từ Init_. Trong trường hợp này Init_foobar.

Bạn có thể compile bằng cách chạy make, và bạn nhận được file so mà bạn có thể load vào ứng dụng Ruby dùng require.

Viết một phương thức Ruby từ C

Bạn có thể tạo hàm C mà bạn có thể gọi từ mã Ruby. Cách các class & phương thức built-in hoạt động.

Tất cả phương thức Ruby phải trả về VALUE. Một VALUE là một đối tượng Ruby.

Ví dụ:

VALUE rb_return_nil() {
  return Qnil;
}

Bây giờ chúng ta cần gắn hàm này vào một class hoặc module Ruby. Bạn có thể tạo class mới hoặc dùng class hiện có.

Ở đây tôi tạo một module:

void Init_foobar() {
  VALUE mod = rb_define_module("RubyGuides");
  rb_define_method(mod, "return_nil", rb_return_nil, 0);
}

Bạn có thể dùng phương thức rb_define_method để gắn hàm C vào module này.

Các tham số là:

Tham số Mô tả
mod Đối tượng Module
“print_hello” Tên phương thức Ruby
rb_print_hello Tên hàm C
0 Số lượng đối số phương thức này nhận, dùng -1 cho đối số biến đổi

Bây giờ chạy make lại để compile extension, và thử như sau:

require 'foobar'
include RubyGuides
print_hello

Xong, bạn vừa gọi hàm C từ Ruby!

Tạo Ruby Hash từ C

Thường xuyên bạn sẽ muốn tạo & thao tác đối tượng Ruby từ C.

Bạn có thể làm điều đó dùng C API.

Ví dụ, để tạo hash & thêm phần tử:

VALUE create_hash() {
  hash = rb_hash_new();
  rb_hash_aset(hash, rb_str_new2("test"), INT2FIX(1));
  return hash;
}

Hai điều quan trọng cần chú ý ở đây, trước tiên hàm rb_str_new2, nó tạo chuỗi Ruby.

Sau đó macro INT2FIX, chuyển đổi số nguyên thông thường thành số nguyên Ruby.

Bây giờ nếu bạn expose hàm này cho Ruby dùng rb_define_method bạn sẽ nhận được hash Ruby thông thường với một key (test) & giá trị 1.

Đừng quên recompile extension mỗi khi bạn thay đổi 🙂

Làm việc với Chuỗi (Strings)

Hàm C của bạn cũng có thể nhận tham số.

Ví dụ:

VALUE rb_print_length(VALUE self, VALUE str) {
  if (RB_TYPE_P(str, T_STRING) == 1) {
    return rb_sprintf("String length: %ld", RSTRING_LEN(str));
  }
  return Qnil;
}
void Init_foobar() {
  rb_define_global_function("print_length", rb_print_length, 1);
}

Ở đây chúng ta nhận một VALUE (đối tượng Ruby) làm tham số & đảm bảo nó là chuỗi với macro RB_TYPE_P. Sau đó, chúng ta chỉ in độ dài chuỗi dùng macro RSTRING_LEN.

Nếu bạn muốn con trỏ đến dữ liệu chuỗi bạn có thể dùng macro RSTRING_PTR.

Ví dụ:

VALUE rb_print_data(VALUE self, VALUE str) {
  if (RB_TYPE_P(str, T_STRING) == 1) {
    return rb_sprintf("String length: %s", RSTRING_LEN(str));
  }
  return Qnil;
}

Cũng lưu ý cách có tham số khác ở đây, self, đây là đối tượng nhận lời gọi phương thức.

Nếu bạn muốn định nghĩa phương thức này trên chính class String bạn làm như sau:

void Init_foobar() {
  rb_define_method(rb_cString, "print_length", rb_print_length, 0);
}

Tóm tắt

Bạn đã học cách viết C extension cho Ruby để truy cập toàn bộ sức mạnh của C từ chương trình Ruby. Bạn cũng học cách expose hàm C vào Ruby & cách làm việc với đối tượng Ruby từ C, như chuỗi & hash.

Nếu bạn cần thêm hàm để tương tác với Ruby từ C bạn có thể phải tìm chúng trong mã nguồn Ruby & đọc mã C extension vì điều này không được tài liệu hóa tốt.

Hy vọng bạn thấy bài viết này hữu ích & thú vị! Nếu bạn thấy vậy hãy chia sẻ với bạn bè để họ cũng tận hưởng.