Ruby C Extension 排坑
Ruby C Extension 排坑
在编写OjRunner的过程中,一开始是参考了Tristan Penman’s Blog,在没有使用gem install
之前,一切安好,但是gen install
之后,也提示build native extension successfully
,但是执行require 'oj_runner'
之后报LoadError: cannot load such file -- oj_runner/oj_runner
。这段代码是lib/oj_runner.rb中所有,目的是为了引入C编译之后的库。
先来看一下目录结构,红框中的文件是由我们创建的。源码写完之后会放到Github上去。
首先我们来尝试直接加载
# now at ext/oj_runner
$ ruby extconf.rb
# generate extconf.h & Makefile & mkmf.log
$ make
# generate oj_runner.o & oj_runner.so
$ irb
> require 'oj_runner'
# => true
> OjRunner.run({})
# => 123
这样是没有问题的。再尝试RubyGems中通过添加-I
参数的方法。
# now at project root
$ ruby -Ilib:ext -r oj_runner -e "puts OjRunner.run({})"
123
这样也没有问题,这是因为使用-I
参数,相当于将lib和ext添加到了include path中,这样lib/oj_runner.rb中的require 'oj_runner/oj_runner'
相当于查找到了ext/oj_runner/oj_runner.so,所以此时的问题并没有暴露出来。
先不管Gemfile和Rakefile中的内容,尝试通过gemspec文件将该测试包安装到gem中
# now at project root
$ gem build oj_runner.gemspec
$ sudo gem install oj_runner-0.0.2.gem
$ irb
> require 'oj_runner'
LoadError: cannot load such file -- oj_runner/oj_runner...
此时无法找到oj_runner/oj_runner
,是因为即使ext也被安装到了gem里去,但是并没有被包含在路径中。查看gem包的安装路径的结构(我的是/var/lib/gems/2.3.0/gems/oj_runner-0.0.2),可以看到ext和lib下都有oj_runner.so,但显然ext并不是被找到的那个,lib下也有一个,但是被放错了位置。
那想,如果把require 'oj_runner/oj_runner'
改为require 'oj_runner'
,可不可以。但因为同一个文件下存在oj_runner.rb和oj_runner.so,并不能正确的引用,导致出现undefined method 'run' for OjRunner:Class
。
仔细看了RubyGems,其中有一句
When the extension is built the files in ext/my_malloc/lib/ will be installed into the lib/ directory for you.
并且查阅了ruby-doc,由此得知,安装的时候会根据create_makefile
中的target
参数将编译生成的oj_runner.so拷贝到lib中的对应位置,因此原Tristan Penman’s Blog其实写错了extconf.rb文件,应该改为create_makefile('oj_runner/oj_runner')
。
或者把ext/extconf.rb中改为oj_runner_lib对应修改oj_runner.c中为Init_oj_runner_lib
,这样就不会因为包名重复导致无法正确导入,并且可以得到下图的效果
上一篇: three.js的学习
下一篇: ThreeJS系列教程-Lesson7