PerlEmbed – C # – Mono – Linux

Qualcuno ha provato a usare perlembed in Mono su Linux?

Ecco il link: perlembed

Ecco il mio primo tentativo di firme di DllImport:

private const string PERL_LIB = "/usr/lib/perl5/5.8.8/i386-linux-thread-multi/CORE/libperl.so"; [DllImport(PERL_LIB, EntryPoint = "perl_alloc", SetLastError = true)] public static extern IntPtr Alloc(); [DllImport(PERL_LIB, EntryPoint = "perl_construct", SetLastError = true)] public static extern void Construct(IntPtr hPerl); [DllImport(PERL_LIB, EntryPoint = "perl_destruct", SetLastError = true)] public static extern void Destruct(IntPtr hPerl); [DllImport(PERL_LIB, EntryPoint = "perl_free", SetLastError = true)] public static extern void Free(IntPtr hPerl); [DllImport(PERL_LIB, EntryPoint = "perl_parse", SetLastError = true)] public static extern void Parse(IntPtr hPerl, IntPtr @null, int argc, StringBuilder argv, StringBuilder env); [DllImport(PERL_LIB, EntryPoint = "perl_run", SetLastError = true)] public static extern void Run(IntPtr hPerl); [DllImport(PERL_LIB, EntryPoint = "eval_pv", SetLastError = true)] public static extern void Eval(string expr, bool flag); 

La directory CORE può cambiare per distro Linux.

Il codice seguente viene eseguito, ma si arresta in modo Parse() metodo Parse() :

 try { Console.WriteLine("Alloc"); IntPtr perl = Alloc(); Console.WriteLine("Construct"); Construct(perl); Console.WriteLine("Parse"); Parse(perl, IntPtr.Zero, 3, new StringBuilder("-e 0"), new StringBuilder()); Console.WriteLine("Run"); Run(perl); Console.WriteLine("Eval"); Eval("$a = 3.14; $a **= 2", true); Console.WriteLine("Destruct"); Destruct(perl); Console.WriteLine("Free"); Free(perl); } catch (Exception exc) { Console.WriteLine(exc.ToString()); } 

Il mio incidente si legge:

 ================================================================= Got a SIGSEGV while executing native code. This usually indicates a fatal error in the mono runtime or one of the native libraries used by your application. ================================================================= Stacktrace: in (wrapper managed-to-native) Woot:Parse (intptr,intptr,int,System.Text.StringBuilder,System.Text.StringBuilder)  in (wrapper managed-to-native) Woot:Parse (intptr,intptr,int,System.Text.StringBuilder,System.Text.StringBuilder)  in Woot:Main ()  in (wrapper runtime-invoke) System.Object:runtime_invoke_void (object,intptr,intptr,intptr)  

Stacktrace nativo:

  mono(mono_handle_native_sigsegv+0xbb) [0x81368fb] mono [0x8105670] [0x4c45a440] /usr/lib/perl5/5.8.8/i386-linux-thread-multi/CORE/libperl.so(perl_parse+0xa3) [0x4c6e6e93] [0x43ad78] [0x434cae] [0x434abe] mono(mono_runtime_exec_main+0x62) [0x80ae5a2] mono(mono_runtime_run_main+0x152) [0x80af6e2] mono(mono_main+0xef9) [0x805dae9] mono [0x805c702] /lib/libc.so.6(__libc_start_main+0xdc) [0x4c48d724] mono [0x805c651] 

Esistono alcune PERL_SYS_INIT3 e PERL_SYS_TERM chiama quelle perlembed , ma non sono stato in grado di chiamare tali metodi tramite DllImport . In questi casi ottengo sempre EntryPointNotFoundException . Sono sicuro che sono in un file diverso che devo importare.

Qualcuno può indirizzarmi nel modo corretto per chiamare DllImports a perlembed?

    Fatto funzionare!

    Realizzato il programma perl, showtime.pl :

     #/usr/bin/perl sub showtime { print "WOOT!\n"; } 

    Fatto il programma c, perlembed.c :

     #include  #include  static PerlInterpreter *my_perl; void Initialize(char* processName, char* perlFile) { int argc = 2; char *argv[] = { processName, perlFile }, *env[] = { "" }; PERL_SYS_INIT3(&argc, &argv, &env); my_perl = perl_alloc(); perl_construct(my_perl); perl_parse(my_perl, NULL, argc, argv, NULL); PL_exit_flags |= PERL_EXIT_DESTRUCT_END; } void Call(char* subName) { char *args[] = { NULL }; call_argv(subName, G_DISCARD | G_NOARGS, args); } void Dispose() { if (my_perl != NULL) { perl_destruct(my_perl); perl_free(my_perl); PERL_SYS_TERM(); my_perl = NULL; } } 

    Compilato tramite:

     "gcc -shared -Wl,-soname,perlembed.so -o perlembed.so perlembed.c `perl -MExtUtils::Embed -e ccopts -e ldopts`" 

    Fatto questo programma C #, perlembed.cs :

     using System; using System.Runtime.InteropServices; public class Woot { [DllImport("perlembed.so", SetLastError = true)] public static extern void Initialize(string processName, string perlFile); [DllImport("perlembed.so", SetLastError = true)] public static extern void Call(string subName); [DllImport("perlembed.so", SetLastError = true)] public static extern void Dispose(); static void Main() { Console.WriteLine("Starting up C#..."); try { Initialize("perlembed.exe", "showtime.pl"); Call("showtime"); } catch(Exception exc) { Console.WriteLine(exc.ToString()); } finally { Dispose(); } Console.WriteLine("DONE!..."); } } 

    Compilato con gmcs e ottenuto l’output:

     Starting up C#... WOOT! DONE!... 

    Spero che questo aiuti qualcuno là fuori, non posso credere che siano occorse 3 lingue. Passerò a passare scalari, array, ecc. Ma dovrebbe essere una brezza da qui.

    Non riesce su perl_parse () perché l’associazione non è corretta.

    L’argomento argv è un char ** (da interpretare come una matrice di char * di dimensioni di argc): questo non ha alcuna relazione con StringBuilder, che rappresenta una stringa modificabile.

    Suggerisco di effettuare il marshalling manuale di questo array: utilizzare un IntPtr [] come argomenti argv ed env e riempire gli elementi dell’array con i puntatori alle stringhe di byte, ad esempio utilizzando Marshal.StringToCoTaskMemAnsi () se la codifica è sufficiente per te. Ricorda anche di liberare la memoria assegnata da quello.

    Ovviamente, dovresti fare tutto questo in un metodo di supporto che espone un’interfaccia più naturale ai programmatori C # che accetta una stringa [] invece della coppia argc / argv.