2011-09-20 8 views
18

D에서 C API를 호출하는 방법에 대한 정보는 충분하지만 그 반대의 경우는 어떨까요? 일반적인 C 공유 라이브러리처럼 작동하는 D 라이브러리를 작성하려면 무엇을해야합니까?D에서 D API 구현 D

main.c를

extern(C) 
{ 
    int foo(int x) 
    { 
     return x*x; 
    } 
} 

이 순진하게 구축하고 GCC와 DMD 단지 링커 오류 결과 이러한 연결을 시도

extern int foo(int x); 
void main() { 
    printf("foo(5)=%d\n",foo(5)); 
} 

foo.d : 다음은 쉬운 경우이다.

GCC의 main.o를의 foo.o와 연결 :

doFoo.o: In function `no symbol': 
doFoo.d:(.text+0x7): undefined reference to `_Dmodule_ref' 
collect2: ld returned 1 exit status 

DMD main.o를 foo.o와 연결 :

/usr/lib64/libphobos2.a(deh2_2eb_525.o): In function `_D2rt4deh213__eh_finddataFPvZPS2rt4deh213DHandlerTable': 
src/rt/deh2.d:(.text._D2rt4deh213__eh_finddataFPvZPS2rt4deh213DHandlerTable+0xa): undefined reference to `_deh_beg' 
src/rt/deh2.d:(.text._D2rt4deh213__eh_finddataFPvZPS2rt4deh213DHandlerTable+0x14): undefined reference to `_deh_beg' 
src/rt/deh2.d:(.text._D2rt4deh213__eh_finddataFPvZPS2rt4deh213DHandlerTable+0x1e): undefined reference to `_deh_end' 
src/rt/deh2.d:(.text._D2rt4deh213__eh_finddataFPvZPS2rt4deh213DHandlerTable+0x46): undefined reference to `_deh_end' 
/usr/lib64/libphobos2.a(lifetime.o): In function `_D2rt8lifetime18_sharedStaticCtor9FZv': 
src/rt/lifetime.d:(.text._D2rt8lifetime18_sharedStaticCtor9FZv+0x15): undefined reference to `_tlsend' 
src/rt/lifetime.d:(.text._D2rt8lifetime18_sharedStaticCtor9FZv+0x29): undefined reference to `_tlsstart' 
/usr/lib64/libphobos2.a(thread_a3_258.o): In function `_D4core6thread6Thread6__ctorMFPFZvmZC4core6thread6Thread': 
src/core/thread.d:(.text._D4core6thread6Thread6__ctorMFPFZvmZC4core6thread6Thread+0x2b): undefined reference to `_tlsend' 
src/core/thread.d:(.text._D4core6thread6Thread6__ctorMFPFZvmZC4core6thread6Thread+0x36): undefined reference to `_tlsstart' 
/usr/lib64/libphobos2.a(thread_a3_258.o): In function `_D4core6thread6Thread6__ctorMFDFZvmZC4core6thread6Thread': 
src/core/thread.d:(.text._D4core6thread6Thread6__ctorMFDFZvmZC4core6thread6Thread+0x28): undefined reference to `_tlsend' 
src/core/thread.d:(.text._D4core6thread6Thread6__ctorMFDFZvmZC4core6thread6Thread+0x33): undefined reference to `_tlsstart' 
/usr/lib64/libphobos2.a(thread_a3_258.o): In function `_D4core6thread6Thread6__ctorMFZC4core6thread6Thread': 
src/core/thread.d:(.text._D4core6thread6Thread6__ctorMFZC4core6thread6Thread+0x26): undefined reference to `_tlsend' 
src/core/thread.d:(.text._D4core6thread6Thread6__ctorMFZC4core6thread6Thread+0x31): undefined reference to `_tlsstart' 
/usr/lib64/libphobos2.a(thread_a0_713.o): In function `thread_entryPoint': 
src/core/thread.d:(.text.thread_entryPoint+0x36): undefined reference to `_tlsend' 
src/core/thread.d:(.text.thread_entryPoint+0x41): undefined reference to `_tlsstart' 
collect2: ld returned 1 exit status 
--- errorlevel 1 
+2

음이, '우리가 매달고 떠나 지마 ... 오류는 무엇인가? – Mehrdad

+0

링커 오류는 다음과 같습니다 :'foo.o : 함수에서 '기호 없음': foo.d :(. 텍스트 + 0x7) : 정의되지 않은 참조 '_Dmodule_ref'' –

답변

9

내 대답은 에서 CD 정적 라이브러리을 사용하는 방법에 대한 것입니다. 예, 약간 주제는 같지만, Windows의 공유 라이브러리는 D의 문서 (http://www.d-programming-language.org/dll.html)에 설명되어 있으며 의 경우 Linux은 아직 공사 중입니다. (http://www.digitalmars.com/d/2.0/changelog.html). 두 시스템의 작업 예제가 첨부되어 있습니다.

  • 는 Win32 : DMD + DMC 잘 작동합니다. 는 : test_d_from_c_win32.zip

  • Linux32 : 원함 D'의 주요 필요하므로 (Linux32에 dmd2 + GCC 테스트) D 주요 기능을 발견되면 DMD 일부 필요한 재료를 추가한다. 링크 이름이 "_Dmain"이고 C의 이름 (실제 "메인")과 섞이지 않습니다. dfakemain.d 파일에 void main(){} 텍스트를 추가하기 만하면됩니다. dmd -c dfakemain.d은 기호가 누락 된 dfakemain.o를 만듭니다. 개체 파일과 연결하면 행복하게됩니다. : test_d_from_c_linux32.tar.gz

+1

흠, 리눅스 메소드가 저에게 효과적 이었지만 여전히 문제가 있습니다. 하나는 dmd를 링커로 사용해야한다는 것입니다. 해당 문제를 해결하기 위해 연결할 수있는 라이브러리가 있습니까? 둘째로 가짜 메인을 고집하는 것처럼 보이기 때문에 라이브러리가 D 라이브러리가 아니며 같은 트릭을 사용하는 다른 라이브러리와 호환되지 않을 수도 있습니다. – sholte

+0

아니요 dmd를 링커로 사용하려면 필요하지 않습니다. (dmd는 링크 할 수 없기 때문에 외부 링커를 호출하기 만합니다.) 당신은'dfakemain.o'와 링크 만하면됩니다. 내 리눅스 예제에서 gcc는 "링커 호출자"로 사용됩니다. _ 해당 문제를 해결하기 위해 연결할 수있는 라이브러리가 있습니까? _ 예. 'dfakemain.o'입니다. 예를 들어, D 라이브러리 (dlibrary.o)와 연결되어 있지 않아야합니다. 일부 D 라이브러리를 사용하는 경우 실행 파일마다 한 번씩 연결해야합니다. – Denis

+0

아, 내 대답은 실제로 당신의 예제 build.sh에 나타났습니다. 솔루션의 -lrt -lphobos2 -lpthread -lm 부분이 누락되었습니다. – sholte

6

것은 GCC는 C로 컴파일 된 경우 ++, 사용되는 기본 연결을 extern은 C가 아니라 C++ 일 것입니다. 대신 다음을 시도하십시오 :

extern "C" int foo(int x); 

D 구문에 문제가없는 것 같습니다. 여기에 접근 방식을 확인하는 단락이 있습니다. http://www.digitalmars.com/d/2.0/interfaceToC.html

+1

아니요, C++로 컴파일하지 않습니다. 그냥 평범한 옛날 gcc -c main.c – sholte

9

compiler source code의 빠른 눈에 따르면 _Dmodule_ref은 모듈 생성자의 링크 된 목록입니다.

void* _Dmodule_ref; 

이 프로그램은 지금 링크를하고 잘 실행 : 문제를 해결하려면 main.c이를 추가 할 수 있습니다.

은 (적어도 그게 내가 작동 생각하는 방법입니다.)

+2

나는 링커 에러를 고치기보다는 D 런타임을 초기화하라는 호출을 실제로해야한다고 확신한다. 그러나 실제로 전에 이것을 한 적이 없다. 알아. 나는 뉴스 그룹의 일부 사람들이 Windows GUI 응용 프로그램을 위해 그것을 해왔다는 것을 알고 있습니다. 그래서 사람들은 정확히 무엇을해야할지 압니다. 방금 D.Learn에 질문을 올렸습니다. 다행히도, 여기있는 사람이 여기에서 응답 할 것입니다. –

+0

네가 메모리 할당이나 정적 생성자 같은 멋진 것들을 원한다면 확실히 설정해야한다. :) 그러나 더 나은 C로 D를 사용하고 싶다면이 방법이 효과적이다. –

+0

이것은이 경우에 효과가있는 것처럼 보이지만 좀 더 철저히 지켜보고 싶습니다. 이 상징이 무엇을해야하는지 알고 있습니까? – sholte