|
1 # Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 # All rights reserved. |
|
3 # This component and the accompanying materials are made available |
|
4 # under the terms of "Eclipse Public License v1.0" |
|
5 # which accompanies this distribution, and is available |
|
6 # at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 # |
|
8 # Initial Contributors: |
|
9 # Nokia Corporation - initial contribution. |
|
10 # |
|
11 # Contributors: |
|
12 # |
|
13 # Description: |
|
14 # |
|
15 |
|
16 # modified start: makefile improvement |
|
17 use Cwd; |
|
18 # modified end: makefile improvement |
|
19 use Digest::MD5; |
|
20 use File::Basename; |
|
21 |
|
22 package featurevariantmap; |
|
23 our $verbose = 0; |
|
24 |
|
25 my $featureListDir = "$ENV{EPOCROOT}epoc32\\include\\variant\\featurelists"; |
|
26 |
|
27 sub LoadFeatureList |
|
28 { |
|
29 my %featurehash; |
|
30 |
|
31 # Try and find the feature master list folder |
|
32 if (!opendir DIR, $featureListDir) |
|
33 { |
|
34 print "\nERROR: Failed to open feature list directory $featureListDir: $!"; |
|
35 return \%featurehash; |
|
36 } |
|
37 |
|
38 # Load the list of features from each file |
|
39 foreach my $file ( grep(/\.txt$/i, readdir DIR) ) |
|
40 { |
|
41 $file = "$featureListDir\\$file"; |
|
42 print "Reading feature list from $file\n" if ($verbose); |
|
43 |
|
44 if (!open IN, $file) |
|
45 { |
|
46 print "\nERROR: Failed to read feature list $file: $!"; |
|
47 } |
|
48 else |
|
49 { |
|
50 while(my $line = <IN>) |
|
51 { |
|
52 $line =~ s/\/\/.+$//; # Get rid of c++ style comments |
|
53 if ($line =~ /(\S+)/) |
|
54 { |
|
55 $featurehash{$1} = $file; |
|
56 } |
|
57 } |
|
58 close IN; |
|
59 } |
|
60 |
|
61 } |
|
62 closedir DIR; |
|
63 return \%featurehash; |
|
64 } |
|
65 |
|
66 sub ValidFeature |
|
67 { |
|
68 our $featurelist; |
|
69 my $name = shift; |
|
70 |
|
71 $featurelist = LoadFeatureList() if !$featurelist; |
|
72 return exists $featurelist->{$name}; |
|
73 # modified start: makefile improvement |
|
74 } |
|
75 sub GetVariantListFromVmap |
|
76 { |
|
77 my $obj = shift; |
|
78 my $vmapfile = shift; |
|
79 if(open(VMAP, "<$vmapfile")) |
|
80 { |
|
81 my @varlist; |
|
82 while(<VMAP>) |
|
83 { |
|
84 if(/^\w{32}\s+(\w+)/) |
|
85 { |
|
86 push @varlist, $1; |
|
87 } |
|
88 |
|
89 } |
|
90 close(VMAP); |
|
91 return @varlist; |
|
92 } |
|
93 close(VMAP); |
|
94 return; |
|
95 |
|
96 } |
|
97 sub CheckOldVmapFile |
|
98 { |
|
99 my $thisObj = shift; |
|
100 my $vmapfile = shift; |
|
101 my $varRef = shift; |
|
102 my $buildincludes = $$varRef{BUILD_INCLUDES}; |
|
103 my $parents = $$varRef{PARENTS}; |
|
104 my $children = $$varRef{CHILDREN}; |
|
105 my $varianthrh = $$varRef{VARIANT_HRH}; |
|
106 my %variantMacrolist; |
|
107 my $Options = "-dM -undef -nostdinc -+"; |
|
108 my $Drive = $1 if (Cwd->cwd =~ /^(.:)/); |
|
109 if($buildincludes) |
|
110 { |
|
111 foreach (@$buildincludes) |
|
112 { |
|
113 $Options .= " -I \"".$Drive.$_."\""; |
|
114 } |
|
115 } |
|
116 if($varianthrh) |
|
117 { |
|
118 $Options .= " \"".$Drive.$varianthrh."\""; |
|
119 } |
|
120 if(open(CPP, "cpp $Options 2>&1 |")) |
|
121 { |
|
122 while(<CPP>) |
|
123 { |
|
124 my ( $key, $value ); |
|
125 if (/^#define (\w+(?:\([^\)]*\))?)(?:\s(\S.*?))?\s*$/) |
|
126 { |
|
127 my $tmpKey = $1; |
|
128 my $tmpValue = $2; |
|
129 $tmpValue =~ s/,/\\,/g; |
|
130 ($key, $value ) = ( $tmpKey, $tmpValue ? "\'$tmpValue\'" : 'defined' ); |
|
131 } |
|
132 if ($key && ValidFeature($key)) |
|
133 { |
|
134 $variantMacrolist{$key} = $value; |
|
135 } |
|
136 } |
|
137 if(!close(CPP)) |
|
138 { |
|
139 print "Incomplete pre-precess of $varianthrh \n"; |
|
140 } |
|
141 } |
|
142 my $findReusedKey = 1; |
|
143 my %vmapfeatureinfo; |
|
144 my $keyhash; |
|
145 my $macroList; |
|
146 if(open(VMAP, "<$vmapfile")) |
|
147 { |
|
148 while(<VMAP>) |
|
149 { |
|
150 if(/^\w{32}\s+(\w+)/) |
|
151 { |
|
152 $findReusedKey = 1; |
|
153 s/(^\w{32})\s+\w+\s+//; |
|
154 $keyhash = $1; |
|
155 my @feature = split(/(?<=[^\\]),/, $_); |
|
156 foreach my $value (@feature) |
|
157 { |
|
158 if($value =~ /([^\s]*)\s*=\s*(.*)/) |
|
159 { |
|
160 $vmapfeatureinfo{$1} = $2; |
|
161 } |
|
162 } |
|
163 foreach my $key (sort keys %vmapfeatureinfo) |
|
164 { |
|
165 |
|
166 if(($vmapfeatureinfo{$key} eq "undefined") && (not(exists($variantMacrolist{$key})))) |
|
167 { |
|
168 $findReusedKey = 1; |
|
169 } |
|
170 elsif($vmapfeatureinfo{$key} eq $variantMacrolist{$key}) |
|
171 { |
|
172 $findReusedKey = 1; |
|
173 }else |
|
174 { |
|
175 $findReusedKey = 0; |
|
176 last; |
|
177 } |
|
178 } |
|
179 if( $findReusedKey == 1) |
|
180 { |
|
181 $macroList = $_; |
|
182 last; |
|
183 } |
|
184 undef(%vmapfeatureinfor); |
|
185 undef($keyhash); |
|
186 } |
|
187 } |
|
188 } |
|
189 if($findReusedKey == 1) |
|
190 { |
|
191 return ($keyhash, $macroList); |
|
192 } |
|
193 else |
|
194 { |
|
195 return; |
|
196 } |
|
197 } |
|
198 # modified end: makefile improvement |
|
199 |
|
200 # Usage: featurevariantmap->Hash(\@sources, \%var) |
|
201 # |
|
202 # Generate a hash value from the source files for a target using the |
|
203 # given feature variant data. |
|
204 # |
|
205 # \@sources - list of source files (full path) |
|
206 # \%var - variant data (from featurevariantparser->GetVariant) |
|
207 # |
|
208 # returns the hash value, or "" if an error occurs. |
|
209 |
|
210 sub Hash |
|
211 { |
|
212 my $thisObj = shift; |
|
213 my @result = $thisObj->HashAndFeatures(@_); |
|
214 return $result[0]; |
|
215 } |
|
216 |
|
217 # Usage: featurevariantmap->HashAndFeatures(\@sources, \%var) |
|
218 # |
|
219 # Generate a hash value from the source files for a target using the |
|
220 # given feature variant data. |
|
221 # |
|
222 # \@sources - list of source files (full path) |
|
223 # \%var - variant data (from featurevariantparser->GetVariant) |
|
224 # |
|
225 # returns a list of two entries [0] the hash value, or "" if an error occurs [1] A string of macros tested or affecting the code |
|
226 |
|
227 sub HashAndFeatures |
|
228 { |
|
229 my $thisObj = shift; |
|
230 my $srcRef = shift; |
|
231 my $varRef = shift; |
|
232 |
|
233 return "" if (!$srcRef || !$varRef); |
|
234 return "" if (!$$varRef{'VALID'}); |
|
235 |
|
236 # get the pre-processing options |
|
237 my $pre = $$varRef{'PREINCLUDE'}; |
|
238 my $inc = $$varRef{'BUILD_INCLUDES'}; |
|
239 my $mac = $$varRef{'MACROS'}; |
|
240 |
|
241 # Pass -dU option to get list of macros affecting the code |
|
242 my $options = "-dU -undef -nostdinc -+"; |
|
243 |
|
244 if ($pre) # pre-include file |
|
245 { |
|
246 $options .= " -include \"$pre\""; |
|
247 } |
|
248 |
|
249 if ($inc) # include directories |
|
250 { |
|
251 foreach (@$inc) |
|
252 { |
|
253 $options .= " -I \"$_\""; |
|
254 } |
|
255 } |
|
256 |
|
257 if ($mac) # macro definitions |
|
258 { |
|
259 foreach (@$mac) |
|
260 { |
|
261 $options .= " -D$_"; |
|
262 } |
|
263 } |
|
264 |
|
265 my %testedMacrosHash; |
|
266 |
|
267 # Macros that affect the mmp file also affect the variant - so add them to the list |
|
268 foreach my $key ( keys %{ $$varRef{MMPTESTED} } ) |
|
269 { |
|
270 $testedMacrosHash{$key} = $$varRef{MMPTESTED}->{$key} if (ValidFeature($key)); |
|
271 } |
|
272 |
|
273 foreach my $src (@$srcRef) |
|
274 { |
|
275 my $options = "-I " . File::Basename::dirname($src) . " $options"; |
|
276 |
|
277 print "cpp $options $src\n" if ($verbose); |
|
278 |
|
279 if (open(CPP, "cpp $options $src 2>&1 |")) |
|
280 { |
|
281 while (<CPP>) |
|
282 { |
|
283 print $_ if ($verbose && /No such file/); |
|
284 |
|
285 # Scan for #define or #undef generated for -dU |
|
286 my ( $key, $value ); |
|
287 if (/^#define (\w+(?:\([^\)]*\))?)(?:\s(\S.*?))?\s*$/) |
|
288 { |
|
289 # modified start: makefile improvement |
|
290 my $tmpKey = $1; |
|
291 my $tmpValue = $2; |
|
292 $tmpValue =~ s/,/\\,/g; |
|
293 ( $key, $value ) = ( $tmpKey, $tmpValue ? "\'$tmpValue\'" : 'defined' ); |
|
294 # modified end: makefile improvement |
|
295 } |
|
296 elsif (/^#undef (.+)$/) |
|
297 { |
|
298 ( $key, $value ) = ( $1, 'undefined' ); |
|
299 } |
|
300 |
|
301 if ($key && ValidFeature($key)) |
|
302 { |
|
303 # Warn the user if a macro appears to have changed value - shouldn't really happen |
|
304 # Feature macros should only be set in platform HRH files and not in the code |
|
305 if (exists $testedMacrosHash{$key} && $testedMacrosHash{$key} ne $value) |
|
306 { |
|
307 print "WARNING: Feature macro $key redefined from $testedMacrosHash{$key} to $value\n"; |
|
308 } |
|
309 |
|
310 # Store the macro details |
|
311 $testedMacrosHash{$key} = $value; |
|
312 } |
|
313 } |
|
314 if (!close(CPP)) |
|
315 { |
|
316 # this probably means that a rsg file was included |
|
317 # that hasn't been generated yet. |
|
318 print "Incomplete pre-process of $src\n" if ($verbose); |
|
319 } |
|
320 } |
|
321 else |
|
322 { |
|
323 print "ERROR: Could not pre-process $src\n"; |
|
324 return ""; |
|
325 } |
|
326 } |
|
327 |
|
328 # Now generate the tested macros string |
|
329 my $testedMacros = ''; |
|
330 foreach my $key ( sort keys %testedMacrosHash ) |
|
331 { |
|
332 $testedMacros .= ',' if $testedMacros; |
|
333 $testedMacros .= "$key=$testedMacrosHash{$key}"; |
|
334 } |
|
335 |
|
336 print "Tested feature list: $testedMacros\n" if $verbose; |
|
337 return ( Digest::MD5::md5_hex($testedMacros), $testedMacros ); |
|
338 } |
|
339 |
|
340 # Usage: featurevariantmap->Save("my.dll", "1234", "myvar", \@hints) |
|
341 # |
|
342 # Write a hash value for a target into the target.vmap file along |
|
343 # with some optional hints data. |
|
344 # |
|
345 # "my.dll" - the target (full path) |
|
346 # "1234" - the hash value (32 character hex number) |
|
347 # "myvar" - the feature variant name |
|
348 # \@hints - optional list of extra strings (eg. "FEATUREVARIANT") |
|
349 # |
|
350 # returns 0 if OK and non-zero if an error occurs. |
|
351 |
|
352 sub Save |
|
353 { |
|
354 my $thisObj = shift; |
|
355 my $binName = shift; |
|
356 my $keyValue = shift; |
|
357 my $varName = shift; |
|
358 my $features = shift; |
|
359 my $hintRef = shift; |
|
360 |
|
361 # read the current data first if the .vmap file already exists |
|
362 # modified by SV start: makefile improvement |
|
363 my $vmapFile = "$binName.$varName.vmap"; |
|
364 my @lines; |
|
365 my $tmpinfo = "$keyValue $varName"; |
|
366 $tmpinfo .= " $features" if $features; |
|
367 if (open(VMAP, $vmapFile)) |
|
368 { |
|
369 my @tmp=<VMAP>; |
|
370 if (grep (/$tmpinfo/, @tmp)){ |
|
371 close(VMAP); |
|
372 return 0; |
|
373 } |
|
374 else { |
|
375 foreach (@tmp) |
|
376 { |
|
377 if (/^\w{32}\s+(\w+)/) |
|
378 { |
|
379 push(@lines, $_) unless (uc($1) eq uc($varName)); |
|
380 } |
|
381 } |
|
382 close(VMAP); |
|
383 } |
|
384 } |
|
385 # modified by SV end: makefile improvement |
|
386 |
|
387 # write the new data to the .vmap file |
|
388 if (!open(VMAP, ">$vmapFile")) |
|
389 { |
|
390 print "ERROR: Could not write VMAP to $vmapFile\n"; |
|
391 return 1; |
|
392 } |
|
393 |
|
394 # put the hints at the beginning |
|
395 if ($hintRef) |
|
396 { |
|
397 foreach (@$hintRef) |
|
398 { |
|
399 print VMAP "$_\n"; |
|
400 } |
|
401 } |
|
402 |
|
403 # then the "key var" pairs |
|
404 foreach (@lines) |
|
405 { |
|
406 print VMAP $_; |
|
407 } |
|
408 print VMAP "$keyValue $varName"; |
|
409 print VMAP " $features" if $features; |
|
410 print VMAP "\n"; |
|
411 |
|
412 close(VMAP); |
|
413 return 0; |
|
414 } |
|
415 |
|
416 # Usage: featurevariantmap->Find("my.dll", "myvar") |
|
417 # |
|
418 # Look for a binary using its "final" name. We will use the feature |
|
419 # variant map and the feature variant name to deduce the "variant" |
|
420 # binary name and test for its existence. |
|
421 # |
|
422 # "my.dll" - the final target (full path) |
|
423 # "myvar" - the feature variant name |
|
424 # |
|
425 # returns the file name if found, or "" otherwise. |
|
426 |
|
427 sub Find |
|
428 { |
|
429 my $thisObj = shift; |
|
430 my $binName = shift; |
|
431 my $varName = shift; |
|
432 |
|
433 # look for the vmap file |
|
434 # modified by SV start: makefile improvement |
|
435 my $vmapFile = "$binName.$varName.vmap"; |
|
436 # modified by SV end: makefile improvement |
|
437 |
|
438 if (-e $vmapFile) |
|
439 { |
|
440 my $key = $thisObj->GetKeyFromVMAP($varName, $vmapFile); |
|
441 |
|
442 if ($key) |
|
443 { |
|
444 $binName =~ /^(.*)\.([^\.]*)$/; |
|
445 $binName = "$1.$key.$2"; |
|
446 } |
|
447 else |
|
448 { |
|
449 print "ERROR: No \'$varName\' variant for $binName in $vmapFile\n"; |
|
450 return ""; # file not found |
|
451 } |
|
452 } |
|
453 |
|
454 # check that the actual binary exists |
|
455 if (-e $binName) |
|
456 { |
|
457 return $binName; |
|
458 } |
|
459 return ""; # file not found |
|
460 } |
|
461 |
|
462 # internal functions |
|
463 |
|
464 sub GetKeyFromVMAP |
|
465 { |
|
466 my $thisObj = shift; |
|
467 my @res = $thisObj->GetDataFromVMAP(@_); |
|
468 return $res[0]; |
|
469 } |
|
470 |
|
471 # Usage: featurevariantmap->GetDataFromVMAP("myvar", "mydll.vmap") |
|
472 # |
|
473 # Opens the vmap file indicated and returns the data for the requested variant |
|
474 # |
|
475 # "myvar" - the feature variant name |
|
476 # "my.vmap" - the final target vmap file (full path) |
|
477 # |
|
478 # Returns a list ( hash, features ) for the variant in the vmap or undef if not found |
|
479 |
|
480 sub GetDataFromVMAP |
|
481 { |
|
482 my $thisObj = shift; |
|
483 my $varName = shift; |
|
484 my $fileName = shift; |
|
485 |
|
486 if (!open(VMAP, $fileName)) |
|
487 { |
|
488 print "ERROR: Could not read VMAP from $fileName\n"; |
|
489 return ""; |
|
490 } |
|
491 while (<VMAP>) |
|
492 { |
|
493 chomp; |
|
494 if (/(\w{32})\s+$varName\s+(.*)$/i or /(\w{32})\s+$varName$/i) |
|
495 { |
|
496 my ( $hash, $features ) = ( $1, $2 ? $2 : '' ); |
|
497 close(VMAP); |
|
498 return ( $hash, $features ); |
|
499 } |
|
500 } |
|
501 close(VMAP); |
|
502 return; |
|
503 } |
|
504 |
|
505 1; |