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