수색…


첫 번째 확장 프로그램

C 확장은 두 가지 일반적인 부분으로 구성됩니다.

  1. C 코드 자체.
  2. 확장 구성 파일.

첫 번째 확장을 시작하려면 extconf.rb 파일에 다음을 입력하십시오.

require 'mkmf'

create_makefile('hello_c')

몇 가지 지적해야 할 점은 다음과 같습니다.

첫째, hello_c 라는 이름은 컴파일 된 확장의 출력 이름입니다. 그것은 당신이 require 와 함께 사용 require 입니다.

둘째, extconf.rb 파일의 이름을 실제로 지정할 수 있습니다.이 파일은 원래 고유 코드를 가진 보석을 만드는 데 사용되는 것으로 전통적으로 확장자를 실제로 컴파일하는 파일은 ruby extconf.rb 실행할 때 생성되는 Makefile입니다. 생성 된 기본 Makefile은 현재 디렉토리의 모든 .c 파일을 컴파일합니다.

다음을 hello.c 라는 파일에 ruby extconf.rb && make 실행하십시오.

#include <stdio.h>
#include "ruby.h"

VALUE world(VALUE self) {
  printf("Hello World!\n");
  return Qnil;
}

// The initialization method for this module
void Init_hello_c() {
  VALUE HelloC = rb_define_module("HelloC");
  rb_define_singleton_method(HelloC, "world", world, 0);
}

코드 분석 :

Init_hello_c 라는 이름은 extconf.rb 파일에 정의 된 이름과 일치해야합니다. 그렇지 않으면 확장을 동적으로로드 할 때 Ruby가 확장을 부트 스트랩하기 위해 심볼을 찾을 수 없습니다.

rb_define_module 대한 호출은 HelloC 라는 루비 모듈을 생성하는데,이 모듈은 우리의 C 함수의 이름 공간을 만듭니다.

마지막으로, 호출 rb_define_singleton_method 받는 직접 연결 모듈 수준의 방법을 만드는 HelloC 우리가 루비에서 호출 할 수있는 모듈 HelloC.world .

make 호출하여 확장을 컴파일 한 후 C 확장자로 코드를 실행할 수 있습니다.

콘솔을 켜십시오!

irb(main):001:0> require './hello_c'
=> true
irb(main):002:0> HelloC.world
Hello World!
=> nil

C 구조체로 작업하기

C 구조체를 Ruby 객체로 사용할 수 있으려면 Data_Wrap_StructData_Get_Struct 를 호출하여 C 구조체를 래핑해야합니다.

Data_Wrap_Struct 는 C 데이터 구조를 Ruby 객체로 래핑합니다. 콜백 함수에 대한 몇 가지 포인터와 함께 데이터 구조에 대한 포인터를 취해 VALUE를 반환합니다. Data_Get_Struct 매크로는 그 값을 취하여 C 데이터 구조에 대한 포인터를 돌려줍니다.

다음은 간단한 예입니다.

#include <stdio.h>
#include <ruby.h>

typedef struct example_struct {
  char *name;
} example_struct;

void example_struct_free(example_struct * self) {
  if (self->name != NULL) {
    free(self->name);
  }
  ruby_xfree(self);
}

static VALUE rb_example_struct_alloc(VALUE klass) {
  return Data_Wrap_Struct(klass, NULL, example_struct_free, ruby_xmalloc(sizeof(example_struct)));
}

static VALUE rb_example_struct_init(VALUE self, VALUE name) {
  example_struct* p;

  Check_Type(name, T_STRING);

  Data_Get_Struct(self, example_struct, p);
  p->name = (char *)malloc(RSTRING_LEN(name) + 1);
  memcpy(p->name, StringValuePtr(name), RSTRING_LEN(name) + 1);

  return self;
}

static VALUE rb_example_struct_name(VALUE self) {
  example_struct* p;
  Data_Get_Struct(self, example_struct, p);

  printf("%s\n", p->name);

  return Qnil;
}

void Init_example()
{
  VALUE mExample = rb_define_module("Example");
  VALUE cStruct = rb_define_class_under(mExample, "Struct", rb_cObject);

  rb_define_alloc_func(cStruct, rb_example_struct_alloc);
  rb_define_method(cStruct, "initialize", rb_example_struct_init, 1);
  rb_define_method(cStruct, "name", rb_example_struct_name, 0);
}

그리고 extconf.rb :

require 'mkmf'

create_makefile('example')

확장 프로그램을 컴파일 한 후 :

irb(main):001:0> require './example'
=> true
irb(main):002:0> test_struct = Example::Struct.new("Test Struct")
=> #<Example::Struct:0x007fc741965068>
irb(main):003:0> test_struct.name
Test Struct
=> nil

인라인 C 작성 - RubyInLine

RubyInline은 Ruby 코드 안에 다른 언어를 포함시킬 수있는 프레임 워크입니다. 빌더 객체를 반환하는 Module # inline 메소드를 정의합니다. 빌더에 Ruby 이외의 다른 언어로 작성된 코드가 포함 된 문자열을 전달하면 빌더는이를 빌더가 Ruby에서 호출 할 수있는 것으로 변환합니다.

C 또는 C ++ 코드 (기본 RubyInline 설치에서 지원되는 두 언어)에서 빌더 객체는 작은 확장자를 디스크에 쓰고 컴파일 한 다음로드합니다. 컴파일을 직접 처리 할 필요는 없지만 홈 디렉토리의 .ruby_inline 서브 디렉토리에서 생성 된 코드와 컴파일 된 확장을 볼 수 있습니다.

Ruby 프로그램에 C 코드를 삽입하십시오.

  • RubyInline ( 루비 읶 젬으로 사용 가능)이 자동으로 확장 기능을 생성합니다.

RubyInline은 irb 내에서 작동하지 않습니다.

#!/usr/bin/ruby -w
    # copy.rb
    require 'rubygems'
    require 'inline'

    class Copier
    inline do |builder|
      builder.c <<END
    void copy_file(const char *source, const char *dest)
    {
      FILE *source_f = fopen(source, "r");
      if (!source_f)
      {
        rb_raise(rb_eIOError, "Could not open source : '%s'", source);
      }

      FILE *dest_f = fopen(dest, "w+");
      if (!dest_f)
      {
        rb_raise(rb_eIOError, "Could not open destination : '%s'", dest);
      }

      char buffer[1024];

      int nread = fread(buffer, 1, 1024, source_f);
      while (nread > 0)
      {
        fwrite(buffer, 1, nread, dest_f);
        nread = fread(buffer, 1, 1024, source_f);
      }
    }
    END
     end
    end

C 함수 copy_file 이제 Copier 의 인스턴스 메소드로 존재합니다.

open('source.txt', 'w') { |f| f << 'Some text.' }
Copier.new.copy_file('source.txt', 'dest.txt')
puts open('dest.txt') { |f| f.read }


Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow