Ruby原生C扩展无法识别核心源码RANGE_BEG宏的编译问题
通过查阅Ruby API源码可知,Array#length与Range#begin方法的实现分别使用了RARRAY_LEN和RANGE_BEG两个宏,对应核心实现代码如下:
Array#length
static VALUE rb_ary_length(VALUE ary) { long len = RARRAY_LEN(ary); return LONG2NUM(len); }
Range#begin
static VALUE range_begin(VALUE range) { return RANGE_BEG(range); }
但在编写原生C扩展时,RARRAY_LEN宏可正常调用,RANGE_BEG宏却无法正常工作,测试代码如下:
test.c
#include "test.h" VALUE rb_mTest = Qnil; VALUE rb_cTest = Qnil; VALUE super_initialize(VALUE self) { return self; } VALUE array_len(VALUE self, VALUE ary) { Check_Type(ary, T_ARRAY); return LONG2NUM(RARRAY_LEN(ary)); // 可正常运行 } VALUE range_begin(VALUE self, VALUE rng) { if (rb_obj_is_kind_of(rng, rb_cRange)) { // return RANGE_BEG(rng); // 无法正常运行 return rb_funcall(rng, rb_intern("begin"), 0); // 可正常运行 } return Qnil; } void Init_test(void) { rb_mTest = rb_define_module("RangeTest"); rb_cTest = rb_define_class_under(rb_mTest, "Tester", rb_cObject); rb_define_method(rb_cTest, "initialize", super_initialize, 0); rb_define_method(rb_cTest, "array_len", array_len, 1); rb_define_method(rb_cTest, "begin_value", range_begin, 1); }
test.h
#ifndef TEST_H #define TEST_H 1 #include "ruby.h" VALUE super_initialize(VALUE self); void Init_test(void); VALUE range_begin(VALUE self, VALUE rng); VALUE array_len(VALUE self, VALUE ary); #endif /* TEST_H */
取消代码中RANGE_BEG(rng)行的注释后,编译器抛出如下错误:
error: implicit declaration of function 'RANGE_BEG' is invalid in C99 [-Werror,-Wimplicit-function-declaration] return RANGE_BEG(rng); ^ 1 error generated.
初步判断是缺少头文件引入,但存在三点疑问:
- 使用
RARRAY_LEN无需额外引入头文件 - 引入
range.h后问题仍未解决 - 通过grep检索未找到
RANGE_BEG宏的定义位置
目前可通过rb_funcall调用begin方法实现需求作为临时替代方案,但根据文档说明宏的访问效率高于函数调用,因此更期望使用宏实现。
现寻求正确使用RANGE_BEG宏的方案,运行环境信息如下:
- 操作系统:MacOS 12.4 (Monterey)
- Ruby环境:通过Homebrew安装ruby 3.1.2p20 (2022-04-12 revision 4491bb740a) [arm64-darwin21]
- 已配置编译参数:
CPPFLAGS=-I/opt/homebrew/opt/ruby/include、LDFLAGS=-L/opt/homebrew/opt/ruby/lib
内容的提问来源于stack exchange,提问作者pjs
相关产品推荐
相关产品推荐

