1xsbuilder.osc2002(3) User Contributed Perl Documentation xsbuilder.osc2002(3)
2
3
4
6 O'Reilly OpenSource Convention 2002
7
8 Gerald Richter
9
10 ecos gmbh
11
12 http://www.ecos.de
13
15 It's purpose is to automaticly generate a Perl interface to C Code
16
17 Solves the problem, that the Perl interface is not always uptodate with
18 the C interface
19
20 Saves a lot of Copy&Paste work
21
22 Systematical changes have to be done only once
23
24 For example changes in the memory management of strings.
25
26 Is part of mod_perl 2.0 build system
27
28 Most code is developed by Doug MacEachern. Additionaly I have
29
30 abstracted the code from mod_perl so it's useable for any C code
31 added new features like callbacks and the ability to parse comments
32 Replaced C::Scan with a Parse::RecDescent to be platform and compiler
33 independend
34
35 Goal is to replace the current mod_perl XS generation code with
36 XSBuilder
37
38 Inline versus XSBuilder
39
40 Inline: embed C-Code into Perl
41 XSBuilder: Create interface for existing C-libraries/applicationen
42
44 Create Perl functions/methods for every C function
45
46 The function can be assigned to different packages, also automaticly by
47 inspecting the first parameter
48
49 Create a Perl class for every C structure
50
51 Every element of structure becomes a Perl method to get/set it's value.
52 The object can be either a scalar reference (used by mod_perl) or a
53 reference to a hash (use by Embperl), which allows to store extra data
54 by the Perl code into this hash.
55
56 Create glue code to handle callbacks
57
58 There several sorts of callback, not all are implemented right now
59
60 Create Perl constant subs
61
62 Coming soon...
63
65 Parse the C header files
66
67 Extract
68
69 Functions, their arguments and return types
70 Structures and it's members
71 Constants
72 Callbacks
73
74 and create four tables which contains the results
75
76 Create the XS code
77
78 Input is
79
80 The source tables
81 Mapfiles which contains the mapping from C to Perl
82 Addtional C and Perl code that can be used to customize the interface
83
84 Output is
85
86 The XS files (one form every generated class)
87 Makefile.PL for every class
88 pm files
89
91 Create your own ParseSource class and override methods...
92
93 package Apache::DAV::ParseSource;
94
95 use strict;
96 use vars qw{@ISA $VERSION} ;
97 use ExtUtils::XSBuilder::ParseSource ;
98
99 @ISA = ('ExtUtils::XSBuilder::ParseSource') ;
100 $VERSION = '0.01';
101
102 my $dav_dir = 'C:\perl\msrc\cvs\mod_dav' ;
103 my $ap_dir = 'c:\programme\apache group\apache' ;
104
105 # ============================================================================
106 sub find_includes {
107 my $self = shift;
108 return $self->{includes} if $self->{includes};
109 my @includes = ("$ap_dir/include/ap_alloc.h", "$dav_dir/mod_dav.h") ;
110 return $self->{includes} = $self -> sort_includes (\@includes) ;
111 }
112
113 # ============================================================================
114 sub package { 'Apache::DAV' }
115
116 # ============================================================================
117 sub preprocess {
118 my $self = shift ;
119 $_[0] =~ s/(?:API_EXPORT)(?:_NONSTD)?\s*\(\s*(.*?)\s*\)/$1/g ;
120 }
121
122 1;
123
124 ...run it
125
126 use FindBin ;
127 use lib ($FindBin::Bin) ;
128
129 require ParseSource ;
130
131 Apache::DAV::ParseSource -> run ;
132
133 ...and you get
134
135 C:\perl\msrc\davint>perl xsbuilder\source_scan.pl
136 Will use mod_dav in C:\perl\msrc\cvs\mod_dav
137 Will use Apache in c:\programme\apache group\apache
138 Initialize parser
139 scan c:\programme\apache group\apache/include/ap_alloc.h ...
140 constant: APACHE_ALLOC_H
141 func: ap_init_alloc
142 func: ap_cleanup_alloc
143 func: ap_make_sub_pool
144 func: ap_destroy_pool
145 constant: ap_pool_join
146 func: ap_pool_join
147 func: ap_find_pool
148 func: ap_pool_is_ancestor
149 func: ap_clear_pool
150 func: ap_cleanup_for_exec
151 func: ap_palloc
152 func: ap_pcalloc
153 func: ap_pstrdup
154 func: ap_pstrndup
155 func: ap_pstrcat
156 func: ap_pvsprintf
157 valuefield: ap_pool * : pool
158 valuefield: int : elt_size
159 valuefield: int : nelts
160 valuefield: int : nalloc
161 valuefield: char * : elts
162 struct: (type=array_header)
163 ...
164
165 The result is stored in four tables
166
167 xsbuilder/tables/Apache/DAV/FuntionTable.pm
168 Contains all function, it arguments and comments
169
170 xsbuilder/tables/Apache/DAV/ConstantTable.pm
171 Contains all constants
172
173 xsbuilder/tables/Apache/DAV/StructureTable.pm
174 Contains all structures, it's members and their comments
175
176 xsbuilder/tables/Apache/DAV/CallbackTable.pm
177 Contains all callback function definitions
178
180 Mapfiles are used to tell XSBuilder how C datatypes, structures and
181 function aruments should be mapped into Perl ones.
182
183 Create your own WrapXS class and override methods
184
185 package Apache::DAV::WrapXS ;
186 use strict;
187 use vars qw{@ISA $VERSION} ;
188
189 use ExtUtils::XSBuilder::WrapXS ;
190
191 @ISA = ('ExtUtils::XSBuilder::WrapXS') ;
192 $VERSION = '0.01';
193
194 # ============================================================================
195 sub new_parsesource { [ Apache::DAV::ParseSource->new ] }
196
197 # ============================================================================
198 sub my_xs_prefix { 'davxs_' }
199
200 # ============================================================================
201 sub h_filename_prefix { 'moddav_xs_' }
202
203 # ============================================================================
204 sub xs_includes {
205 my $self = shift ;
206 my $i = $self -> SUPER::xs_includes ;
207 my @i = grep (!/ap_alloc/, @$i) ;
208 return \@i ;
209 }
210
211 XSBuilder can create/update initial maps for you
212
213 use FindBin ;
214 use lib ($FindBin::Bin) ;
215
216 require ParseSource ;
217 require WrapXS ;
218
219 Apache::DAV::WrapXS->checkmaps (' ');
220
221 run it
222
223 C:\perl\msrc\davint>perl xsbuilder\xs_check.pl
224 Will use mod_dav in C:\perl\msrc\cvs\mod_dav
225 Will use Apache in c:\programme\apache group\apache
226 Parse xsbuilder\maps/_types.map...
227 WARNING: No *_function.map file found in xsbuilder\maps
228 WARNING: No *_callback.map file found in xsbuilder\maps
229 WARNING: No *_structure.map file found in xsbuilder\maps
230 Write xsbuilder\maps/new_function.map...
231 Write xsbuilder\maps/new_callback.map...
232 Write xsbuilder\maps/new_structure.map...
233 Write xsbuilder\maps/new_type.map...
234
235 Now we have four map files
236
237 new_types.map
238 Contains the mapping from C type to Perl classes
239
240 new_functions.map
241 Contains the mapping form C functions to Perl functions. Can be
242 used to reorder arguments, tell XSBuilder which arguments are actu‐
243 aly return values and in which Perl package the function will be
244 created.
245
246 new_structures.map
247 Contains the mapping from C structures to Perl classes and defines
248 for which members a access methods should be created. You can also
249 specify if you want a "new" method for the class.
250
251 new_callbacks.map
252 Contains the mapping form C callback functions to Perl callback
253 functions. Can be used to reorder arguments, tell XSBuilder which
254 arguments are actualy return values and in which Perl package the
255 function will be created.
256
257 It's a good idea to rename the prefix from "new_" to something unique,
258 here we use "dav"
259
260 Everytime you rerun checkmaps, XSBuilder will create new_* files with
261 the items that are not already part of the other maps.
262
263 Next step is to customize the maps...
264
266 autogenerated dav_type.map
267
268 DIR ⎪
269 FILE ⎪
270 HANDLE ⎪
271 array_header ⎪
272 dav_buffer ⎪
273 dav_dyn_context ⎪
274 dav_dyn_hooks ⎪
275 dav_dyn_module ⎪
276 dav_dyn_provider ⎪
277 dav_error ⎪
278 dav_get_props_result ⎪
279 dav_hooks_liveprop ⎪
280 dav_hooks_locks ⎪
281 dav_hooks_repository ⎪
282 dav_if_header ⎪
283 dav_if_state_type ⎪
284 ...
285
286 Add Perl classes
287
288 struct array_header ⎪ Apache::Array
289 struct dav_buffer ⎪
290 struct dav_datum ⎪ Apache::DAV::Datum
291 struct dav_dyn_context ⎪ Apache::DAV::DynContext
292 struct dav_dyn_hooks ⎪ Apache::DAV::DynHooks
293 struct dav_dyn_module ⎪ Apache::DAV::DynModule
294 struct dav_dyn_provider ⎪ Apache::DAV::DynProvider
295 struct dav_error ⎪ Apache::DAV::Error
296 struct dav_get_props_result ⎪ Apache::DAV::PropsResult
297 struct dav_hooks_db ⎪ Apache::DAV::HooksDb
298 struct dav_hooks_liveprop ⎪ Apache::DAV::HooksLiveprop
299 struct dav_hooks_locks ⎪ Apache::DAV::HooksLocks
300 struct dav_hooks_repository ⎪ Apache::DAV::HooksRepository
301 struct dav_hooks_vsn ⎪
302 struct dav_if_header ⎪ Apache::DAV::IfHeader
303 struct dav_if_state_list ⎪ Apache::DAV::StateList
304 ...
305 struct pool ⎪ Apache::Pool
306 struct request_rec ⎪ Apache::
307 struct server_rec ⎪ Apache::Server
308 ...
309
310 Defines the mapping from C datatypes to Perl datatypes and classes and
311 tells XSBuilder which datatype are (like) structures
312
314 Function map defines the mapping from C functions arguments to Perl
315 arguments
316
317 Tell XSBuilder where to place functions and which prefix to strip
318 MODULE=Apache::DAV PACKAGE=guess PREFIX=dav_
319
320 Simple entries in the function map will be mapped 1:1 from C to Perl
321 dav_add_response
322 dav_buffer_append
323 dav_buffer_init
324 dav_buffer_place
325 dav_buffer_place_mem
326 dav_check_bufsize
327 dav_close_propdb
328 dav_collect_liveprop_uris
329 dav_dyn_module_add
330 dav_empty_elem
331 ...
332
333 The following map file entry tells XSBuilder that the value of "res_p"
334 should be returned
335 dav_get_resource ⎪ ⎪ r, <res_p
336
337 The C function
338
339 int dav_get_resource(request_rec *r, dav_resource **res_p) ;
340
341 How to call it from Perl
342
343 # get a sub request of the actual document
344 $subr = $r -> lookup_uri($uri);
345
346 # get a mod_dav resource object
347 my ($err, $resource) = $subr->get_resource;
348
349 You can let XSBuilder insert your custom code, for the interface
350 If you call "get_props" from Perl "glue_dav_get_props" will be
351 called, which can adjust the arguments and return types as neces‐
352 sary. The actual code for "glue_dav_get_props" will be taken from
353 separate include file.
354
355 dav_get_props ⎪ glue_
356 dav_get_allprops ⎪ glue_
357
358 xsinclude\Apache\DAV\PropResult\Apache__DAV__PropResults.h
359
360 dav_get_props_result * dav_glue_get_props(dav_propdb * db, dav_xml_doc *doc)
361 {
362 dav_get_props_result * result = (dav_get_props_result *)ap_palloc (db -> p, sizeof (dav_get_props_result)) ;
363 *result = dav_get_props(db, doc) ;
364 return result ;
365 }
366
367 Arguments can be replaced
368 MODULE=Apache::Array PACKAGE=Apache::Array PREFIX=ap_
369
370 ap_make_array ⎪ ap_make_array(r->pool, nelts, elt_size) ⎪ request_rec *:r, nelts, elt_size
371
372 ap_make_array requires a pool a it's first parameter, we pass the
373 request_rec from Perl and XSBuilder will take the pool from the
374 request_rec.
375
377 MALLOC=strdup:$dest = ($type)strdup($src)
378 FREE=strdup:free($src)
379
380 <dav_xml_elem>
381 name
382 ns
383 lang
384 first_cdata
385 following_cdata
386 parent
387 next
388 first_child
389 attr
390 last_child
391 ns_scope
392 propid
393 provider
394 ns_map
395 new
396 </dav_xml_elem>
397
398 MALLOC=strdup:$dest = ($type)ap_pstrdup(obj -> pool, $src)
399
400 <array_header>
401 pool
402 elt_size
403 nelts
404 nalloc
405 elts
406 private
407 </array_header>
408
409 Create a accessor functions for every element and, if requested, a new
410 method
411
412 $setprop = Apache::DAV::XMLElem -> new ({name => 'prop'}) ;
413 $elem = Apache::DAV::XMLElem -> new ({name => $name, ns => $namespaces}) ;
414 $setprop -> first_child($elem) ;
415 $first = $setprop -> first_child ;
416
417 some datatypes, like strings, requires dynamic allocated memory
418
419 From _types.map,which conatins a set of standard types
420
421 int ⎪ IV
422 int * ⎪ UNDEFINED
423 unsigned int ⎪ UV
424 signed int ⎪ IV
425 long ⎪ IV
426 long int ⎪ IV
427 unsigned long ⎪ UV
428 unsigned ⎪ UV
429
430 char * ⎪ PV ⎪ ⎪ ⎪ strdup
431 const char * ⎪ PV ⎪ ⎪ ⎪ strdup
432 const char ** ⎪ UNDEFINED
433 char const * ⎪ PV ⎪ ⎪ ⎪ strdup
434 unsigned char * ⎪ PV ⎪ ⎪ ⎪ strdup
435 const unsigned char * ⎪ PV ⎪ ⎪ ⎪ strdup
436 ...
437
439 Callback maps have the same options a function maps
440
441 # dav_hooks_db -> open
442
443 dav_error *(*)(pool * p,const dav_resource * resource,int ro,dav_db * * pdb) ⎪ p, resource, ro=0, <pdb
444
445 # dav_hooks_lock -> has_locks
446
447 dav_error *(*)(dav_lockdb * lockdb,const dav_resource * resource,int * locks_present)
448
450 use FindBin ;
451 use lib ($FindBin::Bin) ;
452
453 require ParseSource ;
454 require WrapXS ;
455
456 Apache::DAV::WrapXS->run;
457
458 ...and run...
459
460 C:\perl\msrc\davint>perl xsbuilder\xs_generate.pl
461 Will use mod_dav in C:\perl\msrc\cvs\mod_dav
462 Will use Apache in c:\programme\apache group\apache
463 Parse xsbuilder\maps/_types.map...
464 Parse xsbuilder\maps/dav_type.map...
465 mkdir xs
466 writing...xs//typemap
467 Parse xsbuilder\maps/dav_functions.map...
468 WARNING: Cannot map type int(*)(void * ,const char * ,const char * ) for function ap_table_do
469 WARNING: Cannot map type dav_buffer * for function dav_buffer_append
470 WARNING: Cannot map type dav_buffer * for function dav_buffer_init
471 WARNING: Cannot map type dav_buffer * for function dav_buffer_place
472 WARNING: Cannot map type dav_buffer * for function dav_buffer_place_mem
473 WARNING: Cannot map type dav_buffer * for function dav_check_bufsize
474 WARNING: Cannot map return type int * for function dav_collect_liveprop_uris
475 WARNING: Cannot map type dav_resource * * for function dav_ensure_resource_writable
476 WARNING: Cannot map type dav_buffer * for function dav_lock_get_activelock
477 WARNING: Cannot map type dav_buffer * for function dav_set_bufsize
478 WARNING: Cannot map type int * for function dav_xml2text
479 struct array_header...
480 Parse xsbuilder\maps/dav_structure.map...
481 elt_size...
482 nelts...
483 nalloc...
484 elts...
485 struct dav_buffer...
486 struct dav_datum...
487 dptr...
488 dsize...
489 struct dav_dyn_context...
490
492 We need create a top level Makefile.PL
493
494 use ExtUtils::MakeMaker ();
495
496 my $apdir = '/path/to/apache';
497 my $davdir = '/path/to/moddav';
498
499 %MMARGS = (
500 'INC' => "-I\"$davdir\" -I\"$apdir/include\" -I\"$apdir/os/unix\" -I\"$dir/xs\" -I\"$dir/xsinclude\"",
501 ) ;
502
503 open FH, ">xs/mmargs.pl" or die "Cannot open xs/mmargs.pl ($!)" ;
504 print FH Data::Dumper -> Dump ([\%MMARGS], ['MMARGS']) ;
505 close FH ;
506
507 ExtUtils::MakeMaker::WriteMakefile(
508 'NAME' => 'Apache::DAV',
509 'VERSION' => '0.13',
510 %MMARGS,
511 );
512
513 Makefile.PL's for all class are generated automaticly
514
515 C:\perl\msrc\davint>perl Makefile.PL
516 Will use Apache in c:\programme\apache group\apache
517 Will use mod_dav in C:\perl\msrc\cvs\mod_dav
518 Checking if your kit is complete...
519 Looks good
520 Writing Makefile for Apache::Array
521 Writing Makefile for Apache::DAV::Datum
522 Writing Makefile for Apache::DAV::DynContext
523 Writing Makefile for Apache::DAV::DynHooks
524 Writing Makefile for Apache::DAV::DynModule
525 Writing Makefile for Apache::DAV::DynProvider
526 Writing Makefile for Apache::DAV::Error
527 Writing Makefile for Apache::DAV::HooksDb
528 Writing Makefile for Apache::DAV::HooksLiveprop
529 Writing Makefile for Apache::DAV::HooksLocks
530 Writing Makefile for Apache::DAV::HooksRepository
531 Writing Makefile for Apache::DAV::IfHeader
532 Writing Makefile for Apache::DAV::Lock
533 Writing Makefile for Apache::DAV::LockDB
534 Writing Makefile for Apache::DAV::LockTokenList
535 Writing Makefile for Apache::DAV::LockupResult
536 Writing Makefile for Apache::DAV::PropCtx
537 Writing Makefile for Apache::DAV::PropsResult
538 Writing Makefile for Apache::DAV::Resource
539 Writing Makefile for Apache::DAV::Response
540 Writing Makefile for Apache::DAV::StateList
541 Writing Makefile for Apache::DAV::Text
542 Writing Makefile for Apache::DAV::TextHeader
543 Writing Makefile for Apache::DAV::WalkerCtx
544 Writing Makefile for Apache::DAV::XMLAttr
545 Writing Makefile for Apache::DAV::XMLDoc
546 Writing Makefile for Apache::DAV::XMLElem
547 Writing Makefile for Apache::DAV
548 Writing Makefile for Apache::TableEntry
549 Writing Makefile for Apache
550 Writing Makefile for WrapXS
551 Writing Makefile for Apache::DAV
552
553 and now compile...
554
556 Generating documentation
557
558 XSBuilder already extracts source comments for functions and struc‐
559 tures. It also parses doxygen comments, which are used in Apache 2.0.
560 Lyle Brooks has started on automaticly createing POD files from this
561 information.
562
563 Improving callbacks
564
565 Callbacks are the main area that needs improvement.
566
567 Bring it back to mod_perl 2.0
568
569 First version will be released just after the conference to CPAN
570
571 Any feedback and help appreciated
572
573 Questions?
574
575perl v5.8.8 2005-08-31 xsbuilder.osc2002(3)