1

루비 네이티브 익스텐션을 만들려고하는데 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을 실행하면 동일한 오류로 실패합니다.

몇 가지 추가 정보 :

  • 나는 오류가 발생한 함수는 하위 디렉토리 ext/example_project/c_example_project에 정의 된 함수를 호출하려고 sow example_project
  • 를 통해 프로젝트를 만들 루비 보석 hoe을 사용했다. 내 실제 프로젝트는 ext/example_project 디렉토리의 git 하위 모듈을 사용하며 하위 모듈을 하위 디렉토리로 설정합니다. 하위 모듈은 구조가 평평한 c 프로젝트 (루트 디렉토리의 모든 파일)입니다. 참고 : 그 말씨가 혼란 스러울 수도 있지만 요점은 ext/example_project/c_example_project에 정의 된 중첩 된 C 프로젝트가 있는데 그 중 하나는 호출하려는 메소드가 있다는 것입니다.

설명이 필요한 경우 알려주세요. 최선을 다해 제공해 드리겠습니다.

+0

후속 조치로,이를 수행하기 위해 '괭이'보다 더 나은 것이 있다면 알려 주시기 바랍니다. 나는 튜토리얼을 사용했다. (https://tenderlovemaking.com/2009/12/18/writing-ruby-c-extensions-part-1.html) 발사 지점으로 사용되었지만 7 년이 넘었다. 그때 이후로 오십시오! – JesseBuesking

답변

2

여기 흥미로운 점이 몇 가지 있습니다. 기본적으로 mkmf는 실제로 소스를 빌드하기 위해 여러 디렉토리를 지정하는 것을 지원하지 않습니다.

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

기본적으로, 파일을 직접 당신의 extconf.rb$objs 세계를 구축 :

은 (OBJS 설정에 대한 타케 히로 쿠보의 코멘트) 여기에서 볼 수 있듯이, 해결 방법이 있습니다.

는 github의 코드를 사용하여, 여기에 내가 extconf.rb에 추가

extconf 작동있어거야.우리가 {.,c_example_project}/*.c과 글 로빙 된 경우

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 소스의 각 절대 경로를 구성하고있어 경우 rb는 extconf.rb을 실행중인 아마도 때문에, 현실에서 도피하고 있었다 다른 디렉토리의 파일.

또한 테스트/c 확장에는 몇 가지 오류가 있습니다. example_project.c에서 다음과 같은 변화를 만드는 것은 테스트 실패 수정 : 당신이 당신의 extconf.rb에서 c_example_project.h 헤더를 확인하고 비록

기본적으로

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; 
} 

설명, 당신은 실제로 발생하지 않을 오브젝트 파일 some_function이 정의됩니다. 따라서 루비가로드하는 최종 동적 라이브러리를 연결할 때 some_function에 대한 정의가 없으므로 오류가 발생합니다.

+0

굉장! 예, 파일의 컴파일과 링크가 올바르게 수행되지 않는다고 생각했습니다. 어떻게 작동하는지 모릅니다. 수행해야 할 작업을 파악해 주셔서 감사합니다! – JesseBuesking

0

네이티브 확장 기능을 구현 한 경험이 없지만 mkmf 소스 코드에서 하나의 소스 디렉토리 만 지정할 수있는 것처럼 보입니다. 두 파일을 모두 c_example_project에서 상위 디렉토리로 이동 시켰으며 모든 파일이 제대로 링크되었습니다. 나는 그것이 당신이 그것을 어떻게해야한다고 생각합니다. 모든 일반적인 보석 (pg, nokogiri 등)은 이러한 코드 구조를 가지고 있으며 * .c 및 * .h 파일은 모두 하나의 디렉토리에 있습니다.

항상 Makefile을 만들 수 있지만 유지 관리하는 데 너무 많은 작업이 필요합니다.

추신. 성공적으로 컴파일되었지만 문자열에 대한 포인터가 아닌 some_function에 올바른 루비 문자열 객체를 반환해야하기 때문에 세그먼트 화 오류가 발생했습니다.

+0

나는 파일을 디렉토리로 옮기지 않는 해결책을 원했는데, 그 이유는 더 이상 자식 서브 모듈을 사용할 수없고 수동으로 파일 복사에 의존해야한다는 것을 의미한다. 나는 더 나은 해결책이 있기를 희망하지만, 당신의 것을 받아 들일 것입니다. – JesseBuesking