From 6d86d0773cba83adc7e186967fece96ece4ed8ca Mon Sep 17 00:00:00 2001 From: hsbt Date: Tue, 24 Mar 2015 13:23:38 +0000 Subject: * doc/extention.rdoc: move from toplevel document and added extname. * doc/extention.ja.rdoc: ditto. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@50077 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 5 + README.EXT | 1730 ------------------------------------------------- README.EXT.ja | 1719 ------------------------------------------------ doc/extention.ja.rdoc | 1719 ++++++++++++++++++++++++++++++++++++++++++++++++ doc/extention.rdoc | 1730 +++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 3454 insertions(+), 3449 deletions(-) delete mode 100644 README.EXT delete mode 100644 README.EXT.ja create mode 100644 doc/extention.ja.rdoc create mode 100644 doc/extention.rdoc diff --git a/ChangeLog b/ChangeLog index 900ef9d62a..34a226c04e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +Tue Mar 24 22:23:33 2015 SHIBATA Hiroshi + + * doc/extention.rdoc: move from toplevel document and added extname. + * doc/extention.ja.rdoc: ditto. + Tue Mar 24 22:06:58 2015 SHIBATA Hiroshi * doc/standard_library.rdoc: strip. diff --git a/README.EXT b/README.EXT deleted file mode 100644 index f24029c826..0000000000 --- a/README.EXT +++ /dev/null @@ -1,1730 +0,0 @@ -# README.EXT - -*- RDoc -*- created at: Mon Aug 7 16:45:54 JST 1995 - -This document explains how to make extension libraries for Ruby. - -= Basic Knowledge - -In C, variables have types and data do not have types. In contrast, -Ruby variables do not have a static type, and data themselves have -types, so data will need to be converted between the languages. - -Data in Ruby are represented by the C type `VALUE'. Each VALUE data -has its data-type. - -To retrieve C data from a VALUE, you need to: - -1. Identify the VALUE's data type -2. Convert the VALUE into C data - -Converting to the wrong data type may cause serious problems. - -== Data-Types - -The Ruby interpreter has the following data types: - -T_NIL :: nil -T_OBJECT :: ordinary object -T_CLASS :: class -T_MODULE :: module -T_FLOAT :: floating point number -T_STRING :: string -T_REGEXP :: regular expression -T_ARRAY :: array -T_HASH :: associative array -T_STRUCT :: (Ruby) structure -T_BIGNUM :: multi precision integer -T_FIXNUM :: Fixnum(31bit or 63bit integer) -T_COMPLEX :: complex number -T_RATIONAL :: rational number -T_FILE :: IO -T_TRUE :: true -T_FALSE :: false -T_DATA :: data -T_SYMBOL :: symbol - -In addition, there are several other types used internally: - -T_ICLASS :: included module -T_MATCH :: MatchData object -T_UNDEF :: undefined -T_NODE :: syntax tree node -T_ZOMBIE :: object awaiting finalization - -Most of the types are represented by C structures. - -== Check Data Type of the VALUE - -The macro TYPE() defined in ruby.h shows the data type of the VALUE. -TYPE() returns the constant number T_XXXX described above. To handle -data types, your code will look something like this: - - switch (TYPE(obj)) { - case T_FIXNUM: - /* process Fixnum */ - break; - case T_STRING: - /* process String */ - break; - case T_ARRAY: - /* process Array */ - break; - default: - /* raise exception */ - rb_raise(rb_eTypeError, "not valid value"); - break; - } - -There is the data-type check function - - void Check_Type(VALUE value, int type) - -which raises an exception if the VALUE does not have the type -specified. - -There are also faster check macros for fixnums and nil. - - FIXNUM_P(obj) - NIL_P(obj) - -== Convert VALUE into C Data - -The data for type T_NIL, T_FALSE, T_TRUE are nil, false, true -respectively. They are singletons for the data type. -The equivalent C constants are: Qnil, Qfalse, Qtrue. -Note that Qfalse is false in C also (i.e. 0), but not Qnil. - -The T_FIXNUM data is a 31bit or 63bit length fixed integer. -This size is depend on the size of long: if long is 32bit then -T_FIXNUM is 31bit, if long is 64bit then T_FIXNUM is 63bit. -T_FIXNUM can be converted to a C integer by using the -FIX2INT() macro or FIX2LONG(). Though you have to check that the -data is really FIXNUM before using them, they are faster. FIX2LONG() -never raises exceptions, but FIX2INT() raises RangeError if the -result is bigger or smaller than the size of int. -There are also NUM2INT() and NUM2LONG() which converts any Ruby -numbers into C integers. These macros includes a type check, -so an exception will be raised if the conversion failed. NUM2DBL() -can be used to retrieve the double float value in the same way. - -You can use the macros -StringValue() and StringValuePtr() to get a char* from a VALUE. -StringValue(var) replaces var's value with the result of "var.to_str()". -StringValuePtr(var) does same replacement and returns char* -representation of var. These macros will skip the replacement if var -is a String. Notice that the macros take only the lvalue as their -argument, to change the value of var in place. - -You can also use the macro named StringValueCStr(). This is just -like StringValuePtr(), but always add nul character at the end of -the result. If the result contains nul character, this macro causes -the ArgumentError exception. -StringValuePtr() doesn't guarantee the existence of a nul at the end -of the result, and the result may contain nul. - -Other data types have corresponding C structures, e.g. struct RArray -for T_ARRAY etc. The VALUE of the type which has the corresponding -structure can be cast to retrieve the pointer to the struct. The -casting macro will be of the form RXXXX for each data type; for -instance, RARRAY(obj). See "ruby.h". However, we do not recommend -to access RXXXX data directly because these data structure is complex. -Use corresponding rb_xxx() functions to access internal struct. -For example, to access an entry of array, use rb_ary_entry(ary, offset) -and rb_ary_store(ary, offset, obj). - -There are some accessing macros for structure members, for example -`RSTRING_LEN(str)' to get the size of the Ruby String object. The -allocated region can be accessed by `RSTRING_PTR(str)'. - -Notice: Do not change the value of the structure directly, unless you -are responsible for the result. This ends up being the cause of -interesting bugs. - -== Convert C Data into VALUE - -To convert C data to Ruby values: - -FIXNUM :: - - left shift 1 bit, and turn on LSB. - -Other pointer values:: - - cast to VALUE. - -You can determine whether a VALUE is pointer or not by checking its LSB. - -Notice Ruby does not allow arbitrary pointer values to be a VALUE. They -should be pointers to the structures which Ruby knows about. The known -structures are defined in . - -To convert C numbers to Ruby values, use these macros. - -INT2FIX() :: for integers within 31bits. -INT2NUM() :: for arbitrary sized integer. - -INT2NUM() converts an integer into a Bignum if it is out of the FIXNUM -range, but is a bit slower. - -== Manipulating Ruby Data - -As I already mentioned, it is not recommended to modify an object's -internal structure. To manipulate objects, use the functions supplied -by the Ruby interpreter. Some (not all) of the useful functions are -listed below: - -=== String Functions - -rb_str_new(const char *ptr, long len) :: - - Creates a new Ruby string. - -rb_str_new2(const char *ptr) :: -rb_str_new_cstr(const char *ptr) :: - - Creates a new Ruby string from a C string. This is equivalent to - rb_str_new(ptr, strlen(ptr)). - -rb_str_new_literal(const char *ptr) :: - - Creates a new Ruby string from a C string literal. - -rb_tainted_str_new(const char *ptr, long len) :: - - Creates a new tainted Ruby string. Strings from external data - sources should be tainted. - -rb_tainted_str_new2(const char *ptr) :: -rb_tainted_str_new_cstr(const char *ptr) :: - - Creates a new tainted Ruby string from a C string. - -rb_sprintf(const char *format, ...) :: -rb_vsprintf(const char *format, va_list ap) :: - - Creates a new Ruby string with printf(3) format. - - Note: In the format string, "%"PRIsVALUE can be used for Object#to_s - (or Object#inspect if '+' flag is set) output (and related argument - must be a VALUE). Since it conflicts with "%i", for integers in - format strings, use "%d". - -rb_str_cat(VALUE str, const char *ptr, long len) :: - - Appends len bytes of data from ptr to the Ruby string. - -rb_str_cat2(VALUE str, const char* ptr) :: -rb_str_cat_cstr(VALUE str, const char* ptr) :: - - Appends C string ptr to Ruby string str. This function is - equivalent to rb_str_cat(str, ptr, strlen(ptr)). - -rb_str_catf(VALUE str, const char* format, ...) :: -rb_str_vcatf(VALUE str, const char* format, va_list ap) :: - - Appends C string format and successive arguments to Ruby string - str according to a printf-like format. These functions are - equivalent to rb_str_cat2(str, rb_sprintf(format, ...)) and - rb_str_cat2(str, rb_vsprintf(format, ap)), respectively. - -rb_enc_str_new(const char *ptr, long len, rb_encoding *enc) :: -rb_enc_str_new_cstr(const char *ptr, rb_encoding *enc) :: - - Creates a new Ruby string with the specified encoding. - -rb_enc_str_new_literal(const char *ptr) :: - - Creates a new Ruby string from a C string literal with the specified - encoding. - -rb_usascii_str_new(const char *ptr, long len) :: -rb_usascii_str_new_cstr(const char *ptr) :: - - Creates a new Ruby string with encoding US-ASCII. - -rb_usascii_str_new_literal(const char *ptr) :: - - Creates a new Ruby string from a C string literal with encoding - US-ASCII. - -rb_utf8_str_new(const char *ptr, long len) :: -rb_utf8_str_new_cstr(const char *ptr) :: - - Creates a new Ruby string with encoding UTF-8. - -rb_utf8_str_new_literal(const char *ptr) :: - - Creates a new Ruby string from a C string literal with encoding - UTF-8. - -rb_str_resize(VALUE str, long len) :: - - Resizes Ruby string to len bytes. If str is not modifiable, this - function raises an exception. The length of str must be set in - advance. If len is less than the old length the content beyond - len bytes is discarded, else if len is greater than the old length - the content beyond the old length bytes will not be preserved but - will be garbage. Note that RSTRING_PTR(str) may change by calling - this function. - -rb_str_set_len(VALUE str, long len) :: - - Sets the length of Ruby string. If str is not modifiable, this - function raises an exception. This function preserves the content - upto len bytes, regardless RSTRING_LEN(str). len must not exceed - the capacity of str. - -=== Array Functions - -rb_ary_new() :: - - Creates an array with no elements. - -rb_ary_new2(long len) :: -rb_ary_new_capa(long len) :: - - Creates an array with no elements, allocating internal buffer - for len elements. - -rb_ary_new3(long n, ...) :: -rb_ary_new_from_args(long n, ...) :: - - Creates an n-element array from the arguments. - -rb_ary_new4(long n, VALUE *elts) :: -rb_ary_new_from_values(long n, VALUE *elts) :: - - Creates an n-element array from a C array. - -rb_ary_to_ary(VALUE obj) :: - - Converts the object into an array. - Equivalent to Object#to_ary. - -There are many functions to operate an array. They may dump core if other -types are given. - -rb_ary_aref(argc, VALUE *argv, VALUE ary) :: - - Equivalent to Array#[]. - -rb_ary_entry(VALUE ary, long offset) :: - - ary[offset] - -rb_ary_store(VALUE ary, long offset, VALUE obj) :: - - ary[offset] = obj - -rb_ary_subseq(VALUE ary, long beg, long len) :: - - ary[beg, len] - -rb_ary_push(VALUE ary, VALUE val) :: -rb_ary_pop(VALUE ary) :: -rb_ary_shift(VALUE ary) :: -rb_ary_unshift(VALUE ary, VALUE val) :: - -rb_ary_cat(VALUE ary, const VALUE *ptr, long len) :: - - Appends len elements of objects from ptr to the array. - -= Extending Ruby with C - -== Adding New Features to Ruby - -You can add new features (classes, methods, etc.) to the Ruby -interpreter. Ruby provides APIs for defining the following things: - -* Classes, Modules -* Methods, Singleton Methods -* Constants - -=== Class and Module Definition - -To define a class or module, use the functions below: - - VALUE rb_define_class(const char *name, VALUE super) - VALUE rb_define_module(const char *name) - -These functions return the newly created class or module. You may -want to save this reference into a variable to use later. - -To define nested classes or modules, use the functions below: - - VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super) - VALUE rb_define_module_under(VALUE outer, const char *name) - -=== Method and Singleton Method Definition - -To define methods or singleton methods, use these functions: - - void rb_define_method(VALUE klass, const char *name, - VALUE (*func)(), int argc) - - void rb_define_singleton_method(VALUE object, const char *name, - VALUE (*func)(), int argc) - -The `argc' represents the number of the arguments to the C function, -which must be less than 17. But I doubt you'll need that many. - -If `argc' is negative, it specifies the calling sequence, not number of -the arguments. - -If argc is -1, the function will be called as: - - VALUE func(int argc, VALUE *argv, VALUE obj) - -where argc is the actual number of arguments, argv is the C array of -the arguments, and obj is the receiver. - -If argc is -2, the arguments are passed in a Ruby array. The function -will be called like: - - VALUE func(VALUE obj, VALUE args) - -where obj is the receiver, and args is the Ruby array containing -actual arguments. - -There are some more functions to define methods. One takes an ID -as the name of method to be defined. See also ID or Symbol below. - - void rb_define_method_id(VALUE klass, ID name, - VALUE (*func)(ANYARGS), int argc) - -There are two functions to define private/protected methods: - - void rb_define_private_method(VALUE klass, const char *name, - VALUE (*func)(), int argc) - void rb_define_protected_method(VALUE klass, const char *name, - VALUE (*func)(), int argc) - -At last, rb_define_module_function defines a module functions, -which are private AND singleton methods of the module. -For example, sqrt is the module function defined in Math module. -It can be called in the following way: - - Math.sqrt(4) - -or - - include Math - sqrt(4) - -To define module functions, use: - - void rb_define_module_function(VALUE module, const char *name, - VALUE (*func)(), int argc) - -In addition, function-like methods, which are private methods defined -in the Kernel module, can be defined using: - - void rb_define_global_function(const char *name, VALUE (*func)(), int argc) - -To define an alias for the method, - - void rb_define_alias(VALUE module, const char* new, const char* old); - -To define a reader/writer for an attribute, - - void rb_define_attr(VALUE klass, const char *name, int read, int write) - -To define and undefine the `allocate' class method, - - void rb_define_alloc_func(VALUE klass, VALUE (*func)(VALUE klass)); - void rb_undef_alloc_func(VALUE klass); - -func has to take the klass as the argument and return a newly -allocated instance. This instance should be as empty as possible, -without any expensive (including external) resources. - -If you are overriding an existing method of any ancestor of your class, -you may rely on: - - VALUE rb_call_super(int argc, const VALUE *argv) - -To achieve the receiver of the current scope (if no other way is -available), you can use: - - VALUE rb_current_receiver(void) - -=== Constant Definition - -We have 2 functions to define constants: - - void rb_define_const(VALUE klass, const char *name, VALUE val) - void rb_define_global_const(const char *name, VALUE val) - -The former is to define a constant under specified class/module. The -latter is to define a global constant. - -== Use Ruby Features from C - -There are several ways to invoke Ruby's features from C code. - -=== Evaluate Ruby Programs in a String - -The easiest way to use Ruby's functionality from a C program is to -evaluate the string as Ruby program. This function will do the job: - - VALUE rb_eval_string(const char *str) - -Evaluation is done under the current context, thus current local variables -of the innermost method (which is defined by Ruby) can be accessed. - -Note that the evaluation can raise an exception. There is a safer -function: - - VALUE rb_eval_string_protect(const char *str, int *state) - -It returns nil when an error occur. Moreover, *state is zero if str was -successfully evaluated, or nonzero otherwise. - -=== ID or Symbol - -You can invoke methods directly, without parsing the string. First I -need to explain about ID. ID is the integer number to represent -Ruby's identifiers such as variable names. The Ruby data type -corresponding to ID is Symbol. It can be accessed from Ruby in the -form: - - :Identifier - -or - - :"any kind of string" - -You can get the ID value from a string within C code by using - - rb_intern(const char *name) - rb_intern_str(VALUE name) - -You can retrieve ID from Ruby object (Symbol or String) given as an -argument by using - - rb_to_id(VALUE symbol) - rb_check_id(volatile VALUE *name) - rb_check_id_cstr(const char *name, long len, rb_encoding *enc) - -These functions try to convert the argument to a String if it was not -a Symbol nor a String. The second function stores the converted -result into *name, and returns 0 if the string is not a known symbol. -After this function returned a non-zero value, *name is always a -Symbol or a String, otherwise it is a String if the result is 0. -The third function takes NUL-terminated C string, not Ruby VALUE. - -You can retrieve Symbol from Ruby object (Symbol or String) given as -an argument by using - - rb_to_symbol(VALUE name) - rb_check_symbol(volatile VALUE *namep) - rb_check_symbol_cstr(const char *ptr, long len, rb_encoding *enc) - -These functions are similar to above functions except that these -return a Symbol instead of an ID. - -You can convert C ID to Ruby Symbol by using - - VALUE ID2SYM(ID id) - -and to convert Ruby Symbol object to ID, use - - ID SYM2ID(VALUE symbol) - -=== Invoke Ruby Method from C - -To invoke methods directly, you can use the function below - - VALUE rb_funcall(VALUE recv, ID mid, int argc, ...) - -This function invokes a method on the recv, with the method name -specified by the symbol mid. - -=== Accessing the Variables and Constants - -You can access class variables and instance variables using access -functions. Also, global variables can be shared between both -environments. There's no way to access Ruby's local variables. - -The functions to access/modify instance variables are below: - - VALUE rb_ivar_get(VALUE obj, ID id) - VALUE rb_ivar_set(VALUE obj, ID id, VALUE val) - -id must be the symbol, which can be retrieved by rb_intern(). - -To access the constants of the class/module: - - VALUE rb_const_get(VALUE obj, ID id) - -See also Constant Definition above. - -= Information Sharing Between Ruby and C - -=== Ruby Constants That C Can Be Accessed From C - -As stated in section 1.3, -the following Ruby constants can be referred from C. - - Qtrue - Qfalse - -Boolean values. Qfalse is false in C also (i.e. 0). - - Qnil - -Ruby nil in C scope. - -== Global Variables Shared Between C and Ruby - -Information can be shared between the two environments using shared global -variables. To define them, you can use functions listed below: - - void rb_define_variable(const char *name, VALUE *var) - -This function defines the variable which is shared by both environments. -The value of the global variable pointed to by `var' can be accessed -through Ruby's global variable named `name'. - -You can define read-only (from Ruby, of course) variables using the -function below. - - void rb_define_readonly_variable(const char *name, VALUE *var) - -You can defined hooked variables. The accessor functions (getter and -setter) are called on access to the hooked variables. - - void rb_define_hooked_variable(const char *name, VALUE *var, - VALUE (*getter)(), void (*setter)()) - -If you need to supply either setter or getter, just supply 0 for the -hook you don't need. If both hooks are 0, rb_define_hooked_variable() -works just like rb_define_variable(). - -The prototypes of the getter and setter functions are as follows: - - VALUE (*getter)(ID id, VALUE *var); - void (*setter)(VALUE val, ID id, VALUE *var); - - -Also you can define a Ruby global variable without a corresponding C -variable. The value of the variable will be set/get only by hooks. - - void rb_define_virtual_variable(const char *name, - VALUE (*getter)(), void (*setter)()) - -The prototypes of the getter and setter functions are as follows: - - VALUE (*getter)(ID id); - void (*setter)(VALUE val, ID id); - - -== Encapsulate C Data into a Ruby Object - -To wrap and objectify a C pointer as a Ruby object (so called -DATA), use Data_Wrap_Struct(). - - Data_Wrap_Struct(klass, mark, free, sval) - -Data_Wrap_Struct() returns a created DATA object. The klass argument -is the class for the DATA object. The mark argument is the function -to mark Ruby objects pointed by this data. The free argument is the -function to free the pointer allocation. If this is -1, the pointer -will be just freed. The functions mark and free will be called from -garbage collector. - -These mark / free functions are invoked during GC execution. No -object allocations are allowed during it, so do not allocate ruby -objects inside them. - -You can allocate and wrap the structure in one step. - - Data_Make_Struct(klass, type, mark, free, sval) - -This macro returns an allocated Data object, wrapping the pointer to -the structure, which is also allocated. This macro works like: - - (sval = ALLOC(type), Data_Wrap_Struct(klass, mark, free, sval)) - -Arguments klass, mark, and free work like their counterparts in -Data_Wrap_Struct(). A pointer to the allocated structure will be -assigned to sval, which should be a pointer of the type specified. - -To retrieve the C pointer from the Data object, use the macro -Data_Get_Struct(). - - Data_Get_Struct(obj, type, sval) - -A pointer to the structure will be assigned to the variable sval. - -See the example below for details. - -= Example - Creating dbm Extension - -OK, here's the example of making an extension library. This is the -extension to access DBMs. The full source is included in the ext/ -directory in the Ruby's source tree. - -== Make the Directory - - % mkdir ext/dbm - -Make a directory for the extension library under ext directory. - -== Design the Library - -You need to design the library features, before making it. - -== Write the C Code - -You need to write C code for your extension library. If your library -has only one source file, choosing ``LIBRARY.c'' as a file name is -preferred. On the other hand, in case your library has multiple source -files, avoid choosing ``LIBRARY.c'' for a file name. It may conflict -with an intermediate file ``LIBRARY.o'' on some platforms. -Note that some functions in mkmf library described below generate -a file ``conftest.c'' for checking with compilation. You shouldn't -choose ``conftest.c'' as a name of a source file. - -Ruby will execute the initializing function named ``Init_LIBRARY'' in -the library. For example, ``Init_dbm()'' will be executed when loading -the library. - -Here's the example of an initializing function. - - void - Init_dbm(void) - { - /* define DBM class */ - VALUE cDBM = rb_define_class("DBM", rb_cObject); - /* DBM includes Enumerable module */ - rb_include_module(cDBM, rb_mEnumerable); - - /* DBM has class method open(): arguments are received as C array */ - rb_define_singleton_method(cDBM, "open", fdbm_s_open, -1); - - /* DBM instance method close(): no args */ - rb_define_method(cDBM, "close", fdbm_close, 0); - /* DBM instance method []: 1 argument */ - rb_define_method(cDBM, "[]", fdbm_fetch, 1); - - /* ... */ - - /* ID for a instance variable to store DBM data */ - id_dbm = rb_intern("dbm"); - } - -The dbm extension wraps the dbm struct in the C environment using -Data_Make_Struct. - - struct dbmdata { - int di_size; - DBM *di_dbm; - }; - - obj = Data_Make_Struct(klass, struct dbmdata, 0, free_dbm, dbmp); - -This code wraps the dbmdata structure into a Ruby object. We avoid -wrapping DBM* directly, because we want to cache size information. - -To retrieve the dbmdata structure from a Ruby object, we define the -following macro: - - #define GetDBM(obj, dbmp) do {\ - Data_Get_Struct(obj, struct dbmdata, dbmp);\ - if (dbmp->di_dbm == 0) closed_dbm();\ - } while (0) - -This sort of complicated macro does the retrieving and close checking for -the DBM. - -There are three kinds of way to receive method arguments. First, -methods with a fixed number of arguments receive arguments like this: - - static VALUE - fdbm_delete(VALUE obj, VALUE keystr) - { - /* ... */ - } - -The first argument of the C function is the self, the rest are the -arguments to the method. - -Second, methods with an arbitrary number of arguments receive -arguments like this: - - static VALUE - fdbm_s_open(int argc, VALUE *argv, VALUE klass) - { - /* ... */ - if (rb_scan_args(argc, argv, "11", &file, &vmode) == 1) { - mode = 0666; /* default value */ - } - /* ... */ - } - -The first argument is the number of method arguments, the second -argument is the C array of the method arguments, and the third -argument is the receiver of the method. - -You can use the function rb_scan_args() to check and retrieve the -arguments. The third argument is a string that specifies how to -capture method arguments and assign them to the following VALUE -references. - - -The following is an example of a method that takes arguments by Ruby's -array: - - static VALUE - thread_initialize(VALUE thread, VALUE args) - { - /* ... */ - } - -The first argument is the receiver, the second one is the Ruby array -which contains the arguments to the method. - -*Notice*: GC should know about global variables which refer to Ruby's objects, -but are not exported to the Ruby world. You need to protect them by - - void rb_global_variable(VALUE *var) - -== Prepare extconf.rb - -If the file named extconf.rb exists, it will be executed to generate -Makefile. - -extconf.rb is the file for checking compilation conditions etc. You -need to put - - require 'mkmf' - -at the top of the file. You can use the functions below to check -various conditions. - - have_macro(macro[, headers[, opt]]): check whether macro is defined - have_library(lib[, func[, headers[, opt]]]): check whether library containing function exists - find_library(lib[, func, *paths]): find library from paths - have_func(func[, headers[, opt]): check whether function exists - have_var(var[, headers[, opt]]): check whether variable exists - have_header(header[, preheaders[, opt]]): check whether header file exists - find_header(header, *paths): find header from paths - have_framework(fw): check whether framework exists (for MacOS X) - have_struct_member(type, member[, headers[, opt]]): check whether struct has member - have_type(type[, headers[, opt]]): check whether type exists - find_type(type, opt, *headers): check whether type exists in headers - have_const(const[, headers[, opt]]): check whether constant is defined - check_sizeof(type[, headers[, opts]]): check size of type - check_signedness(type[, headers[, opts]]): check signedness of type - convertible_int(type[, headers[, opts]]): find convertible integer type - find_executable(bin[, path]): find executable file path - create_header(header): generate configured header - create_makefile(target[, target_prefix]): generate Makefile - -See MakeMakefile for full documentation of these functions. - -The value of the variables below will affect the Makefile. - - $CFLAGS: included in CFLAGS make variable (such as -O) - $CPPFLAGS: included in CPPFLAGS make variable (such as -I, -D) - $LDFLAGS: included in LDFLAGS make variable (such as -L) - $objs: list of object file names - -Normally, the object files list is automatically generated by searching -source files, but you must define them explicitly if any sources will -be generated while building. - -If a compilation condition is not fulfilled, you should not call -``create_makefile''. The Makefile will not be generated, compilation will -not be done. - -== Prepare Depend (Optional) - -If the file named depend exists, Makefile will include that file to -check dependencies. You can make this file by invoking - - % gcc -MM *.c > depend - -It's harmless. Prepare it. - -== Generate Makefile - -Try generating the Makefile by: - - ruby extconf.rb - -If the library should be installed under vendor_ruby directory -instead of site_ruby directory, use --vendor option as follows. - - ruby extconf.rb --vendor - -You don't need this step if you put the extension library under the ext -directory of the ruby source tree. In that case, compilation of the -interpreter will do this step for you. - -== Run make - -Type - - make - -to compile your extension. You don't need this step either if you have -put the extension library under the ext directory of the ruby source tree. - -== Debug - -You may need to rb_debug the extension. Extensions can be linked -statically by adding the directory name in the ext/Setup file so that -you can inspect the extension with the debugger. - -== Done! Now You Have the Extension Library - -You can do anything you want with your library. The author of Ruby -will not claim any restrictions on your code depending on the Ruby API. -Feel free to use, modify, distribute or sell your program. - -= Appendix A. Ruby Source Files Overview - -== Ruby Language Core - -class.c :: classes and modules -error.c :: exception classes and exception mechanism -gc.c :: memory management -load.c :: library loading -object.c :: objects -variable.c :: variables and constants - -== Ruby Syntax Parser - -parse.y :: grammar definition -parse.c :: automatically generated from parse.y -keywords :: reserved keywords -lex.c :: automatically generated from keywords - -== Ruby Evaluator (a.k.a. YARV) - - compile.c - eval.c - eval_error.c - eval_jump.c - eval_safe.c - insns.def : definition of VM instructions - iseq.c : implementation of VM::ISeq - thread.c : thread management and context switching - thread_win32.c : thread implementation - thread_pthread.c : ditto - vm.c - vm_dump.c - vm_eval.c - vm_exec.c - vm_insnhelper.c - vm_method.c - - opt_insns_unif.def : instruction unification - opt_operand.def : definitions for optimization - - -> insn*.inc : automatically generated - -> opt*.inc : automatically generated - -> vm.inc : automatically generated - -== Regular Expression Engine (Oniguruma) - - regex.c - regcomp.c - regenc.c - regerror.c - regexec.c - regparse.c - regsyntax.c - -== Utility Functions - -debug.c :: debug symbols for C debugger -dln.c :: dynamic loading -st.c :: general purpose hash table -strftime.c :: formatting times -util.c :: misc utilities - -== Ruby Interpreter Implementation - - dmyext.c - dmydln.c - dmyencoding.c - id.c - inits.c - main.c - ruby.c - version.c - - gem_prelude.rb - prelude.rb - -== Class Library - -array.c :: Array -bignum.c :: Bignum -compar.c :: Comparable -complex.c :: Complex -cont.c :: Fiber, Continuation -dir.c :: Dir -enum.c :: Enumerable -enumerator.c :: Enumerator -file.c :: File -hash.c :: Hash -io.c :: IO -marshal.c :: Marshal -math.c :: Math -numeric.c :: Numeric, Integer, Fixnum, Float -pack.c :: Array#pack, String#unpack -proc.c :: Binding, Proc -process.c :: Process -random.c :: random number -range.c :: Range -rational.c :: Rational -re.c :: Regexp, MatchData -signal.c :: Signal -sprintf.c :: String#sprintf -string.c :: String -struct.c :: Struct -time.c :: Time - -defs/known_errors.def :: Errno::* exception classes --> known_errors.inc :: automatically generated - -== Multilingualization - -encoding.c :: Encoding -transcode.c :: Encoding::Converter -enc/*.c :: encoding classes -enc/trans/* :: codepoint mapping tables - -== goruby Interpreter Implementation - - goruby.c - golf_prelude.rb : goruby specific libraries. - -> golf_prelude.c : automatically generated - - -= Appendix B. Ruby Extension API Reference - -== Types - -VALUE :: - - The type for the Ruby object. Actual structures are defined in ruby.h, - such as struct RString, etc. To refer the values in structures, use - casting macros like RSTRING(obj). - -== Variables and Constants - -Qnil:: - nil object - -Qtrue:: - true object (default true value) - -Qfalse:: - false object - -== C Pointer Wrapping - -Data_Wrap_Struct(VALUE klass, void (*mark)(), void (*free)(), void *sval) :: - - Wrap a C pointer into a Ruby object. If object has references to other - Ruby objects, they should be marked by using the mark function during - the GC process. Otherwise, mark should be 0. When this object is no - longer referred by anywhere, the pointer will be discarded by free - function. - -Data_Make_Struct(klass, type, mark, free, sval) :: - - This macro allocates memory using malloc(), assigns it to the variable - sval, and returns the DATA encapsulating the pointer to memory region. - -Data_Get_Struct(data, type, sval) :: - - This macro retrieves the pointer value from DATA, and assigns it to - the variable sval. - -== Checking Data Types - -TYPE(value) :: - - Internal type (T_NIL, T_FIXNUM, etc.) - -FIXNUM_P(value) :: - - Is +value+ a Fixnum? - -NIL_P(value) :: - - Is +value+ nil? - -void Check_Type(VALUE value, int type) :: - - Ensures +value+ is of the given internal +type+ or raises a TypeError - -SaveStringValue(value) :: - - Checks that +value+ is a String and is not tainted - -== Data Type Conversion - -FIX2INT(value), INT2FIX(i) :: - - Fixnum <-> integer - -FIX2LONG(value), LONG2FIX(l) :: - - Fixnum <-> long - -NUM2INT(value), INT2NUM(i) :: - - Numeric <-> integer - -NUM2UINT(value), UINT2NUM(ui) :: - - Numeric <-> unsigned integer - -NUM2LONG(value), LONG2NUM(l) :: - - Numeric <-> long - -NUM2ULONG(value), ULONG2NUM(ul) :: - - Numeric <-> unsigned long - -NUM2LL(value), LL2NUM(ll) :: - - Numeric <-> long long - -NUM2ULL(value), ULL2NUM(ull) :: - - Numeric <-> unsigned long long - -NUM2OFFT(value), OFFT2NUM(off) :: - - Numeric <-> off_t - -NUM2SIZET(value), SIZET2NUM(size) :: - - Numeric <-> size_t - -NUM2SSIZET(value), SSIZET2NUM(ssize) :: - - Numeric <-> ssize_t - -rb_integer_pack(value, words, numwords, wordsize, nails, flags), rb_integer_unpack(words, numwords, wordsize, nails, flags) :: - - Numeric <-> Arbitrary size integer buffer - -NUM2DBL(value) :: - - Numeric -> double - -rb_float_new(f) :: - - double -> Float - -RSTRING_LEN(str) :: - - String -> length of String data in bytes - -RSTRING_PTR(str) :: - - String -> pointer to String data - Note that the result pointer may not be NUL-terminated - -StringValue(value) :: - - Object with #to_str -> String - -StringValuePtr(value) :: - - Object with #to_str -> pointer to String data - -StringValueCStr(value) :: - - Object with #to_str -> pointer to String data without NUL bytes - It is guaranteed that the result data is NUL-terminated - -rb_str_new2(s) :: - - char * -> String - -== Defining Class and Module - -VALUE rb_define_class(const char *name, VALUE super) :: - - Defines a new Ruby class as a subclass of super. - -VALUE rb_define_class_under(VALUE module, const char *name, VALUE super) :: - - Creates a new Ruby class as a subclass of super, under the module's - namespace. - -VALUE rb_define_module(const char *name) :: - - Defines a new Ruby module. - -VALUE rb_define_module_under(VALUE module, const char *name) :: - - Defines a new Ruby module under the module's namespace. - -void rb_include_module(VALUE klass, VALUE module) :: - - Includes module into class. If class already includes it, just ignored. - -void rb_extend_object(VALUE object, VALUE module) :: - - Extend the object with the module's attributes. - -== Defining Global Variables - -void rb_define_variable(const char *name, VALUE *var) :: - - Defines a global variable which is shared between C and Ruby. If name - contains a character which is not allowed to be part of the symbol, - it can't be seen from Ruby programs. - -void rb_define_readonly_variable(const char *name, VALUE *var) :: - - Defines a read-only global variable. Works just like - rb_define_variable(), except the defined variable is read-only. - -void rb_define_virtual_variable(const char *name, VALUE (*getter)(), VALUE (*setter)()) :: - - Defines a virtual variable, whose behavior is defined by a pair of C - functions. The getter function is called when the variable is - referenced. The setter function is called when the variable is set to a - value. The prototype for getter/setter functions are: - - VALUE getter(ID id) - void setter(VALUE val, ID id) - - The getter function must return the value for the access. - -void rb_define_hooked_variable(const char *name, VALUE *var, VALUE (*getter)(), VALUE (*setter)()) :: - - Defines hooked variable. It's a virtual variable with a C variable. - The getter is called as - - VALUE getter(ID id, VALUE *var) - - returning a new value. The setter is called as - - void setter(VALUE val, ID id, VALUE *var) - - GC requires C global variables which hold Ruby values to be marked. - -void rb_global_variable(VALUE *var) - - Tells GC to protect these variables. - -== Constant Definition - -void rb_define_const(VALUE klass, const char *name, VALUE val) :: - - Defines a new constant under the class/module. - -void rb_define_global_const(const char *name, VALUE val) :: - - Defines a global constant. This is just the same as - - rb_define_const(cKernal, name, val) - -== Method Definition - -rb_define_method(VALUE klass, const char *name, VALUE (*func)(), int argc) :: - - Defines a method for the class. func is the function pointer. argc - is the number of arguments. if argc is -1, the function will receive - 3 arguments: argc, argv, and self. if argc is -2, the function will - receive 2 arguments, self and args, where args is a Ruby array of - the method arguments. - -rb_define_private_method(VALUE klass, const char *name, VALUE (*func)(), int argc) :: - - Defines a private method for the class. Arguments are same as - rb_define_method(). - -rb_define_singleton_method(VALUE klass, const char *name, VALUE (*func)(), int argc) :: - - Defines a singleton method. Arguments are same as rb_define_method(). - -rb_scan_args(int argc, VALUE *argv, const char *fmt, ...) :: - - Retrieve argument from argc and argv to given VALUE references - according to the format string. The format can be described in ABNF - as follows: - - scan-arg-spec := param-arg-spec [option-hash-arg-spec] [block-arg-spec] - - param-arg-spec := pre-arg-spec [post-arg-spec] / post-arg-spec / - pre-opt-post-arg-spec - pre-arg-spec := num-of-leading-mandatory-args [num-of-optional-args] - post-arg-spec := sym-for-variable-length-args - [num-of-trailing-mandatory-args] - pre-opt-post-arg-spec := num-of-leading-mandatory-args num-of-optional-args - num-of-trailing-mandatory-args - option-hash-arg-spec := sym-for-option-hash-arg - block-arg-spec := sym-for-block-arg - - num-of-leading-mandatory-args := DIGIT ; The number of leading - ; mandatory arguments - num-of-optional-args := DIGIT ; The number of optional - ; arguments - sym-for-variable-length-args := "*" ; Indicates that variable - ; length arguments are - ; captured as a ruby array - num-of-trailing-mandatory-args := DIGIT ; The number of trailing - ; mandatory arguments - sym-for-option-hash-arg := ":" ; Indicates that an option - ; hash is captured if the last - ; argument is a hash or can be - ; converted to a hash with - ; #to_hash. When the last - ; argument is nil, it is - ; captured if it is not - ; ambiguous to take it as - ; empty option hash; i.e. '*' - ; is not specified and - ; arguments are given more - ; than sufficient. - sym-for-block-arg := "&" ; Indicates that an iterator - ; block should be captured if - ; given - - For example, "12" means that the method requires at least one - argument, and at most receives three (1+2) arguments. So, the format - string must be followed by three variable references, which are to be - assigned to captured arguments. For omitted arguments, variables are - set to Qnil. NULL can be put in place of a variable reference, which - means the corresponding captured argument(s) should be just dropped. - - The number of given arguments, excluding an option hash or iterator - block, is returned. - -int rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, VALUE *values) - - Retrieves argument VALUEs bound to keywords, which directed by +table+ - into +values+. First +required+ number of IDs referred by +table+ are - mandatory, and succeeding +optional+ (- +optional+ - 1 if - +optional+ is negative) number of IDs are optional. If a - mandatory key is not contained in +keyword_hash+, raises "missing - keyword" +ArgumentError+. If an optional key is not present in - +keyword_hash+, the corresponding element in +values+ is not changed. - If +optional+ is negative, rest of +keyword_hash+ are stored in the - next to optional +values+ as a new Hash, otherwise raises "unknown - keyword" +ArgumentError+. - -VALUE rb_extract_keywords(VALUE *original_hash) - - Extracts pairs whose key is a symbol into a new hash from a hash - object referred by +original_hash+. If the original hash contains - non-symbol keys, then they are copied to another hash and the new hash - is stored through +original_hash+, else 0 is stored. - -== Invoking Ruby method - -VALUE rb_funcall(VALUE recv, ID mid, int narg, ...) :: - - Invokes a method. To retrieve mid from a method name, use rb_intern(). - Able to call even private/protected methods. - -VALUE rb_funcall2(VALUE recv, ID mid, int argc, VALUE *argv) :: -VALUE rb_funcallv(VALUE recv, ID mid, int argc, VALUE *argv) :: - - Invokes a method, passing arguments as an array of values. - Able to call even private/protected methods. - -VALUE rb_funcallv_public(VALUE recv, ID mid, int argc, VALUE *argv) :: - - Invokes a method, passing arguments as an array of values. - Able to call only public methods. - -VALUE rb_eval_string(const char *str) :: - - Compiles and executes the string as a Ruby program. - -ID rb_intern(const char *name) :: - - Returns ID corresponding to the name. - -char *rb_id2name(ID id) :: - - Returns the name corresponding ID. - -char *rb_class2name(VALUE klass) :: - - Returns the name of the class. - -int rb_respond_to(VALUE object, ID id) :: - - Returns true if the object responds to the message specified by id. - -== Instance Variables - -VALUE rb_iv_get(VALUE obj, const char *name) :: - - Retrieve the value of the instance variable. If the name is not - prefixed by `@', that variable shall be inaccessible from Ruby. - -VALUE rb_iv_set(VALUE obj, const char *name, VALUE val) :: - - Sets the value of the instance variable. - -== Control Structure - -VALUE rb_block_call(VALUE recv, ID mid, int argc, VALUE * argv, VALUE (*func) (ANYARGS), VALUE data2) :: - - Calls a method on the recv, with the method name specified by the - symbol mid, with argc arguments in argv, supplying func as the - block. When func is called as the block, it will receive the value - from yield as the first argument, and data2 as the second argument. - When yielded with multiple values (in C, rb_yield_values(), - rb_yield_values2() and rb_yield_splat()), data2 is packed as an Array, - whereas yielded values can be gotten via argc/argv of the third/fourth - arguments. - -[OBSOLETE] VALUE rb_iterate(VALUE (*func1)(), void *arg1, VALUE (*func2)(), void *arg2) :: - - Calls the function func1, supplying func2 as the block. func1 will be - called with the argument arg1. func2 receives the value from yield as - the first argument, arg2 as the second argument. - - When rb_iterate is used in 1.9, func1 has to call some Ruby-level method. - This function is obsolete since 1.9; use rb_block_call instead. - -VALUE rb_yield(VALUE val) :: - - Evaluates the block with value val. - -VALUE rb_rescue(VALUE (*func1)(), VALUE arg1, VALUE (*func2)(), VALUE arg2) :: - - Calls the function func1, with arg1 as the argument. If an exception - occurs during func1, it calls func2 with arg2 as the argument. The - return value of rb_rescue() is the return value from func1 if no - exception occurs, from func2 otherwise. - -VALUE rb_ensure(VALUE (*func1)(), VALUE arg1, VALUE (*func2)(), VALUE arg2) :: - - Calls the function func1 with arg1 as the argument, then calls func2 - with arg2 if execution terminated. The return value from - rb_ensure() is that of func1 when no exception occurred. - -VALUE rb_protect(VALUE (*func) (VALUE), VALUE arg, int *state) :: - - Calls the function func with arg as the argument. If no exception - occurred during func, it returns the result of func and *state is zero. - Otherwise, it returns Qnil and sets *state to nonzero. If state is - NULL, it is not set in both cases. - You have to clear the error info with rb_set_errinfo(Qnil) when - ignoring the caught exception. - -void rb_jump_tag(int state) :: - - Continues the exception caught by rb_protect() and rb_eval_string_protect(). - state must be the returned value from those functions. This function - never return to the caller. - -void rb_iter_break() :: - - Exits from the current innermost block. This function never return to - the caller. - -void rb_iter_break_value(VALUE value) :: - - Exits from the current innermost block with the value. The block will - return the given argument value. This function never return to the - caller. - -== Exceptions and Errors - -void rb_warn(const char *fmt, ...) :: - - Prints a warning message according to a printf-like format. - -void rb_warning(const char *fmt, ...) :: - - Prints a warning message according to a printf-like format, if - $VERBOSE is true. - -void rb_raise(rb_eRuntimeError, const char *fmt, ...) :: - - Raises RuntimeError. The fmt is a format string just like printf(). - -void rb_raise(VALUE exception, const char *fmt, ...) :: - - Raises a class exception. The fmt is a format string just like printf(). - -void rb_fatal(const char *fmt, ...) :: - - Raises a fatal error, terminates the interpreter. No exception handling - will be done for fatal errors, but ensure blocks will be executed. - -void rb_bug(const char *fmt, ...) :: - - Terminates the interpreter immediately. This function should be - called under the situation caused by the bug in the interpreter. No - exception handling nor ensure execution will be done. - -Note: In the format string, "%"PRIsVALUE can be used for Object#to_s -(or Object#inspect if '+' flag is set) output (and related argument -must be a VALUE). Since it conflicts with "%i", for integers in -format strings, use "%d". - -== Initialize and Start the Interpreter - -The embedding API functions are below (not needed for extension libraries): - -void ruby_init() :: - - Initializes the interpreter. - -void *ruby_options(int argc, char **argv) :: - - Process command line arguments for the interpreter. - And compiles the Ruby source to execute. - It returns an opaque pointer to the compiled source - or an internal special value. - -int ruby_run_node(void *n) :: - - Runs the given compiled source and exits this process. - It returns EXIT_SUCCESS if successfully runs the source. - Otherwise, it returns other value. - -void ruby_script(char *name) :: - - Specifies the name of the script ($0). - -== Hooks for the Interpreter Events - - void rb_add_event_hook(rb_event_hook_func_t func, rb_event_flag_t events, - VALUE data) - -Adds a hook function for the specified interpreter events. -events should be OR'ed value of: - - RUBY_EVENT_LINE - RUBY_EVENT_CLASS - RUBY_EVENT_END - RUBY_EVENT_CALL - RUBY_EVENT_RETURN - RUBY_EVENT_C_CALL - RUBY_EVENT_C_RETURN - RUBY_EVENT_RAISE - RUBY_EVENT_ALL - -The definition of rb_event_hook_func_t is below: - - typedef void (*rb_event_hook_func_t)(rb_event_t event, VALUE data, - VALUE self, ID id, VALUE klass) - -The third argument `data' to rb_add_event_hook() is passed to the hook -function as the second argument, which was the pointer to the current -NODE in 1.8. See RB_EVENT_HOOKS_HAVE_CALLBACK_DATA below. - - int rb_remove_event_hook(rb_event_hook_func_t func) - -Removes the specified hook function. - -== Macros for Compatibility - -Some macros to check API compatibilities are available by default. - -NORETURN_STYLE_NEW :: - - Means that NORETURN macro is functional style instead of prefix. - -HAVE_RB_DEFINE_ALLOC_FUNC :: - - Means that function rb_define_alloc_func() is provided, that means the - allocation framework is used. This is same as the result of - have_func("rb_define_alloc_func", "ruby.h"). - -HAVE_RB_REG_NEW_STR :: - - Means that function rb_reg_new_str() is provided, that creates Regexp - object from String object. This is same as the result of - have_func("rb_reg_new_str", "ruby.h"). - -HAVE_RB_IO_T :: - - Means that type rb_io_t is provided. - -USE_SYMBOL_AS_METHOD_NAME :: - - Means that Symbols will be returned as method names, e.g., - Module#methods, #singleton_methods and so on. - -HAVE_RUBY_*_H :: - - Defined in ruby.h and means corresponding header is available. For - instance, when HAVE_RUBY_ST_H is defined you should use ruby/st.h not - mere st.h. - -RB_EVENT_HOOKS_HAVE_CALLBACK_DATA :: - - Means that rb_add_event_hook() takes the third argument `data', to be - passed to the given event hook function. - -= Appendix C. Functions available for use in extconf.rb - -See documentation for {mkmf}[rdoc-ref:MakeMakefile]. - -= Appendix D. Generational GC - -Ruby 2.1 introduced a generational garbage collector (called RGenGC). -RGenGC (mostly) keeps compatibility. - -Generally, the use of the technique called write barriers is required in -extension libraries for generational GC -(http://en.wikipedia.org/wiki/Garbage_collection_%28computer_science%29). -RGenGC works fine without write barriers in extension libraries. - -If your library adheres to the following tips, performance can -be further improved. Especially, the "Don't touch pointers directly" section is -important. - -== Incompatibility - -You can't write RBASIC(obj)->klass field directly because it is const -value now. - -Basically you should not write this field because MRI expects it to be -an immutable field, but if you want to do it in your extension you can -use the following functions: - -VALUE rb_obj_hide(VALUE obj) :: - - Clear RBasic::klass field. The object will be an internal object. - ObjectSpace::each_object can't find this object. - -VALUE rb_obj_reveal(VALUE obj, VALUE klass) :: - - Reset RBasic::klass to be klass. - We expect the `klass' is hidden class by rb_obj_hide(). - -== Write barriers - -RGenGC doesn't require write barriers to support generational GC. -However, caring about write barrier can improve the performance of -RGenGC. Please check the following tips. - -=== Don't touch pointers directly - -In MRI (include/ruby/ruby.h), some macros to acquire pointers to the -internal data structures are supported such as RARRAY_PTR(), -RSTRUCT_PTR() and so on. - -DO NOT USE THESE MACROS and instead use the corresponding C-APIs such as -rb_ary_aref(), rb_ary_store() and so on. - -=== Consider whether to insert write barriers - -You don't need to care about write barriers if you only use built-in -types. - -If you support T_DATA objects, you may consider using write barriers. - -Inserting write barriers into T_DATA objects only works with the -following type objects: (a) long-lived objects, (b) when a huge number -of objects are generated and (c) container-type objects that have -references to other objects. If your extension provides such a type of -T_DATA objects, consider inserting write barriers. - -(a): short-lived objects don't become old generation objects. -(b): only a few oldgen objects don't have performance impact. -(c): only a few references don't have performance impact. - -Inserting write barriers is a very difficult hack, it is easy to -introduce critical bugs. And inserting write barriers has several areas -of overhead. Basically we don't recommend you insert write barriers. -Please carefully consider the risks. - -=== Combine with built-in types - -Please consider utilizing built-in types. Most built-in types support -write barrier, so you can use them to avoid manually inserting write -barriers. - -For example, if your T_DATA has references to other objects, then you -can move these references to Array. A T_DATA object only has a reference -to an array object. Or you can also use a Struct object to gather a -T_DATA object (without any references) and an that Array contains -references. - -With use of such techniques, you don't need to insert write barriers -anymore. - -=== Insert write barriers - -[AGAIN] Inserting write barriers is a very difficult hack, and it is -easy to introduce critical bugs. And inserting write barriers has -several areas of overhead. Basically we don't recommend you insert write -barriers. Please carefully consider the risks. - -Before inserting write barriers, you need to know about RGenGC algorithm -(gc.c will help you). Macros and functions to insert write barriers are -available in in include/ruby/ruby.h. An example is available in iseq.c. - -For a complete guide for RGenGC and write barriers, please refer to -. - -= Appendix E. RB_GC_GUARD to protect from premature GC - -C Ruby currently uses conservative garbage collection, thus VALUE -variables must remain visible on the stack or registers to ensure any -associated data remains usable. Optimizing C compilers are not designed -with conservative garbage collection in mind, so they may optimize away -the original VALUE even if the code depends on data associated with that -VALUE. - -The following example illustrates the use of RB_GC_GUARD to ensure -the contents of sptr remain valid while the second invocation of -rb_str_new_cstr is running. - - VALUE s, w; - const char *sptr; - - s = rb_str_new_cstr("hello world!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); - sptr = RSTRING_PTR(s); - w = rb_str_new_cstr(sptr + 6); /* Possible GC invocation */ - - RB_GC_GUARD(s); /* ensure s (and thus sptr) do not get GC-ed */ - -In the above example, RB_GC_GUARD must be placed _after_ the last use of -sptr. Placing RB_GC_GUARD before dereferencing sptr would be of no use. -RB_GC_GUARD is only effective on the VALUE data type, not converted C -data types. - -RB_GC_GUARD would not be necessary at all in the above example if -non-inlined function calls are made on the `s' VALUE after sptr is -dereferenced. Thus, in the above example, calling any un-inlined -function on `s' such as: - - rb_str_modify(s); - -Will ensure `s' stays on the stack or register to prevent a -GC invocation from prematurely freeing it. - -Using the RB_GC_GUARD macro is preferable to using the "volatile" -keyword in C. RB_GC_GUARD has the following advantages: - -1) the intent of the macro use is clear - -2) RB_GC_GUARD only affects its call site, "volatile" generates some - extra code every time the variable is used, hurting optimization. - -3) "volatile" implementations may be buggy/inconsistent in some - compilers and architectures. RB_GC_GUARD is customizable for broken - systems/compilers without those without negatively affecting other - systems. - -/* - * Local variables: - * fill-column: 70 - * end: - */ diff --git a/README.EXT.ja b/README.EXT.ja deleted file mode 100644 index f4255ebb69..0000000000 --- a/README.EXT.ja +++ /dev/null @@ -1,1719 +0,0 @@ -# README.EXT.ja - -*- RDoc -*- created at: Mon Aug 7 16:45:54 JST 1995 - -Rubyの拡張ライブラリの作り方を説明します. - -= 基礎知識 - -Cの変数には型があり,データには型がありません.ですから,た -とえばポインタをintの変数に代入すると,その値は整数として取 -り扱われます.逆にRubyの変数には型がなく,データに型がありま -す.この違いのため,CとRubyは相互に変換しなければ,お互いの -データをアクセスできません. - -RubyのデータはVALUEというCの型で表現されます.VALUE型のデー -タはそのデータタイプを自分で知っています.このデータタイプと -いうのはデータ(オブジェクト)の実際の構造を意味していて,Ruby -のクラスとはまた違ったものです. - -VALUEからCにとって意味のあるデータを取り出すためには - -1. VALUEのデータタイプを知る -2. VALUEをCのデータに変換する - -の両方が必要です.(1)を忘れると間違ったデータの変換が行われ -て,最悪プログラムがcore dumpします. - -== データタイプ - -Rubyにはユーザが使う可能性のある以下のタイプがあります. - -T_NIL :: nil -T_OBJECT :: 通常のオブジェクト -T_CLASS :: クラス -T_MODULE :: モジュール -T_FLOAT :: 浮動小数点数 -T_STRING :: 文字列 -T_REGEXP :: 正規表現 -T_ARRAY :: 配列 -T_HASH :: 連想配列 -T_STRUCT :: (Rubyの)構造体 -T_BIGNUM :: 多倍長整数 -T_FIXNUM :: Fixnum(31bitまたは63bit長整数) -T_COMPLEX :: 複素数 -T_RATIONAL :: 有理数 -T_FILE :: 入出力 -T_TRUE :: 真 -T_FALSE :: 偽 -T_DATA :: データ -T_SYMBOL :: シンボル - -その他に内部で利用されている以下のタイプがあります. - - T_ICLASS - T_MATCH - T_UNDEF - T_NODE - T_ZOMBIE - -ほとんどのタイプはCの構造体で実装されています. - -== VALUEのデータタイプをチェックする - -ruby.hではTYPE()というマクロが定義されていて,VALUEのデータ -タイプを知ることが出来ます.TYPE()マクロは上で紹介したT_XXXX -の形式の定数を返します.VALUEのデータタイプに応じて処理する -場合には,TYPE()の値で分岐することになります. - - switch (TYPE(obj)) { - case T_FIXNUM: - /* FIXNUMの処理 */ - break; - case T_STRING: - /* 文字列の処理 */ - break; - case T_ARRAY: - /* 配列の処理 */ - break; - default: - /* 例外を発生させる */ - rb_raise(rb_eTypeError, "not valid value"); - break; - } - -それとデータタイプをチェックして,正しくなければ例外を発生す -る関数が用意されています. - - void Check_Type(VALUE value, int type) - -この関数はvalueがtypeで無ければ,例外を発生させます.引数と -して与えられたVALUEのデータタイプが正しいかどうかチェックす -るためには,この関数を使います. - -FIXNUMとNILに関してはより高速な判別マクロが用意されています. - - FIXNUM_P(obj) - NIL_P(obj) - -== VALUEをCのデータに変換する - -データタイプがT_NIL,T_FALSE,T_TRUEである時,データはそれぞ -れnil,false,trueです.このデータタイプのオブジェクトはひと -つずつしか存在しません. - -データタイプがT_FIXNUMの時,これは31bitまたは63bitのサイズを -持つ整数です.longのサイズが32bitのプラットフォームであれば -31bitに,longのサイズが64bitのプラットフォームであれば63bit -になります. FIXNUM を C の整数に変換するためにはマクロ -「FIX2INT()」または「FIX2LONG()」を使います.これらのマクロ -を使用する際には事前にデータタイプがFIXNUMであることを確認す -る必要がありますが,比較的高速に変換を行うことができます.ま -た,「FIX2LONG()」は例外を発生しませんが,「FIX2INT()」は変 -換結果がintのサイズに収まらない場合には例外を発生します. -それから,FIXNUMに限らずRubyのデータを整数に変換する -「NUM2INT()」および「NUM2LONG()」というマクロがあります.こ -れらのマクロはデータタイプのチェック無しで使えます -(整数に変換できない場合には例外が発生する).同様にチェック無し -で使える変換マクロはdoubleを取り出す「NUM2DBL()」があります. - -char* を取り出す場合, StringValue() と StringValuePtr() -を使います. -StringValue(var) は var が String -であれば何もせず,そうでなければ var を var.to_str() の結果 -に置き換えるマクロ,StringValuePtr(var) は同様に var を -String に置き換えてから var のバイト列表現に対する char* を -返すマクロです.var の内容を直接置き換える処理が入るので, -var は lvalue である必要があります. -また,StringValuePtr() に類似した StringValueCStr() というマ -クロもあります.StringValueCStr(var) は var を String に置き -換えてから var の文字列表現に対する char* を返します.返され -る文字列の末尾には nul 文字が付加されます.なお,途中に nul -文字が含まれる場合は ArgumentError が発生します. -一方,StringValuePtr() では,末尾に nul 文字がある保証はなく, -途中に nul 文字が含まれている可能性もあります. - -それ以外のデータタイプは対応するCの構造体があります.対応す -る構造体のあるVALUEはそのままキャスト(型変換)すれば構造体の -ポインタに変換できます. - -構造体は「struct RXxxxx」という名前でruby.hで定義されていま -す.例えば文字列は「struct RString」です.実際に使う可能性が -あるのは文字列と配列くらいだと思います. - -ruby.hでは構造体へキャストするマクロも「RXXXXX()」(全部大文 -字にしたもの)という名前で提供されています(例: RSTRING()).た -だし、構造体への直接のアクセスはできるだけ避け,対応する -rb_xxxx() といった関数を使うようにして下さい.例えば,配列の -要素へアクセスする場合は,rb_ary_entry(ary, offset), -rb_ary_store(ary, offset, obj) を利用するようにして下さい. - -構造体からデータを取り出すマクロが提供されています.文字列 -strの長さを得るためには「RSTRING_LEN(str)」とし,文字列strを -char*として得るためには「RSTRING_PTR(str)」とします. - -Rubyの構造体を直接アクセスする時に気をつけなければならないこ -とは,配列や文字列の構造体の中身は参照するだけで,直接変更し -ないことです.直接変更した場合,オブジェクトの内容の整合性が -とれなくなって,思わぬバグの原因になります. - -== CのデータをVALUEに変換する - -VALUEの実際の構造は - -FIXNUMの場合 :: - - 1bit左シフトして,LSBを立てる. - -その他のポインタの場合 :: - - そのままVALUEにキャストする. - -となっています.よって,LSBをチェックすればVALUEがFIXNUMかど -うかわかるわけです(ポインタのLSBが立っていないことを仮定して -いる). - -ですから,FIXNUM以外のRubyのオブジェクトの構造体は単にVALUE -にキャストするだけでVALUEに変換出来ます.ただし,任意の構造 -体がVALUEにキャスト出来るわけではありません.キャストするの -はRubyの知っている構造体(ruby.hで定義されているstruct RXxxx -のもの)だけです. - -FIXNUMに関しては変換マクロを経由する必要があります.Cの整数 -からVALUEに変換するマクロは以下のものがあります.必要に応じ -て使い分けてください. - -INT2FIX() :: もとの整数が31bitまたは63bit以内に収まる自信 - がある時 -INT2NUM() :: 任意の整数からVALUEへ - -INT2NUM()は整数がFIXNUMの範囲に収まらない場合,Bignumに変換 -してくれます(が,少し遅い). - -== Rubyのデータを操作する - -先程も述べた通り,Rubyの構造体をアクセスする時に内容の更新を -行うことは勧められません.で,Rubyのデータを操作する時には -Rubyが用意している関数を用いてください. - -ここではもっとも使われるであろう文字列と配列の生成/操作を行 -う関数をあげます(全部ではないです). - -=== 文字列に対する関数 - -rb_str_new(const char *ptr, long len) :: - - 新しいRubyの文字列を生成する. - -rb_str_new2(const char *ptr) -rb_str_new_cstr(const char *ptr) - - Cの文字列からRubyの文字列を生成する.この関数の機能は - rb_str_new(ptr, strlen(ptr))と同等である. - -rb_str_new_literal(const char *ptr) - - Cのリテラル文字列からRubyの文字列を生成する. - -rb_tainted_str_new(const char *ptr, long len) - - 汚染マークが付加された新しいRubyの文字列を生成する.外部 - からのデータに基づく文字列には汚染マークが付加されるべき - である. - -rb_tainted_str_new2(const char *ptr) -rb_tainted_str_new_cstr(const char *ptr) - - Cの文字列から汚染マークが付加されたRubyの文字列を生成する. - -rb_sprintf(const char *format, ...) -rb_vsprintf(const char *format, va_list ap) - - Cの文字列formatと続く引数をprintf(3)のフォーマットにしたがって - 整形し,Rubyの文字列を生成する. - - 注意: "%"PRIsVALUEがObject#to_s('+'フラグが指定されている - ときはObject#inspect)を使ったVALUEの出力に利用できる.これ - は"%i"と衝突するため,整数には"%d"を使用すること. - -rb_str_cat(VALUE str, const char *ptr, long len) - - Rubyの文字列strにlenバイトの文字列ptrを追加する. - -rb_str_cat2(VALUE str, const char* ptr) -rb_str_cat_cstr(VALUE str, const char* ptr) - - Rubyの文字列strにCの文字列ptrを追加する.この関数の機能は - rb_str_cat(str, ptr, strlen(ptr))と同等である. - -rb_str_catf(VALUE str, const char* format, ...) -rb_str_vcatf(VALUE str, const char* format, va_list ap) - - Cの文字列formatと続く引数をprintf(3)のフォーマットにしたがって - 整形し,Rubyの文字列strに追加する.この関数の機能は,それぞれ - rb_str_cat2(str, rb_sprintf(format, ...)) や - rb_str_cat2(str, rb_vsprintf(format, ap)) と同等である. - -rb_enc_str_new(const char *ptr, long len, rb_encoding *enc) -rb_enc_str_new_cstr(const char *ptr, rb_encoding *enc) - - 指定されたエンコーディングでRubyの文字列を生成する. - -rb_enc_str_new_literal(const char *ptr) - - Cのリテラル文字列から指定されたエンコーディングでRubyの文字列を生成する. - -rb_usascii_str_new(const char *ptr, long len) -rb_usascii_str_new_cstr(const char *ptr) - - エンコーディングがUS-ASCIIのRubyの文字列を生成する. - -rb_usascii_str_new_literal(const char *ptr) - - Cのリテラル文字列からエンコーディングがUS-ASCIIのRubyの文字列を生成する. - -rb_utf8_str_new(const char *ptr, long len) -rb_utf8_str_new_cstr(const char *ptr) - - エンコーディングがUTF-8のRubyの文字列を生成する. - -rb_usascii_str_new_literal(const char *ptr) - - Cのリテラル文字列からエンコーディングがUTF-8のRubyの文字列を生成する. - -rb_str_resize(VALUE str, long len) - - Rubyの文字列のサイズをlenバイトに変更する.strの長さは前 - 以てセットされていなければならない.lenが元の長さよりも短 - い時は,lenバイトを越えた部分の内容は捨てられる.lenが元 - の長さよりも長い時は,元の長さを越えた部分の内容は保存さ - れないでゴミになるだろう.この関数の呼び出しによって - RSTRING_PTR(str)が変更されるかもしれないことに注意. - -rb_str_set_len(VALUE str, long len) - - Rubyの文字列のサイズをlenバイトにセットする.strが変更可 - 能でなければ例外が発生する.RSTRING_LEN(str)とは無関係に, - lenバイトまでの内容は保存される.lenはstrの容量を越えてい - てはならない. - - -== 配列に対する関数 - -rb_ary_new() - - 要素が0の配列を生成する. - -rb_ary_new2(long len) -rb_ary_new_capa(long len) - - 要素が0の配列を生成する.len要素分の領域をあらかじめ割り - 当てておく. - -rb_ary_new3(long n, ...) -rb_ary_new_from_args(long n, ...) - - 引数で指定したn要素を含む配列を生成する. - -rb_ary_new4(long n, VALUE *elts) -rb_ary_new_from_values(long n, VALUE *elts) - - 配列で与えたn要素の配列を生成する. - -rb_ary_to_ary(VALUE obj) - - オブジェクトを配列に変換する. - Object#to_aryと同等である. - -他にも配列を操作する関数が多数ある. これらは -引数aryに配列を渡さなければならない. さもないと -コアを吐く. - -rb_ary_aref(argc, VALUE *argv, VALUE ary) - - Array#[]と同等. - -rb_ary_entry(VALUE ary, long offset) - - ary[offset] - -rb_ary_store(VALUE ary, long offset, VALUE obj) :: - - ary[offset] = obj - -rb_ary_subseq(VALUE ary, long beg, long len) - - ary[beg, len] - -rb_ary_push(VALUE ary, VALUE val) -rb_ary_pop(VALUE ary) -rb_ary_shift(VALUE ary) -rb_ary_unshift(VALUE ary, VALUE val) - -rb_ary_cat(VALUE ary, const VALUE *ptr, long len) - - 配列aryにptrからlen個のオブジェクトを追加する. - -= Rubyの機能を使う - -原理的にRubyで書けることはCでも書けます.RubyそのものがCで記 -述されているんですから,当然といえば当然なんですけど.ここで -はRubyの拡張に使うことが多いだろうと予測される機能を中心に紹 -介します. - -== Rubyに機能を追加する - -Rubyで提供されている関数を使えばRubyインタプリタに新しい機能 -を追加することができます.Rubyでは以下の機能を追加する関数が -提供されています. - -* クラス,モジュール -* メソッド,特異メソッドなど -* 定数 - -では順に紹介します. - -=== クラス/モジュール定義 - -クラスやモジュールを定義するためには,以下の関数を使います. - - VALUE rb_define_class(const char *name, VALUE super) - VALUE rb_define_module(const char *name) - -これらの関数は新しく定義されたクラスやモジュールを返します. -メソッドや定数の定義にこれらの値が必要なので,ほとんどの場合 -は戻り値を変数に格納しておく必要があるでしょう. - -クラスやモジュールを他のクラスの内部にネストして定義する時に -は以下の関数を使います. - - VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super) - VALUE rb_define_module_under(VALUE outer, const char *name) - -=== メソッド/特異メソッド定義 - -メソッドや特異メソッドを定義するには以下の関数を使います. - - void rb_define_method(VALUE klass, const char *name, - VALUE (*func)(), int argc) - - void rb_define_singleton_method(VALUE object, const char *name, - VALUE (*func)(), int argc) - - -念のため説明すると「特異メソッド」とは,その特定のオブジェク -トに対してだけ有効なメソッドです.RubyではよくSmalltalkにお -けるクラスメソッドとして,クラスに対する特異メソッドが使われ -ます. - -これらの関数の argcという引数はCの関数へ渡される引数の数(と -形式)を決めます.argcが0以上の時は関数に引き渡す引数の数を意 -味します.16個以上の引数は使えません(が,要りませんよね,そ -んなに).実際の関数には先頭の引数としてselfが与えられますの -で,指定した数より1多い引数を持つことになります. - -argcが負の時は引数の数ではなく,形式を指定したことになります. -argcが-1の時は引数を配列に入れて渡されます.argcが-2の時は引 -数はRubyの配列として渡されます. - -メソッドを定義する関数はまだいくつかあります. ひとつはメソッド -名としてIDを取ります. IDについては2.2.2を参照. - - void rb_define_method_id(VALUE klass, ID name, - VALUE (*func)(ANYARGS), int argc) - -private/protectedなメソッドを定義するふたつの関数があります. - - void rb_define_private_method(VALUE klass, const char *name, - VALUE (*func)(), int argc) - void rb_define_protected_method(VALUE klass, const char *name, - VALUE (*func)(), int argc) - -privateメソッドとは関数形式でしか呼び出すことの出来ないメソッ -ドです. - -最後に, rb_define_module関数はモジュール関数を定義します. -モジュール関数とはモジュールの特異メソッドであり,同時に -privateメソッドでもあるものです.例をあげるとMathモジュール -のsqrt()などがあげられます.このメソッドは - - Math.sqrt(4) - -という形式でも - - include Math - sqrt(4) - -という形式でも使えます.モジュール関数を定義する関数は以下の -通りです. - - void rb_define_module_function(VALUE module, const char *name, - VALUE (*func)(), int argc) - -関数的メソッド(Kernelモジュールのprivate method)を定義するた -めの関数は以下の通りです. - - void rb_define_global_function(const char *name, VALUE (*func)(), int argc) - - -メソッドの別名を定義するための関数は以下の通りです. - - void rb_define_alias(VALUE module, const char* new, const char* old); - -属性の取得・設定メソッドを定義するには - - void rb_define_attr(VALUE klass, const char *name, int read, int write) - -クラスメソッドallocateを定義したり削除したりするための関数は -以下の通りです. - - void rb_define_alloc_func(VALUE klass, VALUE (*func)(VALUE klass)); - void rb_undef_alloc_func(VALUE klass); - -funcはクラスを引数として受け取って,新しく割り当てられたイン -スタンスを返さなくてはなりません.このインスタンスは,外部リ -ソースなどを含まない,できるだけ「空」のままにしておいたほう -がよいでしょう. - -継承したクラスにある既存のメソッドをオーバーライドしているな -ら,オーバーライドされたメソッドを呼び出すには以下の関数を使 -います. - - VALUE rb_call_super(int argc, const VALUE *argv) - -現在のスコープのレシーバは(他に方法がなければ),以下の関数で -得ることができます. - - VALUE rb_current_receiver(void) - -=== 定数定義 - -拡張ライブラリが必要な定数はあらかじめ定義しておいた方が良い -でしょう.定数を定義する関数は二つあります. - - void rb_define_const(VALUE klass, const char *name, VALUE val) - void rb_define_global_const(const char *name, VALUE val) - -前者は特定のクラス/モジュールに属する定数を定義するもの,後 -者はグローバルな定数を定義するものです. - -== Rubyの機能をCから呼び出す - -既に『1.5 Rubyのデータを操作する』で一部紹介したような関数を -使えば,Rubyの機能を実現している関数を直接呼び出すことが出来 -ます. - -# このような関数の一覧表はいまのところありません.ソースを見 -# るしかないですね. - -それ以外にもRubyの機能を呼び出す方法はいくつかあります. - -=== Rubyのプログラムをevalする - -CからRubyの機能を呼び出すもっとも簡単な方法として,文字列で -与えられたRubyのプログラムを評価する以下の関数があります. - - VALUE rb_eval_string(const char *str) - -この評価は現在の環境で行われます.つまり,現在のローカル変数 -などを受け継ぎます. - -評価は例外を発生するかもしれないことに注意しましょう. より安全 -な関数もあります. - - VALUE rb_eval_string_protect(const char *str, int *state) - -この関数はエラーが発生するとnilを返します.そして,成功時には -*stateはゼロに,さもなくば非ゼロになります. - -=== IDまたはシンボル - -Cから文字列を経由せずにRubyのメソッドを呼び出すこともできま -す.その前に,Rubyインタプリタ内でメソッドや変数名を指定する -時に使われているIDについて説明しておきましょう. - -IDとは変数名,メソッド名を表す整数です.Rubyの中では - - :識別子 - -または - - :"任意の文字列" - -でアクセスできます.Cからこの整数を得るためには関数 - - rb_intern(const char *name) - rb_intern_str(VALUE name) - -を使います.Rubyから引数として与えられたシンボル(または文字 -列)をIDに変換するには以下の関数を使います. - - rb_to_id(VALUE symbol) - rb_check_id(volatile VALUE *name) - rb_check_id_cstr(const char *name, long len, rb_encoding *enc) - -もし引数がシンボルでも文字列でもなければ,to_strメソッドで文 -字列に変換しようとします.第二の関数はその変換結果を*nameに保 -存し,その名前が既知のシンボルでない場合は0を返します.この関 -数が0以外を返した場合は*nameは常にシンボルか文字列であり,0を -返した場合は常に文字列です.第三の関数はRubyの文字列ではなく -NUL終端されたCの文字列を使います. - -Rubyから引数として与えられたシンボル(または文字列)をシンボル -に変換するには以下の関数を使います. - - rb_to_symbol(VALUE name) - rb_check_symbol(volatile VALUE *namep) - rb_check_symbol_cstr(const char *ptr, long len, rb_encoding *enc) - -これらの関数は,IDの代わりにシンボルを返すことを除けば上記の -関数と同じです. - -=== CからRubyのメソッドを呼び出す - -Cから文字列を経由せずにRubyのメソッドを呼び出すためには以下 -の関数を使います. - - VALUE rb_funcall(VALUE recv, ID mid, int argc, ...) - -この関数はオブジェクトrecvのmidで指定されるメソッドを呼び出 -します.その他に引数の指定の仕方が違う以下の関数もあります. - - VALUE rb_funcall2(VALUE recv, ID mid, int argc, VALUE *argv) - VALUE rb_funcallv(VALUE recv, ID mid, int argc, VALUE *argv) - VALUE rb_apply(VALUE recv, ID mid, VALUE args) - -applyには引数としてRubyの配列を与えます. - -=== 変数/定数を参照/更新する - -Cから関数を使って参照・更新できるのは,定数,インスタンス変 -数です.大域変数は一部のものはCの大域変数としてアクセスでき -ます.ローカル変数を参照する方法は公開していません. - -オブジェクトのインスタンス変数を参照・更新する関数は以下の通 -りです. - - VALUE rb_ivar_get(VALUE obj, ID id) - VALUE rb_ivar_set(VALUE obj, ID id, VALUE val) - -idはrb_intern()で得られるものを使ってください. - -定数を参照するには以下の関数を使ってください. - - VALUE rb_const_get(VALUE obj, ID id) - -定数を新しく定義するためには『2.1.3 定数定義』で紹介さ -れている関数を使ってください. - -= RubyとCとの情報共有 - -C言語とRubyの間で情報を共有する方法について解説します. - -== Cから参照できるRubyの定数 - -以下のRubyの定数はCのレベルから参照できます. - - Qtrue - Qfalse - -真偽値.QfalseはC言語でも偽とみなされます(つまり0). - - Qnil - -C言語から見た「nil」. - -== CとRubyで共有される大域変数 - -CとRubyで大域変数を使って情報を共有できます.共有できる大域 -変数にはいくつかの種類があります.そのなかでもっとも良く使わ -れると思われるのはrb_define_variable()です. - - void rb_define_variable(const char *name, VALUE *var) - -この関数はRubyとCとで共有する大域変数を定義します.変数名が -`$'で始まらない時には自動的に追加されます.この変数の値を変 -更すると自動的にRubyの対応する変数の値も変わります. - -またRuby側からは更新できない変数もあります.このread onlyの -変数は以下の関数で定義します. - - void rb_define_readonly_variable(const char *name, VALUE *var) - -これら変数の他にhookをつけた大域変数を定義できます.hook付き -の大域変数は以下の関数を用いて定義します.hook付き大域変数の -値の参照や設定はhookで行う必要があります. - - void rb_define_hooked_variable(const char *name, VALUE *var, - VALUE (*getter)(), void (*setter)()) - -この関数はCの関数によってhookのつけられた大域変数を定義しま -す.変数が参照された時には関数getterが,変数に値がセットされ -た時には関数setterが呼ばれる.hookを指定しない場合はgetterや -setterに0を指定します. -# getterもsetterも0ならばrb_define_variable()と同じになる. - -getterとsetterの仕様は次の通りです. - - VALUE (*getter)(ID id, VALUE *var); - void (*setter)(VALUE val, ID id, VALUE *var); - - -それから,対応するCの変数を持たないRubyの大域変数を定義する -こともできます. その変数の値はフック関数のみによって取得・設定 -されます. - - void rb_define_virtual_variable(const char *name, - VALUE (*getter)(), void (*setter)()) - -この関数によって定義されたRubyの大域変数が参照された時には -getterが,変数に値がセットされた時にはsetterが呼ばれます. - -getterとsetterの仕様は以下の通りです. - - (*getter)(ID id); - (*setter)(VALUE val, ID id); - -== CのデータをRubyオブジェクトにする - -Cの世界で定義されたデータ(構造体)をRubyのオブジェクトとして -取り扱いたい場合がありえます.このような場合には,Dataという -RubyオブジェクトにCの構造体(へのポインタ)をくるむことでRuby -オブジェクトとして取り扱えるようになります. - -Dataオブジェクトを生成して構造体をRubyオブジェクトにカプセル -化するためには,以下のマクロを使います. - - Data_Wrap_Struct(klass, mark, free, sval) - -このマクロの戻り値は生成されたDataオブジェクトです. - -klassはこのDataオブジェクトのクラスです.markはこの構造体が -Rubyのオブジェクトへの参照がある時に使う関数です.そのような -参照を含まない時には0を指定します. - -# そのような参照は勧められません. - -freeはこの構造体がもう不要になった時に呼ばれる関数です.この -関数がガーベージコレクタから呼ばれます.これが-1の場合は,単 -純に開放されます. - -markおよびfree関数はGC実行中に呼び出されます. -なお, GC実行中はRubyオブジェクトのアロケーションは禁止されま -す. よって, markおよびfree関数でRubyオブジェクトのアロケーシ -ョンは行わないでください. - -Cの構造体の割当とDataオブジェクトの生成を同時に行うマクロと -して以下のものが提供されています. - - Data_Make_Struct(klass, type, mark, free, sval) - -このマクロの戻り値は生成されたDataオブジェクトです.このマク -ロは以下の式のように働きます: - - (sval = ALLOC(type), Data_Wrap_Struct(klass, mark, free, sval)) - -klass, mark, freeはData_Wrap_Structと同じ働きをします.type -は割り当てるC構造体の型です.割り当てられた構造体は変数sval -に代入されます.この変数の型は (type*) である必要があります. - -Dataオブジェクトからポインタを取り出すのは以下のマクロを用い -ます. - - Data_Get_Struct(obj, type, sval) - -Cの構造体へのポインタは変数svalに代入されます. - -これらのDataの使い方はちょっと分かりにくいので,後で説明する -例題を参照してください. - -= 例題 - dbmパッケージを作る - -ここまでの説明でとりあえず拡張ライブラリは作れるはずです. -Rubyのextディレクトリにすでに含まれているdbmライブラリを例に -して段階的に説明します. - -== ディレクトリを作る - - % mkdir ext/dbm - -Ruby 1.1からは任意のディレクトリでダイナミックライブラリを作 -ることができるようになりました.Rubyに静的にリンクする場合に -はRubyを展開したディレクトリの下,extディレクトリの中に拡張 -ライブラリ用のディレクトリを作る必要があります.名前は適当に -選んで構いません. - -== 設計する - -まあ,当然なんですけど,どういう機能を実現するかどうかまず設 -計する必要があります.どんなクラスをつくるか,そのクラスには -どんなメソッドがあるか,クラスが提供する定数などについて設計 -します. - -== Cコードを書く - -拡張ライブラリ本体となるC言語のソースを書きます.C言語のソー -スがひとつの時には「ライブラリ名.c」を選ぶと良いでしょう.C -言語のソースが複数の場合には逆に「ライブラリ名.c」というファ -イル名は避ける必要があります.オブジェクトファイルとモジュー -ル生成時に中間的に生成される「ライブラリ名.o」というファイル -とが衝突するからです.また,後述する mkmf ライブラリのいくつ -かの関数がコンパイルを要するテストのために「conftest.c」とい -うファイル名を使用することに注意してください.ソースファイル -名として「conftest.c」を使用してはなりません. - -Rubyは拡張ライブラリをロードする時に「Init_ライブラリ名」と -いう関数を自動的に実行します.dbmライブラリの場合「Init_dbm」 -です.この関数の中でクラス,モジュール,メソッド,定数などの -定義を行います.dbm.cから一部引用します. - - void - Init_dbm(void) - { - /* DBMクラスを定義する */ - VALUE cDBM = rb_define_class("DBM", rb_cObject); - /* DBMはEnumerableモジュールをインクルードする */ - rb_include_module(cDBM, rb_mEnumerable); - - /* DBMクラスのクラスメソッドopen(): 引数はCの配列で受ける */ - rb_define_singleton_method(cDBM, "open", fdbm_s_open, -1); - - /* DBMクラスのメソッドclose(): 引数はなし */ - rb_define_method(cDBM, "close", fdbm_close, 0); - /* DBMクラスのメソッド[]: 引数は1個 */ - rb_define_method(cDBM, "[]", fdbm_fetch, 1); - - /* ... */ - - /* DBMデータを格納するインスタンス変数名のためのID */ - id_dbm = rb_intern("dbm"); - } - -DBMライブラリはdbmのデータと対応するオブジェクトになるはずで -すから,Cの世界のdbmをRubyの世界に取り込む必要があります. - -dbm.cではData_Make_Structを以下のように使っています. - - struct dbmdata { - int di_size; - DBM *di_dbm; - }; - - - obj = Data_Make_Struct(klass, struct dbmdata, 0, free_dbm, dbmp); - -ここではdbmstruct構造体へのポインタをDataにカプセル化してい -ます.DBM*を直接カプセル化しないのはclose()した時の処理を考 -えてのことです. - -Dataオブジェクトからdbmstruct構造体のポインタを取り出すため -に以下のマクロを使っています. - - #define GetDBM(obj, dbmp) do {\ - Data_Get_Struct(obj, struct dbmdata, dbmp);\ - if (dbmp->di_dbm == 0) closed_dbm();\ - } while (0) - -ちょっと複雑なマクロですが,要するにdbmdata構造体のポインタ -の取り出しと,closeされているかどうかのチェックをまとめてい -るだけです. - -DBMクラスにはたくさんメソッドがありますが,分類すると3種類の -引数の受け方があります.ひとつは引数の数が固定のもので,例と -してはdeleteメソッドがあります.deleteメソッドを実装している -fdbm_delete()はこのようになっています. - - static VALUE - fdbm_delete(VALUE obj, VALUE keystr) - { - /* ... */ - } - -引数の数が固定のタイプは第1引数がself,第2引数以降がメソッド -の引数となります. - -引数の数が不定のものはCの配列で受けるものとRubyの配列で受け -るものとがあります.dbmライブラリの中で,Cの配列で受けるもの -はDBMのクラスメソッドであるopen()です.これを実装している関 -数fdbm_s_open()はこうなっています. - - static VALUE - fdbm_s_open(int argc, VALUE *argv, VALUE klass) - { - /* ... */ - - if (rb_scan_args(argc, argv, "11", &file, &vmode) == 1) { - mode = 0666; /* default value */ - } - - /* ... */ - } - -このタイプの関数は第1引数が与えられた引数の数,第2引数が与え -られた引数の入っている配列になります.selfは第3引数として与 -えられます. - -この配列で与えられた引数を解析するための関数がopen()でも使わ -れているrb_scan_args()です.第3引数に指定したフォーマットに従 -い,第4変数以降に指定したVALUEへの参照に値を代入してくれま -す. - - -引数をRubyの配列として受け取るメソッドの例には -Thread#initializeがあります.実装はこうです. - - static VALUE - thread_initialize(VALUE thread, VALUE args) - { - /* ... */ - } - -第1引数はself,第2引数はRubyの配列です. - -*注意事項* - -Rubyと共有はしないがRubyのオブジェクトを格納する可能性のある -Cの大域変数は以下の関数を使ってRubyインタプリタに変数の存在 -を教えてあげてください.でないとGCでトラブルを起こします. - - void rb_global_variable(VALUE *var) - -== extconf.rbを用意する - -Makefileを作る場合の雛型になるextconf.rbというファイルを作り -ます.extconf.rbはライブラリのコンパイルに必要な条件のチェッ -クなどを行うことが目的です.まず, - - require 'mkmf' - -をextconf.rbの先頭に置きます.extconf.rbの中では以下のRuby関 -数を使うことが出来ます. - - have_library(lib, func): ライブラリの存在チェック - have_func(func, header): 関数の存在チェック - have_header(header): ヘッダファイルの存在チェック - create_makefile(target[, target_prefix]): Makefileの生成 - -以下の変数を使うことができます. - - $CFLAGS: コンパイル時に追加的に指定するフラグ(-Oなど) - $CPPFLAGS: プリプロセッサに追加的に指定するフラグ(-Iや-Dなど) - $LDFLAGS: リンク時に追加的に指定するフラグ(-Lなど) - $objs: リンクされるオブジェクトファイル名のリスト - -オブジェクトファイルのリストは,通常はソースファイルを検索し -て自動的に生成されますが,makeの途中でソースを生成するような -場合は明示的に指定する必要があります. - -ライブラリをコンパイルする条件が揃わず,そのライブラリをコン -パイルしない時にはcreate_makefileを呼ばなければMakefileは生 -成されず,コンパイルも行われません. - -== dependを用意する - -もし,ディレクトリにdependというファイルが存在すれば, -Makefileが依存関係をチェックしてくれます. - - % gcc -MM *.c > depend - -などで作ることが出来ます.あって損は無いでしょう. - -== Makefileを生成する - -Makefileを実際に生成するためには - - ruby extconf.rb - -とします.extconf.rbに require 'mkmf' の行がない場合にはエラー -になりますので,引数を追加して - - ruby -r mkmf extconf.rb - -としてください. - -site_ruby ディレクトリでなく, -vendor_ruby ディレクトリにインストールする場合には -以下のように --vendor オプションを加えてください. - - ruby extconf.rb --vendor - -ディレクトリをext以下に用意した場合にはRuby全体のmakeの時に -自動的にMakefileが生成されますので,このステップは不要です. - -== makeする - -動的リンクライブラリを生成する場合にはその場でmakeしてくださ -い.必要であれば make install でインストールされます. - -ext以下にディレクトリを用意した場合は,Rubyのディレクトリで -makeを実行するとMakefileを生成からmake,必要によってはそのモ -ジュールのRubyへのリンクまで自動的に実行してくれます. -extconf.rbを書き換えるなどしてMakefileの再生成が必要な時はま -たRubyディレクトリでmakeしてください. - -拡張ライブラリはmake installでRubyライブラリのディレクトリの -下にコピーされます.もし拡張ライブラリと協調して使うRubyで記 -述されたプログラムがあり,Rubyライブラリに置きたい場合には, -拡張ライブラリ用のディレクトリの下に lib というディレクトリ -を作り,そこに 拡張子 .rb のファイルを置いておけば同時にイン -ストールされます. - -== デバッグ - -まあ,デバッグしないと動かないでしょうね.ext/Setupにディレ -クトリ名を書くと静的にリンクするのでデバッガが使えるようにな -ります.その分コンパイルが遅くなりますけど. - -== できあがり - -後はこっそり使うなり,広く公開するなり,売るなり,ご自由にお -使いください.Rubyの作者は拡張ライブラリに関して一切の権利を -主張しません. - -= Appendix A. Rubyのソースコードの分類 - -Rubyのソースはいくつかに分類することが出来ます.このうちクラ -スライブラリの部分は基本的に拡張ライブラリと同じ作り方になっ -ています.これらのソースは今までの説明でほとんど理解できると -思います. - -== Ruby言語のコア - -class.c :: クラスとモジュール -error.c :: 例外クラスと例外機構 -gc.c :: 記憶領域管理 -load.c :: ライブラリのロード -object.c :: オブジェクト -variable.c :: 変数と定数 - -== Rubyの構文解析器 - - parse.y : 字句解析器と構文定義 - -> parse.c : 自動生成 - keywords : 予約語 - -> lex.c : 自動生成 - -== Rubyの評価器 (通称YARV) - compile.c - eval.c - eval_error.c - eval_jump.c - eval_safe.c - insns.def : 仮想機械語の定義 - iseq.c : VM::ISeqの実装 - thread.c : スレッド管理とコンテキスト切り替え - thread_win32.c : スレッド実装 - thread_pthread.c : 同上 - vm.c - vm_dump.c - vm_eval.c - vm_exec.c - vm_insnhelper.c - vm_method.c - - opt_insns_unif.def : 命令融合 - opt_operand.def : 最適化のための定義 - - -> insn*.inc : 自動生成 - -> opt*.inc : 自動生成 - -> vm.inc : 自動生成 - -== 正規表現エンジン (鬼車) - - regex.c - regcomp.c - regenc.c - regerror.c - regexec.c - regparse.c - regsyntax.c - -== ユーティリティ関数 - -debug.c :: Cデバッガ用のデバッグシンボル -dln.c :: 動的ローディング -st.c :: 汎用ハッシュ表 -strftime.c :: 時刻整形 -util.c :: その他のユーティリティ - -== Rubyコマンドの実装 - - dmyext.c - dmydln.c - dmyencoding.c - id.c - inits.c - main.c - ruby.c - version.c - - gem_prelude.rb - prelude.rb - -== クラスライブラリ - -array.c :: Array -bignum.c :: Bignum -compar.c :: Comparable -complex.c :: Complex -cont.c :: Fiber, Continuation -dir.c :: Dir -enum.c :: Enumerable -enumerator.c :: Enumerator -file.c :: File -hash.c :: Hash -io.c :: IO -marshal.c :: Marshal -math.c :: Math -numeric.c :: Numeric, Integer, Fixnum, Float -pack.c :: Array#pack, String#unpack -proc.c :: Binding, Proc -process.c :: Process -random.c :: 乱数 -range.c :: Range -rational.c :: Rational -re.c :: Regexp, MatchData -signal.c :: Signal -sprintf.c :: String#sprintf -string.c :: String -struct.c :: Struct -time.c :: Time -defs/known_errors.def :: 例外クラス Errno::* --> known_errors.inc :: 自動生成 - -== 多言語化 - -encoding.c :: Encoding -transcode.c :: Encoding::Converter -enc/*.c :: エンコーディングクラス群 -enc/trans/* :: コードポイント対応表 - -== gorubyコマンドの実装 - - goruby.c - golf_prelude.rb : goruby固有のライブラリ - -> golf_prelude.c : 自動生成 - -= Appendix B. 拡張用関数リファレンス - -C言語からRubyの機能を利用するAPIは以下の通りである. - -== 型 - -VALUE :: - - Rubyオブジェクトを表現する型.必要に応じてキャストして用いる. - 組み込み型を表現するCの型はruby.hに記述してあるRで始まる構造 - 体である.VALUE型をこれらにキャストするためにRで始まる構造体 - 名を全て大文字にした名前のマクロが用意されている. - -== 変数・定数 - -Qnil :: - - 定数: nilオブジェクト - -Qtrue :: - - 定数: trueオブジェクト(真のデフォルト値) - -Qfalse :: - - 定数: falseオブジェクト - -== Cデータのカプセル化 - -Data_Wrap_Struct(VALUE klass, void (*mark)(), void (*free)(), void *sval) :: - - Cの任意のポインタをカプセル化したRubyオブジェクトを返す.こ - のポインタがRubyからアクセスされなくなった時,freeで指定した - 関数が呼ばれる.また,このポインタの指すデータが他のRubyオブ - ジェクトを指している場合,markに指定する関数でマークする必要 - がある. - -Data_Make_Struct(klass, type, mark, free, sval) :: - - type型のメモリをmallocし,変数svalに代入した後,それをカプセ - ル化したデータを返すマクロ. - -Data_Get_Struct(data, type, sval) :: - - dataからtype型のポインタを取り出し変数svalに代入するマクロ. - -== 型チェック - - TYPE(value) - FIXNUM_P(value) - NIL_P(value) - void Check_Type(VALUE value, int type) - SafeStringValue(value) - -== 型変換 - - FIX2INT(value), INT2FIX(i) - FIX2LONG(value), LONG2FIX(l) - NUM2INT(value), INT2NUM(i) - NUM2UINT(value), UINT2NUM(ui) - NUM2LONG(value), LONG2NUM(l) - NUM2ULONG(value), ULONG2NUM(ul) - NUM2LL(value), LL2NUM(ll) - NUM2ULL(value), ULL2NUM(ull) - NUM2OFFT(value), OFFT2NUM(off) - NUM2SIZET(value), SIZET2NUM(size) - NUM2SSIZET(value), SSIZET2NUM(ssize) - rb_integer_pack(value, words, numwords, wordsize, nails, flags), rb_integer_unpack(words, numwords, wordsize, nails, flags) - NUM2DBL(value) - rb_float_new(f) - RSTRING_LEN(str) - RSTRING_PTR(str) - StringValue(value) - StringValuePtr(value) - StringValueCStr(value) - rb_str_new2(s) - -== クラス/モジュール定義 - -VALUE rb_define_class(const char *name, VALUE super) :: - - superのサブクラスとして新しいRubyクラスを定義する. - -VALUE rb_define_class_under(VALUE module, const char *name, VALUE super) :: - - superのサブクラスとして新しいRubyクラスを定義し,moduleの - 定数として定義する. - -VALUE rb_define_module(const char *name) :: - - 新しいRubyモジュールを定義する. - -VALUE rb_define_module_under(VALUE module, const char *name) :: - - 新しいRubyモジュールを定義し,moduleの定数として定義する. - -void rb_include_module(VALUE klass, VALUE module) :: - - モジュールをインクルードする.classがすでにmoduleをインク - ルードしている時には何もしない(多重インクルードの禁止). - -void rb_extend_object(VALUE object, VALUE module) :: - - オブジェクトをモジュール(で定義されているメソッド)で拡張する. - -== 大域変数定義 - -void rb_define_variable(const char *name, VALUE *var) :: - - RubyとCとで共有するグローバル変数を定義する.変数名が`$'で - 始まらない時には自動的に追加される.nameとしてRubyの識別子 - として許されない文字(例えば` ')を含む場合にはRubyプログラ - ムからは見えなくなる. - -void rb_define_readonly_variable(const char *name, VALUE *var) :: - - RubyとCとで共有するread onlyのグローバル変数を定義する. - read onlyであること以外はrb_define_variable()と同じ. - -void rb_define_virtual_variable(const char *name, VALUE (*getter)(), void (*setter)()) :: - - 関数によって実現されるRuby変数を定義する.変数が参照された - 時にはgetterが,変数に値がセットされた時にはsetterが呼ばれ - る. - -void rb_define_hooked_variable(const char *name, VALUE *var, VALUE (*getter)(), void (*setter)()) :: - - 関数によってhookのつけられたグローバル変数を定義する.変数 - が参照された時にはgetterが,関数に値がセットされた時には - setterが呼ばれる.getterやsetterに0を指定した時にはhookを - 指定しないのと同じ事になる. - -void rb_global_variable(VALUE *var) - - GCのため,Rubyプログラムからはアクセスされないが, Rubyオブ - ジェクトを含む大域変数をマークする. - -== 定数 - -void rb_define_const(VALUE klass, const char *name, VALUE val) :: - - 定数を定義する. - -void rb_define_global_const(const char *name, VALUE val) :: - - 大域定数を定義する. - - rb_define_const(rb_cObject, name, val) - - と同じ意味. - -== メソッド定義 - -rb_define_method(VALUE klass, const char *name, VALUE (*func)(), int argc) :: - - メソッドを定義する.argcはselfを除く引数の数.argcが-1の時, - 関数には引数の数(selfを含まない)を第1引数, 引数の配列を第2 - 引数とする形式で与えられる(第3引数はself).argcが-2の時, - 第1引数がself, 第2引数がargs(argsは引数を含むRubyの配列)と - いう形式で与えられる. - -rb_define_private_method(VALUE klass, const char *name, VALUE (*func)(), int argc) :: - - privateメソッドを定義する.引数はrb_define_method()と同じ. - -rb_define_singleton_method(VALUE klass, const char *name, VALUE (*func)(), int argc) :: - - 特異メソッドを定義する.引数はrb_define_method()と同じ. - -rb_scan_args(int argc, VALUE *argv, const char *fmt, ...) :: - - argc, argv形式で与えられた指定されたフォーマットに従って引 - 数を分解し,続くVALUEへの参照にセットします.このフォーマッ - トは,ABNFで記述すると以下の通りです. - - scan-arg-spec := param-arg-spec [option-hash-arg-spec] [block-arg-spec] - - param-arg-spec := pre-arg-spec [post-arg-spec] / post-arg-spec / - pre-opt-post-arg-spec - pre-arg-spec := num-of-leading-mandatory-args [num-of-optional-args] - post-arg-spec := sym-for-variable-length-args - [num-of-trailing-mandatory-args] - pre-opt-post-arg-spec := num-of-leading-mandatory-args num-of-optional-args - num-of-trailing-mandatory-args - option-hash-arg-spec := sym-for-option-hash-arg - block-arg-spec := sym-for-block-arg - - num-of-leading-mandatory-args := DIGIT ; 先頭に置かれる省略不能な引数の数 - num-of-optional-args := DIGIT ; 続いて置かれる省略可能な引数の数 - sym-for-variable-length-args := "*" ; 続いて置かれる可変長引数を - ; Rubyの配列で取得するための指定 - num-of-trailing-mandatory-args := DIGIT ; 終端に置かれる省略不能な引数の数 - sym-for-option-hash-arg := ":" ; オプションハッシュを取得する - ; ための指定; 省略不能な引数の - ; 数よりも多くの引数が指定され, - ; 最後の引数がハッシュ(または - ; #to_hashで変換可能)の場合に - ; 取得される.最後の引数がnilの - ; 場合,可変長引数指定がなく, - ; 省略不能引数の数よりも多くの - ; 引数が指定された場合に取得される - sym-for-block-arg := "&" ; イテレータブロックを取得するための - ; 指定 - - フォーマットが"12"の場合,引数は最低1つで,3つ(1+2)まで許さ - れるという意味になります.従って,フォーマット文字列に続い - て3つのVALUEへの参照を置く必要があります.それらには取得した - 変数がセットされます.変数への参照の代わりにNULLを指定する - こともでき,その場合は取得した引数の値は捨てられます.なお, - 省略可能引数が省略された時の変数の値はnil(C言語のレベルでは - Qnil)になります. - - 返り値は与えられた引数の数です.オプションハッシュおよびイ - テレータブロックは数えません. - -int rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, VALUE *values) - - キーワードで指定された値をtableにしたがって取り出します. - tableの最初のrequired個のIDは必須キーワードを表し,続く - optional (optionalが負の場合は-optional-1) 個のIDは省略可能 - キーワードです.必須キーワードがkeyword_hash中にない場合, - "missing keyword"ArgumentErrorが発生します.省略可能キーワー - ドがない場合は,values中の対応する要素は変更されません. - keyword_hashに使用されない要素がある場合は,optionalが負なら - 新しいHashとして省略可能引数の次に保存されますが,そうでなけ - れば"unknown keyword"ArgumentErrorが発生します. - -VALUE rb_extract_keywords(VALUE *original_hash) - - original_hashで参照されるHashオブジェクトから,Symbolである - キーとその値を新しいHashに取り出します.original_hashの指す - 先には,元のHashがSymbol以外のキーを含んでいた場合はそれらが - コピーされた別の新しいHash,そうでなければ0が保存されます. - -== Rubyメソッド呼び出し - -VALUE rb_funcall(VALUE recv, ID mid, int narg, ...) :: - - メソッド呼び出し.文字列からmidを得るためにはrb_intern()を - 使う. - private/protectedなメソッドでも呼び出せる. - -VALUE rb_funcall2(VALUE recv, ID mid, int argc, VALUE *argv) :: -VALUE rb_funcallv(VALUE recv, ID mid, int argc, VALUE *argv) :: - - メソッド呼び出し.引数をargc, argv形式で渡す. - private/protectedなメソッドでも呼び出せる. - -VALUE rb_funcallv_public(VALUE recv, ID mid, int argc, VALUE *argv) :: - - メソッド呼び出し. - publicなメソッドしか呼べない. - -VALUE rb_eval_string(const char *str) - - 文字列をRubyスクリプトとしてコンパイル・実行する. - -ID rb_intern(const char *name) :: - - 文字列に対応するIDを返す. - -char *rb_id2name(ID id) :: - - IDに対応する文字列を返す(デバッグ用). - -char *rb_class2name(VALUE klass) :: - - クラスの名前を返す(デバッグ用).クラスが名前を持たない時に - は, 祖先を遡って名前を持つクラスの名前を返す. - -int rb_respond_to(VALUE obj, ID id) :: - - objがidで示されるメソッドを持つかどうかを返す. - -== インスタンス変数 - -VALUE rb_iv_get(VALUE obj, const char *name) :: - - objのインスタンス変数の値を得る.`@'で始まらないインスタン - ス変数は Rubyプログラムからアクセスできない「隠れた」イン - スタンス変数になる.定数は大文字の名前を持つクラス(または - モジュール)のインスタンス変数として実装されている. - -VALUE rb_iv_set(VALUE obj, const char *name, VALUE val) :: - - objのインスタンス変数をvalにセットする. - -== 制御構造 - -VALUE rb_block_call(VALUE obj, ID mid, int argc, VALUE * argv, VALUE (*func) (ANYARGS), VALUE data2) :: - - funcをブロックとして設定し,objをレシーバ,argcとargvを引数 - としてmidメソッドを呼び出す.funcは第一引数にyieldされた値, - 第二引数にdata2を受け取る.複数の値がyieldされた場合(Cでは - rb_yield_values()とrb_yield_values2(), rb_yield_splat()), - data2はArrayとしてパックされている.第三, 第四引数のargcと - argvによってyieldされた値を取り出すことができる. - -[OBSOLETE] VALUE rb_iterate(VALUE (*func1)(), VALUE arg1, VALUE (*func2)(), VALUE arg2) :: - - func2をブロックとして設定し, func1をイテレータとして呼ぶ. - func1には arg1が引数として渡され, func2には第1引数にイテレー - タから与えられた値, 第2引数にarg2が渡される. - - 1.9でrb_iterateを使う場合は, func1の中でRubyレベルのメソッド - を呼び出さなければならない. - 1.9でobsoleteとなった. 代わりにrb_block_callが用意された. - -VALUE rb_yield(VALUE val) :: - - valを値としてイテレータブロックを呼び出す. - -VALUE rb_rescue(VALUE (*func1)(), VALUE arg1, VALUE (*func2)(), VALUE arg2) :: - - 関数func1をarg1を引数に呼び出す.func1の実行中に例外が発生 - した時には func2をarg2を引数として呼ぶ.戻り値は例外が発生 - しなかった時はfunc1の戻り値, 例外が発生した時にはfunc2の戻 - り値である. - -VALUE rb_ensure(VALUE (*func1)(), VALUE arg1, VALUE (*func2)(), VALUE arg2) :: - - 関数func1をarg1を引数として実行し, 実行終了後(たとえ例外が - 発生しても) func2をarg2を引数として実行する.戻り値はfunc1 - の戻り値である(例外が発生した時は戻らない). - -VALUE rb_protect(VALUE (*func) (VALUE), VALUE arg, int *state) :: - - 関数funcをargを引数として実行し, 例外が発生しなければその戻 - り値を返す.例外が発生した場合は, *stateに非0をセットして - Qnilを返す. - rb_jump_tag()を呼ばずに捕捉した例外を無視する場合には, - rb_set_errinfo(Qnil)でエラー情報をクリアしなければならない. - -void rb_jump_tag(int state) :: - - rb_protect()やrb_eval_string_protect()で捕捉された例外を再 - 送する.stateはそれらの関数から返された値でなければならない. - この関数は直接の呼び出し元に戻らない. - -void rb_iter_break() :: - - 現在の最も内側のブロックを終了する.この関数は直接の呼び出 - し元に戻らない. - -void rb_iter_break_value(VALUE value) :: - - 現在の最も内側のブロックをvalueで終了する.ブロックは引数で - 与えられたvalueを返す.この関数は直接の呼び出し元に戻らない. - -== 例外・エラー - -void rb_warning(const char *fmt, ...) :: - - rb_verbose時に標準エラー出力に警告情報を表示する.引数は - printf()と同じ. - -void rb_raise(rb_eRuntimeError, const char *fmt, ...) :: - - RuntimeError例外を発生させる.引数はprintf()と同じ. - -void rb_raise(VALUE exception, const char *fmt, ...) :: - - exceptionで指定した例外を発生させる.fmt以下の引数は - printf()と同じ. - -void rb_fatal(const char *fmt, ...) :: - - 致命的例外を発生させる.通常の例外処理は行なわれず, インター - プリタが終了する(ただしensureで指定されたコードは終了前に - 実行される). - -void rb_bug(const char *fmt, ...) :: - - インタープリタなどプログラムのバグでしか発生するはずのない - 状況の時呼ぶ.インタープリタはコアダンプし直ちに終了する. - 例外処理は一切行なわれない. - -注意: "%"PRIsVALUEがObject#to_s('+'フラグが指定されていると -きはObject#inspect)を使ったVALUEの出力に利用できる.これは -"%i"と衝突するため,整数には"%d"を使用すること. - -== Rubyの初期化・実行 - -Rubyをアプリケーションに埋め込む場合には以下のインタフェース -を使う.通常の拡張ライブラリには必要ない. - -void ruby_init() :: - - Rubyインタプリタの初期化を行なう. - -void *ruby_options(int argc, char **argv) :: - - Rubyインタプリタのコマンドライン引数の処理を行ない, - Rubyのソースコードをコンパイルする. - コンパイルされたソースへのポインタ,もしくは特殊値を返す. - -int ruby_run_node(void *n) :: - - コンパイルされたコードを実行する. - 実行に成功した場合はEXIT_SUCCESSを,エラーが起こったときはそれ以外を返す. - -void ruby_script(char *name) :: - - Rubyのスクリプト名($0)を設定する. - -== インタプリタのイベントのフック - - void rb_add_event_hook(rb_event_hook_func_t func, rb_event_flag_t events, - VALUE data) - -指定されたインタプリタのイベントに対するフック関数を追加します. -eventsは以下の値のorでなければなりません: - - RUBY_EVENT_LINE - RUBY_EVENT_CLASS - RUBY_EVENT_END - RUBY_EVENT_CALL - RUBY_EVENT_RETURN - RUBY_EVENT_C_CALL - RUBY_EVENT_C_RETURN - RUBY_EVENT_RAISE - RUBY_EVENT_ALL - -rb_event_hook_func_tの定義は以下の通りです: - - typedef void (*rb_event_hook_func_t)(rb_event_t event, VALUE data, - VALUE self, ID id, VALUE klass) - -rb_add_event_hook() の第3引数 data は,フック関数の第2引数と -して渡されます.これは1.8では現在のNODEへのポインタでした.以 -下の RB_EVENT_HOOKS_HAVE_CALLBACK_DATA も参照してください. - - int rb_remove_event_hook(rb_event_hook_func_t func) - -指定されたフック関数を削除します. - -== 互換性のためのマクロ - -APIの互換性をチェックするために以下のマクロがデフォルトで定義されています. - -NORETURN_STYLE_NEW :: - - NORETURN マクロが関数型マクロとして定義されていることを意味する. - -HAVE_RB_DEFINE_ALLOC_FUNC :: - - rb_define_alloc_func() 関数が提供されていること,つまり - allocation framework が使われることを意味する. - have_func("rb_define_alloc_func", "ruby.h") - の結果と同じ. - -HAVE_RB_REG_NEW_STR :: - - StringオブジェクトからRegexpオブジェクトを作る - rb_reg_new_str() 関数が提供されていることを意味する. - have_func("rb_reg_new_str", "ruby.h"). - の結果と同じ. - -HAVE_RB_IO_T :: - - rb_io_t 型が提供されていることを意味する. - -USE_SYMBOL_AS_METHOD_NAME :: - - メソッド名を返すメソッド,Module#methods, #singleton_methods - などがSymbolを返すことを意味する. - -HAVE_RUBY_*_H :: - - ruby.h で定義されている.対応するヘッダが提供されていること - を意味する.たとえば,HAVE_RUBY_ST_H が定義されている場合は - 単なる st.h ではなく ruby/st.h を使用する. - -RB_EVENT_HOOKS_HAVE_CALLBACK_DATA :: - - rb_add_event_hook() がフック関数に渡す data を第3引数として - 受け取ることを意味する. - -= Appendix C. extconf.rbで使える関数たち - -extconf.rbの中では利用可能なコンパイル条件チェックの関数は以 -下の通りである. - -have_macro(macro, headers) :: - - ヘッダファイルheaderをインクルードしてマクロmacroが定義さ - れているかどうかチェックする.マクロが定義されている時true - を返す. - -have_library(lib, func) :: - - 関数funcを定義しているライブラリlibの存在をチェックする. - チェックに成功すると,-llibを$libsに追加し,trueを返す. - -find_library(lib, func, path...) :: - - 関数funcを定義しているライブラリlibの存在を -Lpath を追加 - しながらチェックする.チェックに成功すると,-llibを$libsに - 追加し,trueを返す. - -have_func(func, header) :: - - ヘッダファイルheaderをインクルードして関数funcの存在をチェ - ックする.funcが標準ではリンクされないライブラリ内のもので - ある時には先にhave_libraryでそのライブラリをチェックしてお - く事.チェックに成功すると,プリプロセッサマクロ - `HAVE_{FUNC}` を定義し,trueを返す. - -have_var(var, header) :: - - ヘッダファイルheaderをインクルードして変数varの存在をチェッ - クする.varが標準ではリンクされないライブラリ内のものであ - る時には先にhave_libraryでそのライブラリをチェックしておく - 事.チェックに成功すると,プリプロセッサマクロ - `HAVE_{VAR}` を定義し,trueを返す. - -have_header(header) :: - - ヘッダファイルの存在をチェックする.チェックに成功すると, - プリプロセッサマクロ `HAVE_{HEADER_H}` を定義し,trueを返す. - (スラッシュやドットはアンダースコアに置換される) - -find_header(header, path...) :: - - ヘッダファイルheaderの存在を -Ipath を追加しながらチェック - する.チェックに成功すると,プリプロセッサマクロ - `HAVE_{HEADER_H}` を定義し,trueを返す. - (スラッシュやドットはアンダースコアに置換される) - -have_struct_member(type, member[, header[, opt]]) :: - - ヘッダファイルheaderをインクルードして型typeが定義され, - なおかつメンバmemberが存在するかをチェックする.チェックに - 成功すると,プリプロセッサマクロ `HAVE_{TYPE}_{MEMBER}` を - 定義し,trueを返す. - -have_type(type, header, opt) :: - - ヘッダファイルheaderをインクルードして型typeが存在するかを - チェックする.チェックに成功すると,プリプロセッサマクロ - `HAVE_TYPE_{TYPE}` を定義し,trueを返す. - -check_sizeof(type, header) :: - - ヘッダファイルheaderをインクルードして型typeのchar単位サイ - ズを調べる.チェックに成功すると,プリプロセッサマクロ - `SIZEOF_{TYPE}` を定義し,そのサイズを返す.定義されていな - いときはnilを返す. - -create_makefile(target[, target_prefix]) :: - - 拡張ライブラリ用のMakefileを生成する.この関数を呼ばなけれ - ばそのライブラリはコンパイルされない.targetはモジュール名 - を表す. - -find_executable(command, path) :: - - コマンドcommandをFile::PATH_SEPARATORで区切られたパス名の - リストpathから探す.pathがnilまたは省略された場合は,環境 - 変数PATHの値を使用する.実行可能なコマンドが見つかった場合 - はパスを含むファイル名,見つからなかった場合はnilを返す. - -with_config(withval[, default=nil]) :: - - コマンドライン上の--with-で指定されたオプション値 - を得る. - -enable_config(config, *defaults) :: -disable_config(config, *defaults) :: - - コマンドライン上の--enable-または - --disable-で指定された真偽値を得る. - --enable-が指定されていた場合はtrue, - --disable-が指定されていた場合はfalseを返す. - どちらも指定されていない場合は,ブロックつきで呼び出されて - いる場合は*defaultsをyieldした結果,ブロックなしなら - *defaultsを返す. - -dir_config(target[, default_dir]) :: -dir_config(target[, default_include, default_lib]) :: - - コマンドライン上の--with--dir, --with--include, - --with--libのいずれかで指定されるディレクトリを - $CFLAGS や $LDFLAGS に追加する.--with--dir=/pathは - --with--include=/path/include --with--lib=/path/lib - と等価である.追加された include ディレクトリと lib ディレ - クトリの配列を返す. ([include_dir, lib_dir]) - -pkg_config(pkg, option=nil) :: - - pkg-configコマンドからパッケージpkgの情報を [cflags, ldflags, libs] - の配列として得る.$CFLAGS, $LDFLAGS, $libs にはそれぞれの値が - 追加される. - - pkg-configの実際のコマンドは,以下の順で試される. - - 1. コマンドラインで--with-{pkg}-config={command}オプションが - 指定された場合: {command} {option} - 2. {pkg}-config {option} - 3. pkg-config {option} {pkg} - - optionが指定された場合は,上記の配列の代わりにそのオプションを - 指定して得られた出力をstripしたものを返す. - -= Appendix D. 世代別GC - -Ruby 2.1から世代別GCに対応しました.我々はこれをRGenGCと呼んでいます. -RGenGCは,過去の拡張ライブラリに(ほぼ)互換性を保つように開発されている -ため,拡張ライブラリ側の対応はほぼ不要です. - -ただし,対応をすることで性能を向上することができる可能性があります.もし -拡張ライブラリに高い性能が必要である場合は対応を検討して下さい. - -とくにRARRAY_PTR()/RHASH_TBL()のようなマクロを用いてポインタに直接アクセ -スするようなコードは書かないようにして下さい.代わりに,rb_ary_aref(), -rb_ary_store() などの,適切な API 関数を利用するようにして下さい. - -そのほか,対応についての詳細は README.EXT の「Appendix D. Generational -GC」を参照して下さい. - -/* - * Local variables: - * fill-column: 60 - * end: - */ diff --git a/doc/extention.ja.rdoc b/doc/extention.ja.rdoc new file mode 100644 index 0000000000..f4255ebb69 --- /dev/null +++ b/doc/extention.ja.rdoc @@ -0,0 +1,1719 @@ +# README.EXT.ja - -*- RDoc -*- created at: Mon Aug 7 16:45:54 JST 1995 + +Rubyの拡張ライブラリの作り方を説明します. + += 基礎知識 + +Cの変数には型があり,データには型がありません.ですから,た +とえばポインタをintの変数に代入すると,その値は整数として取 +り扱われます.逆にRubyの変数には型がなく,データに型がありま +す.この違いのため,CとRubyは相互に変換しなければ,お互いの +データをアクセスできません. + +RubyのデータはVALUEというCの型で表現されます.VALUE型のデー +タはそのデータタイプを自分で知っています.このデータタイプと +いうのはデータ(オブジェクト)の実際の構造を意味していて,Ruby +のクラスとはまた違ったものです. + +VALUEからCにとって意味のあるデータを取り出すためには + +1. VALUEのデータタイプを知る +2. VALUEをCのデータに変換する + +の両方が必要です.(1)を忘れると間違ったデータの変換が行われ +て,最悪プログラムがcore dumpします. + +== データタイプ + +Rubyにはユーザが使う可能性のある以下のタイプがあります. + +T_NIL :: nil +T_OBJECT :: 通常のオブジェクト +T_CLASS :: クラス +T_MODULE :: モジュール +T_FLOAT :: 浮動小数点数 +T_STRING :: 文字列 +T_REGEXP :: 正規表現 +T_ARRAY :: 配列 +T_HASH :: 連想配列 +T_STRUCT :: (Rubyの)構造体 +T_BIGNUM :: 多倍長整数 +T_FIXNUM :: Fixnum(31bitまたは63bit長整数) +T_COMPLEX :: 複素数 +T_RATIONAL :: 有理数 +T_FILE :: 入出力 +T_TRUE :: 真 +T_FALSE :: 偽 +T_DATA :: データ +T_SYMBOL :: シンボル + +その他に内部で利用されている以下のタイプがあります. + + T_ICLASS + T_MATCH + T_UNDEF + T_NODE + T_ZOMBIE + +ほとんどのタイプはCの構造体で実装されています. + +== VALUEのデータタイプをチェックする + +ruby.hではTYPE()というマクロが定義されていて,VALUEのデータ +タイプを知ることが出来ます.TYPE()マクロは上で紹介したT_XXXX +の形式の定数を返します.VALUEのデータタイプに応じて処理する +場合には,TYPE()の値で分岐することになります. + + switch (TYPE(obj)) { + case T_FIXNUM: + /* FIXNUMの処理 */ + break; + case T_STRING: + /* 文字列の処理 */ + break; + case T_ARRAY: + /* 配列の処理 */ + break; + default: + /* 例外を発生させる */ + rb_raise(rb_eTypeError, "not valid value"); + break; + } + +それとデータタイプをチェックして,正しくなければ例外を発生す +る関数が用意されています. + + void Check_Type(VALUE value, int type) + +この関数はvalueがtypeで無ければ,例外を発生させます.引数と +して与えられたVALUEのデータタイプが正しいかどうかチェックす +るためには,この関数を使います. + +FIXNUMとNILに関してはより高速な判別マクロが用意されています. + + FIXNUM_P(obj) + NIL_P(obj) + +== VALUEをCのデータに変換する + +データタイプがT_NIL,T_FALSE,T_TRUEである時,データはそれぞ +れnil,false,trueです.このデータタイプのオブジェクトはひと +つずつしか存在しません. + +データタイプがT_FIXNUMの時,これは31bitまたは63bitのサイズを +持つ整数です.longのサイズが32bitのプラットフォームであれば +31bitに,longのサイズが64bitのプラットフォームであれば63bit +になります. FIXNUM を C の整数に変換するためにはマクロ +「FIX2INT()」または「FIX2LONG()」を使います.これらのマクロ +を使用する際には事前にデータタイプがFIXNUMであることを確認す +る必要がありますが,比較的高速に変換を行うことができます.ま +た,「FIX2LONG()」は例外を発生しませんが,「FIX2INT()」は変 +換結果がintのサイズに収まらない場合には例外を発生します. +それから,FIXNUMに限らずRubyのデータを整数に変換する +「NUM2INT()」および「NUM2LONG()」というマクロがあります.こ +れらのマクロはデータタイプのチェック無しで使えます +(整数に変換できない場合には例外が発生する).同様にチェック無し +で使える変換マクロはdoubleを取り出す「NUM2DBL()」があります. + +char* を取り出す場合, StringValue() と StringValuePtr() +を使います. +StringValue(var) は var が String +であれば何もせず,そうでなければ var を var.to_str() の結果 +に置き換えるマクロ,StringValuePtr(var) は同様に var を +String に置き換えてから var のバイト列表現に対する char* を +返すマクロです.var の内容を直接置き換える処理が入るので, +var は lvalue である必要があります. +また,StringValuePtr() に類似した StringValueCStr() というマ +クロもあります.StringValueCStr(var) は var を String に置き +換えてから var の文字列表現に対する char* を返します.返され +る文字列の末尾には nul 文字が付加されます.なお,途中に nul +文字が含まれる場合は ArgumentError が発生します. +一方,StringValuePtr() では,末尾に nul 文字がある保証はなく, +途中に nul 文字が含まれている可能性もあります. + +それ以外のデータタイプは対応するCの構造体があります.対応す +る構造体のあるVALUEはそのままキャスト(型変換)すれば構造体の +ポインタに変換できます. + +構造体は「struct RXxxxx」という名前でruby.hで定義されていま +す.例えば文字列は「struct RString」です.実際に使う可能性が +あるのは文字列と配列くらいだと思います. + +ruby.hでは構造体へキャストするマクロも「RXXXXX()」(全部大文 +字にしたもの)という名前で提供されています(例: RSTRING()).た +だし、構造体への直接のアクセスはできるだけ避け,対応する +rb_xxxx() といった関数を使うようにして下さい.例えば,配列の +要素へアクセスする場合は,rb_ary_entry(ary, offset), +rb_ary_store(ary, offset, obj) を利用するようにして下さい. + +構造体からデータを取り出すマクロが提供されています.文字列 +strの長さを得るためには「RSTRING_LEN(str)」とし,文字列strを +char*として得るためには「RSTRING_PTR(str)」とします. + +Rubyの構造体を直接アクセスする時に気をつけなければならないこ +とは,配列や文字列の構造体の中身は参照するだけで,直接変更し +ないことです.直接変更した場合,オブジェクトの内容の整合性が +とれなくなって,思わぬバグの原因になります. + +== CのデータをVALUEに変換する + +VALUEの実際の構造は + +FIXNUMの場合 :: + + 1bit左シフトして,LSBを立てる. + +その他のポインタの場合 :: + + そのままVALUEにキャストする. + +となっています.よって,LSBをチェックすればVALUEがFIXNUMかど +うかわかるわけです(ポインタのLSBが立っていないことを仮定して +いる). + +ですから,FIXNUM以外のRubyのオブジェクトの構造体は単にVALUE +にキャストするだけでVALUEに変換出来ます.ただし,任意の構造 +体がVALUEにキャスト出来るわけではありません.キャストするの +はRubyの知っている構造体(ruby.hで定義されているstruct RXxxx +のもの)だけです. + +FIXNUMに関しては変換マクロを経由する必要があります.Cの整数 +からVALUEに変換するマクロは以下のものがあります.必要に応じ +て使い分けてください. + +INT2FIX() :: もとの整数が31bitまたは63bit以内に収まる自信 + がある時 +INT2NUM() :: 任意の整数からVALUEへ + +INT2NUM()は整数がFIXNUMの範囲に収まらない場合,Bignumに変換 +してくれます(が,少し遅い). + +== Rubyのデータを操作する + +先程も述べた通り,Rubyの構造体をアクセスする時に内容の更新を +行うことは勧められません.で,Rubyのデータを操作する時には +Rubyが用意している関数を用いてください. + +ここではもっとも使われるであろう文字列と配列の生成/操作を行 +う関数をあげます(全部ではないです). + +=== 文字列に対する関数 + +rb_str_new(const char *ptr, long len) :: + + 新しいRubyの文字列を生成する. + +rb_str_new2(const char *ptr) +rb_str_new_cstr(const char *ptr) + + Cの文字列からRubyの文字列を生成する.この関数の機能は + rb_str_new(ptr, strlen(ptr))と同等である. + +rb_str_new_literal(const char *ptr) + + Cのリテラル文字列からRubyの文字列を生成する. + +rb_tainted_str_new(const char *ptr, long len) + + 汚染マークが付加された新しいRubyの文字列を生成する.外部 + からのデータに基づく文字列には汚染マークが付加されるべき + である. + +rb_tainted_str_new2(const char *ptr) +rb_tainted_str_new_cstr(const char *ptr) + + Cの文字列から汚染マークが付加されたRubyの文字列を生成する. + +rb_sprintf(const char *format, ...) +rb_vsprintf(const char *format, va_list ap) + + Cの文字列formatと続く引数をprintf(3)のフォーマットにしたがって + 整形し,Rubyの文字列を生成する. + + 注意: "%"PRIsVALUEがObject#to_s('+'フラグが指定されている + ときはObject#inspect)を使ったVALUEの出力に利用できる.これ + は"%i"と衝突するため,整数には"%d"を使用すること. + +rb_str_cat(VALUE str, const char *ptr, long len) + + Rubyの文字列strにlenバイトの文字列ptrを追加する. + +rb_str_cat2(VALUE str, const char* ptr) +rb_str_cat_cstr(VALUE str, const char* ptr) + + Rubyの文字列strにCの文字列ptrを追加する.この関数の機能は + rb_str_cat(str, ptr, strlen(ptr))と同等である. + +rb_str_catf(VALUE str, const char* format, ...) +rb_str_vcatf(VALUE str, const char* format, va_list ap) + + Cの文字列formatと続く引数をprintf(3)のフォーマットにしたがって + 整形し,Rubyの文字列strに追加する.この関数の機能は,それぞれ + rb_str_cat2(str, rb_sprintf(format, ...)) や + rb_str_cat2(str, rb_vsprintf(format, ap)) と同等である. + +rb_enc_str_new(const char *ptr, long len, rb_encoding *enc) +rb_enc_str_new_cstr(const char *ptr, rb_encoding *enc) + + 指定されたエンコーディングでRubyの文字列を生成する. + +rb_enc_str_new_literal(const char *ptr) + + Cのリテラル文字列から指定されたエンコーディングでRubyの文字列を生成する. + +rb_usascii_str_new(const char *ptr, long len) +rb_usascii_str_new_cstr(const char *ptr) + + エンコーディングがUS-ASCIIのRubyの文字列を生成する. + +rb_usascii_str_new_literal(const char *ptr) + + Cのリテラル文字列からエンコーディングがUS-ASCIIのRubyの文字列を生成する. + +rb_utf8_str_new(const char *ptr, long len) +rb_utf8_str_new_cstr(const char *ptr) + + エンコーディングがUTF-8のRubyの文字列を生成する. + +rb_usascii_str_new_literal(const char *ptr) + + Cのリテラル文字列からエンコーディングがUTF-8のRubyの文字列を生成する. + +rb_str_resize(VALUE str, long len) + + Rubyの文字列のサイズをlenバイトに変更する.strの長さは前 + 以てセットされていなければならない.lenが元の長さよりも短 + い時は,lenバイトを越えた部分の内容は捨てられる.lenが元 + の長さよりも長い時は,元の長さを越えた部分の内容は保存さ + れないでゴミになるだろう.この関数の呼び出しによって + RSTRING_PTR(str)が変更されるかもしれないことに注意. + +rb_str_set_len(VALUE str, long len) + + Rubyの文字列のサイズをlenバイトにセットする.strが変更可 + 能でなければ例外が発生する.RSTRING_LEN(str)とは無関係に, + lenバイトまでの内容は保存される.lenはstrの容量を越えてい + てはならない. + + +== 配列に対する関数 + +rb_ary_new() + + 要素が0の配列を生成する. + +rb_ary_new2(long len) +rb_ary_new_capa(long len) + + 要素が0の配列を生成する.len要素分の領域をあらかじめ割り + 当てておく. + +rb_ary_new3(long n, ...) +rb_ary_new_from_args(long n, ...) + + 引数で指定したn要素を含む配列を生成する. + +rb_ary_new4(long n, VALUE *elts) +rb_ary_new_from_values(long n, VALUE *elts) + + 配列で与えたn要素の配列を生成する. + +rb_ary_to_ary(VALUE obj) + + オブジェクトを配列に変換する. + Object#to_aryと同等である. + +他にも配列を操作する関数が多数ある. これらは +引数aryに配列を渡さなければならない. さもないと +コアを吐く. + +rb_ary_aref(argc, VALUE *argv, VALUE ary) + + Array#[]と同等. + +rb_ary_entry(VALUE ary, long offset) + + ary[offset] + +rb_ary_store(VALUE ary, long offset, VALUE obj) :: + + ary[offset] = obj + +rb_ary_subseq(VALUE ary, long beg, long len) + + ary[beg, len] + +rb_ary_push(VALUE ary, VALUE val) +rb_ary_pop(VALUE ary) +rb_ary_shift(VALUE ary) +rb_ary_unshift(VALUE ary, VALUE val) + +rb_ary_cat(VALUE ary, const VALUE *ptr, long len) + + 配列aryにptrからlen個のオブジェクトを追加する. + += Rubyの機能を使う + +原理的にRubyで書けることはCでも書けます.RubyそのものがCで記 +述されているんですから,当然といえば当然なんですけど.ここで +はRubyの拡張に使うことが多いだろうと予測される機能を中心に紹 +介します. + +== Rubyに機能を追加する + +Rubyで提供されている関数を使えばRubyインタプリタに新しい機能 +を追加することができます.Rubyでは以下の機能を追加する関数が +提供されています. + +* クラス,モジュール +* メソッド,特異メソッドなど +* 定数 + +では順に紹介します. + +=== クラス/モジュール定義 + +クラスやモジュールを定義するためには,以下の関数を使います. + + VALUE rb_define_class(const char *name, VALUE super) + VALUE rb_define_module(const char *name) + +これらの関数は新しく定義されたクラスやモジュールを返します. +メソッドや定数の定義にこれらの値が必要なので,ほとんどの場合 +は戻り値を変数に格納しておく必要があるでしょう. + +クラスやモジュールを他のクラスの内部にネストして定義する時に +は以下の関数を使います. + + VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super) + VALUE rb_define_module_under(VALUE outer, const char *name) + +=== メソッド/特異メソッド定義 + +メソッドや特異メソッドを定義するには以下の関数を使います. + + void rb_define_method(VALUE klass, const char *name, + VALUE (*func)(), int argc) + + void rb_define_singleton_method(VALUE object, const char *name, + VALUE (*func)(), int argc) + + +念のため説明すると「特異メソッド」とは,その特定のオブジェク +トに対してだけ有効なメソッドです.RubyではよくSmalltalkにお +けるクラスメソッドとして,クラスに対する特異メソッドが使われ +ます. + +これらの関数の argcという引数はCの関数へ渡される引数の数(と +形式)を決めます.argcが0以上の時は関数に引き渡す引数の数を意 +味します.16個以上の引数は使えません(が,要りませんよね,そ +んなに).実際の関数には先頭の引数としてselfが与えられますの +で,指定した数より1多い引数を持つことになります. + +argcが負の時は引数の数ではなく,形式を指定したことになります. +argcが-1の時は引数を配列に入れて渡されます.argcが-2の時は引 +数はRubyの配列として渡されます. + +メソッドを定義する関数はまだいくつかあります. ひとつはメソッド +名としてIDを取ります. IDについては2.2.2を参照. + + void rb_define_method_id(VALUE klass, ID name, + VALUE (*func)(ANYARGS), int argc) + +private/protectedなメソッドを定義するふたつの関数があります. + + void rb_define_private_method(VALUE klass, const char *name, + VALUE (*func)(), int argc) + void rb_define_protected_method(VALUE klass, const char *name, + VALUE (*func)(), int argc) + +privateメソッドとは関数形式でしか呼び出すことの出来ないメソッ +ドです. + +最後に, rb_define_module関数はモジュール関数を定義します. +モジュール関数とはモジュールの特異メソッドであり,同時に +privateメソッドでもあるものです.例をあげるとMathモジュール +のsqrt()などがあげられます.このメソッドは + + Math.sqrt(4) + +という形式でも + + include Math + sqrt(4) + +という形式でも使えます.モジュール関数を定義する関数は以下の +通りです. + + void rb_define_module_function(VALUE module, const char *name, + VALUE (*func)(), int argc) + +関数的メソッド(Kernelモジュールのprivate method)を定義するた +めの関数は以下の通りです. + + void rb_define_global_function(const char *name, VALUE (*func)(), int argc) + + +メソッドの別名を定義するための関数は以下の通りです. + + void rb_define_alias(VALUE module, const char* new, const char* old); + +属性の取得・設定メソッドを定義するには + + void rb_define_attr(VALUE klass, const char *name, int read, int write) + +クラスメソッドallocateを定義したり削除したりするための関数は +以下の通りです. + + void rb_define_alloc_func(VALUE klass, VALUE (*func)(VALUE klass)); + void rb_undef_alloc_func(VALUE klass); + +funcはクラスを引数として受け取って,新しく割り当てられたイン +スタンスを返さなくてはなりません.このインスタンスは,外部リ +ソースなどを含まない,できるだけ「空」のままにしておいたほう +がよいでしょう. + +継承したクラスにある既存のメソッドをオーバーライドしているな +ら,オーバーライドされたメソッドを呼び出すには以下の関数を使 +います. + + VALUE rb_call_super(int argc, const VALUE *argv) + +現在のスコープのレシーバは(他に方法がなければ),以下の関数で +得ることができます. + + VALUE rb_current_receiver(void) + +=== 定数定義 + +拡張ライブラリが必要な定数はあらかじめ定義しておいた方が良い +でしょう.定数を定義する関数は二つあります. + + void rb_define_const(VALUE klass, const char *name, VALUE val) + void rb_define_global_const(const char *name, VALUE val) + +前者は特定のクラス/モジュールに属する定数を定義するもの,後 +者はグローバルな定数を定義するものです. + +== Rubyの機能をCから呼び出す + +既に『1.5 Rubyのデータを操作する』で一部紹介したような関数を +使えば,Rubyの機能を実現している関数を直接呼び出すことが出来 +ます. + +# このような関数の一覧表はいまのところありません.ソースを見 +# るしかないですね. + +それ以外にもRubyの機能を呼び出す方法はいくつかあります. + +=== Rubyのプログラムをevalする + +CからRubyの機能を呼び出すもっとも簡単な方法として,文字列で +与えられたRubyのプログラムを評価する以下の関数があります. + + VALUE rb_eval_string(const char *str) + +この評価は現在の環境で行われます.つまり,現在のローカル変数 +などを受け継ぎます. + +評価は例外を発生するかもしれないことに注意しましょう. より安全 +な関数もあります. + + VALUE rb_eval_string_protect(const char *str, int *state) + +この関数はエラーが発生するとnilを返します.そして,成功時には +*stateはゼロに,さもなくば非ゼロになります. + +=== IDまたはシンボル + +Cから文字列を経由せずにRubyのメソッドを呼び出すこともできま +す.その前に,Rubyインタプリタ内でメソッドや変数名を指定する +時に使われているIDについて説明しておきましょう. + +IDとは変数名,メソッド名を表す整数です.Rubyの中では + + :識別子 + +または + + :"任意の文字列" + +でアクセスできます.Cからこの整数を得るためには関数 + + rb_intern(const char *name) + rb_intern_str(VALUE name) + +を使います.Rubyから引数として与えられたシンボル(または文字 +列)をIDに変換するには以下の関数を使います. + + rb_to_id(VALUE symbol) + rb_check_id(volatile VALUE *name) + rb_check_id_cstr(const char *name, long len, rb_encoding *enc) + +もし引数がシンボルでも文字列でもなければ,to_strメソッドで文 +字列に変換しようとします.第二の関数はその変換結果を*nameに保 +存し,その名前が既知のシンボルでない場合は0を返します.この関 +数が0以外を返した場合は*nameは常にシンボルか文字列であり,0を +返した場合は常に文字列です.第三の関数はRubyの文字列ではなく +NUL終端されたCの文字列を使います. + +Rubyから引数として与えられたシンボル(または文字列)をシンボル +に変換するには以下の関数を使います. + + rb_to_symbol(VALUE name) + rb_check_symbol(volatile VALUE *namep) + rb_check_symbol_cstr(const char *ptr, long len, rb_encoding *enc) + +これらの関数は,IDの代わりにシンボルを返すことを除けば上記の +関数と同じです. + +=== CからRubyのメソッドを呼び出す + +Cから文字列を経由せずにRubyのメソッドを呼び出すためには以下 +の関数を使います. + + VALUE rb_funcall(VALUE recv, ID mid, int argc, ...) + +この関数はオブジェクトrecvのmidで指定されるメソッドを呼び出 +します.その他に引数の指定の仕方が違う以下の関数もあります. + + VALUE rb_funcall2(VALUE recv, ID mid, int argc, VALUE *argv) + VALUE rb_funcallv(VALUE recv, ID mid, int argc, VALUE *argv) + VALUE rb_apply(VALUE recv, ID mid, VALUE args) + +applyには引数としてRubyの配列を与えます. + +=== 変数/定数を参照/更新する + +Cから関数を使って参照・更新できるのは,定数,インスタンス変 +数です.大域変数は一部のものはCの大域変数としてアクセスでき +ます.ローカル変数を参照する方法は公開していません. + +オブジェクトのインスタンス変数を参照・更新する関数は以下の通 +りです. + + VALUE rb_ivar_get(VALUE obj, ID id) + VALUE rb_ivar_set(VALUE obj, ID id, VALUE val) + +idはrb_intern()で得られるものを使ってください. + +定数を参照するには以下の関数を使ってください. + + VALUE rb_const_get(VALUE obj, ID id) + +定数を新しく定義するためには『2.1.3 定数定義』で紹介さ +れている関数を使ってください. + += RubyとCとの情報共有 + +C言語とRubyの間で情報を共有する方法について解説します. + +== Cから参照できるRubyの定数 + +以下のRubyの定数はCのレベルから参照できます. + + Qtrue + Qfalse + +真偽値.QfalseはC言語でも偽とみなされます(つまり0). + + Qnil + +C言語から見た「nil」. + +== CとRubyで共有される大域変数 + +CとRubyで大域変数を使って情報を共有できます.共有できる大域 +変数にはいくつかの種類があります.そのなかでもっとも良く使わ +れると思われるのはrb_define_variable()です. + + void rb_define_variable(const char *name, VALUE *var) + +この関数はRubyとCとで共有する大域変数を定義します.変数名が +`$'で始まらない時には自動的に追加されます.この変数の値を変 +更すると自動的にRubyの対応する変数の値も変わります. + +またRuby側からは更新できない変数もあります.このread onlyの +変数は以下の関数で定義します. + + void rb_define_readonly_variable(const char *name, VALUE *var) + +これら変数の他にhookをつけた大域変数を定義できます.hook付き +の大域変数は以下の関数を用いて定義します.hook付き大域変数の +値の参照や設定はhookで行う必要があります. + + void rb_define_hooked_variable(const char *name, VALUE *var, + VALUE (*getter)(), void (*setter)()) + +この関数はCの関数によってhookのつけられた大域変数を定義しま +す.変数が参照された時には関数getterが,変数に値がセットされ +た時には関数setterが呼ばれる.hookを指定しない場合はgetterや +setterに0を指定します. +# getterもsetterも0ならばrb_define_variable()と同じになる. + +getterとsetterの仕様は次の通りです. + + VALUE (*getter)(ID id, VALUE *var); + void (*setter)(VALUE val, ID id, VALUE *var); + + +それから,対応するCの変数を持たないRubyの大域変数を定義する +こともできます. その変数の値はフック関数のみによって取得・設定 +されます. + + void rb_define_virtual_variable(const char *name, + VALUE (*getter)(), void (*setter)()) + +この関数によって定義されたRubyの大域変数が参照された時には +getterが,変数に値がセットされた時にはsetterが呼ばれます. + +getterとsetterの仕様は以下の通りです. + + (*getter)(ID id); + (*setter)(VALUE val, ID id); + +== CのデータをRubyオブジェクトにする + +Cの世界で定義されたデータ(構造体)をRubyのオブジェクトとして +取り扱いたい場合がありえます.このような場合には,Dataという +RubyオブジェクトにCの構造体(へのポインタ)をくるむことでRuby +オブジェクトとして取り扱えるようになります. + +Dataオブジェクトを生成して構造体をRubyオブジェクトにカプセル +化するためには,以下のマクロを使います. + + Data_Wrap_Struct(klass, mark, free, sval) + +このマクロの戻り値は生成されたDataオブジェクトです. + +klassはこのDataオブジェクトのクラスです.markはこの構造体が +Rubyのオブジェクトへの参照がある時に使う関数です.そのような +参照を含まない時には0を指定します. + +# そのような参照は勧められません. + +freeはこの構造体がもう不要になった時に呼ばれる関数です.この +関数がガーベージコレクタから呼ばれます.これが-1の場合は,単 +純に開放されます. + +markおよびfree関数はGC実行中に呼び出されます. +なお, GC実行中はRubyオブジェクトのアロケーションは禁止されま +す. よって, markおよびfree関数でRubyオブジェクトのアロケーシ +ョンは行わないでください. + +Cの構造体の割当とDataオブジェクトの生成を同時に行うマクロと +して以下のものが提供されています. + + Data_Make_Struct(klass, type, mark, free, sval) + +このマクロの戻り値は生成されたDataオブジェクトです.このマク +ロは以下の式のように働きます: + + (sval = ALLOC(type), Data_Wrap_Struct(klass, mark, free, sval)) + +klass, mark, freeはData_Wrap_Structと同じ働きをします.type +は割り当てるC構造体の型です.割り当てられた構造体は変数sval +に代入されます.この変数の型は (type*) である必要があります. + +Dataオブジェクトからポインタを取り出すのは以下のマクロを用い +ます. + + Data_Get_Struct(obj, type, sval) + +Cの構造体へのポインタは変数svalに代入されます. + +これらのDataの使い方はちょっと分かりにくいので,後で説明する +例題を参照してください. + += 例題 - dbmパッケージを作る + +ここまでの説明でとりあえず拡張ライブラリは作れるはずです. +Rubyのextディレクトリにすでに含まれているdbmライブラリを例に +して段階的に説明します. + +== ディレクトリを作る + + % mkdir ext/dbm + +Ruby 1.1からは任意のディレクトリでダイナミックライブラリを作 +ることができるようになりました.Rubyに静的にリンクする場合に +はRubyを展開したディレクトリの下,extディレクトリの中に拡張 +ライブラリ用のディレクトリを作る必要があります.名前は適当に +選んで構いません. + +== 設計する + +まあ,当然なんですけど,どういう機能を実現するかどうかまず設 +計する必要があります.どんなクラスをつくるか,そのクラスには +どんなメソッドがあるか,クラスが提供する定数などについて設計 +します. + +== Cコードを書く + +拡張ライブラリ本体となるC言語のソースを書きます.C言語のソー +スがひとつの時には「ライブラリ名.c」を選ぶと良いでしょう.C +言語のソースが複数の場合には逆に「ライブラリ名.c」というファ +イル名は避ける必要があります.オブジェクトファイルとモジュー +ル生成時に中間的に生成される「ライブラリ名.o」というファイル +とが衝突するからです.また,後述する mkmf ライブラリのいくつ +かの関数がコンパイルを要するテストのために「conftest.c」とい +うファイル名を使用することに注意してください.ソースファイル +名として「conftest.c」を使用してはなりません. + +Rubyは拡張ライブラリをロードする時に「Init_ライブラリ名」と +いう関数を自動的に実行します.dbmライブラリの場合「Init_dbm」 +です.この関数の中でクラス,モジュール,メソッド,定数などの +定義を行います.dbm.cから一部引用します. + + void + Init_dbm(void) + { + /* DBMクラスを定義する */ + VALUE cDBM = rb_define_class("DBM", rb_cObject); + /* DBMはEnumerableモジュールをインクルードする */ + rb_include_module(cDBM, rb_mEnumerable); + + /* DBMクラスのクラスメソッドopen(): 引数はCの配列で受ける */ + rb_define_singleton_method(cDBM, "open", fdbm_s_open, -1); + + /* DBMクラスのメソッドclose(): 引数はなし */ + rb_define_method(cDBM, "close", fdbm_close, 0); + /* DBMクラスのメソッド[]: 引数は1個 */ + rb_define_method(cDBM, "[]", fdbm_fetch, 1); + + /* ... */ + + /* DBMデータを格納するインスタンス変数名のためのID */ + id_dbm = rb_intern("dbm"); + } + +DBMライブラリはdbmのデータと対応するオブジェクトになるはずで +すから,Cの世界のdbmをRubyの世界に取り込む必要があります. + +dbm.cではData_Make_Structを以下のように使っています. + + struct dbmdata { + int di_size; + DBM *di_dbm; + }; + + + obj = Data_Make_Struct(klass, struct dbmdata, 0, free_dbm, dbmp); + +ここではdbmstruct構造体へのポインタをDataにカプセル化してい +ます.DBM*を直接カプセル化しないのはclose()した時の処理を考 +えてのことです. + +Dataオブジェクトからdbmstruct構造体のポインタを取り出すため +に以下のマクロを使っています. + + #define GetDBM(obj, dbmp) do {\ + Data_Get_Struct(obj, struct dbmdata, dbmp);\ + if (dbmp->di_dbm == 0) closed_dbm();\ + } while (0) + +ちょっと複雑なマクロですが,要するにdbmdata構造体のポインタ +の取り出しと,closeされているかどうかのチェックをまとめてい +るだけです. + +DBMクラスにはたくさんメソッドがありますが,分類すると3種類の +引数の受け方があります.ひとつは引数の数が固定のもので,例と +してはdeleteメソッドがあります.deleteメソッドを実装している +fdbm_delete()はこのようになっています. + + static VALUE + fdbm_delete(VALUE obj, VALUE keystr) + { + /* ... */ + } + +引数の数が固定のタイプは第1引数がself,第2引数以降がメソッド +の引数となります. + +引数の数が不定のものはCの配列で受けるものとRubyの配列で受け +るものとがあります.dbmライブラリの中で,Cの配列で受けるもの +はDBMのクラスメソッドであるopen()です.これを実装している関 +数fdbm_s_open()はこうなっています. + + static VALUE + fdbm_s_open(int argc, VALUE *argv, VALUE klass) + { + /* ... */ + + if (rb_scan_args(argc, argv, "11", &file, &vmode) == 1) { + mode = 0666; /* default value */ + } + + /* ... */ + } + +このタイプの関数は第1引数が与えられた引数の数,第2引数が与え +られた引数の入っている配列になります.selfは第3引数として与 +えられます. + +この配列で与えられた引数を解析するための関数がopen()でも使わ +れているrb_scan_args()です.第3引数に指定したフォーマットに従 +い,第4変数以降に指定したVALUEへの参照に値を代入してくれま +す. + + +引数をRubyの配列として受け取るメソッドの例には +Thread#initializeがあります.実装はこうです. + + static VALUE + thread_initialize(VALUE thread, VALUE args) + { + /* ... */ + } + +第1引数はself,第2引数はRubyの配列です. + +*注意事項* + +Rubyと共有はしないがRubyのオブジェクトを格納する可能性のある +Cの大域変数は以下の関数を使ってRubyインタプリタに変数の存在 +を教えてあげてください.でないとGCでトラブルを起こします. + + void rb_global_variable(VALUE *var) + +== extconf.rbを用意する + +Makefileを作る場合の雛型になるextconf.rbというファイルを作り +ます.extconf.rbはライブラリのコンパイルに必要な条件のチェッ +クなどを行うことが目的です.まず, + + require 'mkmf' + +をextconf.rbの先頭に置きます.extconf.rbの中では以下のRuby関 +数を使うことが出来ます. + + have_library(lib, func): ライブラリの存在チェック + have_func(func, header): 関数の存在チェック + have_header(header): ヘッダファイルの存在チェック + create_makefile(target[, target_prefix]): Makefileの生成 + +以下の変数を使うことができます. + + $CFLAGS: コンパイル時に追加的に指定するフラグ(-Oなど) + $CPPFLAGS: プリプロセッサに追加的に指定するフラグ(-Iや-Dなど) + $LDFLAGS: リンク時に追加的に指定するフラグ(-Lなど) + $objs: リンクされるオブジェクトファイル名のリスト + +オブジェクトファイルのリストは,通常はソースファイルを検索し +て自動的に生成されますが,makeの途中でソースを生成するような +場合は明示的に指定する必要があります. + +ライブラリをコンパイルする条件が揃わず,そのライブラリをコン +パイルしない時にはcreate_makefileを呼ばなければMakefileは生 +成されず,コンパイルも行われません. + +== dependを用意する + +もし,ディレクトリにdependというファイルが存在すれば, +Makefileが依存関係をチェックしてくれます. + + % gcc -MM *.c > depend + +などで作ることが出来ます.あって損は無いでしょう. + +== Makefileを生成する + +Makefileを実際に生成するためには + + ruby extconf.rb + +とします.extconf.rbに require 'mkmf' の行がない場合にはエラー +になりますので,引数を追加して + + ruby -r mkmf extconf.rb + +としてください. + +site_ruby ディレクトリでなく, +vendor_ruby ディレクトリにインストールする場合には +以下のように --vendor オプションを加えてください. + + ruby extconf.rb --vendor + +ディレクトリをext以下に用意した場合にはRuby全体のmakeの時に +自動的にMakefileが生成されますので,このステップは不要です. + +== makeする + +動的リンクライブラリを生成する場合にはその場でmakeしてくださ +い.必要であれば make install でインストールされます. + +ext以下にディレクトリを用意した場合は,Rubyのディレクトリで +makeを実行するとMakefileを生成からmake,必要によってはそのモ +ジュールのRubyへのリンクまで自動的に実行してくれます. +extconf.rbを書き換えるなどしてMakefileの再生成が必要な時はま +たRubyディレクトリでmakeしてください. + +拡張ライブラリはmake installでRubyライブラリのディレクトリの +下にコピーされます.もし拡張ライブラリと協調して使うRubyで記 +述されたプログラムがあり,Rubyライブラリに置きたい場合には, +拡張ライブラリ用のディレクトリの下に lib というディレクトリ +を作り,そこに 拡張子 .rb のファイルを置いておけば同時にイン +ストールされます. + +== デバッグ + +まあ,デバッグしないと動かないでしょうね.ext/Setupにディレ +クトリ名を書くと静的にリンクするのでデバッガが使えるようにな +ります.その分コンパイルが遅くなりますけど. + +== できあがり + +後はこっそり使うなり,広く公開するなり,売るなり,ご自由にお +使いください.Rubyの作者は拡張ライブラリに関して一切の権利を +主張しません. + += Appendix A. Rubyのソースコードの分類 + +Rubyのソースはいくつかに分類することが出来ます.このうちクラ +スライブラリの部分は基本的に拡張ライブラリと同じ作り方になっ +ています.これらのソースは今までの説明でほとんど理解できると +思います. + +== Ruby言語のコア + +class.c :: クラスとモジュール +error.c :: 例外クラスと例外機構 +gc.c :: 記憶領域管理 +load.c :: ライブラリのロード +object.c :: オブジェクト +variable.c :: 変数と定数 + +== Rubyの構文解析器 + + parse.y : 字句解析器と構文定義 + -> parse.c : 自動生成 + keywords : 予約語 + -> lex.c : 自動生成 + +== Rubyの評価器 (通称YARV) + compile.c + eval.c + eval_error.c + eval_jump.c + eval_safe.c + insns.def : 仮想機械語の定義 + iseq.c : VM::ISeqの実装 + thread.c : スレッド管理とコンテキスト切り替え + thread_win32.c : スレッド実装 + thread_pthread.c : 同上 + vm.c + vm_dump.c + vm_eval.c + vm_exec.c + vm_insnhelper.c + vm_method.c + + opt_insns_unif.def : 命令融合 + opt_operand.def : 最適化のための定義 + + -> insn*.inc : 自動生成 + -> opt*.inc : 自動生成 + -> vm.inc : 自動生成 + +== 正規表現エンジン (鬼車) + + regex.c + regcomp.c + regenc.c + regerror.c + regexec.c + regparse.c + regsyntax.c + +== ユーティリティ関数 + +debug.c :: Cデバッガ用のデバッグシンボル +dln.c :: 動的ローディング +st.c :: 汎用ハッシュ表 +strftime.c :: 時刻整形 +util.c :: その他のユーティリティ + +== Rubyコマンドの実装 + + dmyext.c + dmydln.c + dmyencoding.c + id.c + inits.c + main.c + ruby.c + version.c + + gem_prelude.rb + prelude.rb + +== クラスライブラリ + +array.c :: Array +bignum.c :: Bignum +compar.c :: Comparable +complex.c :: Complex +cont.c :: Fiber, Continuation +dir.c :: Dir +enum.c :: Enumerable +enumerator.c :: Enumerator +file.c :: File +hash.c :: Hash +io.c :: IO +marshal.c :: Marshal +math.c :: Math +numeric.c :: Numeric, Integer, Fixnum, Float +pack.c :: Array#pack, String#unpack +proc.c :: Binding, Proc +process.c :: Process +random.c :: 乱数 +range.c :: Range +rational.c :: Rational +re.c :: Regexp, MatchData +signal.c :: Signal +sprintf.c :: String#sprintf +string.c :: String +struct.c :: Struct +time.c :: Time +defs/known_errors.def :: 例外クラス Errno::* +-> known_errors.inc :: 自動生成 + +== 多言語化 + +encoding.c :: Encoding +transcode.c :: Encoding::Converter +enc/*.c :: エンコーディングクラス群 +enc/trans/* :: コードポイント対応表 + +== gorubyコマンドの実装 + + goruby.c + golf_prelude.rb : goruby固有のライブラリ + -> golf_prelude.c : 自動生成 + += Appendix B. 拡張用関数リファレンス + +C言語からRubyの機能を利用するAPIは以下の通りである. + +== 型 + +VALUE :: + + Rubyオブジェクトを表現する型.必要に応じてキャストして用いる. + 組み込み型を表現するCの型はruby.hに記述してあるRで始まる構造 + 体である.VALUE型をこれらにキャストするためにRで始まる構造体 + 名を全て大文字にした名前のマクロが用意されている. + +== 変数・定数 + +Qnil :: + + 定数: nilオブジェクト + +Qtrue :: + + 定数: trueオブジェクト(真のデフォルト値) + +Qfalse :: + + 定数: falseオブジェクト + +== Cデータのカプセル化 + +Data_Wrap_Struct(VALUE klass, void (*mark)(), void (*free)(), void *sval) :: + + Cの任意のポインタをカプセル化したRubyオブジェクトを返す.こ + のポインタがRubyからアクセスされなくなった時,freeで指定した + 関数が呼ばれる.また,このポインタの指すデータが他のRubyオブ + ジェクトを指している場合,markに指定する関数でマークする必要 + がある. + +Data_Make_Struct(klass, type, mark, free, sval) :: + + type型のメモリをmallocし,変数svalに代入した後,それをカプセ + ル化したデータを返すマクロ. + +Data_Get_Struct(data, type, sval) :: + + dataからtype型のポインタを取り出し変数svalに代入するマクロ. + +== 型チェック + + TYPE(value) + FIXNUM_P(value) + NIL_P(value) + void Check_Type(VALUE value, int type) + SafeStringValue(value) + +== 型変換 + + FIX2INT(value), INT2FIX(i) + FIX2LONG(value), LONG2FIX(l) + NUM2INT(value), INT2NUM(i) + NUM2UINT(value), UINT2NUM(ui) + NUM2LONG(value), LONG2NUM(l) + NUM2ULONG(value), ULONG2NUM(ul) + NUM2LL(value), LL2NUM(ll) + NUM2ULL(value), ULL2NUM(ull) + NUM2OFFT(value), OFFT2NUM(off) + NUM2SIZET(value), SIZET2NUM(size) + NUM2SSIZET(value), SSIZET2NUM(ssize) + rb_integer_pack(value, words, numwords, wordsize, nails, flags), rb_integer_unpack(words, numwords, wordsize, nails, flags) + NUM2DBL(value) + rb_float_new(f) + RSTRING_LEN(str) + RSTRING_PTR(str) + StringValue(value) + StringValuePtr(value) + StringValueCStr(value) + rb_str_new2(s) + +== クラス/モジュール定義 + +VALUE rb_define_class(const char *name, VALUE super) :: + + superのサブクラスとして新しいRubyクラスを定義する. + +VALUE rb_define_class_under(VALUE module, const char *name, VALUE super) :: + + superのサブクラスとして新しいRubyクラスを定義し,moduleの + 定数として定義する. + +VALUE rb_define_module(const char *name) :: + + 新しいRubyモジュールを定義する. + +VALUE rb_define_module_under(VALUE module, const char *name) :: + + 新しいRubyモジュールを定義し,moduleの定数として定義する. + +void rb_include_module(VALUE klass, VALUE module) :: + + モジュールをインクルードする.classがすでにmoduleをインク + ルードしている時には何もしない(多重インクルードの禁止). + +void rb_extend_object(VALUE object, VALUE module) :: + + オブジェクトをモジュール(で定義されているメソッド)で拡張する. + +== 大域変数定義 + +void rb_define_variable(const char *name, VALUE *var) :: + + RubyとCとで共有するグローバル変数を定義する.変数名が`$'で + 始まらない時には自動的に追加される.nameとしてRubyの識別子 + として許されない文字(例えば` ')を含む場合にはRubyプログラ + ムからは見えなくなる. + +void rb_define_readonly_variable(const char *name, VALUE *var) :: + + RubyとCとで共有するread onlyのグローバル変数を定義する. + read onlyであること以外はrb_define_variable()と同じ. + +void rb_define_virtual_variable(const char *name, VALUE (*getter)(), void (*setter)()) :: + + 関数によって実現されるRuby変数を定義する.変数が参照された + 時にはgetterが,変数に値がセットされた時にはsetterが呼ばれ + る. + +void rb_define_hooked_variable(const char *name, VALUE *var, VALUE (*getter)(), void (*setter)()) :: + + 関数によってhookのつけられたグローバル変数を定義する.変数 + が参照された時にはgetterが,関数に値がセットされた時には + setterが呼ばれる.getterやsetterに0を指定した時にはhookを + 指定しないのと同じ事になる. + +void rb_global_variable(VALUE *var) + + GCのため,Rubyプログラムからはアクセスされないが, Rubyオブ + ジェクトを含む大域変数をマークする. + +== 定数 + +void rb_define_const(VALUE klass, const char *name, VALUE val) :: + + 定数を定義する. + +void rb_define_global_const(const char *name, VALUE val) :: + + 大域定数を定義する. + + rb_define_const(rb_cObject, name, val) + + と同じ意味. + +== メソッド定義 + +rb_define_method(VALUE klass, const char *name, VALUE (*func)(), int argc) :: + + メソッドを定義する.argcはselfを除く引数の数.argcが-1の時, + 関数には引数の数(selfを含まない)を第1引数, 引数の配列を第2 + 引数とする形式で与えられる(第3引数はself).argcが-2の時, + 第1引数がself, 第2引数がargs(argsは引数を含むRubyの配列)と + いう形式で与えられる. + +rb_define_private_method(VALUE klass, const char *name, VALUE (*func)(), int argc) :: + + privateメソッドを定義する.引数はrb_define_method()と同じ. + +rb_define_singleton_method(VALUE klass, const char *name, VALUE (*func)(), int argc) :: + + 特異メソッドを定義する.引数はrb_define_method()と同じ. + +rb_scan_args(int argc, VALUE *argv, const char *fmt, ...) :: + + argc, argv形式で与えられた指定されたフォーマットに従って引 + 数を分解し,続くVALUEへの参照にセットします.このフォーマッ + トは,ABNFで記述すると以下の通りです. + + scan-arg-spec := param-arg-spec [option-hash-arg-spec] [block-arg-spec] + + param-arg-spec := pre-arg-spec [post-arg-spec] / post-arg-spec / + pre-opt-post-arg-spec + pre-arg-spec := num-of-leading-mandatory-args [num-of-optional-args] + post-arg-spec := sym-for-variable-length-args + [num-of-trailing-mandatory-args] + pre-opt-post-arg-spec := num-of-leading-mandatory-args num-of-optional-args + num-of-trailing-mandatory-args + option-hash-arg-spec := sym-for-option-hash-arg + block-arg-spec := sym-for-block-arg + + num-of-leading-mandatory-args := DIGIT ; 先頭に置かれる省略不能な引数の数 + num-of-optional-args := DIGIT ; 続いて置かれる省略可能な引数の数 + sym-for-variable-length-args := "*" ; 続いて置かれる可変長引数を + ; Rubyの配列で取得するための指定 + num-of-trailing-mandatory-args := DIGIT ; 終端に置かれる省略不能な引数の数 + sym-for-option-hash-arg := ":" ; オプションハッシュを取得する + ; ための指定; 省略不能な引数の + ; 数よりも多くの引数が指定され, + ; 最後の引数がハッシュ(または + ; #to_hashで変換可能)の場合に + ; 取得される.最後の引数がnilの + ; 場合,可変長引数指定がなく, + ; 省略不能引数の数よりも多くの + ; 引数が指定された場合に取得される + sym-for-block-arg := "&" ; イテレータブロックを取得するための + ; 指定 + + フォーマットが"12"の場合,引数は最低1つで,3つ(1+2)まで許さ + れるという意味になります.従って,フォーマット文字列に続い + て3つのVALUEへの参照を置く必要があります.それらには取得した + 変数がセットされます.変数への参照の代わりにNULLを指定する + こともでき,その場合は取得した引数の値は捨てられます.なお, + 省略可能引数が省略された時の変数の値はnil(C言語のレベルでは + Qnil)になります. + + 返り値は与えられた引数の数です.オプションハッシュおよびイ + テレータブロックは数えません. + +int rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, VALUE *values) + + キーワードで指定された値をtableにしたがって取り出します. + tableの最初のrequired個のIDは必須キーワードを表し,続く + optional (optionalが負の場合は-optional-1) 個のIDは省略可能 + キーワードです.必須キーワードがkeyword_hash中にない場合, + "missing keyword"ArgumentErrorが発生します.省略可能キーワー + ドがない場合は,values中の対応する要素は変更されません. + keyword_hashに使用されない要素がある場合は,optionalが負なら + 新しいHashとして省略可能引数の次に保存されますが,そうでなけ + れば"unknown keyword"ArgumentErrorが発生します. + +VALUE rb_extract_keywords(VALUE *original_hash) + + original_hashで参照されるHashオブジェクトから,Symbolである + キーとその値を新しいHashに取り出します.original_hashの指す + 先には,元のHashがSymbol以外のキーを含んでいた場合はそれらが + コピーされた別の新しいHash,そうでなければ0が保存されます. + +== Rubyメソッド呼び出し + +VALUE rb_funcall(VALUE recv, ID mid, int narg, ...) :: + + メソッド呼び出し.文字列からmidを得るためにはrb_intern()を + 使う. + private/protectedなメソッドでも呼び出せる. + +VALUE rb_funcall2(VALUE recv, ID mid, int argc, VALUE *argv) :: +VALUE rb_funcallv(VALUE recv, ID mid, int argc, VALUE *argv) :: + + メソッド呼び出し.引数をargc, argv形式で渡す. + private/protectedなメソッドでも呼び出せる. + +VALUE rb_funcallv_public(VALUE recv, ID mid, int argc, VALUE *argv) :: + + メソッド呼び出し. + publicなメソッドしか呼べない. + +VALUE rb_eval_string(const char *str) + + 文字列をRubyスクリプトとしてコンパイル・実行する. + +ID rb_intern(const char *name) :: + + 文字列に対応するIDを返す. + +char *rb_id2name(ID id) :: + + IDに対応する文字列を返す(デバッグ用). + +char *rb_class2name(VALUE klass) :: + + クラスの名前を返す(デバッグ用).クラスが名前を持たない時に + は, 祖先を遡って名前を持つクラスの名前を返す. + +int rb_respond_to(VALUE obj, ID id) :: + + objがidで示されるメソッドを持つかどうかを返す. + +== インスタンス変数 + +VALUE rb_iv_get(VALUE obj, const char *name) :: + + objのインスタンス変数の値を得る.`@'で始まらないインスタン + ス変数は Rubyプログラムからアクセスできない「隠れた」イン + スタンス変数になる.定数は大文字の名前を持つクラス(または + モジュール)のインスタンス変数として実装されている. + +VALUE rb_iv_set(VALUE obj, const char *name, VALUE val) :: + + objのインスタンス変数をvalにセットする. + +== 制御構造 + +VALUE rb_block_call(VALUE obj, ID mid, int argc, VALUE * argv, VALUE (*func) (ANYARGS), VALUE data2) :: + + funcをブロックとして設定し,objをレシーバ,argcとargvを引数 + としてmidメソッドを呼び出す.funcは第一引数にyieldされた値, + 第二引数にdata2を受け取る.複数の値がyieldされた場合(Cでは + rb_yield_values()とrb_yield_values2(), rb_yield_splat()), + data2はArrayとしてパックされている.第三, 第四引数のargcと + argvによってyieldされた値を取り出すことができる. + +[OBSOLETE] VALUE rb_iterate(VALUE (*func1)(), VALUE arg1, VALUE (*func2)(), VALUE arg2) :: + + func2をブロックとして設定し, func1をイテレータとして呼ぶ. + func1には arg1が引数として渡され, func2には第1引数にイテレー + タから与えられた値, 第2引数にarg2が渡される. + + 1.9でrb_iterateを使う場合は, func1の中でRubyレベルのメソッド + を呼び出さなければならない. + 1.9でobsoleteとなった. 代わりにrb_block_callが用意された. + +VALUE rb_yield(VALUE val) :: + + valを値としてイテレータブロックを呼び出す. + +VALUE rb_rescue(VALUE (*func1)(), VALUE arg1, VALUE (*func2)(), VALUE arg2) :: + + 関数func1をarg1を引数に呼び出す.func1の実行中に例外が発生 + した時には func2をarg2を引数として呼ぶ.戻り値は例外が発生 + しなかった時はfunc1の戻り値, 例外が発生した時にはfunc2の戻 + り値である. + +VALUE rb_ensure(VALUE (*func1)(), VALUE arg1, VALUE (*func2)(), VALUE arg2) :: + + 関数func1をarg1を引数として実行し, 実行終了後(たとえ例外が + 発生しても) func2をarg2を引数として実行する.戻り値はfunc1 + の戻り値である(例外が発生した時は戻らない). + +VALUE rb_protect(VALUE (*func) (VALUE), VALUE arg, int *state) :: + + 関数funcをargを引数として実行し, 例外が発生しなければその戻 + り値を返す.例外が発生した場合は, *stateに非0をセットして + Qnilを返す. + rb_jump_tag()を呼ばずに捕捉した例外を無視する場合には, + rb_set_errinfo(Qnil)でエラー情報をクリアしなければならない. + +void rb_jump_tag(int state) :: + + rb_protect()やrb_eval_string_protect()で捕捉された例外を再 + 送する.stateはそれらの関数から返された値でなければならない. + この関数は直接の呼び出し元に戻らない. + +void rb_iter_break() :: + + 現在の最も内側のブロックを終了する.この関数は直接の呼び出 + し元に戻らない. + +void rb_iter_break_value(VALUE value) :: + + 現在の最も内側のブロックをvalueで終了する.ブロックは引数で + 与えられたvalueを返す.この関数は直接の呼び出し元に戻らない. + +== 例外・エラー + +void rb_warning(const char *fmt, ...) :: + + rb_verbose時に標準エラー出力に警告情報を表示する.引数は + printf()と同じ. + +void rb_raise(rb_eRuntimeError, const char *fmt, ...) :: + + RuntimeError例外を発生させる.引数はprintf()と同じ. + +void rb_raise(VALUE exception, const char *fmt, ...) :: + + exceptionで指定した例外を発生させる.fmt以下の引数は + printf()と同じ. + +void rb_fatal(const char *fmt, ...) :: + + 致命的例外を発生させる.通常の例外処理は行なわれず, インター + プリタが終了する(ただしensureで指定されたコードは終了前に + 実行される). + +void rb_bug(const char *fmt, ...) :: + + インタープリタなどプログラムのバグでしか発生するはずのない + 状況の時呼ぶ.インタープリタはコアダンプし直ちに終了する. + 例外処理は一切行なわれない. + +注意: "%"PRIsVALUEがObject#to_s('+'フラグが指定されていると +きはObject#inspect)を使ったVALUEの出力に利用できる.これは +"%i"と衝突するため,整数には"%d"を使用すること. + +== Rubyの初期化・実行 + +Rubyをアプリケーションに埋め込む場合には以下のインタフェース +を使う.通常の拡張ライブラリには必要ない. + +void ruby_init() :: + + Rubyインタプリタの初期化を行なう. + +void *ruby_options(int argc, char **argv) :: + + Rubyインタプリタのコマンドライン引数の処理を行ない, + Rubyのソースコードをコンパイルする. + コンパイルされたソースへのポインタ,もしくは特殊値を返す. + +int ruby_run_node(void *n) :: + + コンパイルされたコードを実行する. + 実行に成功した場合はEXIT_SUCCESSを,エラーが起こったときはそれ以外を返す. + +void ruby_script(char *name) :: + + Rubyのスクリプト名($0)を設定する. + +== インタプリタのイベントのフック + + void rb_add_event_hook(rb_event_hook_func_t func, rb_event_flag_t events, + VALUE data) + +指定されたインタプリタのイベントに対するフック関数を追加します. +eventsは以下の値のorでなければなりません: + + RUBY_EVENT_LINE + RUBY_EVENT_CLASS + RUBY_EVENT_END + RUBY_EVENT_CALL + RUBY_EVENT_RETURN + RUBY_EVENT_C_CALL + RUBY_EVENT_C_RETURN + RUBY_EVENT_RAISE + RUBY_EVENT_ALL + +rb_event_hook_func_tの定義は以下の通りです: + + typedef void (*rb_event_hook_func_t)(rb_event_t event, VALUE data, + VALUE self, ID id, VALUE klass) + +rb_add_event_hook() の第3引数 data は,フック関数の第2引数と +して渡されます.これは1.8では現在のNODEへのポインタでした.以 +下の RB_EVENT_HOOKS_HAVE_CALLBACK_DATA も参照してください. + + int rb_remove_event_hook(rb_event_hook_func_t func) + +指定されたフック関数を削除します. + +== 互換性のためのマクロ + +APIの互換性をチェックするために以下のマクロがデフォルトで定義されています. + +NORETURN_STYLE_NEW :: + + NORETURN マクロが関数型マクロとして定義されていることを意味する. + +HAVE_RB_DEFINE_ALLOC_FUNC :: + + rb_define_alloc_func() 関数が提供されていること,つまり + allocation framework が使われることを意味する. + have_func("rb_define_alloc_func", "ruby.h") + の結果と同じ. + +HAVE_RB_REG_NEW_STR :: + + StringオブジェクトからRegexpオブジェクトを作る + rb_reg_new_str() 関数が提供されていることを意味する. + have_func("rb_reg_new_str", "ruby.h"). + の結果と同じ. + +HAVE_RB_IO_T :: + + rb_io_t 型が提供されていることを意味する. + +USE_SYMBOL_AS_METHOD_NAME :: + + メソッド名を返すメソッド,Module#methods, #singleton_methods + などがSymbolを返すことを意味する. + +HAVE_RUBY_*_H :: + + ruby.h で定義されている.対応するヘッダが提供されていること + を意味する.たとえば,HAVE_RUBY_ST_H が定義されている場合は + 単なる st.h ではなく ruby/st.h を使用する. + +RB_EVENT_HOOKS_HAVE_CALLBACK_DATA :: + + rb_add_event_hook() がフック関数に渡す data を第3引数として + 受け取ることを意味する. + += Appendix C. extconf.rbで使える関数たち + +extconf.rbの中では利用可能なコンパイル条件チェックの関数は以 +下の通りである. + +have_macro(macro, headers) :: + + ヘッダファイルheaderをインクルードしてマクロmacroが定義さ + れているかどうかチェックする.マクロが定義されている時true + を返す. + +have_library(lib, func) :: + + 関数funcを定義しているライブラリlibの存在をチェックする. + チェックに成功すると,-llibを$libsに追加し,trueを返す. + +find_library(lib, func, path...) :: + + 関数funcを定義しているライブラリlibの存在を -Lpath を追加 + しながらチェックする.チェックに成功すると,-llibを$libsに + 追加し,trueを返す. + +have_func(func, header) :: + + ヘッダファイルheaderをインクルードして関数funcの存在をチェ + ックする.funcが標準ではリンクされないライブラリ内のもので + ある時には先にhave_libraryでそのライブラリをチェックしてお + く事.チェックに成功すると,プリプロセッサマクロ + `HAVE_{FUNC}` を定義し,trueを返す. + +have_var(var, header) :: + + ヘッダファイルheaderをインクルードして変数varの存在をチェッ + クする.varが標準ではリンクされないライブラリ内のものであ + る時には先にhave_libraryでそのライブラリをチェックしておく + 事.チェックに成功すると,プリプロセッサマクロ + `HAVE_{VAR}` を定義し,trueを返す. + +have_header(header) :: + + ヘッダファイルの存在をチェックする.チェックに成功すると, + プリプロセッサマクロ `HAVE_{HEADER_H}` を定義し,trueを返す. + (スラッシュやドットはアンダースコアに置換される) + +find_header(header, path...) :: + + ヘッダファイルheaderの存在を -Ipath を追加しながらチェック + する.チェックに成功すると,プリプロセッサマクロ + `HAVE_{HEADER_H}` を定義し,trueを返す. + (スラッシュやドットはアンダースコアに置換される) + +have_struct_member(type, member[, header[, opt]]) :: + + ヘッダファイルheaderをインクルードして型typeが定義され, + なおかつメンバmemberが存在するかをチェックする.チェックに + 成功すると,プリプロセッサマクロ `HAVE_{TYPE}_{MEMBER}` を + 定義し,trueを返す. + +have_type(type, header, opt) :: + + ヘッダファイルheaderをインクルードして型typeが存在するかを + チェックする.チェックに成功すると,プリプロセッサマクロ + `HAVE_TYPE_{TYPE}` を定義し,trueを返す. + +check_sizeof(type, header) :: + + ヘッダファイルheaderをインクルードして型typeのchar単位サイ + ズを調べる.チェックに成功すると,プリプロセッサマクロ + `SIZEOF_{TYPE}` を定義し,そのサイズを返す.定義されていな + いときはnilを返す. + +create_makefile(target[, target_prefix]) :: + + 拡張ライブラリ用のMakefileを生成する.この関数を呼ばなけれ + ばそのライブラリはコンパイルされない.targetはモジュール名 + を表す. + +find_executable(command, path) :: + + コマンドcommandをFile::PATH_SEPARATORで区切られたパス名の + リストpathから探す.pathがnilまたは省略された場合は,環境 + 変数PATHの値を使用する.実行可能なコマンドが見つかった場合 + はパスを含むファイル名,見つからなかった場合はnilを返す. + +with_config(withval[, default=nil]) :: + + コマンドライン上の--with-で指定されたオプション値 + を得る. + +enable_config(config, *defaults) :: +disable_config(config, *defaults) :: + + コマンドライン上の--enable-または + --disable-で指定された真偽値を得る. + --enable-が指定されていた場合はtrue, + --disable-が指定されていた場合はfalseを返す. + どちらも指定されていない場合は,ブロックつきで呼び出されて + いる場合は*defaultsをyieldした結果,ブロックなしなら + *defaultsを返す. + +dir_config(target[, default_dir]) :: +dir_config(target[, default_include, default_lib]) :: + + コマンドライン上の--with--dir, --with--include, + --with--libのいずれかで指定されるディレクトリを + $CFLAGS や $LDFLAGS に追加する.--with--dir=/pathは + --with--include=/path/include --with--lib=/path/lib + と等価である.追加された include ディレクトリと lib ディレ + クトリの配列を返す. ([include_dir, lib_dir]) + +pkg_config(pkg, option=nil) :: + + pkg-configコマンドからパッケージpkgの情報を [cflags, ldflags, libs] + の配列として得る.$CFLAGS, $LDFLAGS, $libs にはそれぞれの値が + 追加される. + + pkg-configの実際のコマンドは,以下の順で試される. + + 1. コマンドラインで--with-{pkg}-config={command}オプションが + 指定された場合: {command} {option} + 2. {pkg}-config {option} + 3. pkg-config {option} {pkg} + + optionが指定された場合は,上記の配列の代わりにそのオプションを + 指定して得られた出力をstripしたものを返す. + += Appendix D. 世代別GC + +Ruby 2.1から世代別GCに対応しました.我々はこれをRGenGCと呼んでいます. +RGenGCは,過去の拡張ライブラリに(ほぼ)互換性を保つように開発されている +ため,拡張ライブラリ側の対応はほぼ不要です. + +ただし,対応をすることで性能を向上することができる可能性があります.もし +拡張ライブラリに高い性能が必要である場合は対応を検討して下さい. + +とくにRARRAY_PTR()/RHASH_TBL()のようなマクロを用いてポインタに直接アクセ +スするようなコードは書かないようにして下さい.代わりに,rb_ary_aref(), +rb_ary_store() などの,適切な API 関数を利用するようにして下さい. + +そのほか,対応についての詳細は README.EXT の「Appendix D. Generational +GC」を参照して下さい. + +/* + * Local variables: + * fill-column: 60 + * end: + */ diff --git a/doc/extention.rdoc b/doc/extention.rdoc new file mode 100644 index 0000000000..f24029c826 --- /dev/null +++ b/doc/extention.rdoc @@ -0,0 +1,1730 @@ +# README.EXT - -*- RDoc -*- created at: Mon Aug 7 16:45:54 JST 1995 + +This document explains how to make extension libraries for Ruby. + += Basic Knowledge + +In C, variables have types and data do not have types. In contrast, +Ruby variables do not have a static type, and data themselves have +types, so data will need to be converted between the languages. + +Data in Ruby are represented by the C type `VALUE'. Each VALUE data +has its data-type. + +To retrieve C data from a VALUE, you need to: + +1. Identify the VALUE's data type +2. Convert the VALUE into C data + +Converting to the wrong data type may cause serious problems. + +== Data-Types + +The Ruby interpreter has the following data types: + +T_NIL :: nil +T_OBJECT :: ordinary object +T_CLASS :: class +T_MODULE :: module +T_FLOAT :: floating point number +T_STRING :: string +T_REGEXP :: regular expression +T_ARRAY :: array +T_HASH :: associative array +T_STRUCT :: (Ruby) structure +T_BIGNUM :: multi precision integer +T_FIXNUM :: Fixnum(31bit or 63bit integer) +T_COMPLEX :: complex number +T_RATIONAL :: rational number +T_FILE :: IO +T_TRUE :: true +T_FALSE :: false +T_DATA :: data +T_SYMBOL :: symbol + +In addition, there are several other types used internally: + +T_ICLASS :: included module +T_MATCH :: MatchData object +T_UNDEF :: undefined +T_NODE :: syntax tree node +T_ZOMBIE :: object awaiting finalization + +Most of the types are represented by C structures. + +== Check Data Type of the VALUE + +The macro TYPE() defined in ruby.h shows the data type of the VALUE. +TYPE() returns the constant number T_XXXX described above. To handle +data types, your code will look something like this: + + switch (TYPE(obj)) { + case T_FIXNUM: + /* process Fixnum */ + break; + case T_STRING: + /* process String */ + break; + case T_ARRAY: + /* process Array */ + break; + default: + /* raise exception */ + rb_raise(rb_eTypeError, "not valid value"); + break; + } + +There is the data-type check function + + void Check_Type(VALUE value, int type) + +which raises an exception if the VALUE does not have the type +specified. + +There are also faster check macros for fixnums and nil. + + FIXNUM_P(obj) + NIL_P(obj) + +== Convert VALUE into C Data + +The data for type T_NIL, T_FALSE, T_TRUE are nil, false, true +respectively. They are singletons for the data type. +The equivalent C constants are: Qnil, Qfalse, Qtrue. +Note that Qfalse is false in C also (i.e. 0), but not Qnil. + +The T_FIXNUM data is a 31bit or 63bit length fixed integer. +This size is depend on the size of long: if long is 32bit then +T_FIXNUM is 31bit, if long is 64bit then T_FIXNUM is 63bit. +T_FIXNUM can be converted to a C integer by using the +FIX2INT() macro or FIX2LONG(). Though you have to check that the +data is really FIXNUM before using them, they are faster. FIX2LONG() +never raises exceptions, but FIX2INT() raises RangeError if the +result is bigger or smaller than the size of int. +There are also NUM2INT() and NUM2LONG() which converts any Ruby +numbers into C integers. These macros includes a type check, +so an exception will be raised if the conversion failed. NUM2DBL() +can be used to retrieve the double float value in the same way. + +You can use the macros +StringValue() and StringValuePtr() to get a char* from a VALUE. +StringValue(var) replaces var's value with the result of "var.to_str()". +StringValuePtr(var) does same replacement and returns char* +representation of var. These macros will skip the replacement if var +is a String. Notice that the macros take only the lvalue as their +argument, to change the value of var in place. + +You can also use the macro named StringValueCStr(). This is just +like StringValuePtr(), but always add nul character at the end of +the result. If the result contains nul character, this macro causes +the ArgumentError exception. +StringValuePtr() doesn't guarantee the existence of a nul at the end +of the result, and the result may contain nul. + +Other data types have corresponding C structures, e.g. struct RArray +for T_ARRAY etc. The VALUE of the type which has the corresponding +structure can be cast to retrieve the pointer to the struct. The +casting macro will be of the form RXXXX for each data type; for +instance, RARRAY(obj). See "ruby.h". However, we do not recommend +to access RXXXX data directly because these data structure is complex. +Use corresponding rb_xxx() functions to access internal struct. +For example, to access an entry of array, use rb_ary_entry(ary, offset) +and rb_ary_store(ary, offset, obj). + +There are some accessing macros for structure members, for example +`RSTRING_LEN(str)' to get the size of the Ruby String object. The +allocated region can be accessed by `RSTRING_PTR(str)'. + +Notice: Do not change the value of the structure directly, unless you +are responsible for the result. This ends up being the cause of +interesting bugs. + +== Convert C Data into VALUE + +To convert C data to Ruby values: + +FIXNUM :: + + left shift 1 bit, and turn on LSB. + +Other pointer values:: + + cast to VALUE. + +You can determine whether a VALUE is pointer or not by checking its LSB. + +Notice Ruby does not allow arbitrary pointer values to be a VALUE. They +should be pointers to the structures which Ruby knows about. The known +structures are defined in . + +To convert C numbers to Ruby values, use these macros. + +INT2FIX() :: for integers within 31bits. +INT2NUM() :: for arbitrary sized integer. + +INT2NUM() converts an integer into a Bignum if it is out of the FIXNUM +range, but is a bit slower. + +== Manipulating Ruby Data + +As I already mentioned, it is not recommended to modify an object's +internal structure. To manipulate objects, use the functions supplied +by the Ruby interpreter. Some (not all) of the useful functions are +listed below: + +=== String Functions + +rb_str_new(const char *ptr, long len) :: + + Creates a new Ruby string. + +rb_str_new2(const char *ptr) :: +rb_str_new_cstr(const char *ptr) :: + + Creates a new Ruby string from a C string. This is equivalent to + rb_str_new(ptr, strlen(ptr)). + +rb_str_new_literal(const char *ptr) :: + + Creates a new Ruby string from a C string literal. + +rb_tainted_str_new(const char *ptr, long len) :: + + Creates a new tainted Ruby string. Strings from external data + sources should be tainted. + +rb_tainted_str_new2(const char *ptr) :: +rb_tainted_str_new_cstr(const char *ptr) :: + + Creates a new tainted Ruby string from a C string. + +rb_sprintf(const char *format, ...) :: +rb_vsprintf(const char *format, va_list ap) :: + + Creates a new Ruby string with printf(3) format. + + Note: In the format string, "%"PRIsVALUE can be used for Object#to_s + (or Object#inspect if '+' flag is set) output (and related argument + must be a VALUE). Since it conflicts with "%i", for integers in + format strings, use "%d". + +rb_str_cat(VALUE str, const char *ptr, long len) :: + + Appends len bytes of data from ptr to the Ruby string. + +rb_str_cat2(VALUE str, const char* ptr) :: +rb_str_cat_cstr(VALUE str, const char* ptr) :: + + Appends C string ptr to Ruby string str. This function is + equivalent to rb_str_cat(str, ptr, strlen(ptr)). + +rb_str_catf(VALUE str, const char* format, ...) :: +rb_str_vcatf(VALUE str, const char* format, va_list ap) :: + + Appends C string format and successive arguments to Ruby string + str according to a printf-like format. These functions are + equivalent to rb_str_cat2(str, rb_sprintf(format, ...)) and + rb_str_cat2(str, rb_vsprintf(format, ap)), respectively. + +rb_enc_str_new(const char *ptr, long len, rb_encoding *enc) :: +rb_enc_str_new_cstr(const char *ptr, rb_encoding *enc) :: + + Creates a new Ruby string with the specified encoding. + +rb_enc_str_new_literal(const char *ptr) :: + + Creates a new Ruby string from a C string literal with the specified + encoding. + +rb_usascii_str_new(const char *ptr, long len) :: +rb_usascii_str_new_cstr(const char *ptr) :: + + Creates a new Ruby string with encoding US-ASCII. + +rb_usascii_str_new_literal(const char *ptr) :: + + Creates a new Ruby string from a C string literal with encoding + US-ASCII. + +rb_utf8_str_new(const char *ptr, long len) :: +rb_utf8_str_new_cstr(const char *ptr) :: + + Creates a new Ruby string with encoding UTF-8. + +rb_utf8_str_new_literal(const char *ptr) :: + + Creates a new Ruby string from a C string literal with encoding + UTF-8. + +rb_str_resize(VALUE str, long len) :: + + Resizes Ruby string to len bytes. If str is not modifiable, this + function raises an exception. The length of str must be set in + advance. If len is less than the old length the content beyond + len bytes is discarded, else if len is greater than the old length + the content beyond the old length bytes will not be preserved but + will be garbage. Note that RSTRING_PTR(str) may change by calling + this function. + +rb_str_set_len(VALUE str, long len) :: + + Sets the length of Ruby string. If str is not modifiable, this + function raises an exception. This function preserves the content + upto len bytes, regardless RSTRING_LEN(str). len must not exceed + the capacity of str. + +=== Array Functions + +rb_ary_new() :: + + Creates an array with no elements. + +rb_ary_new2(long len) :: +rb_ary_new_capa(long len) :: + + Creates an array with no elements, allocating internal buffer + for len elements. + +rb_ary_new3(long n, ...) :: +rb_ary_new_from_args(long n, ...) :: + + Creates an n-element array from the arguments. + +rb_ary_new4(long n, VALUE *elts) :: +rb_ary_new_from_values(long n, VALUE *elts) :: + + Creates an n-element array from a C array. + +rb_ary_to_ary(VALUE obj) :: + + Converts the object into an array. + Equivalent to Object#to_ary. + +There are many functions to operate an array. They may dump core if other +types are given. + +rb_ary_aref(argc, VALUE *argv, VALUE ary) :: + + Equivalent to Array#[]. + +rb_ary_entry(VALUE ary, long offset) :: + + ary[offset] + +rb_ary_store(VALUE ary, long offset, VALUE obj) :: + + ary[offset] = obj + +rb_ary_subseq(VALUE ary, long beg, long len) :: + + ary[beg, len] + +rb_ary_push(VALUE ary, VALUE val) :: +rb_ary_pop(VALUE ary) :: +rb_ary_shift(VALUE ary) :: +rb_ary_unshift(VALUE ary, VALUE val) :: + +rb_ary_cat(VALUE ary, const VALUE *ptr, long len) :: + + Appends len elements of objects from ptr to the array. + += Extending Ruby with C + +== Adding New Features to Ruby + +You can add new features (classes, methods, etc.) to the Ruby +interpreter. Ruby provides APIs for defining the following things: + +* Classes, Modules +* Methods, Singleton Methods +* Constants + +=== Class and Module Definition + +To define a class or module, use the functions below: + + VALUE rb_define_class(const char *name, VALUE super) + VALUE rb_define_module(const char *name) + +These functions return the newly created class or module. You may +want to save this reference into a variable to use later. + +To define nested classes or modules, use the functions below: + + VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super) + VALUE rb_define_module_under(VALUE outer, const char *name) + +=== Method and Singleton Method Definition + +To define methods or singleton methods, use these functions: + + void rb_define_method(VALUE klass, const char *name, + VALUE (*func)(), int argc) + + void rb_define_singleton_method(VALUE object, const char *name, + VALUE (*func)(), int argc) + +The `argc' represents the number of the arguments to the C function, +which must be less than 17. But I doubt you'll need that many. + +If `argc' is negative, it specifies the calling sequence, not number of +the arguments. + +If argc is -1, the function will be called as: + + VALUE func(int argc, VALUE *argv, VALUE obj) + +where argc is the actual number of arguments, argv is the C array of +the arguments, and obj is the receiver. + +If argc is -2, the arguments are passed in a Ruby array. The function +will be called like: + + VALUE func(VALUE obj, VALUE args) + +where obj is the receiver, and args is the Ruby array containing +actual arguments. + +There are some more functions to define methods. One takes an ID +as the name of method to be defined. See also ID or Symbol below. + + void rb_define_method_id(VALUE klass, ID name, + VALUE (*func)(ANYARGS), int argc) + +There are two functions to define private/protected methods: + + void rb_define_private_method(VALUE klass, const char *name, + VALUE (*func)(), int argc) + void rb_define_protected_method(VALUE klass, const char *name, + VALUE (*func)(), int argc) + +At last, rb_define_module_function defines a module functions, +which are private AND singleton methods of the module. +For example, sqrt is the module function defined in Math module. +It can be called in the following way: + + Math.sqrt(4) + +or + + include Math + sqrt(4) + +To define module functions, use: + + void rb_define_module_function(VALUE module, const char *name, + VALUE (*func)(), int argc) + +In addition, function-like methods, which are private methods defined +in the Kernel module, can be defined using: + + void rb_define_global_function(const char *name, VALUE (*func)(), int argc) + +To define an alias for the method, + + void rb_define_alias(VALUE module, const char* new, const char* old); + +To define a reader/writer for an attribute, + + void rb_define_attr(VALUE klass, const char *name, int read, int write) + +To define and undefine the `allocate' class method, + + void rb_define_alloc_func(VALUE klass, VALUE (*func)(VALUE klass)); + void rb_undef_alloc_func(VALUE klass); + +func has to take the klass as the argument and return a newly +allocated instance. This instance should be as empty as possible, +without any expensive (including external) resources. + +If you are overriding an existing method of any ancestor of your class, +you may rely on: + + VALUE rb_call_super(int argc, const VALUE *argv) + +To achieve the receiver of the current scope (if no other way is +available), you can use: + + VALUE rb_current_receiver(void) + +=== Constant Definition + +We have 2 functions to define constants: + + void rb_define_const(VALUE klass, const char *name, VALUE val) + void rb_define_global_const(const char *name, VALUE val) + +The former is to define a constant under specified class/module. The +latter is to define a global constant. + +== Use Ruby Features from C + +There are several ways to invoke Ruby's features from C code. + +=== Evaluate Ruby Programs in a String + +The easiest way to use Ruby's functionality from a C program is to +evaluate the string as Ruby program. This function will do the job: + + VALUE rb_eval_string(const char *str) + +Evaluation is done under the current context, thus current local variables +of the innermost method (which is defined by Ruby) can be accessed. + +Note that the evaluation can raise an exception. There is a safer +function: + + VALUE rb_eval_string_protect(const char *str, int *state) + +It returns nil when an error occur. Moreover, *state is zero if str was +successfully evaluated, or nonzero otherwise. + +=== ID or Symbol + +You can invoke methods directly, without parsing the string. First I +need to explain about ID. ID is the integer number to represent +Ruby's identifiers such as variable names. The Ruby data type +corresponding to ID is Symbol. It can be accessed from Ruby in the +form: + + :Identifier + +or + + :"any kind of string" + +You can get the ID value from a string within C code by using + + rb_intern(const char *name) + rb_intern_str(VALUE name) + +You can retrieve ID from Ruby object (Symbol or String) given as an +argument by using + + rb_to_id(VALUE symbol) + rb_check_id(volatile VALUE *name) + rb_check_id_cstr(const char *name, long len, rb_encoding *enc) + +These functions try to convert the argument to a String if it was not +a Symbol nor a String. The second function stores the converted +result into *name, and returns 0 if the string is not a known symbol. +After this function returned a non-zero value, *name is always a +Symbol or a String, otherwise it is a String if the result is 0. +The third function takes NUL-terminated C string, not Ruby VALUE. + +You can retrieve Symbol from Ruby object (Symbol or String) given as +an argument by using + + rb_to_symbol(VALUE name) + rb_check_symbol(volatile VALUE *namep) + rb_check_symbol_cstr(const char *ptr, long len, rb_encoding *enc) + +These functions are similar to above functions except that these +return a Symbol instead of an ID. + +You can convert C ID to Ruby Symbol by using + + VALUE ID2SYM(ID id) + +and to convert Ruby Symbol object to ID, use + + ID SYM2ID(VALUE symbol) + +=== Invoke Ruby Method from C + +To invoke methods directly, you can use the function below + + VALUE rb_funcall(VALUE recv, ID mid, int argc, ...) + +This function invokes a method on the recv, with the method name +specified by the symbol mid. + +=== Accessing the Variables and Constants + +You can access class variables and instance variables using access +functions. Also, global variables can be shared between both +environments. There's no way to access Ruby's local variables. + +The functions to access/modify instance variables are below: + + VALUE rb_ivar_get(VALUE obj, ID id) + VALUE rb_ivar_set(VALUE obj, ID id, VALUE val) + +id must be the symbol, which can be retrieved by rb_intern(). + +To access the constants of the class/module: + + VALUE rb_const_get(VALUE obj, ID id) + +See also Constant Definition above. + += Information Sharing Between Ruby and C + +=== Ruby Constants That C Can Be Accessed From C + +As stated in section 1.3, +the following Ruby constants can be referred from C. + + Qtrue + Qfalse + +Boolean values. Qfalse is false in C also (i.e. 0). + + Qnil + +Ruby nil in C scope. + +== Global Variables Shared Between C and Ruby + +Information can be shared between the two environments using shared global +variables. To define them, you can use functions listed below: + + void rb_define_variable(const char *name, VALUE *var) + +This function defines the variable which is shared by both environments. +The value of the global variable pointed to by `var' can be accessed +through Ruby's global variable named `name'. + +You can define read-only (from Ruby, of course) variables using the +function below. + + void rb_define_readonly_variable(const char *name, VALUE *var) + +You can defined hooked variables. The accessor functions (getter and +setter) are called on access to the hooked variables. + + void rb_define_hooked_variable(const char *name, VALUE *var, + VALUE (*getter)(), void (*setter)()) + +If you need to supply either setter or getter, just supply 0 for the +hook you don't need. If both hooks are 0, rb_define_hooked_variable() +works just like rb_define_variable(). + +The prototypes of the getter and setter functions are as follows: + + VALUE (*getter)(ID id, VALUE *var); + void (*setter)(VALUE val, ID id, VALUE *var); + + +Also you can define a Ruby global variable without a corresponding C +variable. The value of the variable will be set/get only by hooks. + + void rb_define_virtual_variable(const char *name, + VALUE (*getter)(), void (*setter)()) + +The prototypes of the getter and setter functions are as follows: + + VALUE (*getter)(ID id); + void (*setter)(VALUE val, ID id); + + +== Encapsulate C Data into a Ruby Object + +To wrap and objectify a C pointer as a Ruby object (so called +DATA), use Data_Wrap_Struct(). + + Data_Wrap_Struct(klass, mark, free, sval) + +Data_Wrap_Struct() returns a created DATA object. The klass argument +is the class for the DATA object. The mark argument is the function +to mark Ruby objects pointed by this data. The free argument is the +function to free the pointer allocation. If this is -1, the pointer +will be just freed. The functions mark and free will be called from +garbage collector. + +These mark / free functions are invoked during GC execution. No +object allocations are allowed during it, so do not allocate ruby +objects inside them. + +You can allocate and wrap the structure in one step. + + Data_Make_Struct(klass, type, mark, free, sval) + +This macro returns an allocated Data object, wrapping the pointer to +the structure, which is also allocated. This macro works like: + + (sval = ALLOC(type), Data_Wrap_Struct(klass, mark, free, sval)) + +Arguments klass, mark, and free work like their counterparts in +Data_Wrap_Struct(). A pointer to the allocated structure will be +assigned to sval, which should be a pointer of the type specified. + +To retrieve the C pointer from the Data object, use the macro +Data_Get_Struct(). + + Data_Get_Struct(obj, type, sval) + +A pointer to the structure will be assigned to the variable sval. + +See the example below for details. + += Example - Creating dbm Extension + +OK, here's the example of making an extension library. This is the +extension to access DBMs. The full source is included in the ext/ +directory in the Ruby's source tree. + +== Make the Directory + + % mkdir ext/dbm + +Make a directory for the extension library under ext directory. + +== Design the Library + +You need to design the library features, before making it. + +== Write the C Code + +You need to write C code for your extension library. If your library +has only one source file, choosing ``LIBRARY.c'' as a file name is +preferred. On the other hand, in case your library has multiple source +files, avoid choosing ``LIBRARY.c'' for a file name. It may conflict +with an intermediate file ``LIBRARY.o'' on some platforms. +Note that some functions in mkmf library described below generate +a file ``conftest.c'' for checking with compilation. You shouldn't +choose ``conftest.c'' as a name of a source file. + +Ruby will execute the initializing function named ``Init_LIBRARY'' in +the library. For example, ``Init_dbm()'' will be executed when loading +the library. + +Here's the example of an initializing function. + + void + Init_dbm(void) + { + /* define DBM class */ + VALUE cDBM = rb_define_class("DBM", rb_cObject); + /* DBM includes Enumerable module */ + rb_include_module(cDBM, rb_mEnumerable); + + /* DBM has class method open(): arguments are received as C array */ + rb_define_singleton_method(cDBM, "open", fdbm_s_open, -1); + + /* DBM instance method close(): no args */ + rb_define_method(cDBM, "close", fdbm_close, 0); + /* DBM instance method []: 1 argument */ + rb_define_method(cDBM, "[]", fdbm_fetch, 1); + + /* ... */ + + /* ID for a instance variable to store DBM data */ + id_dbm = rb_intern("dbm"); + } + +The dbm extension wraps the dbm struct in the C environment using +Data_Make_Struct. + + struct dbmdata { + int di_size; + DBM *di_dbm; + }; + + obj = Data_Make_Struct(klass, struct dbmdata, 0, free_dbm, dbmp); + +This code wraps the dbmdata structure into a Ruby object. We avoid +wrapping DBM* directly, because we want to cache size information. + +To retrieve the dbmdata structure from a Ruby object, we define the +following macro: + + #define GetDBM(obj, dbmp) do {\ + Data_Get_Struct(obj, struct dbmdata, dbmp);\ + if (dbmp->di_dbm == 0) closed_dbm();\ + } while (0) + +This sort of complicated macro does the retrieving and close checking for +the DBM. + +There are three kinds of way to receive method arguments. First, +methods with a fixed number of arguments receive arguments like this: + + static VALUE + fdbm_delete(VALUE obj, VALUE keystr) + { + /* ... */ + } + +The first argument of the C function is the self, the rest are the +arguments to the method. + +Second, methods with an arbitrary number of arguments receive +arguments like this: + + static VALUE + fdbm_s_open(int argc, VALUE *argv, VALUE klass) + { + /* ... */ + if (rb_scan_args(argc, argv, "11", &file, &vmode) == 1) { + mode = 0666; /* default value */ + } + /* ... */ + } + +The first argument is the number of method arguments, the second +argument is the C array of the method arguments, and the third +argument is the receiver of the method. + +You can use the function rb_scan_args() to check and retrieve the +arguments. The third argument is a string that specifies how to +capture method arguments and assign them to the following VALUE +references. + + +The following is an example of a method that takes arguments by Ruby's +array: + + static VALUE + thread_initialize(VALUE thread, VALUE args) + { + /* ... */ + } + +The first argument is the receiver, the second one is the Ruby array +which contains the arguments to the method. + +*Notice*: GC should know about global variables which refer to Ruby's objects, +but are not exported to the Ruby world. You need to protect them by + + void rb_global_variable(VALUE *var) + +== Prepare extconf.rb + +If the file named extconf.rb exists, it will be executed to generate +Makefile. + +extconf.rb is the file for checking compilation conditions etc. You +need to put + + require 'mkmf' + +at the top of the file. You can use the functions below to check +various conditions. + + have_macro(macro[, headers[, opt]]): check whether macro is defined + have_library(lib[, func[, headers[, opt]]]): check whether library containing function exists + find_library(lib[, func, *paths]): find library from paths + have_func(func[, headers[, opt]): check whether function exists + have_var(var[, headers[, opt]]): check whether variable exists + have_header(header[, preheaders[, opt]]): check whether header file exists + find_header(header, *paths): find header from paths + have_framework(fw): check whether framework exists (for MacOS X) + have_struct_member(type, member[, headers[, opt]]): check whether struct has member + have_type(type[, headers[, opt]]): check whether type exists + find_type(type, opt, *headers): check whether type exists in headers + have_const(const[, headers[, opt]]): check whether constant is defined + check_sizeof(type[, headers[, opts]]): check size of type + check_signedness(type[, headers[, opts]]): check signedness of type + convertible_int(type[, headers[, opts]]): find convertible integer type + find_executable(bin[, path]): find executable file path + create_header(header): generate configured header + create_makefile(target[, target_prefix]): generate Makefile + +See MakeMakefile for full documentation of these functions. + +The value of the variables below will affect the Makefile. + + $CFLAGS: included in CFLAGS make variable (such as -O) + $CPPFLAGS: included in CPPFLAGS make variable (such as -I, -D) + $LDFLAGS: included in LDFLAGS make variable (such as -L) + $objs: list of object file names + +Normally, the object files list is automatically generated by searching +source files, but you must define them explicitly if any sources will +be generated while building. + +If a compilation condition is not fulfilled, you should not call +``create_makefile''. The Makefile will not be generated, compilation will +not be done. + +== Prepare Depend (Optional) + +If the file named depend exists, Makefile will include that file to +check dependencies. You can make this file by invoking + + % gcc -MM *.c > depend + +It's harmless. Prepare it. + +== Generate Makefile + +Try generating the Makefile by: + + ruby extconf.rb + +If the library should be installed under vendor_ruby directory +instead of site_ruby directory, use --vendor option as follows. + + ruby extconf.rb --vendor + +You don't need this step if you put the extension library under the ext +directory of the ruby source tree. In that case, compilation of the +interpreter will do this step for you. + +== Run make + +Type + + make + +to compile your extension. You don't need this step either if you have +put the extension library under the ext directory of the ruby source tree. + +== Debug + +You may need to rb_debug the extension. Extensions can be linked +statically by adding the directory name in the ext/Setup file so that +you can inspect the extension with the debugger. + +== Done! Now You Have the Extension Library + +You can do anything you want with your library. The author of Ruby +will not claim any restrictions on your code depending on the Ruby API. +Feel free to use, modify, distribute or sell your program. + += Appendix A. Ruby Source Files Overview + +== Ruby Language Core + +class.c :: classes and modules +error.c :: exception classes and exception mechanism +gc.c :: memory management +load.c :: library loading +object.c :: objects +variable.c :: variables and constants + +== Ruby Syntax Parser + +parse.y :: grammar definition +parse.c :: automatically generated from parse.y +keywords :: reserved keywords +lex.c :: automatically generated from keywords + +== Ruby Evaluator (a.k.a. YARV) + + compile.c + eval.c + eval_error.c + eval_jump.c + eval_safe.c + insns.def : definition of VM instructions + iseq.c : implementation of VM::ISeq + thread.c : thread management and context switching + thread_win32.c : thread implementation + thread_pthread.c : ditto + vm.c + vm_dump.c + vm_eval.c + vm_exec.c + vm_insnhelper.c + vm_method.c + + opt_insns_unif.def : instruction unification + opt_operand.def : definitions for optimization + + -> insn*.inc : automatically generated + -> opt*.inc : automatically generated + -> vm.inc : automatically generated + +== Regular Expression Engine (Oniguruma) + + regex.c + regcomp.c + regenc.c + regerror.c + regexec.c + regparse.c + regsyntax.c + +== Utility Functions + +debug.c :: debug symbols for C debugger +dln.c :: dynamic loading +st.c :: general purpose hash table +strftime.c :: formatting times +util.c :: misc utilities + +== Ruby Interpreter Implementation + + dmyext.c + dmydln.c + dmyencoding.c + id.c + inits.c + main.c + ruby.c + version.c + + gem_prelude.rb + prelude.rb + +== Class Library + +array.c :: Array +bignum.c :: Bignum +compar.c :: Comparable +complex.c :: Complex +cont.c :: Fiber, Continuation +dir.c :: Dir +enum.c :: Enumerable +enumerator.c :: Enumerator +file.c :: File +hash.c :: Hash +io.c :: IO +marshal.c :: Marshal +math.c :: Math +numeric.c :: Numeric, Integer, Fixnum, Float +pack.c :: Array#pack, String#unpack +proc.c :: Binding, Proc +process.c :: Process +random.c :: random number +range.c :: Range +rational.c :: Rational +re.c :: Regexp, MatchData +signal.c :: Signal +sprintf.c :: String#sprintf +string.c :: String +struct.c :: Struct +time.c :: Time + +defs/known_errors.def :: Errno::* exception classes +-> known_errors.inc :: automatically generated + +== Multilingualization + +encoding.c :: Encoding +transcode.c :: Encoding::Converter +enc/*.c :: encoding classes +enc/trans/* :: codepoint mapping tables + +== goruby Interpreter Implementation + + goruby.c + golf_prelude.rb : goruby specific libraries. + -> golf_prelude.c : automatically generated + + += Appendix B. Ruby Extension API Reference + +== Types + +VALUE :: + + The type for the Ruby object. Actual structures are defined in ruby.h, + such as struct RString, etc. To refer the values in structures, use + casting macros like RSTRING(obj). + +== Variables and Constants + +Qnil:: + nil object + +Qtrue:: + true object (default true value) + +Qfalse:: + false object + +== C Pointer Wrapping + +Data_Wrap_Struct(VALUE klass, void (*mark)(), void (*free)(), void *sval) :: + + Wrap a C pointer into a Ruby object. If object has references to other + Ruby objects, they should be marked by using the mark function during + the GC process. Otherwise, mark should be 0. When this object is no + longer referred by anywhere, the pointer will be discarded by free + function. + +Data_Make_Struct(klass, type, mark, free, sval) :: + + This macro allocates memory using malloc(), assigns it to the variable + sval, and returns the DATA encapsulating the pointer to memory region. + +Data_Get_Struct(data, type, sval) :: + + This macro retrieves the pointer value from DATA, and assigns it to + the variable sval. + +== Checking Data Types + +TYPE(value) :: + + Internal type (T_NIL, T_FIXNUM, etc.) + +FIXNUM_P(value) :: + + Is +value+ a Fixnum? + +NIL_P(value) :: + + Is +value+ nil? + +void Check_Type(VALUE value, int type) :: + + Ensures +value+ is of the given internal +type+ or raises a TypeError + +SaveStringValue(value) :: + + Checks that +value+ is a String and is not tainted + +== Data Type Conversion + +FIX2INT(value), INT2FIX(i) :: + + Fixnum <-> integer + +FIX2LONG(value), LONG2FIX(l) :: + + Fixnum <-> long + +NUM2INT(value), INT2NUM(i) :: + + Numeric <-> integer + +NUM2UINT(value), UINT2NUM(ui) :: + + Numeric <-> unsigned integer + +NUM2LONG(value), LONG2NUM(l) :: + + Numeric <-> long + +NUM2ULONG(value), ULONG2NUM(ul) :: + + Numeric <-> unsigned long + +NUM2LL(value), LL2NUM(ll) :: + + Numeric <-> long long + +NUM2ULL(value), ULL2NUM(ull) :: + + Numeric <-> unsigned long long + +NUM2OFFT(value), OFFT2NUM(off) :: + + Numeric <-> off_t + +NUM2SIZET(value), SIZET2NUM(size) :: + + Numeric <-> size_t + +NUM2SSIZET(value), SSIZET2NUM(ssize) :: + + Numeric <-> ssize_t + +rb_integer_pack(value, words, numwords, wordsize, nails, flags), rb_integer_unpack(words, numwords, wordsize, nails, flags) :: + + Numeric <-> Arbitrary size integer buffer + +NUM2DBL(value) :: + + Numeric -> double + +rb_float_new(f) :: + + double -> Float + +RSTRING_LEN(str) :: + + String -> length of String data in bytes + +RSTRING_PTR(str) :: + + String -> pointer to String data + Note that the result pointer may not be NUL-terminated + +StringValue(value) :: + + Object with #to_str -> String + +StringValuePtr(value) :: + + Object with #to_str -> pointer to String data + +StringValueCStr(value) :: + + Object with #to_str -> pointer to String data without NUL bytes + It is guaranteed that the result data is NUL-terminated + +rb_str_new2(s) :: + + char * -> String + +== Defining Class and Module + +VALUE rb_define_class(const char *name, VALUE super) :: + + Defines a new Ruby class as a subclass of super. + +VALUE rb_define_class_under(VALUE module, const char *name, VALUE super) :: + + Creates a new Ruby class as a subclass of super, under the module's + namespace. + +VALUE rb_define_module(const char *name) :: + + Defines a new Ruby module. + +VALUE rb_define_module_under(VALUE module, const char *name) :: + + Defines a new Ruby module under the module's namespace. + +void rb_include_module(VALUE klass, VALUE module) :: + + Includes module into class. If class already includes it, just ignored. + +void rb_extend_object(VALUE object, VALUE module) :: + + Extend the object with the module's attributes. + +== Defining Global Variables + +void rb_define_variable(const char *name, VALUE *var) :: + + Defines a global variable which is shared between C and Ruby. If name + contains a character which is not allowed to be part of the symbol, + it can't be seen from Ruby programs. + +void rb_define_readonly_variable(const char *name, VALUE *var) :: + + Defines a read-only global variable. Works just like + rb_define_variable(), except the defined variable is read-only. + +void rb_define_virtual_variable(const char *name, VALUE (*getter)(), VALUE (*setter)()) :: + + Defines a virtual variable, whose behavior is defined by a pair of C + functions. The getter function is called when the variable is + referenced. The setter function is called when the variable is set to a + value. The prototype for getter/setter functions are: + + VALUE getter(ID id) + void setter(VALUE val, ID id) + + The getter function must return the value for the access. + +void rb_define_hooked_variable(const char *name, VALUE *var, VALUE (*getter)(), VALUE (*setter)()) :: + + Defines hooked variable. It's a virtual variable with a C variable. + The getter is called as + + VALUE getter(ID id, VALUE *var) + + returning a new value. The setter is called as + + void setter(VALUE val, ID id, VALUE *var) + + GC requires C global variables which hold Ruby values to be marked. + +void rb_global_variable(VALUE *var) + + Tells GC to protect these variables. + +== Constant Definition + +void rb_define_const(VALUE klass, const char *name, VALUE val) :: + + Defines a new constant under the class/module. + +void rb_define_global_const(const char *name, VALUE val) :: + + Defines a global constant. This is just the same as + + rb_define_const(cKernal, name, val) + +== Method Definition + +rb_define_method(VALUE klass, const char *name, VALUE (*func)(), int argc) :: + + Defines a method for the class. func is the function pointer. argc + is the number of arguments. if argc is -1, the function will receive + 3 arguments: argc, argv, and self. if argc is -2, the function will + receive 2 arguments, self and args, where args is a Ruby array of + the method arguments. + +rb_define_private_method(VALUE klass, const char *name, VALUE (*func)(), int argc) :: + + Defines a private method for the class. Arguments are same as + rb_define_method(). + +rb_define_singleton_method(VALUE klass, const char *name, VALUE (*func)(), int argc) :: + + Defines a singleton method. Arguments are same as rb_define_method(). + +rb_scan_args(int argc, VALUE *argv, const char *fmt, ...) :: + + Retrieve argument from argc and argv to given VALUE references + according to the format string. The format can be described in ABNF + as follows: + + scan-arg-spec := param-arg-spec [option-hash-arg-spec] [block-arg-spec] + + param-arg-spec := pre-arg-spec [post-arg-spec] / post-arg-spec / + pre-opt-post-arg-spec + pre-arg-spec := num-of-leading-mandatory-args [num-of-optional-args] + post-arg-spec := sym-for-variable-length-args + [num-of-trailing-mandatory-args] + pre-opt-post-arg-spec := num-of-leading-mandatory-args num-of-optional-args + num-of-trailing-mandatory-args + option-hash-arg-spec := sym-for-option-hash-arg + block-arg-spec := sym-for-block-arg + + num-of-leading-mandatory-args := DIGIT ; The number of leading + ; mandatory arguments + num-of-optional-args := DIGIT ; The number of optional + ; arguments + sym-for-variable-length-args := "*" ; Indicates that variable + ; length arguments are + ; captured as a ruby array + num-of-trailing-mandatory-args := DIGIT ; The number of trailing + ; mandatory arguments + sym-for-option-hash-arg := ":" ; Indicates that an option + ; hash is captured if the last + ; argument is a hash or can be + ; converted to a hash with + ; #to_hash. When the last + ; argument is nil, it is + ; captured if it is not + ; ambiguous to take it as + ; empty option hash; i.e. '*' + ; is not specified and + ; arguments are given more + ; than sufficient. + sym-for-block-arg := "&" ; Indicates that an iterator + ; block should be captured if + ; given + + For example, "12" means that the method requires at least one + argument, and at most receives three (1+2) arguments. So, the format + string must be followed by three variable references, which are to be + assigned to captured arguments. For omitted arguments, variables are + set to Qnil. NULL can be put in place of a variable reference, which + means the corresponding captured argument(s) should be just dropped. + + The number of given arguments, excluding an option hash or iterator + block, is returned. + +int rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, VALUE *values) + + Retrieves argument VALUEs bound to keywords, which directed by +table+ + into +values+. First +required+ number of IDs referred by +table+ are + mandatory, and succeeding +optional+ (- +optional+ - 1 if + +optional+ is negative) number of IDs are optional. If a + mandatory key is not contained in +keyword_hash+, raises "missing + keyword" +ArgumentError+. If an optional key is not present in + +keyword_hash+, the corresponding element in +values+ is not changed. + If +optional+ is negative, rest of +keyword_hash+ are stored in the + next to optional +values+ as a new Hash, otherwise raises "unknown + keyword" +ArgumentError+. + +VALUE rb_extract_keywords(VALUE *original_hash) + + Extracts pairs whose key is a symbol into a new hash from a hash + object referred by +original_hash+. If the original hash contains + non-symbol keys, then they are copied to another hash and the new hash + is stored through +original_hash+, else 0 is stored. + +== Invoking Ruby method + +VALUE rb_funcall(VALUE recv, ID mid, int narg, ...) :: + + Invokes a method. To retrieve mid from a method name, use rb_intern(). + Able to call even private/protected methods. + +VALUE rb_funcall2(VALUE recv, ID mid, int argc, VALUE *argv) :: +VALUE rb_funcallv(VALUE recv, ID mid, int argc, VALUE *argv) :: + + Invokes a method, passing arguments as an array of values. + Able to call even private/protected methods. + +VALUE rb_funcallv_public(VALUE recv, ID mid, int argc, VALUE *argv) :: + + Invokes a method, passing arguments as an array of values. + Able to call only public methods. + +VALUE rb_eval_string(const char *str) :: + + Compiles and executes the string as a Ruby program. + +ID rb_intern(const char *name) :: + + Returns ID corresponding to the name. + +char *rb_id2name(ID id) :: + + Returns the name corresponding ID. + +char *rb_class2name(VALUE klass) :: + + Returns the name of the class. + +int rb_respond_to(VALUE object, ID id) :: + + Returns true if the object responds to the message specified by id. + +== Instance Variables + +VALUE rb_iv_get(VALUE obj, const char *name) :: + + Retrieve the value of the instance variable. If the name is not + prefixed by `@', that variable shall be inaccessible from Ruby. + +VALUE rb_iv_set(VALUE obj, const char *name, VALUE val) :: + + Sets the value of the instance variable. + +== Control Structure + +VALUE rb_block_call(VALUE recv, ID mid, int argc, VALUE * argv, VALUE (*func) (ANYARGS), VALUE data2) :: + + Calls a method on the recv, with the method name specified by the + symbol mid, with argc arguments in argv, supplying func as the + block. When func is called as the block, it will receive the value + from yield as the first argument, and data2 as the second argument. + When yielded with multiple values (in C, rb_yield_values(), + rb_yield_values2() and rb_yield_splat()), data2 is packed as an Array, + whereas yielded values can be gotten via argc/argv of the third/fourth + arguments. + +[OBSOLETE] VALUE rb_iterate(VALUE (*func1)(), void *arg1, VALUE (*func2)(), void *arg2) :: + + Calls the function func1, supplying func2 as the block. func1 will be + called with the argument arg1. func2 receives the value from yield as + the first argument, arg2 as the second argument. + + When rb_iterate is used in 1.9, func1 has to call some Ruby-level method. + This function is obsolete since 1.9; use rb_block_call instead. + +VALUE rb_yield(VALUE val) :: + + Evaluates the block with value val. + +VALUE rb_rescue(VALUE (*func1)(), VALUE arg1, VALUE (*func2)(), VALUE arg2) :: + + Calls the function func1, with arg1 as the argument. If an exception + occurs during func1, it calls func2 with arg2 as the argument. The + return value of rb_rescue() is the return value from func1 if no + exception occurs, from func2 otherwise. + +VALUE rb_ensure(VALUE (*func1)(), VALUE arg1, VALUE (*func2)(), VALUE arg2) :: + + Calls the function func1 with arg1 as the argument, then calls func2 + with arg2 if execution terminated. The return value from + rb_ensure() is that of func1 when no exception occurred. + +VALUE rb_protect(VALUE (*func) (VALUE), VALUE arg, int *state) :: + + Calls the function func with arg as the argument. If no exception + occurred during func, it returns the result of func and *state is zero. + Otherwise, it returns Qnil and sets *state to nonzero. If state is + NULL, it is not set in both cases. + You have to clear the error info with rb_set_errinfo(Qnil) when + ignoring the caught exception. + +void rb_jump_tag(int state) :: + + Continues the exception caught by rb_protect() and rb_eval_string_protect(). + state must be the returned value from those functions. This function + never return to the caller. + +void rb_iter_break() :: + + Exits from the current innermost block. This function never return to + the caller. + +void rb_iter_break_value(VALUE value) :: + + Exits from the current innermost block with the value. The block will + return the given argument value. This function never return to the + caller. + +== Exceptions and Errors + +void rb_warn(const char *fmt, ...) :: + + Prints a warning message according to a printf-like format. + +void rb_warning(const char *fmt, ...) :: + + Prints a warning message according to a printf-like format, if + $VERBOSE is true. + +void rb_raise(rb_eRuntimeError, const char *fmt, ...) :: + + Raises RuntimeError. The fmt is a format string just like printf(). + +void rb_raise(VALUE exception, const char *fmt, ...) :: + + Raises a class exception. The fmt is a format string just like printf(). + +void rb_fatal(const char *fmt, ...) :: + + Raises a fatal error, terminates the interpreter. No exception handling + will be done for fatal errors, but ensure blocks will be executed. + +void rb_bug(const char *fmt, ...) :: + + Terminates the interpreter immediately. This function should be + called under the situation caused by the bug in the interpreter. No + exception handling nor ensure execution will be done. + +Note: In the format string, "%"PRIsVALUE can be used for Object#to_s +(or Object#inspect if '+' flag is set) output (and related argument +must be a VALUE). Since it conflicts with "%i", for integers in +format strings, use "%d". + +== Initialize and Start the Interpreter + +The embedding API functions are below (not needed for extension libraries): + +void ruby_init() :: + + Initializes the interpreter. + +void *ruby_options(int argc, char **argv) :: + + Process command line arguments for the interpreter. + And compiles the Ruby source to execute. + It returns an opaque pointer to the compiled source + or an internal special value. + +int ruby_run_node(void *n) :: + + Runs the given compiled source and exits this process. + It returns EXIT_SUCCESS if successfully runs the source. + Otherwise, it returns other value. + +void ruby_script(char *name) :: + + Specifies the name of the script ($0). + +== Hooks for the Interpreter Events + + void rb_add_event_hook(rb_event_hook_func_t func, rb_event_flag_t events, + VALUE data) + +Adds a hook function for the specified interpreter events. +events should be OR'ed value of: + + RUBY_EVENT_LINE + RUBY_EVENT_CLASS + RUBY_EVENT_END + RUBY_EVENT_CALL + RUBY_EVENT_RETURN + RUBY_EVENT_C_CALL + RUBY_EVENT_C_RETURN + RUBY_EVENT_RAISE + RUBY_EVENT_ALL + +The definition of rb_event_hook_func_t is below: + + typedef void (*rb_event_hook_func_t)(rb_event_t event, VALUE data, + VALUE self, ID id, VALUE klass) + +The third argument `data' to rb_add_event_hook() is passed to the hook +function as the second argument, which was the pointer to the current +NODE in 1.8. See RB_EVENT_HOOKS_HAVE_CALLBACK_DATA below. + + int rb_remove_event_hook(rb_event_hook_func_t func) + +Removes the specified hook function. + +== Macros for Compatibility + +Some macros to check API compatibilities are available by default. + +NORETURN_STYLE_NEW :: + + Means that NORETURN macro is functional style instead of prefix. + +HAVE_RB_DEFINE_ALLOC_FUNC :: + + Means that function rb_define_alloc_func() is provided, that means the + allocation framework is used. This is same as the result of + have_func("rb_define_alloc_func", "ruby.h"). + +HAVE_RB_REG_NEW_STR :: + + Means that function rb_reg_new_str() is provided, that creates Regexp + object from String object. This is same as the result of + have_func("rb_reg_new_str", "ruby.h"). + +HAVE_RB_IO_T :: + + Means that type rb_io_t is provided. + +USE_SYMBOL_AS_METHOD_NAME :: + + Means that Symbols will be returned as method names, e.g., + Module#methods, #singleton_methods and so on. + +HAVE_RUBY_*_H :: + + Defined in ruby.h and means corresponding header is available. For + instance, when HAVE_RUBY_ST_H is defined you should use ruby/st.h not + mere st.h. + +RB_EVENT_HOOKS_HAVE_CALLBACK_DATA :: + + Means that rb_add_event_hook() takes the third argument `data', to be + passed to the given event hook function. + += Appendix C. Functions available for use in extconf.rb + +See documentation for {mkmf}[rdoc-ref:MakeMakefile]. + += Appendix D. Generational GC + +Ruby 2.1 introduced a generational garbage collector (called RGenGC). +RGenGC (mostly) keeps compatibility. + +Generally, the use of the technique called write barriers is required in +extension libraries for generational GC +(http://en.wikipedia.org/wiki/Garbage_collection_%28computer_science%29). +RGenGC works fine without write barriers in extension libraries. + +If your library adheres to the following tips, performance can +be further improved. Especially, the "Don't touch pointers directly" section is +important. + +== Incompatibility + +You can't write RBASIC(obj)->klass field directly because it is const +value now. + +Basically you should not write this field because MRI expects it to be +an immutable field, but if you want to do it in your extension you can +use the following functions: + +VALUE rb_obj_hide(VALUE obj) :: + + Clear RBasic::klass field. The object will be an internal object. + ObjectSpace::each_object can't find this object. + +VALUE rb_obj_reveal(VALUE obj, VALUE klass) :: + + Reset RBasic::klass to be klass. + We expect the `klass' is hidden class by rb_obj_hide(). + +== Write barriers + +RGenGC doesn't require write barriers to support generational GC. +However, caring about write barrier can improve the performance of +RGenGC. Please check the following tips. + +=== Don't touch pointers directly + +In MRI (include/ruby/ruby.h), some macros to acquire pointers to the +internal data structures are supported such as RARRAY_PTR(), +RSTRUCT_PTR() and so on. + +DO NOT USE THESE MACROS and instead use the corresponding C-APIs such as +rb_ary_aref(), rb_ary_store() and so on. + +=== Consider whether to insert write barriers + +You don't need to care about write barriers if you only use built-in +types. + +If you support T_DATA objects, you may consider using write barriers. + +Inserting write barriers into T_DATA objects only works with the +following type objects: (a) long-lived objects, (b) when a huge number +of objects are generated and (c) container-type objects that have +references to other objects. If your extension provides such a type of +T_DATA objects, consider inserting write barriers. + +(a): short-lived objects don't become old generation objects. +(b): only a few oldgen objects don't have performance impact. +(c): only a few references don't have performance impact. + +Inserting write barriers is a very difficult hack, it is easy to +introduce critical bugs. And inserting write barriers has several areas +of overhead. Basically we don't recommend you insert write barriers. +Please carefully consider the risks. + +=== Combine with built-in types + +Please consider utilizing built-in types. Most built-in types support +write barrier, so you can use them to avoid manually inserting write +barriers. + +For example, if your T_DATA has references to other objects, then you +can move these references to Array. A T_DATA object only has a reference +to an array object. Or you can also use a Struct object to gather a +T_DATA object (without any references) and an that Array contains +references. + +With use of such techniques, you don't need to insert write barriers +anymore. + +=== Insert write barriers + +[AGAIN] Inserting write barriers is a very difficult hack, and it is +easy to introduce critical bugs. And inserting write barriers has +several areas of overhead. Basically we don't recommend you insert write +barriers. Please carefully consider the risks. + +Before inserting write barriers, you need to know about RGenGC algorithm +(gc.c will help you). Macros and functions to insert write barriers are +available in in include/ruby/ruby.h. An example is available in iseq.c. + +For a complete guide for RGenGC and write barriers, please refer to +. + += Appendix E. RB_GC_GUARD to protect from premature GC + +C Ruby currently uses conservative garbage collection, thus VALUE +variables must remain visible on the stack or registers to ensure any +associated data remains usable. Optimizing C compilers are not designed +with conservative garbage collection in mind, so they may optimize away +the original VALUE even if the code depends on data associated with that +VALUE. + +The following example illustrates the use of RB_GC_GUARD to ensure +the contents of sptr remain valid while the second invocation of +rb_str_new_cstr is running. + + VALUE s, w; + const char *sptr; + + s = rb_str_new_cstr("hello world!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); + sptr = RSTRING_PTR(s); + w = rb_str_new_cstr(sptr + 6); /* Possible GC invocation */ + + RB_GC_GUARD(s); /* ensure s (and thus sptr) do not get GC-ed */ + +In the above example, RB_GC_GUARD must be placed _after_ the last use of +sptr. Placing RB_GC_GUARD before dereferencing sptr would be of no use. +RB_GC_GUARD is only effective on the VALUE data type, not converted C +data types. + +RB_GC_GUARD would not be necessary at all in the above example if +non-inlined function calls are made on the `s' VALUE after sptr is +dereferenced. Thus, in the above example, calling any un-inlined +function on `s' such as: + + rb_str_modify(s); + +Will ensure `s' stays on the stack or register to prevent a +GC invocation from prematurely freeing it. + +Using the RB_GC_GUARD macro is preferable to using the "volatile" +keyword in C. RB_GC_GUARD has the following advantages: + +1) the intent of the macro use is clear + +2) RB_GC_GUARD only affects its call site, "volatile" generates some + extra code every time the variable is used, hurting optimization. + +3) "volatile" implementations may be buggy/inconsistent in some + compilers and architectures. RB_GC_GUARD is customizable for broken + systems/compilers without those without negatively affecting other + systems. + +/* + * Local variables: + * fill-column: 70 + * end: + */ -- cgit v1.2.3