ViewVC Help
View File | Revision Log | Show Annotations | Root Listing
root/cvsroot/COMP/SCRAM/src/BuildSystem/ToolParser.pm
Revision: 1.6
Committed: Tue Feb 27 11:59:45 2007 UTC (18 years, 2 months ago) by sashby
Content type: text/plain
Branch: MAIN
CVS Tags: V1_1_0, v110p1, V110p6, V110p5, V110p4, V110p3
Branch point for: v200branch
Changes since 1.5: +302 -65 lines
Log Message:
Merged from XML branch to HEAD. Start release prep.

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.4 2007/02/27 11:38:39 sashby 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 $self->{scramdoc}->parse("setup");
352 delete $self->{scramdoc};
353 return $self;
354 }
355
356 sub pushlevel
357 {
358 my $self = shift;
359 my ($info, $nextlevel)=@_;
360
361 $self->{id} = $info if (defined $info);
362
363 # Check to see if last tag was arch: if so, ceate new level:
364 if ($self->{isarch} == 1)
365 {
366 $self->{nested} = 2;
367 $self->{nexttagcontent}={};
368 }
369 else
370 {
371 $self->{nested} = 1;
372 $self->{tagcontent}={};
373 }
374
375 # Set something which says "last starter tag was ARCH":
376 if ($nextlevel)
377 {
378 $self->{isarch} = 1;
379 }
380 }
381
382 sub poplevel
383 {
384 my $self = shift;
385
386 # Drop level of nesting by one:
387 $self->{nested}--;
388
389 if ($self->{isarch} != 1)
390 {
391 delete $self->{tagcontent};
392 }
393 }
394
395 sub rmenvdata
396 {
397 my $self=shift;
398 delete $self->{ENVDATA};
399 }
400
401 ###################################
402 ## Data Access Methods ##
403 ###################################
404 sub toolname
405 {
406 my $self=shift;
407 # Return tool name:
408 return ($self->{content}->{TOOLNAME});
409 }
410
411 sub toolversion
412 {
413 my $self=shift;
414 # Return tool version:
415 return ($self->{content}->{TOOLVERSION});
416 }
417
418 sub toolcontent
419 {
420 my $self=shift;
421 # Return whole of content hash:
422 return $self->{content};
423 }
424
425 sub getrawdata()
426 {
427 my $self=shift;
428 my ($tagtype)=@_;
429
430 # Check to see if we have data for this tag:
431 if (! exists ($self->{content}->{$tagtype}))
432 {
433 # If not, return:
434 return 0;
435 }
436
437 # Check the number of keys for hash referred to by this object.
438 # If 0, return:
439 if (ref($self->{content}->{$tagtype}) eq 'HASH') #
440 {
441 if ((my $nkeys=keys %{$self->{content}->{$tagtype}}) > 0)
442 {
443 # Return the data for the tag $tagtype. ARCH is a bit special because
444 # we want the data for the actual arch (thus, data is on a different level):
445 if ($tagtype eq 'ARCH')
446 {
447 my $archmatch = {};
448 # Check for matching arch key and return hash of relevant data.
449 # Also must take into account the fact that several arch names may match, e.g. Linux, Linux__2 and
450 # Linux__2.4 all match. If we find more than one match, collect ALL matching data and return it:
451 while (my ($k,$v) = each %{$self->{content}->{ARCH}})
452 {
453 # For every matching architecture we snatch the data and squirrel it away:
454 if ( $ENV{SCRAM_ARCH} =~ /$k.*/ )
455 {
456 # Now we check the tags inside the arch block. Note that we do not want to descend
457 # into CLIENT tags, if these exist. We just want to return all data in the ARCH
458 # block while making sure that multiple matches are handled correctly. We assume that
459 # you will only find one CLIENT block inside and ARCH:
460 while (my ($matchtag, $matchval) = each %{$v})
461 {
462 if ($matchtag =~ /CLIENT|FLAGS|RUNTIME/)
463 {
464 $archmatch->{$matchtag} = $matchval;
465 }
466 else
467 {
468 # Treat tags differently according to whether they are HASHes or ARRAYs:
469 if (ref($matchval) =~ /HASH/)
470 {
471 while (my ($t, $val) = each %{$matchval})
472 {
473 if (exists ($archmatch->{$matchtag}->{$t}))
474 {
475 push(@{$archmatch->{$matchtag}->{$t}},@$val);
476 }
477 else
478 {
479 $archmatch->{$matchtag}->{$t} = $val;
480 }
481 }
482 }
483 else # Here we deal with arrays:
484 {
485 if (exists ($archmatch->{$matchtag}))
486 {
487 push(@{$archmatch->{$matchtag}},@$matchval);
488 }
489 else
490 {
491 $archmatch->{$matchtag} = $matchval;
492 }
493 }
494 }
495 }
496 }
497 }
498 # Return the squirrel:
499 return $archmatch;
500
501 } # End of ARCH tag treatment
502 else
503 {
504 # Return other tag data:
505 return $self->{content}->{$tagtype};
506 }
507 }
508 else
509 {
510 print "Warning: $tagtype tags contain no other tag data!","\n";
511 return undef;
512 }
513 }
514 else
515 {
516 # We have an array of data or a scalar:
517 return $self->{content}->{$tagtype};
518 }
519 }
520
521 sub processrawtool()
522 {
523 my $self=shift;
524 my ($interactive) = @_;
525 my $data = [];
526 my $environments = {}; # Somewhere to collect our environments
527
528 # Set interactive mode if required:
529 $self->{interactive} = $interactive;
530
531 # Somewhere to store the data:
532 use BuildSystem::ToolData;
533 my $tooldataobj = BuildSystem::ToolData->new();
534
535 # Set the name and version:
536 $tooldataobj->toolname($self->toolname());
537 $tooldataobj->toolversion($self->toolversion());
538
539 # First, collect all tag data so that we only have non-nested tags.
540 # Check for architecture-dependent data first, followed by client tags:
541 foreach $nested_tag (qw( ARCH CLIENT ))
542 {
543 if (my $thisdata=$self->getrawdata($nested_tag))
544 {
545 foreach my $item (keys %{ $thisdata })
546 {
547 if ($item eq 'CLIENT')
548 {
549 my $clientdata = $thisdata->{$item};
550 foreach my $ckey (keys %{$clientdata})
551 {
552 $environments->{$ckey} = $clientdata->{$ckey};
553 }
554 }
555 elsif ($item eq 'ENVIRONMENT' || $item eq 'RUNTIME')
556 {
557 # Check to see if tag already exists before saving:
558 if (exists($environments->{$item}))
559 {
560 foreach my $ek (keys %{$thisdata})
561 {
562 if (exists($environments->{$item}->{$ek}))
563 {
564 push(@{$environments->{$item}->{$ek}}, @{$thisdata->{$item}->{$ek}});
565 }
566 else
567 {
568 $environments->{$item}->{$ek} = $thisdata->{$item}->{$ek};
569 }
570 }
571 }
572 else
573 {
574 # There isn't an entry yet:
575 $environments->{$item} = $thisdata->{$item};
576 }
577 }
578 else
579 {
580 my $data = $thisdata->{$item};
581
582 if (ref($data) eq 'HASH')
583 {
584 while (my ($f,$v) = each %$data)
585 {
586 $tooldataobj->flags($f,$v);
587 }
588 }
589 else
590 {
591 my $subname = lc($item);
592 $tooldataobj->$subname($data), if ($#$data != -1);
593 }
594 }
595 }
596 }
597 else
598 {
599 # No entry for this nested tag. Proceed.
600 next;
601 }
602 }
603
604 # Now handle all other normal tags:
605 foreach my $normal_tag (qw( ENVIRONMENT RUNTIME ))
606 {
607 # Do we have some data for this tag?
608 if (my $thisdata=$self->getrawdata($normal_tag))
609 {
610 # Add the data to our environments hash. We must check to see if
611 # there is an entry already:
612 if (exists($environments->{$normal_tag}))
613 {
614 foreach my $ek (keys %{$thisdata})
615 {
616 if (exists($environments->{$normal_tag}->{$ek}))
617 {
618 push(@{$environments->{$normal_tag}->{$ek}}, @{$thisdata->{$normal_tag}->{$ek}});
619 }
620 else
621 {
622 $environments->{$normal_tag}->{$ek} = $thisdata->{$normal_tag}->{$ek};
623 }
624 }
625 }
626 else
627 {
628 # There isn't an entry yet:
629 $environments->{$normal_tag} = $thisdata;
630 }
631 }
632 else
633 {
634 # No data so proceed:
635 next;
636 }
637 }
638
639 # Finally, tags that can be stored straight away:
640 foreach my $tag (qw( FLAGS MAKEFILE ))
641 {
642 my $bdata = $self->getrawdata($tag);
643 if (ref($bdata) eq 'HASH')
644 {
645 while (my ($f,$v) = each %$bdata)
646 {
647 $tooldataobj->flags($f,$v);
648 }
649 }
650 else
651 {
652 $tooldataobj->makefile($bdata), if ($#$bdata != -1);
653 }
654 }
655
656 # Libs and tool dependencise:
657 foreach my $tag (qw( LIB USE ))
658 {
659 my $bdata = $self->getrawdata($tag);
660 my $subname = lc($tag);
661 $tooldataobj->$subname($bdata), if ($#$bdata != -1);
662 }
663
664 # Also check to see if this tool is a scram-managed project. If
665 # so, set the SCRAM_PROJECT variable in the ToolData object:
666 if (exists ($self->{content}->{SCRAM_PROJECT}))
667 {
668 $tooldataobj->scram_project($self->{content}->{SCRAM_PROJECT});
669 }
670
671 # And check to see if this tool is a compiler. If so, set
672 # the SCRAM_COMPILER variable in the ToolData object:
673 if (exists ($self->{content}->{SCRAM_COMPILER}))
674 {
675 $tooldataobj->scram_compiler($self->{content}->{SCRAM_COMPILER});
676 }
677
678 # Establish the order of parsing the value strings:
679 my $order = $self->process_environments($environments);
680
681 if ($self->{interactive})
682 {
683 # Set the values interactively:
684 $self->interactively_find_settings($tooldataobj, $environments, $order);
685 }
686 else
687 {
688 # Set the values:
689 $self->find_settings($tooldataobj, $environments, $order);
690 }
691
692 # Return a ToolData object:
693 return $tooldataobj;
694 }
695
696 sub process_environments()
697 {
698 my $self=shift;
699 my ($environments)=@_;
700
701 use BuildSystem::SCRAMGrapher;
702 my $G = BuildSystem::SCRAMGrapher->new();
703
704 foreach $envtype (keys %{$environments})
705 {
706 while (my ($envcontent,$envdata) = each %{$environments->{$envtype}})
707 {
708 # Add a vertex for the VARIABLE name:
709 $G->vertex($envcontent);
710
711 foreach my $element (@$envdata)
712 {
713 if (exists($element->{'ELEMENTS'}))
714 {
715 map
716 {
717 # Add a path for each element in ELEMENTS:
718 $G->edge($envcontent, $_);
719 } @{$element->{'ELEMENTS'}};
720 }
721 }
722 }
723 }
724
725 my $setup_order = $G->sort();
726 return $setup_order;
727 }
728
729 sub find_settings()
730 {
731 my $self=shift;
732 my ($tooldataobj, $environments, $ordering)=@_;
733 my $stringtoeval;
734 my $runtime=[];
735 my $path;
736
737 use BuildSystem::ToolSettingValidator;
738
739 my $tsv = BuildSystem::ToolSettingValidator->new($environments, $self->toolname());
740
741 foreach my $envname (@$ordering)
742 {
743 my $type = 'ENVIRONMENT';
744 my $envdata = $tsv->environment($type, $envname);
745
746 # Handle single-occurrence variables first (i.e. VAR appears once
747 # in array of hashes):
748 if ($envdata != 0 && $#$envdata == 0) # One element only!
749 {
750 print "\nFinding a value for $envname:","\n";
751 print "\n";
752 # We have an environment and only one data element:
753 # Check the lookup DB:
754 if ($tsv->checkDB($envname))
755 {
756 print "\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 print "\nFinding a value for $envname:","\n";
780 print "\n";
781 foreach my $elementdata (@$envdata)
782 {
783 $path = $tsv->findvalue($envname, $elementdata);
784 # Save in ToolData object:
785 $self->store($tooldataobj, $envname, $path);
786 }
787 }
788 elsif (exists($ENV{$envname}))
789 {
790 # Nothing to do here:
791 push(@$runtime, $envname); # FIX From Shahzad.
792 next;
793 }
794 else
795 {
796 push(@$runtime, $envname);
797 }
798 }
799
800 # Check that the required libraries exist:
801 $self->_lib_validate($tooldataobj);
802
803 # Now process the runtime settings:
804 print "\n";
805 print "-------------------------------\n";
806
807 foreach my $rtname (@$runtime)
808 {
809 my $type = 'RUNTIME';
810 my $envdata = $tsv->environment($type, $rtname);
811 my ($rttype,$realrtname) = split(':',$rtname);
812
813 # Only validate paths:
814 if ($rtname =~ /:/)
815 {
816 # Handle single-occurrence variables first (i.e. VAR appears once
817 # in array of hashes):
818 if ($envdata != 0 && $#$envdata == 0) # One element only!
819 {
820 print "\nRuntime path settings for $realrtname:","\n";
821 print "\n";
822 # We have an environment and only one data element:
823 # Check the lookup DB:
824 if ($tsv->checkDB($rtname))
825 {
826 print "\tValidating value for path $realrtname (found in tool DB):","\n";
827 if ($tsv->validatepath())
828 {
829 # Save in TSV and store in ToolData object:
830 $tsv->savevalue($rtname, $tsv->pathfromdb());
831 $tooldataobj->runtime($rtname, [ $tsv->pathfromdb() ]);
832 }
833 else
834 {
835 $path = $tsv->findvalue($rtname, $envdata);
836 # Save the value in ToolData object:
837 $tooldataobj->runtime($rtname, [ $path ]);
838 }
839 }
840 else
841 {
842 $path = $tsv->findvalue($rtname, $envdata);
843 # Save in ToolData object:
844 $tooldataobj->runtime($rtname, [ $path ]);
845 }
846 }
847 elsif ($envdata != 0 && $#$envdata > 0)
848 {
849 print "\nRuntime path settings for $realrtname:","\n";
850 print "\n";
851 foreach my $elementdata (@$envdata)
852 {
853 $path = $tsv->findvalue($rtname, $elementdata);
854 # Save in ToolData object:
855 $tooldataobj->runtime($rtname, [ $path ]);
856 }
857 }
858 else
859 {
860 next;
861 }
862 }
863 else
864 {
865 # Handle runtime variables:
866 if ($envdata != 0 && $#$envdata == 0) # One element only!
867 {
868 my $value='';
869 $tsv->checkdefaults($envdata, \$value);
870 print "\n";
871
872 # Chck to see if the value contains a variable that should be evaluated:
873 if ($value =~ /$/)
874 {
875 # If so, find the value and substitute. This should work for all
876 # occurrences of variables because by this point (and because the ordering
877 # was established at the start) all other variables will have real values:
878 my $dvalue = $tsv->_expandvars($value);
879 $value = $dvalue;
880 }
881
882 print "Runtime variable ",$rtname," set to \"",$value,"\"\n";
883
884 # Store the variable setting:
885 $tooldataobj->runtime($rtname, [ $value ]);
886 }
887 else
888 {
889 next;
890 }
891 }
892 }
893
894 print "\n";
895 }
896
897 sub interactively_find_settings()
898 {
899 my $self=shift;
900 my ($tooldataobj, $environments, $ordering)=@_;
901 my $stringtoeval;
902 my $runtime=[];
903 my ($path, $dpath);
904
905 use BuildSystem::ToolSettingValidator;
906
907 my $tsv = BuildSystem::ToolSettingValidator->new($environments, $self->toolname(), $self->{interactive});
908
909 foreach my $envname (@$ordering)
910 {
911 my $type = 'ENVIRONMENT';
912 my $envdata = $tsv->environment($type, $envname);
913
914 # Handle single-occurrence variables first (i.e. VAR appears once
915 # in array of hashes):
916 if ($envdata != 0 && $#$envdata == 0) # One element only!
917 {
918 print "\nFinding a value for $envname:","\n";
919 print "\n";
920 # We have an environment and only one data element:
921 # Check the lookup DB:
922 if ($tsv->checkDB($envname))
923 {
924 print "\tValidating value for $envname (found in tool DB):","\n";
925 if ($tsv->validatepath())
926 {
927 # This is our default:
928 $dpath = $tsv->pathfromdb();
929 # Run promptuser() to see if this value can be kept
930 # or should be changed:
931 $path = $tsv->promptuser($envname, $dpath);
932 # Save in TSV and store in ToolData object:
933 $tsv->savevalue($envname,$path);
934 $self->store($tooldataobj, $envname, $path);
935 }
936 else
937 {
938 $path = $tsv->ifindvalue($envname, $envdata);
939 # Save the value in ToolData object:
940 $self->store($tooldataobj, $envname, $path);
941 }
942 }
943 else
944 {
945 $dpath = $tsv->ifindvalue($envname, $envdata);
946 # Save in ToolData object:
947 $self->store($tooldataobj, $envname, $dpath);
948 }
949 }
950 elsif ($envdata != 0 && $#$envdata > 0)
951 {
952 print "\nFinding a value for $envname:","\n";
953 print "\n";
954 foreach my $elementdata (@$envdata)
955 {
956 $path = $tsv->ifindvalue($envname, $elementdata);
957 # Save in ToolData object:
958 $self->store($tooldataobj, $envname, $path);
959 }
960 }
961 elsif (exists($ENV{$envname}))
962 {
963 # Nothing to do here:
964 next;
965 }
966 else
967 {
968 push(@$runtime, $envname);
969 }
970 }
971
972 # Check that the required libraries exist:
973 $self->_lib_validate($tooldataobj);
974
975 # Now process the runtime settings:
976 print "\n";
977 print "-------------------------------\n";
978 foreach my $rtname (@$runtime)
979 {
980 my $type = 'RUNTIME';
981 my $envdata = $tsv->environment($type, $rtname);
982 my ($rttype,$realrtname) = split(':',$rtname);
983
984 # Only validate paths:
985 if ($rtname =~ /:/)
986 {
987 # Handle single-occurrence variables first (i.e. VAR appears once
988 # in array of hashes):
989 if ($envdata != 0 && $#$envdata == 0) # One element only!
990 {
991 print "\nRuntime path settings for $realrtname:","\n";
992 print "\n";
993 # We have an environment and only one data element:
994 # Check the lookup DB:
995 if ($tsv->checkDB($rtname))
996 {
997 print "\tValidating value for path $realrtname (found in tool DB):","\n";
998 if ($tsv->validatepath())
999 {
1000 $dpath = $tsv->pathfromdb();
1001 # Run promptuser() to see if this value can be kept
1002 # or should be changed:
1003 $path = $tsv->promptuser($rtname, $dpath);
1004 # Save in TSV and store in ToolData object:
1005 $tsv->savevalue($rtname, $path);
1006 $tooldataobj->runtime($rtname, [ $path ]);
1007 }
1008 else
1009 {
1010 $dpath = $tsv->ifindvalue($rtname, $envdata);
1011 # Save the value in ToolData object:
1012 $tooldataobj->runtime($rtname, [ $path ]);
1013 }
1014 }
1015 else
1016 {
1017 $path = $tsv->ifindvalue($rtname, $envdata);
1018 # Save in ToolData object:
1019 $tooldataobj->runtime($rtname, [ $path ]);
1020 }
1021 }
1022 elsif ($envdata != 0 && $#$envdata > 0)
1023 {
1024 print "\nRuntime path settings for $realrtname:","\n";
1025 print "\n";
1026 foreach my $elementdata (@$envdata)
1027 {
1028 $path = $tsv->ifindvalue($rtname, $elementdata);
1029 # Save in ToolData object:
1030 $tooldataobj->runtime($rtname, [ $path ]);
1031 }
1032 }
1033 else
1034 {
1035 next;
1036 }
1037 }
1038 else
1039 {
1040 # Handle runtime variables:
1041 if ($envdata != 0 && $#$envdata == 0) # One element only!
1042 {
1043 my $dvalue='';
1044 $tsv->checkdefaults($envdata, \$dvalue);
1045 print "\n";
1046 my $value = $tsv->promptuserforvar($rtname, $dvalue);
1047 # Store the variable setting:
1048 $tooldataobj->runtime($rtname, [ $value ]);
1049 }
1050 else
1051 {
1052 next;
1053 }
1054 }
1055 }
1056
1057 print "\n";
1058 }
1059
1060 sub store()
1061 {
1062 my $self=shift;
1063 my ($tooldataobj, $envname, $path) = @_;
1064 my $subrtn = lc($envname);
1065
1066 if ($tooldataobj->can($subrtn))
1067 {
1068 $tooldataobj->$subrtn([ $path ]);
1069 }
1070 else
1071 {
1072 $tooldataobj->variable_data($envname, $path);
1073 }
1074 }
1075
1076 sub _lib_validate()
1077 {
1078 my $self=shift;
1079 my ($toolobj)=@_;
1080 my $errorstatus = { 0 => $main::good."[OK]".$main::normal, 1 => $main::error."[ERROR]".$main::normal };
1081 my $libsfound={};
1082
1083 # Firstly, we check to see if there are libraries provided by this tool:
1084 my @libraries = $toolobj->lib();
1085 my @libpaths = $toolobj->libdir();
1086
1087 foreach my $ldir (@libpaths)
1088 {
1089 my $full_libname_glob="lib".$lib."*.*";
1090 # Change to lib dir so we avoid the very long paths in our glob:
1091 chdir($ldir);
1092 # Next we use a glob to get libs matching this string (so we
1093 # can see if there's a shared or archive lib):
1094 my @possible_libs = glob($full_libname_glob);
1095 #
1096 map
1097 {
1098 $_ =~ s/\.so*|\.a*//g; # Remove all endings
1099 # Store in our hash of found libs:
1100 $libsfound->{$_} = 1;
1101 } @possible_libs;
1102 }
1103
1104 # Next we iterate over the list of libraries in our tool and
1105 # see if it was found in one of the libdirs:
1106 print "\n\n", if ($#libraries != -1);
1107 foreach my $library (@libraries)
1108 {
1109 # Good status:
1110 my $errorid = 0;
1111 if (! exists ($libsfound->{'lib'.$library}))
1112 {
1113 # Check in system library dirs:
1114 if ($self->_check_system_libs($library))
1115 {
1116 $errorid = 0;
1117 }
1118 else
1119 {
1120 $errorid = 1;
1121 }
1122 }
1123 printf("* Library check %-10s for lib%-12s\n",$errorstatus->{$errorid}, $library);
1124 }
1125
1126 print "\n";
1127 }
1128
1129 sub _check_system_libs()
1130 {
1131 my $self=shift;
1132 my ($lib)=@_;
1133 my $libsfound = {};
1134 my $systemdirs = [ qw( /lib /usr/lib /usr/local/lib /usr/X11R6/lib ) ];
1135 my $full_libname_glob="lib".$lib."*.*";
1136 my $found = 0;
1137
1138 foreach my $dir (@$systemdirs)
1139 {
1140 # Change to lib dir so we avoid the very long paths in our glob:
1141 chdir($dir);
1142 # Next we use a glob to get libs matching this string (so we
1143 # can see if there's a shared or archive lib):
1144 my @possible_libs = glob($full_libname_glob);
1145 #
1146 map
1147 {
1148 $_ =~ s/\.so*|\.a*//g; # Remove all endings
1149 # Store in our hash of found libs:
1150 $libsfound->{$_} = 1;
1151 } @possible_libs;
1152 }
1153
1154 # See if we find the library in the system lib directories:
1155 if (! exists ($libsfound->{'lib'.$library}))
1156 {
1157 $found = 1;
1158 }
1159
1160 return $found;
1161 }
1162
1163 sub AUTOLOAD()
1164 {
1165 my ($xmlparser,$name,%attributes)=@_;
1166 return if $AUTOLOAD =~ /::DESTROY$/;
1167 my $name=$AUTOLOAD;
1168 $name =~ s/.*://;
1169 }
1170
1171 1;