Computer >> 컴퓨터 >  >> 프로그램 작성 >> Ruby

Ruby C 확장을 작성하는 방법(단계별)

C 확장을 작성하면 C에서 Ruby와 상호 작용할 수 있습니다.

C의 속도로 최적화하려는 특정 중요한 방법이 있거나 C 라이브러리와 Ruby 간의 인터페이스를 생성하려는 경우 이 작업을 수행할 수 있습니다.

대안은 FFI 모듈을 사용하는 것입니다.

지금 :

C 확장자를 작성하는 방법을 알아봅시다!

첫 번째 C 확장

extconf.rb라는 파일을 만듭니다. 다음 콘텐츠:

require 'mkmf'

create_header
create_makefile 'foobar'

그런 다음 ruby extconf.rb를 실행합니다. 그러면 몇 개의 파일이 생성됩니다(Makefile &extconf.h ). 이 파일을 변경하지 마십시오.

이제 foobar.c를 만듭니다. , 이 이름은 create_makefile에서 가져옵니다. extconf.rb 줄 . 원하는 경우 변경할 수 있지만 .c와 일치해야 합니다. 이 작업을 위한 파일 이름입니다.

foobar.c 내부 당신은 이것을 추가합니다:

#include "ruby.h"
#include "extconf.h"

void Init_foobar()
{
  // Your C code goes here
}

이것은 C 확장의 기본 골격입니다. extconf.rb에 선언한 이름을 사용해야 합니다. 플러스 단어 Init_ . 이 경우 Init_foobar .

make를 실행하여 컴파일할 수 있습니다. , 그리고 당신이 얻는 것은 so require를 사용하여 Ruby 애플리케이션에 로드할 수 있는 파일 .

C에서 루비 메소드 작성

Ruby 코드에서 호출할 수 있는 c 함수를 만들 수 있습니다. 이것이 내장 클래스와 메소드가 작동하는 방식입니다.

모든 Ruby 메서드는 VALUE를 반환해야 합니다. . VALUE Ruby 개체입니다.

:

VALUE rb_return_nil() {
  return Qnil;
}

이제 이 함수를 Ruby 클래스나 모듈에 연결해야 합니다. 새 클래스를 만들거나 기존 클래스를 사용할 수 있습니다.

여기서 모듈을 만들고 있습니다 :

void Init_foobar() {
  VALUE mod = rb_define_module("RubyGuides");

  rb_define_method(mod, "return_nil", rb_return_nil, 0);
}

rb_define_method를 사용할 수 있습니다. 이 모듈에 C 함수를 연결하는 메서드입니다.

인수 :

인수 설명
모드 모듈 개체
"print_hello" 루비 메서드 이름
rb_print_hello C 함수의 이름
0 이 메서드가 사용하는 인수의 수, 가변 인수에 -1 사용

이제 make를 실행하세요. 확장을 다시 컴파일하고 다음과 같이 시도하십시오.

require 'foobar'

include RubyGuides
print_hello

자, 방금 Ruby에서 C 함수를 호출했습니다!

C에서 루비 해시 만들기

종종 C에서 Ruby 객체를 만들고 조작하고 싶을 것입니다.

C API를 사용하여 그렇게 할 수 있습니다.

예를 들어 해시를 만들고 여기에 일부 요소를 추가하려면:

VALUE create_hash() {
  hash = rb_hash_new();

  rb_hash_aset(hash, rb_str_new2("test"), INT2FIX(1));
  return hash;
}

여기서 주목해야 할 두 가지 중요한 사항은 먼저 rb_str_new2입니다. 함수를 사용하면 Ruby 문자열이 생성됩니다.

그런 다음 INT2FIX 매크로, 이것은 일반 정수를 루비 정수로 변환합니다.

이제 rb_define_method를 사용하여 이 함수를 Ruby에 노출하면 하나의 키(test ) 및 1 값 .

변경할 때마다 확장 프로그램을 다시 컴파일하는 것을 잊지 마세요 🙂

문자열 작업

C 함수도 매개변수를 사용할 수 있습니다.

예:

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);
}

여기에서 VALUE를 사용합니다. (ruby 객체)를 인수로 사용하고 RB_TYPE_P가 있는 문자열인지 확인합니다. 매크로. 그런 다음 RSTRING_LEN을 사용하여 문자열 길이를 인쇄합니다. 매크로.

문자열 데이터에 대한 포인터를 원하면 RSTRING_PTR를 사용할 수 있습니다. 매크로.

:

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;
}

또한 self에 또 다른 매개변수가 있음을 확인하세요. , 메소드 호출을 받는 객체입니다.

String 클래스 자체에서 이 메서드를 정의하려면 다음과 같이 하면 됩니다.

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

요약

Ruby 프로그램에서 C의 모든 기능에 액세스할 수 있도록 Ruby용 C 확장을 작성하는 방법을 배웠습니다. 또한 C 함수를 Ruby에 노출하는 방법과 문자열 및 해시와 같은 C의 Ruby 객체로 작업하는 방법도 배웠습니다.

C에서 Ruby와 상호 작용하기 위해 더 많은 기능이 필요한 경우 문서화가 잘 되어 있지 않기 때문에 Ruby의 소스 코드 및 C 확장 코드에서 해당 기능을 찾아야 할 수도 있습니다.

이 기사가 유용하고 흥미로웠기를 바랍니다! 그렇다면 친구들과 공유하여 그들도 즐길 수 있도록 하십시오.