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

# User Rev Content
1 sashby 1.2 #____________________________________________________________________
2     # File: ToolParser.pm
3     #____________________________________________________________________
4     #
5     # Author: Shaun Ashby <Shaun.Ashby@cern.ch>
6     # Update: 2004-02-09 20:14:55+0100
7 sashby 1.6 # Revision: $Id: ToolParser.pm,v 1.5.4.4 2007/02/27 11:38:39 sashby Exp $
8 sashby 1.2 #
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 sashby 1.6 $self={};
37 sashby 1.2
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 sashby 1.6 $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 sashby 1.2
78 sashby 1.6 # 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 sashby 1.2
150 sashby 1.6 # 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 sashby 1.2 }
223    
224 sashby 1.6 sub client_()
225 sashby 1.2 {
226 sashby 1.6 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 sashby 1.2
237 sashby 1.6 $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 sashby 1.2
263 sashby 1.6 # 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 sashby 1.2 }
276    
277 sashby 1.6 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 sashby 1.2 sub parse
344     {
345     my $self=shift;
346 sashby 1.6 my ($tool,$toolver,$file)=@_;
347 sashby 1.2 $self->{tool}=$tool;
348     $self->{version}=$toolver;
349 sashby 1.6 $self->{scramdoc}->filetoparse($file);
350 sashby 1.2 $self->verbose("Setup Parse");
351 sashby 1.6 $self->{scramdoc}->parse("setup");
352     delete $self->{scramdoc};
353 sashby 1.2 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 sashby 1.4
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 sashby 1.2
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 sashby 1.5 push(@$runtime, $envname); # FIX From Shahzad.
792 sashby 1.2 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 sashby 1.3
813 sashby 1.2 # 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 sashby 1.6 sub AUTOLOAD()
1164     {
1165     my ($xmlparser,$name,%attributes)=@_;
1166     return if $AUTOLOAD =~ /::DESTROY$/;
1167     my $name=$AUTOLOAD;
1168     $name =~ s/.*://;
1169     }
1170    
1171 sashby 1.2 1;