I was looking for a way to hack with Perl 5 from C# and found PerlNet(from activestate) and PerlSharp(open source) which is only for Mono and Unix-like os … Frustrated I started to make it working on my platform and compiler.
Introduction
To begin, PerlSharp was written by Joshua Tauberer and last built was on 6/6/2005…
Compilation
Okay, just extract archive content, I want to compile project: then I remember that nmake is not make !
So I start rewriting a Makefile for nmake, it took me long time to find which compiler to use, how to mix them and which flags to set!
Yes, it was my first C# project.
I found nmake file poorer than make for its lake of reading output of a command to define a macro, or I miss something?
So I wrote a pseudo generator in order to setup CC and LD flags from Perl Config.pm module here is the *hack* :
!IF EXIST(config.mak)
!ELSE
!MESSAGE Build additional configuration 'config.mak' file
!IF [echo CCFLAGS = \> config.mak]
!ENDIF
#Take ccflags without -MT -MD -MDd -MTd
!IF [perl -MConfig -e "$$_=$$Config{ccflags};s!(-|/)M(T|D)d?!!g; print $$_,' -I',$$Config{archlibexp}.'\CORE'" >> config.mak]
!ENDIF
!IF [echo+ >> config.mak]
!ENDIF
!IF [echo LDFLAGS = \>> config.mak]
!ENDIF
!IF [perl -MConfig -e "print join ' ', $$Config{libperl}, '-libpath:'.$$Config{archlibexp}.'\CORE'" >> config.mak]
!ENDIF
!MESSAGE Configuration file generated.
!ENDIF
!INCLUDE config.mak
C# DllImport referenced to “Perl” which is resolved to perl.dll but I was working with Perl 5.10 and required them to resolved to perl510.dll.
So I was refactoring all DllImport to they point to a constant into the master namespace, so I can change the reference without editing every sources.
namespace Perl {
public class PERL_DLL{
public const String name = "perl510";
}
...
[DllImport(PERL_DLL.name)] private static extern IntPtr perl_alloc();
}
Then, it took me time again to fix minor bugs (ref count and initialization specific to Perl under Win32) and functions exports.
But the part that takes me the most of the time is the XSUB callback system, a bridge between C# Managed code and Perl XS glue.
It was running an access violation while returning from C# or some time from XS callbacks I thought it was due to a Perl stack corruption, so I decided to rewrite the bridge to make it falling under XS rather than C# which is to new for me; it was working
Yes, but I was adding lots of Perl_Warn call to trace code, and as soon as I commented out some of them it was generating access violation exceptions randomly
I finally find that C# export it’s delegate using stdcall convention by default but my XS glue was expected cdecl convention.
So after removing all hacks around callbacks, the final fix was just to add an attribute line before the delegate declaration:
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void XSUB(IntPtr interpreter, IntPtr args);
To resume, it took me about two days to write one line of code!
Hacking a bit
Now it was working I start to play with it and found that it generates perl.exe (a .net Perl interp) which now conflict with my system Perl interpreter!
I decided to rename perl.exe as perlinterp.exe, and added a code line just after interpreter initialization in order to let’s Perl script manipulate the C# interpreter object itself.
...
Interpreter perl = new Interpreter();
perl.AddExtensionObject( perl );
...
I was looking for a way to inject an assembly from Perl script and wrote a method Interpreter.Using( namespace ) which try to load the assembly, and an Interpreter.CreateObject( typename ) method that will create an instance of a particular object.
So I could write a Perl script (samples/script02.pl) that open a WinForm which is declared in a separated assembly ( samples/MyForm.dll ).
>ildasm PerlSharp.dll
Limitation
The callback system creates a XS Bridge for each public method of an object passed to Interpreter.AddExtensionObject.
The trick is that overloaded methods are not handled with this system, as Perl 5 disallow to declare multiple subs with the same name, because argument list is variable by default.
Another limitation is that the package method exported is linked with a particular instance of a C# object.
Conclusion
This was a good C# learning challenge for me but I may consider writing something else if I want to better interact between .Net and Perl 5.
But if you want to hack yourself, the MS.Net release is attached.
License
Still the one fixed by the author: the README file says “PerlSharp is released under the GPL.”