ViewVC Help
View File | Revision Log | Show Annotations | Root Listing
root/cvsroot/COMP/SCRAM/src/BuildSystem/ToolParser.pm
Revision: 1.7
Committed: Tue Nov 6 14:13:49 2007 UTC (17 years, 6 months ago) by muzaffar
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD_SM_071214, v103_xml_071106
Branch point for: HEAD_BRANCH_SM_071214
Changes since 1.6: +3 -1 lines
Log Message:
xml scram with changes to make it fast

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 muzaffar 1.7 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 sashby 1.6 delete $self->{scramdoc};
355 sashby 1.2 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 sashby 1.4
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 sashby 1.2
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 sashby 1.5 push(@$runtime, $envname); # FIX From Shahzad.
794 sashby 1.2 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 sashby 1.3
815 sashby 1.2 # 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 sashby 1.6 sub AUTOLOAD()
1166     {
1167     my ($xmlparser,$name,%attributes)=@_;
1168     return if $AUTOLOAD =~ /::DESTROY$/;
1169     my $name=$AUTOLOAD;
1170     $name =~ s/.*://;
1171     }
1172    
1173 sashby 1.2 1;