perlrpcgen - generate Perl interfaces from ONC RPC interface definitions
perlrpcgen [--makefile] [--all] [--client] [--server] [--data] [--constants] [--module module] [--typemap typemap] [--fork] [--perl perl] [--cc cc] [--rpclibs rpclibs] rpcfile.x
perlrpcgen builds a set of Perl extensions and a server shell from an ONC RPC interface definition. For an interface Foo, perlrpcgen creates modules Foo::Client, Foo::Data, and Foo::Constants. Foo::Client contains routines for creating a Foo client and making remote procedure calls via the client. Foo::Data contains routines for creating and manipulating the data structures defined in the Foo interface. Foo::Constants contains functions to retrieve the constants defined in the Foo interface.
The option parsing uses Getopt::Long, so you can abbreviate option names.
Generates a top-level Makefile which will build all the pieces. Include all the other options you want so they'll be propagated to the Makefile.
Implies --client, --server, --data, and --constants. This is usually what you want.
Generates Foo::Client module.
Generates Foo::Data module.
Generates Foo::Constants module.
Sets the basename of the modules. If not given, the name defaults to the basename of the interface file.
Uses the given typemap during stub generation. This option can be specified many times. perlrpcgen generates a typemap for the data structures in the interface, but you also need the main Perl typemap.
Munges the server shell code so that it forks for each request. You probably don't want to do this (it's better to prefork several processes when you start the server and let them fight over accept() calls).
Sets the Perl binary against which extensions should be built. Defaults to the Perl you used to install perlrpcgen.
Sets the C compiler to use. Defaults to the compiler used when building Perl.
Sets the RPC libraries to link against. Defaults to '-lnsl -lrpcsvc'.
RPC clients and the procedure calls they support are encapsulated in Foo::Client objects (which inherit from RPC::ONC::Client).
A new Foo::Client can be created like this:
$foo = Foo::Client->new($server, $prot, $prog, $vers);
$prot, $prog, and $vers are optional, and will default to 'netpath', the value of the first 'program' declaration in the interface, and the value of the first 'version' declaration in the interface, respectively.
If the client creation fails, the constructor will set $RPC::ONC::errno and $RPC::ONC::errstr to the error number and error string, respectively, and croak.
For each procedure there is a method with the same name (with an underscore and the version number appended as in C). Methods are called like this:
$val = $foo->someproc_1($arg);
$arg must be an object of the correct type as given in the interface definition (see Foo::Data for details), or nothing if the interface specifies a 'void' argument. If the remote procedure call fails, the method will set $RPC::ONC::errno and $RPC::ONC::errstr and croak.
You'll need to use RPC::ONC, Foo::Data, Foo::Constants, and Foo::Client in your client code.
For each structure and union definition 'bar' in the interface definition, perlrpcgen creates a package in the Foo::Data module called Foo::bar. (If your interface contains an anonymous structure or union you'll get a package with an arbitrary name--you'll have to check out the Foo::Data module to see what it is. A warning would be nice here.)
You can create a new Foo::bar object like this:
$bar = Foo::bar->new; $bar2 = Foo::bar->new($bar);
The first form creates an uninitialized object. The second form initializes an object by doing a shallow copy of another object. Be careful; you can cause coredumps and other weird behavior if you try to get an uninitialized field from a structure or return a structure with any uninitialized fields to a client (in that case the XDR routine for the structure will blow up). Finally, there's nothing stopping you from setting or retrieving the wrong type from a union (this may be fixed in a future version), and you can coredump that way too.
For each field in a structure or union (including the discriminant of a union) there is a getter (with the same name) that returns the value of the field, and a setter (with the same name prepended with 'set_') which takes an argument of the appropriate type and sets the field. For fields which are structures or unions themselves, the getter returns a reference to the field, so if you set the fields on this sub-structure you'll side-effect the super-structure.
In order to avoid having to doink around with various levels of indirection (as in C), all structures and unions are passed by reference, and multiple indirections are collapsed into one. So you can do $foo->set_bar($baz) whether foo is a structure, a pointer to a structure, a pointer to a pointer to a structure, etc.
As part of this magic, all the typedefs are collapsed as well. So if your interface has, say, 'typedef bar *quux' and a particular procedure calls for a 'quux', pass it a Foo::bar from Perl--there is no Perl type corresponding to 'quux'. (This is perhaps less of a good thing than the pointer collapsing but I couldn't see a simple way to do one without the other.)
Finally, functions which call for a pointer to a structure or union may be passed undef, which translates to a NULL pointer.
Types are converted from their XDR/RPC definitions as follows:
Become Perl numbers.
Become Perl strings (and are length-checked if a length is specified).
Become Perl objects as described above.
Become Perl arrays of Foo::bar objects (and are length-checked if a length is specified).
All the constants (including enums and identifiers for 'program' and 'version' definitions) defined in the interface are available via Foo::Constants (and are imported by default).
perlrpcgen creates a server shell which embeds Perl. To implement the procedure calls, you must define a function in the main package for each procedure defined in the interface (as in C, they should have the same names with an underscore and the version number appended).
These functions are called as follows:
$val = someproc_1($arg, $svc_req, $transp); $val = someproc_1($svc_req, $transp);
$arg is the procedure argument (of the appropriate type) or nothing if the procedure is declared to take 'void'. $svc_req is an RPC::ONC::svc_req object (see RPC::ONC) through which the client's credentials can be accessed. $transp is an RPC::ONC::Svcxprt object (see RPC::ONC) through which the client's IP address can be accessed.
You'll need to use RPC::ONC, Foo::Data, and Foo::Constants, but don't try to use Foo::Client in a server, because you'll get symbol conflicts.
The command line arguments are passed unchanged to Perl. Usually you start a server with something like:
If you're planning to write a lot of servers you might want to build Perl with a shared libperl.
Jake Donham <email@example.com>
Thanks to Organic Online <http://www.organic.com/> for letting me hack at work.
If your interface has comments or other preprocessor statements in it you need to run it through cpp before giving it to perlrpcgen.
perlrpcgen should use MakeMaker for the top-level Makefile.