Re: Autogenerating XS code and Docs (fwd)

[email protected] (Tony Payne)
Newsgroups perl.cvs.mod_parrot
Message-ID <[email protected]>
True.  That's especially a good idea since the parrot interfaces are
going to be moving targets for a while.  

It seems like there are some important enhancements to parrot coming in
the next few months, including extention support and sub-routines (July)
and method calls and PMC attributes (August).  Once those are in, I
think we'll be able to stress the new code fairly easily :-).

++t

On Wed, 2002-06-12 at 01:27, Ask Bjoern Hansen wrote:
> 
> maybe we should look at hacking this for generating the pmc too.
> :-/
> 
> -- 
> ask bjoern hansen, http://ask.netcetera.dk/   !try; do();
>                    http://www.askbjoernhansen.com/
> 
> ---------- Forwarded message ----------
> Date: Wed, 12 Jun 2002 09:35:21 +0200
> From: Gerald Richter <[email protected]>
> To: [email protected], [email protected]
> Subject: Autogenerating XS code and Docs
> 
> Hi,
> 
> as some of you may know, last fall I have started a project that splits out
> the XS autogenerating stuff from mod_perl 2.0 and generalize it to make it
> useable also outside of mod_perl. I have converted the C parser from C::Scan
> to a more flexible approach with Parse::RecDescent (which needs no C
> Compiler anymore), abtracted the Apache/mod_perl specific stuff into it's
> own subclass and added some other features. The result runs as
> ExtUtils::XSBuilder. I use this currently to build the Perl <-> C interface
> of Embperl 2.0 and for generating a mod_dav 1.0 interfaces (which I hope to
> release soon). Then, of course, I have tried to use it for mod_perl itself,
> but due to my limited time the process of makeing it run with mod_perl has
> been stalled since some time. I had a mail exchange with Stas some time ago
> and we though it will be the best to make the effort public, so maybe
> somebody can join in. Also I have some time now available, so I want to
> continue to work on it. There are two parts:
> 
> 1.) generating code
> 2.) generating docs
> 
> While the first requires some knowledge of XS and mod_perl / Apache
> internals, the second could be done without such a need. My current version
> already splits out the comments that included in the Apache header files, so
> we end up with something like:
> 
> 'perl_name' => 'apr_table_add',
> 'comment_parsed' => {
>     'doxygen_param' => [
>                          't',
>                          'key',
>                          'val'
>                        ],
>     'doxygen_param_desc' => {
>                               'val' => 'The value to add.',
>                               'key' => 'The key to use',
>                               't' => 'The table to add to'
>                             },
>     'func_desc' => 'Add data to a table, regardless of whether there is
> another element with the same key.',
>     'doxygen_remark' => 'When adding data, this function makes a copy of
> both the key and the value.'
>   },
> more stuff, like mapping form C to Perl arguments etc. follows here....
> 
> Since the whole Apache API is well documented in this way, it should be
> possible to autogenerate most of the mod_perl API documentation from this
> informations. It would be necessary that somebody writes a tool that takes
> this informations, brings it together with some manualy maintained pod and
> generates the pods out of it. This shouldn't be to hard to do.
> 
> For the XS genaration stuff there some issue with pTHX_ parameters left,
> which I hope to resolve soon. Also the whole stuff for generating constants
> is missing yet.
> 
> I would be very happy if anybody likes to join this project, either the docs
> part or help me with the XS part!
> 
> I have put the current version on my ftp server
> (ftp://ftp.dev.ecos.de/pub/perl/xsbuilder/), ExtUtils-XSBuilder is the
> general module, mpbuilder contains the mod_perl specify classes and wrapxs
> is what is generated for mod_perl right now. The pdd files inside of wrapxs
> contains the parsed comments. The ExtUtils-XSBuilder also contains a
> XSBuilder.pod, which describes how the current stuff works, I append it for
> convenience below. Also I append a list of changes that I have made, since I
> have forked off from mod_perl.
> 
> Gerald
> 
> CHANGES:
> 
> 
> - structs that are contained in another struct are now handled correctly.
>   When reading the struct memeber a new object is returned, which can be
> used
>   to access the members of the contained struct. The contained struct cannot
>   be set directly.
> 
> - In class name in xxx_types.map can end with :: to use single level
> classnames
>   (e.g. request_rec * | Apache::  for mod_perl 1.x)
> 
> - Argspec of xxx_functions.map can specify argument as return only by
> prefixing
>   it with < e.g.
>     dav_open_lockdb | | r, ro, <lockdb
>   will be called as ($error get the return value of the C function)
>     ($error, $lockdb) = $r -> open_lockdb (0) ;
>   The return argument (e.g. lockdb) will always be passed by address
>   to the function.
> 
> - xs/xxxx_sv_convert.h now also contains macros to convert C data types to
> Perl
>   for non object types e.g. IV
> 
> - better handling for structs that for which a typedef doesn't exist.
> 
> - method checkmaps & writemaps creates new_*.map with all
>   functions/structures/types/callbacks that are not already in a map file.
> 
> - ParseSource now scans for callbacks and generates a CallbackTable.pm
>   with similar format as FunctionTable.pm
> 
> - WrapXS generates callbacks for struct members as method calls when the
>   struct doesn't contains any field where to store some userdata. An
> optimized
>   version which passes the perl object in some user data field need still to
> be done.
> 
> - Extra include files now given in xs/maps/foo_types instead of hardcoded
>   in TypeMap.pm
> 
> - prefixes for conversion macros and other generated functions are now
>   set via an overrideable method
> 
> - support for passing structure by value as function argument / return type
> 
> - macros in xxx_sv_convert.h now correctly convert NULL to undef and
> viceversa
> 
> - Structure members can have a different name in Perl and C. Controlled via
>   the map file.
> 
> - %convert_alias  has been moved into types.map
> 
> - typemap ids (e.g. T_APACHEOBJ) has been moved into types.map
> 
> - it possible to configure the way how memory for strings is allocated
>   via map files, by giveing a malloctype in type map file and allocation
>   code in structure map file.
> 
> - a dispatch argspec can now given in the map file, this allows to pass
>   $r to the xs function and r -> pool to the C function by writing:
> 
>   ap_make_array | ap_make_array(r->pool, nelts, elt_size) | request_rec *:r,
> nelts, elt_size
> 
> - handle conversion from package name to directory correctly when more then
> two
>   levels of namespaces e.g. Apache::DAV::Resource ->
> Apache/DAV/Resource/Resource_pm
> 
> 
> DOCS
> 
> 
> 
> =head1 Basics
> 
> ExtUtils::XSBuilder is a set modules to parse C header files and create XS
> glue code and documentation out of it. Idealy this allows to "write" an
> interface to a C library without coding a line. Since no C-API is ideal,
> some adjuments are necessary most of the time. So to use this module you
> must still be familar with C and XS programming, but it removes a lot of
> stupid work and copy&paste from you. Also when the C API changes, most
> of the time you only have to rerun XSBuilder to get your new Perl API.
> 
> The creation process takes place in the following steps:
> 
> =over 4
> 
> =item Derive a class from ExtUtils::XSBuilder::ParseSource
> 
> This class must override some methods to tell XSBuilder which C header files
> to parse and some other necessary parameters. You need at least to override
> the
> methods C<package> to give the name of the package you want to create and
> either the method C<find_includes> and return all C header files to parse or
> the method C<include_dirs> to return a list of all directories which should
> be scanned for C header files.
> 
> Of course there are more methods you can overide. See
> L<ExtUtils::XSBuilder::ParseSource> for a list of overrideable methods.
> 
> =item Scan the source files
> 
> If your derived class is called MyClass::ParseSource you simply start the
> source scan with
> 
>     perl -MMyClass::ParseSource -e 'MyClass::ParseSource->run'
> 
> You may also put this into a small script to ease usage and maybe set the
> Perl libpath etc.
> 
> After you run the source scan XSBuilder has created a set of tables, which
> contains the result of the parseing. If you don't have changed the defaults
> in your class, the tables are created under C<xs/tables/current> and then
> appended
> the name of the module you want to create as given with the method
> C<package>.
> There will be a C<FunctionTable.pm> which holds all the function
> declarations,
> a C<StructureTable.pm> which holds the structures, a C<ConstantTable.pm>,
> which
> contains alls constants found in the header files and a C<CallbackTable.pm>
> which contains definitions for callback types.
> 
> The main reason why we not directly create XS code, but first these
> intermediate
> tables is, that source scanning may take some time. As we save the result,
> we can
> avoid rescanning the sources as long as they don't change.
> 
> =item Derive a class from ExtUtils::XSBuilder::WrapXS
> 
> The WarpXS class is resonsible for takeing the tables which contains the
> information
> about the scanned sources and from the map files (see below) and create the
> XS code.
> As with the ParseSource class, you have to override this call with your own
> implementaion,
> to tell WrapXS what to do.
> 
> See L<ExtUtils::XSBuilder::WarpXS> for a list of overrideable methods.
> 
> =item Create map files
> 
> XSBuilder will not automaticly create XS functions for all C function and
> structure. You
> have to give some hints. This is basicly done via the map files. If you
> don't change the
> default they live under C<xs/maps>. There four map types. For each type
> there could
> multiple files prefixed with C<foo_>:
> 
> =over 4
> 
> =item foo_types.map
> 
> Contains the mapping from C type to Perl classes
> 
> =item foo_functions.map
> 
> Contains the mapping form C functions to Perl functions. Can be used to
> reorder arguments, tell XSBuilder which arguments are actualy return values
> and in which Perl package the function will be created.
> 
> =item foo_structures.map
> 
> Contains the mapping from C structures to Perl classes and defines for which
> members a access methods should be created. You can also specify if you want
> a
> C<new> method for the class.
> 
> =item foo_callbacks.map
> 
> Contains the mapping form C callback functions to Perl callback functions.
> Can be used to
> reorder arguments, tell XSBuilder which arguments are actualy return values
> and in which Perl package the function will be created.
> 
> =back
> 
> For a detailed description of the format of the map files see below.
> 
> To have a starting point XSBuilder is able to create default map files,
> which simply
> include all types, functions and structures. You can rerun this map file
> creation
> everytime and XSBuilder will append all items, that are not already in the
> maps files.
> 
> If your derived class is called MyClass::WarpXS you simply start the
> createing/update
> of the maps files with
> 
>     perl -MMyClass::WarpXS -e 'MyClass::WarpXS->checkmaps(" ")'
> 
> The the argument to checkmaps give the character that should be at the first
> column
> of the new map entries. If you give no argument at all, no map files are
> written,
> but checkmaps will only compare what is missing. (You need to print the
> result somehow
> e.g. by using Data::Dumper).
> You may also put this into a small script to ease usage and maybe set the
> Perl libpath etc.
> 
> After you have created your default maps, you have at least to edit the
> C<xs/maps/new_type.map>
> file, which contains all types that found in the sources. Simply append the
> class or the typename
> to the line spearated by a C<|> e.g.
> 
>     int                 | IV
>     struct request_rec  | Apache::RequestRec
> 
> =item Create the XS files
> 
> Now we can create the code. By starting
> 
>     perl -MMyClass::WarpXS -e 'MyClass::WarpXS->run'
> 
> XSBuilder will create the XS, pm and Makefile.PL files for every module that
> is mentioned in the maps. The result is placed as a directory hierarchy
> under
> WrapXS. To control the content of the C<Makefile.PL> and the C<pm> file, you
> can override the methods C<makefilepl_text> and C<pm_text>. You can include
> addtional code in the XS files, by writing an include file which is included
> at the top of the XS file. This file can contain helper functions that can't
> automaticly generated. The files must be placed under the C<xs> directory,
> with the correct path and name. E.g. to have a header file included for the
> module Apache::DAV, create a file C<xs/Apache/DAV/Apache__DAV.h>. The same
> can be done for inclusion in the pm file. The name for the above example
> would be C<xs/Apache/DAV/DAV_pm>.
> 
> =head1 Format of the maps files
> 
> For all map files blank lines are ignored and lines starting with a C<#> are
> treaded as comments and also ignored.
> 
> =head2 foo_types.map
> 
> Contains the mapping from C type to Perl classes.
> 
> Format is the name of the C type followed by the name of the Perl class
> or the XS type specifier, separated by a |. Example:
> 
>     int                 | IV
>     struct request_rec  | Apache::RequestRec
> 
> If you have a Perl class with a single name namespace (e.g. Apache) you
> need to postfix it with two colons (e.g. Apache::). Structures always
> needs to be written as "struct foo", also when a typedef for "foo"
> exists.
> Addionaly you can give the id for the typemap if you need a special
> conversion and one or more other names for the struct:
> 
>     struct request_rec  | Apache::RequestRec | T_APACHEOBJ | r
> 
> an optional fivth parameter specifies that the data needs to be copied
> when assigned to a struct member and selects the way how memory is
> allocated:
> 
>     char *   | PV | | | strdup
> 
> The actual code for memory allocation is provided inside the structure map
> e.g.
> 
>     MALLOC=strdup:$dest = ($type)ap_pstrdup(obj -> pool, $src)
>     MALLOC=malloc:ap_palloc(obj -> pool, $src, sizeof($type)) ;
> memcpy($dest,$src,sizeof($type))
> 
> This gives two ways to allocate memory and copy the data into it. The fives
> parameter in the type map selects which of these two should be used.
> $src, $dest and $type are replaced by the source, the destionation and the
> type.
> C<obj> is a pointer to the C-structure.
> 
> 
> =head2 foo_functions.map
> 
> Contains the mapping form C functions to Perl functions. Can be used to
> reorder arguments, tell XSBuilder which arguments are actualy return values
> and in which Perl package the function will be created.
> 
> There are some keywords which affects all functions follwing that keyword
> until a new values for that keyword is given:
> 
> =over 4
> 
> =item MODULE
> 
> the module name (file name) where the function should be placed in
> e.g. Apache::Connection -> Apache/Connection.{pm,xs}
> 
> =item PACKAGE
> 
> the package name functions belong to, defaults to MODULE
> value of 'guess' indicates that package name should be
> guessed based on first argument found that maps to a Perl class
> fallsback on the prefix (ap_ -> Apache, apr_ -> APR)
> 
> =item PREFIX
> 
> prefix to be stripped
> defaults to PACKAGE, converted to C name convention, e.g.
> APR::Base64 -> apr_base64_
> if the converted prefix does not match, defaults to ap_ or apr_
> 
> =back
> 
> The format of entries is:
> 
>     C function name | dispatch function name (dispatch argspec) | argspec |
> Perl alias
> 
> Dispatch function name (the C function that is actually called) defaults
> to C function name
> if the dispatch name is just a prefix (mpxs_, MPXS_)
> the C function name is appended to it
> the return type can be specified before the C function name,
> defaults to return_type in {foo}::FunctionTable as generated by
> the ParseSource module.
> The dispatch argspec is optional, if given you can use it to pass differnt
> parameters to the dispatch function then to the xs function.
> If the function name beginns with DEFINE_ a new function is defined,
> (for defining function that are not parsed from the source). argsec
> must be given also. For the real function name the DEFINE_ is removed.
> 
> The argspec defaults to arguments in {foo}::FunctionTable as generated by
> the ParseSource module
> argument types can be specified to override those in the FunctionTable
> default values can be specified, e.g. arg=default_value
> 
> Example:
>   ap_get_client_block   | mpxs_ | r, SV *:buffer, bufsiz
>   ap_setup_client_block |       | r, read_policy=REQUEST_CHUNKED_ERROR
>   ap_make_array      | ap_make_array(r->pool, nelts, elt_size) | request_rec
> *:r, nelts, elt_size
> 
> 
> argspec of '...' indicates passthru, calling the function with
> 
>     (aTHX_ I32 items, SP **sp, SV **MARK)
> 
> To mark an argument as return only you can prefix it with < e.g.
> 
>     dav_open_lockdb | | r, ro, <lockdb
> 
> will be called as ($error get the return value of the C function)
> 
>     ($error, $lockdb) = $r -> open_lockdb (0) ;
> 
> The return argument (e.g. lockdb) will always be passed by address
> to the function.
> 
> the alias will be created in the current PACKAGE
> 
> function names that do not begin with /^\w/ or space are skipped.
> You can prefix each function name with the following symbols:
> 
>     '!' => 'disabled or not yet implemented',
>     '~' => 'implemented but not auto-generated',
>     '-' => 'likely never be available to Perl',
>     '>' => '"private" to apache',
>     '?' => 'unclassified',
> 
> =head2 foo_structures.map
> 
> Contains the mapping from C structures to Perl classes and defines for which
> members a access methods should be created. You can also specify if you want
> a
> C<new> method for the class.
> 
> The format looks like the following:
> 
>  <struct_name>
>    member1
>    member2
>    new
>  </struct_name>
> 
> An optional module name can be given, so the module name specifies in which
> file the code should be placed, which the package name is determinated from
> the type map file. Example:
> 
>  <struct_name MODULE=My::Module>
> 
> For all members that are listed here, XSBuilder will generate an access
> method
> to read and write it's content. If you want to name the perl access method
> different than the C member, you can write
> 
>    cMemberValue | member_value
> 
> this will map the C<cMemberValue> structure member to the access function
> C<member_value>. Default is to use the same name in Perl as in C.
> If you give the C<new> member XSBuilder will
> create a new method for that class, which can be used to create a new
> instance
> of that class and initialize it with initial data.
> 
> =head2 foo_callbacks.map
> 
> same format as function map, but contains the callbacks
> 
> =back
> 
> 
> 
> 
> -------------------------------------------------------------
> Gerald Richter    ecos electronic communication services gmbh
> Internetconnect * Webserver/-design/-datenbanken * Consulting
> 
> Post:       Tulpenstrasse 5         D-55276 Dienheim b. Mainz
> E-Mail:     [email protected]         Voice:    +49 6133 925131
> WWW:        http://www.ecos.de      Fax:      +49 6133 925152
> -------------------------------------------------------------
> 
> 
> 
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: [email protected]
> For additional commands, e-mail: [email protected]
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.