Ruby Language
C förlängningar
Sök…
Din första tillägg
C-förlängningar består av två allmänna delar:
- C-koden själv.
- 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 }