summaryrefslogtreecommitdiff
path: root/symbian/xsbuild.pl
diff options
context:
space:
mode:
Diffstat (limited to 'symbian/xsbuild.pl')
-rw-r--r--symbian/xsbuild.pl861
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);
+