2011-02-27 123 views
26

嘿, 我正在學習Haskell,我有興趣使用它來製作靜態庫,以便在Python和C中使用。經過一些Google搜索後,我發現如何讓GHC輸出共享對象,但它動態地依賴於在GHC的圖書館。 在GHC中編譯生成的ELF只能動態地依賴於C庫,並且它的大小略低於MB - 它已經與GHC的libs靜態鏈接。如何以及如果這可以實現共享對象?當前狀態的如何將Haskell編譯爲靜態庫?

例子:

$ ghc --make -dynamic -shared -fPIC foo.hs -o libfoo.so 
$ ldd libfoo.so 
    linux-vdso.so.1 => (0x00007fff125ff000) 
    libHSbase-4.2.0.2-ghc6.12.3.so => /usr/lib/ghc-6.12.3/base-4.2.0.2/libHSbase-4.2.0.2-ghc6.12.3.so (0x00007f7d5fcbe000) 
    libHSinteger-gmp-0.2.0.1-ghc6.12.3.so => /usr/lib/ghc-6.12.3/integer-gmp-0.2.0.1/libHSinteger-gmp-0.2.0.1-ghc6.12.3.so (0x00007f7d5faac000) 
    libgmp.so.10 => /usr/lib/libgmp.so.10 (0x00007f7d5f816000) 
    libHSghc-prim-0.2.0.0-ghc6.12.3.so => /usr/lib/ghc-6.12.3/ghc-prim-0.2.0.0/libHSghc-prim-0.2.0.0-ghc6.12.3.so (0x00007f7d5f591000) 
    libHSffi-ghc6.12.3.so => /usr/lib/ghc-6.12.3/libHSffi-ghc6.12.3.so (0x00007f7d5f383000) 
    libc.so.6 => /lib/libc.so.6 (0x00007f7d5f022000) 
    /lib/ld-linux-x86-64.so.2 (0x00007f7d60661000) 

$ ghc foo.hs 
$ ldd foo 
    linux-vdso.so.1 => (0x00007fff2d3ff000) 
    libgmp.so.10 => /usr/lib/libgmp.so.10 (0x00007f50014ec000) 
    libm.so.6 => /lib/libm.so.6 (0x00007f5001269000) 
    librt.so.1 => /lib/librt.so.1 (0x00007f5001061000) 
    libdl.so.2 => /lib/libdl.so.2 (0x00007f5000e5d000) 
    libc.so.6 => /lib/libc.so.6 (0x00007f5000afc000) 
    libpthread.so.0 => /lib/libpthread.so.0 (0x00007f50008df000) 
    /lib/ld-linux-x86-64.so.2 (0x00007f5001759000) 

如果我嘗試(沒有 '-dynamic')進行編譯:

$ ghc --make -shared -fPIC foo.hs -o libfoo.so 
Linking libfoo.so ... 
/usr/bin/ld: foo.o: relocation R_X86_64_32S against `stg_CAF_BLACKHOLE_info' can not be used when making a shared object; recompile with -fPIC 
foo.o: could not read symbols: Bad value 
collect2: ld returned 1 exit status 

在谷歌上搜索,我發現一些有關這整個問題 - 它可能來自GHC以特定方式編譯(動態/靜態?)的事實,因此靜態鏈接是不可能的。如果這是真的,ELF二進制文件如何可能靜態鏈接?

無論如何,我希望有人能夠說明這一點,因爲大量的谷歌搜索給我留下了比我更多的問題。

非常感謝。

+0

你用什麼系統?看來它是x86_64 Linux。 GHC版本也很重要,因爲它可能實際上是一個已經修復的bug。動態鏈接在過去有一些缺陷,它可能是其中之一。 – Tener 2011-03-01 22:45:43

+0

@Tener | Glasgow Haskell編譯器版本6.12.3,適用於Haskell 98,第2階段由GHC版本6.12.1引導|也許我應該嘗試GHC 7,看看它是否覆蓋了這個問題。 – kuratkull 2011-03-02 23:09:11

+0

@Tener。我開始安裝GHC7,但它仍然無法正常工作,雖然它給了我一些不同的錯誤。 = >>> ' - > ghc --make -shared -fPIC bwt.hs -o libbwt.so [1 of 1]編譯Main(bwt.hs,bwt.o) 鏈接libbwt.so .. 。 的/ usr /斌/ LD:/usr/lib/ghc-7.0.2/base-4.3.1.0/libHSbase-4.3.1.0.a(Base__90.o):針對 「stg_upd_frame_info」 重定位R_X86_64_32S不能使用時製作一個共享對象;使用-fPIC重新編譯 /usr/lib/ghc-7.0.2/base-4.3.1.0/libHSbase-4.3.1.0.a:無法讀取符號:錯誤值 collect2:ld返回1退出狀態# – kuratkull 2011-03-15 19:46:21

回答

4

的是這種情況的典型方式:

  1. 導出功能(通過FFI)由國外程序初始化RTS(運行時系統)
  2. 出口的實際功能,你想在Haskell實施

手冊的以下部分描述了這一點:[1][2]

在其他的方式,你可以嘗試在這個博客帖子描述的技術(其中礦,順便說一句):

http://mostlycode.wordpress.com/2010/01/03/shared-haskell-so-library-with-ghc-6-10-4-and-cabal/

它歸結爲創造這之後立即自動調用一個小的C文件庫被加載。 它應該被鏈接到圖書館。

#define CAT(a,b) XCAT(a,b) 
#define XCAT(a,b) a ## b 
#define STR(a) XSTR(a) 
#define XSTR(a) #a 

#include 

extern void CAT (__stginit_, MODULE) (void); 

static void library_init (void) __attribute__ ((constructor)); 
static void 
library_init (void) 
{ 
     /* This seems to be a no-op, but it makes the GHCRTS envvar work. */ 
     static char *argv[] = { STR (MODULE) ".so", 0 }, **argv_ = argv; 
     static int argc = 1; 

     hs_init (&argc, &argv_); 
     hs_add_root (CAT (__stginit_, MODULE)); 
} 

static void library_exit (void) __attribute__ ((destructor)); 
static void 
library_exit (void) 
{ 
    hs_exit(); 
} 

編輯:原創博客文章說明該手法是這樣的:http://weblog.haskell.cz/pivnik/building-a-shared-library-in-haskell/

+3

謝謝,但這些方法都沒有工作(同樣的錯誤),它可能是由於這種(以您所提供的鏈接之一找到):「在大多數平臺但將要求所有已建有-fPIC靜態庫,以便該代碼適合包含到共享庫中,而我們目前不這樣做。「我可以假設我將不得不用手動重新編譯GHC來解決我的問題 - 否則這是不可能的。我會將你的答案標記爲正確的答案,因爲在重新編譯GHC之後,所有這些都應該工作。非常感謝 :) – kuratkull 2011-03-20 16:08:20

0

這使得GHC靜態編譯(注意並行線程是optl靜態前): ghc --make -static -optl-pthread -optl-static test.hs

編輯:但靜態編譯似乎有點冒險。大多數時候都有一些錯誤。而在我的x64 fedora上它根本不起作用。形成的二分也是相當大的,1.5M的main = putStrLn "hello world"

+5

但是這使得可執行文件的靜態,我想有靜態庫(*。所以/ * a)所示。我試圖用 '-shared' 標誌在那裏,但我得到: 在/ usr/bin中/ LD:/usr/lib/gcc/x86_64-unknown-linux-gnu/4.5.2/crtbeginT.o:搬遷R_X86_64_32在製作共享對象時不能使用'__DTOR_END__';與-fPIC /usr/lib/gcc/x86_64-unknown-linux-gnu/4.5.2/crtbeginT.o重新編譯:看不懂的符號:錯誤值。 好像做靜態庫可能完全不畢竟那麼容易。或者我做錯了什麼? – kuratkull 2011-02-28 11:52:56