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

File Contents

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