2013-01-18 23 views
10

長時間監聽器,第一次調用者。我知道這是一個有點晦澀的問題,不要指望太多。 :-)用DynaLoader.pm在Perl中加載Ada共享對象

我有以下阿達文件:

greeter.ads

package Greeter is 
    procedure Hello; 
end Greeter; 

greeter.adb

with Ada.Text_IO; use Ada.Text_IO; 
package body Greeter is 
    procedure Hello is 
    begin 
     Put_Line ("Hello, world!"); 
    end Hello; 
end Greeter; 

而且它們編成像一個共享對象這個:

gnatmake -z -fPIC greeter.adb 
gcc -shared -o libgreeter.so greeter.o 

這編譯得很好。 nm顯示下列符號:

$ nm -D libgreeter.so 
       w _Jv_RegisterClasses 
0000000000201028 A __bss_start 
       w __cxa_finalize 
       w __gmon_start__ 
       U __gnat_eh_personality 
0000000000201028 A _edata 
0000000000201038 A _end 
00000000000006a8 T _fini 
0000000000000520 T _init 
       U ada__text_io__put_line__2 
0000000000201018 D greeter_E 
000000000000063c T greeter__hello 

現在我嘗試加載共享對象在Perl:

#!/usr/bin/env perl 

use 5.014; 
use strict; 
use warnings; 

#BEGIN { $ENV{PERL_DL_DEBUG} = 1 }; 

package Greeter 
{ 
    use constant ADADIR => '/usr/lib/gcc/x86_64-linux-gnu/4.4/rts-native/adalib/'; 
    use constant OURDIR => do { (my $f = __FILE__) =~ s{[^/]+$}//; $f || "." }; 

    require DynaLoader; 
    our @ISA = 'DynaLoader'; 

    my $runtime = DynaLoader::dl_load_file(
     ADADIR.'/libgnat.so', 
    ) or die DynaLoader::dl_error(); 

    my $gep = DynaLoader::dl_find_symbol(
     $runtime, 
     '__gnat_eh_personality', 
    ) or die DynaLoader::dl_error(); 

    my $libref = DynaLoader::dl_load_file(
     OURDIR.'/libgreeter.so', 
     0x01, 
    ) or die DynaLoader::dl_error(); 

    my $func = DynaLoader::dl_find_symbol(
     $libref, 
     'greeter__hello', 
    ) or die DynaLoader::dl_error(); 

    print $func, $/; 
} 

但這種炸彈不與下面的消息:

./libgreeter.so :undefined symbol:__gnat_eh_ personality at ./greeter.pl line 26.

有沒有人有任何提示?有什麼比DynaLoader更好/更容易使用?

我與這裏的所有相關文件的存儲庫:給沒有太大的Perl知識

回答

9

我不能幫助Perl方面(你需要5.14,Mac OS X有5.12,Debian 6有5.10)。也就是說,我可以幫助構建C主庫和直接鏈接庫...

GNAT構建過程非常複雜,有兩種工具可以支持它:gnatmakegprbuild。很可能(寫於2015年9月)gnatmake將失去構建庫的能力,因此gprbuild是更好的選擇。

我認爲你需要一個獨立庫項目(也就是說,有一個控制Ada精化的初始化和終結操作;如果你不初始化Ada庫,你會得到SEGVs或其他不好的東西行爲)。你會發現建立一個here的內幕。

greeter.gpr我寫的是

project Greeter is 
    for Library_Name use "greeter"; 
    for Library_Kind use "relocatable"; 
    for Library_Dir use "lib"; 
    for Library_Interface use ("greeter"); 
    for Library_Auto_Init use "true"; -- the default, I think 
    for Object_Dir use ".build"; -- to keep temp objects out of the way 
end Greeter; 

Library_Name屬性控制庫的名稱;在Mac OS X上爲libgreeter.dylib,在Linux上爲libgreeter.so

Library_Kind屬性也可以是"static",在這種情況下名稱將是libgreeter.a。但是,獨立庫必須可重定位

您必須提供的Library_Dir屬性(與上述兩者一起)用於創建庫,它控制庫的創建位置;在這種情況下,在lib/

您必須提供Library_Interface屬性才能使其成爲獨立庫,並生成控制Ada精化的初始化和結束操作。他們被稱爲庫名init庫名final - 在這裏,greeterinit,greeterfinal

如果Library_Auto_Init"false"你必須自己調用初始化和結束操作,如果是"true",它們是自動管理的。

OK,通過

gprbuild -p -P greeter 

建庫(-p爲 「創建任何需要的輸出目錄」,-P指定項目文件)。

我使用

$ gcc greeter.c -o greeter -L lib -l greeter 

,並使用

$ LD_LIBRARY_PATH=./lib ./greeter 
+0

西蒙·賴特++(在Linux上)運行內置greeter.c

#include <stdio.h> extern void greeter_hello(); int main() { greeter__hello(); return 0; } 

,這給了我開始使用一些好東西。我會嘗試一下,如果它有效,將會接受這個答案。 – tobyink

+0

我還沒有嘗試過這個,但同時我已經接受了答案,因爲它似乎是迄今爲止更有前途的兩個。 – tobyink

4

我會做這個盡我所能。

它看起來像我在perl中的Dynaloader是一個實用工具,它允許您將可動態加載的庫(Unix系統上的lib * .so)加載到perl程序中。

要使用Ada程序,您需要考慮幾件事情。

  1. 您需要將Ada程序構建爲合適的動態庫。看起來你是這麼做的。不過,我不是這方面的專家,所以也許你錯過了一些東西。我強烈建議在TFM上查看。
  2. 您需要正確調用您的Ada代碼。 Ada程序通常需要在執行任何實際代碼之前執行稱爲「精化」的過程。爲了達到這個目的,大多數Ada編譯器爲程序創建了一個特殊的入口點,而不僅僅是使用與「主」例程相關的入口點。我認爲Gnat的是像C_yourprogramname,但不要抱着我。即使你正在實施某種類型的圖書館,也應該先進行闡述(在某些特殊情況下可能會失敗,這在此不適用)。但是,如果你想讓一個例程成爲Ada之外調用的庫例程,你通常不需要一個「main」,所以還有一些額外的步驟。如何用Gnat做到這一點是described in their user guide,但總的來說,它涉及到告訴編譯器不要做「主」,在從外部運行任何Ada例程之前調用adainit,並且在完成之後調用adafinal