我有一个用C ++编写的ruby扩展,P4
,它似乎通常有效:
irb -Ilib
然后require 'P4'
,并使用它bin
文件夹中的shell脚本来执行rake测试,例如${GEM_HOME}/gems/rake-10.3.2/bin/rake test
但是,当我通过路径中的RubyGems包装器访问rake时,例如rake test
,我得到了这个TypeError
/Users/tjuricek/dev/p4ruby/lib/P4.rb:38:in `require': P4 is not a class (TypeError)
from /Users/tjuricek/dev/p4ruby/lib/P4.rb:38:in `<top (required)>'
from /Users/tjuricek/dev/p4ruby/test/testlib.rb:31:in `require'
from /Users/tjuricek/dev/p4ruby/test/testlib.rb:31:in `<top (required)>'
from /Users/tjuricek/.rvm/gems/ruby-2.1.2/gems/rake-10.3.2/lib/rake/rake_test_loader.rb:15:in `require'
from /Users/tjuricek/.rvm/gems/ruby-2.1.2/gems/rake-10.3.2/lib/rake/rake_test_loader.rb:15:in `block in <main>'
from /Users/tjuricek/.rvm/gems/ruby-2.1.2/gems/rake-10.3.2/lib/rake/rake_test_loader.rb:4:in `select'
from /Users/tjuricek/.rvm/gems/ruby-2.1.2/gems/rake-10.3.2/lib/rake/rake_test_loader.rb:4:in `<main>'
rake aborted!
然后它会弹出“失败”的ruby命令。如果我复制并粘贴该命令并运行它,它就可以工作。
我注意到RubyGems创建了一个相当简单的包装器脚本:
#!/usr/bin/env ruby_executable_hooks
#
# This file was generated by RubyGems.
#
# The application 'rake' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require 'rubygems'
version = ">= 0"
if ARGV.first
str = ARGV.first
str = str.dup.force_encoding("BINARY") if str.respond_to? :force_encoding
if str =~ /\A_(.*)_\z/ and Gem::Version.correct?($1) then
version = $1
ARGV.shift
end
end
gem 'rake', version
load Gem.bin_path('rake', 'rake', version)
我猜测最后一行load Gem.bin_path...
引发了我在创建扩展程序时遇到的某种错误配置,但我不知道那会是什么。
有没有人知道只有在RubyGems包装器下运行时可能导致require
失败的原因?
答案 0 :(得分:3)
好的,调试方法是进入加载文件的行:
require 'P4.so'
看看它是否定义了:
puts "P4 #{P4.class}"
require 'P4.so'
在这种情况下,当直接在rake下运行时,它加载了.gemspec
,它引入了一个版本定义(在我的情况下,错误地)P4
模块:
module P4
version = VERSION = '3000.0.0.pre0'
end
所以,对我而言,修复包括:
module P4
更改为class P4
require 'P4.so'
语句之前需要版本定义,通常为:require_relative 'P4/version'
没有在我的C ++扩展代码中定义类,而是加载它并扩展我的版本文件中定义的类:
//确保该类已由版本规范定义 cP4 = rb_path2class(“P4”);