use 5.006; use ExtUtils::MakeMaker; my $LLVER="UNKNOWN"; $CC=$ExtUtils::MakeMaker::Config{"cc"}; # # I hope this bit works out the base LoadLeveler version. # Can't use the variables in the llapi.h file because the version number is the # same for 3.1 & 3.2! I am sure there is a very good reason for this, I don't know # what it is, but i'm sure it must be a very good reason. # if ( $^O eq "linux" ) { $LoadL="/opt/ibmll/LoadL/full"; # Quit if no llapi.h file (for CPAN testers) if ( ! -f "$LoadL/include/llapi.h") { print STDERR "Unable to find LoadLeveler include file\n"; exit 0; } $ExtraLibs="-lstdc++"; # stops load failure with error undefined symbol: __gxx_personality_v0 my $rpm = ""; $rpm = "/usr/bin/rpm" if -f "/usr/bin/rpm"; $rpm = "/bin/rpm" if -f "/bin/rpm"; my @packages=`$rpm -qa`; foreach $package (@packages) { next unless $package=~/LoadL.*-([\d.]+)-/; # print "$package ----> $1\n"; $LLVER=$1; } if ( ! $LLVER eq "UNKNOWN" ) { print STDERR "Unable to extract LoadLeveler version\n"; exit 0; } # 64 bit required on PowerPC if ( ! defined $ExtUtils::MakeMaker::Config{"use64bitall"} && $ExtUtils::MakeMaker::Config{"archname"} =~ /ppc-linux/) { print "I'm not totally sure but I think you are trying to build with a 32 bit version of Perl, the llapi is 64 bit\n"; print "This is probably going to end very badly. Sorry\n\n"; } } elsif ( $^O eq "aix" ) { $LoadL="/usr/lpp/LoadL/full"; # Quit if no llapi.h file (for CPAN testers) if ( ! -f "$LoadL/include/llapi.h") { print STDERR "Unable to find LoadLeveler include file\n"; exit 0; } $ExtraLibs=""; # # The code extracts the package version using lslpp. # open(LLVER,"/usr/bin/lslpp -Ou -qlc LoadL.full |"); $_=; $_=~/^[^:]+:[^:]+:([^:]+):/; close(LLVER); $LLVER=$1; } else { # Return a value that CPAN testers might like # http://cpantest.grango.org/cgi-bin/pages.cgi?act=wiki-page&pagename=CPANAuthorNotes print STDERR "OS unsupported\n"; print STDERR "LoadLevler is only supported on Linux and AIX. Found $OS\n"; exit 0; } # # The code converts the package version to a number, eg # String is 3.1.0.16 # doubles any single digits: 03.01.00.16 # removes the dots: 03010016 # removes the leading 0 (octal): 3010016 # The final number is used in #ifdef statements # # The 1 while ..... construct repeatedly runs the doubling search. This is needed # because if you match one .0. then the start for the next search is the first digit # in the next number. See Page 155 of Camel V3. Alternativly just trust me that it works :) # 1 while $LLVER=~s/\.(\d)\./.0$1./g; $LLVER=~s/\.(\d)$/.0$1/; $LLVER=~s/\.//g; $LLVER=~s/^0(\d+)/$1/; print "Building for version $LLVER on $^O\n\n"; process_defs(); WriteMakefile( 'NAME' => 'IBM::LoadLeveler', 'VERSION_FROM' => 'LoadLeveler.pm', 'PREREQ_PM' => {}, # e.g., Module::Name => 1.1 ($] >= 5.005 ? ## Add these new keywords supported since 5.005 (ABSTRACT_FROM => 'LoadLeveler.pod', # retrieve abstract from module AUTHOR => 'Mike Hawkins ') : ()), 'PM' => { 'llapi.ph' => '$(INST_LIBDIR)/llapi.ph', 'LoadLeveler.pm' => '$(INST_LIBDIR)/LoadLeveler.pm' }, 'MAN3PODS' => { 'LoadLeveler.pod' => '$(INST_MAN3DIR)/LoadLeveler.$(MAN3EXT)', 'DataAccess.pod' => '$(INST_MAN3DIR)/LoadLeveler::DataAccess.$(MAN3EXT)', 'Submit.pod' => '$(INST_MAN3DIR)/LoadLeveler::Submit.$(MAN3EXT)', 'Query.pod' => '$(INST_MAN3DIR)/LoadLeveler::Query.$(MAN3EXT)', 'Workload.pod' => '$(INST_MAN3DIR)/LoadLeveler::Workload.$(MAN3EXT)', 'Reservation.pod' => '$(INST_MAN3DIR)/LoadLeveler::Reservation.$(MAN3EXT)', 'Error.pod' => '$(INST_MAN3DIR)/LoadLeveler::Error.$(MAN3EXT)', 'Fairshare.pod' => '$(INST_MAN3DIR)/LoadLeveler::Fairshare.$(MAN3EXT)', }, 'LIBS' => ["-L$LoadL/lib -lllapi $ExtraLibs"], # e.g., '-lm' 'DEFINE' => "-DLLVER=$LLVER", 'INC' => "-I$LoadL/include", 'OBJECT' => '$(O_FILES) ', 'MYEXTLIB' => 'ct.a', # Fake Library to con MakeMaker into building C tests 'CC' => $CC, 'macro' => { LoadL => "$LoadL" }, 'clean' => { FILES => "llapi.ph ct.a ct/version ct/data_access ct/int_types" }, ); sub MY::postamble { my $postamble = <<'END'; llapi.ph: $(LoadL)/include/llapi.h ( cd $(LoadL)/include ; h2ph -d /tmp llapi.h ) cat /tmp/llapi.ph | sed -e /require.*/d > $(INST_LIB)/../../llapi.ph rm /tmp/llapi.ph html: LoadLeveler.pm DataAccess.pod Reservation.pod Submit.pod Query.pod Workload.pod Error.pod Fairshare.pod LoadLeveler.pod pod2html --flush --noindex --podpath=. --htmlroot=. --outfile=DataAccess.html DataAccess.pod pod2html --noindex --podpath=. --htmlroot=. --outfile=Reservation.html Reservation.pod pod2html --noindex --podpath=. --htmlroot=. --outfile=Submit.html Submit.pod pod2html --noindex --podpath=. --htmlroot=. --outfile=Query.html Query.pod pod2html --noindex --podpath=. --htmlroot=. --outfile=Workload.html Workload.pod pod2html --noindex --podpath=. --htmlroot=. --outfile=Error.html Error.pod pod2html --noindex --podpath=. --htmlroot=. --outfile=Fairshare.html Fairshare.pod pod2html --noindex --podpath=. --htmlroot=. --outfile=LoadLeveler.html LoadLeveler.pod ct.a: ct/version ct/data_access ct/int_types ar r ct.a ct/version: ct/version.c $(CC) -o $@ $(CCFLAGS) $(INC) $@.c $(EXTRALIBS) ct/data_access: ct/data_access.c $(CC) -o $@ $(CCFLAGS) $(INC) $@.c $(EXTRALIBS) ct/int_types: ct/int_types.c $(CC) -o $@ $(CCFLAGS) $(INC) $@.c $(EXTRALIBS) END $postamble; } sub process_defs { my %enums=(); my @values=(); print "Building list of current ll_get_data specifications\n"; open(LLAPI,"$LoadL/include/llapi.h") || die "Can't open $LoadL/include/llapi.h $!"; # Speed through the file till we find # the LLAPI_Specification enum while ( ) { last if /LLAPI_Specification/; } my $count=0; while ( ) { last if /}/; next if /Unused_LL/; next unless /LL/; chomp; # Don't bother with anything that doesn't have a comma in it. next unless /([^,]*),(.*)/; my $before=$1; my $after=$2; # If the version of C we are using does not support Designated Initializers # we need the enum id number. boo hiss btw $count = $1 if /=\s*(\d+),/; # Process the enum # remove leading whitespace $before=~s/^\s+//; # remove everything after a white space $before=~s/\s+.*//; # remove everything after and including an = $before=~s/=.*//; # Process the definition $after="NONE" if $after=~/^\s*$/; # remove anything up to the start of a type def $after=~s|^.*/\*\s*||; # remove everything after a : $after=~s|:.*||; # or a ( $after=~s|\(.*||; # remove anything after a * $after=~s|\*\s+.*|\*|; # strip out C end comments $after=~s|\*/||; $after= uc($after); $after=~s/\s*$//g; $after=~s/\*/_STAR/g; $after=~s/ /_/g; $after=~s/_+/_/g; $after="LL_$after"; # print "$count $before -> $after ($_)\n"; $enums{$before}=$after; $values[$count++]=$before; } close(LLAPI); print "Generating new definitions array\n"; open(DEFS,"defs.h.in") || die "Can't open defs.h.in $!"; open(OUT,"> defs.h.new")|| die "Can't open defs.h.new $!"; # # C99 introduced Designated Initalizers for arrays, meaning you # can do things like: # static int defs[]={ # [LL_StepCheckpointing] = LL_BOOLEAN_STAR, # [LL_MachineName] = LL_CHAR_STAR, # }; # Which is very nice since the alternative is to build a very nasty array. # # For now I don't know how to work out if C supports this feature, I do know it # doesn't work on my version of AIX though... # my $UseDesignatedInitializers = 1; $UseDesignatedInitializers = 0 if $OS =~ /AIX/; # Copy everything out until we get to the array definition while( ) { print OUT $_; last if ( $_ =~ /\[\]/ ); } # # We are now pointing at the definitions in the template array # What I want to do at this point is to read the defs.h.in file # and if I find a line like # [LL_StepCheckpointing] = LL_BOOLEAN_STAR, # then see if the LL_ thingie was defined in the # include file, if it is write it out, if not don't. # # However this will only work if the Designated Initializers # are supported, otherwise a fully defined array needs to be built # # So, suck my handcranked defs in from the defs.h.in file # and then loop through all enums as slurped out of the # system llapi.h file, @values contains a number to LL_ thingie # which can be used to see if there is anything to print. # my %defs=(); while ( ) { last if ( $_ !~ /\[.*\]/ ); # slurp the definition from the file into a hash next unless $_=~/\[(.*)\]\s*=\s*(\S+)\s*\,/; $defs{$1}=$2; } for(my $i=0;$i<$count;$i++) { if ( exists $defs{$values[$i]}) { if ( $UseDesignatedInitializers) { print OUT "\t\[$values[$i]\] = $defs{$values[$i]},\n"; # print "\t\[$values[$i]\] = $defs{$values[$i]},\n"; } else { print OUT "$defs{$values[$i]},\n"; } delete $enums{$values[$i]}; delete $defs{$values[$i]}; } else { print OUT "LL_NONE,\n" if ! $UseDesignatedInitializers; } } # Close the array print OUT "};\n"; print OUT "\n"; close(OUT); close(DEFS); if ( scalar keys %enums > 0 ) { print "Current llapi.h has the following definitions, add them to defs.h at your own risk:\n\n"; foreach my $key ( keys %enums) { print "[$key] = $enums{$key},\n"; } print "\n"; } if ( scalar keys %defs > 0 ) { print "defs.h.in has the following definitions not seen in your system llapi.h file. They have been removed from defs.h:\n\n"; foreach my $key ( keys %defs) { print "[$key] = $defs{$key},\n"; } print "\n"; } if ( -s "defs.h.new" ) { unlink "defs.h.old" if ( -f "defs.h.old"); rename "defs.h","defs.h.old" if ( -f "defs.h" ); rename "defs.h.new","defs.h"; } }