2

我正在尝试创建一个 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,但我不确定如何。

我创建了一个简单的存储库,用于在 GitHub 上演示该问题。如果您克隆它并rake从项目根目录运行,它将失败并出现相同的错误。

一些附加信息:

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

让我知道是否需要任何澄清,我会尽力提供。

4

3 回答 3

4

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

有一种解决方法,如此处所示(Takehiro Kubo's comment about setting 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 源构建一个绝对路径,由于某种原因,如果我们只是使用 ,rake-compiler 会吓坏{.,c_example_project}/*.c,大概是因为它正在从另一个目录运行 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​​ 加载的最终动态库时,没有定义 forsome_function并且您会得到错误。

于 2016-11-08T17:08:26.800 回答
0

我没有任何构建本机扩展的经验,但是从mkmf源代码看来,您只能指定一个源目录。我将这两个文件都从父目录移到c_example_project了父目录,并且所有内容都已正确链接。我认为这就是你应该这样做的方式。所有常见的 gem(如 pg、nokogiri 等)都有这样的代码结构,所有 *.c 和 *.h 文件都在一个目录中。

你总是可以Makefile自己创造,但这需要太多的工作来维护。

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

于 2016-11-03T07:57:17.353 回答
0

photoionized 有一个很好的答案,但是 $obj 可以是数组而不是枚举器。简单地使用绝对路径似乎没问题。

$objs = Dir.glob([".c", "libfoobar/*.c"], base: __dir__)
           .map { |f| File.expand_path(f, __dir__) }
           .map { |f| f.sub(/\.c$/, ".o") }
于 2021-12-18T23:27:56.177 回答