#!/usr/bin/perl -w use strict; use Getopt::Long; use File::Basename; use Cwd; do "sanity.pl"; my $CoreBuild = -d "ext" && -f "perl.h" && -d "symbian" && -f "perl.c"; my $SymbianVersion; if (exists $ENV{EPOCROOT}) { if ($ENV{EPOCROOT} =~ m!\\Symbian\\UIQ_21\\$!i) { $SymbianVersion = '7.0s'; # TODO: other UIQ versions } elsif ($ENV{EPOCROOT} =~ m!\\Symbian\\(.+?)\\!i) { $SymbianVersion = $1; } } $SymbianVersion = $ENV{XSBUILD_SYMBIAN_VERSION} if exists $ENV{XSBUILD_SYMBIAN_VERSION}; my $PerlVersion = $ENV{XSBUILD_PERL_VERSION}; my $CSuffix = '.c'; my $CPlusPlus; my $Config; my $Build; my $Clean; my $DistClean; my $Sis; sub usage { die <<__EOF__; $0: Usage: $0 [--symbian=version] [--perl=version] [--extversion=x.y] [--csuffix=csuffix] [--cplusplus|--cpp] [--win=win] [--arm=arm] [--config|--build|--clean|--distclean|--sis] ext __EOF__ } my $CWD; my $SDK; my $VERSION; my $R_V_SV; my $PERLSDK; my $WIN = 'wins'; my $ARM = 'thumb'; my $BUILDROOT = getcwd(); if ( !defined $PerlVersion && $0 =~ m:\\symbian\\perl\\(.+)\\bin\\xsbuild.pl:i ) { $PerlVersion = $1; } if ( !defined $SymbianVersion) { ($SymbianVersion) = ($ENV{PATH} =~ m!\\Symbian\\(.+?)\\!i); } my ($SYMBIAN_ROOT, $SYMBIAN_VERSION, $SDK_NAME, $SDK_VARIANT, $SDK_VERSION); if ($CoreBuild) { unshift @INC, "symbian"; do "sanity.pl"; my %VERSION = %{ do "version.pl" }; ($SYMBIAN_ROOT, $SYMBIAN_VERSION, $SDK_NAME, $SDK_VARIANT, $SDK_VERSION) = @{ do "sdk.pl" }; $VERSION = "$VERSION{REVISION}$VERSION{VERSION}$VERSION{SUBVERSION}"; $R_V_SV = "$VERSION{REVISION}.$VERSION{VERSION}.$VERSION{SUBVERSION}"; $BUILDROOT = do "cwd.pl"; $PerlVersion = $R_V_SV; } my %CONF; usage() unless GetOptions( 'symbian=s' => \$SymbianVersion, 'perl=s' => \$PerlVersion, 'extversion=s' => \$CONF{EXTVERSION}, 'csuffix=s' => \$CSuffix, 'cplusplus|cpp' => \$CPlusPlus, 'win=s' => \$WIN, 'arm=s' => \$ARM, 'config' => \$Config, 'build' => \$Build, 'clean' => \$Clean, 'distclean' => \$DistClean, 'sis' => \$Sis ); usage() unless @ARGV; $CSuffix = '.cpp' if $CPlusPlus; $Build = !( $Config || $Clean || $DistClean ) || $Sis unless defined $Build; die "$0: Symbian version undefined\n" unless defined $SymbianVersion; $SymbianVersion =~ s:/:\\:g; die "$0: Symbian version '$SymbianVersion' not found\n" unless -d "\\Symbian\\$SymbianVersion"; die "$0: Perl version undefined\n" unless defined $PerlVersion; die "$0: Perl version '$PerlVersion' not found\n" if !$CoreBuild && !-d "\\Symbian\\Perl\\$PerlVersion"; print "Configuring with Symbian $SymbianVersion and Perl $PerlVersion...\n"; $PERLSDK = "\\Symbian\\Perl\\$PerlVersion"; $R_V_SV = $PerlVersion; $VERSION = $PerlVersion unless defined $VERSION; $VERSION =~ tr/.//d if defined $VERSION; $ENV{SDK} = $SYMBIAN_ROOT; # For the Errno extension $ENV{CROSS} = 1; # For the Encode extension (unbuilt now) my $UARM = 'urel'; my $UREL = "$SYMBIAN_ROOT\\epoc32\\release\\-ARM-\\$UARM"; my $SRCDBG; if (exists $ENV{UREL}) { $UREL = $ENV{UREL}; # from sdk.pl $UREL =~ s/-ARM-/$ARM/; $UARM = $ENV{UARM}; # from sdk.pl $SRCDBG = $UARM eq 'udeb' ? "SRCDBG" : ""; } my %EXTCFG; sub write_bld_inf { my ($base) = @_; print "\tbld.inf\n"; open( BLD_INF, ">bld.inf" ) or die "$0: bld.inf: $!\n"; print BLD_INF <<__EOF__; PRJ_MMPFILES $base.mmp PRJ_PLATFORMS $WIN $ARM __EOF__ close(BLD_INF); } sub system_echo { my $cmd = shift; print "xsbuild: ", $cmd, "\n"; return system($cmd); } sub run_PL { my ( $PL, $dir, $file ) = @_; if ( defined $file ) { print "\t(Running $dir\\$PL to create $file)\n"; unlink($file); } else { print "\t(Running $dir\\$PL)\n"; } my $cmd; if ($CoreBuild) { # Problem: the Config.pm we have in $BUILDROOT\\lib carries the # version number of the Perl we are building, while the Perl # we are running might have some other version. Solution: # temporarily replace the Config.pm with a patched version. my $V = sprintf "%vd", $^V; unlink("$BUILDROOT\\lib\\Config.pm.bak"); print "(patching $BUILDROOT\\lib\\Config.pm)\n"; system_echo("perl -pi.bak -e \"s:\\Q$R_V_SV:$V:\" $BUILDROOT\\lib\\Config.pm"); } system_echo("perl -I$BUILDROOT\\lib -I$BUILDROOT\\xlib\\symbian -I$BUILDROOT\\t\\lib $PL") == 0 or warn "$0: $PL failed.\n"; if ($CoreBuild) { system_echo("copy $BUILDROOT\\lib\\Config.pm.bak $BUILDROOT\\lib\\Config.pm"); } if ( defined $file ) { -s $file or die "$0: No $file created.\n" } } sub read_old_multi { my ( $conf, $k ) = @_; push @{ $conf->{$k} }, split( ' ', $1 ) if /^$k\s(.+)$/; } sub uniquefy_filenames { my $b = []; my %c = (); for my $i (@{$_[0]}) { $i =~ s!/!\\!g; $i = lc $i if $i =~ m!\\!; $i =~ s!^c:!!; push @$b, $i unless $c{$i}++; } return $b; } sub read_mmp { my ( $conf, $mmp ) = @_; if ( -r $mmp && open( MMP, "<$mmp" ) ) { print "\tReading $mmp...\n"; while () { chomp; $conf->{TARGET} = $1 if /^TARGET\s+(.+)$/; $conf->{TARGETPATH} = $1 if /^TARGETPATH\s+(.+)$/; $conf->{EXTVERSION} = $1 if /^EXTVERSION\s+(.+)$/; read_old_multi( $conf, "SOURCE" ); read_old_multi( $conf, "SOURCEPATH" ); read_old_multi( $conf, "USERINCLUDE" ); read_old_multi( $conf, "SYSTEMINCLUDE" ); read_old_multi( $conf, "LIBRARY" ); read_old_multi( $conf, "MACRO" ); } close(MMP); } } sub write_mmp { my ( $ext, $base, $userinclude, @src ) = @_; my $extdash = $ext; $extdash =~ s!\\!-!g; print "\t$base.mmp\n"; $CONF{TARGET} = "perl$VERSION-$extdash.dll"; $CONF{TARGETPATH} = "\\System\\Libs\\Perl\\$R_V_SV"; $CONF{SOURCE} = [@src]; $CONF{SOURCEPATH} = [ $CWD, $BUILDROOT ]; $CONF{USERINCLUDE} = [ $CWD, $BUILDROOT ]; $CONF{SYSTEMINCLUDE} = ["$PERLSDK\\include"] unless $CoreBuild; $CONF{SYSTEMINCLUDE} = [ $BUILDROOT, "$BUILDROOT\\symbian" ] if $CoreBuild; $CONF{LIBRARY} = []; $CONF{MACRO} = []; read_mmp( \%CONF, "_init.mmp" ); read_mmp( \%CONF, "$base.mmp" ); if ($base eq 'Zlib') { push @{$CONF{USERINCLUDE}}, "$CWD\\zlib-src"; } for my $ui ( @{$userinclude} ) { $ui =~ s!/!\\!g; if ( $ui =~ m!^(?:[CD]:)?\\! ) { push @{ $CONF{USERINCLUDE} }, $ui; } else { push @{ $CONF{USERINCLUDE} }, "$BUILDROOT\\$ui"; } } push @{ $CONF{SYSTEMINCLUDE} }, "\\epoc32\\include"; push @{ $CONF{SYSTEMINCLUDE} }, "\\epoc32\\include\\libc"; push @{ $CONF{LIBRARY} }, "euser.lib"; push @{ $CONF{LIBRARY} }, "estlib.lib"; push @{ $CONF{LIBRARY} }, "perl$VERSION.lib"; push @{ $CONF{MACRO} }, "SYMBIAN" unless $CoreBuild; push @{ $CONF{MACRO} }, "PERL_EXT" if $CoreBuild; push @{ $CONF{MACRO} }, "MULTIPLICITY"; push @{ $CONF{MACRO} }, "PERL_IMPLICIT_CONTEXT"; push @{ $CONF{MACRO} }, "PERL_GLOBAL_STRUCT"; push @{ $CONF{MACRO} }, "PERL_GLOBAL_STRUCT_PRIVATE"; if ($SDK_VARIANT eq 'S60') { push @{ $CONF{MACRO} }, '__SERIES60__' unless grep { $_ eq '__SERIES60__' } @{ $CONF{MACRO} }; } if ($SDK_VARIANT eq 'S80') { push @{ $CONF{MACRO} }, '__SERIES80__' unless grep { $_ eq '__SERIES80__' } @{ $CONF{MACRO} }; } if ($SDK_VARIANT eq 'UIQ') { push @{ $CONF{MACRO} }, '__UIQ__' unless grep { $_ eq '__UIQ__' } @{ $CONF{MACRO} }; } for my $u (qw(SOURCE SOURCEPATH SYSTEMINCLUDE USERINCLUDE LIBRARY MACRO)) { $CONF{$u} = uniquefy_filenames( $CONF{$u} ); } open( BASE_MMP, ">$base.mmp" ) or die "$0: $base.mmp: $!\n"; print BASE_MMP <<__EOF__; TARGET $CONF{TARGET} TARGETTYPE dll TARGETPATH $CONF{TARGETPATH} SOURCE @{$CONF{SOURCE}} $SRCDBG __EOF__ for my $u (qw(SOURCEPATH SYSTEMINCLUDE USERINCLUDE)) { for my $v ( @{ $CONF{$u} } ) { print BASE_MMP "$u\t$v\n"; } } # OPTION does not work in MMPs for pre-2.0 SDKs? print BASE_MMP <<__EOF__; LIBRARY @{$CONF{LIBRARY}} MACRO @{$CONF{MACRO}} // OPTION MSVC /P // Uncomment for creating .i (cpp'ed .cpp) // OPTION GCC -E // Uncomment for creating .i (cpp'ed .cpp) __EOF__ # if (-f "$base.rss") { # print BASE_MMP "RESOURCE\t$base.rss\n"; # } close(BASE_MMP); } sub write_makefile { my ( $base, $build ) = @_; print "\tMakefile\n"; my $windef1 = "$SYMBIAN_ROOT\\Epoc32\\Build$CWD\\$base\\$WIN\\$base.def"; my $windef2 = "..\\BWINS\\${base}u.def"; my $armdef1 = "$SYMBIAN_ROOT\\Epoc32\\Build$CWD\\$base\\$ARM\\$base.def"; my $armdef2 = "..\\BMARM\\${base}u.def"; my $wrap = $SYMBIAN_ROOT && defined $SDK_VARIANT eq 'S60' && $SDK_VERSION eq '1.2' && $SYMBIAN_ROOT !~ /_CW$/; my $ABLD = $wrap ? 'perl b.pl' : 'abld'; open( MAKEFILE, ">Makefile" ) or die "$0: Makefile: $!\n"; print MAKEFILE <<__EOF__; WIN = $WIN ARM = $ARM ABLD = $ABLD all: build freeze sis: build_arm freeze_arm build: abld.bat build_win build_arm abld.bat: bldmake bldfiles build_win: abld.bat bldmake bldfiles \$(ABLD) build \$(WIN) udeb build_arm: abld.bat bldmake bldfiles \$(ABLD) build \$(ARM) $UARM win: build_win freeze_win arm: build_arm freeze_arm freeze: freeze_win freeze_arm freeze_win: bldmake bldfiles \$(ABLD) freeze \$(WIN) $base freeze_arm: bldmake bldfiles \$(ABLD) freeze \$(ARM) $base defrost: defrost_win defrost_arm defrost_win: -del /f $windef1 -del /f $windef2 defrost_arm: -del /f $armdef1 -del /f $armdef2 clean: clean_win clean_arm clean_win: \$(ABLD) clean \$(WIN) clean_arm: \$(ABLD) clean \$(ARM) realclean: clean realclean_win realclean_arm -del /f _init.c b.pl -del /f $base.c $base.mmp realclean_win: \$(ABLD) reallyclean \$(WIN) realclean_arm: \$(ABLD) reallyclean \$(ARM) distclean: defrost realclean -rmdir ..\\BWINS ..\\BMARM -del /f const-c.inc const-xs.inc -del /f Makefile abld.bat bld.inf __EOF__ close(MAKEFILE); if ($wrap) { if(open(B,">b.pl")) { print B <<'__EOF__'; # abld.pl wrapper. # nmake doesn't like MFLAGS and MAKEFLAGS being set to -w and w. delete $ENV{MFLAGS}; delete $ENV{MAKEFLAGS}; print "abld @ARGV\n"; system_echo("abld @ARGV"); __EOF__ close(B); } else { warn "$0: failed to create b.pl: $!\n"; } } } sub update_dir { print "[chdir from ", getcwd(), " to "; chdir(shift) or return; update_cwd(); print getcwd(), "]\n"; } sub xsconfig { my ( $ext, $dir ) = @_; print "Configuring for $ext, directory '$dir'...\n"; my $extu = $CoreBuild ? "$BUILDROOT\\lib\\ExtUtils" : "$PERLSDK\\lib\\ExtUtils"; update_dir($dir) or die "$0: chdir '$dir': $!\n"; my $build = dirname($ext); my $base = basename($ext); my $basexs = "$base.xs"; my $basepm = "$base.pm"; my $basec = "$base$CSuffix"; my $extdir = "."; if ( $dir =~ m:^ext\\(.+): ) { $extdir = $1; } elsif ( $dir ne "." ) { $extdir = $dir; } my $extdirdir = dirname($extdir); my $targetroot = "\\System\\Libs\\Perl\\$R_V_SV"; write_bld_inf($base) if -f $basexs; my %src; $src{$basec}++; $extdirdir = $extdirdir eq "." ? "" : "$extdirdir\\"; my $extdash = $ext; $extdash =~ s!\\!-!g; my %lst; $lst{"$UREL\\perl$VERSION-$extdash.dll"} = "$targetroot\\$ARM-symbian\\$base.dll" if -f $basexs; $lst{"$dir\\$base.pm"} = "$targetroot\\$extdirdir$base.pm" if -f $basepm && $base ne 'XSLoader'; my %incdir; my $ran_PL; if ( -d 'lib' ) { use File::Find; my @found; find( sub { push @found, $File::Find::name if -f $_ }, 'lib' ); for my $found (@found) { next if $found =~ /\.bak$/i; # Zlib my ($short) = ( $found =~ m/^lib.(.+)/ ); $short =~ s!/!\\!g; $found =~ s!/!\\!g; $lst{"$dir\\$found"} = "$targetroot\\$short"; } } if ( my @pm = glob("*.pm */*.pm") ) { for my $pm (@pm) { next if $pm =~ m:^t/:; $pm =~ s:/:\\:g; $lst{"$dir\\$pm"} = "$targetroot\\$extdirdir$pm"; } } if ( my @c = glob("*.c *.cpp */*.c */*.cpp") ) { @c = grep { ! m:^zlib-src/: } @c if $ext eq 'ext\Compress\Zlib'; for my $c (@c) { $c =~ s:/:\\:g; $src{$c}++; } } if ( my @h = glob("*.h */*.h") ) { @h = grep { ! m:^zlib-src/: } @h if $ext eq 'ext\Compress\Zlib'; for my $h (@h) { $h =~ s:/:\\:g; $h = dirname($h); $incdir{"$dir\\$h"}++ unless $h eq "."; } } if ( exists $EXTCFG{$ext} ) { for my $cfg ( @{ $EXTCFG{$ext} } ) { if ( $cfg =~ /^([-+])?(.+\.(c|cpp|h))$/ ) { my $o = defined $1 ? $1 : '+'; my $f = $2; $f =~ s:/:\\:g; for my $f ( glob($f) ) { if ( $o eq '+' ) { warn "$0: no source file $dir\\$f\n" unless -f $f; $src{$f}++ unless $cfg =~ /\.h$/; if ( $f =~ m:^(.+)\\[^\\]+$: ) { $incdir{$1}++; } } elsif ( $o eq '-' ) { delete $src{$f}; } } } if ( $cfg =~ /^([-+])?(.+\.(pm|pl|inc))$/ ) { my $o = defined $1 ? $1 : '+'; my $f = $2; $f =~ s:/:\\:g; for my $f ( glob($f) ) { if ( $o eq '+' ) { warn "$0: no Perl file $dir\\$f\n" unless -f $f; $lst{"$dir\\$f"} = "$targetroot\\$extdir\\$f"; } elsif ( $o eq '-' ) { delete $lst{"$dir\\$f"}; } } } if ( $cfg eq 'CONST' && !$ran_PL++ ) { run_PL( "Makefile.PL", $dir, "const-xs.inc" ); } } } unless ( $ran_PL++ ) { run_PL( "Makefile.PL", $dir ) if -f "Makefile.PL"; } if ( $dir eq "ext\\Errno" ) { run_PL( "Errno_pm.PL", $dir, "Errno.pm" ); $lst{"$dir\\Errno.pm"} = "$targetroot\\Errno.pm"; } elsif ( $dir eq "ext\\Devel\\PPPort" ) { run_PL( "ppport_h.PL", $dir, "ppport.h" ); } elsif ( $dir eq "ext\\DynaLoader" ) { run_PL( "XSLoader_pm.PL", $dir, "XSLoader.pm" ); $lst{"ext\\DynaLoader\\XSLoader.pm"} = "$targetroot\\XSLoader.pm"; } elsif ( $dir eq "ext\\Encode" ) { system_echo("perl bin\\enc2xs -Q -O -o def_t.c -f def_t.fnm") == 0 or die "$0: running enc2xs failed: $!\n"; } my @lst = sort keys %lst; read_mmp( \%CONF, "_init.mmp" ); read_mmp( \%CONF, "$base.mmp" ); if ( -f $basexs ) { my %MM; # MakeMaker results my @MM = qw(VERSION XS_VERSION); if ( -f "Makefile" ) { print "\tReading MakeMaker Makefile...\n"; if ( open( MAKEFILE, "Makefile" ) ) { while () { for my $m (@MM) { if (m!^$m = (.+)!) { $MM{$m} = $1; print "\t$m = $1\n"; } } } close(MAKEFILE); } else { warn "$0: Makefile: $!"; } print "\tDeleting MakeMaker Makefile.\n"; unlink("Makefile"); } unlink($basec); print "\t$basec\n"; if ( defined $CONF{EXTVERSION} ) { my $EXTVERSION = $CONF{EXTVERSION}; print "\tUsing $EXTVERSION for version...\n"; $MM{VERSION} = $MM{XS_VERSION} = $EXTVERSION; } die "$0: VERSION or XS_VERSION undefined\n" unless defined $MM{VERSION} && defined $MM{XS_VERSION}; if ( open( BASE_C, ">$basec" ) ) { print BASE_C <<__EOF__; #ifndef VERSION #define VERSION "$MM{VERSION}" #endif #ifndef XS_VERSION #define XS_VERSION "$MM{XS_VERSION}" #endif __EOF__ close(BASE_C); } else { warn "$0: $basec: $!"; } unless ( system_echo( "perl -I$BUILDROOT\\lib -I$PERLSDK\\lib $extu\\xsubpp -csuffix .cpp -typemap $extu\\typemap -noprototypes $basexs >> $basec" ) == 0 && -s $basec ) { die "$0: perl xsubpp failed: $!\n"; } print "\t_init.c\n"; open( _INIT_C, ">_init.c" ) or die "$!: _init.c: $!\n"; print _INIT_C <<__EOF__; #include "EXTERN.h" #include "perl.h" EXPORT_C void _init(void *handle) { } __EOF__ close(_INIT_C); my @src = ( "_init.c", sort keys %src ); if ( $base eq "Encode" ) { # Currently unused. for my $submf ( glob("*/Makefile") ) { my $d = dirname($submf); print "Configuring Encode::$d...\n"; if ( open( SUBMF, $submf ) ) { if ( update_dir($d) ) { my @subsrc; while () { next if 1 .. /postamble/; if (m!^(\w+_t)\.c : !) { system_echo( "perl ..\\bin\\enc2xs -Q -o $1.c -f $1.fnm") == 0 or warn "$0: enc2xs: $!\n"; push @subsrc, "$1.c"; } } close(SUBMF); unlink($submf); my $subbase = $d; $subbase =~ s!/!::!g; write_mmp( $ext, $subbase, ["..\\Encode"], "$subbase.c", @subsrc ); write_makefile( $subbase, $build ); write_bld_inf($subbase); unless ( system_echo( "perl -I$BUILDROOT\\lib ..\\$extu\\xsubpp -csuffix .cpp -typemap ..\\$extu\\typemap -noprototypes $subbase.xs > $subbase.c" ) == 0 && -s "$subbase.c" ) { die "$0: perl xsubpp failed: $!\n"; } update_dir(".."); } else { warn "$0: chdir $d: $!\n"; } } else { warn "$0: $submf: $!"; } } print "Configuring Encode...\n"; } write_mmp( $ext, $base, [ keys %incdir ], @src ); write_makefile( $base, $build ); } my $lstname = $ext; $lstname =~ s:^ext\\::; $lstname =~ s:\\:-:g; print "\t$lstname.lst\n"; my $lstout = $CoreBuild ? "$BUILDROOT/symbian/$lstname.lst" : "$BUILDROOT/$lstname.lst"; if ( open( my $lst, ">$lstout" ) ) { for my $f (@lst) { print $lst qq["$f"-"!:$lst{$f}"\n] } close($lst); } else { die "$0: $lstout: $!\n"; } update_dir($BUILDROOT); } sub update_cwd { $CWD = getcwd(); $CWD =~ s!^[CD]:!!i; $CWD =~ s!/!\\!g; } for my $ext (@ARGV) { $ext =~ s!::!\\!g; my $extdash = $ext =~ /ext\\/ ? $ext : "ext\\$ext"; $extdash =~ s!\\!-!g; $ext =~ s!/!\\!g; my $cfg; $cfg = $2 if $ext =~ s/(.+?),(.+)/$1/; my $dir; unless ( -e $ext ) { if ( $ext =~ /\.xs$/ && !-f $ext ) { if ( -f "ext\\$ext" ) { $ext = "ext\\$ext"; $dir = dirname($ext); } } elsif ( !-d $ext ) { if ( -d "ext\\$ext" ) { $ext = "ext\\$ext"; $dir = $ext; } } $dir = "." unless defined $dir; } else { if ( $ext =~ /\.xs$/ && -f $ext ) { $ext = dirname($ext); $dir = $ext; } elsif ( -d $ext ) { $dir = $ext; } } if ( $ext eq "XSLoader" ) { $ext = "ext\\XSLoader"; } if ( $ext eq "ext\\XSLoader" ) { $dir = "ext\\DynaLoader"; } $EXTCFG{$ext} = [ split( /,/, $cfg ) ] if defined $cfg; die "$0: no lib\\Config.pm\n" if $CoreBuild && $Build && !-f "lib\\Config.pm"; if ($CoreBuild) { open( my $cfg, "symbian/install.cfg" ) or die "$0: symbian/install.cfg: $!\n"; my $extdir = $dir; $extdir =~ s:^ext\\::; while (<$cfg>) { next unless /^ext\s+(.+)/; chomp; my $ext = $1; my @ext = split( ' ', $ext ); $EXTCFG{"ext\\$ext[0]"} = [@ext]; } close($cfg); } if ( $Config || $Build ) { xsconfig( $ext, $dir ) or die "$0: xsconfig '$ext' failed\n"; next if $Config; } if ($dir eq ".") { warn "$0: No directory for $ext, skipping...\n"; next; } my $chdir = $ext eq "ext\\XSLoader" ? "ext\\DynaLoader" : $dir; die "$0: no directory '$chdir'\n" unless -d $chdir; update_dir($chdir) or die "$0: chdir '$chdir' failed: $!\n"; my %CONF; my @ext = split( /\\/, $ext ); my $base = $ext[-1]; if ( $Clean || $DistClean ) { print "Cleaning $ext...\n"; unlink("bld.inf"); unlink("$base.mmp"); unlink("_init.c"); unlink("const-c.inc"); unlink("const-xs.inc"); rmdir("..\\bmarm"); } if ( $Build && $ext ne "ext\\XSLoader" && $ext ne "ext\\Errno" ) { # We compile the extension three (3) times. # (1) Only the _init.c to get _init() as the ordinal 1 function in the DLL. # (2) With the rest and the _init.c to get ordinals for the rest. # (3) With an updated _init.c that carries the symbols from step (2). system_echo("make clean"); system_echo("make defrost") == 0 or warn "$0: make defrost failed\n"; my @TARGET; push @TARGET, 'sis' if $Sis; # Compile #1. # Hide all but the _init.c. print "\n*** $ext - Compile 1 of 3.\n\n"; print "(patching $base.mmp)\n"; system( "perl -pi.bak -e \"s:^SOURCE\\s+_init.c:SOURCE\\t_init.c // :\" $base.mmp" ); system_echo("bldmake bldfiles"); system_echo("make @TARGET") == 0 or die "$0: make #1 failed\n"; # Compile #2. # Reveal the rest again. print "\n*** $ext - Compile 2 of 3.\n\n"; print "(patching $base.mmp)\n"; system( "perl -pi.bak -e \"s:^SOURCE\\t_init.c // :SOURCE\\t_init.c :\" $base.mmp" ); system_echo("make @TARGET") == 0 or die "$0: make #2 failed\n"; unlink("$base.mmp.bak"); open( _INIT_C, ">_init.c" ) or die "$0: _init.c: $!\n"; print _INIT_C <<'__EOF__'; #include "EXTERN.h" #include "perl.h" /* This is a different but matching definition from in dl_symbian.xs. */ typedef struct { void* handle; int error; HV* symbols; } PerlSymbianLibHandle; EXPORT_C void _init(void* handle) { __EOF__ my %symbol; my $def; my $basef; for my $f ("$SYMBIAN_ROOT\\Epoc32\\Build$CWD\\$base\\WINS\\perl$VERSION-$extdash.def", "..\\BMARM\\perl$VERSION-${extdash}u.def") { print "\t($f - "; if ( open( $def, $f ) ) { print "OK)\n"; $basef = $f; last; } else { print "no)\n"; } } unless (defined $basef) { die "$0: failed to find .def for $base\n"; } while (<$def>) { next while 1 .. /^EXPORTS/; if (/^\s*(\w+) \@ (\d+) /) { $symbol{$1} = $2; } } close($def); my @symbol = sort keys %symbol; if (@symbol) { print _INIT_C <<'__EOF__'; dTHX; PerlSymbianLibHandle* h = (PerlSymbianLibHandle*)handle; if (!h->symbols) h->symbols = newHV(); if (h->symbols) { __EOF__ for my $sym (@symbol) { my $len = length($sym); print _INIT_C <<__EOF__; hv_store(h->symbols, "$sym", $len, newSViv($symbol{$sym}), 0); __EOF__ } } else { die "$0: $basef: no exports found\n"; } print _INIT_C <<'__EOF__'; } } __EOF__ close(_INIT_C); # Compile #3. This is for real. print "\n*** $ext - Compile 3 of 3.\n\n"; system_echo("make @TARGET") == 0 or die "$0: make #3 failed\n"; } elsif ( $Clean || $DistClean ) { if ( $ext eq "ext\\Errno" ) { unlink( "Errno.pm", "Makefile" ); } else { if ( -f "Makefile" ) { if ($Clean) { system_echo("make clean") == 0 or die "$0: make clean failed\n"; } elsif ($DistClean) { system_echo("make distclean") == 0 or die "$0: make distclean failed\n"; } } if ( $ext eq "ext\\Compress\\Zlib" ) { my @bak; find( sub { push @bak, $File::Find::name if /\.bak$/ }, "." ); unlink(@bak) if @bak; my @src; find( sub { push @src, $_ if -f $_ }, "zlib-src" ); unlink(@src) if @src; unlink("constants.xs"); } if ( $ext eq "ext\\Devel\\PPPort" ) { unlink("ppport.h"); } } my @D = glob("../BMARM/*.def ../BWINS/*.def"); unlink(@D) if @D; my @B = glob("ext/BWINS ext/BMARM ext/*/BWINS ext/*/BMARM Makefile"); rmdir(@B) if @B; } update_dir($BUILDROOT); } # for my $ext exit(0);