Sök…


Din första tillägg

C-förlängningar består av två allmänna delar:

  1. C-koden själv.
  2. Tilläggskonfigurationsfilen.

För att komma igång med ditt första tillägg sätter du följande i en fil med namnet extconf.rb :

require 'mkmf'

create_makefile('hello_c')

Ett par saker att påpeka:

Först, namnet hello_c är vad utgången från din sammanställda tillägg kommer att namnges. Det kommer att vara det du använder i samband med att du require .

För det andra kan extconf.rb filen faktiskt namnges vad som helst, det är bara traditionellt vad som används för att bygga ädelstenar som har inbyggd kod, filen som faktiskt kommer att kompilera förlängningen är Makefile som genereras när man kör ruby extconf.rb . Standard Makefile som genereras sammanställer alla .c filer i den aktuella katalogen.

Lägg följande i en fil med namnet hello.c och kör 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);
}

En uppdelning av koden:

Namnet Init_hello_c måste matcha namnet som definieras i din extconf.rb fil, annars kan Ruby inte hitta symbolen för att starta om din tillägg när du laddar tillägget dynamiskt.

Samtalet till rb_define_module skapar en Ruby-modul med namnet HelloC som vi kommer att namnge HelloC för våra C-funktioner under.

Slutligen gör samtalet till rb_define_singleton_method en rb_define_singleton_method bunden direkt till HelloC modulen som vi kan åberopa från rubin med HelloC.world .

Efter att ha sammanställt tillägget med samtalet för att make vi köra koden i vår C-tillägg.

Avfyra en konsol!

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

Arbeta med C-strukturer

För att kunna arbeta med C-strukturer som Ruby-objekt måste du radera in dem med samtal till Data_Wrap_Struct och Data_Get_Struct .

Data_Wrap_Struct en C-datastruktur i ett Ruby-objekt. Det tar en pekare till din datastruktur, tillsammans med några pekare till återuppringningsfunktioner, och returnerar en VALUE. Data_Get_Struct tar det VALUE och ger dig tillbaka en pekare till din C-datastruktur.

Här är ett enkelt exempel:

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

Och extconf.rb :

require 'mkmf'

create_makefile('example')

Efter att ha sammanställt tillägget:

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

Skriva inline C - RubyInLine

RubyInline är ett ramverk som låter dig bädda in andra språk i din Ruby-kod. Den definierar inline-metoden Module #, som returnerar ett byggareobjekt. Du passerar byggaren en sträng som innehåller kod skriven på ett annat språk än Ruby, och byggaren omvandlar den till något som du kan ringa från Ruby.

När C- eller C ++ -kod ges (de två språken som stöds i standardinstallationen RubyInline) skriver byggnadsobjekten en liten tillägg till disken, sammanställer den och laddar den. Du behöver inte ta itu med kompilationen själv, men du kan se den genererade koden och kompilerade tillägg i underkatalogen .ruby_inline i din hemkatalog.

Bädda in C-kod direkt i ditt Ruby-program:

  • RubyInline (tillgänglig som rubyinline- pärla) skapar automatiskt ett tillägg

RubyInline fungerar inte från 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-funktion copy_file nu som en instansmetod för 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
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow