ViewVC Help
View File | Revision Log | Show Annotations | Root Listing
root/cvsroot/COMP/SCRAM/src/BuildSystem/BuildSetup.pm
Revision: 1.8
Committed: Fri Sep 29 06:45:51 2000 UTC (24 years, 7 months ago) by williamc
Content type: text/plain
Branch: MAIN
Changes since 1.7: +100 -33 lines
Log Message:
update from laptop

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