Ruby Language
C एक्सटेंशन
खोज…
आपका पहला विस्तार
C एक्सटेंशन में दो सामान्य टुकड़े शामिल हैं:
- सी कोड ही।
- एक्सटेंशन कॉन्फ़िगरेशन फ़ाइल।
अपने पहले एक्सटेंशन के साथ शुरुआत करने के लिए, extconf.rb
नामक फ़ाइल में निम्नलिखित extconf.rb
:
require 'mkmf'
create_makefile('hello_c')
कुछ बातें इंगित करने के लिए:
सबसे पहले, नाम hello_c
वह है जो आपके संकलित एक्सटेंशन का आउटपुट नाम देने वाला है। यह वही होगा जो आप require
के साथ संयोजन में उपयोग करते हैं।
दूसरा, extconf.rb
फ़ाइल को वास्तव में कुछ भी नाम दिया जा सकता है, यह सिर्फ पारंपरिक रूप से उन रत्नों के निर्माण के लिए उपयोग किया जाता है जिनमें मूल कोड होते हैं, फ़ाइल जो वास्तव में विस्तार को संकलित करने के लिए जा रही है वह है ruby extconf.rb
। डिफ़ॉल्ट मेकफ़ाइल जो उत्पन्न होता है वह वर्तमान निर्देशिका में सभी .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
फ़ाइल में परिभाषित नाम से मेल Init_hello_c
चाहिए, अन्यथा जब गतिशील रूप से एक्सटेंशन लोड हो रहा है, तो रूबी आपके एक्सटेंशन को बूटस्ट्रैप करने के लिए प्रतीक को खोजने में सक्षम नहीं होगा।
rb_define_module
कॉल rb_define_module
नाम का एक रूबी मॉड्यूल HelloC
जिसे हम अपने कार्यों के तहत नाम स्थान पर ले जा रहे हैं।
अंत में, 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
सी स्ट्रक्चर्स के साथ काम करना
रूबी ऑब्जेक्ट्स के रूप में सी स्ट्रक्चर्स के साथ काम करने में सक्षम होने के लिए, आपको उन्हें Data_Wrap_Struct
और Data_Get_Struct
कॉल के साथ लपेटने की आवश्यकता है।
Data_Wrap_Struct
एक रूबी ऑब्जेक्ट में C डेटा संरचना लपेटता है। यह कॉलबैक फ़ंक्शंस में कुछ पॉइंटर्स के साथ आपकी डेटा संरचना की ओर एक पॉइंटर ले जाता है, और एक 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
इनलाइन सी लिखना - RubyInLine
RubyInline एक ढांचा है जो आपको अपने रूबी कोड के अंदर अन्य भाषाओं को एम्बेड करने देता है। यह मॉड्यूल # इनलाइन विधि को परिभाषित करता है, जो एक बिल्डर ऑब्जेक्ट लौटाता है। आप बिल्डर को रूबी के अलावा किसी अन्य भाषा में लिखे गए एक स्ट्रिंग कोड को पास करते हैं, और बिल्डर उसे कुछ इस तरह से बदल देता है जिसे आप रूबी से कॉल कर सकते हैं।
जब सी या सी ++ कोड (डिफ़ॉल्ट रूबी इनलाइन इंस्टॉल में समर्थित दो भाषाएं) दिया जाता है, तो बिल्डर ऑब्जेक्ट डिस्क पर एक छोटा सा एक्सटेंशन लिखता है, इसे संकलित करता है, और इसे लोड करता है। आपको स्वयं संकलन से निपटने की आवश्यकता नहीं है, लेकिन आप अपने होम निर्देशिका की .ruby_inline उपनिर्देशिका में उत्पन्न कोड और संकलित एक्सटेंशन देख सकते हैं।
अपने रूबी कार्यक्रम में सी कोड एम्बेड करें:
- 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 }