サーチ…


あなたの最初の内線番号

C拡張は2つの一般的な部分で構成されます:

  1. Cコードそのもの。
  2. 拡張構成ファイル。

最初の拡張機能を使い始めるには、 extconf.rbというファイルに次のextconf.rb

require 'mkmf'

create_makefile('hello_c')

いくつかのことを指摘しておきます。

最初に、 hello_cという名前は、コンパイルされた拡張の出力に名前をhello_cものです。それはあなたがrequireと関連して使用するものになります。

次に、 extconf.rbファイルは実際に何かに名前をextconf.rbことができます。これは伝統的にネイティブコードを持つ宝石を作るために使われています。実際には拡張子をコンパイルするファイルはruby extconf.rb実行するときに生成されるMakefile ruby extconf.rb 。生成されるデフォルトの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ファイルで定義されている名前と一致していなければなりません。そうしないと、拡張機能を動的にロードすると、拡張機能を起動するためのシンボルが見つかりません。

rb_define_moduleへの呼び出しはrb_define_moduleという名前のRubyモジュールを作成しています。 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_Structようにするには、 Data_Wrap_StructData_Get_Struct呼び出しでそれらをラップする必要があります。

Data_Wrap_Struct 、Cのデータ構造をRubyオブジェクトにラップします。コールバック関数へのポインタとともに、データ構造体へのポインタをとり、VALUEを返します。 Data_Get_StructマクロはそのVALUEを受け取り、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以外の言語で書かれたコードを含む文字列をBuilderに渡し、Rubyから呼び出せるものにBuilderを変換します。

CまたはC ++コード(デフォルトのRubyInlineインストールでサポートされている2つの言語)が与えられると、Builderオブジェクトは小さな拡張をディスクに書き込み、コンパイルしてロードします。自分でコンパイルする必要はありませんが、ホームディレクトリの.ruby_inlineサブディレクトリに生成されたコードとコンパイルされた拡張子が表示されます。

あなたのRubyプログラムにCコードを埋め込む:

  • RubyInline( rubyinline gemとして利用可能)は自動的に拡張子を作成します

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_fileCopierインスタンスメソッドとして存在するようになりました。

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