11 my $CoreBuild = -d "ext" && -f "perl.h" && -d "symbian" && -f "perl.c";
13 my $SymbianVersion = $ENV{XSBUILD_SYMBIAN_VERSION};
14 my $PerlVersion = $ENV{XSBUILD_PERL_VERSION};
25 $0: Usage: $0 [--symbian=version] [--perl=version]
26 [--csuffix=csuffix] [--cplusplus]
27 [--win=win] [--arm=arm]
28 [--config|--build|--clean|--distclean|--sis] ext
41 if ( !defined $PerlVersion && $0 =~ m:\\symbian\\perl\\(.+)\\bin\\xsbuild.pl:i )
46 if ( !defined $SymbianVersion) {
47 ($SymbianVersion) = ($ENV{PATH} =~ m!C:\\Symbian\\(.+?)\\!i);
53 unshift @INC, "symbian";
55 my %VERSION = %{ do "version.pl" };
57 $VERSION = "$VERSION{REVISION}$VERSION{VERSION}$VERSION{SUBVERSION}";
58 $R_V_SV = "$VERSION{REVISION}.$VERSION{VERSION}.$VERSION{SUBVERSION}";
60 $SymbianVersion = $1 if $SDK =~ m:\\Symbian\\([^\\]+):;
61 $PerlVersion = $R_V_SV;
62 $S60SDK = $ENV{S60SDK}; # from sdk.pl
67 'symbian=s' => \$SymbianVersion,
68 'perl=s' => \$PerlVersion,
69 'csuffix=s' => \$CSuffix,
70 'cplusplus' => \$CPlusPlus,
76 'distclean' => \$DistClean,
82 $CSuffix = '.cpp' if $CPlusPlus;
83 $Build = !( $Config || $Clean || $DistClean ) || $Sis unless defined $Build;
85 die "$0: Symbian version undefined\n" unless defined $SymbianVersion;
87 $SymbianVersion =~ s:/:\\:g;
89 die "$0: Symbian version '$SymbianVersion' not found\n"
90 unless -d "\\Symbian\\$SymbianVersion";
92 die "$0: Perl version undefined\n" unless defined $PerlVersion;
94 die "$0: Perl version '$PerlVersion' not found\n"
95 if !$CoreBuild && !-d "\\Symbian\\Perl\\$PerlVersion";
97 print "Configuring with Symbian $SymbianVersion and Perl $PerlVersion...\n";
99 $SDK = "\\Symbian\\$SymbianVersion" unless defined $SDK;
100 $PERLSDK = "\\Symbian\\Perl\\$PerlVersion";
102 $R_V_SV = $PerlVersion;
106 $ENV{SDK} = $SDK; # For the Errno extension
107 $ENV{CROSS} = 1; # For the Encode extension
109 my $UREL = $ENV{UREL}; # from sdk.pl
110 $UREL =~ s/-ARM-/$ARM/;
111 my $UARM = $ENV{UARM}; # from sdk.pl
112 my $SRCDBG = $UARM eq 'udeb' ? "SRCDBG" : "";
120 open( BLD_INF, ">bld.inf" ) or die "$0: bld.inf: $!\n";
121 print BLD_INF <<__EOF__;
132 print "xsbuild: ", $cmd, "\n";
137 my ( $PL, $dir, $file ) = @_;
138 if ( defined $file ) {
139 print "\t(Running $dir\\$PL to create $file)\n";
143 print "\t(Running $dir\\$PL)\n";
147 # Problem: the Config.pm we have in $HOME\\lib carries the
148 # version number of the Perl we are building, while the Perl
149 # we are running might have some other version. Solution:
150 # temporarily replace the Config.pm with a patched version.
151 my $V = sprintf "%vd", $^V;
152 unlink("$HOME\\lib\\Config.pm.bak");
153 system_echo("perl -pi.bak -e \"s:\\Q$R_V_SV:$V:\" $HOME\\lib\\Config.pm");
155 system_echo("perl -I$HOME\\lib -I$HOME\\xlib\\symbian $PL") == 0
156 or warn "$0: $PL failed.\n";
158 system_echo("copy $HOME\\lib\\Config.pm.bak $HOME\\lib\\Config.pm");
160 if ( defined $file ) { -s $file or die "$0: No $file created.\n" }
164 my ( $conf, $k ) = @_;
165 push @{ $conf->{$k} }, split( ' ', $1 ) if /^$k\s(.+)$/;
168 sub uniquefy_filenames {
171 for my $i (@{$_[0]}) {
173 $i = lc $i if $i =~ m!\\!;
175 push @$b, $i unless $c{$i}++;
181 my ( $conf, $mmp ) = @_;
182 if ( -r $mmp && open( MMP, "<$mmp" ) ) {
183 print "\tReading $mmp...\n";
186 $conf->{TARGET} = $1 if /^TARGET\s+(.+)$/;
187 $conf->{TARGETPATH} = $1 if /^TARGETPATH\s+(.+)$/;
188 $conf->{EXTVERSION} = $1 if /^EXTVERSION\s+(.+)$/;
189 read_old_multi( $conf, "SOURCE" );
190 read_old_multi( $conf, "SOURCEPATH" );
191 read_old_multi( $conf, "USERINCLUDE" );
192 read_old_multi( $conf, "SYSTEMINCLUDE" );
193 read_old_multi( $conf, "LIBRARY" );
194 read_old_multi( $conf, "MACRO" );
201 my ( $base, $userinclude, @src ) = @_;
203 print "\t$base.mmp\n";
204 $CONF{TARGET} = "$base.dll";
205 $CONF{TARGETPATH} = "\\System\\Libs\\Perl\\$R_V_SV";
206 $CONF{SOURCE} = [@src];
207 $CONF{SOURCEPATH} = [ $CWD, $HOME ];
208 $CONF{USERINCLUDE} = [ $CWD, $HOME ];
209 $CONF{SYSTEMINCLUDE} = ["$PERLSDK\\include"] unless $CoreBuild;
210 $CONF{SYSTEMINCLUDE} = [ $HOME ] if $CoreBuild;
213 read_mmp( \%CONF, "_init.mmp" );
214 read_mmp( \%CONF, "$base.mmp" );
216 for my $ui ( @{$userinclude} ) {
218 if ( $ui =~ m!^(?:[CD]:)?\\! ) {
219 push @{ $CONF{USERINCLUDE} }, $ui;
222 push @{ $CONF{USERINCLUDE} }, "$HOME\\$ui";
225 push @{ $CONF{SYSTEMINCLUDE} }, "\\epoc32\\include";
226 push @{ $CONF{SYSTEMINCLUDE} }, "\\epoc32\\include\\libc";
227 push @{ $CONF{LIBRARY} }, "euser.lib";
228 push @{ $CONF{LIBRARY} }, "estlib.lib";
229 push @{ $CONF{LIBRARY} }, "perl$VERSION.lib";
230 push @{ $CONF{MACRO} }, "SYMBIAN" unless $CoreBuild;
231 push @{ $CONF{MACRO} }, "PERL_EXT" if $CoreBuild;
232 push @{ $CONF{MACRO} }, "MULTIPLICITY";
233 push @{ $CONF{MACRO} }, "PERL_IMPLICIT_CONTEXT";
234 push @{ $CONF{MACRO} }, "PERL_GLOBAL_STRUCT";
235 push @{ $CONF{MACRO} }, "PERL_GLOBAL_STRUCT_PRIVATE";
237 for my $u (qw(SOURCE SOURCEPATH SYSTEMINCLUDE USERINCLUDE LIBRARY MACRO)) {
238 $CONF{$u} = uniquefy_filenames( $CONF{$u} );
240 open( BASE_MMP, ">$base.mmp" ) or die "$0: $base.mmp: $!\n";
242 print BASE_MMP <<__EOF__;
245 TARGETPATH $CONF{TARGETPATH}
246 SOURCE @{$CONF{SOURCE}}
249 for my $u (qw(SOURCEPATH SYSTEMINCLUDE USERINCLUDE)) {
250 for my $v ( @{ $CONF{$u} } ) {
251 print BASE_MMP "$u\t$v\n";
254 # OPTION does not work in MMPs for pre-2.0 SDKs?
255 print BASE_MMP <<__EOF__;
256 LIBRARY @{$CONF{LIBRARY}}
257 MACRO @{$CONF{MACRO}}
266 my ( $base, $build ) = @_;
268 print "\tMakefile\n";
270 my $windef1 = "$SDK\\Epoc32\\Build$CWD\\$base\\$WIN\\$base.def";
271 my $windef2 = "..\\BWINS\\${base}u.def";
272 my $armdef1 = "$SDK\\Epoc32\\Build$CWD\\$base\\$ARM\\$base.def";
273 my $armdef2 = "..\\BMARM\\${base}u.def";
275 my $wrap = $SDK && $S60SDK eq '1.2' && $SDK !~ /_CW$/;
276 my $ABLD = $wrap ? 'perl b.pl' : 'abld';
278 open( MAKEFILE, ">Makefile" ) or die "$0: Makefile: $!\n";
279 print MAKEFILE <<__EOF__;
286 sis: build_arm freeze_arm
288 build: abld.bat build_win build_arm
295 \$(ABLD) build \$(WIN) udeb
299 \$(ABLD) build \$(ARM) $UARM
301 win: build_win freeze_win
303 arm: build_arm freeze_arm
305 freeze: freeze_win freeze_arm
309 \$(ABLD) freeze \$(WIN) $base
313 \$(ABLD) freeze \$(ARM) $base
315 defrost: defrost_win defrost_arm
325 clean: clean_win clean_arm
328 \$(ABLD) clean \$(WIN)
331 \$(ABLD) clean \$(ARM)
333 realclean: clean realclean_win realclean_arm
335 -del /f $base.c $base.mmp
338 \$(ABLD) reallyclean \$(WIN)
341 \$(ABLD) reallyclean \$(ARM)
343 distclean: defrost realclean
344 -rmdir ..\\BWINS ..\\BMARM
345 -del /f const-c.inc const-xs.inc
346 -del /f Makefile abld.bat bld.inf
350 if(open(B,">b.pl")) {
354 # nmake doesn't like MFLAGS and MAKEFLAGS being set to -w and w.
356 delete $ENV{MAKEFLAGS};
358 print "abld @ARGV\n";
359 system("abld @ARGV");
363 warn "$0: failed to create b.pl: $!\n";
369 print "[chdir from ", getcwd(), " to ";
370 chdir(shift) or return;
372 print getcwd(), "]\n";
376 my ( $ext, $dir ) = @_;
377 print "Configuring for $ext, directory $dir...\n";
378 my $extu = $CoreBuild ? "$HOME\\lib\\ExtUtils" : "$PERLSDK\\lib\\ExtUtils";
379 update_dir($dir) or die "$0: chdir '$dir': $!\n";
380 my $build = dirname($ext);
381 my $base = basename($ext);
382 my $basexs = "$base.xs";
383 my $basepm = "$base.pm";
384 my $basec = "$base$CSuffix";
386 if ( $dir =~ m:^ext\\(.+): ) {
389 elsif ( $dir ne "." ) {
392 my $extdirdir = dirname($extdir);
393 my $targetroot = "\\System\\Libs\\Perl\\$R_V_SV";
394 write_bld_inf($base) if -f $basexs;
399 $extdirdir = $extdirdir eq "." ? "" : "$extdirdir\\";
402 $lst{"$UREL\\$base.dll"} =
403 "$targetroot\\$ARM-symbian\\$base.dll"
405 $lst{"$dir\\$base.pm"} = "$targetroot\\$extdirdir$base.pm"
406 if -f $basepm && $base ne 'XSLoader';
413 find( sub { push @found, $File::Find::name if -f $_ }, 'lib' );
414 for my $found (@found) {
415 my ($short) = ( $found =~ m/^lib.(.+)/ );
418 $lst{"$dir\\$found"} = "$targetroot\\$short";
421 if ( my @pm = glob("*.pm */*.pm") ) {
423 next if $pm =~ m:^t/:;
425 $lst{"$dir\\$pm"} = "$targetroot\\$extdirdir$pm";
428 if ( my @c = glob("*.c *.cpp */*.c */*.cpp") ) {
434 if ( my @h = glob("*.h */*.h") ) {
438 $incdir{"$dir\\$h"}++ unless $h eq ".";
441 if ( exists $EXTCFG{$ext} ) {
442 for my $cfg ( @{ $EXTCFG{$ext} } ) {
443 if ( $cfg =~ /^([-+])?(.+\.(c|cpp|h))$/ ) {
444 my $o = defined $1 ? $1 : '+';
447 for my $f ( glob($f) ) {
449 warn "$0: no source file $dir\\$f\n" unless -f $f;
450 $src{$f}++ unless $cfg =~ /\.h$/;
451 if ( $f =~ m:^(.+)\\[^\\]+$: ) {
455 elsif ( $o eq '-' ) {
460 if ( $cfg =~ /^([-+])?(.+\.(pm|pl|inc))$/ ) {
461 my $o = defined $1 ? $1 : '+';
464 for my $f ( glob($f) ) {
466 warn "$0: no Perl file $dir\\$f\n" unless -f $f;
467 $lst{"$dir\\$f"} = "$targetroot\\$extdir\\$f";
469 elsif ( $o eq '-' ) {
470 delete $lst{"$dir\\$f"};
474 if ( $cfg eq 'CONST' && !$ran_PL++ ) {
475 run_PL( "Makefile.PL", $dir, "const-xs.inc" );
479 unless ( $ran_PL++ ) {
480 run_PL( "Makefile.PL", $dir ) if -f "Makefile.PL";
482 if ( $dir eq "ext\\Errno" ) {
483 run_PL( "Errno_pm.PL", $dir, "Errno.pm" );
484 $lst{"$dir\\Errno.pm"} = "$targetroot\\Errno.pm";
486 elsif ( $dir eq "ext\\Devel\\PPPort" ) {
487 run_PL( "ppport_h.PL", $dir, "ppport.h" );
489 elsif ( $dir eq "ext\\DynaLoader" ) {
490 run_PL( "XSLoader_pm.PL", $dir, "XSLoader.pm" );
491 $lst{"ext\\DynaLoader\\XSLoader.pm"} = "$targetroot\\XSLoader.pm";
493 elsif ( $dir eq "ext\\Encode" ) {
494 system_echo("perl bin\\enc2xs -Q -O -o def_t.c -f def_t.fnm") == 0
495 or die "$0: running enc2xs failed: $!\n";
498 my @lst = sort keys %lst;
500 read_mmp( \%CONF, "_init.mmp" );
501 read_mmp( \%CONF, "$base.mmp" );
504 my %MM; # MakeMaker results
505 my @MM = qw(VERSION XS_VERSION);
506 if ( -f "Makefile" ) {
507 print "\tReading MakeMaker Makefile...\n";
508 if ( open( MAKEFILE, "Makefile" ) ) {
520 warn "$0: Makefile: $!";
522 print "\tDeleting MakeMaker Makefile.\n";
528 if ( defined $CONF{EXTVERSION} ) {
529 my $EXTVERSION = $CONF{EXTVERSION};
530 print "\tUsing $EXTVERSION for version...\n";
531 $MM{VERSION} = $MM{XS_VERSION} = $EXTVERSION;
533 die "VERSION or XS_VERSION undefined\n"
534 unless defined $MM{VERSION} && defined $MM{XS_VERSION};
535 if ( open( BASE_C, ">$basec" ) ) {
536 print BASE_C <<__EOF__;
538 #define VERSION "$MM{VERSION}"
541 #define XS_VERSION "$MM{XS_VERSION}"
547 warn "$0: $basec: $!";
551 "perl -I$PERLSDK\\lib $extu\\xsubpp -C++ -csuffix .cpp -typemap $extu\\typemap -noprototypes $basexs >> $basec"
556 die "$0: perl xsubpp failed: $!\n";
560 open( _INIT_C, ">_init.c" ) or die "$!: _init.c: $!\n";
561 print _INIT_C <<__EOF__;
564 EXPORT_C void _init(void *handle) {
569 my @src = ( "_init.c", sort keys %src );
571 if ( $base eq "Encode" ) { # Currently unused.
572 for my $submf ( glob("*/Makefile") ) {
573 my $d = dirname($submf);
574 print "Configuring Encode::$d...\n";
575 if ( open( SUBMF, $submf ) ) {
576 if ( update_dir($d) ) {
579 next if 1 .. /postamble/;
580 if (m!^(\w+_t)\.c : !) {
582 "perl ..\\bin\\enc2xs -Q -o $1.c -f $1.fnm")
584 or warn "$0: enc2xs: $!\n";
585 push @subsrc, "$1.c";
591 $subbase =~ s!/!::!g;
592 write_mmp( $subbase, ["..\\Encode"], "$subbase.c",
594 write_makefile( $subbase, $build );
595 write_bld_inf($subbase);
599 "perl -I$HOME\\lib ..\\$extu\\xsubpp -C++ -csuffix .cpp -typemap ..\\$extu\\typemap -noprototypes $subbase.xs > $subbase.c"
604 die "$0: perl xsubpp failed: $!\n";
609 warn "$0: chdir $d: $!\n";
613 warn "$0: $submf: $!";
616 print "Configuring Encode...\n";
619 write_mmp( $base, [ keys %incdir ], @src );
620 write_makefile( $base, $build );
623 $lstname =~ s:^ext\\::;
624 $lstname =~ s:\\:-:g;
625 print "\t$lstname.lst\n";
627 $CoreBuild ? "$HOME/symbian/$lstname.lst" : "$HOME/$lstname.lst";
628 if ( open( my $lst, ">$lstout" ) ) {
629 for my $f (@lst) { print $lst qq["$f"-"!:$lst{$f}"\n] }
633 die "$0: $lstout: $!\n";
644 for my $ext (@ARGV) {
651 $cfg = $2 if $ext =~ s/(.+?),(.+)/$1/;
656 if ( $ext =~ /\.xs$/ && !-f $ext ) {
657 if ( -f "ext\\$ext" ) {
659 $dir = dirname($ext);
663 if ( -d "ext\\$ext" ) {
668 $dir = "." unless defined $dir;
671 if ( $ext =~ /\.xs$/ && -f $ext ) {
672 $ext = dirname($ext);
680 if ( $ext eq "XSLoader" ) {
681 $ext = "ext\\XSLoader";
683 if ( $ext eq "ext\\XSLoader" ) {
684 $dir = "ext\\DynaLoader";
687 $EXTCFG{$ext} = [ split( /,/, $cfg ) ] if defined $cfg;
689 die "$0: no lib\\Config.pm\n"
690 if $CoreBuild && $Build && !-f "lib\\Config.pm";
693 open( my $cfg, "symbian/install.cfg" )
694 or die "$0: symbian/install.cfg: $!\n";
696 $extdir =~ s:^ext\\::;
698 next unless /^ext\s+(.+)/;
701 my @ext = split( ' ', $ext );
702 $EXTCFG{"ext\\$ext[0]"} = [@ext];
707 if ( $Config || $Build ) {
708 xsconfig( $ext, $dir ) or die "$0: xsconfig '$ext' failed\n";
712 my $chdir = $ext eq "ext\\XSLoader" ? "ext\\DynaLoader" : $dir;
713 die "$0: no directory '$chdir'\n" unless -d $chdir;
714 update_dir($chdir) or die "$0: chdir '$chdir' failed: $!\n";
718 my @ext = split( /\\/, $ext );
721 if ( $Clean || $DistClean ) {
722 print "Cleaning $ext...\n";
726 unlink("const-c.inc");
727 unlink("const-xs.inc");
731 if ( $Build && $ext ne "ext\\XSLoader" && $ext ne "ext\\Errno" ) {
733 # We compile the extension three (3) times.
734 # (1) Only the _init.c to get _init() as the ordinal 1 function in the DLL.
735 # (2) With the rest and the _init.c to get ordinals for the rest.
736 # (3) With an updated _init.c that carries the symbols from step (2).
738 system("make clean");
739 system("make defrost") == 0 or die "$0: make defrost failed\n";
743 push @TARGET, 'sis' if $Sis;
746 # Hide all but the _init.c.
747 print "\n*** $ext - Compile 1 of 3.\n\n";
749 "perl -pi.bak -e \"s:^SOURCE\\s+_init.c:SOURCE\\t_init.c // :\" $base.mmp"
751 system("bldmake bldfiles");
752 system("make @TARGET") == 0 or die "$0: make #1 failed\n";
755 # Reveal the rest again.
756 print "\n*** $ext - Compile 2 of 3.\n\n";
758 "perl -pi.bak -e \"s:^SOURCE\\t_init.c // :SOURCE\\t_init.c :\" $base.mmp"
760 system("make @TARGET") == 0 or die "$0: make #2 failed\n";
761 unlink("$base.mmp.bak");
763 open( _INIT_C, ">_init.c" ) or die "$0: _init.c: $!\n";
764 print _INIT_C <<'__EOF__';
768 /* This is a different but matching definition from in dl_symbian.xs. */
773 } PerlSymbianLibHandle;
775 EXPORT_C void _init(void* handle) {
781 for my $f ("$SDK\\Epoc32\\Build$CWD\\$base\\WINS\\$base.def",
782 "..\\BMARM\\${base}u.def") {
784 if ( open( $def, $f ) ) {
792 unless (defined $basef) {
793 die "$0: failed to find .def for $base\n";
796 next while 1 .. /^EXPORTS/;
797 if (/^\s*(\w+) \@ (\d+) /) {
803 my @symbol = sort keys %symbol;
805 print _INIT_C <<'__EOF__';
807 PerlSymbianLibHandle* h = (PerlSymbianLibHandle*)handle;
809 h->symbols = newHV();
812 for my $sym (@symbol) {
813 my $len = length($sym);
814 print _INIT_C <<__EOF__;
815 hv_store(h->symbols, "$sym", $len, newSViv($symbol{$sym}), 0);
820 die "$0: $basef: no exports found\n";
823 print _INIT_C <<'__EOF__';
829 # Compile #3. This is for real.
830 print "\n*** $ext - Compile 3 of 3.\n\n";
831 system("make @TARGET") == 0 or die "$0: make #3 failed\n";
834 elsif ( $Clean || $DistClean ) {
835 if ( $ext eq "ext\\Errno" ) {
836 unlink( "Errno.pm", "Makefile" );
839 if ( -f "Makefile" ) {
841 system("make clean") == 0 or die "$0: make clean failed\n";
844 system("make distclean") == 0
845 or die "$0: make distclean failed\n";
848 if ( $ext eq "ext\\Devel\\PPPort" ) {
852 my @B = glob("ext/BWINS ext/BMARM ext/*/BWINS ext/*/BMARM Makefile");