PerlEmbed - C# - Mono - Linux
c#, embed, linux, mono, perl
Solution
Got it to work!
Made the perl program, showtime.pl:
#/usr/bin/perl
sub showtime {
print "WOOT!\n";
}
Made the c program, perlembed.c:
#include <EXTERN.h>
#include <perl.h>
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;
}
}
Compiled it via:
"gcc -shared -Wl,-soname,perlembed.so -o perlembed.so perlembed.c `perl -MExtUtils::Embed -e ccopts -e ldopts`"
Made this C# program, 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!...");
}
}
Compiled it with gmcs, and got the output:
Starting up C#...
WOOT!
DONE!...
Hope this helps anyone out there, can't believe it took 3 languages to happen. I will move on to passing scalars, arrays, etc. but it should be a breeze from here.
Problem
Has anyone attempted using perlembed in Mono on Linux? Here is the link: perlembed Here is my first attempt at the DllImport signatures: ``` 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); ``` The CORE directory can change per Linux distro. The following code runs, but crashes on the `Parse()` method: ``` 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()); } ``` My crash reads: ``` ================================================================= 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) <0x4> in (wrapper managed-to-native) Woot:Parse (intptr,intptr,int,System.Text.StringBuilder,System.Text.StringBuilder) <0xffff9f85> in Woot:Main () <0x8d> in (wrapper runtime-invoke) System.Object:runtime_invoke_void (object,intptr,intptr,intptr) <0x7c79b09> ``` Native stacktrace: ``` 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] ``` There are some `PERL_SYS_INIT3`, and `PERL_SYS_TERM` calls that perlembed mentions, but I have not been able to call those methods through `DllImport`. I always get `EntryPointNotFoundException` in those cases. I'm sure they are in a different file I need to import. Can someone direct me in the correct way to call `DllImports` to perlembed?