ViewVC Help
View File | Revision Log | Show Annotations | Root Listing
root/cvsroot/COMP/SCRAM/src/BuildSystem/ToolParser.pm
Revision: 1.8
Committed: Fri Dec 14 09:03:47 2007 UTC (17 years, 4 months ago) by muzaffar
Content type: text/plain
Branch: MAIN
CVS Tags: V1_1_7, V1_1_6, V1_1_5, V1_1_4, V1_1_3, V1_1_2, V1_1_0_reltag8, V1_1_0_reltag7, V1_1_0_reltag6, V1_1_1, V1_1_0_reltag5, V1_1_0_reltag4, V1_1_0_reltag3, V1_1_0_reltag2, V1_1_0_reltag1, V1_1_0_reltag, V1_1_0_cand3, V1_1_0_cand2, V1_1_0_cand1
Branch point for: forBinLess_SCRAM
Changes since 1.7: +15 -24 lines
Log Message:
replace head with xml branch

File Contents

# Content
1 #____________________________________________________________________
2 # File: ToolParser.pm
3 #____________________________________________________________________
4 #
5 # Author: Shaun Ashby <Shaun.Ashby@cern.ch>
6 # Update: 2004-02-09 20:14:55+0100
7 # Revision: $Id: ToolParser.pm,v 1.5.4.6 2007/12/13 14:35:44 muzaffar Exp $
8 #
9 # Copyright: 2004 (C) Shaun Ashby
10 #
11 #--------------------------------------------------------------------
12 package BuildSystem::ToolParser;
13 require 5.004;
14
15 use Exporter;
16 use SCRAM::MsgLog;
17 use ActiveDoc::SimpleDoc;
18 use Utilities::Verbose;
19
20 @ISA=qw(Exporter Utilities::Verbose);
21 @EXPORT=qw();
22
23 #
24 sub new
25 ###############################################################
26 # new #
27 ###############################################################
28 # modified : Thu Nov 13 10:42:08 2003 / SFA #
29 # params : #
30 # : #
31 # function : #
32 # : #
33 ###############################################################
34 {
35 my $proto=shift;
36 my $class=ref($proto) || $proto;
37 $self={};
38
39 bless $self,$class;
40
41 $self->{cache}=shift;
42 $self->{mydoctype}="BuildSystem::ToolParser";
43 $self->{mydocversion}="1.1";
44 $self->{interactive} = 0;
45 $self->{content} = {};
46 $self->{nested} = 0;
47 $self->{scramdoc}=ActiveDoc::SimpleDoc->new();
48 $self->{scramdoc}->newparse("setup", $self->{mydoctype},'Subs');
49
50 return $self;
51 }
52
53 ### Tag handler methods ###
54 sub tool()
55 {
56 my ($object,$name,%attributes)=@_;
57 my $hashref = \%attributes;
58 # A way to distinguish the naming of different nested levels:
59 $self->{levels}=['','tag','nexttag'];
60 $$hashref{'name'} =~ tr[A-Z][a-z];
61
62 # Make sure we only pick up the tool requested:
63 if ( ($self->{tool} eq $$hashref{'name'}) &&
64 ($self->{version} eq $$hashref{'version'} ))
65 {
66 # These variables will be used when expanding settings
67 # in tool variable defs:
68 $ENV{SCRAMToolname} = $$hashref{'name'};
69 $ENV{SCRAMToolversion} = $$hashref{'version'};
70 $self->{content}->{TOOLNAME}=$$hashref{'name'};
71 $self->{content}->{TOOLVERSION}=$$hashref{'version'};
72 }
73 else
74 {
75 print "\n";
76 $::scram->scramerror("Configuration problem! Wanted/actual ".$self->{tool}." tool versions differ (wanted = ".$self->{version}.", downloaded = ".$$hashref{'version'}.")\n");
77 }
78
79 # Test to see if this doc defines a
80 # scram-managed project or a compiler:
81 if (exists ($$hashref{'type'}))
82 {
83 $$hashref{'type'} =~ tr[A-Z][a-z];
84 $self->{content}->{SCRAM_PROJECT} = 0;
85
86 if ($$hashref{'type'} eq 'scram')
87 {
88 $self->{content}->{SCRAM_PROJECT} = 1;
89 }
90 elsif ($$hashref{'type'} eq 'compiler')
91 {
92 # Is tool a compiler? Store this for retrieval from tool manager obj:
93 $self->{content}->{SCRAM_COMPILER} = 1;
94 }
95 else
96 {
97 $::scram->scramwarn("Unknown type \"".$$hashref{'type'}."\" in tool ".$$hashref{'name'}."\n");
98 }
99 }
100 }
101
102 sub tool_()
103 {
104 delete $self->{levels};
105 delete $self->{id};
106 delete $self->{nested};
107 }
108
109 sub lib()
110 {
111 my ($object,$name,%attributes)=@_;
112 push(@{$self->{"$self->{levels}->[$self->{nested}]".content}->{LIB}},$attributes{'name'});
113 }
114
115 sub info()
116 {
117 my ($object,$name,%attributes)=@_;
118 $self->{"$self->{levels}->[$self->{nested}]".content}->{INFO} = \%attributes;
119 }
120
121 sub use()
122 {
123 my ($object,$name,%attributes)=@_;
124 push(@{$self->{"$self->{levels}->[$self->{nested}]".content}->{USE}},$attributes{'name'});
125 }
126
127 sub runtime()
128 {
129 my ($object,$name,%attributes)=@_;
130 my $hashref = \%attributes;
131 my $envname;
132 # Break the value/default value into its constituent parts:
133 foreach my $t (qw(value default))
134 {
135 if (exists ($$hashref{$t}))
136 {
137 $hashref->{ELEMENTS} = [];
138 map
139 {
140 # In some cases, we might set a runtime path (e.g. LD_LIBRARY_PATH) to
141 # a proper path value i.e. X:Y. In this case, don't bother adding the string
142 # as a "variable" to ELEMENTS:
143 if ($_ =~ m|\$(.*)?| && $_ !~ /:/)
144 {
145 push(@{$hashref->{ELEMENTS}},$1);
146 }
147 } split("/",$hashref->{$t});
148 }
149 }
150
151 # Check to see if we have a "type" arg. If so, we use this to create the key:
152 if (exists ($hashref->{'type'}))
153 {
154 my $type=$hashref->{'type'};
155 # Make the type uppercase:
156 $type =~ tr/[a-z]/[A-Z]/;
157 # Rename the environment as "<type>:<env name>":
158 $envname = $type.":".$$hashref{'name'};
159 }
160 else
161 {
162 $envname = $$hashref{'name'};
163 }
164
165 # Delete name entry so hash is more tidy
166 delete $$hashref{'name'};
167
168 # Before we save $hashref we need to know if there are already
169 # any runtime tags with the same name. If there are, we must save all
170 # data to an aray of hashes:
171 if (exists ($self->{"$self->{levels}->[$self->{nested}]".content}->{RUNTIME}->{$envname}))
172 {
173 push(@{$self->{"$self->{levels}->[$self->{nested}]".content}->{RUNTIME}->{$envname}},$hashref);
174 }
175 else
176 {
177 # No entry yet so just store the hashref:
178 $self->{"$self->{levels}->[$self->{nested}]".content}->{RUNTIME}->{$envname} = [ $hashref ];
179 }
180 }
181
182 sub flags()
183 {
184 my ($object,$name,%attributes)=@_;
185 # Extract the flag name and its value:
186 my ($flagname,$flagvaluestring) = each %attributes;
187 $flagname =~ tr/[a-z]/[A-Z]/; # Keep flag name uppercase
188 chomp($flagvaluestring);
189 # Split the value on whitespace so we can push all
190 # individual flags into an array:
191 my @flagvalues = split(' ',$flagvaluestring);
192
193 # Is current tag within another tag block?
194 if ($self->{nested} > 0)
195 {
196 # Check to see if the current flag name is already stored in the hash. If so,
197 # just add the new values to the array of flag values:
198 if (exists ($self->{"$self->{levels}->[$self->{nested}]".content}->{FLAGS}->{$flagname}))
199 {
200 push(@{$self->{"$self->{levels}->[$self->{nested}]".content}->{FLAGS}->{$flagname}},@flagvalues);
201 }
202 else
203 {
204 $self->{"$self->{levels}->[$self->{nested}]".content}->{FLAGS}->{$flagname} = [ @flagvalues ];
205 }
206 }
207 else
208 {
209 if (exists ($self->{content}->{FLAGS}->{$flagname}))
210 {
211 push(@{$self->{content}->{FLAGS}->{$flagname}},@flagvalues);
212 }
213 else
214 {
215 $self->{content}->{FLAGS}->{$flagname} = [ @flagvalues ];
216 }
217 }
218 }
219
220 sub client()
221 {
222 $self->pushlevel();
223 }
224
225 sub client_()
226 {
227 if ($self->{isarch} == 1)
228 {
229 # If we already have an architecture tag, we must write to tagcontent hash:
230 $self->{tagcontent}->{CLIENT}=$self->{nexttagcontent};
231 delete $self->{nexttagcontent};
232 }
233 else
234 {
235 $self->{content}->{CLIENT}=$self->{tagcontent};
236 }
237
238 $self->poplevel();
239 }
240
241 sub environment()
242 {
243 my ($object,$name,%attributes)=@_;
244 my $hashref = \%attributes;
245 # Save a copy of the name of this environment:
246 my $envname=$$hashref{'name'};
247 delete $$hashref{'name'}; # Delete name entry so hash is more tidy
248 # Break the value/default value into its constituent parts:
249 foreach my $t (qw(value default))
250 {
251 if (exists ($$hashref{$t}))
252 {
253 $hashref->{ELEMENTS} = [];
254 map
255 {
256 if ($_ =~ m|\$(.*)?|)
257 {
258 push(@{$hashref->{ELEMENTS}},$1);
259 }
260 } split("/",$hashref->{$t});
261 }
262 }
263
264 # Before we save $hashref we need to know if there are already
265 # any env tags with the same name. If there are, we must save all
266 # data to an aray of hashes:
267 if (exists ($self->{"$self->{levels}->[$self->{nested}]".content}->{ENVIRONMENT}->{$envname}))
268 {
269 push(@{$self->{"$self->{levels}->[$self->{nested}]".content}->{ENVIRONMENT}->{$envname}},$hashref);
270 }
271 else
272 {
273 # No entry yet so just store the hashref:
274 $self->{"$self->{levels}->[$self->{nested}]".content}->{ENVIRONMENT}->{$envname} = [ $hashref ];
275 }
276 }
277
278 sub makefile()
279 {
280 my ($object,$name,%attributes)=@_;
281 # Set our own Char handler so we can collect the content
282 # of the Makefile tag:
283 $object->setHandlers(Char => \&makefile_content);
284 $self->{makefilecontent} = [];
285 }
286
287 sub makefile_content()
288 {
289 my ($object, @strings) = @_;
290 push(@{$self->{makefilecontent}},@strings);
291 }
292
293 sub makefile_()
294 {
295 my ($object,$name)=@_;
296 push(@{$self->{"$self->{levels}->[$self->{nested}]".content}->{MAKEFILE}},
297 join('',@{$self->{makefilecontent}}));
298 delete $self->{makefilecontent};
299 # Unset the Char handler to revert to the default behaviour:
300 $object->setHandlers(Char => 0);
301 }
302
303 sub architecture()
304 {
305 my ($object,$name,%attributes)=@_;
306 $self->pushlevel(\%attributes,1); # Set nested to 1;
307 }
308
309 sub architecture_()
310 {
311 # Need to be able to cope with multiple arch blocks with same arch string:
312 if (exists ($self->{content}->{ARCH}->{$self->{id}->{'name'}}))
313 {
314 # Already have an architecture tag for this arch:
315 while (my ($k,$v) = each %{$self->{tagcontent}})
316 {
317 # If this tag (e.g. LIB, USE, MAKEFILE) already exists and (as we know
318 # it should be) its data is an ARRAY, push it to the store:
319 if (exists ($self->{content}->{ARCH}->{$self->{id}->{'name'}}->{$k}) &&
320 ref($v) eq 'ARRAY')
321 {
322 push(@{$self->{content}->{ARCH}->{$self->{id}->{'name'}}->{$k}},@$v);
323 }
324 else
325 {
326 # Otherwise (for HASH data) we just store it. Note that, because we do
327 # not loop over the HASH content and check for already existsing keys,
328 # if two arch blocks with same arch name define the same tag (e.g, ENV),
329 # the last occurrence will be kept (i.e. the two values won't be added
330 # to one ENV hash: //FIXME for later....)
331 $self->{content}->{ARCH}->{$self->{id}->{'name'}}->{$k} = $v;
332 }
333 }
334 }
335 else
336 {
337 $self->{content}->{ARCH}->{$self->{id}->{'name'}}=$self->{tagcontent};
338 }
339
340 delete $self->{isarch};
341 $self->poplevel();
342 }
343
344 sub parse
345 {
346 my $self=shift;
347 my ($tool,$toolver,$file)=@_;
348 $self->{tool}=$tool;
349 $self->{version}=$toolver;
350 $self->{scramdoc}->filetoparse($file);
351 $self->verbose("Setup Parse");
352 my $fhead='<?xml version="1.0" encoding="UTF-8" standalone="yes"?><doc type="BuildSystem/ToolParser" version="1.0">';
353 my $ftail='</doc>';
354 $self->{scramdoc}->parse("setup",$fhead,$ftail);
355 delete $self->{scramdoc};
356 return $self;
357 }
358
359 sub pushlevel
360 {
361 my $self = shift;
362 my ($info, $nextlevel)=@_;
363
364 $self->{id} = $info if (defined $info);
365
366 # Check to see if last tag was arch: if so, ceate new level:
367 if ($self->{isarch} == 1)
368 {
369 $self->{nested} = 2;
370 $self->{nexttagcontent}={};
371 }
372 else
373 {
374 $self->{nested} = 1;
375 $self->{tagcontent}={};
376 }
377
378 # Set something which says "last starter tag was ARCH":
379 if ($nextlevel)
380 {
381 $self->{isarch} = 1;
382 }
383 }
384
385 sub poplevel
386 {
387 my $self = shift;
388
389 # Drop level of nesting by one:
390 $self->{nested}--;
391
392 if ($self->{isarch} != 1)
393 {
394 delete $self->{tagcontent};
395 }
396 }
397
398 sub rmenvdata
399 {
400 my $self=shift;
401 delete $self->{ENVDATA};
402 }
403
404 ###################################
405 ## Data Access Methods ##
406 ###################################
407 sub toolname
408 {
409 my $self=shift;
410 # Return tool name:
411 return ($self->{content}->{TOOLNAME});
412 }
413
414 sub toolversion
415 {
416 my $self=shift;
417 # Return tool version:
418 return ($self->{content}->{TOOLVERSION});
419 }
420
421 sub toolcontent
422 {
423 my $self=shift;
424 # Return whole of content hash:
425 return $self->{content};
426 }
427
428 sub getrawdata()
429 {
430 my $self=shift;
431 my ($tagtype)=@_;
432
433 # Check to see if we have data for this tag:
434 if (! exists ($self->{content}->{$tagtype}))
435 {
436 # If not, return:
437 return 0;
438 }
439
440 # Check the number of keys for hash referred to by this object.
441 # If 0, return:
442 if (ref($self->{content}->{$tagtype}) eq 'HASH') #
443 {
444 if ((my $nkeys=keys %{$self->{content}->{$tagtype}}) > 0)
445 {
446 # Return the data for the tag $tagtype. ARCH is a bit special because
447 # we want the data for the actual arch (thus, data is on a different level):
448 if ($tagtype eq 'ARCH')
449 {
450 my $archmatch = {};
451 # Check for matching arch key and return hash of relevant data.
452 # Also must take into account the fact that several arch names may match, e.g. Linux, Linux__2 and
453 # Linux__2.4 all match. If we find more than one match, collect ALL matching data and return it:
454 while (my ($k,$v) = each %{$self->{content}->{ARCH}})
455 {
456 # For every matching architecture we snatch the data and squirrel it away:
457 if ( $ENV{SCRAM_ARCH} =~ /$k.*/ )
458 {
459 # Now we check the tags inside the arch block. Note that we do not want to descend
460 # into CLIENT tags, if these exist. We just want to return all data in the ARCH
461 # block while making sure that multiple matches are handled correctly. We assume that
462 # you will only find one CLIENT block inside and ARCH:
463 while (my ($matchtag, $matchval) = each %{$v})
464 {
465 if ($matchtag =~ /CLIENT|FLAGS|RUNTIME/)
466 {
467 $archmatch->{$matchtag} = $matchval;
468 }
469 else
470 {
471 # Treat tags differently according to whether they are HASHes or ARRAYs:
472 if (ref($matchval) =~ /HASH/)
473 {
474 while (my ($t, $val) = each %{$matchval})
475 {
476 if (exists ($archmatch->{$matchtag}->{$t}))
477 {
478 push(@{$archmatch->{$matchtag}->{$t}},@$val);
479 }
480 else
481 {
482 $archmatch->{$matchtag}->{$t} = $val;
483 }
484 }
485 }
486 else # Here we deal with arrays:
487 {
488 if (exists ($archmatch->{$matchtag}))
489 {
490 push(@{$archmatch->{$matchtag}},@$matchval);
491 }
492 else
493 {
494 $archmatch->{$matchtag} = $matchval;
495 }
496 }
497 }
498 }
499 }
500 }
501 # Return the squirrel:
502 return $archmatch;
503
504 } # End of ARCH tag treatment
505 else
506 {
507 # Return other tag data:
508 return $self->{content}->{$tagtype};
509 }
510 }
511 else
512 {
513 print "Warning: $tagtype tags contain no other tag data!","\n";
514 return undef;
515 }
516 }
517 else
518 {
519 # We have an array of data or a scalar:
520 return $self->{content}->{$tagtype};
521 }
522 }
523
524 sub processrawtool()
525 {
526 my $self=shift;
527 my ($interactive) = @_;
528 my $data = [];
529 my $environments = {}; # Somewhere to collect our environments
530
531 # Set interactive mode if required:
532 $self->{interactive} = $interactive;
533
534 # Somewhere to store the data:
535 use BuildSystem::ToolData;
536 my $tooldataobj = BuildSystem::ToolData->new();
537
538 # Set the name and version:
539 $tooldataobj->toolname($self->toolname());
540 $tooldataobj->toolversion($self->toolversion());
541
542 # First, collect all tag data so that we only have non-nested tags.
543 # Check for architecture-dependent data first, followed by client tags:
544 foreach $nested_tag (qw( ARCH CLIENT ))
545 {
546 if (my $thisdata=$self->getrawdata($nested_tag))
547 {
548 foreach my $item (keys %{ $thisdata })
549 {
550 if ($item eq 'CLIENT')
551 {
552 my $clientdata = $thisdata->{$item};
553 foreach my $ckey (keys %{$clientdata})
554 {
555 $environments->{$ckey} = $clientdata->{$ckey};
556 }
557 }
558 elsif ($item eq 'ENVIRONMENT' || $item eq 'RUNTIME')
559 {
560 # Check to see if tag already exists before saving:
561 if (exists($environments->{$item}))
562 {
563 foreach my $ek (keys %{$thisdata})
564 {
565 if (exists($environments->{$item}->{$ek}))
566 {
567 push(@{$environments->{$item}->{$ek}}, @{$thisdata->{$item}->{$ek}});
568 }
569 else
570 {
571 $environments->{$item}->{$ek} = $thisdata->{$item}->{$ek};
572 }
573 }
574 }
575 else
576 {
577 # There isn't an entry yet:
578 $environments->{$item} = $thisdata->{$item};
579 }
580 }
581 else
582 {
583 my $data = $thisdata->{$item};
584
585 if (ref($data) eq 'HASH')
586 {
587 while (my ($f,$v) = each %$data)
588 {
589 $tooldataobj->flags($f,$v);
590 }
591 }
592 else
593 {
594 my $subname = lc($item);
595 $tooldataobj->$subname($data), if ($#$data != -1);
596 }
597 }
598 }
599 }
600 else
601 {
602 # No entry for this nested tag. Proceed.
603 next;
604 }
605 }
606 # Now handle all other normal tags:
607 foreach my $normal_tag (qw( ENVIRONMENT RUNTIME ))
608 {
609 # Do we have some data for this tag?
610 if (my $thisdata=$self->getrawdata($normal_tag))
611 {
612 # Add the data to our environments hash. We must check to see if
613 # there is an entry already:
614 if (exists($environments->{$normal_tag}))
615 {
616 foreach my $ek (keys %{$thisdata})
617 {
618 if (exists($environments->{$normal_tag}->{$ek}))
619 {
620 push(@{$environments->{$normal_tag}->{$ek}}, @{$thisdata->{$normal_tag}->{$ek}});
621 }
622 else
623 {
624 $environments->{$normal_tag}->{$ek} = $thisdata->{$normal_tag}->{$ek};
625 }
626 }
627 }
628 else
629 {
630 # There isn't an entry yet:
631 $environments->{$normal_tag} = $thisdata;
632 }
633 }
634 else
635 {
636 # No data so proceed:
637 next;
638 }
639 }
640
641 # Finally, tags that can be stored straight away:
642 foreach my $tag (qw( FLAGS MAKEFILE ))
643 {
644 my $bdata = $self->getrawdata($tag);
645 if (ref($bdata) eq 'HASH')
646 {
647 while (my ($f,$v) = each %$bdata)
648 {
649 $tooldataobj->flags($f,$v);
650 }
651 }
652 else
653 {
654 $tooldataobj->makefile($bdata), if ($#$bdata != -1);
655 }
656 }
657
658 # Libs and tool dependencise:
659 foreach my $tag (qw( LIB USE ))
660 {
661 my $bdata = $self->getrawdata($tag);
662 my $subname = lc($tag);
663 $tooldataobj->$subname($bdata), if ($#$bdata != -1);
664 }
665
666 # Also check to see if this tool is a scram-managed project. If
667 # so, set the SCRAM_PROJECT variable in the ToolData object:
668 if (exists ($self->{content}->{SCRAM_PROJECT}))
669 {
670 $tooldataobj->scram_project($self->{content}->{SCRAM_PROJECT});
671 }
672
673 # And check to see if this tool is a compiler. If so, set
674 # the SCRAM_COMPILER variable in the ToolData object:
675 if (exists ($self->{content}->{SCRAM_COMPILER}))
676 {
677 $tooldataobj->scram_compiler($self->{content}->{SCRAM_COMPILER});
678 }
679
680 # Establish the order of parsing the value strings:
681 my $order = $self->process_environments($environments);
682 if ($self->{interactive})
683 {
684 # Set the values interactively:
685 $self->interactively_find_settings($tooldataobj, $environments, $order);
686 }
687 else
688 {
689 # Set the values:
690 $self->find_settings($tooldataobj, $environments, $order);
691 }
692
693 # Return a ToolData object:
694 return $tooldataobj;
695 }
696
697 sub process_environments()
698 {
699 my $self=shift;
700 my ($environments)=@_;
701
702 use BuildSystem::SCRAMGrapher;
703 my $G = BuildSystem::SCRAMGrapher->new();
704
705 foreach $envtype (keys %{$environments})
706 {
707 while (my ($envcontent,$envdata) = each %{$environments->{$envtype}})
708 {
709 # Add a vertex for the VARIABLE name:
710 $G->vertex($envcontent);
711
712 foreach my $element (@$envdata)
713 {
714 if (exists($element->{'ELEMENTS'}))
715 {
716 map
717 {
718 # Add a path for each element in ELEMENTS:
719 $G->edge($envcontent, $_);
720 } @{$element->{'ELEMENTS'}};
721 }
722 }
723 }
724 }
725
726 my $setup_order = $G->sort();
727 return $setup_order;
728 }
729
730 sub find_settings()
731 {
732 my $self=shift;
733 my ($tooldataobj, $environments, $ordering)=@_;
734 my $stringtoeval;
735 my $runtime=[];
736 my $path;
737
738 use BuildSystem::ToolSettingValidator;
739
740 my $tsv = BuildSystem::ToolSettingValidator->new($environments, $self->toolname());
741
742 foreach my $envname (@$ordering)
743 {
744 my $type = 'ENVIRONMENT';
745 my $envdata = $tsv->environment($type, $envname);
746
747 # Handle single-occurrence variables first (i.e. VAR appears once
748 # in array of hashes):
749 if ($envdata != 0 && $#$envdata == 0) # One element only!
750 {
751 scramlogmsg("\nFinding a value for $envname:","\n\n");
752 # We have an environment and only one data element:
753 # Check the lookup DB:
754 if ($tsv->checkDB($envname))
755 {
756 scramlogmsg("\tValidating value for $envname (found in tool DB):","\n");
757 if ($tsv->validatepath())
758 {
759 # Save in TSV and store in ToolData object:
760 $tsv->savevalue($envname,$tsv->pathfromdb());
761 $self->store($tooldataobj, $envname, $tsv->pathfromdb());
762 }
763 else
764 {
765 $path = $tsv->findvalue($envname, $envdata);
766 # Save the value in ToolData object:
767 $self->store($tooldataobj, $envname, $path);
768 }
769 }
770 else
771 {
772 $path = $tsv->findvalue($envname, $envdata);
773 # Save in ToolData object:
774 $self->store($tooldataobj, $envname, $path);
775 }
776 }
777 elsif ($envdata != 0 && $#$envdata > 0)
778 {
779 scramlogmsg("\nFinding a value for $envname:","\n\n");
780 foreach my $elementdata (@$envdata)
781 {
782 $path = $tsv->findvalue($envname, $elementdata);
783 # Save in ToolData object:
784 $self->store($tooldataobj, $envname, $path);
785 }
786 }
787 elsif (exists($ENV{$envname}))
788 {
789 # Nothing to do here:
790 push(@$runtime, $envname); # FIX From Shahzad.
791 next;
792 }
793 else
794 {
795 push(@$runtime, $envname);
796 }
797 }
798 # Check that the required libraries exist:
799 $self->_lib_validate($tooldataobj);
800 # Now process the runtime settings:
801 scramlogmsg("\n-------------------------------\n");
802 foreach my $rtname (@$runtime)
803 {
804 my $type = 'RUNTIME';
805 my $envdata = $tsv->environment($type, $rtname);
806 my ($rttype,$realrtname) = split(':',$rtname);
807
808 # Only validate paths:
809 if ($rtname =~ /:/)
810 {
811 # Handle single-occurrence variables first (i.e. VAR appears once
812 # in array of hashes):
813 if ($envdata != 0 && $#$envdata == 0) # One element only!
814 {
815 scramlogmsg("\nRuntime path settings for $realrtname:","\n\n");
816 # We have an environment and only one data element:
817 # Check the lookup DB:
818 if ($tsv->checkDB($rtname))
819 {
820 scramlogmsg("\tValidating value for path $realrtname (found in tool DB):","\n");
821 if ($tsv->validatepath())
822 {
823 # Save in TSV and store in ToolData object:
824 $tsv->savevalue($rtname, $tsv->pathfromdb());
825 $tooldataobj->runtime($rtname, [ $tsv->pathfromdb() ]);
826 }
827 else
828 {
829 $path = $tsv->findvalue($rtname, $envdata);
830 # Save the value in ToolData object:
831 $tooldataobj->runtime($rtname, [ $path ]);
832 }
833 }
834 else
835 {
836 $path = $tsv->findvalue($rtname, $envdata);
837 # Save in ToolData object:
838 $tooldataobj->runtime($rtname, [ $path ]);
839 }
840 }
841 elsif ($envdata != 0 && $#$envdata > 0)
842 {
843 scramlogmsg("\nRuntime path settings for $realrtname:","\n\n");
844 foreach my $elementdata (@$envdata)
845 {
846 $path = $tsv->findvalue($rtname, $elementdata);
847 # Save in ToolData object:
848 $tooldataobj->runtime($rtname, [ $path ]);
849 }
850 }
851 else
852 {
853 next;
854 }
855 }
856 else
857 {
858 # Handle runtime variables:
859 if ($envdata != 0 && $#$envdata == 0) # One element only!
860 {
861 my $value='';
862 $tsv->checkdefaults($envdata, \$value);
863 scramlogmsg("\n");
864
865 # Chck to see if the value contains a variable that should be evaluated:
866 if ($value =~ /$/)
867 {
868 # If so, find the value and substitute. This should work for all
869 # occurrences of variables because by this point (and because the ordering
870 # was established at the start) all other variables will have real values:
871 my $dvalue = $tsv->_expandvars($value);
872 $value = $dvalue;
873 }
874
875 scramlogmsg("Runtime variable ",$rtname," set to \"",$value,"\"\n");
876
877 # Store the variable setting:
878 $tooldataobj->runtime($rtname, [ $value ]);
879 }
880 else
881 {
882 next;
883 }
884 }
885 }
886
887 scramlogmsg("\n");
888 }
889
890 sub interactively_find_settings()
891 {
892 my $self=shift;
893 my ($tooldataobj, $environments, $ordering)=@_;
894 my $stringtoeval;
895 my $runtime=[];
896 my ($path, $dpath);
897
898 use BuildSystem::ToolSettingValidator;
899
900 my $tsv = BuildSystem::ToolSettingValidator->new($environments, $self->toolname(), $self->{interactive});
901
902 foreach my $envname (@$ordering)
903 {
904 my $type = 'ENVIRONMENT';
905 my $envdata = $tsv->environment($type, $envname);
906
907 # Handle single-occurrence variables first (i.e. VAR appears once
908 # in array of hashes):
909 if ($envdata != 0 && $#$envdata == 0) # One element only!
910 {
911 print "\nFinding a value for $envname:","\n";
912 print "\n";
913 # We have an environment and only one data element:
914 # Check the lookup DB:
915 if ($tsv->checkDB($envname))
916 {
917 print "\tValidating value for $envname (found in tool DB):","\n";
918 if ($tsv->validatepath())
919 {
920 # This is our default:
921 $dpath = $tsv->pathfromdb();
922 # Run promptuser() to see if this value can be kept
923 # or should be changed:
924 $path = $tsv->promptuser($envname, $dpath);
925 # Save in TSV and store in ToolData object:
926 $tsv->savevalue($envname,$path);
927 $self->store($tooldataobj, $envname, $path);
928 }
929 else
930 {
931 $path = $tsv->ifindvalue($envname, $envdata);
932 # Save the value in ToolData object:
933 $self->store($tooldataobj, $envname, $path);
934 }
935 }
936 else
937 {
938 $dpath = $tsv->ifindvalue($envname, $envdata);
939 # Save in ToolData object:
940 $self->store($tooldataobj, $envname, $dpath);
941 }
942 }
943 elsif ($envdata != 0 && $#$envdata > 0)
944 {
945 print "\nFinding a value for $envname:","\n";
946 print "\n";
947 foreach my $elementdata (@$envdata)
948 {
949 $path = $tsv->ifindvalue($envname, $elementdata);
950 # Save in ToolData object:
951 $self->store($tooldataobj, $envname, $path);
952 }
953 }
954 elsif (exists($ENV{$envname}))
955 {
956 # Nothing to do here:
957 next;
958 }
959 else
960 {
961 push(@$runtime, $envname);
962 }
963 }
964
965 # Check that the required libraries exist:
966 $self->_lib_validate($tooldataobj);
967
968 # Now process the runtime settings:
969 print "\n";
970 print "-------------------------------\n";
971 foreach my $rtname (@$runtime)
972 {
973 my $type = 'RUNTIME';
974 my $envdata = $tsv->environment($type, $rtname);
975 my ($rttype,$realrtname) = split(':',$rtname);
976
977 # Only validate paths:
978 if ($rtname =~ /:/)
979 {
980 # Handle single-occurrence variables first (i.e. VAR appears once
981 # in array of hashes):
982 if ($envdata != 0 && $#$envdata == 0) # One element only!
983 {
984 print "\nRuntime path settings for $realrtname:","\n";
985 print "\n";
986 # We have an environment and only one data element:
987 # Check the lookup DB:
988 if ($tsv->checkDB($rtname))
989 {
990 print "\tValidating value for path $realrtname (found in tool DB):","\n";
991 if ($tsv->validatepath())
992 {
993 $dpath = $tsv->pathfromdb();
994 # Run promptuser() to see if this value can be kept
995 # or should be changed:
996 $path = $tsv->promptuser($rtname, $dpath);
997 # Save in TSV and store in ToolData object:
998 $tsv->savevalue($rtname, $path);
999 $tooldataobj->runtime($rtname, [ $path ]);
1000 }
1001 else
1002 {
1003 $dpath = $tsv->ifindvalue($rtname, $envdata);
1004 # Save the value in ToolData object:
1005 $tooldataobj->runtime($rtname, [ $path ]);
1006 }
1007 }
1008 else
1009 {
1010 $path = $tsv->ifindvalue($rtname, $envdata);
1011 # Save in ToolData object:
1012 $tooldataobj->runtime($rtname, [ $path ]);
1013 }
1014 }
1015 elsif ($envdata != 0 && $#$envdata > 0)
1016 {
1017 print "\nRuntime path settings for $realrtname:","\n";
1018 print "\n";
1019 foreach my $elementdata (@$envdata)
1020 {
1021 $path = $tsv->ifindvalue($rtname, $elementdata);
1022 # Save in ToolData object:
1023 $tooldataobj->runtime($rtname, [ $path ]);
1024 }
1025 }
1026 else
1027 {
1028 next;
1029 }
1030 }
1031 else
1032 {
1033 # Handle runtime variables:
1034 if ($envdata != 0 && $#$envdata == 0) # One element only!
1035 {
1036 my $dvalue='';
1037 $tsv->checkdefaults($envdata, \$dvalue);
1038 print "\n";
1039 my $value = $tsv->promptuserforvar($rtname, $dvalue);
1040 # Store the variable setting:
1041 $tooldataobj->runtime($rtname, [ $value ]);
1042 }
1043 else
1044 {
1045 next;
1046 }
1047 }
1048 }
1049
1050 print "\n";
1051 }
1052
1053 sub store()
1054 {
1055 my $self=shift;
1056 my ($tooldataobj, $envname, $path) = @_;
1057 my $subrtn = lc($envname);
1058
1059 if ($tooldataobj->can($subrtn))
1060 {
1061 $tooldataobj->$subrtn([ $path ]);
1062 }
1063 else
1064 {
1065 $tooldataobj->variable_data($envname, $path);
1066 }
1067 }
1068
1069 sub _lib_validate()
1070 {
1071 my $self=shift;
1072 my ($toolobj)=@_;
1073 my $errorstatus = { 0 => $main::good."[OK]".$main::normal, 1 => $main::error."[ERROR]".$main::normal };
1074 my $libsfound={};
1075
1076 # Firstly, we check to see if there are libraries provided by this tool:
1077 my @libraries = $toolobj->lib();
1078 my @libpaths = $toolobj->libdir();
1079
1080 foreach my $ldir (@libpaths)
1081 {
1082 my $full_libname_glob="lib".$lib."*.*";
1083 # Change to lib dir so we avoid the very long paths in our glob:
1084 chdir($ldir);
1085 # Next we use a glob to get libs matching this string (so we
1086 # can see if there's a shared or archive lib):
1087 my @possible_libs = glob($full_libname_glob);
1088 #
1089 map
1090 {
1091 $_ =~ s/\.so*|\.a*//g; # Remove all endings
1092 # Store in our hash of found libs:
1093 $libsfound->{$_} = 1;
1094 } @possible_libs;
1095 }
1096
1097 # Next we iterate over the list of libraries in our tool and
1098 # see if it was found in one of the libdirs:
1099 scramlogmsg("\n\n"), if ($#libraries != -1);
1100 foreach my $library (@libraries)
1101 {
1102 # Good status:
1103 my $errorid = 0;
1104 if (! exists ($libsfound->{'lib'.$library}))
1105 {
1106 # Check in system library dirs:
1107 if ($self->_check_system_libs($library))
1108 {
1109 $errorid = 0;
1110 }
1111 else
1112 {
1113 $errorid = 1;
1114 }
1115 }
1116 scramlogmsg(sprintf("* Library check %-10s for lib%-12s\n",$errorstatus->{$errorid}, $library));
1117 }
1118
1119 scramlogmsg("\n");
1120 }
1121
1122 sub _check_system_libs()
1123 {
1124 my $self=shift;
1125 my ($lib)=@_;
1126 my $libsfound = {};
1127 my $systemdirs = [ qw( /lib /usr/lib /usr/local/lib /usr/X11R6/lib ) ];
1128 my $full_libname_glob="lib".$lib."*.*";
1129 my $found = 0;
1130
1131 foreach my $dir (@$systemdirs)
1132 {
1133 # Change to lib dir so we avoid the very long paths in our glob:
1134 chdir($dir);
1135 # Next we use a glob to get libs matching this string (so we
1136 # can see if there's a shared or archive lib):
1137 my @possible_libs = glob($full_libname_glob);
1138 #
1139 map
1140 {
1141 $_ =~ s/\.so*|\.a*//g; # Remove all endings
1142 # Store in our hash of found libs:
1143 $libsfound->{$_} = 1;
1144 } @possible_libs;
1145 }
1146
1147 # See if we find the library in the system lib directories:
1148 if (! exists ($libsfound->{'lib'.$library}))
1149 {
1150 $found = 1;
1151 }
1152
1153 return $found;
1154 }
1155
1156 sub AUTOLOAD()
1157 {
1158 my ($xmlparser,$name,%attributes)=@_;
1159 return if $AUTOLOAD =~ /::DESTROY$/;
1160 my $name=$AUTOLOAD;
1161 $name =~ s/.*://;
1162 }
1163
1164 1;