os/kernelhwsrv/kerneltest/f32test/loader/dlltree.pl
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
sl@0
     1
# Copyright (c) 2001-2009 Nokia Corporation and/or its subsidiary(-ies).
sl@0
     2
# All rights reserved.
sl@0
     3
# This component and the accompanying materials are made available
sl@0
     4
# under the terms of the License "Eclipse Public License v1.0"
sl@0
     5
# which accompanies this distribution, and is available
sl@0
     6
# at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0
     7
#
sl@0
     8
# Initial Contributors:
sl@0
     9
# Nokia Corporation - initial contribution.
sl@0
    10
#
sl@0
    11
# Contributors:
sl@0
    12
#
sl@0
    13
# Description:
sl@0
    14
# \f32test\loader\dlltree.pl
sl@0
    15
# Generate header and build files for one or more trees
sl@0
    16
# of DLLs and EXEs according to a description file.
sl@0
    17
# 
sl@0
    18
#
sl@0
    19
sl@0
    20
require Cwd;
sl@0
    21
sl@0
    22
my $dllbasename='dllt';
sl@0
    23
my $dllext='.dll';
sl@0
    24
my $exebasename='exet';
sl@0
    25
my $exeext='.exe';
sl@0
    26
my $mmpext='.mmp';
sl@0
    27
my $defext='.def';
sl@0
    28
my $libext='.lib';
sl@0
    29
sl@0
    30
my $source0ext='.cpp';
sl@0
    31
my $source1ext='.cia';
sl@0
    32
my $xippath="sys\\bin\\";
sl@0
    33
my $nonxippath="sys\\bin\\";
sl@0
    34
sl@0
    35
my $hostpath="\\Epoc32\\Release\\##MAIN##\\##BUILD##\\";
sl@0
    36
sl@0
    37
my $flag_value_exe=1;
sl@0
    38
my $flag_value_fixed=2;
sl@0
    39
my $flag_value_data=4;
sl@0
    40
my $flag_value_xip=8;
sl@0
    41
my $flag_value_dll_in_cycle=16;
sl@0
    42
my $flag_value_data_in_tree=32;
sl@0
    43
my $flag_value_xip_data_in_tree=64;
sl@0
    44
my $flag_value_exports=128;
sl@0
    45
my $flag_value_pagedcode=256;
sl@0
    46
my $flag_value_unpagedcode=512;
sl@0
    47
my $flag_value_idrive=1024;
sl@0
    48
my $flag_value_vdrive=2048;
sl@0
    49
my $flag_value_bytepair=4096;
sl@0
    50
my $flag_value_uncompressed=8192;
sl@0
    51
my $flag_value_targetonly=16384;
sl@0
    52
my $flag_value_pageddata=32768;
sl@0
    53
my $flag_value_unpageddata=65536;
sl@0
    54
sl@0
    55
my $sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst;
sl@0
    56
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = gmtime;
sl@0
    57
my $copy_end=$year+1900;
sl@0
    58
sl@0
    59
my $argc=scalar(@ARGV);
sl@0
    60
($argc==1 or $argc==2 or $argc==3) or die "Usage: perl dlltree.pl <filename> <dir> [-allowbad]\n";
sl@0
    61
my $infile=$ARGV[0];
sl@0
    62
open IN, $infile or die "Cannot open input file $infile\n";
sl@0
    63
my @in;
sl@0
    64
while (<IN>)	{
sl@0
    65
	push @in, $_;
sl@0
    66
}
sl@0
    67
close IN;
sl@0
    68
my $destdir='';
sl@0
    69
if ($argc>=2) {
sl@0
    70
	$destdir=$ARGV[1];
sl@0
    71
	unless (-d $destdir) {
sl@0
    72
		mkdir $destdir, 0777 or die "Can't create directory $destdir\n";
sl@0
    73
	}
sl@0
    74
	chdir $destdir or die "Can't chdir to directory $destdir\n";
sl@0
    75
}
sl@0
    76
my $allowbad;
sl@0
    77
if ($argc==3) {
sl@0
    78
	if ($ARGV[2] eq '-allowbad') {
sl@0
    79
		$allowbad = 1;
sl@0
    80
	}
sl@0
    81
}
sl@0
    82
$cwd=Cwd::getcwd();
sl@0
    83
$destpath=$cwd;
sl@0
    84
$destpath=~s/\//\\/g;
sl@0
    85
if ($destpath=~/^\w\:(.*)/) {
sl@0
    86
	$destpath=$1;
sl@0
    87
}
sl@0
    88
unless ($destpath=~/^(.*?)\\$/) {
sl@0
    89
	$destpath.='\\';
sl@0
    90
}
sl@0
    91
#print "$cwd\n";
sl@0
    92
#print "$destpath\n";
sl@0
    93
sl@0
    94
my @modules;
sl@0
    95
my @testcases;
sl@0
    96
my $line=0;
sl@0
    97
my $modnum=0;
sl@0
    98
my $state=0;
sl@0
    99
my $concat;
sl@0
   100
foreach (@in)	{
sl@0
   101
	++$line;
sl@0
   102
	next if (/^\s*$/ or /^\s*\#/);
sl@0
   103
	if ($state==0)	{
sl@0
   104
		if (/^\!TESTCASES/) {
sl@0
   105
			$state=1;
sl@0
   106
			next;
sl@0
   107
		}
sl@0
   108
		my @moddesc=split;
sl@0
   109
		my $modname=shift @moddesc;
sl@0
   110
		if (grep {lc($$_{name}) eq lc($modname)} @modules) {
sl@0
   111
			die "Duplicate module specification at line $line\n";
sl@0
   112
		}
sl@0
   113
		my %module;
sl@0
   114
		$module{name}=$modname;
sl@0
   115
		$module{num}=$modnum;
sl@0
   116
		$module{exports}=1;
sl@0
   117
		$module{nclients}=0;	# number of modules which import from this one
sl@0
   118
		while (scalar(@moddesc)) {
sl@0
   119
			my $att=shift @moddesc;
sl@0
   120
			if ($att=~/^\:$/) {
sl@0
   121
				last;
sl@0
   122
			} elsif ($att=~/^X$/i) {
sl@0
   123
				$module{exe}=1;
sl@0
   124
			} elsif ($att=~/^F$/i) {
sl@0
   125
				$module{fixed}=1;
sl@0
   126
			} elsif ($att=~/^D$/i) {
sl@0
   127
				$module{data}=1;
sl@0
   128
			} elsif ($att=~/^P$/i) {
sl@0
   129
				$module{pagedcode}=1;
sl@0
   130
			} elsif ($att=~/^PD$/i) {
sl@0
   131
				$module{pageddata}=1;
sl@0
   132
			} elsif ($att=~/^B$/i) {
sl@0
   133
				$module{bytepair}=1;
sl@0
   134
			} elsif ($att=~/^U$/i) {
sl@0
   135
				$module{uncompressed}=1;
sl@0
   136
			} elsif ($att=~/^I$/i) {
sl@0
   137
				$module{idrive}=1;
sl@0
   138
			} elsif ($att=~/^V$/i) {
sl@0
   139
				$module{vdrive}=1;
sl@0
   140
			} elsif ($att=~/^N$/i) {
sl@0
   141
				$module{unpagedcode}=1;
sl@0
   142
			} elsif ($att=~/^T$/i) {
sl@0
   143
				$module{targetonly}=1;
sl@0
   144
			} elsif ($att=~/^R(.*?)$/i) {
sl@0
   145
				$module{xip}=1;
sl@0
   146
				my $attp=$1;
sl@0
   147
				if ($attp=~/^\,(.*?)$/) {
sl@0
   148
					$module{attpname}=$1;
sl@0
   149
				} elsif (!($attp=~/^\s*$/)) {
sl@0
   150
					die "Garbage following R attribute at line $line\n";
sl@0
   151
				}
sl@0
   152
			}
sl@0
   153
		}
sl@0
   154
		if ($module{fixed} && !$module{exe}) {
sl@0
   155
			die "Can't have FIXED without EXE at line $line\n";
sl@0
   156
		}
sl@0
   157
		if ($module{pagedcode} && $module{xip}) {
sl@0
   158
			die "Can't have PAGEDCODE with XIP at line $line\n";
sl@0
   159
		}
sl@0
   160
sl@0
   161
		# makmake won't support paged binaries which aren't bytepair or uncompressed.
sl@0
   162
		# However, P can be specified without them in dlltree.txt.  This program generates
sl@0
   163
		# an MMP file with neither flag.  The flag is added when the files are copied to
sl@0
   164
		# internal media by T_LDRTST.  (It would be pointless to copy the files to removable
sl@0
   165
		# media and then edit them because removable media doesn't support paging.)
sl@0
   166
sl@0
   167
		my $bothCodePageFlags = $module{pagedcode} && $module{unpagedcode};
sl@0
   168
		if ($bothCodePageFlags && !$module{idrive}) {
sl@0
   169
			die "Can't have PAGEDCODE and UNPAGEDCODE without INTERNAL DRIVE at line $line\n";
sl@0
   170
		}
sl@0
   171
		if ($module{unpagedcode} && $module{xip}) {
sl@0
   172
			die "Can't have UNPAGEDCODE with XIP at line $line\n";
sl@0
   173
		}
sl@0
   174
		if ($module{pageddata} && !$module{exe}) {
sl@0
   175
			die "Can't have PAGEDDATA without EXE at line $line\n";
sl@0
   176
		}
sl@0
   177
		if ($module{idrive} && $module{xip}) {
sl@0
   178
			die "Can't have INTERNAL DRIVE with XIP at line $line\n";
sl@0
   179
		}
sl@0
   180
		if ($module{vdrive} && $module{xip}) {
sl@0
   181
			die "Can't have REMOVABLE DRIVE with XIP at line $line\n";
sl@0
   182
		}
sl@0
   183
		if ($module{idrive} && $module{vdrive}) {
sl@0
   184
			die "Can't have INTERNAL DRIVE with REMOVABLE DRIVE at line $line\n";
sl@0
   185
		}
sl@0
   186
		if ($module{bytepair} && $module{uncompressed}) {
sl@0
   187
			die "Can't have BYTEPAIR with UNCOMPRESSED at line $line\n";
sl@0
   188
		}
sl@0
   189
		if ($module{exe}) {
sl@0
   190
			if ($module{attpname}) {
sl@0
   191
				warn "Attach process with EXE ignored at line $line\n";
sl@0
   192
				delete $module{attpname};
sl@0
   193
			}
sl@0
   194
			$module{basefilename}=$exebasename.$modnum;
sl@0
   195
			$module{filename}=$module{basefilename}.$exeext;
sl@0
   196
			$module{source0}=$exebasename.$source0ext;
sl@0
   197
			$module{source1}="";
sl@0
   198
			$module{trgtype}='exexp';
sl@0
   199
			$module{lib}=$module{basefilename}.$libext;
sl@0
   200
		} else {
sl@0
   201
			$module{basefilename}=$dllbasename.$modnum;
sl@0
   202
			$module{filename}=$module{basefilename}.$dllext;
sl@0
   203
			$module{source0}=$dllbasename.$source0ext;
sl@0
   204
			$module{source1}=$dllbasename.$source1ext;
sl@0
   205
			$module{trgtype}='dll';
sl@0
   206
			$module{lib}=$module{basefilename}.$libext;
sl@0
   207
		}
sl@0
   208
		$module{depnames}=\@moddesc;	# dependency names are left over
sl@0
   209
		$module{line}=$line;
sl@0
   210
		$module{mark}=0;
sl@0
   211
		push @modules, \%module;
sl@0
   212
		++$modnum;
sl@0
   213
	} elsif ($state<=2) {
sl@0
   214
		if ($state==1) {
sl@0
   215
			$concat="";
sl@0
   216
			die "Syntax error at line $line\n" unless (/^(\w+)\:/);
sl@0
   217
		}
sl@0
   218
		if (/^(.*?)\\$/) {
sl@0
   219
			$concat.=$1;
sl@0
   220
			$concat.=' ';
sl@0
   221
			$state=2;
sl@0
   222
			next;
sl@0
   223
		} else {
sl@0
   224
			$concat.=$_;
sl@0
   225
			$state=1;
sl@0
   226
		}
sl@0
   227
		my @modlist=split(/\s+/, $concat);
sl@0
   228
		my $tcname=shift @modlist;
sl@0
   229
		$tcname=~/^(.*?)\:$/ or die "???\n";
sl@0
   230
		$tcname=$1;
sl@0
   231
		my %tc;
sl@0
   232
		$tc{name}=$tcname;
sl@0
   233
		$tc{mod_names}=\@modlist;
sl@0
   234
		push @testcases, \%tc;
sl@0
   235
	}
sl@0
   236
}
sl@0
   237
foreach $modref (@modules) {
sl@0
   238
	my $moddepref=$$modref{depnames};
sl@0
   239
	my @deps;
sl@0
   240
	foreach (@$moddepref) {
sl@0
   241
		my $depname=lc($_);
sl@0
   242
		my @match=grep {lc($$_{name}) eq $depname} @modules;
sl@0
   243
		if (scalar(@match)==0) {
sl@0
   244
			die "Unknown dependent module $depname at line $$modref{line}\n";
sl@0
   245
		}
sl@0
   246
		my $depref=$match[0];
sl@0
   247
		if ($$modref{xip} and !$$depref{xip}) {
sl@0
   248
			die "Illegal dependency: $$modref{name} (XIP) on $$depref{name} (non-XIP)\n";
sl@0
   249
		}
sl@0
   250
		push @deps, $$depref{num};
sl@0
   251
		++$$depref{nclients};
sl@0
   252
	}
sl@0
   253
	$$modref{deps}=\@deps;
sl@0
   254
	my $attpname=$$modref{attpname};
sl@0
   255
	if ($attpname) {
sl@0
   256
		my @match=grep {lc($$_{name}) eq lc($attpname)} @modules;
sl@0
   257
		if (scalar(@match)==0) {
sl@0
   258
			die "Unknown attach process $attpname at line $$modref{line}\n";
sl@0
   259
		}
sl@0
   260
		my $attpref=$match[0];
sl@0
   261
		if (!$$attpref{exe}) {
sl@0
   262
			die "Specified attach process is not EXE at line $$modref{line}\n";
sl@0
   263
		} elsif (!$$attpref{xip}) {
sl@0
   264
			die "Specified attach process is not XIP at line $$modref{line}\n";
sl@0
   265
		}
sl@0
   266
		$$modref{attp}=$attpref;
sl@0
   267
	}
sl@0
   268
}
sl@0
   269
foreach $tcref (@testcases) {
sl@0
   270
	my $modlistref=$$tcref{mod_names};
sl@0
   271
	my @modnums;
sl@0
   272
	foreach $modname (@$modlistref) {
sl@0
   273
		next if ($modname=~/^\s*$/);
sl@0
   274
		my @match=grep {lc($$_{name}) eq lc($modname)} @modules;
sl@0
   275
		if (scalar(@match)==0) {
sl@0
   276
			die "Unknown module $modname in test case $$tcref{name}\n";
sl@0
   277
		}
sl@0
   278
		push @modnums, $match[0]->{num};
sl@0
   279
	}
sl@0
   280
	$$tcref{modules}=\@modnums;
sl@0
   281
	$$tcref{count}=scalar(@modnums);
sl@0
   282
}
sl@0
   283
my $next_mark=0;
sl@0
   284
foreach $modref (@modules) {
sl@0
   285
	if ($$modref{nclients}==0 and $$modref{exe}) {
sl@0
   286
		# EXE with no exports
sl@0
   287
		$$modref{exports}=0;
sl@0
   288
		$$modref{trgtype}='exe';
sl@0
   289
	}
sl@0
   290
	++$next_mark;
sl@0
   291
	my $modnum=$$modref{num};
sl@0
   292
	my @tcdeps;
sl@0
   293
	calc_tc(\@tcdeps, \@modules, $modref, $next_mark);
sl@0
   294
	$$modref{tcdeps}=\@tcdeps;
sl@0
   295
	if (grep {$_==$modnum} @tcdeps) {
sl@0
   296
		$$modref{cycle}=1;
sl@0
   297
	}
sl@0
   298
	my @exes=grep {$modules[$_]->{exe}} @tcdeps;
sl@0
   299
	my $nexes=scalar(@exes);
sl@0
   300
sl@0
   301
	unless ($allowbad) {
sl@0
   302
		if ($nexes>1) {
sl@0
   303
			die "Module $$modref{name} links to more than one EXE\n";
sl@0
   304
		} elsif ($nexes==1) {
sl@0
   305
			my $exeref=$modules[$exes[0]];
sl@0
   306
			$$modref{linkexe}=$exeref;
sl@0
   307
			if ($$modref{exe}) {
sl@0
   308
				if ($$exeref{num}!=$modnum) {
sl@0
   309
					die "EXE $modref{name} links to another EXE\n";
sl@0
   310
				}
sl@0
   311
			} else {
sl@0
   312
				if ($$modref{attp} and $$exeref{num}!=$modref->{attp}->{num}) {
sl@0
   313
					die "DLL $$modref{name} ($modnum) incompatible attach process\n";
sl@0
   314
				}
sl@0
   315
				if (!$$modref{attp}) {
sl@0
   316
					$$modref{attp}=$exeref;
sl@0
   317
				}
sl@0
   318
			}
sl@0
   319
		}
sl@0
   320
	}
sl@0
   321
	if ($$modref{exe}) {
sl@0
   322
		foreach $depnum (@tcdeps) {
sl@0
   323
			my $depref=$modules[$depnum];
sl@0
   324
			my $depattpref=$depref->{attp};
sl@0
   325
			if ($depattpref and $depattpref->{num}!=$modnum) {
sl@0
   326
				die "DEP DLL $$depref{name} ($$depref{num}) incompatible attach process\n";
sl@0
   327
			}
sl@0
   328
#			if (!$depattpref) {
sl@0
   329
#				$$depref{attp}=$modref;
sl@0
   330
#			}
sl@0
   331
		}
sl@0
   332
	}
sl@0
   333
}
sl@0
   334
foreach $modref (@modules) {
sl@0
   335
	my @total_deps;
sl@0
   336
	my $tcdepref=$$modref{tcdeps};
sl@0
   337
	push @total_deps, @$tcdepref;
sl@0
   338
	my $linkexe=$$modref{linkexe};
sl@0
   339
	if ($linkexe) {
sl@0
   340
		my $exetcdepref=$$linkexe{tcdeps};
sl@0
   341
		push @total_deps, @$exetcdepref;
sl@0
   342
	}
sl@0
   343
	push @total_deps, $$modref{num};
sl@0
   344
	my $data=scalar(grep {$modules[$_]->{data}} @total_deps);
sl@0
   345
	if ($data!=0) {
sl@0
   346
		$$modref{dataintree}=1;
sl@0
   347
	}
sl@0
   348
	my $xipdata=scalar(grep {$modules[$_]->{data} and $modules[$_]->{xip}} @total_deps);
sl@0
   349
	if ($xipdata!=0) {
sl@0
   350
		$$modref{xipdataintree}=1;
sl@0
   351
	}
sl@0
   352
}
sl@0
   353
sl@0
   354
#foreach $modref (@modules) {
sl@0
   355
#	print "Module $$modref{num}:\n";
sl@0
   356
#	print "\tName:     $$modref{name}\n";
sl@0
   357
#	print "\tFilename: $$modref{filename}\n";
sl@0
   358
#	my $depref=$$modref{deps};
sl@0
   359
#	my $ndeps=scalar(@$depref);
sl@0
   360
#	print "\t#Deps:    $ndeps\n";
sl@0
   361
#	print "\tDeps:     ",join(',',@$depref),"\n";
sl@0
   362
#}
sl@0
   363
sl@0
   364
my @bldinf;
sl@0
   365
my $bldname='dlltree.inf';
sl@0
   366
push @bldinf, "// $destpath$bldname\n";
sl@0
   367
push @bldinf, "//\n";
sl@0
   368
push @bldinf, "// Copyright (c) 2000-$copy_end Symbian Ltd. All rights reserved.\n";
sl@0
   369
push @bldinf, "//\n";
sl@0
   370
push @bldinf, "\n";
sl@0
   371
push @bldinf, "PRJ_PLATFORMS\n";
sl@0
   372
push @bldinf, "BASEUSERDEFAULT\n";
sl@0
   373
push @bldinf, "\n";
sl@0
   374
push @bldinf, "PRJ_TESTMMPFILES\n";
sl@0
   375
push @bldinf, "\n";
sl@0
   376
sl@0
   377
my @dlltree;
sl@0
   378
my $dlltreename='dlltree.h';
sl@0
   379
push @dlltree, "// $destpath$dlltreename\n";
sl@0
   380
push @dlltree, "//\n";
sl@0
   381
push @dlltree, "// Copyright (c) 2000-$copy_end Symbian Ltd. All rights reserved.\n";
sl@0
   382
push @dlltree, "//\n";
sl@0
   383
push @dlltree, "\n";
sl@0
   384
push @dlltree, "#ifndef __DLLTREE_H__\n";
sl@0
   385
push @dlltree, "#define __DLLTREE_H__\n";
sl@0
   386
push @dlltree, "#include <e32std.h>\n";
sl@0
   387
push @dlltree, "\n";
sl@0
   388
push @dlltree, "class MDllList;\n";
sl@0
   389
push @dlltree, "\n";
sl@0
   390
sl@0
   391
my $ibyname='ldrtest.iby';
sl@0
   392
my @iby;
sl@0
   393
sl@0
   394
foreach $modref (@modules) {
sl@0
   395
	my @mmp;
sl@0
   396
	my $num=$$modref{num};
sl@0
   397
	my $mmpname=$$modref{basefilename}.$mmpext;
sl@0
   398
	my $defname=$$modref{basefilename}.$defext;
sl@0
   399
	my $depsref=$$modref{deps};
sl@0
   400
	my $ndeps=scalar(@$depsref);
sl@0
   401
	push @mmp, "// $destpath$mmpname\n";
sl@0
   402
	push @mmp, "//\n";
sl@0
   403
	push @mmp, "// Copyright (c) 2000-$copy_end Symbian Ltd. All rights reserved.\n";
sl@0
   404
	push @mmp, "//\n";
sl@0
   405
	push @mmp, "// Generated from $$modref{name}\n";
sl@0
   406
	push @mmp, "\n";
sl@0
   407
	push @mmp, "macro             __DLLNUM$num\n";
sl@0
   408
	push @mmp, "target            $$modref{filename}\n";
sl@0
   409
	push @mmp, "targettype        $$modref{trgtype}\n";
sl@0
   410
	push @mmp, "sourcepath        .\n";
sl@0
   411
	push @mmp, "source            $$modref{source0} $$modref{source1}\n";
sl@0
   412
	push @mmp, "library           euser.lib efsrv.lib\n";
sl@0
   413
	push @mmp, "Capability		NONE\n";
sl@0
   414
	foreach (@$depsref) {
sl@0
   415
		my $depref=$modules[$_];
sl@0
   416
		push @mmp, "library           $$depref{lib}\n";
sl@0
   417
	}
sl@0
   418
	if ($$modref{exports}) {
sl@0
   419
		push @mmp, "deffile           ./$defname\n";
sl@0
   420
		push @mmp, "nostrictdef\n";
sl@0
   421
	}
sl@0
   422
	push @mmp, "OS_LAYER_SYSTEMINCLUDE_SYMBIAN   \n";
sl@0
   423
	push @mmp, "systeminclude     ../../../e32test/mmu   \n";
sl@0
   424
	push @mmp, "userinclude       . \n";
sl@0
   425
	if ($$modref{fixed}) {
sl@0
   426
		push @mmp, "epocfixedprocess\n";
sl@0
   427
	}
sl@0
   428
sl@0
   429
	# if both paged flags are set or the compression is not pageable then print neither.
sl@0
   430
	# T_LDRTST will add the required flags when it copies the file to internal media.
sl@0
   431
sl@0
   432
	my $bothCodePageFlags = $$modref{pagedcode} && $$modref{unpagedcode};
sl@0
   433
	my $pageableCompression = $$modref{bytepair} || $$modref{uncompressed};
sl@0
   434
	if (!$bothCodePageFlags && $pageableCompression) {
sl@0
   435
		push @mmp, "pagedcode\n" if $$modref{pagedcode};
sl@0
   436
		push @mmp, "unpagedcode\n" if $$modref{unpagedcode};
sl@0
   437
	}
sl@0
   438
sl@0
   439
	if ($$modref{exe}) {
sl@0
   440
		# make exes unpageddata by default
sl@0
   441
		if (!$$modref{pageddata}) {
sl@0
   442
			$$modref{unpageddata}=1;
sl@0
   443
		}
sl@0
   444
		if ($$modref{pageddata}) {
sl@0
   445
			push @mmp, "pageddata\n";
sl@0
   446
		}
sl@0
   447
		if ($$modref{unpageddata}) {
sl@0
   448
			push @mmp, "unpageddata\n";
sl@0
   449
		}
sl@0
   450
	}
sl@0
   451
sl@0
   452
	if ($$modref{bytepair}) {
sl@0
   453
		push @mmp, "bytepaircompresstarget\n";
sl@0
   454
	}
sl@0
   455
sl@0
   456
	if ($$modref{uncompressed}) {
sl@0
   457
		push @mmp, "nocompresstarget\n";
sl@0
   458
	}
sl@0
   459
sl@0
   460
	if ($$modref{data} && !$$modref{exe}) {
sl@0
   461
		push @mmp, "epocallowdlldata\n";
sl@0
   462
	}
sl@0
   463
	push @mmp, sprintf("uid               0x00000000 0x%08x\n", $num+256);
sl@0
   464
	push @mmp, "SMPSAFE\n";
sl@0
   465
	$$modref{mmp}=\@mmp;
sl@0
   466
sl@0
   467
	if ($$modref{exports}) {
sl@0
   468
		my @def;
sl@0
   469
		push @def, "EXPORTS\n";
sl@0
   470
		if ($$modref{exe}) {
sl@0
   471
			push @def, "\tRegisterConstructorCall @ 1 NONAME\n";
sl@0
   472
			push @def, "\tRegisterInitCall @ 2 NONAME\n";
sl@0
   473
			push @def, "\tRegisterDestructorCall @ 3 NONAME\n";
sl@0
   474
		} else {
sl@0
   475
			push @def, "\tInit$num @ 1 NONAME\n";
sl@0
   476
			push @def, "\tChkC$num @ 2 NONAME\n";
sl@0
   477
			push @def, "\tBlkI$num @ 3 NONAME\n";
sl@0
   478
			push @def, "\tGetGeneration @ 4 NONAME\n";
sl@0
   479
			push @def, "\tRBlkI$num @ 5 NONAME\n";
sl@0
   480
			push @def, "\tSetCloseLib @ 6 NONAME\n";
sl@0
   481
		}
sl@0
   482
		$$modref{def}=\@def;
sl@0
   483
	}
sl@0
   484
sl@0
   485
	push @bldinf, "$$modref{basefilename}\t\tsupport\n";
sl@0
   486
sl@0
   487
	if ($num==0) {
sl@0
   488
		push @dlltree, "#if defined(__DLLNUM$num)\n";
sl@0
   489
	} else {
sl@0
   490
		push @dlltree, "#elif defined(__DLLNUM$num)\n";
sl@0
   491
	}
sl@0
   492
	push @dlltree, "#define DLLNUM               $num\n";
sl@0
   493
	if ($$modref{exe}) {
sl@0
   494
		push @dlltree, "#define EXENUM               $num\n";
sl@0
   495
		push @dlltree, "_LIT(KServerName, \"$$modref{name}\");\n";
sl@0
   496
	}
sl@0
   497
	push @dlltree, "#define INITFUNC             Init$num\n";
sl@0
   498
	push @dlltree, "#define CHKCFUNC             ChkC$num\n";
sl@0
   499
	push @dlltree, "#define BLKIFUNC             BlkI$num\n";
sl@0
   500
	push @dlltree, "#define RBLKIFUNC            RBlkI$num\n";
sl@0
   501
	push @dlltree, "#define CHKDEPS(r)           (\\\n";
sl@0
   502
	foreach (@$depsref) {
sl@0
   503
		my $depref=$modules[$_];
sl@0
   504
		unless ($$depref{exe}) {
sl@0
   505
			my $func="ChkC$_";
sl@0
   506
			push @dlltree, "\t((r)=$func())!=0 ||\\\n";
sl@0
   507
		}
sl@0
   508
	}
sl@0
   509
	push @dlltree, "\t((r)=0)!=0 )\n";
sl@0
   510
	push @dlltree, "#define INITDEPS(r,l)        (\\\n";
sl@0
   511
	foreach (@$depsref) {
sl@0
   512
		my $depref=$modules[$_];
sl@0
   513
		unless ($$depref{exe}) {
sl@0
   514
			my $func="Init$_";
sl@0
   515
			push @dlltree, "\t((r)=$func(l))!=0 ||\\\n";
sl@0
   516
		}
sl@0
   517
	}
sl@0
   518
	push @dlltree, "\t((r)=0)!=0 )\n";
sl@0
   519
	my $link_to_exe;
sl@0
   520
	push @dlltree, "#define RBLKIFUNC_DEPS(i,g)  {\\\n";
sl@0
   521
	foreach (@$depsref) {
sl@0
   522
		my $depref=$modules[$_];
sl@0
   523
		if ($$depref{exe}) {
sl@0
   524
			$link_to_exe=1;
sl@0
   525
		} else {
sl@0
   526
			my $func="RBlkI$_";
sl@0
   527
			push @dlltree, "\t(i)=$func(i,g);\\\n";
sl@0
   528
		}
sl@0
   529
	}
sl@0
   530
	push @dlltree, "\t}\n";
sl@0
   531
	if ($link_to_exe) {
sl@0
   532
		push @dlltree, "#define __DLL_LINK_TO_EXE\n";
sl@0
   533
	}
sl@0
   534
	if ($$modref{cycle}) {
sl@0
   535
		push @dlltree, "#define __DLL_IN_CYCLE\n";
sl@0
   536
	}
sl@0
   537
	if ($$modref{data}) {
sl@0
   538
		push @dlltree, "#define __MODULE_HAS_DATA\n";
sl@0
   539
	}
sl@0
   540
	if ($$modref{exports}) {
sl@0
   541
		push @dlltree, "#define __MODULE_EXPORT\t\tEXPORT_C\n";
sl@0
   542
		push @dlltree, "#define __MODULE_IMPORT\t\tIMPORT_C\n";
sl@0
   543
	} else {
sl@0
   544
		push @dlltree, "#define __MODULE_EXPORT\n";
sl@0
   545
		push @dlltree, "#define __MODULE_IMPORT\n";
sl@0
   546
	}
sl@0
   547
	foreach (@$depsref) {
sl@0
   548
		my $depref=$modules[$_];
sl@0
   549
		if ($$depref{exe}) {
sl@0
   550
		} else {
sl@0
   551
			push @dlltree, "extern \"C\" IMPORT_C TInt Init$_(MDllList&);\n";
sl@0
   552
			push @dlltree, "extern \"C\" IMPORT_C TInt ChkC$_();\n";
sl@0
   553
			push @dlltree, "extern \"C\" IMPORT_C TInt RBlkI$_(TInt, TInt);\n";
sl@0
   554
		}
sl@0
   555
	}
sl@0
   556
	my $hostfullpathname=$hostpath.$$modref{filename};
sl@0
   557
	if ($$modref{xip}) {
sl@0
   558
		my $epocfullpathname=$xippath.$$modref{filename};
sl@0
   559
		my $flags;
sl@0
   560
		if ($$modref{attp}) {
sl@0
   561
			$flags='process '.$modref->{attp}->{filename};
sl@0
   562
		}
sl@0
   563
		push @iby, "file=$hostfullpathname\t\t$epocfullpathname\t\t$flags\n";
sl@0
   564
	} else {
sl@0
   565
		my $epocfullpathname=$nonxippath.$$modref{filename};
sl@0
   566
		push @iby, "data=$hostfullpathname\t\t$epocfullpathname\n";
sl@0
   567
	}
sl@0
   568
}
sl@0
   569
sl@0
   570
#push @dlltree, "#else\n";
sl@0
   571
#push @dlltree, "#error No __DLLNUM macro defined\n";
sl@0
   572
push @dlltree, "#endif\n";
sl@0
   573
push @dlltree, "\n";
sl@0
   574
sl@0
   575
my $module_count=scalar(@modules);
sl@0
   576
push @dlltree, "const TInt KNumModules=$module_count;\n";
sl@0
   577
push @dlltree, "\n";
sl@0
   578
push @dlltree, "#ifdef __INCLUDE_DEPENDENCY_GRAPH\n";
sl@0
   579
push @dlltree, "static const TText* const ModuleName[KNumModules] =\n";
sl@0
   580
push @dlltree, "\t\{\n";
sl@0
   581
foreach $modref (@modules) {
sl@0
   582
	my $string="\t(const TText*)L\"$$modref{name}\"";
sl@0
   583
	unless ($$modref{num}==$module_count-1) {
sl@0
   584
		$string.=',';
sl@0
   585
	}
sl@0
   586
	push @dlltree, $string;
sl@0
   587
	my $pad=41-length($string);
sl@0
   588
	$pad=($pad+3)/4;
sl@0
   589
	push @dlltree, "\t"x$pad, "\/*", $$modref{num}, "*\/\n";
sl@0
   590
}
sl@0
   591
push @dlltree, "\t\};\n";
sl@0
   592
push @dlltree, "\n";
sl@0
   593
push @dlltree, "#define MODULE_NAME(n)	TPtrC(ModuleName[n])\n";
sl@0
   594
push @dlltree, "\n";
sl@0
   595
push @dlltree, "static const TText* const ModuleFileName[KNumModules] =\n";
sl@0
   596
push @dlltree, "\t\{\n";
sl@0
   597
foreach $modref (@modules) {
sl@0
   598
	if ($$modref{idrive} || $$modref{vdrive}) {
sl@0
   599
		my $fn = $$modref{filename};
sl@0
   600
		my $used_nxip_path = "?:\\$nonxippath$fn";
sl@0
   601
		$used_nxip_path =~ s/\\/\\\\/g;		# double backslashes
sl@0
   602
		substr($used_nxip_path,0,1) = $$modref{idrive} ? "0" : "1";
sl@0
   603
		push @dlltree, "\t(const TText*)L\"$used_nxip_path\"";
sl@0
   604
	} else {
sl@0
   605
		push @dlltree, "\t(const TText*)L\"$$modref{filename}\"";
sl@0
   606
	}
sl@0
   607
	if ($$modref{num}==$module_count-1) {
sl@0
   608
		push @dlltree, "\n";
sl@0
   609
	} else {
sl@0
   610
		push @dlltree, ",\n";
sl@0
   611
	}
sl@0
   612
}
sl@0
   613
push @dlltree, "\t\};\n";
sl@0
   614
push @dlltree, "\n";
sl@0
   615
push @dlltree, "#define MODULE_FILENAME(n)	TPtrC(ModuleFileName[n])\n";
sl@0
   616
push @dlltree, "\n";
sl@0
   617
foreach $modref (@modules) {
sl@0
   618
	my $modnum=$$modref{num};
sl@0
   619
	my $tcdepsref=$$modref{tcdeps};
sl@0
   620
	my $numdeps=scalar(@$tcdepsref);
sl@0
   621
	push @dlltree, "static const TInt Module$modnum","Deps[] =\n";
sl@0
   622
	push @dlltree, "\t\{$numdeps";
sl@0
   623
	if ($numdeps) {
sl@0
   624
		push @dlltree, ",", join(',',@$tcdepsref)
sl@0
   625
	}
sl@0
   626
	push @dlltree, "\};\n";
sl@0
   627
}
sl@0
   628
push @dlltree, "static const TInt* const ModuleDependencies[KNumModules] =\n";
sl@0
   629
push @dlltree, "\t\{\n";
sl@0
   630
foreach $modref (@modules) {
sl@0
   631
	my $modnum=$$modref{num};
sl@0
   632
	push @dlltree, "\tModule$modnum","Deps";
sl@0
   633
	if ($$modref{num}==$module_count-1) {
sl@0
   634
		push @dlltree, "\n";
sl@0
   635
	} else {
sl@0
   636
		push @dlltree, ",\n";
sl@0
   637
	}
sl@0
   638
}
sl@0
   639
push @dlltree, "\t\};\n";
sl@0
   640
push @dlltree, "\n";
sl@0
   641
push @dlltree, sprintf "const TInt KModuleFlagExe=0x%04x;\n", $flag_value_exe;
sl@0
   642
push @dlltree, sprintf "const TInt KModuleFlagFixed=0x%04x;\n", $flag_value_fixed;
sl@0
   643
push @dlltree, sprintf "const TInt KModuleFlagData=0x%04x;\n", $flag_value_data;
sl@0
   644
#push @dlltree, "#ifdef __EPOC32__\n";
sl@0
   645
push @dlltree, sprintf "const TInt KModuleFlagXIP=0x%04x;\n", $flag_value_xip;
sl@0
   646
push @dlltree, sprintf "const TInt KModuleFlagPagedCode=0x%04x;\n", $flag_value_pagedcode;
sl@0
   647
push @dlltree, sprintf "const TInt KModuleFlagUnpagedCode=0x%04x;\n", $flag_value_unpagedcode;
sl@0
   648
push @dlltree, sprintf "const TInt KModuleFlagIDrive=0x%04x;\n", $flag_value_idrive;
sl@0
   649
push @dlltree, sprintf "const TInt KModuleFlagVDrive=0x%04x;\n", $flag_value_vdrive;
sl@0
   650
push @dlltree, sprintf "const TInt KModuleFlagBytePair=0x%04x;\n", $flag_value_bytepair;
sl@0
   651
push @dlltree, sprintf "const TInt KModuleFlagUncompressed=0x%04x;\n", $flag_value_uncompressed;
sl@0
   652
#push @dlltree, "#else\n";
sl@0
   653
#push @dlltree, sprintf "const TInt KModuleFlagXIP=0x%04x;\n", 0;	# no XIPs on emulator
sl@0
   654
#push @dlltree, "#endif\n";
sl@0
   655
push @dlltree, sprintf "const TInt KModuleFlagDllInCycle=0x%04x;\n", $flag_value_dll_in_cycle;
sl@0
   656
push @dlltree, sprintf "const TInt KModuleFlagDataInTree=0x%04x;\n", $flag_value_data_in_tree;
sl@0
   657
#push @dlltree, "#ifdef __EPOC32__\n";
sl@0
   658
push @dlltree, sprintf "const TInt KModuleFlagXIPDataInTree=0x%04x;\n", $flag_value_xip_data_in_tree;
sl@0
   659
#push @dlltree, "#else\n";
sl@0
   660
#push @dlltree, sprintf "const TInt KModuleFlagXIPDataInTree=0x%04x;\n", 0;
sl@0
   661
#push @dlltree, "#endif\n";
sl@0
   662
push @dlltree, sprintf "const TInt KModuleFlagExports=0x%04x;\n", $flag_value_exports;
sl@0
   663
push @dlltree, sprintf "const TInt KModuleFlagTargetOnly=0x%04x;\n", $flag_value_targetonly;
sl@0
   664
push @dlltree, sprintf "const TInt KModuleFlagPagedData=0x%04x;\n", $flag_value_pageddata;
sl@0
   665
push @dlltree, sprintf "const TInt KModuleFlagUnpagedData=0x%04x;\n", $flag_value_unpageddata;
sl@0
   666
push @dlltree, "static const TInt ModuleFlags[KNumModules] =\n";
sl@0
   667
push @dlltree, "\t\{\n";
sl@0
   668
foreach $modref (@modules) {
sl@0
   669
	my $flags=0;
sl@0
   670
	my @flagNames = ();
sl@0
   671
sl@0
   672
	push @flagNames, "KModuleFlagExe" if ($$modref{exe});
sl@0
   673
	push @flagNames, "KModuleFlagFixed" if ($$modref{fixed});
sl@0
   674
	push @flagNames, "KModuleFlagData" if ($$modref{data});
sl@0
   675
	push @flagNames, "KModuleFlagXIP" if ($$modref{xip});
sl@0
   676
	push @flagNames, "KModuleFlagPagedCode" if ($$modref{pagedcode});
sl@0
   677
	push @flagNames, "KModuleFlagUnpagedCode" if ($$modref{unpagedcode});
sl@0
   678
	push @flagNames, "KModuleFlagPagedData" if ($$modref{pageddata});
sl@0
   679
	push @flagNames, "KModuleFlagUnpagedData" if (!$$modref{pageddata});
sl@0
   680
	push @flagNames, "KModuleFlagIDrive" if ($$modref{idrive});
sl@0
   681
	push @flagNames, "KModuleFlagVDrive" if ($$modref{vdrive});
sl@0
   682
	push @flagNames, "KModuleFlagBytePair" if ($$modref{bytepair});
sl@0
   683
	push @flagNames, "KModuleFlagDllInCycle" if ($$modref{cycle});
sl@0
   684
	push @flagNames, "KModuleFlagDataInTree" if ($$modref{dataintree});
sl@0
   685
	push @flagNames, "KModuleFlagXIPDataInTree" if ($$modref{xipdataintree});
sl@0
   686
	push @flagNames, "KModuleFlagExports" if ($$modref{exports});
sl@0
   687
	push @flagNames, "KModuleFlagUncompressed" if ($$modref{uncompressed});
sl@0
   688
	push @flagNames, "KModuleFlagTargetOnly" if ($$modref{targetonly});
sl@0
   689
sl@0
   690
	@flagNames = qw(0) if (scalar(@flagNames) == 0);
sl@0
   691
	my $flagString = "/\* " . $$modref{num} . " \*/\t" . join(' | ', @flagNames);
sl@0
   692
	unless ($$modref{num}==$module_count-1) {
sl@0
   693
		$flagString.=',';
sl@0
   694
	}
sl@0
   695
	push @dlltree, $flagString . "\n";
sl@0
   696
}
sl@0
   697
push @dlltree, "\t\};\n";
sl@0
   698
push @dlltree, "\n";
sl@0
   699
foreach $modref (@modules) {
sl@0
   700
	my $modnum=$$modref{num};
sl@0
   701
	my @rblki;
sl@0
   702
	++$next_mark;
sl@0
   703
	calc_rblki(\@rblki, \@modules, $modref, $next_mark);
sl@0
   704
	my $rblki_count=scalar(@rblki);
sl@0
   705
	my $rblki_sum=0;
sl@0
   706
	foreach (@rblki) {
sl@0
   707
		$rblki_sum += $_;
sl@0
   708
	}
sl@0
   709
	push @dlltree, "static const TInt Module$modnum","RBlkIParams[2] = \{ $rblki_count, $rblki_sum \};\n";
sl@0
   710
}
sl@0
   711
push @dlltree, "\n";
sl@0
   712
push @dlltree, "static const TInt* const ModuleRBlkIParams[KNumModules] =\n";
sl@0
   713
push @dlltree, "\t\{\n";
sl@0
   714
foreach $modref (@modules) {
sl@0
   715
	my $modnum=$$modref{num};
sl@0
   716
	push @dlltree, "\tModule$modnum","RBlkIParams";
sl@0
   717
	if ($$modref{num}==$module_count-1) {
sl@0
   718
		push @dlltree, "\n";
sl@0
   719
	} else {
sl@0
   720
		push @dlltree, ",\n";
sl@0
   721
	}
sl@0
   722
}
sl@0
   723
push @dlltree, "\t\};\n";
sl@0
   724
push @dlltree, "\n";
sl@0
   725
foreach $modref (@modules) {
sl@0
   726
	my $modnum=$$modref{num};
sl@0
   727
	my $mod_attp=$modnum;
sl@0
   728
	my $mod_linkp=$modnum;
sl@0
   729
	unless ($$modref{exe}) {
sl@0
   730
		$mod_attp = ($$modref{attp}) ? ($modref->{attp}->{num}) : -1;
sl@0
   731
		$mod_linkp = ($$modref{linkexe}) ? ($modref->{linkexe}->{num}) : -1;
sl@0
   732
	}
sl@0
   733
	push @dlltree, "static const TInt Module$modnum","ExeInfo[2] = \{ $mod_attp, $mod_linkp \};\n";
sl@0
   734
}
sl@0
   735
push @dlltree, "\n";
sl@0
   736
push @dlltree, "static const TInt* const ModuleExeInfo[KNumModules] =\n";
sl@0
   737
push @dlltree, "\t\{\n";
sl@0
   738
foreach $modref (@modules) {
sl@0
   739
	my $modnum=$$modref{num};
sl@0
   740
	push @dlltree, "\tModule$modnum","ExeInfo";
sl@0
   741
	if ($$modref{num}==$module_count-1) {
sl@0
   742
		push @dlltree, "\n";
sl@0
   743
	} else {
sl@0
   744
		push @dlltree, ",\n";
sl@0
   745
	}
sl@0
   746
}
sl@0
   747
push @dlltree, "\t\};\n";
sl@0
   748
sl@0
   749
foreach $tcref (@testcases) {
sl@0
   750
	push @dlltree, "\n";
sl@0
   751
	my $modlistref=$$tcref{modules};
sl@0
   752
	my $count=$$tcref{count};
sl@0
   753
	my $arraysize=$count+1;
sl@0
   754
	push @dlltree, "static const TInt TC_$$tcref{name}\[$arraysize\]=\n\t\{\n";
sl@0
   755
	if ($count==0) {
sl@0
   756
		push @dlltree, "\t$count\n";
sl@0
   757
	} else {
sl@0
   758
		push @dlltree, "\t$count\,\n";
sl@0
   759
	}
sl@0
   760
	foreach (@$modlistref) {
sl@0
   761
		--$count;
sl@0
   762
		if ($count==0) {
sl@0
   763
			push @dlltree, "\t$_\n";
sl@0
   764
		} else {
sl@0
   765
			push @dlltree, "\t$_\,\n";
sl@0
   766
		}
sl@0
   767
	}
sl@0
   768
	push @dlltree, "\t\};\n";
sl@0
   769
}
sl@0
   770
sl@0
   771
push @dlltree, "#endif\n";
sl@0
   772
push @dlltree, "\n";
sl@0
   773
push @dlltree, "#endif\n";
sl@0
   774
sl@0
   775
foreach $modref (@modules) {
sl@0
   776
	my $mmpname=$$modref{basefilename}.$mmpext;
sl@0
   777
	my $mmpref=$$modref{mmp};
sl@0
   778
	open OUT, ">$mmpname" or die "Could not open $mmpname for output\n";
sl@0
   779
	print OUT @$mmpref;
sl@0
   780
	close OUT;
sl@0
   781
	if ($$modref{exports}) {
sl@0
   782
		my $defname=$$modref{basefilename}.$defext;
sl@0
   783
		my $defref=$$modref{def};
sl@0
   784
		open OUT, ">$defname" or die "Could not open $defname for output\n";
sl@0
   785
		print OUT @$defref;
sl@0
   786
		close OUT;
sl@0
   787
	}
sl@0
   788
}
sl@0
   789
if (!$allowbad) {
sl@0
   790
	push @bldinf, "t_ldrtst\n";
sl@0
   791
}
sl@0
   792
open OUT, ">$bldname" or die "Could not open $bldname for output\n";
sl@0
   793
print OUT @bldinf;
sl@0
   794
close OUT;
sl@0
   795
open OUT, ">$dlltreename" or die "Could not open $dlltreename for output\n";
sl@0
   796
print OUT @dlltree;
sl@0
   797
close OUT;
sl@0
   798
my $testbatch = "$ENV{EPOCROOT}epoc32\\build";
sl@0
   799
$destpath =~ s/\//\\/go;
sl@0
   800
$testbatch.="\\" unless ($destpath =~ /^\\/);
sl@0
   801
$testbatch.=$destpath;
sl@0
   802
$testbatch.="##MAIN##.auto.bat";
sl@0
   803
if (!$allowbad) {
sl@0
   804
	push @iby, "data=$testbatch\t\ttest\\loader.auto.bat\n";
sl@0
   805
}
sl@0
   806
open OUT, ">$ibyname" or die "Could not open $ibyname for output\n";
sl@0
   807
print OUT @iby;
sl@0
   808
close OUT;
sl@0
   809
sl@0
   810
#
sl@0
   811
# Accumulate list of dependency numbers
sl@0
   812
# 1st arg = \output list
sl@0
   813
# 2nd arg = \module list
sl@0
   814
# 3rd arg = \module to start from
sl@0
   815
# 4th arg = mark value to use
sl@0
   816
#
sl@0
   817
sub calc_tc($$$$) {
sl@0
   818
	my ($out, $mods, $modref, $mark)=@_;
sl@0
   819
	my $depsref=$$modref{deps};
sl@0
   820
	foreach $dep (@$depsref) {
sl@0
   821
		my $depref=$$mods[$dep];
sl@0
   822
		if ($$depref{mark} != $mark) {
sl@0
   823
			$$depref{mark}=$mark;
sl@0
   824
			unless ($$depref{exe}) {
sl@0
   825
				calc_tc($out, $mods, $depref, $mark);
sl@0
   826
			}
sl@0
   827
			push @$out, $dep;
sl@0
   828
		}
sl@0
   829
	}
sl@0
   830
}
sl@0
   831
sl@0
   832
#
sl@0
   833
# Accumulate RBlkI parameters
sl@0
   834
# 1st arg = \output list
sl@0
   835
# 2nd arg = \module list
sl@0
   836
# 3rd arg = \module to start from
sl@0
   837
# 4th arg = mark value to use
sl@0
   838
#
sl@0
   839
sub calc_rblki($$$$) {
sl@0
   840
	my ($out, $mods, $modref, $mark)=@_;
sl@0
   841
	if ($$modref{mark} != $mark) {
sl@0
   842
		$$modref{mark}=$mark;
sl@0
   843
		if (!$$modref{exe} and $$modref{data}) {
sl@0
   844
			push @$out, $$modref{num};
sl@0
   845
			my $depsref=$$modref{deps};
sl@0
   846
			foreach $dep (@$depsref) {
sl@0
   847
				calc_rblki($out, $mods, $$mods[$dep], $mark);
sl@0
   848
			}
sl@0
   849
		}
sl@0
   850
	}
sl@0
   851
}
sl@0
   852
sl@0
   853
sl@0
   854