#******************************************************************************* # Copyright (c) 1997-2007, Perforce Software, Inc. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL PERFORCE SOFTWARE, INC. BE LIABLE FOR ANY # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #******************************************************************************* use ExtUtils::MakeMaker; use Getopt::Long; use File::Copy; use English; use Cwd; use Cwd 'abs_path'; use Config; use strict; #$ExtUtils::MakeMaker::Verbose = 1; # This is the version of the API that this build of P4Perl supports. our $TARGET_API_VERSION = encode_api_version( "2007.3" ); our $APIDIR = undef; our $P4PORT = undef; our $P4API_VERSION = undef; our $P4PERL_VERSION = undef; our $P4PERL_PATCHLEVEL = undef; our $P4PERL_PLAT = undef; our $P4PERL_OS = undef; our $P4PERL_OSVER = undef; our @P4PERL_DATE = undef; our $RELNOTES_PATH = '../p4-doc/user/p4perlnotes.txt'; # # Check the Perforce API version from the Version file # sub extract_api_version { my $path = shift; my $cwd = getcwd(); foreach my $vfile ( "$path/Version", "$path/sample/Version" ) { next unless ( -e $vfile ); open( VF, $vfile ) or die( "Can't open $vfile" ); while( ) { if( /^RELEASE = (.*) ;/ ) { $P4API_VERSION = $1; $P4API_VERSION =~ s/ /./g; last; } } close( FH ); } my $tries = 3; while( !defined( $P4API_VERSION ) && --$tries ) { print( "Unable to determine API version string\n" ); print( "Enter API version: " ); $P4API_VERSION = ; } die( "Aborting: API version not provided" ) unless $P4API_VERSION; printf( "Found %s Perforce API in %s\n", $P4API_VERSION, $path ); return $P4API_VERSION; } # # Encode an API version string into an integer # sub encode_api_version( $ ) { my $vs = shift; if( defined $vs && $vs =~ /^(\d+)(\.|\s)(\d+)/ ) { return (($1 << 8 ) | $3 ); } return undef; } sub api_major( $ ) { my $v = shift; return $v >> 8; } sub api_minor( $ ) { my $v = shift; return $v & 0xff; } sub is_api_dir( $ ) { my $dir = shift; return 0 unless ( -d $dir ); return 1 if( -e "$dir/Version" ); return 1 if( -e "$dir/sample/Version" ); return 0; } # # Check that they're using the API version we want. # sub check_api_version( $ ) { my $api_ver = shift; my $api_name = sprintf( "%d.%d", api_major( $TARGET_API_VERSION ), api_minor( $TARGET_API_VERSION ) ); $api_ver = encode_api_version( $api_ver ); return 1 if( $api_ver == $TARGET_API_VERSION ); print <; chomp( $answer ); return 0 unless $answer eq "y"; return 1; } sub get_api_dir() { if( defined( $APIDIR ) && is_api_dir( $APIDIR ) ) { return $APIDIR; } # Get the path to the Perforce API my $apipath = undef; my $tries = 3; $apipath = $APIDIR if( defined( $APIDIR ) ); while( !defined( $apipath ) && --$tries ) { print( "Enter the path to the Perforce API: " ); $apipath = ; $apipath =~ s/\n//; # Filthy support for ~/ type paths ( NOT ~user/ though! ) $apipath =~ s#\~/#$ENV{HOME}/#; $apipath = abs_path( $apipath ); $apipath = undef unless( is_api_dir( $apipath ) ); } die ( "Aborting - no API directory provided" ) unless $apipath; return $apipath; } sub define( $$;$$ ) { my $href = shift; my $var = shift; my $val = shift; my $string = shift; if( !$val ) { $href->{ 'DEFINE' } .= qq{ -D$var}; } elsif( $string ) { $href->{ 'DEFINE' } .= qq{ -D$var="\\"$val\\""}; } else { $href->{ 'DEFINE' } .= qq{ -D$var="$val"}; } } # # Add the Perforce libraries to the linker configuration # sub add_p4_libs( $$$ ) { my $cfg = shift; # Perl's pre-set config my $flags = shift; # Flags we want to add my $apidir = shift; # Our API directory my $libdir = $apidir; $libdir = "$libdir/lib" if( -d "$libdir/lib" ); $flags->{'LIBS'} = []; if( defined( $cfg->{LIBS} ) ) { my $libs = $cfg->{LIBS}; foreach my $libset (@$libs ) { push( @{$flags->{LIBS}}, "-L$libdir -lclient -lrpc -lsupp $libset" ); } } else { push( @{$flags->{LIBS}}, "-L$libdir -lclient -lrpc -lsupp" ); } } # # Add the Perforce headers to the includes # sub add_p4_hdrs( $$ ) { my $flags = shift; my $apipath = shift; $apipath = "$apipath/include/p4" if( -d "$apipath/include/p4" ); $flags->{ 'INC' } = "-I$apipath -Ilib"; } sub identify_p4perl() { open( VF, "p4perl_version" ) or die( "Can't open p4perl_version file!" ); while( ) { if( /^RELEASE\s*=\s*([[:alnum:] ]+)/ ) { $P4PERL_VERSION = $1; $P4PERL_VERSION =~ s/ +$//; $P4PERL_VERSION =~ s/ +/./g; } elsif( /^PATCHLEVEL\s*=\s*(\d+)/ ) { $P4PERL_PATCHLEVEL = $1; } elsif( /^SUPPDATE\s*=\s*([0-9 ]+)/ ) { @P4PERL_DATE = split( / +/, $1 ); } } close( VF ); } # # Work out what platform we're on. What's in here is stuff that we have # to do on all platforms - anything that's specific to one platform should # go in its hints file. # sub identify_platform( $ ) { my $href = shift; # Read $Config{ 'archname' ), which looks like this: # # i86pc-solaris-64int (solaris10x86_64 ) # x86_64-linux-gnu-thread-multi (linux26x86_64) # MSWin32-x86-multi-thread (ntx86) - note os/plat reversal!!! # # So, we get the osname from Config, then we use whichever of the # first two fields in archname is NOT the os as the platform. # my $os = $Config{ 'osname' }; my @fields = split( /-/, $Config{ 'archname' } ); $P4PERL_PLAT = $fields[ 0 ] if( $os eq $fields[ 1 ] ); $P4PERL_PLAT = $fields[ 1 ] if( $os eq $fields[ 0 ] ); # Now convert the platform identifier to Perforce style for known # differences in terminology $P4PERL_PLAT = "x86" if( $P4PERL_PLAT =~ "[xi]86pc" ); $P4PERL_PLAT = "sparc" if( $P4PERL_PLAT =~ /sun/ ); $P4PERL_PLAT = uc( $P4PERL_PLAT ); # Now convert the OS to Perforce style for known differences. $os = "NT" if( $os eq "MSWin32" ); # Default is our guestimate. $P4PERL_OS = uc( $os ); # Identify the OS version. We take the first two numbers in the # dotted string. On NT, we don't bother. if( $os eq "NT" ) { $P4PERL_OSVER=""; } else { $P4PERL_OSVER = $Config{ 'osvers' }; $P4PERL_OSVER =~ s/^(\d+)\.(\d+).*/\1\2/; } # # Override any derived values with hints from the hints file for the # platform # if( defined( $href->{ 'P4PERL_OS_HINT' } ) ) { $P4PERL_OS = $href->{ 'P4PERL_OS_HINT' }; delete( $href->{ 'P4PERL_OS_HINT' } ); } if( defined( $href->{ 'P4PERL_PLAT_HINT' } ) ) { $P4PERL_PLAT = $href->{ 'P4PERL_PLAT_HINT' }; delete( $href->{ 'P4PERL_PLAT_HINT' } ); } if( defined( $href->{ 'P4PERL_OSVER_HINT' } ) ) { $P4PERL_OSVER = $href->{ 'P4PERL_OSVER_HINT' }; delete( $href->{ 'P4PERL_OSVER_HINT' } ); } } # # This sub adds the Perforce API path to the header includes and libs # used by the compiler. It's called by WriteMakefile. # sub config_sub { my $class = shift; my $href = shift; # Work out what platform we're running on, and the P4Perl version identify_platform( $href ); # Define Ident macros my $id_os = $P4PERL_OS . $P4PERL_OSVER . $P4PERL_PLAT; define( $href, "ID_OS", $id_os, 1 ); define( $href, "ID_REL", $P4PERL_VERSION, 1 ); define( $href, "ID_PATCH", $P4PERL_PATCHLEVEL, 1 ); define( $href, "ID_Y", $P4PERL_DATE[ 0 ], 1 ); define( $href, "ID_M", $P4PERL_DATE[ 1 ], 1 ); define( $href, "ID_D", $P4PERL_DATE[ 2 ], 1 ); # Define OS_* macros define( $href, "OS_$P4PERL_OS" ); define( $href, "OS_${P4PERL_OS}${P4PERL_OSVER}" ); define( $href, "OS_${P4PERL_OS}${P4PERL_OSVER}${P4PERL_PLAT}" ); define( $href, "OS_${P4PERL_OS}${P4PERL_PLAT}" ); # Now find the API! my $flags = {}; # Get the path to the Perforce API my $apipath = get_api_dir(); # dies if API not found extract_api_version( $apipath ); # # Abort if the user's decided not to press ahead with a newer # version of the API than this version was written for # exit( 1 ) unless ( check_api_version( $P4API_VERSION ) ); define( $href, "P4API_VERSION", encode_api_version( $P4API_VERSION ) ); define( $href, "ID_API", $P4API_VERSION, 1 ); add_p4_libs( $href, $flags, $apipath ); add_p4_hdrs( $flags, $apipath ); # # Handle renaming the distribution to our standard filename # convention # if( $P4PERL_OS eq 'NT' ) { $flags->{ 'POSTOP' } = "ren p4perl-${P4PERL_VERSION}.tar.gz p4perl.tar.gz"; } else { $flags->{ 'POSTOP' } = "mv -f p4perl-${P4PERL_VERSION}.tar.gz p4perl.tar.gz"; } return $flags; } # Ensure that the clientuserperl interface gets built. sub MY::postamble { ' $(MYEXTLIB): lib/Makefile cd lib && $(MAKE) $(PASSTHRU) '; } #******************************************************************************* #* START OF MAIN SCRIPT #******************************************************************************* identify_p4perl(); my %flags = ( 'NAME' => 'P4', 'VERSION' => $P4PERL_VERSION, 'PREREQ_PM' => {}, # e.g., Module::Name => 1.1 'MYEXTLIB' => 'lib/libp4$(LIB_EXT)', 'XSOPT' => '-C++ -prototypes', 'CONFIGURE' => \&config_sub, 'DISTNAME' => 'p4perl', 'PL_FILES' => { }, 'clean' => { 'FILES' => [ qw( p4perl.tar.gz ) ] }, ); my $result = GetOptions ( "apidir=s" => \$APIDIR, "p4port=s" => \$P4PORT ); # # Ensure that the release notes are copied in from the p4-doc # tree if it exists. If not, we'll check that we have the release # notes in place already and warn the user if that's not the case. # if( -f $RELNOTES_PATH ) { printf( "Copying release notes from p4-doc tree...\n" ); copy( $RELNOTES_PATH, "RELNOTES.txt" ); # Remove RELNOTES.txt on 'make distclean'. This will cause # a manifest check warning, but it keeps the tree tidy. push( @{$flags{ 'clean' }->{ 'FILES' }}, "RELNOTES.txt" ); } elsif( ! -f "RELNOTES.txt" ) { warn( "The P4Perl release notes are missing." ); warn( "Proceeding anyway." ); } # # Now invoke MakeMaker to build the makefile # WriteMakefile( %flags );