ruby原生扩展:未定义的符号

时间:2016-10-31 04:44:12

标签: ruby ruby-c-extension extconf.rb ruby-native-extensions

我尝试创建ruby原生扩展,但当我运行rake使用ext/example_project/extconf.rb构建我的项目并在test/下运行我的测试时,我得到了运行测试时出现以下错误:

./home/jbuesking/.rbenv/versions/2.3.0/bin/ruby: symbol lookup error: 
/home/jbuesking/repositories/example_project/lib/example_project/example_project.so: undefined symbol: some_function

我非常确定我的文件没有正确关联,我需要以某种方式更改我的extconf.rb和/或Rakefile,但我不确定

我创建了一个简单的存储库来演示问题over on GitHub。如果您克隆它并从项目根目录运行rake,它将失败并返回相同的错误。

其他一些信息:

  • 我使用ruby gem hoe通过sow example_project
  • 创建项目
  • 失败的函数正在尝试调用子目录ext/example_project/c_example_project中定义的函数。我的实际项目使用ext/example_project目录中的git子模块,该子模块又将子模块设置为子目录。子模块是一个具有扁平结构的c项目(根目录中的所有文件)。 注意:这个措辞可能会让人感到困惑,但关键点在于ext/example_project/c_example_project定义了一个嵌套的c项目,其中包含我试图调用的方法。

如果需要澄清,请告诉我,我会尽力提供。

2 个答案:

答案 0 :(得分:3)

所以,你有一些有趣的问题。默认情况下,mkmf实际上不支持为构建源指定多个目录。

有一种解决方法,如此处所示(Takehiro Kubo关于设置objs的评论):

https://www.ruby-forum.com/topic/4224640

基本上,您自己在$objs文件中构建extconf.rb全局。

使用你的github代码,这是我添加到extconf.rb并开始工作的内容

<强> extconf.rb

globs = [".", "c_example_project"].map do |directory|
  File.join(File.dirname(__FILE__), directory)
end.join(",")

$objs = Dir.glob("{#{globs}}/*.c").map do |file|
  File.join(File.dirname(file), "#{File.basename(file, ".c")}.o")
end

注意我实际上构建了一个到每个c源的绝对路径,出于某种原因,如果我们只是用{.,c_example_project}/*.c进行通信,那么rake-compiler就会吓坏,大概是因为它正在运行extconf.rb文件。另一个目录。

此外,您的tests / c扩展程序中存在一些错误。在example_project.c中进行以下更改可修复测试失败:

 static VALUE example_project_c_code_function()
 {
-    return some_function();
+    VALUE _string = rb_str_new2(some_function());
+    int _enc = rb_enc_find_index("UTF-8");
+    rb_enc_associate_index(_string, _enc);
+    return _string;
 }

<强>解释

基本上即使你在extconf.rb中检查c_example_project.h标头,你实际上并没有生成定义some_function的目标文件。因此,当链接ruby加载的最终动态库时,没有some_function的定义,您就会收到错误。

答案 1 :(得分:0)

我没有构建本机扩展的经验,但从mkmf源代码看,您只能指定一个源目录。我将两个文件从c_example_project移动到父目录,所有内容都正确链接。我认为你应该怎么做。所有常见的宝石(如pg,nokogiri等)都有这样的代码结构,所有* .c和* .h文件都在一个目录中。

您可以随时自行创建Makefile,但这需要太多工作才能维护。

PS。您的项目编译成功,但是您存在分段错误,因为您应该在some_function中返回正确的ruby字符串对象而不是指向字符串的指针。