diff options
Diffstat (limited to 'symbian/xsbuild.pl')
-rw-r--r-- | symbian/xsbuild.pl | 861 |
1 files changed, 861 insertions, 0 deletions
diff --git a/symbian/xsbuild.pl b/symbian/xsbuild.pl new file mode 100644 index 0000000000..ff743bda79 --- /dev/null +++ b/symbian/xsbuild.pl @@ -0,0 +1,861 @@ +#!/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 = $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] + [--csuffix=csuffix] [--cplusplus] + [--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; +my $ARM; +my $HOME = getcwd(); + +if ( !defined $PerlVersion && $0 =~ m:\\symbian\\perl\\(.+)\\bin\\xsbuild.pl:i ) +{ + $PerlVersion = $1; +} + +if ( !defined $SymbianVersion) { + ($SymbianVersion) = ($ENV{PATH} =~ m!C:\\Symbian\\(.+?)\\!i); +} + +my $S60SDK; + +if ($CoreBuild) { + unshift @INC, "symbian"; + do "sanity.pl"; + my %VERSION = %{ do "version.pl" }; + $SDK = do "sdk.pl"; + $VERSION = "$VERSION{REVISION}$VERSION{VERSION}$VERSION{SUBVERSION}"; + $R_V_SV = "$VERSION{REVISION}.$VERSION{VERSION}.$VERSION{SUBVERSION}"; + $HOME = do "cwd.pl"; + $SymbianVersion = $1 if $SDK =~ m:\\Symbian\\([^\\]+):; + $PerlVersion = $R_V_SV; + $S60SDK = $ENV{S60SDK}; # from sdk.pl +} + +usage() + unless GetOptions( + 'symbian=s' => \$SymbianVersion, + 'perl=s' => \$PerlVersion, + 'csuffix=s' => \$CSuffix, + 'cplusplus' => \$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"; + +$SDK = "\\Symbian\\$SymbianVersion" unless defined $SDK; +$PERLSDK = "\\Symbian\\Perl\\$PerlVersion"; + +$R_V_SV = $PerlVersion; + +$VERSION =~ tr/.//d; + +$ENV{SDK} = $SDK; # For the Errno extension +$ENV{CROSS} = 1; # For the Encode extension + +my $UREL = $ENV{UREL}; # from sdk.pl +$UREL =~ s/-ARM-/$ARM/; +my $UARM = $ENV{UARM}; # from sdk.pl +my $SRCDBG = $UARM eq 'udeb' ? "SRCDBG" : ""; + +my %CONF; +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 $HOME\\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("$HOME\\lib\\Config.pm.bak"); + system_echo("perl -pi.bak -e \"s:\\Q$R_V_SV:$V:\" $HOME\\lib\\Config.pm"); + } + system_echo("perl -I$HOME\\lib -I$HOME\\xlib\\symbian $PL") == 0 + or warn "$0: $PL failed.\n"; + if ($CoreBuild) { + system_echo("copy $HOME\\lib\\Config.pm.bak $HOME\\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 (<MMP>) { + 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 ( $base, $userinclude, @src ) = @_; + + print "\t$base.mmp\n"; + $CONF{TARGET} = "$base.dll"; + $CONF{TARGETPATH} = "\\System\\Libs\\Perl\\$R_V_SV"; + $CONF{SOURCE} = [@src]; + $CONF{SOURCEPATH} = [ $CWD, $HOME ]; + $CONF{USERINCLUDE} = [ $CWD, $HOME ]; + $CONF{SYSTEMINCLUDE} = ["$PERLSDK\\include"] unless $CoreBuild; + $CONF{SYSTEMINCLUDE} = [ $HOME ] if $CoreBuild; + $CONF{LIBRARY} = []; + $CONF{MACRO} = []; + read_mmp( \%CONF, "_init.mmp" ); + read_mmp( \%CONF, "$base.mmp" ); + + for my $ui ( @{$userinclude} ) { + $ui =~ s!/!\\!g; + if ( $ui =~ m!^(?:[CD]:)?\\! ) { + push @{ $CONF{USERINCLUDE} }, $ui; + } + else { + push @{ $CONF{USERINCLUDE} }, "$HOME\\$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"; + + 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 +// OPTION GCC -E +__EOF__ + close(BASE_MMP); + +} + +sub write_makefile { + my ( $base, $build ) = @_; + + print "\tMakefile\n"; + + my $windef1 = "$SDK\\Epoc32\\Build$CWD\\$base\\$WIN\\$base.def"; + my $windef2 = "..\\BWINS\\${base}u.def"; + my $armdef1 = "$SDK\\Epoc32\\Build$CWD\\$base\\$ARM\\$base.def"; + my $armdef2 = "..\\BMARM\\${base}u.def"; + + my $wrap = $SDK && $S60SDK eq '1.2' && $SDK !~ /_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("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 ? "$HOME\\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 %lst; + $lst{"$UREL\\$base.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) { + 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") ) { + for my $c (@c) { + $c =~ s:/:\\:g; + $src{$c}++; + } + } + if ( my @h = glob("*.h */*.h") ) { + 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 (<MAKEFILE>) { + 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 "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( +"perl -I$PERLSDK\\lib $extu\\xsubpp -C++ -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 (<SUBMF>) { + next if 1 .. /postamble/; + if (m!^(\w+_t)\.c : !) { + system( + "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( $subbase, ["..\\Encode"], "$subbase.c", + @subsrc ); + write_makefile( $subbase, $build ); + write_bld_inf($subbase); + + unless ( + system( +"perl -I$HOME\\lib ..\\$extu\\xsubpp -C++ -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( $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 ? "$HOME/symbian/$lstname.lst" : "$HOME/$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($HOME); +} + +sub update_cwd { + $CWD = getcwd(); + $CWD =~ s!^[CD]:!!i; + $CWD =~ s!/!\\!g; +} + +for my $ext (@ARGV) { + + $ext =~ 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; + } + + 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("make clean"); + system("make defrost") == 0 or die "$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"; + system( +"perl -pi.bak -e \"s:^SOURCE\\s+_init.c:SOURCE\\t_init.c // :\" $base.mmp" + ); + system("bldmake bldfiles"); + system("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"; + system( +"perl -pi.bak -e \"s:^SOURCE\\t_init.c // :SOURCE\\t_init.c :\" $base.mmp" + ); + system("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 ("$SDK\\Epoc32\\Build$CWD\\$base\\WINS\\$base.def", + "..\\BMARM\\${base}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("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("make clean") == 0 or die "$0: make clean failed\n"; + } + elsif ($DistClean) { + system("make distclean") == 0 + or die "$0: make distclean failed\n"; + } + } + if ( $ext eq "ext\\Devel\\PPPort" ) { + unlink("ppport.h"); + } + } + my @B = glob("ext/BWINS ext/BMARM ext/*/BWINS ext/*/BMARM Makefile"); + rmdir(@B) if @B; + } + + update_dir($HOME); + +} # for my $ext + +exit(0); + |