|
1 #!perl -w |
|
2 # baserom |
|
3 # |
|
4 # Copyright (c) 2009 - 2010 Accenture. All rights reserved. |
|
5 # This component and the accompanying materials are made available |
|
6 # under the terms of the "Eclipse Public License v1.0" |
|
7 # which accompanies this distribution, and is available |
|
8 # at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
9 # |
|
10 # Initial Contributors: |
|
11 # Accenture - Initial contribution |
|
12 # |
|
13 use strict; |
|
14 use Cwd; |
|
15 use Getopt::Long; |
|
16 use File::Path; |
|
17 |
|
18 #fwd decls for functions. |
|
19 sub CreateNewObeyFile(); |
|
20 sub ProcessCommandLine(); |
|
21 sub Usage(); |
|
22 sub ConvertIbyLine($); |
|
23 sub FindMissingDeps($); |
|
24 sub ResolveMissingDeps($); |
|
25 sub FindIby($); |
|
26 sub CheckIbyContains($$); |
|
27 sub headerInfo($); |
|
28 sub trim($); |
|
29 sub Query($$); |
|
30 sub makeFullFileName($); |
|
31 |
|
32 |
|
33 # globals |
|
34 my $verbose = 0; |
|
35 my $help; |
|
36 my $epocroot = $ENV{"epocroot"}; |
|
37 my $tempDir = $ENV{"temp"}; |
|
38 my $romIncludeDir; |
|
39 my $obyName; |
|
40 my $obyPath; |
|
41 my $baseObeyFile = "tshell.oby"; |
|
42 my $main = "armv5"; |
|
43 my $build = "udeb"; |
|
44 my $variant = "h4hrp"; |
|
45 my $extraInclude = undef; |
|
46 |
|
47 my %ignoreDeps = ('scppnwdl.dll' => 1, 'drtaeabi.dll' => 1, 'drtrvct2_2.dll' => 1, 'dfpaeabi.dll' => 1, 'dfprvct2_2.dll' => 1); |
|
48 |
|
49 ProcessCommandLine(); |
|
50 |
|
51 my $newObyFile; |
|
52 my $missingCount; |
|
53 my $continue; |
|
54 do { |
|
55 $continue = 0; |
|
56 $newObyFile = CreateNewObeyFile(); |
|
57 my $missingFiles = FindMissingDeps($newObyFile); |
|
58 $missingCount = scalar(@$missingFiles); |
|
59 |
|
60 if ($missingCount) { |
|
61 #print "$missingCount missing dependancies:\n"; |
|
62 #foreach my $dep (@$missingFiles) { |
|
63 # if (defined $dep->[1]) { |
|
64 # print "$dep->[0] UID3: $dep->[1]\n"; |
|
65 # } else { |
|
66 # print "$dep->[0]\n"; |
|
67 # } |
|
68 #} |
|
69 |
|
70 if (Query("\nThere are $missingCount missing dependancies; resolve them now?", "yn")==0) { |
|
71 |
|
72 ResolveMissingDeps($missingFiles); |
|
73 |
|
74 $continue = 1; |
|
75 |
|
76 } else { |
|
77 $newObyFile = CreateNewObeyFile(); |
|
78 } |
|
79 } |
|
80 } while ($missingCount && $continue); |
|
81 |
|
82 print "New OBY file: $newObyFile\n\n"; |
|
83 print "To build a ROM:\n"; |
|
84 print "rom --type tshell_$obyName --inst $main --build $build --variant $variant\n"; |
|
85 exit(0); |
|
86 |
|
87 |
|
88 sub ProcessCommandLine() { |
|
89 Getopt::Long::Configure ("bundling"); |
|
90 GetOptions( 'h' => \$help, |
|
91 'v+' => \$verbose, |
|
92 'e=s' => \$epocroot, |
|
93 'i=s' => \$romIncludeDir, |
|
94 'x=s' => \$extraInclude, |
|
95 'o=s' => \$baseObeyFile, |
|
96 'V=s' => \$variant, |
|
97 't=s' => \$main, |
|
98 'b=s' => \$build); |
|
99 Usage() if ($help); |
|
100 |
|
101 $epocroot = "$epocroot\\" unless $epocroot =~ m/\\$/; |
|
102 my ($drive) = (getcwd =~ m/^(\w)\:/); |
|
103 die "Can't get current drive\n" unless $drive; |
|
104 $epocroot = "$drive:$epocroot"; |
|
105 print "Using epocroot $epocroot\n" if ($verbose); |
|
106 |
|
107 |
|
108 |
|
109 ($romIncludeDir = "epoc32\\rom\\include") unless ($romIncludeDir); |
|
110 $romIncludeDir =~ s/\\$//; # remove trailing \ if it exists |
|
111 $romIncludeDir = "$epocroot$romIncludeDir"; |
|
112 print "Using include directory $romIncludeDir\n" if ($verbose); |
|
113 |
|
114 unless (scalar (@ARGV) == 1) { |
|
115 print "Inavlid arguments\n"; |
|
116 Usage(); |
|
117 } |
|
118 |
|
119 $obyPath = $ARGV[0]; |
|
120 if ($obyPath =~ m/.*[\\\/]([^.]+)\..*/i) { |
|
121 $obyName = $1; |
|
122 } else { |
|
123 $obyName = $obyPath; |
|
124 } |
|
125 |
|
126 die "ERROR: Build must be either 'udeb' or 'urel'\n" unless ($build =~ m/(udeb)|(urel)/i); |
|
127 |
|
128 print "Using variant $variant, build $main $build\n"; |
|
129 } |
|
130 |
|
131 sub CreateNewObeyFile() { |
|
132 unless (-d $obyName) { |
|
133 mkdir $obyName or die "Can't create dir $obyName: $!\n"; |
|
134 } |
|
135 |
|
136 open OBEY, "<$obyPath" or die "Can't open $obyPath: $!\n"; |
|
137 |
|
138 |
|
139 my %ibysProcessed; |
|
140 my @ibyStack; |
|
141 |
|
142 my $obyBaseName; |
|
143 if ($baseObeyFile =~ m/(.*)\.oby/i) { |
|
144 $obyBaseName = $1; |
|
145 } else { |
|
146 $obyBaseName = "tshell"; |
|
147 } |
|
148 |
|
149 my $newObyName = "${obyBaseName}_$obyName.oby"; |
|
150 |
|
151 open TSHELL_OBY, "<$baseObeyFile" or die "Can't open $baseObeyFile: $!\n"; |
|
152 open TSHELL_NEW, ">$newObyName" or die "Can't write to $newObyName: $!\n"; |
|
153 |
|
154 print "Creating tshell_$obyName.oby\n"; |
|
155 |
|
156 while (my $line = <TSHELL_OBY>) { |
|
157 print TSHELL_NEW "$line"; |
|
158 } |
|
159 |
|
160 close (TSHELL_OBY); |
|
161 |
|
162 while (my $line = <OBEY>) { |
|
163 chomp $line; |
|
164 if ($line =~ m/^#include\s+[<"](.*)[>"]/ ) { |
|
165 my $iby = $1; |
|
166 if (!$ibysProcessed{lc($iby)}) { |
|
167 print "Adding $iby to stack\n" if ($verbose); |
|
168 push @ibyStack, $iby; |
|
169 $ibysProcessed{lc($iby)} = 1; |
|
170 } |
|
171 print TSHELL_NEW "#include \"$obyName\\$iby\"\n"; |
|
172 next; |
|
173 } else { |
|
174 print TSHELL_NEW ConvertIbyLine("$line"); |
|
175 print TSHELL_NEW "\n"; |
|
176 } |
|
177 } |
|
178 |
|
179 close TSHELL_NEW; |
|
180 |
|
181 while (my $iby = pop(@ibyStack)) { |
|
182 print "Processing $iby\n" if ($verbose); |
|
183 my $fullIby = "$romIncludeDir\\$iby"; |
|
184 unless (-f $fullIby) { |
|
185 warn "$fullIby does not exist\n" ; |
|
186 next; |
|
187 } |
|
188 |
|
189 my $fixedIby = $iby; |
|
190 $fixedIby =~ s|^(\.\.[\\/])*||; # get rid of ..\ at path start |
|
191 $fixedIby =~ s|^[\\/]||; # remove \ at start too |
|
192 my ($ibyPath, $ibyFile) = ($fixedIby =~ m|^((?:.*[\\/])?)(.*)$|); |
|
193 if (($ibyPath) && (!-d "$obyName\\$ibyPath")) { |
|
194 $ibyPath =~ s|[\\/]$||; |
|
195 mkpath("$obyName\\$ibyPath") or die "Can't create path $obyName\\$ibyPath: $!\n"; |
|
196 $ibyPath .= "/"; |
|
197 } |
|
198 |
|
199 my $newIby = "$obyName\\$ibyPath$ibyFile"; |
|
200 |
|
201 #BEGIN TOMSCI |
|
202 # For the purposes of finding #includes, we run $fulliby through CPP first so that we don't pick up includes that are #ifdef'd out |
|
203 # To prevent the #includes being expanded, we have to change them in the file we run cpp over. |
|
204 open IBY, "<$fullIby" or die "Can't open $fullIby: $!\n"; |
|
205 open NOINCLUDEIBY, ">$newIby.noinclude" or die "Can't open $newIby.noinclude: $!\n"; |
|
206 while (my $line = <IBY>) { |
|
207 $line =~ s/#include/BASEROMHASHINCLUDE/; |
|
208 print NOINCLUDEIBY $line; |
|
209 } |
|
210 close IBY; |
|
211 close NOINCLUDEIBY; |
|
212 my $cppOpts = "-undef -traditional -lang-c++ -nostdinc -I . -I $romIncludeDir"; |
|
213 if ($extraInclude) { |
|
214 if (!($newIby =~ /$extraInclude$/)) { # Make sure we don't include the extraInclude in itself |
|
215 $cppOpts .= " -include $romIncludeDir\\$extraInclude"; |
|
216 } |
|
217 } |
|
218 |
|
219 my $cmd .= "cpp $cppOpts $newIby.noinclude"; |
|
220 print "running: $cmd\n" if ($verbose); |
|
221 open IBYCPP, "$cmd |" or die "Can't run '$cmd': $!\n"; |
|
222 while (my $line = <IBYCPP>) { |
|
223 chomp $line; |
|
224 #print "TOMSCI: $line\n"; |
|
225 if ($line =~ m/^BASEROMHASHINCLUDE\s+[<"](.*)[>"]/ ) { |
|
226 my $iby = $1; |
|
227 if (!$ibysProcessed{lc($iby)}) { |
|
228 print "Adding $iby to stack\n" if ($verbose); |
|
229 push @ibyStack, $iby; |
|
230 $ibysProcessed{lc($iby)} = 1; |
|
231 } |
|
232 } |
|
233 } |
|
234 close IBYCPP; |
|
235 #END TOMSCI |
|
236 |
|
237 open IBY, "<$fullIby" or die "Can't open $fullIby: $!\n"; |
|
238 open NEWIBY, ">$newIby" or die "Can't open $newIby: $!\n"; |
|
239 print "Creating $newIby\n" if ($verbose); |
|
240 |
|
241 while (my $line = <IBY>) { |
|
242 chomp $line; |
|
243 if ($line =~ m/^#include\s+[<"](.*)[>"]/ ) { |
|
244 my $iby = $1; |
|
245 #if (!$ibysProcessed{lc($iby)}) { |
|
246 # print "Adding $iby to stack\n" if ($verbose); |
|
247 # push @ibyStack, $iby; |
|
248 # $ibysProcessed{lc($iby)} = 1; |
|
249 # } |
|
250 print NEWIBY "#include \"$iby\"\n"; |
|
251 next; |
|
252 } else { |
|
253 print NEWIBY ConvertIbyLine("$line"); |
|
254 print NEWIBY "\n"; |
|
255 } |
|
256 } |
|
257 |
|
258 |
|
259 close IBY; |
|
260 close NEWIBY; |
|
261 } |
|
262 return $newObyName; |
|
263 } |
|
264 |
|
265 |
|
266 sub ConvertIbyLine($) { |
|
267 my $line = shift; |
|
268 |
|
269 if ($line =~ m/^\s*\w*ECOM_PLUGIN(?:_UDEB)?\s*\(\s*(.*?)\s*,\s*(.*?)\s*\)\s*$/ ) { |
|
270 my $dll = $1; |
|
271 my $rsc = $2; |
|
272 |
|
273 my ($dllName) = $dll =~ m/^(.*?)\./; |
|
274 $rsc =~ s/[A-Fa-f0-9]{8}\.rs[cs]/$dllName.rsc/; # Some broken IBYs specify .rss instead of .rsc |
|
275 |
|
276 return "file=\\epoc32\\release\\##MAIN\\##BUILD##\\$dll\t\"sys\\bin\\$dll\"\n". |
|
277 "data=\\epoc32\\data\\Z\\resource\\Plugins\\$rsc\t\"resource\\plugins\\$rsc\""; |
|
278 } |
|
279 |
|
280 if ($line =~ m|\\ABI_DIR\\|) { |
|
281 $line =~ s|\\ABI_DIR\\|\\epoc32\\release\\##MAIN##\\|; |
|
282 } else { |
|
283 $line =~ s|ABI_DIR\\|\\epoc32\\release\\##MAIN##\\|; |
|
284 } |
|
285 $line =~ s|\\BUILD_DIR\\|\\##BUILD##\\|; |
|
286 $line =~ s|\\DEBUG_DIR\\|\\##BUILD##\\|; |
|
287 $line =~ s|\\USB_DIR\\|\\##BUILD##\\|; |
|
288 $line =~ s|ZRESOURCE\\|\\epoc32\\data\\Z\\resource\\|; |
|
289 $line =~ s|ZPRIVATE\\|\\epoc32\\data\\Z\\private\\|; |
|
290 $line =~ s|ZSYSTEM\\|\\epoc32\\data\\Z\\system\\|; |
|
291 $line =~ s|DATAZ_\\|\\epoc32\\data\\Z\\|; |
|
292 |
|
293 if ($line =~ m|MULTI_LINGUIFY\s*\(\s*RSC\s+(.*?)\s+(.*?)\s*\)|) { |
|
294 my $localRsc = $1; |
|
295 my $romRsc = $2; |
|
296 |
|
297 my @resources = <$epocroot$localRsc.R*>; |
|
298 |
|
299 if (scalar(@resources)) { |
|
300 $localRsc = $resources[0]; |
|
301 my $er = $epocroot; |
|
302 $er =~ s/\\/\\\\/g; |
|
303 $localRsc =~ s|$er|\\|; |
|
304 #print "FOUND: $localRsc\n"; |
|
305 } else { |
|
306 print "WARNING: resource for $romRsc could not be found\n"; |
|
307 $localRsc .= ".RSC"; |
|
308 } |
|
309 |
|
310 $line = "data=$localRsc\t\"$romRsc.RSC\""; |
|
311 } |
|
312 |
|
313 if ($line =~ m|^#\s*include (["^])(.*?)([">])(.*)$|) { |
|
314 my ($firstQuote, $include, $lastQuote, $extra) = ($1, $2, $3, $4); |
|
315 $include =~ s|^(\.\.[\\/])*||; |
|
316 $include =~ s|^[\\/]||; |
|
317 $line = "#include $firstQuote$include$lastQuote$extra\n"; |
|
318 } |
|
319 |
|
320 return $line; |
|
321 } |
|
322 |
|
323 |
|
324 sub Usage() { |
|
325 require Pod::Text; |
|
326 print "\n"; |
|
327 my $parser = Pod::Text->new(); |
|
328 $parser->parse_from_file($0); |
|
329 exit; |
|
330 } |
|
331 |
|
332 |
|
333 sub FindMissingDeps($) { |
|
334 my $obyFile = shift; |
|
335 print "Checking dependancies...\n"; |
|
336 |
|
337 my $ibys = {}; |
|
338 my $filesByName = {}; |
|
339 my $filesByUid = {}; |
|
340 |
|
341 |
|
342 # since cpp doesn't deal with macros inside #include's, do it manually here: |
|
343 print "Manually processing $obyFile\n" if ($verbose); |
|
344 open IBY, "<$obyFile" or die "Can't open $obyFile: $!\n"; |
|
345 my $ibyFile = "$tempDir\\baserom.tmp"; |
|
346 open TEMPIBY, ">$ibyFile" or die "Can't open $ibyFile: $!\n"; |
|
347 |
|
348 while (my $line = <IBY>) { |
|
349 $line =~ s/\#\#VARIANT\#\#/$variant/; |
|
350 $line =~ s/^\s*#/#/; |
|
351 print TEMPIBY $line; |
|
352 } |
|
353 close IBY; |
|
354 close TEMPIBY; |
|
355 |
|
356 my $cppOpts = "-undef -traditional -lang-c++ -nostdinc -I . -I ${epocroot}epoc32 -DVARIANT=$variant -DBUILD=$build -DMAIN=$main -DEUSERDIR=$main -DKMAIN=$main"; |
|
357 |
|
358 my $cmd .= "cpp $cppOpts $ibyFile"; |
|
359 print "running: $cmd\n" if ($verbose); |
|
360 |
|
361 open CPP, "$cmd |" or die "Can't run '$cmd': $!\n"; |
|
362 while (my $line = <CPP>) { |
|
363 chomp $line; |
|
364 #print "\tCPP:$.:$line\n"; |
|
365 $line =~ s/EPOCROOT##/\\/; |
|
366 $line =~ s/##//g; |
|
367 |
|
368 my $executableSrc = undef; |
|
369 my $executableTrg = undef; |
|
370 |
|
371 if ($line =~ m/^# 1 "(.*)" 1/) { |
|
372 my $includedIby = $1; |
|
373 print "iby included by cpp: $includedIby\n" if ($verbose); |
|
374 $ibys->{lc($includedIby)} = 1; |
|
375 } elsif ($line =~ m/^#/) { |
|
376 # ignore - line inserted by c preprocessor |
|
377 $line = ""; |
|
378 } elsif ($line =~ m/^\s*file\s*=\s*(.*?)\s+(.*)$/) { |
|
379 $executableSrc = $1; |
|
380 $executableTrg = trim $2; |
|
381 } elsif ($line =~ m/^\s*(device|extension|primary|variant|file)\[0x[0-9A-Fa-f]{8}\]\s*=\s*(.*?)\s+(.*)$/) { |
|
382 $executableSrc = $2; |
|
383 $executableTrg = trim $3; |
|
384 } elsif ($line =~ m|^\s*ECOM_PLUGIN\(\s*(.*?)\s*,| ) { |
|
385 $executableSrc = $1; |
|
386 $executableTrg = $executableSrc; |
|
387 } elsif ($line =~ m|^\s*secondary\s*=(.*?)\s+(.*)$| ) { |
|
388 $executableSrc = $1; |
|
389 $executableTrg = trim $2; |
|
390 } elsif ($line =~ m|^\s*data\s*=(.*?)\s|) { |
|
391 my $data = $1; |
|
392 print "WARNING: file $data not found\n" unless (-f "$epocroot$data"); |
|
393 } elsif (length(trim($line))==0) { |
|
394 # ignore empty line |
|
395 } elsif ($line =~ m|^\s*REM\s.*$|i) { |
|
396 # comment, ignore. |
|
397 } elsif ($line =~ m|^\s*patchdata\s.*$| ) { |
|
398 # patchdata - ignore |
|
399 } elsif ($line =~ m|^files=$|) { |
|
400 # tshell.oby contains this line, not sure why. |
|
401 } elsif ($line =~ m/^\s*PlatSec(Diagnostics|Enforcement|ProcessIsolation|EnforceSysBin)\s*(ON|OFF)\s*$/) { |
|
402 # ignore platsec stuff |
|
403 } elsif ($line =~ m/^\s*(debugport|kerneltrace|memmodel|trace|collapse|multikernel|version|bootbinary|romsize|romlinearbase|romalign|(kernel)?dataaddress|kernelheap(max|min)|defaultstackreserve|romchecksum|nowrapper|pagingpolicy)/) { |
|
404 # rom config stuff, ignore |
|
405 } elsif ($line =~ m/^\s*#/) { |
|
406 # We ignore any other preprocessor directive |
|
407 } else { |
|
408 print "OBY line not recognised: $line\n"; |
|
409 } |
|
410 |
|
411 if ((defined $executableSrc) && (! ($executableSrc =~ m|eka1_entry_stub\.dll$|)) ) { |
|
412 |
|
413 #die "Cannot find file ${epocroot}$executableSrc\n" unless (-f "${epocroot}$executableSrc"); |
|
414 # Assume anything like BTDEBUG_DIR should equate to urel |
|
415 $executableSrc =~ s/\\[A-Z]+_DIR\\/\\urel\\/; |
|
416 |
|
417 if (!(-f "${epocroot}$executableSrc")) { |
|
418 print "WARNING: Can't find ${epocroot}$executableSrc, skipping dependancy check\n"; |
|
419 next; |
|
420 } |
|
421 |
|
422 my $exeOnly = lc $executableSrc; |
|
423 $exeOnly =~ s/.*\\//; |
|
424 my $exeOnlyTrg = lc $executableTrg; |
|
425 $exeOnlyTrg =~ s/.*\\//; |
|
426 |
|
427 my $uid3 = (headerInfo("${epocroot}$executableSrc"))[3]; |
|
428 if (defined $uid3) { |
|
429 if ($filesByName->{$exeOnlyTrg}) { |
|
430 print "WARNING: 2 files with name $exeOnlyTrg in rom\n"; |
|
431 } |
|
432 $filesByName->{$exeOnlyTrg} = $executableSrc; |
|
433 if (!($uid3 eq "00000000")) { |
|
434 $filesByUid->{$uid3} = $executableSrc; |
|
435 print "UID3 for $executableSrc: $uid3\n" if ($verbose>1); |
|
436 } |
|
437 } else { |
|
438 print "WARNING: could not find UID3 for $executableSrc\n" |
|
439 } |
|
440 |
|
441 |
|
442 } |
|
443 |
|
444 } |
|
445 |
|
446 close CPP; |
|
447 |
|
448 |
|
449 # now check for missing dependancies |
|
450 my @missingFiles; |
|
451 |
|
452 foreach my $dependancy (keys %$filesByName) { |
|
453 |
|
454 my $executable = $filesByName->{$dependancy}; |
|
455 |
|
456 $cmd = "elftran -dump i ${epocroot}$executable"; |
|
457 print "running: $cmd\n" if ($verbose); |
|
458 |
|
459 open ELFTRAN, "$cmd|" or die "Couldn't run $cmd: $!\n"; |
|
460 |
|
461 while (my $line = <ELFTRAN>) { |
|
462 if ($line =~ m/^\d+ imports from (.*)$/) { |
|
463 my $dep = lc($1); |
|
464 |
|
465 my $depName = undef; |
|
466 my $depUid = undef; |
|
467 |
|
468 if ($dep =~ m/^(.*?)\{[a-f0-9]{8}\}\[([a-f0-9]{8})\]\.(.*)$/ ) { |
|
469 unless ($ignoreDeps{lc("$1.$3")}) { |
|
470 $depName = "$1.$3"; |
|
471 $depUid = $2; |
|
472 } |
|
473 } elsif ($dep =~ m/^(.*?)\{[a-f0-9]{8}\}\.(.*)$/ ) { |
|
474 unless ($ignoreDeps{lc("$1.$2")}) { |
|
475 $depName = "$1.$2"; |
|
476 } |
|
477 } else { |
|
478 print "WARNING: dependancy name '$dep' could not be parsed\n"; |
|
479 } |
|
480 |
|
481 |
|
482 if (defined $depName) { |
|
483 print "$executable links to $depName\n" if ($verbose>1); |
|
484 if ((defined $depUid) && ($filesByUid->{$depUid})) { |
|
485 print "Found match by UID3: $filesByUid->{$depUid} ($depUid)\n" if ($verbose>1); |
|
486 } elsif ($filesByName->{lc($depName)}) { |
|
487 my $uid3 = $filesByName->{lc($depName)}; |
|
488 #print "WARNING: Found match by name but not UID: $depName UID3: $uid3 expected $depUid\n"; |
|
489 } else { |
|
490 my $fullDepName = makeFullFileName($depName); |
|
491 if (defined $depUid) { |
|
492 print "Missing dependancy: $depName (UID3 $depUid) required by $executable\n"; |
|
493 $filesByUid->{$depUid} = $fullDepName; |
|
494 } else { |
|
495 print "Missing dependancy: $depName required by $executable\n"; |
|
496 } |
|
497 push @missingFiles, [$depName, $depUid]; |
|
498 #print "WARNING: can't find dependancy $depName at $fullDepName\n" unless (-f $fullDepName); |
|
499 $filesByName->{lc($depName)} = $fullDepName; |
|
500 } |
|
501 |
|
502 } |
|
503 } |
|
504 } |
|
505 |
|
506 |
|
507 |
|
508 |
|
509 close (ELFTRAN); |
|
510 } |
|
511 |
|
512 return \@missingFiles; |
|
513 |
|
514 } |
|
515 |
|
516 |
|
517 sub ResolveMissingDeps($) { |
|
518 my $missingFiles = shift; |
|
519 |
|
520 my %addedIbys; |
|
521 |
|
522 foreach my $depInfo (@$missingFiles) { |
|
523 |
|
524 my $expectedDepPath = makeFullFileName $depInfo->[0]; |
|
525 |
|
526 # find an IBY file than contains this dependancy |
|
527 my $ibyFile = FindIby($depInfo->[0]); |
|
528 |
|
529 if (defined $ibyFile) { |
|
530 print "\nFound $depInfo->[0] in $ibyFile\n"; |
|
531 } elsif (-f $expectedDepPath) { |
|
532 if (Query("\nCan't find IBY file for $depInfo->[0] based on components exports.\nSearch all of $romIncludeDir instead?", "yn") == 0) { |
|
533 print "Not implemented yet, sorry!\n"; |
|
534 } |
|
535 } else { |
|
536 print "IBY file for $depInfo->[0] not found, and $expectedDepPath does not exist.\n"; |
|
537 } |
|
538 |
|
539 my $lineToAdd = undef; |
|
540 if (defined $ibyFile) { |
|
541 |
|
542 if ($addedIbys{$ibyFile}) { |
|
543 print "$ibyFile already included.\n"; |
|
544 } else { |
|
545 |
|
546 my $continue; |
|
547 |
|
548 do { |
|
549 $continue = 0; |
|
550 my $option = Query("Do you want to include whole (I)BY file, just the one (f)ile or (n)either? (or (v)iew the IBY contents)", "ifnv"); |
|
551 if ($option==0) { |
|
552 $addedIbys{$ibyFile}=1; |
|
553 |
|
554 my $romIncludeMatchStr = $romIncludeDir; |
|
555 $romIncludeMatchStr =~ s|^\w\:\\||; |
|
556 $romIncludeMatchStr =~ s|\\|\\\\|g; |
|
557 my $shortIby = $ibyFile; |
|
558 $shortIby =~ s|.*$romIncludeMatchStr||i; |
|
559 $shortIby =~ s|^\\*||; |
|
560 $lineToAdd = "#include \"$shortIby\""; |
|
561 } elsif ($option==1) { |
|
562 $lineToAdd = "file=ABI_DIR\\DEBUG_DIR\\$depInfo->[0]\t\\sys\\bin\\$depInfo->[0]"; |
|
563 } elsif ($option==3) { |
|
564 $continue=1; |
|
565 |
|
566 open IBYFILE, "<$ibyFile" or die "ERROR: Can't open $ibyFile: $!\n"; |
|
567 print "$ibyFile:\n"; |
|
568 while (<IBYFILE>) { |
|
569 print; |
|
570 } |
|
571 print "\n"; |
|
572 } |
|
573 } while ($continue); |
|
574 } |
|
575 } elsif (-f $expectedDepPath) { |
|
576 if (Query("\nIBY file for $depInfo->[0] not found; include single file?", "yn")==0) { |
|
577 $lineToAdd = "file=ABI_DIR\\DEBUG_DIR\\$depInfo->[0]\t\\sys\\bin\\$depInfo->[0]"; |
|
578 } |
|
579 } else { |
|
580 # perhaps we could search in \release\$main\$build for a binary with the required UID3 value. |
|
581 # might be worth implementing later? |
|
582 print "WARNING: $expectedDepPath does not exist, manual resolution of dependancy likely needed.\n"; |
|
583 } |
|
584 |
|
585 |
|
586 |
|
587 if (defined $lineToAdd) { |
|
588 open OBYFILE, ">>$obyName.oby" or die "Can't append to $obyName.oby: $!\n"; |
|
589 print "Adding line:\n"; |
|
590 print "$lineToAdd\n"; |
|
591 print OBYFILE "$lineToAdd\n"; |
|
592 close OBYFILE; |
|
593 } |
|
594 |
|
595 } |
|
596 |
|
597 print "\n"; |
|
598 |
|
599 } |
|
600 |
|
601 sub FindIby($) { |
|
602 my $file = shift; |
|
603 my $fullFile = makeFullFileName $file; |
|
604 return undef unless (-f $fullFile); |
|
605 my $cmd = "bininfo $fullFile"; |
|
606 print "$cmd\n" if ($verbose); |
|
607 |
|
608 my @ibys; |
|
609 my $comp = undef; |
|
610 |
|
611 if (open BININFO, "$cmd |") { |
|
612 while (my $line = <BININFO>) { |
|
613 if ($line =~ m/^Component\:\s*(.*)$/) { |
|
614 $comp = trim($1); |
|
615 print "$comp owns $fullFile\n" if ($verbose>1); |
|
616 } |
|
617 } |
|
618 close (BININFO); |
|
619 |
|
620 return undef unless defined ($comp); |
|
621 |
|
622 $cmd = "bininfo $comp"; |
|
623 print "$cmd\n" if ($verbose); |
|
624 if (open BININFO2, "$cmd |") { |
|
625 while (my $line = <BININFO2>) { |
|
626 if ($line =~ m/^File\s+Status\s*$/ ) { |
|
627 # ignore header line |
|
628 } elsif ($line =~ m/^\s*$/ ) { |
|
629 # ignore emptry line |
|
630 } elsif ($line =~ m/^(.*?)\s+\w+\s*$/ ) { |
|
631 my $file = trim($1); |
|
632 if ($file =~ m/\.iby$/i) { |
|
633 push @ibys, $file; |
|
634 } |
|
635 } else { |
|
636 print "WARNING: could not parse bininfo output '$line'\n" if ($verbose); |
|
637 } |
|
638 } |
|
639 close BININFO2; |
|
640 |
|
641 } else { |
|
642 print "WARNING: could not run '$cmd': $!\n"; |
|
643 return undef; |
|
644 } |
|
645 |
|
646 |
|
647 } else { |
|
648 print "WARNING: could not run '$cmd': $!\n"; |
|
649 return undef; |
|
650 } |
|
651 |
|
652 my $num = scalar(@ibys); |
|
653 print "$comp owns $num IBY file(s)\n" if ($verbose); |
|
654 |
|
655 return undef if ($num == 0); |
|
656 return $ibys[0] if ($num == 1); |
|
657 |
|
658 my $compSubName; |
|
659 if ($comp =~ m/.*_(.*)/ ) { |
|
660 $compSubName = $1; |
|
661 } else { |
|
662 $compSubName = $comp; |
|
663 } |
|
664 |
|
665 my $chosenIby = undef; |
|
666 |
|
667 foreach my $iby (@ibys) { |
|
668 if ($iby =~ m/\\$compSubName\.iby$/i) { |
|
669 $chosenIby = $iby; |
|
670 print "Choosing IBY file $iby for component $comp based on name\n" if ($verbose); |
|
671 last; |
|
672 } |
|
673 } |
|
674 |
|
675 return $chosenIby if ((defined $chosenIby) && (CheckIbyContains($chosenIby, $file))); |
|
676 |
|
677 # last resort: the first iby file that contains this file |
|
678 |
|
679 foreach my $iby (@ibys) { |
|
680 return $iby if (CheckIbyContains($iby, $file)); |
|
681 } |
|
682 |
|
683 return undef; |
|
684 |
|
685 } |
|
686 |
|
687 sub CheckIbyContains($$) { |
|
688 my $iby = shift; |
|
689 my $file = shift; |
|
690 print "Checking for $file in $iby\n" if ($verbose>1); |
|
691 open IBYFILE, "<$iby" or return 0; |
|
692 |
|
693 my $found = 0; |
|
694 while (my $line = <IBYFILE>) { |
|
695 if ($line =~ m/\\$file\s/i) { |
|
696 $found = 1; |
|
697 last; |
|
698 } |
|
699 } |
|
700 |
|
701 close IBYFILE; |
|
702 |
|
703 print "$iby contains $file\n" if ($found && $verbose); |
|
704 print "$iby does not contain $file\n" if ((!$found) && $verbose); |
|
705 |
|
706 return $found; |
|
707 } |
|
708 |
|
709 sub headerInfo($) { |
|
710 my $file = shift; |
|
711 my $cmd = "elftran -dump h $file"; |
|
712 print "running: $cmd\n" if ($verbose); |
|
713 open ELFTRANUID, "$cmd|" or die "Couldn't run $cmd: $!\n"; |
|
714 |
|
715 my ($flags, $uid1, $uid2, $uid3) = (undef, undef, undef, undef); |
|
716 while (my $line = <ELFTRANUID>) { |
|
717 if ($line =~ m/^Uids:\s+([\da-f]{8})\s+([\da-f]{8})\s+([\da-f]{8})\s+\(([\da-f]{8})\)$/ ) { |
|
718 ($uid1, $uid2, $uid3) = ($1, $2, $3); |
|
719 } elsif ($line =~ m/^Flags:\s+([\da-f]{8})$/i) { |
|
720 $flags = $1; |
|
721 } |
|
722 } |
|
723 close (ELFTRANUID); |
|
724 return ($flags, $uid1, $uid2, $uid3); |
|
725 } |
|
726 |
|
727 |
|
728 |
|
729 sub trim($) { |
|
730 my $str= shift; |
|
731 $str =~ s/^\s*//g; |
|
732 $str =~ s/\s*$//g; |
|
733 return $str; |
|
734 } |
|
735 |
|
736 sub Query($$) { |
|
737 my $question = shift; |
|
738 my $options = shift; |
|
739 local $" = '/'; |
|
740 #" fix syntax highlighting from above in CW |
|
741 my @options = split(//, $options); |
|
742 while (1) { |
|
743 print "$question [@options] "; |
|
744 my $response = lc <STDIN>; |
|
745 chomp $response; |
|
746 |
|
747 if (length($response)==1) { |
|
748 if ($options =~ m/$response/g) { |
|
749 return pos($options)-1; |
|
750 } |
|
751 } |
|
752 } |
|
753 |
|
754 } |
|
755 |
|
756 sub makeFullFileName($) { |
|
757 my $depName = shift; |
|
758 return "${epocroot}epoc32\\release\\$main\\$build\\$depName" |
|
759 } |
|
760 |
|
761 __END__ |
|
762 |
|
763 =head1 NAME |
|
764 |
|
765 BaseRom - A tool to help you build a base ROM with selected user-side binaries. |
|
766 |
|
767 =head1 SYNOPSIS |
|
768 |
|
769 baserom [options] F<romname> |
|
770 |
|
771 options: |
|
772 |
|
773 =over |
|
774 |
|
775 =item -V variant |
|
776 |
|
777 Use the specified variant; defaults to C<h4hrp>. (note capital V). |
|
778 |
|
779 =item -t target |
|
780 |
|
781 Use the specified target architecture; defaults to C<armv5>. |
|
782 |
|
783 =item -b build |
|
784 |
|
785 Use the specified build; defaults to C<udeb>. |
|
786 |
|
787 =item -e F<\epocroot\> |
|
788 |
|
789 Use specified epocroot path instead of environment variable epocroot. |
|
790 |
|
791 =item -i F<\rom\include\directory> |
|
792 |
|
793 Use the specified directory to search for IBY files. Defaults to F<\epoc32\rom\include>. |
|
794 |
|
795 =item -o F<base.oby> |
|
796 |
|
797 Use the specified OBY file as the basis for the ROM. Defaults to F<tshell.oby>. |
|
798 |
|
799 =item -h |
|
800 |
|
801 help |
|
802 |
|
803 =item -v |
|
804 |
|
805 verbose (-vv very verbose) |
|
806 |
|
807 =item -x extraInclude |
|
808 |
|
809 If specified this file is included whenever preprocessing IBYs. It also prevents this file from being processed for dependancies itself. This option is needed when building an toolkit rom and should be set to C<-x fsh_config.iby>. |
|
810 |
|
811 =back |
|
812 |
|
813 =head1 DESCRIPTION |
|
814 |
|
815 The script is written to help you determine the dependancies that need to be included in a ROM to be able to use |
|
816 specific functionality. It also builds the appropriate OBY file. |
|
817 |
|
818 To use it: |
|
819 |
|
820 =over |
|
821 |
|
822 =item 1 |
|
823 |
|
824 do a C<getsource base_e32> if you don't already have the source |
|
825 |
|
826 =item 2 |
|
827 |
|
828 create a file F<myrom.oby> in F<\src\cedar\generic\base\e32\rombuild\>. In this, include the top level IBY file (or executables, etc) that |
|
829 you need to include in your ROM. Use OBY syntax that is used by the main rombuild tool (i.e. not the base one), for example: |
|
830 |
|
831 #include <mmf.iby> |
|
832 file=ABI_DIR\BUILD_DIR\MyTestHarness.exe sys\bin\MyTestHarness.exe |
|
833 |
|
834 =item 3 |
|
835 |
|
836 run C<baserom myrom>. This will cause the script to create a new OBY file based on F<tshell.oby> called F<tshell_myrom.oby>. |
|
837 It will also copy any required IBY files from the default ROM include directory (F<\epoc32\rom\include> by default) into a new directory |
|
838 called F<myrom>. The format of the IBY files is converted for the base ROM building tool. |
|
839 |
|
840 =item 4 |
|
841 |
|
842 The script will the check the dependancies for the executables in your ROM. Any files that are missing will be listed, and it will give |
|
843 you the option of attempting to resolve the dependancies. |
|
844 |
|
845 =item 5 |
|
846 |
|
847 If you choose the resolve the dependancies, the script will search for appropriate IBY files and ask you whether you want to include |
|
848 the whole IBY file in your ROM, or just include the 1 dependancy via a C<file=> statement. |
|
849 |
|
850 =item 6 |
|
851 |
|
852 Once you have worked through all the dependancies, it will start again from step 3, allowing you to iteratively resolve all your |
|
853 dependancies. Some often have to be resolved by hand, for example binaries that have a different name depending upon the variant |
|
854 that you are building for. |
|
855 |
|
856 =item 7 |
|
857 |
|
858 When you are done, it will tell you the command to use to build the ROM. |
|
859 |
|
860 =back |
|
861 |
|
862 =head1 NOTES |
|
863 |
|
864 =head2 Resolving dependancies |
|
865 |
|
866 Generally, when choosing whether or not to include an entire IBY file for a dependancy, you need to use to use some judgement. Including |
|
867 the whole IBY file has the benefit that you won't end up including a user-side DLL for a server but not the server itself. You should |
|
868 do this if you actually need to use the services provided by that server (ECOM is usually a good example of this). |
|
869 |
|
870 Including just the dependancy DLL is good if you only need to include it to satisfy linking requirements, but you never actually need to |
|
871 call into that DLL (i.e. to stop the rom build failing). For example, if your code links to F<c32.dll> but never actually uses it, it's best |
|
872 to just include that one file rather than including F<c32.iby>. |
|
873 |
|
874 Always including the whole IBY file generally results in the dependancies growing very fast until you are including pretty much the whole OS. |
|
875 |
|
876 Including F<wserv.iby> can cause problems in a C<tshell> ROM, as then you'll end up with two files trying to be F<EwSrv.exe> in the ROM. |
|
877 |
|
878 Generally, after a few iterations you can resolve most of the dependancies in your ROM, and those that remain must be done by hand, or can |
|
879 be ignored. |
|
880 |
|
881 =head3 Manually Resolving dependancies |
|
882 |
|
883 Some dependancies the script will fail to resolve automatically. For example, something that links to the screen driver F<ScDv.dll> will |
|
884 cause problems because F<ScDv.dll> doesn't exist in F<\epoc32\release\armv5\udeb> or similar places - it's actually called F<_omapqvga_scdv.dll> |
|
885 for the H4, and other things for other platforms. |
|
886 |
|
887 Generally, when the script has finished resolving dependancies automatically, you can work these out by yourself. In the example of F<ScDv.dll>, |
|
888 looking in F<\epoc32\rom\include\base_h4hrp.iby> does the trick: |
|
889 |
|
890 define SCDV_DLL _omapqvga_scdv.dll |
|
891 |
|
892 Then you can manually include the following line in your F<myrom.oby> file: |
|
893 |
|
894 file=ABI_DIR\DEBUG_DIR\_omapqvga_scdv.dll \sys\bin\ScDv.dll |
|
895 |
|
896 The same trick for other files should work. After editing F<myrom.oby> you need to run the script on it again to update the generated OBY file. |
|
897 |
|
898 =head2 Finding IBY files |
|
899 |
|
900 When finding an IBY file for a given file, the tool does the following: |
|
901 |
|
902 =over |
|
903 |
|
904 =item 1 |
|
905 |
|
906 determine the CBR component that owns the file, using C<bininfo> |
|
907 |
|
908 =item 2 |
|
909 |
|
910 use C<bininfo> again to find a list of IBY files owned by that component. |
|
911 |
|
912 =item 3 |
|
913 |
|
914 If it owns just 1 IBY file, use that if it includes the file we're looking for. Otherwise, |
|
915 |
|
916 =item 4 |
|
917 |
|
918 Find the IBY file whose name closely matches the components name For example, for the component C<graphics_wserv> it will prefer |
|
919 an IBY file called F<wserv.iby>, or F<graphics_wserv.iby>. If one matches on this basis, use it. Otherwise, |
|
920 |
|
921 =item 5 |
|
922 |
|
923 Use the first IBY file owned by the component that contains the file needed. |
|
924 |
|
925 =back |
|
926 |
|
927 =head1 COPYRIGHT |
|
928 |
|
929 Copyright (c) 2009 - 2010 Accenture. All rights reserved. |
|
930 |
|
931 =cut |