PerlObjCBridge

last edited September 5, 2005 09:24:07 (61.122.67.57)
CocoaDev is sponsored by: Panic: Shockingly good Mac software!

CocoaGlossary:Languages (Bridges) - Objective-C bridge for Perl

From the manpage for PerlObjCBridge:

" The PerlObjCBridge module supports creating and messaging Objective-C objects from Perl programs, allowing Cocoa objects in Apple Computer's Mac OS X to be directly manipulated from Perl. In addition, Perl objects can be messaged from Objective-C, making it possible for Perl objects to function as Cocoa delegates and as targets of notifications and other Cocoa call-back messages. Perl programs can take advantage of Cocoa's Distributed Objects mechanism to support messaging between Perl objects and Objective-C objects (or other Perl objects) in different address spaces, possibly on different machines."

See also this web page: http://cocoadevcentral.com/articles/000076.php for more information.


Before reading this, you should be familiar with the PerlObjCBridge man page (in the terminal or, for example, at http://www.hmug.org/man/3/PerlObjCBridge.html )

I wanted the example of the man page to work without using xs. In the end, my goal is to be able to talk to a Perl module from within a Cocoa application, using the Distributed Objects runtime system, and using NSBundle instead of xs, so encapsulation in the application bundle will be natural. When I have time, I will add such an example to this page.

(see also http://www.whoot.org/archives/000009.html , where James Duncan develops the same idea)

I put all the code in AddSystemFramework. I give some details below.

I created in Project Builder a framework named 'AddSystemFramework' to define the two Objective-C classes:

  • Addserver
  • Addclient
This is the equivalent of the xs code in the man page example. The classes declare some mock methods that have to have the same signature as the methods that will be declared in Perl, so the Distributed Object runtime will make the proper calls. I found that this code has to be different from what is used in the man page example. Apparently, for some reason, the 'Addserver' class has to know that the client actually implements the 'firstNumber' and 'secondNumber' methods, ie some static typing is needed. I don't understand why this is needed, as the Objective C runtime should be able to find the class of the client at runtime, and do the proper calls. In the man page example, the xs code does not do any static typing and it works fine. In my example, I decided to use a protocol, and it does not work without it (and I am not just talking about compilation errors). Maybe somebody can explain that...

Instead of 3 perl files, I created 5 (that was just to make things a little "cleaner", separating the module parts from the script part):

  • addSystemFramework.pm = the module that loads the framework. This replaces the Addsystem.pm module of the man page example, as well as the xs stuff. Calling this module will start the bridge and will let the Objective C side know about the 'Addserver' and 'Addclient' classes
  • addserver.pm = the module that defines the perl class equivalent to the Objective C 'Addserver' class, and 'links' it to the Objective C runtime
  • addclient.pm = the same for the Objective C 'Addclient' class
  • runserver.pl = the script that runs the server
  • runclient.pl = the script that runs the client

The addSystemFramework.pm module essentially does the following:

  • use Foundation; this will start the whole PerlObjCBridge thing and make all the declarations needed to use the Foundation classes
  • NSBundle->bundleWithPath('AddSystemFramework')->load(); this will simply load the framework and the classes in the Objective C runtime

The 'addserver.pm' and 'addclient.pm' module do the following:

  • use addSystemFramework; I just explained what that does
  • declare an oject-oriented Perl module with the appropriate name (Addclient or Addserver)
  • make this module inherit from PerlObjCBridge, which will ensure proper forwarding of the messages from the Objective C runtime to the Perl program
  • declare the methods and write their code; the Objective C counterparts of these methods are defined in the AddSystemFramework framework; the methods declared in Perl should have the appropriate name and return the right type; they take $self as their first argument, and then the Objective C arguments
  • PerlObjCBridge::preloadSelectors('CLASS_NAME'); where CLASS_NAME is 'Addclient' or 'Addserver'; I am not sure what this is for; the PerlObjCBridge man page says it is needed to pre-cache the selectors; it does more than that, as pre-caching is not normally needed for the Objective C runtime; anyway, this is necessary for the programs to run properly;

The runclient.pl and runserver.pl scripts do essentially the same as the man page example. Note that runclient.pl do 'use Addclient;' and 'use Addserver;', while runserver.pl only 'use Addserver;'. However, the Addserver module has to 'use Addclient;', so well...

To get the example to work, put all the perl files AND THE FRAMEWORK in the same folder, ie copy the compiled framework from the project 'build' folder. I guess as an alternative, you could put it in /Library/Frameworks/. Open two windows in Terminal.app where you should 'cd' to the folder. Type 'perl runserver.pl' in one window. The server is now running. Type 'perl runclient 2 2' in the other window...