2016-10-31 10 views
1

Я пытаюсь создать собственное расширение ruby, но когда я запустил rake, который использует ext/example_project/extconf.rb для создания моего проекта и выполнения моих тестов под test/, я получаю следующую ошибку при запуске тестов:ruby ​​native extension: undefined symbol

./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 из корня проектов.

Некоторая дополнительная информация:

  • Я использовал рубиновый камень hoe создать проект с помощью sow example_project
  • Функции провала пытается вызвать функцию, определенную в подкаталоге ext/example_project/c_example_project. В моем фактическом проекте используется подмодуль git из каталога ext/example_project, который, в свою очередь, устанавливает подмодуль в качестве подкаталога. Подмодуль представляет собой проект c с плоской структурой (все файлы в корневом каталоге). Примечание: Эта формулировка может вводить в заблуждение, но ключевым моментом является то, что существует вложенный проект c, определенный в ext/example_project/c_example_project, у которого есть методы, которые я пытаюсь вызвать.

Сообщите мне, если требуется какое-либо разъяснение, и я сделаю все возможное, чтобы обеспечить его.

+0

Просто последуйте за ними, если для этого есть что-то лучше, чем 'hoe', пожалуйста, дайте мне знать. Я использовал [учебник] (https://tenderlovemaking.com/2009/12/18/writing-ruby-c-extensions-part-1.html) в качестве точки запуска, но ему 7 лет, поэтому, возможно, что-то лучше приходите с тех пор! – JesseBuesking

ответ

2

Итак, есть несколько интересных вопросов, которые у вас есть. По умолчанию mkmf фактически не поддерживает указание нескольких каталогов для создания источников.

Существует обходной путь, как показано здесь (Такэхиро Кубо комментарий о настройке OBJS):

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

В принципе, вы строите $objs глобальный в вашем extconf.rb файл самостоятельно.

Используя код GitHub, вот что я добавил к extconf.rb и получил работу

extconf.Р.Б.

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_example_project}/*.c, по-видимому, так как он работает в extconf.rb файл из другого каталога.

Кроме того, в ваших тестах/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; 
} 

Пояснения

В принципе, даже если вы проверяете заголовок c_example_project.h в вашем extconf.rb, вы на самом деле не порождающие объектный файл, где определено значение some_function. Таким образом, при связывании конечной динамической библиотеки, загружаемой рубином, нет определения для some_function, и вы получите свою ошибку.

+0

Удивительный! Да, я думал, что проблема в том, что файл не был скомпилирован и правильно связан, я просто не знал, как это сделать. Спасибо, что поняли, что нужно сделать! – JesseBuesking

0

У меня нет опыта создания внутренних расширений, но из исходного кода mkmf похоже, что вы можете указать только один исходный каталог. Я переместил оба файла с c_example_project в родительский каталог, и все было правильно связано. Думаю, именно так вы должны это делать. Все обычные драгоценные камни (например, pg, nokogiri и т. Д.) Имеют такую ​​структуру кода, все файлы * .c и * .h находятся в одном каталоге.

Вы всегда можете создать Makefile самостоятельно, но для этого потребуется слишком много работы.

PS. Ваш проект скомпилирован успешно, но у вас есть ошибка сегментации, потому что вы должны вернуть правильный объект строки ruby ​​в some_function, а не указатель на строку.

+0

Я надеялся на решение, которое не связано с перемещением файлов вверх по каталогу, так как это означает, что я больше не могу использовать подмодуль git и вместо этого должен полагаться на копирование файлов вручную ... если никто другой не даст лучшего ответа I я приму твое, хотя я надеюсь, что есть лучшее решение. – JesseBuesking