ViewVC Help
View File | Revision Log | Show Annotations | Root Listing
root/cvsroot/COMP/SCRAM/src/BuildSystem/BuildSetup.pm
Revision: 1.9
Committed: Fri Sep 29 10:32:18 2000 UTC (24 years, 7 months ago) by williamc
Content type: text/plain
Branch: MAIN
Changes since 1.8: +8 -2 lines
Log Message:
Bugfixes

File Contents

# Content
1 #
2 #
3 # Interface
4 # ---------
5 # new(ConfigArea) : A new BuildSetup
6 # BuildDir(directory,targets) : prepare the ground for a build and build
7 # getclass(directory) : return (Class, ClassDir, BuildFileobject)
8 # associated with directory
9 # setup(dir)
10
11 package BuildSystem::BuildSetup;
12 require 5.004;
13 use Utilities::Verbose;
14 use Utilities::SCRAMUtils;
15 use BuildSystem::BuildFile;
16 use BuildSystem::DateStampRecord;
17 use Utilities::AddDir;
18 @ISA=qw(Utilities::Verbose);
19
20 sub new {
21 my $class=shift;
22 my $self={};
23 bless $self,$class;
24 $self->{area}=shift;
25 $self->{toolbox}=$self->{area}->toolbox();
26 $self->{projconfigdir}=$self->{area}->configurationdir();
27 $self->{localtop}=$self->{area}->location();
28 $self->{releasearea}=$self->{area}->linkarea();
29 if ( ! defined $self->{releasearea} ) {
30 $self->{releasearea}=$self->{area};
31 }
32 $self->{releasetop}=$self->{releasearea}->location();
33 $self->{buildfilename}="BuildFile";
34 #$self->verbosity(1);
35 $self->_configurationsetup();
36 return $self;
37 }
38
39 sub _generateexternals {
40 my $self=shift;
41 my $outfile=shift;
42
43 # -- specify these files for dependency information
44 my $depfile=$self->{projconfigdir}."/External_Dependencies";
45
46 # -- get list of dependent files
47 my $datadir=$self->{localtop}."/.SCRAM/".$ENV{SCRAM_ARCH};
48 $fdir=FileHandle->new();
49 opendir $fdir, $datadir;
50 my @depfiles=grep !/^\.\.?$/, readdir $fdir;
51 undef $fdir;
52 for (my $i=0; $i<=$#depfiles; $i++ ) {
53 $depfiles[$i]=$datadir."/".$depfiles[$i];
54 }
55
56 # -- do we need to rebuild?
57 if ( SCRAMUtils::dated($outfile,@depfiles) ) {
58 print "Configuring Local Area\n";
59 # -- open output file
60 my $fout=FileHandle->new();
61 $fout->open(">".$outfile) or die "Unable to open $outfile for output".
62 $!."\n";
63
64 # -- print out tool/ version info
65 my ($tool,$toolobj,$f,$val,$version);
66 foreach $tool ( $self->{toolbox}->tools() ) {
67 $version=$self->{toolbox}->defaultversion($tool);
68 # default versions
69 print $fout "ifdef $tool\n".$tool."_V_".$version."=true\nendif\n";
70 # -- set up the different version -- externals
71 foreach $version ( $self->{toolbox}->versions($tool) ) {
72 $toolobj=$self->{toolbox}->gettool($tool,$version);
73 @deps=$toolobj->getfeature("_externals");
74 foreach $d ( @deps ) {
75 $d=~tr[A-Z][a-z];
76 print $fout "ifdef ".$tool."_V_".$version."\n $d=true\nendif\n";
77 }
78 # -- tool info
79 print $fout "ifdef ".$tool."_V_".$version."\n";
80 foreach $f ( $toolobj->features() ) {
81 foreach $val ( $toolobj->getfeature($f) ) {
82 print $fout "\t".$f." += ".$val."\n";
83 }
84 }
85 print $fout "endif\n";
86 }
87 }
88 # some addittional processing of specific vars
89 print $fout 'INCLUDEPATH+=$(addprefix -I,$(INCLUDE))'."\n";
90 print $fout 'LDFLAGS+=$(addprefix -L,$(LIBDIR))'."\n";
91 print $fout 'CPPFLAGS+=$(addprefix -D,$(CPPDEFINES))'."\n";
92 print $fout 'lib+=$(extralib)'."\n";
93 print $fout 'LDLIBS+=$(addprefix -l,$(lib))'."\n";
94 print $fout 'LDLIBS+=$(addprefix -l,$(REQUIRES))'."\n";
95
96 undef $fout;
97 $self->verbose("End Configuration Setup");
98 }
99 }
100
101 sub classsetup {
102 my $self=shift;
103 my $THISDIR=shift;
104
105 my $classmakefile;
106
107 my ($Class, $ClassDir, $bf)=$self->getclass($THISDIR);
108 $self->verbose("Class = $Class : ClassDir = $ClassDir for directory ".
109 $THISDIR);
110
111 # -- should we ignore?
112 if ( $bf->ignore() ) {
113 print "Nothing to be done - empty group\n";
114 exit;
115 }
116
117
118 # -- Create a makefile from the class BuildFile
119 my $classbuildfile=$self->{localtop}."/".
120 $self->{projconfigdir}."/".$Class."_BuildFile";
121 if ( -f $classbuildfile ) {
122 $classmakefile=$self->{localtop}."/".$ENV{INTwork}.
123 "/".$Class."_makefile.mk";
124 if ( SCRAMUtils::dated($classmakefile, $classbuildfile) ) {
125 # -- generate the new makefile if out of date
126 $self->verbose("Generating $classmakefile from".
127 " $classbuildfile");
128 my $classbf=BuildSystem::BuildFile->new($self->{area});
129 undef $ENV{LatestBuildFile}; # gets set by BuildFile
130 $classbf->GenerateMakefile($classbuildfile, $classmakefile);
131 undef $ENV{LatestBuildFile}; # gets set by BuildFile
132 }
133 }
134 else {
135 # -- No BuildFile - maybe its old style makefile
136 $classmakefile=$self->{localtop}."/".
137 $self->{projconfigdir}."/".$Class."_makefile.mk";
138 if ( ! -f $classmakefile ) {
139 $self->error("Unable to find matching ".$Class.
140 "_BuildFile or ".$Class."_makefile.mk");
141 }
142 }
143 # -- set LatestBuildFile
144 if ( $bf->buildfile() ne "" ) {
145 $ENV{LatestBuildFile}=$bf->makefile();
146 }
147 else {
148 $ENV{LatestBuildFile}=$self->{topbf}->makefile();
149 }
150
151 return ($Class,$ClassDir,$classmakefile);
152 }
153
154 sub _configurationsetup {
155 my $self=shift;
156
157 # -- set working directory
158 $self->{workdir}=$ENV{INTwork};
159 $self->{fullworkdir}=$self->{localtop}."/".$self->{workdir};
160
161 # -- make working directory
162 chdir $self->{localtop};
163 AddDir::adddir($self->{workdir});
164
165 # -- generate tool info
166 $self->_generateexternals($self->{fullworkdir}."/clientmakefile");
167
168 # -- process project BuildFile
169 $self->_topbuildfile();
170 }
171
172 sub BuildDir {
173 my $self=shift;
174 my $THISDIR=shift;
175 my @Targets=@_;
176 my $DefaultBuildFile="";
177
178 # -- Setup Class specifics
179 ($Class,$ClassDir,$classmakefile)=$self->classsetup($THISDIR);
180 $ENV{classmakefile}=$classmakefile;
181 $ENV{Class}=$Class;
182 $ENV{ClassDir}=$ClassDir;
183 $DefaultBuildFile=$ENV{classmakefile};
184 $ENV{DefaultBuildFile}=$DefaultBuildFile;
185
186 # -- Create working directory
187 my $workdir=$self->{workdir}."/".$ClassDir;
188 chdir $self->{localtop};
189 AddDir::adddir($workdir);
190 $ENV{workdir}=$workdir;
191 my $fullworkdir=$self->{localtop}."/".$ENV{workdir};
192 chdir $fullworkdir || die "Unable to enter working directory $!";
193
194 # -- Set up some other useful variables for the Build
195 # set variables listing directories/files available
196 my $fh=FileHandle->new();
197 opendir $fh, "$self->{localtop}/$ClassDir";
198 my @allfiles= grep !/^\.\.?$/, readdir $fh;
199 undef $fh;
200 foreach $file ( @allfiles ) {
201 if ( -d "$self->{localtop}/$ClassDir/$file" ) {
202 $ENV{SCRAM_AVAILDIRS}=$ENV{SCRAM_AVAILDIRS}." ".$file;
203 }
204 else {
205 $ENV{SCRAM_AVAILFILES}=$ENV{SCRAM_AVAILFILES}." ".$file;
206 }
207 }
208 my $targetnumber=$#Targets;
209 $ENV{"MAKETARGETS"}="";
210 foreach $word ( @Targets ) {
211 if ( $word=~/.*=.*/ ) { # if we have an assignment it cant be a target
212 $targetnumber--;
213 }
214 else {
215 # set some variables for use in makefiles
216 $ENV{"MAKETARGET_".$word}=$word;
217 if ( $ENV{"MAKETARGETS"} ne "" ) {
218 $ENV{"MAKETARGETS"}=$ENV{"MAKETARGETS"}." ".$word;
219 }
220 else {
221 $ENV{"MAKETARGETS"}=$word;
222 }
223 }
224 }
225
226 # -- If target not specified default to the class name target
227 if ( $targetnumber == -1 ) {
228 push @Targets,$Class;
229 }
230
231 $ENV{DefaultMakefile}="$ENV{TOOL_HOME}/basics.mk";
232
233
234 $SCRAM_GROUPSDIR=$self->{localtop}."/".$self->{projconfigdir}."/groups.mk";
235 if ( -f $SCRAM_GROUPSDIR ) {
236 $ENV{SCRAM_GROUPSDIR}=$SCRAM_GROUPSDIR;
237 }
238
239 # Do a datestamp check so that make will build files that have changed
240 # rather than just those which are older than their dependencies
241 $self->_checkdatestampindir($ClassDir);
242
243 # -- call the block building method
244 #$report=$bs->build(@Targets);
245
246
247 # The main build here
248 $rv=system("gmake","--no-print-directory","-r","-k","-f","$ENV{DefaultMakefile}","-I$ENV{TOOL_HOME}", @Targets);
249 return $rv/256; # return the exit status of gmake
250
251 }
252
253 sub BuildIt {
254 my $self=shift;
255 my $dir=shift;
256
257 # -- get the building block for the directory
258 my $block=$self->_getdirblock($dir);
259
260 # -- is there a class block associated with the directory?
261 my ($class)=getclass($dir);
262 my $classblock=$self->_getclassblock($class);
263
264 # -- Search for Blocks up to tree root
265 my @dirblocks=();
266 my @dirs=split /\//, $dir;
267 my $fulldir="";
268 foreach $dire ( "/",@dirs ) {
269 $fulldir=$fulldir."/".$dire; # root is //
270 my $block=$self->_getdirblock($fulldir);
271 last if $block->ignore(); # we dont need to go futher
272 push @dirblocks, $block;
273 }
274 foreach $block ( $classblock, @dirblocks ) {
275 # -- merge class blocks together
276 foreach $name ( $block->classes() ) {
277 $object->merge();
278 }
279 foreach $classinst ( $block->classinst() ) {
280 $types{$classinst->id()}=$class->newinst();
281 foreach $element ( $classinst ) {
282 $types{$classinst->id()}->setelement($element,
283 $classinst->value($element));
284 }
285 }
286 }
287
288 # -- call the builder
289
290 }
291
292 sub _getdirblock {
293 my $self=shift;
294 my $dir=shift;
295
296 if ( ! defined $self->{blocks}{$dir} ) {
297
298 # -- get a buildfile and do a block parse
299 my $bf=$self->_startbuildfile($dir);
300 $bf->blockparse($self->{blocks}{$dir});
301
302 }
303 return $self->{blocks}{$dir};
304 }
305
306 sub getclass {
307 my $self=shift;
308 my $dirname = shift;
309 my $Class="DEFAULT";
310 my $ClassDir="";
311
312 #return if $dirname eq "";
313 @DIRA=split /\//, $dirname;
314
315 my $thispath=".";
316 # -- construct all class buildfiles in the path
317 for ( $i=0; $i<=$#DIRA; $i++ ) {
318 #$thispath=(($thispath eq "")?$DIRA[$i]:$thispath."/".$DIRA[$i]);
319 $thispath=$thispath."/".$DIRA[$i];
320 if ( ! exists $self->{pathbf}{$thispath} ) {
321 $self->verbose("Initialising BuildFile in $thispath");
322 $self->{pathbf}{$thispath}=$self->_startbuildfile($thispath);
323 }
324 # -- check class overriden by BuildFile
325 if ( defined $self->{pathbf}{$thispath}->classname() ) {
326 $Class=$self->{pathbf}{$thispath}->classname();
327 $ClassDir=$thispath;
328 }
329 else {
330 # -- sort it out from classpath directives
331 foreach $BlockClassA ( @{$self->{LoBCA}} ) {
332 next if ( $#{$BlockClassA} < $i );
333 $elem=${$BlockClassA}[$i];
334 if ( $elem=~/^$DIRA[$i]\+/ ) {
335 $elem=~s/^$DIRA[$i]//;
336 }
337 #print $elem." ".$DIRA[$i]."\n";
338 if ( $elem=~/^\+/ ) {
339 ($Class=$elem)=~s/^\+//;
340 $ClassDir=$thispath;
341 }
342 #}
343 }
344 }
345 }
346 # -- default case
347 if ( $ClassDir eq "" ) {
348 if ( ! defined $self->{pathbf}{'.'}) {
349 $self->{pathbf}{'.'}=$self->_startbuildfile(".");
350 $self->verbose("DEFAULT class initialised : ".$self->{pathbf}{'.'});
351 }
352 $ClassDir=".";
353 }
354
355 # -- returns
356 ($ClassDir_c=$ClassDir)=~s/^\.\///;
357 return ( $Class, $ClassDir_c, $self->{pathbf}{$ClassDir});
358 }
359
360 #
361 # Check to see if the buildfile is local or in the release area and
362 # parse appropriately
363 #
364 sub _startbuildfile {
365 my $self=shift;
366 my $classdir=shift;
367
368 my $bf=BuildSystem::BuildFile->new($self->{area});
369 my $thisfile="$classdir/$self->{buildfilename}";
370
371 if ( -e $self->{localtop}."/".$thisfile ) {
372 $bf->buildfile($self->{localtop}."/".$thisfile);
373 $bf->ParseBuildFile($self->{localtop}, $classdir,
374 $self->{buildfilename});
375 }
376 elsif ( -e $self->{releasetop}."/".$thisfile ) {
377 $bf->buildfile($self->{releasetop}."/".$thisfile);
378 $bf->ParseBuildFile($self->{releasetop}, $classdir,
379 $self->{buildfilename});
380 }
381 return $bf;
382 }
383
384 sub _topbuildfile {
385 my $self=shift;
386
387 # -- Analyse project buildfile if it exists
388 $self->{topbf}=BuildSystem::BuildFile->new($self->{area});
389
390 $self->{topbf}->buildfile($self->{localtop}."/".$self->{projconfigdir}
391 ."/".$self->{buildfilename});
392 # -- generate top level makefile
393 $self->verbose("Generating Top Level BuildFile");
394 undef $ENV{LatestBuildFile};
395 $self->{topbf}->ParseBuildFile($self->{localtop},
396 $self->{projconfigdir},$self->{buildfilename});
397
398 my @ClassPaths=split /:/, $self->{topbf}->BlockClassPath();
399 foreach $BClassPath ( @ClassPaths ) {
400 next if ( $BClassPath eq "");
401 push @{$self->{LoBCA}}, [ split /\//, $BClassPath ];
402 }
403
404 }
405
406 sub _checkdatestampindir {
407 my $self=shift;
408 my $dir=shift;
409
410 # -- get all local .ds files
411 my $fh=FileHandle->new();
412 my $ldir=$self->{localtop}."/".$self->{workdir}."/".$dir;
413 opendir $fh, $ldir;
414 my @dsfiles= grep /^.*\.ds$/, readdir $fh;
415 $fh->close();
416
417 # -- copy across ds files from releasetop if not existing locally
418 if ( $#dsfiles < 0 ) {
419 # -- get all releasetop .ds files
420 my $rdir=$self->{releasetop}."/".$self->{workdir}."/".$dir;
421 opendir $fh, $rdir;
422 my @releasedsfiles= grep /^.*\.ds$/, readdir $fh;
423 foreach $file ( @releasedsfiles ) {
424 use File::Copy;
425 $self->verbose("Copying $file from $rdir to $ldir");
426 copy($rdir."/".$file,$ldir."/".$file);
427 }
428 $fh->close();
429 @dsfiles=@releasedsfiles;
430 }
431
432 # -- process ds files
433 my $file;
434 foreach $datafile ( @dsfiles ) {
435 $self->verbose("Processing $ldir/$datafile\n");
436 my $ds=BuildSystem::DateStampRecord->new($ldir."/".$datafile);
437 $ds->verbosity($self->verbosity());
438 my $needsupdate;
439 my $productfile=$ds->product();
440 my (%files,%moddate);
441
442 # now get dates in our dependency list
443 my @datedfiles=$ds->dated();
444 if ( $#datedfiles >= 0 ) {
445
446 $needsupdate=1;
447 $date=$datedfiles[0][1]-1;
448 }
449 else {
450 # -- extra checks for local replacement of files
451 foreach $file ( $ds->contents() ) {
452 # -- only check files
453 if ( -f $file ) {
454 $files{$file}=$ds->filedate($file);
455 # -- check to see if we have a new local copy
456 if ( ($file=~/\Q$self->{releasetop}\E/) &&
457 ($self->{releasetop} ne $self->{localtop}) ) {
458 ($tempfile=$file)=~s/\Q$self->{releasetop}\E/$self->{localtop}/;
459 if ( -f $tempfile ) {
460 $files{$tempfile}=$files{$file};
461 $file=$tempfile;
462 }
463 }
464 $moddate{$file}=(stat($file))[9];
465 if ( $moddate{$file} != $files{$file} ) {
466 $self->verbose($file." changed");
467 $date=$moddate{$file}-1;
468 $needsupdate=1;
469 }
470 }
471 }
472 }
473 # time stamp the product file to be older than the dependencies
474 if ( $needsupdate == 1 ) { # touch file into the past
475 my $newproductfile;
476 if ( $productfile!~/\Q$self->{localtop}\E/ ) {
477 if ( $productfile=~/\Q$self->{releasetop}\E/ ) {
478 ($newproductfile=$productfile)=~
479 s/\Q$self->{releasetop}\E/$self->{localtop}/;
480 $self->verbose("Copying $productfile to $newproductfile");
481 copy($productfile,$newproductfile);
482 }
483 else { # assume no path to worry about
484 $newproductfile=$self->{localtop}."/".$ENV{workdir}.
485 "/".$productfile;
486 # -- make a local copy of the product file if not already here
487 my $oldproductfile=$self->{releasetop}."/".$ENV{workdir}.
488 "/".$productfile;
489 if ( ! -f $newproductfile ) {
490 if ( -f $oldproductfile ) {
491 $self->verbose("Copying $oldproductfile to $newproductfile");
492 copy($oldproductfile,$newproductfile);
493 }
494 }
495 }
496 }
497 else {
498 $newproductfile=$productfile;
499 }
500 if ( -f $newproductfile ) {
501 $self->verbose("Blasting $newproductfile to the past ($date)");
502 # If the (local) productfile exists - make it older
503 utime($date,$date,$newproductfile);
504 }
505 else {
506 $self->verbose("SomeThing Wrong(?) with $newproductfile\n".
507 "RELEASETOP=".$self->{releasetop}."\n".
508 "LOCALTOP=".$self->{localtop}."\n".
509 "workdir=".$ENV{workdir});
510 }
511 }
512 else {
513 $self->verbose("No need to touch $productfile");
514 }
515 }
516 undef $fh;
517 }