root/mpich2/branches/dev/kumudb/src/binding/cxx/buildiface @ 4870

Revision 4870, 148.6 KB (checked in by kumudb, 5 months ago)

Merge from trunk to kumudb r4748:r4869

  • Property svn:executable set to *
Line 
1#! /usr/bin/env perl
2#
3# This file builds candidate interface files from the descriptions in
4# mpi.h
5#
6# Here are the steps:
7# 1) Find the prototypes in mpi.h.in (Look for *Begin Prototypes*)
8# 2) For each function, match the name and args:
9#    int MPI_xxxx( ... )
10# 3) By groups, create a new file with the name {catname}.h containing
11#    Copyright
12#    For each function in the group, the expansion of the method
13#
14# Each MPI routine is assigned to a group.  Within each group,
15# a particular argument is (usually) eliminated from the C++ call.
16# E.g., in MPI::Send, the communicator argument is removed from the
17# call sequence.
18# Routines that have out parameters (e.g., the request in MPI_Isend)
19# remove them as well.  Other routines return void.
20#
21# The replacement text will look something like
22#    void Name( args ) const {
23#      MPIX_CALL( MPI_Name( args, with (cast)((class).the_real_(class)) ); }
24#
25# If coverage analysis is desired, consider using the -coverage
26# switch.  This (will, once done) allow generating crude coverage data.
27# We'd prefer to use gcov, but gcov aborts (!) when used on the data
28# generated by the g++.  The coverage switch changes the replacement text
29# to something like
30#    void Name( args ) const {
31#       COVERAGE_ENTER(Name,argcount);
32#       MPIX_Call ....
33#       COVERAGE_EXIT(Name,argcount); }
34# The COVERAGE_ENTER and EXIT can be used as macros to invoke code to keep
35# track of each entry and exit.  The argcount is the number of parameters,
36# and can be used to distinquish between routines with the same name but
37# different number of arguments.
38#
39# (const applies only if the function does not modify its object (e.g.,
40# get_name may be const but set_name must not be.)
41#
42# A capability of this approach is that a stripped-down interface that
43# implements only the required routines can be created.
44#
45# Data structures
46#   %<class>_members (e.g., mpi1comm): keys are names of routines.
47#            Values are string indicating processing:
48#            returnvalue-arg (0 if void, type if unique, position if not)
49#   Pass by reference to process routine
50#   
51# TODO:
52#    The derived classes (such as Intracomm) must *not* have their own
53#    protected the_real_intracomm; instead, the must refer to the
54#    parent class's private storage. - DONE
55#
56#    The pack, unpack, packsize, init, and finalize routines must be
57#    placed in initcpp.cpp. - DONE
58#
59#    externs for the predefined objects need to be added to the
60#    end of mpicxx.h - DONE
61#
62#    The optional no-status versions need to be created for
63#    methods such as Recv, Test, and Sendrecv . - DONE
64#
65# Setup global variables
66$build_io = 1;        # If false, exclude the MPI-IO routines
67$oldSeek = 0;         # Use old code for seek_set etc.
68$indent = "    ";
69$print_line_len = 0;
70$gDebug = 0;
71$gDebugRoutine = "NONE";
72@mpilevels = ( 'mpi1' , 'mpi2' );
73#feature variables
74$do_subdecls = 1;
75$doCoverage = 0;
76$doFuncspec = 1;
77# Process environment variables
78#   CXX_COVERAGE - yes    : turn on coverage code
79if (defined($ENV{"CXX_COVERAGE"}) && $ENV{"CXX_COVERAGE"} eq "yes") {
80    setCoverage(1);
81}
82
83# Process arguments
84#
85# Args
86# -feature={logical,fint,subdecls,weak,bufptr}, separated by :, value given
87# by =on or =off, eg
88# -feature=logical=on:fint=off
89# The feature names mean:
90#    subdecls - Declarations for PC-C++ compilers added
91# -routines=name  - provide a list of routines or a file that
92# lists the routines to use.  The names must be in the same form as the
93# the class_xxx variables.  E.g., comm-Send, dtype-Commit.
94$routine_list = "";
95foreach $_ (@ARGV) {
96    if (/--?feature=(.*)/) {
97        foreach $feature (split(/:/,$1)) {
98            print STDERR "Processing feature $feature\n" if $gDebug;
99            # Feature values are foo=on,off
100            ($name,$value) = split(/=/,$feature);
101            if ($value eq "on") { $value = 1; } 
102            elsif ($value eq "off") { $value = 0; }
103            # Set the variable based on the string
104            $varname = "do_$name";
105            $$varname = $value;
106        }
107    }
108    elsif (/--?nosep/ || /--?sep/) { ; }   # Old argument; ignore
109    elsif (/--?noromio/) { $build_io = 0; }
110    elsif (/--?oldseek/) { $oldSeek = 1; }
111    elsif (/--?newseek/) { $oldSeek = 0; }
112    elsif (/--?debug=(.*)/) {
113        $gDebug = 0;
114        $gDebugRoutine = $1;
115    }
116    elsif (/--?debug/) { $gDebug = 1; }
117    elsif (/--?routines=(.*)/) {
118        $routine_list = $1;
119    }
120    elsif (/--?coverage/) { &setCoverage( 1 ); }
121    elsif (/--?nocoverage/) { &setCoverage( 0 ); }
122    else {
123        print STDERR "Unrecognized argument $_\n";
124    }
125}
126
127if (! -d "../../mpi/romio") { $build_io = 0; }
128# ----------------------------------------------------------------------------
129#
130# The following hashes define each of the methods that belongs to each class.
131# To allow us to differentiate between MPI-1 and MPI-2, the methods for
132# are separated.  The hash names have the form
133# class_mpi<1 or 2><short classname>
134# The value of each key is the POSITION (from 1) of the return argument
135# if an integer is used or the MPI-1 type (e.g., MPI_Request) if a string is
136# used.  The position form is normally used to return an int or other value
137# whose type does not give an unambiguous argument.  A value of 0 indicates
138# that the routine does not return a value.
139# Value of the hash is the argument of the routine that returns a value
140# ToDo:
141# Add to the value of each routine any special instructions on
142# processing the arguments.  See the Fortran version of buildiface.
143# Needed are:
144#   in:array, out:array    - Convert array of class members to/from
145#                            arrays of the_real_xxx.  Question: for
146#                            simplicity, should we have just in:reqarray,
147#                            inout:reqarray, out:reqarray?  Answer: the
148#                            current approach uses separate routines for
149#                            each array type.
150#   in:const               - Add const in the C++ declaration (e.g.,
151#                            in send, make the buf const void * instead
152#                            of just void *)
153#   in:bool,out:bool       - Convert value from bool to/from int
154#   
155# We'll indicate these with to fields returnvalue:argnum:...
156# For each method with special processing for an arg, there is
157# methodname-argnum.
158# Eg, Isend is
159#  Isend => 'MPI_Request:1', Isend-1 => 'in:const'
160# and Send is
161#  Send => '0:1', Send-1 => 'in:const'
162# The mappings for the arguments are kept in a
163# separate hash, %funcArgMap.
164#
165%class_mpi1comm = ( Send => '0:1', Recv => 0, 
166                    Bsend => '0:1', Ssend => '0:1', 
167                    Rsend => '0:1', Isend => 'MPI_Request:1', 
168                    Irsend => 'MPI_Request:1', Issend => 'MPI_Request:1', 
169                    Ibsend => 'MPI_Request:1', Irecv => MPI_Request, 
170                    Iprobe => 'int;bool', Probe => 0, 
171                    Send_init => 'MPI_Request:1', 
172                    Ssend_init => 'MPI_Request:1', 
173                    Bsend_init => 'MPI_Request:1', 
174                    Rsend_init => 'MPI_Request:1', Recv_init => MPI_Request, 
175                    Sendrecv => 0, Sendrecv_replace => 0, Get_size => 'int', 
176                    Get_rank => 'int', Free => 0, Get_topology => 2, 
177                    Get_group => MPI_Group,
178                    Compare => 'static:int', 
179                    Abort => 0,
180                    Set_errhandler => 0,
181                    Get_errhandler => MPI_Errhandler,
182                    Is_inter => '2;bool',
183                   );
184%funcArgMap = (
185                    'Send-1' => 'in:const',
186                    'Bsend-1' => 'in:const',
187                    'Rsend-1' => 'in:const',
188                    'Ssend-1' => 'in:const',
189                    'Irsend-1' => 'in:const',
190                    'Isend-1' => 'in:const',
191                    'Ibsend-1' => 'in:const',
192                    'Issend-1' => 'in:const',
193                    'Send_init-1' => 'in:const',
194                    'Ssend_init-1' => 'in:const',
195                    'Bsend_init-1' => 'in:const',
196                    'Rsend_init-1' => 'in:const',
197
198                    'Free_keyval-1' =>  'in:refint',
199                   
200                     'Waitany-2' => 'inout:reqarray:1',
201                     'Waitsome-2' => 'inout:reqarray:1',
202                     'Waitsome-5' => 'out:statusarray:1', # or 4?
203                     'Waitall-2' => 'inout:reqarray:1',
204                     'Waitall-3' => 'out:statusarray:1',
205                     'Testany-2' => 'inout:reqarray:1',
206                     'Testany-3' => 'in:refint',
207                     'Testsome-2' => 'inout:reqarray:1',
208                     'Testsome-5' => 'out:statusarray:1', # or 4?
209                     'Testall-2' => 'inout:reqarray:1',
210                     'Testall-4' => 'out:statusarray:1',
211                     'Startall-2' => 'inout:preqarray:1',
212                     'Pack-1' => 'in:const',
213                     'Unpack-1' => 'in:const',
214                     'Pack-6' => 'in:refint',
215                     'Unpack-5' => 'in:refint',
216
217                     'Get_error_string-3' => 'in:refint', 
218                     'Create_struct-4' => 'in:dtypearray:1',
219
220                     'Merge-2' => 'in:bool',
221                     'Create_cart-4' => 'in:boolarray:2',
222                     'Create_cart-5' => 'in:bool',
223                     'Create_graph-5' => 'in:bool',
224                     'cart-Get_topo-4' => 'out:boolarray:2',
225                     'Sub-2' => 'in:boolarray:-10', # Use -10 for immediate number
226                     'Shift-4' => 'in:refint',
227                     'Shift-5' => 'in:refint',
228                     # Bug - there are cartcomm map and graphcomm map.  The
229                     # call routine will find this
230                     'cart-Map-4' => 'in:boolarray:2',
231
232                     'Get_processor_name-2' => 'in:refint',
233
234                     'info-Set-2' => 'in:const',
235                     'info-Set-3' => 'in:const',
236                     'info-Get-2' => 'in:const',
237                     'Get_valuelen-2' => 'in:const',
238
239                     'file-Open-2' => 'in:const',
240                     'file-Delete-1' => 'in:const',
241                     'Set_view-4' => 'in:const',
242                     'Write-2' => 'in:const',
243                     'Write_all-2' => 'in:const',
244                     'Iwrite_at-2' => 'in:const',
245                     'Iwrite-2' => 'in:const',
246                     'Write_at-3' => 'in:const',
247                     'Write_at_all-3' => 'in:const',
248                     'Write_at_all_begin-3' => 'in:const',
249                     'Write_at_all_end-2' => 'in:const',
250                     'Write_all_begin-2' => 'in:const',
251                     'Write_all_end-2' => 'in:const',
252                     'Write_ordered_begin-2' => 'in:const',
253                     'Write_ordered_end-2' => 'in:const',
254                     'Write_ordered-2' => 'in:const',
255                     'Write_shared-2' => 'in:const', 
256                     'Set_atomicity-2' => 'in:bool',
257
258                     'Put-1' => 'in:const',
259                     'Accumulate-1' => 'in:const',
260                     'Alloc_mem-2' => 'in:constref:Info',
261
262                     'Detach_buffer-1' => 'inout:ptrref', 
263                     'Get_version-1' => 'in:refint',
264                     'Get_version-2' => 'in:refint',
265                     'Get_name-3' => 'in:refint',
266                     'Set_name-2' => 'in:const',
267                     'Add_error_string-2' => 'in:const', 
268                     );
269%class_mpi1cart = ( 'Dup' => MPI_Comm,
270                    'Get_dim' => 'int',
271                    'Get_topo' => '0:4',
272                    'Get_cart_rank' => '3',
273                    'Get_coords' => 0,
274                    'Shift' => '0:4:5',
275                    'Sub' => 'MPI_Comm:2',
276                    'Map' => '5:4',
277);
278$specialReturnType{"cart-Dup"} = "Cartcomm";
279$specialReturnType{"cart-Sub"} = "Cartcomm";
280$specialReturnType{"cart-Split"} = "Cartcomm";
281
282%class_mpi1dtype = ( 'Create_contiguous' => 'MPI_Datatype',
283                     'Create_vector' => 'MPI_Datatype', 
284                     'Create_indexed' => 'MPI_Datatype', 
285                     'Create_struct' => 'static:5:4',
286                     'Get_size' => 2, 
287                     'Commit' => 0,
288                     'Free' => 0, 
289#                    'Pack' => '0:1:6',
290#                    'Unpack' => '0:1:5',
291                     'Pack_size' => 4,
292                     );
293%class_mpi1errh = ( 'Free' => 0, 
294                    # Init missing
295                    );
296%class_mpi1graph = ( 'Get_dims' => 0, 
297                     'Get_topo' => 0,
298                     'Get_neighbors_count' => 'int', 
299                     'Get_neighbors' => 0,
300                     'Map' => 5,
301                     );
302$specialReturnType{"graph-Dup"} = "Graphcomm";
303$specialReturnType{"graph-Split"} = "Graphcomm";
304
305# Range routines will require special handling
306# The Translate_ranks, Union, Intersect, Difference, and Compare routines are
307# static and don't work on an instance of a group
308%class_mpi1group = ( 'Get_size' => 'int',
309                     'Get_rank' => 'int',
310                     'Translate_ranks' => 'static:0',
311                     'Compare' => 'static:int',
312                     'Union' => 'static:MPI_Group',
313                     'Intersect' => 'static:MPI_Group',
314                     'Difference' => 'static:MPI_Group',
315                     'Incl', MPI_Group,
316                     'Excl', MPI_Group,
317                     'Range_incl', MPI_Group,
318                     'Range_excl', MPI_Group,
319                     'Free' => 0,
320);
321%class_mpi1inter = ( 'Dup' => MPI_Comm, 
322                     'Get_remote_size' => 'int', 
323                     'Get_remote_group' => MPI_Group,
324                     'Merge' => 'MPI_Comm:2',
325                     );
326$specialReturnType{"inter-Dup"} = "Intercomm";
327$specialReturnType{"inter-Split"} = "Intercomm";
328
329%class_mpi1intra = ( #'Barrier' => 0,
330                     #'Bcast' => 0,
331                     #'Gather' => 0,
332                     #'Gatherv' => 0,
333                     #'Scatter' => 0,
334                     #'Scatterv' => 0,
335                     #'Allgather' => 0,
336                     #'Allgatherv' => 0,
337                     #'Alltoall' => 0,
338                     #'Alltoallv' => 0,
339                     #'Reduce' => 0,
340                     #'Allreduce' => 0,
341                     #'Reduce_scatter' => 0,
342                     'Scan' => 0,
343                     'Dup' => MPI_Comm,
344                     'Create' => MPI_Comm,
345                     'Split' => MPI_Comm,
346                     'Create_intercomm' => MPI_Comm,
347                     'Create_cart' => 'MPI_Comm:4:5',
348                     'Create_graph' => 'MPI_Comm:5' 
349);
350$specialReturnType{"intra-Split"} = "Intracomm";
351$specialReturnType{"intra-Create"} = "Intracomm";
352$specialReturnType{"intra-Dup"} = "Intracomm";
353
354%class_mpi1op = ( 'Free' => 0);
355%class_mpi1preq = ( 'Start' => 0,
356                    'Startall' => 'static:0:2' );
357%class_mpi1req = ( 'Wait' => 0, 
358                   'Test' => 'int;bool',
359                   'Free' => 0, 
360                   'Cancel' => 0,
361                   'Waitall' => 'static:0:2:3',
362                   'Waitany' => 'static:int:2',
363                   'Waitsome' => 'static:3:2:5',
364                   'Testall' => 'static:int;bool:2:4',
365                   'Testany' => 'static:4;bool:2:3:4',
366                   'Testsome' => 'static:3:2:5',
367);
368%class_mpi1st = ( 'Get_count' => 'int',
369                  'Is_cancelled' => 'int;bool',
370                  'Get_elements' => 'int',
371                  # get/set source, tag, error have no C binding
372                  );
373
374# These are the routines that are in no class, minus the few that require
375# special handling (Init, Wtime, and Wtick).
376%class_mpi1base = ( 'Get_processor_name' => '0:2',
377                    'Get_error_string' => '0:3',
378                    'Get_error_class', => '2', 
379                    'Compute_dims' => 0,
380                    'Finalize' => 0,
381                    'Is_initialized', => '1;bool',
382                    'Attach_buffer' => 0,
383                    'Detach_buffer' => '2:1',
384                    'Pcontrol' => '0',
385                    'Get_version' => '0:1:2',   # MPI 1.2
386                    );
387#
388# Here are the MPI-2 methods
389# WARNING: These are incomplete.  They primarily define only the
390# MPI-2 routines implemented by MPICH2.
391%class_mpi2base = ( 'Alloc_mem' => '3;void *:2',
392                    'Free_mem' => '0', 
393                    'Open_port' => '1',
394                    'Close_port' => '0',
395                    'Publish_name' => '0',
396                    'Lookup_name' => '0',
397                    'Unpublish_name' => '0',
398                    'Is_finalized' => '1;bool',
399                    'Query_thread' => '1',
400                    'Is_thread_main' => '1;bool',
401                    'Add_error_class' => 1,
402                    'Add_error_code' => 2, 
403                    'Add_error_string' => '0:2',
404                    );
405%class_mpi2comm = ( 'Barrier' => 0, 
406                    'Get_attr' => 'int',
407                    'Set_attr' => 0,
408                    'Delete_attr' => 0,
409#                   'Create_keyval' => 'int',
410                    'Free_keyval' =>  'static:0:1',
411                    'Call_errhandler' => 0,
412                    'Set_name' => '0:2',
413                    'Get_name' => '0:3',
414                    'Disconnect' => 0,
415                    'Get_parent' => 'static:0;Intercomm',
416                   );
417%class_mpi2cart = ();
418%class_mpi2dtype = ( 'Set_name' => '0:2', 
419                     'Get_name' => '0:3',
420                     'Dup' => 'MPI_Datatype',
421                     'Get_extent' => '0',
422                     'Create_hvector' => 'MPI_Datatype',
423                     'Create_hindexed' => 'MPI_Datatype',
424                     'Get_extent' => '0',
425                     'Create_resized' => 'MPI_Datatype',  # FIXME Check not just resized
426                     'Get_true_extent' => 0,
427                     'Create_subarray' => 'MPI_Datatype',
428                     'Create_darray' => 'MPI_Datatype',
429                     'Get_attr' => 'int',
430                     'Set_attr' => 0,
431                     'Delete_attr' => 0,
432#                    'Create_keyval' => 'int',
433                     'Free_keyval' =>  'static:0:1',
434);
435%class_mpi2errh = ( 
436                    );
437%class_mpi2graph = ();
438%class_mpi2group = ();
439%class_mpi2inter = ( #'Barrier' => 0, # MPI-2 adds intercomm collective
440                     #'Bcast' => 0,   # These are moved into the Comm class
441                     #'Gather' => 0,
442                     #'Gatherv' => 0,
443                     #'Scatter' => 0,
444                     #'Scatterv' => 0,
445                     #'Allgather' => 0,
446                     #'Allgatherv' => 0,
447                     #'Alltoall' => 0,
448                     #'Alltoallv' => 0,
449                     #'Reduce' => 0,
450                     #'Allreduce' => 0,
451                     #'Reduce_scatter' => 0,
452                     #'Scan' => 0,
453                     #'Exscan' => 0,
454);
455#$specialReturnType{"inter-Split"} = "Intercomm";
456
457# Alltoallw uses an array of datatypes, which requires special handling
458# Spawn and spawn mulitple uses arrays of character strings, which
459# also require special handling
460%class_mpi2intra = ( #'Alltoallw' => 0,
461                     'Exscan' => 0,
462#                   'Spawn' => 'MPI_Comm',
463#                   'Spawn_multiple' => 'MPI_Comm',
464                    'Accept' => 'MPI_Comm',
465                     'Connect' => 'MPI_Comm',
466                     );
467%class_mpi2op = ();
468%class_mpi2preq = ();
469%class_mpi2req = ();
470# Start requires C++ to C function interposers (like errhandlers)
471%class_mpi2greq = ( 'Complete' => 0, 
472#                   'Start' => 'MPI_Request',
473);
474%class_mpi2st = ();
475%class_mpi2file = ( );
476if ($build_io) {
477    %class_mpi2file = ( 
478                   'Open' => 'static:MPI_File:2',
479                   'Close' => 0,
480                   'Delete' => 'static:0:1',
481                   'Set_size' => 0,
482                   'Preallocate' => 0,
483                   'Get_size' => 'MPI_Offset',
484                   'Get_group' => 'MPI_Group',
485                   'Get_amode' => 'int',
486                   'Set_info' => 0,
487                   'Get_info' => 'MPI_Info',
488                   'Set_view' => '0:4',
489                   'Get_view' => 0,
490                   'Read_at' => 0,
491                   'Read_at_all' => 0,
492                   'Write_at' => '0:3',
493                   'Write_at_all' => '0:3',
494                   'Iread_at' => 'MPI_Request', 
495                   'Iwrite_at' => 'MPI_Request:2',
496                   'Read' => 0,
497                   'Read_all' => 0,
498                   'Write' => '0:2',
499                   'Write_all' => '0:2',
500                   'Iread' => 'MPI_Request',
501                   'Iwrite' => 'MPI_Request:2',
502                   'Seek' => 0,
503                   'Get_position' => 'MPI_Offset',
504                   'Get_byte_offset' => 'MPI_Offset',
505                   'Read_shared' => 0,
506                   'Write_shared' => '0:2',
507                   'Iread_shared' => 'MPI_Request',
508                   'Iwrite_shared' => 'MPI_Request:2',
509                   'Read_ordered' => 0,
510                   'Write_ordered' => '0:2',
511                   'Seek_shared' => 0,
512                   'Get_position_shared' => 'MPI_Offset',
513                   'Read_at_all_begin' => 0,
514                   'Read_at_all_end' => 0,
515                   'Write_at_all_begin' => '0:3',
516                   'Write_at_all_end' => '0:2',
517                   'Read_all_begin' => 0,
518                   'Read_all_end' => 0,
519                   'Write_all_begin' => '0:2',
520                   'Write_all_end' => '0:2',
521                   'Read_ordered_begin' => 0,
522                   'Read_ordered_end' => 0,
523                   'Write_ordered_begin' => '0:2',
524                   'Write_ordered_end' => '0:2',
525                   'Get_type_extent' => 'MPI_Aint',
526                   'Set_atomicity' => '0:2',
527                   'Get_atomicity' => 'int;bool',
528                   'Sync' => 0,
529                   'Get_errhandler' => 'MPI_Errhandler',
530                   'Set_errhandler' => 0,
531                   'Call_errhandler' => 0,
532                   );           
533#     %class_mpi2file = (
534#                  'File_open' => 'static:MPI_File:2',
535#                  'File_close' => 0,
536#                  'File_delete' => 'static:0:1',
537#                  'File_set_size' => 0,
538#                  'File_preallocate' => 0,
539#                  'File_get_size' => 'MPI_Offset',
540#                  'File_get_group' => 'MPI_Group',
541#                  'File_get_amode' => 'int',
542#                  'File_set_info' => 0,
543#                  'File_get_info' => 'MPI_Info',
544#                  'File_set_view' => '0:4',
545#                  'File_get_view' => 0,
546#                  'File_read_at' => 0,
547#                  'File_read_at_all' => 0,
548#                  'File_write_at' => '0:2',
549#                  'File_write_at_all' => '0:2',
550#                  'File_iread_at' => 'MPI_Request',
551#                  'File_iwrite_at' => 'MPI_Request:1',
552#                  'File_read' => 0,
553#                  'File_read_all' => 0,
554#                  'File_write' => '0:1',
555#                  'File_write_all' => '0:1',
556#                  'File_iread' => 'MPI_Request',
557#                  'File_iwrite' => 'MPI_Request:1',
558#                  'File_seek' => 0,
559#                  'File_get_position' => 'MPI_Offset',
560#                  'File_get_byte_offset' => 'MPI_Offset',
561#                  'File_read_shared' => 0,
562#                  'File_write_shared' => 0,
563#                  'File_iread_shared' => 'MPI_Request',
564#                  'File_iwrite_shared' => 'MPI_Request:1',
565#                  'File_read_ordered' => 0,
566#                  'File_write_ordered' => '0:1',
567#                  'File_seek_shared' => 0,
568#                  'File_get_position_shared' => 'MPI_Offset',
569#                  'File_read_at_all_begin' => 0,
570#                  'File_read_at_all_end' => 0,
571#                  'File_write_at_all_begin' => '0:2',
572#                  'File_write_at_all_end' => '0:1',
573#                  'File_read_all_begin' => 0,
574#                  'File_read_all_end' => 0,
575#                  'File_write_all_begin' => '0:1',
576#                  'File_write_all_end' => '0:1',
577#                  'File_read_ordered_begin' => 0,
578#                  'File_read_ordered_end' => 0,
579#                  'File_write_ordered_begin' => '0:1',
580#                  'File_write_ordered_end' => '0:1',
581#                  'File_get_type_extent' => 'MPI_Aint',
582#                  'File_set_atomicity' => '0:1',
583#                  'File_get_atomicity' => 'bool',
584#                  'File_sync' => 0,
585#                  'File_set_errhandler' => 'MPI_Errhandler',
586#                  'File_get_errhandler' => 0,
587#                  );           
588}
589%class_mpi2win = (  'Put' => '0:1', 'Get' => '0', 
590                    'Accumulate' => '0', 
591                    'Create' => 'static:MPI_Win', 
592                    'Free' => '0',
593                    'Fence' => '0', 
594                    'Get_group' => 'MPI_Group',
595                    'Call_errhandler' => 0,
596                    'Get_attr' => '0',
597                    'Start' => '0',
598                    'Complete' => '0',
599                    'Post' => '0',
600                    'Wait' => '0',
601                    'Test' => 'int;bool',
602                    'Lock' => '0',
603                    'Unlock' => '0',
604                    'Set_name' => '0:2',
605                    'Get_name' => '0:3',
606                    'Get_attr' => 'int',
607                    'Set_attr' => 0,
608                    'Delete_attr' => 0,
609                    'Free_keyval' =>  'static:0:1',
610                    );
611%class_mpi2info = ( 'Create' => 'static:1',
612                    'Set' => '0:2:3',
613                    'Delete' => '0:2',
614                    'Get' => '5;bool:2',
615                    'Get_valuelen' => '4;bool:2',
616                    'Get_nkeys' => '2',
617                    'Get_nthkey' => '0', 
618                    'Dup' => '2',
619                    'Free' => '0', 
620                    );
621
622# Name of classes, in the order in which they must be declared.  This
623# includes all classes, by their short names
624@classes = ( 
625                   'except',
626                   'dtype', 
627                   'info', 
628                   'st', 
629                   'group', 
630                   'op', 
631                   'errh',
632                   'req', 
633                   'preq', 
634                   'comm', 
635                   'null',
636                   'inter', 
637                   'intra', 
638                   'greq', 
639                   'win', 
640                   'file', 
641                   'graph',
642                   'cart', 
643);
644
645#
646# Some classes have additional methods.  This hash on the classes (by
647# short name) gives the name of a routine that will add additional methods.
648# Primarily used for the Status methods (get/set_tag etc) and for
649# Communicator clone methods.
650%class_extra_fnc = ( 'st'        => 'Status_methods',
651                     'except'    => 'Exception_methods',
652                     'comm'      => 'Comm_methods',
653                     'null'  => 'Nullcomm_methods',
654                     'inter' => 'Intercomm_methods',
655                     'intra' => 'Intracomm_methods',
656                     'graph' => 'Graphcomm_methods',
657                     'cart'  => 'Cartcomm_methods',
658                     'dtype'     => 'Datatype_methods',
659                     'op'        => 'Op_methods',
660                     'file'      => 'File_methods',
661                     'win'       => 'Win_methods',
662                     'greq'      => 'Grequest_methods',
663                     );
664
665# ----------------------------------------------------------------------------
666# If there is a specific list of routines, replace the list with this
667# list
668%newclasses = ();
669if ($routine_list ne "") {
670    for $routine (split(/\s+/,$routine_list)) {
671        print "$routine\n" if $gDebug;
672        ($class,$rname) = split(/-/,$routine);
673        # Look up name in the class list
674        $classvar = "class-mpi1$class";
675        $result_type = 0;
676        if (defined($$classvar{$rname})) {
677            $result_type = $$classvar{$rname};
678        }
679        else {
680            $classvar = "class-mpi2$class";
681            if (defined($$classvar{$rname})) {
682                $result_type = $$classvar{$rname};
683            }
684        }
685        $newclasses{$class} .= " $rname=>$result_type";
686    }
687    # Now, clear all of the classes
688    foreach $class (@classes) {
689        $class_name = "class_mpi1$class";
690        %$class_name = ();
691        $class_name = "class_mpi2$class";
692        %$class_name = ();
693    }             
694    # And unpack newclasses
695    foreach $class (keys(%newclasses)) {
696        $class_name = "class_mpi1$class";
697        foreach $rpair (split(/\s+/,$newclasses{$class})) {
698            if ($rpair eq "") { next; }
699            print "$rpair\n" if $gDebug;
700            ($routine, $rval) = split(/=>/,$rpair);
701            $$class_name{$routine} = $rval;
702        }
703    }
704    # At this point, we should generate only the routines requested,
705    # plus all of the classes (we may need the empty classes for the
706    # predefined types)
707}
708
709# ----------------------------------------------------------------------------
710
711# MPI objects
712# dtypes gives all of the MPI datatypes whose C version are this name
713# with MPI_ in front.  E.g., MPI::CHAR is the same as MPI_CHAR.
714# The size-specific types were added in MPI-2, and are required for
715# C and C++ as well as for Fortran
716@dtypes = ( 'CHAR', 'UNSIGNED_CHAR', 'BYTE', 'SHORT', 'UNSIGNED_SHORT',
717            'INT', 'UNSIGNED', 'LONG', 'UNSIGNED_LONG', 'FLOAT', 
718            'DOUBLE', 'LONG_DOUBLE', 'LONG_LONG_INT', 'LONG_LONG', 
719            'PACKED', 'LB', 'UB', 'FLOAT_INT', 'DOUBLE_INT', 
720            'LONG_INT', 'SHORT_INT', 'LONG_DOUBLE_INT',
721            'REAL4', 'REAL8', 'REAL16', 'COMPLEX8', 'COMPLEX16',
722            'COMPLEX32', 'INTEGER1', 'INTEGER2', 'INTEGER4', 
723            'INTEGER8', 'INTEGER16', 'WCHAR', 'SIGNED_CHAR', 
724            'UNSIGNED_LONG_LONG' );
725
726@typeclasses = ( 'TYPECLASS_REAL', 'TYPECLASS_INTEGER', 'TYPECLASS_COMPLEX' );
727
728
729#
730# Still missing: C++ only types: BOOL, COMPLEX, DOUBLE_COMPLEX,
731# LONG_DOUBLE_COMPLEX.
732@cppdtypes = ( 'BOOL', 'COMPLEX', 'DOUBLE_COMPLEX', 'LONG_DOUBLE_COMPLEX' );
733
734# ops is like dtypes
735@ops = ( 'MAX', 'MIN', 'SUM', 'PROD', 'LAND', 'BAND', 'LOR', 'BOR', 
736         'LXOR', 'BXOR', 'MINLOC', 'MAXLOC', 'REPLACE' );
737# errclasses is like dtypes.  Contains both MPI-1 and MPI-2 classes
738@errclasses = ( 'SUCCESS', 'ERR_BUFFER', 'ERR_COUNT', 'ERR_TYPE',
739                'ERR_TAG', 'ERR_COMM', 'ERR_RANK', 'ERR_REQUEST',
740                'ERR_ROOT', 'ERR_GROUP', 'ERR_OP', 'ERR_TOPOLOGY',
741                'ERR_DIMS', 'ERR_ARG', 'ERR_UNKNOWN', 'ERR_TRUNCATE',
742                'ERR_OTHER', 'ERR_INTERN', 'ERR_PENDING', 'ERR_IN_STATUS',
743                'ERR_LASTCODE', 
744                'ERR_FILE', 'ERR_ACCESS', 'ERR_AMODE', 'ERR_BAD_FILE',
745                'ERR_FILE_EXISTS', 'ERR_FILE_IN_USE', 'ERR_NO_SPACE',
746                'ERR_NO_SUCH_FILE', 'ERR_IO', 'ERR_READ_ONLY', 
747                'ERR_CONVERSION', 'ERR_DUP_DATAREP', 'ERR_UNSUPPORTED_DATAREP',
748                'ERR_INFO', 'ERR_INFO_KEY', 'ERR_INFO_VALUE', 'ERR_INFO_NOKEY',
749                'ERR_NAME', 'ERR_NO_MEM', 'ERR_NOT_SAME', 'ERR_PORT',
750                'ERR_QUOTA', 'ERR_SERVICE', 'ERR_SPAWN',
751                'ERR_UNSUPPORTED_OPERATION', 'ERR_WIN', 'ERR_BASE',
752                'ERR_LOCKTYPE', 'ERR_KEYVAL', 'ERR_RMA_CONFLICT', 
753                'ERR_RMA_SYNC', 'ERR_SIZE', 'ERR_DISP', 'ERR_ASSERT',
754                );
755
756#
757# Special routines require special processing in C++
758%special_routines = ( 'Init' => 1, 'Init_thread' => 1, 'Pcontrol' => '1' );
759
760#
761# Most routines can be processed automatically.  However, some
762# require some special processing.  (See the Fortran version
763# of buildiface)
764
765$arg_string = join( ' ', @ARGV );
766
767# ---------------------------------------------------------------------------
768# Here begins more executable code.  Read the definitions of the
769# routines.  The argument list for routine xxx is placed into the hash
770# mpi_routine{xxx}.
771&ReadInterface( "../../include/mpi.h.in" );
772# Special case:  Add Pcontrol
773$mpi_routine{'Pcontrol'} = "int,...";
774
775# if doing MPI2, we also need to read the MPI-2 protottypes
776if ( -s "../../mpi/romio/include/mpio.h.in" ) { 
777    &ReadInterface( "../../mpi/romio/include/mpio.h.in" );
778}
779
780# Class_type gives the C datatype for each class, except for the
781# exception class, which has no C counterpart
782%class_type = ( 'comm' => MPI_Comm, 
783                'cart' => MPI_Comm,
784                'dtype' => MPI_Datatype,
785                'errh' => MPI_Errhandler,
786                'null'  => MPI_Comm,
787                'graph' => MPI_Comm,
788                'group' => MPI_Group,
789                'inter' => MPI_Comm,
790                'intra' => MPI_Comm,
791                'op' => MPI_Op,
792                'preq' => MPI_Request,
793                'req' => MPI_Request,
794                'greq' => MPI_Request,
795                'st' => MPI_Status,
796                'info' => MPI_Info,
797                'win' => MPI_Win,
798                'file' => MPI_File,
799                'except' => 'int',
800 );
801#
802# fullclassname gives the C++ binding class name for each shorthand version
803%fullclassname = ( 'comm' => 'Comm',
804                   'cart' => 'Cartcomm',
805                   'dtype' => 'Datatype',
806                   'errh' => 'Errhandler',
807                   'graph' => 'Graphcomm',
808                   'group' => 'Group',
809                   'null'  => 'Nullcomm',
810                   'inter' => 'Intercomm',
811                   'intra' => 'Intracomm',
812                   'op' => 'Op',
813                   'preq' => 'Prequest',
814                   'req' => 'Request',
815                   'st' => 'Status',
816                   'greq' => 'Grequest',
817                   'info' => 'Info',
818                   'win' => 'Win',
819                   'file' => 'File',
820                   'except' => 'Exception',
821);
822
823#
824# Each class may need to access internal elements of another class.
825# This has gives the list of friends for each class (i.e., the
826# classes that are allowed to directly access the protected members).
827# The friends are the full class names
828%class_friends = ( 'comm' => 'Cartcomm,Intercomm,Intracomm,Graphcomm,Nullcomm,Datatype,Win,File',
829                   'cart' => '',
830                   'dtype' => 'Comm,Status,Intracomm,Intercomm,Win,File',
831                   'errh' => 'Comm,File,Win',
832                   'graph' => '',
833                   'group' => 'Comm,Intracomm,Intercomm,Win,File',
834                   'inter' => 'Intracomm',
835                   'intra' => 'Cartcomm,Graphcomm,Datatype',
836                   # Op adds comm as a friend because of MPI2
837                   'op' => 'Intracomm,Intercomm,Win,Comm',
838                   'preq' => '',
839                   'req' => 'Comm,File,Grequest',
840                   'st' => 'Comm,File,Request',
841                   'greq' => '',
842                   'info' => 'File,Win,Comm,Intracomm',
843                   'win' => '',
844                   'file' => '',
845 );
846
847#
848# We also need to know the derived classes.  This gives the class that
849# a class is derived from.  Base classes are not included here.
850%derived_class = ( 'graph' => 'Intracomm', 
851                   'preq' => 'Request',
852                   'greq' => 'Request',
853                   'null' => 'Comm',
854                   'inter' => 'Comm',
855                   'intra' => 'Comm',
856                   'cart' => 'Intracomm',
857                   );
858
859#
860# Maps all of the derived classes to their ultimate parent.  This is
861# used to find the name of the correct protected element (the_real_xxx),
862# used to store the C version of the class handle.
863%mytopclass = ( 'graph'     => 'comm', 
864                'graphcomm' => 'comm',
865                'nullcomm'  => 'comm',
866                'intracomm' => 'comm', 
867                'intercomm' => 'comm',
868                'intra'     => 'comm', 
869                'inter'     => 'comm',
870                'cart'      => 'comm',
871                'cartcomm'  => 'comm',
872                'grequest'  => 'request',
873                'prequest'  => 'request',
874                'greq'      => 'request',
875                'preq'      => 'request' );
876
877#
878# Many of the C++ binding names are easily derived from the C name.
879# For those names that are not so derived, this hash provides a mapping from
880# the C names to the C++ names.
881# WARNING: This list is incomplete
882#
883# These have the form <short-class-name>-<C++name> => <C-name>; i.e.,
884# MPI_Comm_rank becomes 'comm-rank'.  Routines that are part of the MPI
885# namespace but not in any class leave the class field blank, i.e.,
886# -Attach_buffer .
887%altname = ( 'base-Attach_buffer' => 'Buffer_attach',
888             'base-Detach_buffer' => 'Buffer_detach',
889             'base-Compute_dims' => 'Dims_create',
890             'base-Get_error_class' => 'Error_class',
891             'base-Get_error_string' => 'Error_string',
892             'base-Is_initialized' => 'Initialized',
893             'base-Is_finalized' => 'Finalized',
894             'base-Register_datarep' => 'Register_datarep',
895             'comm-Sendrecv_replace' => 'Sendrecv_replace',
896             'comm-Get_topology' => 'Topo_test',
897             'comm-Get_rank' => 'Comm_rank',
898             'comm-Get_size' => 'Comm_size',
899             'comm-Get_group' => 'Comm_group',
900             'comm-Is_inter' => 'Comm_test_inter',
901             'dtype-Create_contiguous' => 'Type_contiguous',
902             'dtype-Create_vector' => 'Type_vector',
903             'dtype-Create_indexed' => 'Type_indexed',
904             'dtype-Create_indexed_block' => 'Type_create_indexed_block',
905             'dtype-Create_struct' => 'Type_create_struct',
906             'dtype-Get_envelope' => 'Type_get_envelope',
907             'dtype-Get_contents' => 'Type_get_contents',
908             'dtype-Match_size' => 'Type_match_size',
909             'dtype-Create_f90_real' => 'Type_create_f90_real',
910             'dtype-Create_f90_complex' => 'Type_create_f90_complex',
911             'dtype-Create_f90_integer' => 'Type_create_f90_integer',
912             'dtype-Commit' => 'Type_commit',
913             'dtype-Pack' => 'Pack',
914#            'dtype-Unpack' => 'Unpack',
915# Unpack is a special case because the C++ binding doesn't follow a simple
916# rule to derive from the C binding
917             'dtype-Pack_size' => 'Pack_size',
918             'dtype-Free' => 'Type_free',
919             'dtype-Get_size' => 'Type_size',
920             'dtype-Get_name' => 'Type_get_name',
921             'dtype-Set_name' => 'Type_set_name',
922             'dtype-Get_extent' => 'Type_get_extent',
923             'dtype-Dup' => 'Type_dup',
924             'dtype-Create_subarray' => 'Type_create_subarray',
925             'dtype-Create_resized' => 'Type_create_resized',
926             'dtype-Create_hvector' => 'Type_create_hvector',
927             'dtype-Create_darray' => 'Type_create_darray',
928             'dtype-Create_hindexed' => 'Type_create_hindexed',
929             'dtype-Get_true_extent' => 'Type_get_true_extent',
930             'dtype-Get_attr' => 'Type_get_attr',
931             'dtype-Set_attr' => 'Type_set_attr',
932             'dtype-Delete_attr' => 'Type_delete_attr',
933             'dtype-Free_keyval' => 'Type_free_keyval',
934             'group-Get_size' => 'Group_size',
935             'group-Get_rank' => 'Group_rank',
936             'group-Intersect' => 'Group_intersection',
937             'intra-Create_intercomm' => 'Intercomm_create',
938             'inter-Create' => 'Comm_create',
939             'inter-Split' => 'Comm_split',
940             'intra-Split' => 'Comm_split',
941             'inter-Get_remote_group' => 'Comm_remote_group',
942             'inter-Get_remote_size' => 'Comm_remote_size',
943             'inter-Dup' => 'Comm_dup',
944             'intra-Create' => 'Comm_create',
945             'intra-Dup' => 'Comm_dup',
946             'intra-Split' => 'Comm_split',
947             'intra-Create_cart' => 'Cart_create',
948             'intra-Create_graph' => 'Graph_create',
949             'intra-Connect' => 'Comm_connect',
950             'intra-Spawn' => 'Comm_spawn',
951             'intra-Spawn_multiple' => 'Comm_spawn_multiple',
952             'intra-Accept' => 'Comm_accept',
953             'st-Is_cancelled' => 'Test_cancelled',
954             'cart-Get_cart_rank' => 'Cart_rank',
955             'cart-Map' => 'Cart_map',
956             'cart-Get_topo' => 'Cart_get',
957             'cart-Shift' => 'Cart_shift',
958             'cart-Sub' => 'Cart_sub',
959             'cart-Dup' => 'Comm_dup',
960             'cart-Get_dim' => 'Cartdim_get',
961             'cart-Get_coords' => 'Cart_coords',
962             'cart-Get_rank' => 'Cart_rank',
963             'graph-Map' => 'Graph_map',
964             'graph-Get_topo' => 'Graph_get',
965             'graph-Get_neighbors' => 'Graph_neighbors',
966             'graph-Get_neighbors_count' => 'Graph_neighbors_count',
967             'graph-Get_dims' => 'Graphdims_get',
968             'graph-Dup' => 'Comm_dup',
969             );
970
971# These routines must be defered because their implementations need
972# definitions of classes that must be made later than the class that they
973# are in.  In particular, these need both datatypes and communicators.
974%defer_definition = ( 'Pack' => Datatype, 
975                      'Pack_size' => Datatype, 
976                      'Unpack' => Datatype
977                      );
978
979# These classes (in the binding name) do not have a compare operation, or
980# use the parent class's compare operation.
981# These use the Full class name.
982%class_has_no_compare = ( 'Status' => 1,
983                          'Intracomm' => 1,
984                          'Intercomm' => 1,
985                          'Nullcomm' => 1,
986                          'Cartcomm' => 1,
987                          'Graphcomm' => 1,
988                          'Prequest' => 1,
989                          );
990# These classes do not have a default intialization
991# These use the Full class name
992%class_has_no_default = ( 'Status' => 1 );
993
994# Read the function specification (will eventually replace the hard-coded
995# values set in this file).  This file contains information that is not
996# derived from the ReadInterface
997if ($doFuncspec) {
998    &ReadFuncSpec( "cxxdecl3.dat" );
999    # Use the MPI C++ binding names for the defered definitions
1000    $defer_definition{"Create_cart"}  = "Comm";
1001    $defer_definition{"Create_graph"} = "Comm";
1002    $defer_definition{"Get_parent"}   = "Comm";
1003    $defer_definition{"Join"}         = "Comm";
1004    $defer_definition{"Merge"}        = "Intercomm";
1005    $defer_definition{"Call_errhandler"} = "Comm";
1006    $defer_definition{"Call_errhandler"} = "File";
1007    $defer_definition{"Call_errhandler"} = "Win";
1008
1009    $dtype_Get_name_init = "    MPIR_CXX_InitDatatypeNames();";
1010}
1011
1012# FIXME: TODO
1013# Some of the routine definitions require future class definitions; e.g.,
1014# The Intracomm routine Create_cart needs to create a Cartcomm.  These
1015# routines must have their definitions in initcxx.cxx, not
1016# mpicxx.h .  How should we mark these?
1017# (The original buildiface incorrectly generated Comm objects for these)
1018# Because there are only a few routines, we can keep track of these here
1019
1020
1021# create the master file
1022$filename = "mpicxx.h.in";
1023$OUTFD = OUTFILEHANDLE;
1024open ( $OUTFD, ">${filename}.new" ) || die "Could not open ${filename}.new\n";
1025# Use the derived file as a source
1026$files[$#files+1] = "mpicxx.h";
1027&print_header;
1028&printDefineChecks;
1029
1030&printCoverageHeader( $OUTFD, 1 );
1031
1032&PrintNewSeek( $OUTFD );
1033
1034print $OUTFD "namespace MPI {\n";
1035
1036#
1037# FIXME: This isn't correct - if the error handler is
1038# *not* errors_throw_exceptions, this causes the wrong thing to happen. 
1039# Instead, we should throw only if that is the requested error handler.
1040# This may mean changing this approach, and having the error call
1041# interface call back into the C++ interface to invoke a throw routine.
1042print $OUTFD "#if \@HAVE_CXX_EXCEPTIONS\@
1043#define MPIX_CALL( fnc ) \\
1044{int err; err = fnc ; if (err) throw Exception(err);}
1045#else
1046#define MPIX_CALL( fnc ) (void)fnc
1047#endif\n";
1048
1049#
1050# Within a "namespace" qualifier, the namespace name should not be used.
1051# Thus, we use Offset, not MPI::Offset.
1052print $OUTFD "
1053// Typedefs for basic int types
1054typedef MPI_Offset Offset;
1055typedef MPI_Aint   Aint;
1056typedef MPI_Fint   Fint;
1057
1058// Special internal routine
1059void MPIR_CXX_InitDatatypeNames( void );
1060
1061// Forward class declarations
1062class Comm;
1063class Nullcomm;
1064class Intercomm;
1065class Intracomm;
1066class Cartcomm;
1067class Graphcomm;
1068\n";
1069
1070
1071#
1072# Add the base routines.  Since these are not in any class, we
1073# place only their prototype in the header file.  The
1074# implementation is then placed in the source file.  We can
1075# put these here because none of them use any of the other classes,
1076# and we'll want to use a few of them in the implementations of the
1077# other functions.
1078foreach $routine (keys(%class_mpi1base)) {
1079    # These aren't really a class, so they don't use Begin/EndClass
1080    $arginfo = $class_mpi1base{$routine};
1081    print $OUTFD "extern ";
1082    &PrintRoutineDef( $OUTFD, "base", $routine, $arginfo, 1 );
1083}
1084
1085# mpi2base adds a few routines which need definitions (Info), so
1086# all of them are at the end, right before the extern declarations
1087
1088#
1089# Here's the loop structure
1090# foreach class
1091#   output class header
1092#   for mpi1, mpi2
1093#      for the routines in that class and choice of mpi1, mpi2
1094#   output any special methods
1095#
1096
1097# Build the routines by class
1098foreach $class (@classes) {
1099    $shortclass = $class;
1100    $Class = $fullclassname{$class};
1101    #$mpi_type = $class_type{$class};
1102
1103    # Special case to skip over the file routines (whose prototypes cause
1104    # us some problems).
1105    if ($class eq "file") {
1106        if (!$build_io) { next; }
1107        # Add a definition for MPI_FILE_NULL and MPI_File if none available
1108        print $OUTFD "#ifndef MPI_FILE_NULL\
1109#define MPI_FILE_NULL 0\
1110typedef int MPI_File;\
1111#endif\n";
1112    }
1113   
1114    # Begin the class, writing the common operations (destructors etc.)
1115    &BeginClass( $class );
1116
1117    # Hack to ifdef out the file routines
1118    if ($class eq "file") {
1119        # Define the file type only if supported.
1120        print $OUTFD "#ifdef MPI_MODE_RDONLY\n";
1121    }
1122
1123    foreach $mpilevel (@mpilevels) {
1124        $mpiclass = "$mpilevel$class";
1125        $class_hash = "class_$mpiclass";
1126        foreach $routine (keys(%$class_hash)) {
1127            print STDERR "processing $routine\n" if $gDebug;
1128
1129            # info describes the return parameter and any special
1130            # processing for this routine.
1131            $arginfo = $$class_hash{$routine};
1132           
1133            &PrintRoutineDef( $OUTFD, $class, $routine, $arginfo, 0 );
1134           
1135            # Check for Status as an arg (handle MPI_STATUS_IGNORE
1136            # by providing a definition without using Status).
1137            if ($args =~ /Status/ && $class ne "st") {
1138                &PrintRoutineDefNoStatus( $OUTFD, $class, 
1139                                          $routine, $arginfo, 0 );
1140            }
1141        }
1142    }
1143    if (defined($class_extra_fnc{$class})) {
1144        $extrafnc = $class_extra_fnc{$class};
1145        &$extrafnc( $OUTFD );
1146    }
1147
1148    # Hack to ifdef out the file routines
1149    if ($class eq "file") {
1150        # Define the file type only if supported.
1151        print $OUTFD "#endif\n";
1152    }
1153    &EndClass;
1154
1155    # Special case.  Once we define a Datatype, add this typedef
1156    if ($class eq "dtype") {
1157        print $OUTFD "
1158    typedef void User_function(const void *, void*, int, const Datatype&);
1159";
1160    }
1161}
1162
1163    # Add a few more external functions (some require the above definitions)
1164    foreach $routine (keys(%class_mpi2base)) {
1165        # These aren't really a class, so they don't use Begin/EndClass
1166        $arginfo = $class_mpi2base{$routine};
1167        print $OUTFD "extern ";
1168        #print "$routine - $arginfo\n";
1169        &PrintRoutineDef( $OUTFD, "base", $routine, $arginfo, 1 );
1170    }
1171    # Special case: the typedefs for the datarep function
1172    # Only define these typedefs when MPI-IO is available (this is the same
1173    # test as used for the rest of the I/O routines );
1174print $OUTFD "\
1175#ifdef MPI_MODE_RDONLY
1176typedef int Datarep_extent_function( const Datatype&, Aint&, void *);
1177typedef int Datarep_conversion_function( void *, Datatype &, int, void *,
1178                Offset, void * );
1179#endif
1180\n";
1181
1182    print $OUTFD "\n";
1183
1184    # Print the extern names for the various constants defined in the
1185    # MPI namespace
1186    &PrintConstants( $OUTFD, 0 );
1187
1188    # Other routines
1189    print $OUTFD "extern void Init(void);\n";
1190    print $OUTFD "extern void Init(int &, char **& );\n";
1191    print $OUTFD "extern int Init_thread(int);\n";
1192    print $OUTFD "extern int Init_thread(int &, char **&, int );\n";
1193    print $OUTFD "extern void Finalize(void);\n";
1194    print $OUTFD "extern Aint Get_address( void * );\n";
1195    print $OUTFD "extern double Wtime(void);\n";
1196    print $OUTFD "extern double Wtick(void);\n";
1197
1198    print $OUTFD "} // namespace MPI\n";
1199
1200    close ( $OUTFD );
1201    &ReplaceIfDifferent( $filename, "${filename}.new" );
1202
1203
1204# Build the special routines
1205&build_specials;
1206
1207#
1208# This block can be used to create the Makefile
1209#
1210# This isn't quite right.  mpicxx.h isn't a regular kind of source file.
1211$filename = "Makefile.sm";
1212open ( MAKEFD, ">${filename}.new" ) || die "Cannot create ${filename}.new";
1213print MAKEFD "# DO NOT EDIT\n# This file created by buildiface $arg_string\n";
1214# This line is unfortunately necessary to ensure that a working
1215# autoconf is used.
1216print MAKEFD "smvar_do_dependencies = ignore\n";
1217&print_line(  MAKEFD, "mpi_sources = ", 80, "\\\n\t", 8 );
1218for ($i=0; $i<=$#files; $i++) {
1219    $name = $files[$i];
1220    &print_line( MAKEFD, "$name ", 80, "\\\n\t", 8 );
1221}
1222&print_endline( MAKEFD );
1223
1224# No profile library for C++.  All routines call the MPI, not PMPI, routines.
1225my $otherSources = "";
1226my $otherHeaders = "";
1227if ($doCoverage) {
1228    $otherSources .= " mpicovsimple.cxx";
1229    $otherHeaders .= " \${srcdir}/mpicxxcov.h \${srcdir}/mpicovsimple.h";
1230}
1231print MAKEFD "MPICXXLIBNAME = \@MPICXXLIBNAME\@\n";
1232print MAKEFD "lib\${MPICXXLIBNAME}_a_DIR = ROOTDIR/lib\
1233lib\${MPICXXLIBNAME}_a_SOURCES = \${mpi_sources} $otherSources\
1234\
1235INCLUDES = -I../../include -I\${top_srcdir}/src/include -I\$(master_top_srcdir)/src/include \
1236maintainerclean-local:\
1237\trm -f \${mpi_sources}\
1238install_INCLUDE = mpicxx.h $otherHeaders\n";
1239
1240    # Add the documentation
1241    print MAKEFD "# Documentation sources
1242doc_sources = mpicxx.txt
1243DOCDESTDIRS = html:www/www1,man:man/man1,latex:doc/refman
1244doc_HTML_SOURCES  = \${doc_sources}
1245doc_MAN_SOURCES   = \${doc_sources}
1246doc_LATEX_SOURCES = \${doc_sources}
1247";
1248
1249# Since configure copies mpicxx to the bin dir, we need to remove it
1250# in a distclean step. 
1251print MAKEFD "distclean-local:\n";
1252print MAKEFD "\trm -f ../../../bin/mpicxx\n";
1253print MAKEFD "\trm -f ../../../src/include/mpicxx.h\n";
1254if ($doCoverage) {
1255    print MAKEFD "\trm -f ../../../src/include/mpicovsimple.h\n";
1256    print MAKEFD "\trm -f ../../../src/include/mpicxxcov.h\n";
1257}
1258
1259#
1260# Special targets for building the coverage support
1261if ($doCoverage) {
1262    print MAKEFD "mpicovsimple.o: mpicovsimple.cxx mpicovsimple.h\n";
1263    print MAKEFD "\t\$(CXX_COMPILE) -c -DCOVERAGE_DIR='\"\@builddir\@\"' \${srcdir}/mpicovsimple.cxx\n";
1264}
1265
1266close( MAKEFD );
1267&ReplaceIfDifferent( $filename, "${filename}.new" );
1268
1269
1270#
1271# ------------------------------------------------------------------------
1272# Procedures
1273# print_line( FD, line, count, continue, continuelen )
1274# Print line to FD; if line size > count, output continue string and
1275# continue.  Use print_endline to finish a line
1276sub print_line {
1277    my $FD = $_[0];
1278    my $line = $_[1];
1279    my $count = $_[2];
1280    my $continue = $_[3];
1281    my $continue_len = $_[4];
1282   
1283    $linelen = length( $line );
1284    #print "linelen = $linelen, print_line_len = $print_line_len\n";
1285    if ($print_line_len + $linelen > $count) {
1286        print $FD $continue;
1287        $print_line_len = $continue_len;
1288    }
1289    print $FD $line;
1290    $print_line_len += $linelen;
1291}
1292sub print_endline {
1293    my $FD = $_[0];
1294    print $FD "\n";
1295    $print_line_len = 0;
1296}
1297
1298# Print the header of the file, containing the definitions etc.
1299sub print_header {
1300    print $OUTFD "/* -*- Mode: C++; c-basic-offset:4 ; -*- */\
1301/*  \
1302 *  (C) 2001 by Argonne National Laboratory.\
1303 *      See COPYRIGHT in top-level directory.\
1304 *\
1305 * This file is automatically generated by buildiface $arg_string\
1306 * DO NOT EDIT\
1307 */
1308/* style: c++ header */\
1309\n";
1310}
1311
1312# Print checks for names that might be defined but that conflict with
1313# MPI
1314sub printDefineChecks {
1315    # Add a test for definitions that will cause problems
1316    # Unfortunately, #warning isn't part of standard C, so we can't use
1317    # it. 
1318    print $OUTFD "#ifdef MPI
1319#error \"You cannot define MPI; that name is reserved for the MPI namespace\"
1320#endif\n";
1321    if ($oldSeek) {
1322        # Let the user define MPICH_IGNORE_CXX_SEEK to both
1323        # suppress the check for SEEK_SET etc. and to suppress the definition
1324        # of the values.
1325        print $OUTFD "
1326// There is a name conflict between stdio.h and iostream (or iostream.h)
1327// and the MPI C++ binding
1328// with respect to the names SEEK_SET, SEEK_CUR, and SEEK_END.  MPI
1329// wants these in the MPI namespace, but stdio.h will #define these
1330// to integer values.  #undef'ing these can cause obscure problems
1331// with other include files (such as iostream), so we instead use
1332// #error to indicate a fatal error.  Users can either #undef
1333// the names before including mpi.h or include mpi.h *before* stdio.h
1334// or iostream. 
1335\n";
1336        print $OUTFD "#ifndef MPICH_IGNORE_CXX_SEEK
1337#ifdef SEEK_SET
1338#error \"SEEK_SET is #defined but must not be for the C++ binding of MPI\"
1339//#undef SEEK_SET
1340#endif
1341#ifdef SEEK_CUR
1342#error \"SEEK_CUR is #defined but must not be for the C++ binding of MPI\"
1343//#undef SEEK_CUR
1344#endif
1345#ifdef SEEK_END
1346//#undef SEEK_END
1347#error \"SEEK_END is #defined but must not be for the C++ binding of MPI\"
1348#endif
1349#endif\n\n";
1350    }
1351
1352    # GCC changed the calling convention between 3.2.3 and 3.4.3 (!!!)
1353    # check for that
1354    print $OUTFD "
1355// Check for incompatible GCC versions
1356// GCC (specifically) g++ changed the calling convention
1357// between 3.2.3 and 3.4.3 (!!)  Normally such changes
1358// should only occur at major releases (e.g., version 3 to 4)
1359#ifdef __GNUC__
1360# if __GNUC__ >= \@GNUCXX_VERSION\@
1361#  if __GNUC_MINOR__ > 2 && \@GNUCXX_MINORVERSION\@ == 2
1362#  error 'Please use the same version of GCC and g++ for compiling MPICH2 and user MPI programs'
1363#  endif
1364# endif     
1365#endif\n";
1366}
1367
1368# Use this after the MPI namespace is defined
1369sub PrintNewSeek {
1370    my $OUTFD = $_[0];
1371
1372    if (! $oldSeek) {
1373    print $OUTFD <<EOT;
1374// There is a name conflict between stdio.h and iostream (or iostream.h)
1375// and the MPI C++ binding with respect to the names SEEK_SET, SEEK_CUR, 
1376// and SEEK_END.  MPI wants these in the MPI namespace, but stdio.h, 
1377// iostream, or iostream.h will #define these to integer values. 
1378// #undef'ing these can cause obscure problems. 
1379#ifndef MPICH_IGNORE_CXX_SEEK
1380
1381// MPICH_DONT_INCLUDE_STDIO_H is another escape hatch for us, just like
1382// MPICH_IGNORE_CXX_SEEK.  If we encounter a wacky environment or user in the
1383// wild that does not want our workaround and/or the stdio.h header, then we can
1384// offer them a way out.
1385#ifndef MPICH_DONT_INCLUDE_STDIO_H
1386// ensure that we have SEEK_* defined
1387# include <stdio.h>
1388#endif
1389
1390enum MPIR_Dummy_seek_type {
1391    MPIR_DUMMY_SEEK_COMMA_VAL = -1  // permits cleaner comma logic
1392#ifdef SEEK_SET
1393    , MPIR_SEEK_SET = SEEK_SET
1394#   undef SEEK_SET
1395    , SEEK_SET = MPIR_SEEK_SET
1396#endif
1397#ifdef SEEK_CUR
1398    , MPIR_SEEK_CUR = SEEK_CUR
1399#   undef SEEK_CUR
1400    , SEEK_CUR = MPIR_SEEK_CUR
1401#endif
1402#ifdef SEEK_END
1403    , MPIR_SEEK_END = SEEK_END
1404#   undef SEEK_END
1405    , SEEK_END = MPIR_SEEK_END
1406#endif
1407#ifdef LOCK_SHARED
1408    , MPIR_LOCK_SHARED = LOCK_SHARED
1409#   undef LOCK_SHARED
1410    , LOCK_SHARED = MPIR_LOCK_SHARED
1411#endif
1412};
1413
1414#endif // MPICH_IGNORE_CXX_SEEK
1415EOT
1416    }
1417}
1418
1419# Print the arguments for the routine DEFINITION.
1420# TODO : Remove any output parameters.  This is stored in info by position
1421# if an integer or type (if a string).  If 0, there is no return object
1422sub print_args { 
1423    my $OUTFD = $_[0];
1424    my @parms = split(/\s*,\s*/, $_[1] );  # the original parameter list
1425    my $class_type = $_[2];                # Is this a Comm, Info, or othe
1426                                           # class?  Use to find the position
1427                                           # of the "this" entry in the C
1428                                           # version of the routine.
1429    my $arginfo = $_[3];                   # Value of <class>_hash{routine)}
1430
1431    my $count = 1;
1432    my $last_args = "";
1433    $first = 1;
1434    my $args_printed = 0;
1435    my $is_static = 0;           # set to true if function is static
1436
1437    &debugPrint( $routine, "In print_args" );
1438    my $special_args = "::";
1439    if (defined($arginfo)) {
1440        if ($arginfo =~ /^static:/) {
1441            $arginfo =~ s/^static://;
1442            $is_static = 1;
1443        }
1444        if ($arginfo =~ /(^[^:]+):(.*)/) {
1445            $returnarg = $1;
1446            $special_args = ":".$2.":";  # makes the numbers :\d+:...
1447            &debugPrint( $routine, "Routine $routine special args $special_args" );
1448        }
1449    }
1450
1451    # Special case: if the only parm is "void", remove it from the list
1452    print STDERR "Nparms = $#parms, parms = " . join(',',@parms) . "\n" if $gDebug;
1453    if ($#parms == 0 && $parms[0] eq "void") {
1454        &debugPrint( $routine, "Setting nparms to -1" );
1455        $#parms = -1;
1456    }
1457    # class_pos is the position of the class variable in the argument list.
1458    # If specified by parm type, we must find it
1459    $class_pos = -1;
1460    if ($class_pos == -1 && defined($class_type) && $class_type ne "" && 
1461        !$is_static) {
1462        &debugPrint( $routine, "Looking for class $class_type" );
1463        $class_pos = 0;
1464        $pos = 1;
1465        foreach $parm (@parms) {
1466            if ($parm =~ /$class_type/) {
1467                # Found the type; set the position of the class variable
1468                $class_pos = $pos;
1469                last;
1470            }
1471            $pos++;
1472        }
1473    }
1474
1475    # Output the list
1476    print $OUTFD "( ";
1477    foreach $parm (@parms) {
1478        $pos_check = ":" . $count . ":";
1479        print "parm = :$parm:\n" if $gDebug;
1480
1481        # Check whether this argument has special processing
1482        # Otherwise, apply standardized rules (currently, this
1483        # is used only to prepend a qualifier, such as "const").
1484        if ($special_args =~ /$pos_check/) {
1485            if (&DoSpecialArgProcessing( $OUTFD, $routine, $count, 
1486                                         "methoddecl" ) ) {
1487                $args_printed ++;
1488                $count++;
1489                if ($first) { $first = 0; }
1490                next;
1491            }
1492        }
1493        # Match type to replacement
1494        if ($count == $class_pos || $count == $return_parm_pos) {
1495            &debugPrint( $routine, "Skipping parm $parm because of position or return" );
1496            # Skip this arg in the definition
1497            ;
1498        }
1499        else {
1500            $args_printed ++;
1501            if ($first) { $first = 0; }
1502            else { print $OUTFD ", "; }
1503           
1504            if ($parm =~/\[/) {
1505                # Argument type is array, so we need to
1506                #  a) place parameter correctly
1507                # Split into raw type and []
1508                # Handle multidim arrays as well (Range_excl/incl)
1509                # Use \S* instead of the equivalent [^\s]*.
1510                # See ../f77/buildiface for an explanation
1511                $foundbrack = ""; # We actually ignore foundbrack
1512                if ($parm =~ /\s*(\S*)\s*(\[\s*\])(.*)/) {
1513                    $basetype = $1;
1514                    $foundbrack = $2;
1515                    $extrabracks = $3;
1516                    $otherdims = "";
1517                }
1518                else {
1519                    print STDERR "Internal error.  Could not find basetype\n";
1520                    print STDERR "This may be a bug in perl in the handling of certain expressions\n";
1521                }
1522                if ($extrabracks =~ /(\[[\d\s]*\])/) {
1523                    $otherdims = $1;
1524                }
1525                print $OUTFD "$basetype v$count\[\]$otherdims";
1526            }
1527            elsif ($parm =~ /\.\.\./) {
1528                # Special case for varargs.  Only ints!
1529                print $OUTFD $parm;
1530            }
1531            else {
1532                # Convert C to C++ types
1533                $cxxtype = $parm;
1534                if ($cxxtype =~ /MPI_/) {
1535                    $cxxtype =~ s/\*/\&/;
1536                }
1537                $cxxtype =~ s/MPI_//;
1538                print $OUTFD "${cxxtype} v$count";
1539            }
1540        }
1541        $count++;
1542    }
1543    if ($args_printed == 0) { print $OUTFD "void"; }
1544    print $OUTFD " )";
1545}
1546
1547# Count the number of parameters.  Don't count MPI_xxx_IGNORE
1548sub GetArgCount {
1549    my $args = $_[0];
1550    # First, remove any special chars
1551    $args =~ s/,\s*%%\w*%%//g;
1552    my @parms = split(/\s*,\s*/,$args);
1553    return $#parms + 1;
1554}
1555
1556# Print the arguments for the routine CALL. 
1557# Handle the special arguments
1558sub print_call_args {
1559    my @parms = split(/\s*,\s*/, $_[1] );
1560    my $OUTFD = $_[0];
1561    my $class_type = $_[2];    # ??
1562    my $arginfo = $_[3];       # Value of <class>_hash{routine)}
1563    my $count = 1;
1564    $first = 1;
1565
1566    my $is_static = 0;
1567
1568    if ($arginfo =~ /^static:/) { $is_static = 1; }
1569
1570    print $OUTFD "( ";
1571
1572    # Special case: if the only parm is "void", remove it from the list
1573    if ($#parms == 0 && $parms[0] eq "void") {
1574        $#parms = -1;
1575    }
1576
1577    # class_pos is the position of the class variable in the argument list.
1578    # If specified by parm type, we must find it
1579    $class_pos = "";
1580    if ($class_pos eq "" && !$is_static) {
1581        $class_pos = 1;
1582        foreach $parm (@parms) {
1583            if ($parm =~ /$class_type/) {
1584                last;
1585            }
1586            $class_pos++;
1587        }
1588    }
1589
1590    my $lcclass = lc($fullclassname{$class});
1591    my $shortclass = $class; # ??? FIXME
1592    my $lctopclass = $lcclass;
1593    # For derived classes, we sometimes need to know the name of the
1594    # top-most class, particularly for the "the_real_xxx" name.
1595    if (defined($mytopclass{$lcclass})) {
1596        $lctopclass = $mytopclass{$lcclass};
1597    }
1598    print "$routine-$count\n" if $gDebug;
1599    foreach $parm (@parms) {
1600        if (!$first) { print $OUTFD ", "; } else { $first = 0; }
1601
1602        # Special handling must preempt any other handling
1603        if (defined($funcArgMap{"${routine}-$count"}) ||
1604            defined($funcArgMap{"${class}-${routine}-${count}"})) {
1605            &DoSpecialArgProcessing( $OUTFD, $routine, $count, "call" );
1606        }
1607        elsif ($count == $return_parm_pos) {
1608            # We may need to pass the address of a temporary object
1609            # We'll unilateraly assume this for now
1610            # This must be first, so that it has a priority over the
1611            # class pos location.
1612            if ($parm =~ /MPI_/ && !($parm =~ /MPI_Offset/) &&
1613                !($parm =~ /MPI_Aint/) ) {
1614                my $lctype = $real_return_type;
1615                # Convert class_type to the appropriate name
1616                $lctype = lc($lctype);
1617                if (defined($mytopclass{$lctype})) {
1618                    $lctype = $mytopclass{$lctype};
1619                }
1620                # Handle the MPIO_Request problem (temp until ROMIO uses
1621                # MPI_Requests)
1622                $cast = "";
1623                if ($parm =~ /MPI_Request/ &&
1624                    $class eq "file") {
1625                    $cast = "(MPIO_Request *)";
1626                }
1627                print $OUTFD "$cast&(v$count.the_real_$lctype)";
1628            }
1629            else {
1630                print $OUTFD "&v$count";
1631            }
1632        }
1633        elsif ($count == $class_pos) {
1634            # Skip this arg in the definition
1635            if ($parm =~ /\*/) {
1636                print $OUTFD "($parm) &the_real_$lctopclass";
1637            }
1638            else {
1639                print $OUTFD "($parm) the_real_$lctopclass";
1640            }
1641        }
1642        elsif ($parm =~ /%%(.*)%%/) {
1643            print $OUTFD "$1";
1644        }
1645        else {
1646            # Convert to/from object type as required. 
1647            if (defined($argsneedcast{$parm})) {
1648                $argval = "v$count";
1649                $callparm = $argsneedcast{$parm};
1650                $callparm =~ s/ARG/$argval/;
1651               
1652                print $OUTFD &HandleObjectParm( $parm, $argval );
1653            }
1654            else {
1655                print $OUTFD &HandleObjectParm( $parm, "v$count" );
1656            }
1657        }
1658        $count++;
1659    }
1660    print $OUTFD " )";
1661}
1662
1663# Print the option function attribute; this supports GCC, particularly
1664# the __atribute__ weak option.
1665sub print_attr {
1666#    if ($do_weak) {
1667#       print $OUTFD "FUNC_ATTRIBUTES\n";
1668#    }
1669}
1670
1671#
1672# Look through $args for parameter names (foo\s\s*name)
1673# and remove them
1674sub clean_args {
1675    my $newargs = "";
1676    my $comma = "";
1677    for $parm (split(',',$args)) {
1678        # Remove any leading or trailing spaces
1679        $parm =~ s/^\s*//;
1680        $parm =~ s/\s*$//;
1681        # Handle parameters with parameter names
1682        # First if handles "int foo", second handles "int *foo"
1683        if ( ($parm =~ /^([A-Za-z0-9_]+)\s+[A-Za-z0-9_]+$/) ) {
1684            $parm = $1;
1685        }
1686        elsif ( ($parm =~ /^([A-Za-z0-9_]+\s*\*)\s*[A-Za-z0-9_]+$/) ) {
1687            $parm = $1;
1688        }
1689        $newargs .= "$comma$parm";
1690        $comma = ",";
1691    }
1692    print STDERR "$newargs\n" if $gDebug;
1693    $args = $newargs;
1694}
1695
1696# Print out the constants.
1697# PrintConstants( FD, giveValue )
1698# if GiveValue is true, defint the value, otherwise, make it external
1699sub PrintConstants {   
1700    my ($OUTFD, $giveValue) = @_;
1701    my $extern = "extern ";
1702    if ($giveValue) { $extern = ""; }
1703
1704    # Initialize the datatypes.
1705    # We do not use MPI:: within the MPI namespace
1706    foreach $dtype (@dtypes) {
1707        print $OUTFD "${extern}Datatype $dtype";
1708        if ($giveValue) { print $OUTFD "(MPI_$dtype);\n"; }
1709        else            { print $OUTFD ";\n"; }
1710    }
1711    # special case
1712    if ($giveValue) {
1713        print $OUTFD "Datatype TWOINT(MPI_2INT);\n";
1714    }
1715    else {
1716        print $OUTFD "extern Datatype TWOINT;\n";
1717    }
1718    # Add the C++ only types (e.g., BOOL, COMPLEX).  These have no
1719    # C counterpart; their MPI Datatype handles are determined by the
1720    # configure step and inserted into mpicxx.h as #define's
1721    foreach $dtype (@cppdtypes) {
1722        print $OUTFD "${extern}Datatype $dtype";
1723        if ($giveValue) { print $OUTFD "(MPIR_CXX_$dtype);\n"; }
1724        else { 
1725            print $OUTFD ";\n"; 
1726            print $OUTFD "#define MPIR_CXX_$dtype \@MPIR_CXX_${dtype}\@\n";
1727        }
1728    }
1729
1730    print $OUTFD "${extern}Datatype DATATYPE_NULL;\n";
1731
1732    # Fortran types
1733    if ($giveValue) {
1734        print $OUTFD "
1735#ifdef HAVE_FORTRAN_BINDING
1736Datatype INTEGER(MPI_INTEGER);
1737Datatype REAL(MPI_REAL);
1738Datatype DOUBLE_PRECISION(MPI_DOUBLE_PRECISION);
1739Datatype F_COMPLEX(MPI_COMPLEX);
1740Datatype F_DOUBLE_COMPLEX(MPI_DOUBLE_COMPLEX);
1741Datatype LOGICAL(MPI_LOGICAL);
1742Datatype CHARACTER(MPI_CHARACTER);
1743Datatype TWOREAL(MPI_2REAL);
1744Datatype TWODOUBLE_PRECISION(MPI_2DOUBLE_PRECISION);
1745Datatype TWOINTEGER(MPI_2INTEGER);
1746#endif\n";
1747    }
1748    else {
1749        # This is for the mpicxx.h.in file, so instead of assuming that
1750        # we have mpichconf.h (which we do not, so as to keep the user's
1751        # CPP name space clean), we directly set this value
1752        print $OUTFD "
1753#if \@FORTRAN_BINDING\@
1754extern Datatype INTEGER;
1755extern Datatype REAL;
1756extern Datatype DOUBLE_PRECISION;
1757extern Datatype F_COMPLEX;
1758extern Datatype F_DOUBLE_COMPLEX;
1759extern Datatype LOGICAL;
1760extern Datatype CHARACTER;
1761extern Datatype TWOREAL;
1762extern Datatype TWODOUBLE_PRECISION;
1763extern Datatype TWOINTEGER;
1764#endif\n";
1765    }
1766    # Still to do: Fortran optional types, integer1,2,4, real2,4,8,
1767
1768    # Initialize the operations
1769    foreach $op (@ops) {
1770        print $OUTFD "${extern}const Op $op";
1771        if ($giveValue) { print $OUTFD "(MPI_$op);\n"; }
1772        else            { print $OUTFD ";\n"; }
1773    }
1774    print $OUTFD "${extern}const Op OP_NULL;\n";
1775
1776    # Predefined communicators and groups
1777    if ($giveValue) {
1778        print $OUTFD "Intracomm COMM_WORLD(MPI_COMM_WORLD);\n";
1779        print $OUTFD "Intracomm COMM_SELF(MPI_COMM_SELF);\n";
1780        print $OUTFD "const Group GROUP_EMPTY(MPI_GROUP_EMPTY);\n";
1781    } 
1782    else {
1783        print $OUTFD "extern Intracomm COMM_WORLD;\n";
1784        print $OUTFD "extern Intracomm COMM_SELF;\n";
1785        print $OUTFD "extern const Group GROUP_EMPTY;\n";
1786    }
1787    # COMM_NULL can't be a Comm since Comm is an abstract base class.
1788    # Following the model of Intracomm etc., we make this a separate class,
1789    # and a peer to the other communicator classes.
1790    print $OUTFD "${extern}const Nullcomm COMM_NULL;\n";
1791    print $OUTFD "${extern}const Group GROUP_NULL;\n"; 
1792
1793    # Predefined requests
1794    print $OUTFD "${extern}const Request REQUEST_NULL;\n";
1795
1796    # Predefined errhandlers
1797    print $OUTFD "${extern}const Errhandler ERRHANDLER_NULL;\n";
1798    if ($giveValue) {
1799        print $OUTFD "const Errhandler ERRORS_RETURN(MPI_ERRORS_RETURN);\n";
1800        print $OUTFD "const Errhandler ERRORS_ARE_FATAL(MPI_ERRORS_ARE_FATAL);\n";
1801        # Errors_return is not quite right for errors-throw-exceptions,
1802        # but it is close.
1803        print $OUTFD "const Errhandler ERRORS_THROW_EXCEPTIONS(MPIR_ERRORS_THROW_EXCEPTIONS);\n";
1804    }
1805    else {
1806        print $OUTFD "extern const Errhandler ERRORS_RETURN;\n";
1807        print $OUTFD "extern const Errhandler ERRORS_ARE_FATAL;\n";
1808        print $OUTFD "extern const Errhandler ERRORS_THROW_EXCEPTIONS;\n";
1809    }
1810
1811    # Predefined info
1812    print $OUTFD "${extern}const Info INFO_NULL;\n";
1813
1814    # Predefined File and Win
1815    print $OUTFD "${extern}const Win WIN_NULL;\n";
1816    # Note that FILE_NULL cannot be const because you can set the
1817    # error handler on it.
1818    print $OUTFD "${extern} File FILE_NULL;\n";
1819
1820    # Predefined integers
1821    foreach $int (BSEND_OVERHEAD, KEYVAL_INVALID, CART, GRAPH,
1822                  IDENT, SIMILAR, CONGRUENT, UNEQUAL, PROC_NULL,
1823                  ANY_TAG, ANY_SOURCE, ROOT, TAG_UB, IO, HOST, WTIME_IS_GLOBAL,
1824                  UNIVERSE_SIZE, LASTUSEDCODE, APPNUM, 
1825                  MAX_PROCESSOR_NAME, MAX_ERROR_STRING,
1826                  MAX_PORT_NAME, MAX_OBJECT_NAME,
1827                  MAX_INFO_VAL, MAX_INFO_KEY, 
1828                  UNDEFINED, LOCK_EXCLUSIVE, LOCK_SHARED, 
1829                  WIN_BASE, WIN_DISP_UNIT, WIN_SIZE, 
1830                  @errclasses, @typeclasses ) {
1831        print $OUTFD "${extern}const int $int";
1832        if ($giveValue) { print $OUTFD "= MPI_$int;\n"; }
1833        else            { print $OUTFD ";\n"; }
1834    }
1835    # Handle seek as a special case
1836    print $OUTFD "#if defined(MPI_SEEK_SET) && !defined(MPICH_IGNORE_CXX_SEEK) && !defined(SEEK_SET)\n";
1837    foreach $int (SEEK_SET, SEEK_END, SEEK_CUR) {
1838        print $OUTFD "${extern}const int $int";
1839        if ($giveValue) { print $OUTFD " = MPI_$int;\n"; }
1840        else            { print $OUTFD ";\n"; }
1841    }
1842    print $OUTFD "#endif\n";
1843
1844    foreach $int (DISTRIBUTE_BLOCK, DISTRIBUTE_CYCLIC,
1845                  DISTRIBUTE_DFLT_DARG, DISTRIBUTE_NONE, ORDER_C, 
1846                  ORDER_FORTRAN) {
1847        print $OUTFD "${extern}const int $int";
1848        if ($giveValue) { print $OUTFD " = MPI_$int;\n"; }
1849        else            { print $OUTFD ";\n"; }
1850    }
1851
1852    print $OUTFD "// Include these only if MPI-IO is available\n";
1853    print $OUTFD "#ifdef MPI_MODE_RDONLY\n";
1854
1855    # Other file constants
1856    foreach $int (MAX_DATAREP_STRING) {
1857        print $OUTFD "${extern}const int $int";
1858        if ($giveValue) { print $OUTFD " = MPI_$int;\n"; }
1859        else            { print $OUTFD ";\n"; }
1860    }
1861    foreach $int (DISPLACEMENT_CURRENT) {
1862        print $OUTFD "${extern}const MPI_Offset $int";
1863        if ($giveValue) { print $OUTFD " = MPI_$int;\n"; }
1864        else            { print $OUTFD ";\n"; }
1865    }
1866
1867    # MPI Mode
1868    foreach $int (APPEND, CREATE, DELETE_ON_CLOSE, EXCL, 
1869                  RDONLY, RDWR, SEQUENTIAL, UNIQUE_OPEN, WRONLY) {
1870        print $OUTFD "${extern}const int MODE_$int";
1871        if ($giveValue) { print $OUTFD " = MPI_MODE_$int;\n"; }
1872        else            { print $OUTFD ";\n"; }
1873    }
1874    print $OUTFD "#endif // IO\n";
1875    # Some modes are for RMA, not I/O
1876    foreach $int (NOCHECK,NOPRECEDE, NOPUT, NOSTORE, NOSUCCEED) {
1877        print $OUTFD "${extern}const int MODE_$int";
1878        if ($giveValue) { print $OUTFD " = MPI_MODE_$int;\n"; }
1879        else            { print $OUTFD ";\n"; }
1880    }
1881
1882    # MPI Combiners
1883    foreach $int (CONTIGUOUS, DARRAY, DUP, F90_COMPLEX, F90_INTEGER, 
1884                  F90_REAL, HINDEXED_INTEGER, HINDEXED, HVECTOR_INTEGER,
1885                  HVECTOR, INDEXED_BLOCK, INDEXED, NAMED, RESIZED, 
1886                  STRUCT_INTEGER, STRUCT, SUBARRAY, VECTOR) {
1887        print $OUTFD "${extern}const int COMBINER_$int";
1888        if ($giveValue) { print $OUTFD " = MPI_COMBINER_$int;\n"; }
1889        else            { print $OUTFD ";\n"; }
1890    }
1891    # MPI Thread levels
1892    foreach $int (FUNNELED, MULTIPLE, SERIALIZED, SINGLE) {
1893        print $OUTFD "${extern}const int THREAD_$int";
1894        if ($giveValue) { print $OUTFD " = MPI_THREAD_$int;\n"; }
1895        else            { print $OUTFD ";\n"; }
1896    }
1897    # MPI Empty argvs
1898    if ($giveValue) {
1899        print $OUTFD "const char ** const ARGV_NULL = 0;\n";
1900        print $OUTFD "const char *** const ARGVS_NULL = 0;\n";
1901    }
1902    else {
1903        print $OUTFD "extern const char ** const ARGV_NULL;\n";
1904        print $OUTFD "extern const char *** const ARGVS_NULL;\n";
1905    }
1906
1907    # Predefined other
1908    if ($giveValue) {
1909        print $OUTFD "void * const BOTTOM = MPI_BOTTOM;\n";
1910        print $OUTFD "void * const IN_PLACE = MPI_IN_PLACE;\n";
1911    }
1912    else {
1913        print $OUTFD "extern void * const BOTTOM;\n";
1914        print $OUTFD "extern void * const IN_PLACE;\n";
1915    }
1916}
1917
1918#
1919# Build the special routines
1920sub build_specials {
1921    # The init routine contains some configure-time values.
1922    my $filename = "initcxx.cxx";
1923    open( $OUTFD, ">${filename}.new" ) || die "Cannot open ${filename}.new\n";
1924    $files[$#files+1] = "initcxx.cxx";
1925    &print_header;
1926    print $OUTFD "#include \"mpi.h\"\n";
1927    print $OUTFD "#include <stdarg.h>\n";    # Required for pcontrol
1928    print $OUTFD "#include \"mpichconf.h\"\n"; # Requires for HAVE_FORTRAN_BINDING
1929
1930    # The coverage header is included in mpicxx.h.in
1931    #&printCoverageHeader( $OUTFD, 0 );
1932
1933    print $OUTFD "
1934// #define MPIX_TRACE_MEMORY
1935#ifdef MPIX_TRACE_MEMORY
1936int _mpi_lineno = __LINE__;
1937// We need stdlib.h for size_t.  But that can cause problems if the
1938// header isn't C++ clean.  Instead, we just include a definition
1939// for size_t.  If this is not the correct size, then edit this line
1940// (Note that this is needed only when memory tracing is enabled)
1941typedef unsigned int size_t;
1942extern \"C\" void *MPIU_trmalloc( unsigned int, int, const char [] );
1943extern \"C\" void MPIU_trfree( void *, int, const char [] );
1944extern \"C\" void MPIU_trdump( void *, int );
1945void *operator new(size_t size) {
1946    void *p = MPIU_trmalloc( (unsigned int) size, _mpi_lineno, __FILE__ );
1947    return p;}
1948void operator delete(void *p) {
1949    MPIU_trfree( p, _mpi_lineno, __FILE__ );}
1950void *operator new[]( size_t size) {
1951    void *p = MPIU_trmalloc( (unsigned int) size, _mpi_lineno, __FILE__ );
1952    return p;}
1953void operator delete[](void *p) {
1954    MPIU_trfree( p, _mpi_lineno, __FILE__ );}
1955#define MPIX_TRSummary() MPIU_trdump( 0, -1 )
1956#define MPIX_SetLineno _mpi_lineno = __LINE__ + 1
1957#else
1958#define MPIX_TRSummary()
1959#define MPIX_SetLineno
1960#endif\n";
1961
1962    # Start the namespace
1963    print $OUTFD "namespace MPI {\n";
1964
1965    &PrintConstants( $OUTFD, 1 );
1966
1967    print $OUTFD "void Init";
1968    $args = "";
1969    &print_args( $OUTFD, $args );
1970    &print_attr;
1971    print $OUTFD "{\n";
1972    print $OUTFD "    MPI_Init( 0, 0 );\n";
1973    &printCoverageInitialize( $OUTFD );
1974    print $OUTFD "}\n";
1975
1976    #
1977    # The following may not be quite right because they don't include
1978    # any attributes that we may include with the definitions.  However,
1979    # this is easier than forcing the print_args routine to handle these
1980    # simple cases.
1981    #
1982    print $OUTFD "void Init( int &argc, char **&argv )
1983{
1984    MPI_Init( &argc, &argv );\n";
1985    &printCoverageInitialize( $OUTFD );
1986    print $OUTFD "}\n";
1987
1988    print $OUTFD "int Init_thread";
1989    $routine = "Init_thread"; # So we'll know for debugging
1990    # The two args are needed to tell print_args that one is the output
1991    $return_parm_pos = 2;
1992    #$args = "int,int";
1993    # Grr.  Under Cygwin, we needed two...
1994    $args = "int";
1995    &print_args( $OUTFD, $args );
1996    &print_attr;
1997    print $OUTFD "{
1998    int provided;
1999    MPI_Init_thread( 0, 0, v1, &provided );\n";
2000    &printCoverageInitialize( $OUTFD );
2001    print $OUTFD "\
2002    return provided;
2003}\n";
2004    #
2005    # The following may not be quite right because they don't include
2006    # any attributes that we may include with the definitions.  However,
2007    # this is easier than forcing the print_args routine to handle these
2008    # simple cases.
2009    #
2010    print $OUTFD "int Init_thread( int &argc, char **&argv, int req )
2011{
2012    int provided;
2013    MPI_Init_thread( &argc, &argv, req, &provided );\n";
2014
2015    &printCoverageInitialize( $OUTFD );
2016    print $OUTFD "    return provided;\n}\n";
2017
2018    print $OUTFD "void Finalize"; 
2019    $args = "";
2020    &print_args( $OUTFD, $args );
2021    &print_attr;
2022    print $OUTFD "{\n";
2023    &printCoverageFinalize( $OUTFD );
2024    print $OUTFD "    MPIX_TRSummary();\n";
2025    print $OUTFD "    MPI_Finalize( );\n";
2026    print $OUTFD "}\n";
2027
2028    print $OUTFD "bool Is_initialized(void)
2029    {
2030        int flag;\n";
2031     &printCoverageStart( $OUTFD, "Initialized", 0 );
2032    print $OUTFD "\
2033        MPI_Initialized( &flag );\n";
2034     &printCoverageEnd( $OUTFD, "Initialized", 0 );
2035    # Microsoft C++ compiler complains about using an explicit cast to bool (!)
2036    print $OUTFD "\
2037        return (flag != 0);
2038    }\n";
2039
2040    print $OUTFD "void Compute_dims( int nnodes, int ndims, int dims[] )
2041    {\n";
2042    &printCoverageStart( $OUTFD, "Dims_create", 3 );
2043    print $OUTFD "\
2044        MPIX_CALL( MPI_Dims_create( nnodes, ndims, dims ) );\n";
2045    &printCoverageEnd( $OUTFD, "Dims_create", 3 );
2046    print $OUTFD "\
2047    }\n";
2048
2049    print $OUTFD "void Attach_buffer( void *buffer, int size )
2050    {\n";
2051    &printCoverageStart( $OUTFD, "Buffer_attach", 2 );
2052    print $OUTFD "\
2053        MPIX_CALL( MPI_Buffer_attach( buffer, size ) );\n";
2054    &printCoverageEnd( $OUTFD, "Buffer_attach", 2 );
2055    print $OUTFD "\
2056    }\n";
2057
2058    print $OUTFD "int Detach_buffer( void *&buffer )
2059    {
2060        int size;\n";
2061    &printCoverageStart( $OUTFD, "Buffer_detach", 2 );
2062    print $OUTFD "\
2063        MPIX_CALL( MPI_Buffer_detach( &buffer, &size ) );\n";
2064    &printCoverageEnd( $OUTFD, "Buffer_detach", 2 );
2065    print $OUTFD "\
2066        return size;
2067    }\n";
2068
2069    print $OUTFD "void Get_processor_name( char *name, int &resultlen )
2070    {\n";
2071    &printCoverageStart( $OUTFD, "Get_processor_name", 2 );
2072    print $OUTFD "\
2073    MPIX_CALL( MPI_Get_processor_name( name, &resultlen ) );\n";
2074    &printCoverageEnd( $OUTFD, "Get_processor_name", 2 );
2075    print $OUTFD "\
2076    }\n";
2077
2078    # The MPI-2 specification specifies Pcontrol as taking const int,
2079    # not just int, and some C++ compilers will (correctly) require this
2080    print $OUTFD "void Pcontrol( const int v, ... )
2081    {
2082        va_list ap;
2083        va_start(ap,v);\n";
2084     &printCoverageStart( $OUTFD, "Pcontrol", -1 );
2085    print $OUTFD "\
2086        MPIX_CALL( MPI_Pcontrol( (int)v, ap ) );\n";
2087     &printCoverageEnd( $OUTFD, "Pcontrol", -1 );
2088    print $OUTFD "\
2089    }\n";
2090
2091    print $OUTFD "int Get_error_class( int errcode )
2092    {
2093    int errclass;\n";
2094     &printCoverageStart( $OUTFD, "Error_class", 1 );
2095    print $OUTFD "\
2096    MPIX_CALL( MPI_Error_class( errcode, &errclass ) );\n";
2097     &printCoverageEnd( $OUTFD, "Error_class", 1 );
2098     print $OUTFD "\
2099    return errclass;
2100    }\n";
2101
2102    print $OUTFD "void Get_error_string( int errcode, char *name, int &resultlen )
2103    {\n";
2104     &printCoverageStart( $OUTFD, "Error_string", 3 );
2105     print $OUTFD "\
2106    MPIX_CALL( MPI_Error_string( errcode, name, &resultlen ) );\n";
2107     &printCoverageEnd( $OUTFD, "Error_string", 3 );
2108     print $OUTFD "\
2109    }\n";
2110
2111    print $OUTFD "Aint Get_address( void *ptr )
2112    {
2113    MPI_Aint a;\n";
2114     &printCoverageStart( $OUTFD, "Get_address", 2 );
2115     print $OUTFD "\
2116    MPI_Get_address( ptr, &a );\n";
2117     &printCoverageEnd( $OUTFD, "Get_address", 2 );
2118     print $OUTFD "\
2119    return (Aint)a;
2120    }\n";
2121
2122   
2123    print $OUTFD "void *Alloc_mem( Aint size, const Info &info )
2124    {
2125        void *result;\n";
2126     &printCoverageStart( $OUTFD, "Alloc_mem", 2 );
2127     print $OUTFD "\
2128        MPIX_CALL( MPI_Alloc_mem( size, (MPI_Info)info, &result ) );\n";
2129     &printCoverageEnd( $OUTFD, "Alloc_mem", 2 );
2130     print $OUTFD "\
2131        return result;
2132    }\n";
2133
2134    print $OUTFD "void Free_mem( void * base )
2135    {\n";
2136     &printCoverageStart( $OUTFD, "Free_mem", 1 );
2137     print $OUTFD "\
2138     MPIX_CALL( MPI_Free_mem( base ) );\n";
2139     &printCoverageEnd( $OUTFD, "Free_mem", 1 );
2140     print $OUTFD "\
2141    }\n";
2142
2143    # Init is a difficult function because we must allow C to call a
2144    # C++ function.  We do this by getting help from the MPI implementation
2145    # which invokes the MPIR_Call_op_fn routine, with a pointer to the
2146    # C++ routine to invoke.
2147    #
2148    # Note: Some compilers complain about the cast to the
2149    # (void (*)(void)) function, expecting an `extern "C"' as well, but
2150    # other compilers do not accept the extern "C".  Sigh.
2151    print $OUTFD "
2152    extern \"C\" {
2153typedef void (*mpircallback)(void);
2154}
2155extern \"C\" void MPIR_Op_set_cxx( MPI_Op, void (*)(void) );
2156extern \"C\"
2157void MPIR_Call_op_fn( void *invec, void *outvec, int len, MPI_Datatype dtype,
2158                     User_function *uop )
2159{
2160    MPI::Datatype cxxdtype = dtype;
2161    (*uop)( invec, outvec, len, cxxdtype );
2162}
2163void Op::Init( User_function *f, bool commute )
2164    {\n";
2165&printCoverageStart( $OUTFD, "Op_create", 2 );
2166     print $OUTFD "\
2167        MPIX_CALL( MPI_Op_create( (MPI_User_function *)f,
2168                                 (int) commute, &the_real_op ) );
2169        MPIR_Op_set_cxx( the_real_op, (mpircallback) MPIR_Call_op_fn );\n";
2170&printCoverageEnd( $OUTFD, "Op_create", 2 );
2171print $OUTFD "\
2172    }\n";
2173
2174    # Keyval and attribute routines
2175    print $OUTFD "
2176#include \"mpihandlemem.h\"
2177#include \"mpi_attr.h\"
2178#include \"mpi_lang.h\"
2179static
2180int
2181MPIR_Comm_delete_attr_cxx_proxy(
2182    MPI_Comm_delete_attr_function* user_function,
2183    MPI_Comm comm,
2184    int keyval,
2185    MPIR_AttrType attrib_type,
2186    void* attrib,
2187    void* extra_state
2188    )
2189{
2190    void *value = NULL;
2191    /* Make sure that the attribute value is delivered as a pointer */
2192    if(MPIR_ATTR_KIND(attrib_type) == MPIR_ATTR_KIND(MPIR_ATTR_INT)){
2193        value = &attrib;
2194    }
2195    else{
2196        value = attrib;
2197    }
2198    MPI::Comm::Delete_attr_function* f = (MPI::Comm::Delete_attr_function*)user_function;
2199   
2200    int ttype;
2201    MPI_Topo_test( comm, &ttype );
2202    if (ttype == MPI_UNDEFINED)
2203    {
2204        MPI_Comm_test_inter( comm, &ttype );
2205        if (ttype)
2206        {
2207            MPI::Intercomm c = comm;
2208            return f( c, keyval, value, extra_state );
2209        }
2210        else
2211        {
2212            MPI::Intracomm c = comm;
2213            return f( c, keyval, value, extra_state );
2214        }
2215    }
2216    else if (ttype == MPI_CART)
2217    {
2218        MPI::Cartcomm c = comm;
2219        return f( c, keyval, value, extra_state );
2220    }
2221    else
2222    {
2223        MPI::Graphcomm c = comm;
2224        return f( c, keyval, value, extra_state );
2225    }
2226}
2227
2228static
2229int
2230MPIR_Comm_copy_attr_cxx_proxy(
2231    MPI_Comm_copy_attr_function* user_function,
2232    MPI_Comm comm,
2233    int keyval,
2234    void* extra_state,
2235    MPIR_AttrType attrib_type,
2236    void* attrib,
2237    void** new_value,
2238    int* flag
2239    )
2240{
2241    void *value = NULL;
2242    /* Make sure that the attribute value is delivered as a pointer */
2243    if(MPIR_ATTR_KIND(attrib_type) == MPIR_ATTR_KIND(MPIR_ATTR_INT)){
2244        value = &attrib;
2245    }
2246    else{
2247        value = attrib;
2248    }
2249
2250    *flag = 0;
2251    MPI::Comm::Copy_attr_function* f = (MPI::Comm::Copy_attr_function*)user_function;
2252   
2253    int ttype;
2254    MPI_Topo_test( comm, &ttype );
2255    if (ttype == MPI_UNDEFINED)
2256    {
2257        MPI_Comm_test_inter( comm, &ttype );
2258        if (ttype)
2259        {
2260            MPI::Intercomm c = comm;
2261            return f( c, keyval, extra_state, value, new_value, *(bool*)flag );
2262        }
2263        else
2264        {
2265            MPI::Intracomm c = comm;
2266            return f( c, keyval, extra_state, value, new_value, *(bool*)flag );
2267        }
2268    }
2269    else if (ttype == MPI_CART)
2270    {
2271        MPI::Cartcomm c = comm;
2272        return f( c, keyval, extra_state, value, new_value, *(bool*)flag );
2273    }
2274    else
2275    {
2276        MPI::Graphcomm c = comm;
2277        return f( c, keyval, extra_state, value, new_value, *(bool*)flag );
2278    }
2279}
2280
2281
2282int Comm::Create_keyval( Copy_attr_function *cf, Delete_attr_function *df, void *extra_state )
2283{
2284    int keyval;
2285
2286    if (cf == MPI::Comm::NULL_COPY_FN) cf = 0;
2287    if (df == MPI::Comm::NULL_DELETE_FN) df = 0;\n";
2288    &printCoverageStart( $OUTFD, "Comm_create_keyval", 3 );
2289    print $OUTFD "\
2290    MPIX_CALL( MPI_Comm_create_keyval( (MPI_Comm_copy_attr_function *)cf,
2291                                       (MPI_Comm_delete_attr_function *)df,
2292                                      &keyval, extra_state ) );
2293    MPIR_Keyval_set_proxy( keyval, MPIR_Comm_copy_attr_cxx_proxy, MPIR_Comm_delete_attr_cxx_proxy );\n";
2294    &printCoverageEnd( $OUTFD, "Comm_create_keyval", 3 );
2295    print $OUTFD "\
2296    return keyval;
2297}
2298
2299static
2300int
2301MPIR_Type_delete_attr_cxx_proxy(
2302    MPI_Type_delete_attr_function* user_function,
2303    MPI_Datatype datatype,
2304    int keyval,
2305    MPIR_AttrType attrib_type,
2306    void* attrib,
2307    void* extra_state
2308    )
2309{
2310    MPI::Datatype d = datatype;
2311    MPI::Datatype::Delete_attr_function* f = (MPI::Datatype::Delete_attr_function*)user_function;
2312    void *value = NULL;
2313    /* Make sure that the attribute value is delivered as a pointer */
2314    if(MPIR_ATTR_KIND(attrib_type) == MPIR_ATTR_KIND(MPIR_ATTR_INT)){
2315        value = &attrib;
2316    }
2317    else{
2318        value = attrib;
2319    }
2320    return f( d, keyval, value, extra_state );
2321}
2322
2323static
2324int
2325MPIR_Type_copy_attr_cxx_proxy(
2326    MPI_Type_copy_attr_function* user_function,
2327    MPI_Datatype datatype,
2328    int keyval,
2329    void* extra_state,
2330    MPIR_AttrType attrib_type,
2331    void* attrib,
2332    void** new_value,
2333    int* flag
2334    )
2335{
2336    *flag = 0;
2337    MPI::Datatype d = datatype;
2338    MPI::Datatype::Copy_attr_function* f = (MPI::Datatype::Copy_attr_function*)user_function;
2339    void *value = NULL;
2340    /* Make sure that the attribute value is delivered as a pointer */
2341    if(MPIR_ATTR_KIND(attrib_type) == MPIR_ATTR_KIND(MPIR_ATTR_INT)){
2342        value = &attrib;
2343    }
2344    else{
2345        value = attrib;
2346    }
2347    return f( d, keyval, extra_state, value, new_value, *(bool*)flag );
2348}
2349
2350int Datatype::Create_keyval( Copy_attr_function *cf, Delete_attr_function *df, void *extra_state )
2351{
2352    int keyval;
2353
2354    if (cf == MPI::Datatype::NULL_COPY_FN) cf = 0;
2355    if (df == MPI::Datatype::NULL_DELETE_FN) df = 0;\n";
2356    &printCoverageStart( $OUTFD, "Type_create_keyval", 3 );
2357    print $OUTFD "\
2358    MPIX_CALL( MPI_Type_create_keyval( (MPI_Type_copy_attr_function *)cf,
2359                                       (MPI_Type_delete_attr_function *)df,
2360                                      &keyval, extra_state ) );
2361    MPIR_Keyval_set_proxy( keyval, MPIR_Type_copy_attr_cxx_proxy, MPIR_Type_delete_attr_cxx_proxy );\n";
2362    &printCoverageEnd( $OUTFD, "Type_create_keyval", 3 );
2363    print $OUTFD "\
2364    return keyval;
2365}
2366
2367static
2368int
2369MPIR_Win_delete_attr_cxx_proxy(
2370    MPI_Win_delete_attr_function* user_function,
2371    MPI_Win win,
2372    int keyval,
2373    MPIR_AttrType attrib_type,
2374    void* attrib,
2375    void* extra_state
2376    )
2377{
2378    MPI::Win w = win;
2379    MPI::Win::Delete_attr_function* f = (MPI::Win::Delete_attr_function*)user_function;
2380    void *value = NULL;
2381    /* Make sure that the attribute value is delivered as a pointer */
2382    if(MPIR_ATTR_KIND(attrib_type) == MPIR_ATTR_KIND(MPIR_ATTR_INT)){
2383        value = &attrib;
2384    }
2385    else{
2386        value = attrib;
2387    }
2388    return f( w, keyval, value, extra_state );
2389}
2390
2391static
2392int
2393MPIR_Win_copy_attr_cxx_proxy(
2394    MPI_Win_copy_attr_function* user_function,
2395    MPI_Win win,
2396    int keyval,
2397    void* extra_state,
2398    MPIR_AttrType attrib_type,
2399    void* attrib,
2400    void** new_value,
2401    int* flag
2402    )
2403{
2404    *flag = 0;
2405    MPI::Win w = win;
2406    MPI::Win::Copy_attr_function* f = (MPI::Win::Copy_attr_function*)user_function;
2407    void *value = NULL;
2408    /* Make sure that the attribute value is delivered as a pointer */
2409    if(MPIR_ATTR_KIND(attrib_type) == MPIR_ATTR_KIND(MPIR_ATTR_INT)){
2410        value = &attrib;
2411    }
2412    else{
2413        value = attrib;
2414    }
2415    return f( w, keyval, extra_state, value, new_value, *(bool*)flag );
2416}
2417
2418int Win::Create_keyval( Copy_attr_function *cf, Delete_attr_function *df, void *extra_state )
2419{
2420    int keyval;
2421
2422    if (cf == MPI::Win::NULL_COPY_FN) cf = 0;
2423    if (df == MPI::Win::NULL_DELETE_FN) df = 0;\n";
2424    &printCoverageStart( $OUTFD, "Win_create_keyval", 3 );
2425    print $OUTFD "\
2426    MPIX_CALL( MPI_Win_create_keyval( (MPI_Win_copy_attr_function *)cf,
2427                                       (MPI_Win_delete_attr_function *)df,
2428                                      &keyval, extra_state ) );
2429    MPIR_Keyval_set_proxy( keyval, MPIR_Win_copy_attr_cxx_proxy, MPIR_Win_delete_attr_cxx_proxy );\n";
2430    &printCoverageEnd( $OUTFD, "Win_create_keyval", 3 );
2431    print $OUTFD "\
2432    return keyval;
2433}
2434";
2435
2436print $OUTFD "\
2437// Provide a C routine that can call the C++ error handler, handling
2438// any calling-sequence change. 
2439extern \"C\" void MPIR_Errhandler_set_cxx( MPI_Errhandler, void (*)(void) );
2440extern \"C\"
2441void MPIR_Call_errhandler_fn( int kind, int *handle, int *errcode,
2442                              void (*cxxfn)(void) )
2443{
2444    // Use horrible casts to get the correct routine signature
2445    switch (kind) {
2446    case 0: // comm
2447            {
2448                MPI_Comm *ch = (MPI_Comm *)handle;
2449                int flag;
2450                MPI::Comm::Errhandler_fn *f = (MPI::Comm::Errhandler_fn *)cxxfn;
2451                // Make an actual Comm (inter or intra-comm)
2452                MPI_Comm_test_inter( *ch, &flag );
2453                if (flag) {
2454                    MPI::Intercomm ic(*ch);
2455                    (*f)( ic, errcode );
2456                }
2457                else {
2458                    MPI::Intracomm ic(*ch);
2459                    (*f)( ic, errcode );
2460                }
2461            }
2462            break;
2463#ifdef MPI_MODE_RDONLY
2464    case 1: // file
2465            {
2466                MPI::File fh = (MPI_File)*(MPI_File*)handle;
2467                MPI::File::Errhandler_fn *f = (MPI::File::Errhandler_fn *)cxxfn;
2468                (*f)( fh, errcode );
2469            }
2470            break;
2471#endif // IO
2472    case 2: // win
2473            {
2474                MPI::Win fh = (MPI_Win)*(MPI_Win*)handle;
2475                MPI::Win::Errhandler_fn *f = (MPI::Win::Errhandler_fn *)cxxfn;
2476                (*f)( fh, errcode );
2477            }
2478            break;
2479    }
2480}
2481#ifdef MPI_MODE_RDONLY
2482Errhandler File::Create_errhandler( Errhandler_fn *f )
2483{
2484    MPI_Errhandler eh;
2485    MPI::Errhandler e1;
2486    MPI_File_create_errhandler( (MPI_File_errhandler_fn *)f, &eh );
2487    MPIR_Errhandler_set_cxx( eh,
2488                             (mpircallback)MPIR_Call_errhandler_fn );
2489    e1.the_real_errhandler = eh;
2490    return e1;
2491}
2492#endif // IO
2493Errhandler Comm::Create_errhandler( Errhandler_fn *f )
2494{
2495    MPI_Errhandler eh;
2496    MPI::Errhandler e1;
2497    MPI_Comm_create_errhandler( (MPI_Comm_errhandler_fn *)f, &eh );
2498    MPIR_Errhandler_set_cxx( eh,
2499                             (mpircallback)MPIR_Call_errhandler_fn );
2500    e1.the_real_errhandler = eh;
2501    return e1;
2502}
2503Errhandler Win::Create_errhandler( Errhandler_fn *f )
2504{
2505    MPI_Errhandler eh;
2506    MPI::Errhandler e1;
2507    MPI_Win_create_errhandler( (MPI_Win_errhandler_fn *)f, &eh );
2508    MPIR_Errhandler_set_cxx( eh,
2509                             (mpircallback)MPIR_Call_errhandler_fn );
2510    e1.the_real_errhandler = eh;
2511    return e1;
2512}
2513
2514
2515// Call_errhandler implementations.  These sadly must contain a bit of logic to
2516// cover the ERRORS_THROW_EXCEPTIONS case.
2517void Comm::Call_errhandler( int errorcode ) const
2518{
2519    if (Get_errhandler() == ERRORS_THROW_EXCEPTIONS) {
2520        throw Exception(errorcode); // throw by value, catch by reference
2521    }
2522    MPIX_CALL( MPI_Comm_call_errhandler( (MPI_Comm) the_real_comm, errorcode ));
2523}
2524
2525void Win::Call_errhandler( int errorcode ) const
2526{
2527    if (Get_errhandler() == ERRORS_THROW_EXCEPTIONS) {
2528        throw Exception(errorcode); // throw by value, catch by reference
2529    }
2530    MPIX_CALL( MPI_Win_call_errhandler( (MPI_Win) the_real_win, errorcode ));
2531}
2532
2533#ifdef MPI_MODE_RDONLY
2534void File::Call_errhandler( int errorcode ) const
2535{
2536    if (Get_errhandler() == ERRORS_THROW_EXCEPTIONS) {
2537        throw Exception(errorcode); // throw by value, catch by reference
2538    }
2539    MPIX_CALL( MPI_File_call_errhandler( (MPI_File) the_real_file, errorcode ));
2540}
2541#endif // IO
2542
2543\n";
2544
2545    # The data rep conversion functions need to be wrapped in C code
2546    # Only define this routine when MPI-IO is available (this is the same
2547    # test as used for the rest of the I/O routines );
2548print $OUTFD "#ifdef MPI_MODE_RDONLY\n";
2549    print $OUTFD "
2550extern \"C\" {
2551//
2552// Rather than use a registered interposer, instead we interpose, taking
2553// advantage of the extra_data field, similar to the handling of Grequest.
2554typedef struct {
2555    Datarep_conversion_function *read_fn;
2556    Datarep_conversion_function *write_fn;
2557    Datarep_extent_function *extent_fn;
2558    void *orig_extra_state;
2559    } MPIR_Datarep_data;
2560int MPIR_Call_datarep_read_fn( void *userbuf, MPI_Datatype datatype,
2561                               int count,
2562                               void *filebuf, MPI_Offset position,
2563                               void *extra_state )
2564{
2565    MPIR_Datarep_data *ldata = (MPIR_Datarep_data *)extra_state;
2566    Datatype dtype = (Datatype)datatype;
2567    return (ldata->read_fn)( userbuf, dtype, count, filebuf,
2568                            position, ldata->orig_extra_state);
2569}
2570int MPIR_Call_datarep_write_fn( void *userbuf, MPI_Datatype datatype,
2571                               int count,
2572                               void *filebuf, MPI_Offset position,
2573                               void *extra_state )
2574{
2575    MPIR_Datarep_data *ldata = (MPIR_Datarep_data *)extra_state;
2576    Datatype dtype = (Datatype)datatype;
2577    return (ldata->write_fn)( userbuf, dtype, count, filebuf,
2578                             position, ldata->orig_extra_state);
2579}
2580int MPIR_Call_datarep_extent_fn( MPI_Datatype datatype, MPI_Aint *extent,
2581                                 void *extra_state ) {
2582    MPIR_Datarep_data *ldata = (MPIR_Datarep_data *)extra_state;
2583    Aint myextent;
2584    int err;
2585    err =  (ldata->extent_fn)( (Datatype)datatype, myextent,
2586                               ldata->orig_extra_state);
2587    *extent = myextent;
2588    return err;
2589}
2590} /* extern C */
2591void Register_datarep( const char *datarep,
2592                       Datarep_conversion_function *read_fn,
2593                       Datarep_conversion_function *write_fn,
2594                       Datarep_extent_function *extent_fn,
2595                       void *orig_extra_state )
2596{
2597    MPIR_Datarep_data *ldata = new(MPIR_Datarep_data);
2598    ldata->read_fn          = read_fn;
2599    ldata->write_fn         = write_fn;
2600    ldata->extent_fn        = extent_fn;
2601    ldata->orig_extra_state = orig_extra_state;
2602    MPIX_CALL(MPI_Register_datarep( (char *)datarep,
2603                                MPIR_Call_datarep_read_fn,
2604                                MPIR_Call_datarep_write_fn,
2605                                MPIR_Call_datarep_extent_fn, (void *)ldata ));
2606    /* Because datareps are never freed, the space allocated in this
2607       routine for ldata will never be freed */
2608}
2609";
2610print $OUTFD "#endif\n";
2611
2612
2613    print $OUTFD "\
2614void Datatype::Pack( const void *inbuf, int incount, void *outbuf,
2615                     int outsize, int &position, const Comm &comm ) const {\n";
2616    &printCoverageStart( $OUTFD, "Pack", 6 );
2617    print $OUTFD "\
2618        MPIX_CALL( MPI_Pack( (void *)inbuf, incount, the_real_datatype, outbuf,
2619                            outsize, &position, comm.the_real_comm ) );\n";
2620    &printCoverageEnd( $OUTFD, "Pack", 6 );
2621    print $OUTFD "\
2622    }\n";
2623    print $OUTFD "\
2624int Datatype::Pack_size( int count, const Comm &comm ) const {\n";
2625    &printCoverageStart( $OUTFD, "Pack_size", 6 );
2626    print $OUTFD "\
2627        int size;
2628        MPIX_CALL( MPI_Pack_size( count, the_real_datatype, comm.the_real_comm, &size ) );\n";
2629    &printCoverageEnd( $OUTFD, "Pack_size", 6 );
2630    print $OUTFD "\
2631        return size;
2632    }\n";
2633    print $OUTFD "\
2634void Datatype::Unpack( const void *inbuf, int insize, void *outbuf,
2635                       int outcount, int &position, const Comm &comm ) const {\n";
2636    &printCoverageStart( $OUTFD, "Unpack", 6 );
2637    print $OUTFD "\
2638        MPIX_CALL( MPI_Unpack( (void *)inbuf, insize, &position, outbuf, outcount,
2639                              the_real_datatype, comm.the_real_comm ) );\n";
2640    &printCoverageEnd( $OUTFD, "Unpack", 6 );
2641    print $OUTFD "\
2642    }\n";
2643
2644    # No coverage for Wtime and Wtick
2645    print $OUTFD "double Wtime(void) { return MPI_Wtime(); }\n";
2646    print $OUTFD "double Wtick(void) { return MPI_Wtick(); }\n";
2647
2648    print $OUTFD "\
2649    Cartcomm Intracomm::Create_cart( int v2, const int * v3, const bool v4[], bool v5 ) const
2650    {
2651        Cartcomm v6;
2652        int *l4 = new int[v2];
2653        int l5;
2654        {
2655            int i4;
2656            for (i4=0;i4<v2;i4++) {
2657                l4[i4] = v4[i4] == true ? 1 : 0;
2658            }
2659        }
2660         l5 = (v5 == true) ? 1 : 0;\n";
2661     &printCoverageStart( $OUTFD, "Cart_create", 5 );
2662     print $OUTFD "\
2663        MPIX_CALL( MPI_Cart_create( (MPI_Comm) the_real_comm, v2, (int *)v3, l4, l5, &(v6.the_real_comm) ));\n";
2664     &printCoverageEnd( $OUTFD, "Cart_create", 5 );
2665     print $OUTFD "\
2666            delete[] l4;
2667        return v6;
2668    }\n";
2669
2670    print $OUTFD "\
2671    Graphcomm Intracomm::Create_graph( int v2, const int * v3, const int * v4, bool v5 ) const
2672    {
2673        Graphcomm v6;
2674        int l5;
2675         l5 = (v5 == true) ? 1 : 0;\n";
2676    &printCoverageStart( $OUTFD, "Graph_create", 6 );
2677    print $OUTFD "\
2678        MPIX_CALL( MPI_Graph_create( (MPI_Comm) the_real_comm, v2, (int *)v3, (int *)v4, l5, &(v6.the_real_comm) ));\n";
2679    &printCoverageEnd( $OUTFD, "Graph_create", 6 );
2680    print $OUTFD "\
2681        return v6;
2682    }\n";
2683
2684    print $OUTFD "\
2685    Intracomm Intercomm::Merge( bool v2 ) const
2686    {
2687        Intracomm v3;
2688        int l2;
2689         l2 = (v2 == true) ? 1 : 0;\n";
2690    &printCoverageStart( $OUTFD, "Intercomm_merge", 3 );
2691    print $OUTFD "\
2692        MPIX_CALL( MPI_Intercomm_merge( (MPI_Comm) the_real_comm, l2, &(v3.the_real_comm) ));\n";
2693    &printCoverageEnd( $OUTFD, "Intercomm_merge", 3 );
2694    print $OUTFD "\
2695        return v3;
2696    }\n";
2697
2698    # MPI-2 base routines
2699    &PrintWrapper( $OUTFD, "bool", "Is_finalized", "void",
2700                   "int flag;", "Finalized", "&flag", "(flag != 0)" );
2701
2702    &PrintWrapper( $OUTFD, "int", "Query_thread", "void", 
2703                   "int provided;", "Query_thread", "&provided", 
2704                   "provided" );
2705    &PrintWrapper( $OUTFD, "bool", "Is_thread_main", "void",
2706                   "int flag;", "Is_thread_main", "&flag", "(flag != 0)" );
2707    &PrintWrapper( $OUTFD, "void", "Get_version", "int &v, int&sv",
2708                  "", "", "&v,&sv", "" );
2709
2710    &PrintWrapper( $OUTFD, "int", "Add_error_class", "void", 
2711                   "int eclass;", "", "&eclass", "eclass" );
2712    &PrintWrapper( $OUTFD, "int", "Add_error_code", "int eclass",
2713                   "int ecode;", "", "eclass, &ecode", "ecode" );
2714    &PrintWrapper( $OUTFD, "void", "Add_error_string", 
2715                   "int ecode, const char *estring", 
2716                   "", "", "ecode, (char *)estring", "" );
2717
2718    &PrintWrapper( $OUTFD, "void", "Lookup_name", 
2719                    "const char *sn, const Info &info, char *pn",
2720                    "", "", "(char *)sn, (MPI_Info)info, pn", "" );
2721    &PrintWrapper( $OUTFD, "void", "Publish_name",
2722                    "const char *sn, const Info &info, const char *pn",
2723                    "", "", "(char *)sn, (MPI_Info)info, (char *)pn", "");
2724    &PrintWrapper( $OUTFD, "void", "Unpublish_name", 
2725                    "const char *sn, const Info &info, const char *pn",
2726                    "", "", "(char *)sn, (MPI_Info)info, (char *)pn", "");
2727
2728    &PrintWrapper( $OUTFD, "Intercomm", "Comm::Get_parent", "void", 
2729                   "MPI::Intercomm v;MPI_Comm vv;", 
2730                   "Comm_get_parent",
2731                   "&vv", "(v = (Intercomm)vv, v)" );
2732    &PrintWrapper( $OUTFD, "Intercomm", "Comm::Join", "const int fd",
2733                    "MPI::Intercomm v;MPI_Comm vv;",
2734                    "Comm_join",
2735                    "fd,&vv", "(v = (Intercomm)vv,v)" );
2736
2737    &PrintWrapper( $OUTFD, "void", "Close_port", 
2738                   "const char *pn", "", "", "(char *)pn", "" );
2739    &PrintWrapper( $OUTFD, "void", "Open_port", 
2740                   "const Info &info, char *portname", "", "", 
2741                   "(MPI_Info)info, portname", "" );
2742
2743    print $OUTFD "
2744//
2745// Rather than use a registered interposer, instead we interpose taking
2746// advantage of the extra_data field
2747typedef struct {
2748    MPI::Grequest::Query_function  *query_fn;
2749    MPI::Grequest::Free_function   *free_fn;
2750    MPI::Grequest::Cancel_function *cancel_fn;
2751    void *orig_extra_data; } MPIR_Grequest_data;
2752extern \"C\" int MPIR_Grequest_call_query_fn( void *extra_data,
2753                                            MPI_Status *status )
2754{
2755    int err;
2756    MPI::Status s;
2757    MPIR_Grequest_data *d = (MPIR_Grequest_data *)extra_data;
2758   
2759    err = (d->query_fn)( d->orig_extra_data, s );
2760    *status = s;
2761
2762    return err;
2763}
2764extern \"C\" int MPIR_Grequest_call_free_fn( void *extra_data )
2765{
2766    int err;
2767    MPIR_Grequest_data *d = (MPIR_Grequest_data *)extra_data;
2768   
2769    err = (d->free_fn)( d->orig_extra_data );
2770
2771    // Recover the storage that we used for the extra_data item.
2772    delete d;
2773    return err;
2774}
2775extern \"C\" int MPIR_Grequest_call_cancel_fn( void *extra_data, int done )
2776{
2777    int err;
2778    MPI::Status s;
2779    MPIR_Grequest_data *d = (MPIR_Grequest_data *)extra_data;
2780   
2781    // Pass a C++ bool to the C++ version of the cancel function
2782    err = (d->cancel_fn)( d->orig_extra_data, done ? true : false );
2783    return err;
2784}
2785Grequest Grequest::Start( Grequest::Query_function query_fn,
2786                          Grequest::Free_function free_fn,
2787                          Grequest::Cancel_function cancel_fn,
2788                          void *extra_state )
2789{
2790    MPI::Grequest req;
2791    MPIR_Grequest_data *d = new MPIR_Grequest_data;
2792    d->query_fn        = query_fn;
2793    d->free_fn         = free_fn;
2794    d->cancel_fn       = cancel_fn;
2795    d->orig_extra_data = extra_state;
2796    MPI_Grequest_start( MPIR_Grequest_call_query_fn,
2797                        MPIR_Grequest_call_free_fn,
2798                        MPIR_Grequest_call_cancel_fn,
2799                        (void *)d, &req.the_real_request );
2800    return req;
2801}
2802";
2803
2804# Add the routine to initialize MPI datatype names for the C++ datatypes
2805print $OUTFD "
2806/* MT FIXME: this is not thread-safe */
2807void MPIR_CXX_InitDatatypeNames( void )
2808{
2809    static int _isInit = 1;
2810    if (_isInit) {
2811        _isInit=0;
2812        PMPI_Type_set_name( MPI::BOOL, (char *)\"MPI::BOOL\" );
2813        PMPI_Type_set_name( MPI::COMPLEX, (char *)\"MPI::COMPLEX\" );\
2814        PMPI_Type_set_name( MPI::DOUBLE_COMPLEX, (char *)\"MPI::DOUBLE_COMPLEX\" );\
2815#if defined(HAVE_LONG_DOUBLE)
2816        PMPI_Type_set_name( MPI::LONG_DOUBLE_COMPLEX, (char *)\"MPI::LONG_DOUBLE_COMPLEX\" );\
2817#endif
2818    }
2819}\n";
2820
2821    print $OUTFD "} // namespace MPI\n";
2822    close ($OUTFD);
2823    &ReplaceIfDifferent( $filename, "${filename}.new" );
2824}
2825
2826# ------------------------------------------------------------------------
2827# A special routine to add code to call an mpi routine:
2828# PrintWrapper ( fd, returntype, c++name, c++args,
2829#                cdecls, mpiroutine, cArgs, return-exp )
2830# if mpiroutine is empty, use the C++ name
2831sub PrintWrapper {
2832    my ($OUTFD, $returntype, $cxxname, $cxxargs,
2833        $cdecls, $mpiroutine, $cArgs, $returnExp ) = @_;
2834
2835    if ($mpiroutine eq "") {
2836        $mpiroutine = $cxxname;
2837    }
2838
2839    my $nargs = &GetArgCount( $cArgs );
2840    print $OUTFD "\n$returntype $cxxname( $cxxargs )
2841    {
2842    $cdecls\n";
2843    &printCoverageStart( $OUTFD, $mpiroutine, $nargs );
2844    print $OUTFD "    MPIX_CALL( MPI_$mpiroutine( $cArgs ) );\n";
2845    &printCoverageEnd( $OUTFD, $mpiroutine, $nargs );
2846    if ($returntype ne "void") {
2847        print $OUTFD "    return $returnExp;\n";
2848    }
2849    print $OUTFD "}\n";
2850}
2851# ------------------------------------------------------------------------
2852
2853# Given an integer location of an argument, return the corresponding
2854# type, from the arg list
2855sub Convert_pos_to_type {
2856    my @parm = split( ',', $_[0] );
2857    my $loc = $_[1];
2858
2859    return $parm[$loc-1];
2860}
2861sub Convert_type_to_pos {
2862    my @parm = split( ',', $_[0] );
2863    my $type = $_[1];
2864    my $loc = 1;
2865   
2866    for $parm (@parm) {
2867        if ($parm =~ /$type/) { return $loc; }
2868        $loc ++;
2869    }
2870    return 0;
2871}
2872
2873# Print the class header
2874# PrintClassHead( $OUTFD, class, mpitype, friends )
2875# E.g., PrintClassHead( $OUTFD, "Datatype", "MPI_Datatype", "Comm,Status" )
2876sub PrintClassHead {
2877    my $OUTFD = $_[0];
2878    my $class = $_[1];
2879    my $mpi_type = $_[2];
2880    my $friends  = $_[3];
2881    my $mpi_null_type = uc("${mpi_type}_NULL" );
2882
2883    my $lcclass = lc($class);
2884    my $lctopclass = $lcclass;
2885
2886    if (! ($mpi_type =~ /^MPI_/) ) {
2887        # The mpi_type isn't an MPI type after all.  Assume that
2888        # it is something (like an int) where we want the default to
2889        # be 0
2890        $mpi_null_type = "0";
2891    }
2892    # For derived classes, we sometimes need to know the name of the
2893    # top-most class, particularly for the "the_real_xxx" name.
2894    if (defined($mytopclass{$lcclass})) {
2895        $lctopclass = $mytopclass{$lcclass};
2896    }
2897    my $parent = "";
2898
2899    my $baseclass = "";
2900    if (defined($derived_class{$shortclass})) {
2901        $baseclass = $derived_class{$shortclass};
2902        $parent = ": public $baseclass";
2903    }
2904   
2905    print $OUTFD "\nclass $class $parent {\n";
2906    if (defined($friends) && $friends ne "") {
2907        foreach $name (split(/,/,$friends)) {
2908            print $OUTFD "    friend class $name;\n";
2909        }
2910    }
2911    if ($lcclass eq $lctopclass) {
2912        print $OUTFD "\         
2913  protected:
2914    $mpi_type the_real_$lcclass;\n";
2915        # Check for special declarations
2916        $otherdeclfn = "$class" . "_extradecls";
2917        if (defined(&$otherdeclfn)) {
2918            &$otherdeclfn( $OUTFD );
2919        }
2920    }
2921  print $OUTFD "\
2922  public:
2923    // new/delete\n";
2924    if (0) {
2925        print $OUTFD "\
2926    inline $class($mpi_type obj) { the_real_$lctopclass = obj; }\n";
2927    }
2928    else {
2929        if ($lcclass eq $lctopclass) {
2930            print $OUTFD "\
2931    inline $class($mpi_type obj) : the_real_$lctopclass(obj) {}\n";
2932        }
2933        else {
2934            print $OUTFD "\
2935    inline $class($mpi_type obj) : $baseclass(obj) {}\n";
2936        }
2937    }
2938
2939    if (defined($class_has_no_default{$class})) {
2940        if (0) {
2941            print $OUTFD "    inline $class(void) {}\n";
2942        }
2943        else {
2944            if ($lcclass eq $lctopclass) {
2945                print $OUTFD "    inline $class(void) : the_real_$lctopclass() {}\n";
2946        }
2947            else {
2948                print $OUTFD "    inline $class(void) : $baseclass\(\) {}\n";
2949            }
2950        }
2951    }
2952    else {
2953        if (0) {
2954            print $OUTFD "    inline $class(void) { the_real_$lctopclass = $mpi_null_type; }\n";
2955        }
2956        else {
2957            if ($lcclass eq $lctopclass) {
2958                print $OUTFD "    inline $class(void) : the_real_$lctopclass($mpi_null_type) {}\n";
2959        }
2960            else {
2961                print $OUTFD "    inline $class(void) : $baseclass\(\) {}\n";
2962            }
2963        }
2964    }
2965   
2966    # These had $class :: $class..., but pgCC complained,
2967    # so the $class :: was removed
2968    print $OUTFD "\
2969    virtual ~$class() {}
2970    // copy/assignment\n";
2971    # Three cases (two that we should really use):
2972    # If the base class, initialize directly
2973    # If a derived class, initialize with the base class initializer
2974    if (0) {
2975        print $OUTFD "\
2976    $class(const $class &obj) {
2977      the_real_$lctopclass = obj.the_real_$lctopclass; }\n";
2978    }
2979    else {
2980        if ($lcclass eq $lctopclass) {
2981            print $OUTFD "\
2982    $class(const $class &obj) : the_real_$lctopclass(obj.the_real_$lctopclass){}\n";
2983        }
2984        else {
2985            print $OUTFD "\
2986    $class(const $class &obj) : $baseclass(obj) {}\n";
2987        }
2988    }
2989    print $OUTFD "\
2990    $class& operator=(const $class &obj) {
2991      the_real_$lctopclass = obj.the_real_$lctopclass; return *this; }\n";
2992    if (!defined($class_has_no_compare{$class})) {
2993        # Some classes (e.g., Status) do not have compare operations
2994        # *or* they are derived classes that must use the parent's
2995        # comparison operations
2996        print $OUTFD "
2997    // logical
2998    bool operator== (const $class &obj) {
2999      return (the_real_$lctopclass == obj.the_real_$lctopclass); }
3000    bool operator!= (const $class &obj) {
3001      return (the_real_$lctopclass != obj.the_real_$lctopclass); }";
3002    }
3003
3004    # These had $class :: $class..., but pgCC complained,
3005    # so the $class :: was removed on operator=
3006    print $OUTFD "
3007    // C/C++ cast and assignment
3008    inline operator $mpi_type*() { return &the_real_$lctopclass; }
3009    inline operator $mpi_type() const { return the_real_$lctopclass; }
3010    $class& operator=(const $mpi_type& obj) {
3011      the_real_$lctopclass = obj; return *this; }
3012";
3013}
3014
3015sub PrintClassTail { 
3016    my $OUTFD = $_[0];
3017    print $OUTFD "};\n";
3018}
3019
3020# -----------------------------------------------------------------------------
3021# Here will go routines for handling return values.  These need to move them
3022# from pointer arguments in the parameter list into a local declaration
3023# (possibly using new)
3024#
3025# We process a binding *first* and set the global variables
3026#    return_type (type of return value, in the C binding)
3027#    return_actual_type (real return type, in the C++ binding)
3028#    return_parm_pos (number of location of arg in parm list; 0 if none)
3029# return_info is either a number or a type.  If a type, it does NOT include
3030# the * (e.g., int instead of int *), but the * must be in the parameter
3031# FindReturnInfo( return_info, args )
3032#    The return info may also contain a ;<actual type>, as in
3033#     3;bool
3034# This is used for the cases where the return type isn't obvious
3035# from the return type.  This is necessary for C++ returns of type bool
3036# that are int in C (since other int returns may in fact be ints). 
3037sub FindReturnInfo {
3038    my @parms = split(/,/,$_[1] );
3039    my $return_info = $_[0];
3040
3041    $return_actual_type = "";
3042    $return_parm_pos = -1;
3043    if ($return_info =~ /(.*);(.*)/) {
3044        $return_info = $1;
3045        $return_actual_type = $2;
3046    }
3047    if ($return_info eq "0") {
3048        $return_type = "void";
3049        $return_parm_pos = 0;
3050    }
3051    elsif ($return_info =~ /^[0-9]/) {
3052        # We have the position but we need to find the type
3053        my $count = 1;
3054        for $parm (@parms) {
3055            if ($count == $return_info) { 
3056                $return_type     = $parm;
3057                $return_type     =~ s/\s*\*$//;   # Remove *
3058                $return_parm_pos = $count;
3059            }
3060            $count ++;
3061        }
3062    }
3063    else {
3064        # Return info is a type. Find the matching location
3065        my $count = 1;
3066        $return_type = "";
3067        for $parm (@parms) {
3068            if ($parm =~ /$return_info\s*\*/) {
3069                $return_parm_pos = $count;
3070                $return_type     = $return_info;
3071                last;
3072            }
3073            $count ++;
3074        }
3075        if ($return_type eq "") {
3076            print STDERR "Warning: no return type found for $routine\n";
3077        }
3078    }
3079    if ($return_actual_type eq "") { $return_actual_type = $return_type; }
3080}
3081# -----------------------------------------------------------------------------
3082# Convert other arguments from C to C++ versions.  E.g., change the
3083# MPI_Datatype arg in Comm::Send from MPI_Datatype to Datatype.  Use
3084# (MPI_Datatype)datatype.the_real_datatype (always).
3085#
3086# HandleObjectParms( parmtype, parm )
3087# e.g., HandleObjectParms( MPI_Datatype, v7 )
3088# returns appropriate string.  If parmtype unknown, just return parm
3089sub HandleObjectParm {
3090    my $parmtype = $_[0];
3091    my $parm     = $_[1];
3092    my $need_address = 0;
3093    my $newparm;
3094
3095    # Check for the special case of MPI_Aint, MPI_Offset
3096    if ($parmtype =~ /MPI_/ && 
3097        ! ($parmtype =~/MPI_Aint/ || $parmtype =~ /MPI_Offset/)) {
3098        $ctype = $parmtype;
3099        if ($ctype =~ /\*/) {
3100            $need_address = 1;
3101            $ctype