Subversion Repositories DevTools

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
227 dpurdie 1
# -*- mode: perl; tabs: 8; indent-width: 4; show-tabs: yes; -*-
2
# Copyright (C) 1998-2004 ERG Transit Systems, All rights reserved
3
#
4
# Module name   : Makelib.pl
5
# Module type   : Makefile system
6
#
7
# Description:
8
#       This modules builds the primary makefile for each directory,
9
#       used in conjunction with Makelib.pl2.  The produced makefile
10
#       acts as a frontend to platform builds.
11
#
12
# Notes:
13
#
14
#                       *** DO NOT DETAB ***
15
#
16
#       Beware the use of space v's tab characters within the
17
#       makefile generation sessions.
18
#
19
#.........................................................................#
20
 
255 dpurdie 21
require 5.006_001;
227 dpurdie 22
use strict;
23
use warnings;
261 dpurdie 24
use Getopt::Long;
263 dpurdie 25
use JatsError;
227 dpurdie 26
use JatsEnv;
27
use JatsMakeInfo qw(:create);
28
 
29
our $MakelibVersion         = "2.33";           # makelib.pl version
30
 
31
our $ScmRoot                = "";
32
our $ScmSrcDir              = "";
33
our $ScmMakelib             = "";
34
our @ScmDepends             = ();
35
our $ScmExpert              = 0;
36
our $ScmAll                 = 0;
37
our $ProjectBase            = "";               # Base of the user's project
38
our $ScmInterface           = "interface";
39
 
40
our @SUBDIRS                = ();
41
our @PLATFORMS              = ();
42
our %PLATFORMARGS           = ();
43
our @DEFINES                = "";
44
our @RULES                  = ();
45
 
46
our %PACKAGE_DIST           = ();
47
 
48
our $ROOTMAKEFILE           = 0;
49
our $PLATFORMINCLUDED       = 0;
50
our @BUILDPLATFORMS         = ();
51
 
263 dpurdie 52
our $GBE_CONFIG;
53
our $GBE_TOOLS;
54
our $GBE_PERL;
227 dpurdie 55
 
56
#.. Running under 'buildlib.pl' ?
57
#
58
unless ( $::ScmBuildlib )
59
{
60
    MakeLibInit();
61
}
62
 
63
sub MakeLibInit
64
{
65
    my ( $argc );                               # argument count
66
 
261 dpurdie 67
    #.. Test environment
68
    #
227 dpurdie 69
    EnvImport( "GBE_BIN" );
70
    EnvImport( "GBE_PERL" );
71
    EnvImport( "GBE_TOOLS" );
72
    EnvImport( "GBE_CONFIG" );
73
    EnvImport( "GBE_MACHTYPE" );
74
 
261 dpurdie 75
    #.. Common stuff
76
    #
227 dpurdie 77
    require "$::GBE_TOOLS/common.pl";
78
 
79
    CommonInit( "makelib " );
80
    Debug( "version:   $MakelibVersion" );
81
 
261 dpurdie 82
    #.. Parse command line
83
    #       makefile.pl  rootdir Makelib.pl [options ...]
84
    #
85
    Verbose ("Command Line: @ARGV");
86
    my $opt_help = 0;
87
    my $result = GetOptions (
88
                "help+"         => \$opt_help,
89
                "interface=s"   => \$::ScmInterface,
90
                );
91
 
92
    MLUsage() if ( $opt_help || !$result );
93
 
94
    #
95
    #   Needs 2 command line arguments
96
    #
227 dpurdie 97
    $::ScmRoot    = StripDrive( ${ARGV[0]} );
279 dpurdie 98
    $::ScmRoot    = '/./' if ( $::ScmRoot eq '/'  );    # Prevent leading '//'
227 dpurdie 99
    $::ProjectBase= $::ScmRoot;
100
    $::ScmMakelib = ${ARGV[1]};
101
 
102
    Debug( "ARGV:      @ARGV" );
103
    Debug( "Root:      $::ScmRoot" );
104
    Debug( "Makelib:   $::ScmMakelib" );
105
 
261 dpurdie 106
    #.. Get the stuff from the platform definition file
107
    #
227 dpurdie 108
    ConfigLoad();
109
 
261 dpurdie 110
    #.. Get the stuff from the package definition file
111
    #
227 dpurdie 112
    require "$::ScmRoot/package.pl"
113
        if ( -f "$::ScmRoot/package.pl" );
114
}
115
 
116
#   MLUsage ---
117
#       Makelib command line usage.
118
#..
119
 
120
sub MLUsage
121
{
261 dpurdie 122
    Error ( "Usage: perl makefile.pl <ROOTDIR> <makelib.pl> [options ...]",
123
            "Valid options:",
124
            "   --help            Display Help",
125
            "   --interface=name  Set interface directory",
126
            );
227 dpurdie 127
}
128
 
129
#-------------------------------------------------------------------------------
130
# Function        : SubDir
131
#
132
# Description     : Recurse into the specified sub directories
133
#                   This is one of the very few directives in a 'makefile.pl'
134
#                   that is processed by this script - all the others are
135
#                   processed by makelib.pl2.
136
#
137
#                   This directive MUST appear before the 'Platform' directive
138
#
139
# Inputs          : List of sub directories to visit
140
#
141
# Returns         : Nothing
142
#
143
sub SubDir
144
{
145
    my( @NewDirs );
146
    Debug( "SubDir(@_)" );
147
    Error ("Directive 'SubDir' not allowed in this context") if ( $::ScmBuildlib  );
148
 
149
    #
150
    #   Support different constructs:
151
    #       'dir1 dir2'
152
    #       'dir1','dir2'
153
    #
154
    @NewDirs = map { split /\s+/ } @_;
155
    @NewDirs = grep { defined $_ } @NewDirs;
156
 
157
    foreach my $ThisDir ( @NewDirs )
158
    {
159
        Warning ("SubDir contains a '\\' character: $ThisDir" )
160
            if ( $ThisDir =~ m~\\~);
161
 
162
        if ( grep /^$ThisDir$/, @::SUBDIRS )
163
        {
164
            Warning( "Duplicate SubDir '$ThisDir' -- ignored." );
165
            next;
166
        }
167
        if ( ! ( -e $ThisDir and -d $ThisDir ) )
168
        {
169
            Error( "SubDir(): Subdirectory not found: '$ThisDir'",
170
                   "Current directory: $::Cwd" );
171
        }
172
        if ( ! -f $ThisDir . '/makefile.pl' )
173
        {
174
            Error( "SubDir(): makefile.pl not found in subdirectory: '$ThisDir'",
175
                   "Current directory: $::Cwd" );
176
        }
177
 
178
        push(@::SUBDIRS, $ThisDir);
179
    }
180
}
181
 
182
 
183
#-------------------------------------------------------------------------------
184
# Function        : RootMakefile
185
#
186
# Description     : This function is called from buildlib.pl prior to the
187
#                   generation of the root makefile. The Root Makefile is
188
#                   different to the others in this it does not have any platform
189
#                   specific makefiles associated with it. It is simply used to
190
#                   invoke the makefile in the 'src' subdirectory
191
#
192
# Inputs          : None
193
#
194
# Returns         : Nothing
195
#
196
sub RootMakefile
197
{
198
    Error ("Directive 'RootMakefile' not allowed in this context") if ( $::ScmBuildlib  );
199
    $::ROOTMAKEFILE = 1;
200
}
201
 
202
 
203
sub PackageDist
204
{
205
    my( $name, @elements ) = @_;
206
    Error ("Directive 'PackageDist' not allowed in this context") if ( $::ScmBuildlib  );
207
 
208
    foreach ( @elements ) {
209
        HashJoin( \%::PACKAGE_DIST, $;, $name, "$_" );
210
    }
211
}
212
 
213
 
214
sub Define
215
{
216
    Error ("Directive 'Define' not allowed in this context") if ( $::ScmBuildlib  );
217
    push( @::DEFINES, @_ );
218
}
219
 
220
 
221
sub Defines
222
{
223
    my( $path, $script ) = @_;
224
    my( $line );
225
    Error ("Directive 'Defines' not allowed in this context") if ( $::ScmBuildlib  );
226
 
227
    $script = Exists( $path, $script, "Defines" );
228
    open( SCRIPT, $script ) ||
229
        Error( "cannot open '$script'" );
230
    while (<SCRIPT>) {
231
        $_ =~ s/\s*(\n|$)//;                    # kill trailing whitespace & nl
232
        push( @::DEFINES, $_ );
233
    }
234
    push( @::ScmDepends, "$script" );           # makefile dependencies
235
    close( SCRIPT );
236
}
237
 
238
 
239
sub Rule
240
{
241
    Error ("Directive 'Rule' not allowed in this context") if ( $::ScmBuildlib  );
242
    push( @::RULES, @_ );
243
}
244
 
245
 
246
sub Rules
247
{
248
    Error ("Directive 'Rules' not allowed in this context") if ( $::ScmBuildlib  );
249
    my( $path, $script ) = @_;
250
    my( $line );
251
 
252
    $script = Exists( $path, $script, "Rules" );
253
    open( SCRIPT, $script ) ||
254
        Error( "cannot open '$script'" );
255
    while (<SCRIPT>) {
256
        $_ =~ s/\s*(\n|$)//;                    # kill trailing whitespace & nl
257
        push( @::RULES, $_ );
258
    }
259
    push( @::ScmDepends, "$script" );           # makefile dependencies
260
    close( SCRIPT );
261
}
262
 
263
#-------------------------------------------------------------------------------
264
# Function        : Platform
265
#
266
# Description     : Within "makelib.pl" the Platform directive is processed
267
#                   in such a manner as to trigger the verification and
268
#                   generation of Makefile and xxxxx.mk files in the tree
269
#                   below the makefile.pl
270
#
271
# Inputs          : A list of platforms for which the body of the makefile.pl
272
#                   are to be processed + GBE_PLATFORM
273
#
274
#                   "*", ...            - A wildcard for all platforms
275
#                                         Options include
276
#                                           --Targets (Not Products)
277
#                                           --Products
278
#                                           --NoPlatformBuilds
279
#                                           !xxx - Exclude a platform
280
#
281
#                   "--NoPlatformBuilds"
282
#
283
#                   "xxx"[, "yyy"]*     - A list of platforms and aliases
284
#
285
#                   "!xxx"              - A platform to be excluded
286
#
287
# Returns         :
288
#
289
sub Platform
290
{
291
    my ( @platforms ) = @_;
292
    my ( $dir, $exitVal, $platform );
293
    my $noplatforms = 0;
294
    my $defplatforms = 0;
295
    my %platforms;
296
 
297
    Debug( "Platform(@_)" );
298
    Error ("Directive 'Platform' not allowed in this context") if ( $::ScmBuildlib  );
299
 
300
    #
301
    #   Import user platform specification (GBE_PLATFORM)
302
    #   Note: This is also used by the Makefile and it cannot be
303
    #         alias expanded or sanitised. Its not really really useful
304
    #
305
    #   Only use GB_PLATFORM if the user has not specified to build ALL
306
    #   makefiles.
307
    #
308
    my %filter;
309
    my $filter_present = 0;
310
 
311
    if (  $::ScmAll == 0  )
312
    {
239 dpurdie 313
        $filter{GENERIC} = 1;
227 dpurdie 314
        foreach ( split( ' ', $ENV{ "GBE_PLATFORM" } || '' ) )
315
        {
316
            $filter{$_} = 1;
317
            $filter_present = 1;
318
        }
319
    }
320
 
321
    #
322
    #   Expand out the directive platform list (and optional arguments)
323
    #   Expand wildcards and aliases
324
    #
325
    #   Handle format
326
    #       Platform ('*', '--Options', [!Name]);
327
    #       Platform ('--NoPlatformBuilds' );
328
    #       Platform ('Name', '--Options', [!Name] );
329
    #       Platform ('!Name' );
330
    #
331
    #
332
    if ( $platforms[0] && $platforms[0] eq '*' )
333
    {
334
        my( $targets, $products );              # options
335
        my( @args );
336
        my( @exclude );
337
 
338
        $targets = $products = 0;
339
 
340
        foreach $_ ( @platforms ) {
341
            next if ( /^\*$/);
342
            next if ( /^--Targets$/ && ($targets = 1));
343
            next if ( /^--Products$/ && ($products = 1));
344
            next if ( /^--NoPlatformBuilds/ && ($noplatforms = 1));
345
            next if ( /^--/ && push @args, $_ );
346
            next if ( /^!/  && push @exclude, $_ );
347
            Warning( "Platform: unknown option $_ -- ignored\n" );
348
        }
349
 
350
        #
351
        #   Determine the list of platforms to expand the '*' into
352
        #   The result may be modified by optional arguments
353
        #       --Targets           # Expands to all targets
354
        #       --Products          # Expands to all products
355
        #       OtherWise           # Expands to all build platforms
356
        #
357
        @platforms = ();                        # zap list
358
 
359
                                                # 'all' platforms
360
        push( @platforms, @::DEFBUILDPLATFORMS )
361
            unless ( $targets | $products );
362
 
363
        #
364
        #   Expand the '*' into a list of platforms that are NOT products
365
        #
366
        if ( $targets && defined( %::ScmBuildPlatforms ) )
367
        {                                       # targets
368
            foreach my $key (keys %::ScmBuildPlatforms) {
369
                push( @platforms, $key )
370
                    if (! defined( %::ScmBuildProducts ) ||
371
                            ! scalar $::ScmBuildProducts{ $key } );
372
            }
373
        }
374
 
375
        #
376
        #   Expand the '*' into a list of platforms that are 'products'
377
        #
378
        if ( $products && defined( %::ScmBuildProducts ) )
379
        {                                       # products
380
            foreach my $key (keys %::ScmBuildProducts) {
381
                push( @platforms, $key );
382
            }
383
        }
384
 
385
        #
386
        #   Distribute arguments over all expanded platforms
387
        #
388
        if ( @args )
389
        {
390
            my @baseplatforms;
391
            foreach  ( @platforms )
392
            {
393
                push @baseplatforms, $_, @args;
394
            }
395
            @platforms = @baseplatforms;
396
        }
397
 
398
        #
399
        #   Place the excluded platforms at the end of the list
400
        #
401
        push @platforms, ExpandPlatforms( @exclude );
402
 
403
    }
404
    elsif ( scalar @platforms == 1 && $platforms[0] eq "--NoPlatformBuilds" )
405
    {                                           # short-cut
406
        $noplatforms = 1;
407
        @platforms = @::DEFBUILDPLATFORMS;
408
    }
409
    else
410
    {                                           # aliasing
411
        @platforms = ExpandPlatforms( @platforms );
412
        #
413
        #   Process excluded platform lists
414
        #   Migrate excluded platforms to the end of the list
415
        #
416
        my (@include, @exclude);
417
 
418
        foreach ( @platforms )
419
        {
420
            next if ( m/^!/ && push @exclude, $_ );
421
            push @include, $_;
422
        }
423
 
424
        #
425
        #   If no included platforms have been found then assume that the
426
        #   list is an exclusion list and seed the platform list with
427
        #   a set of defualt platforms - like '*'
428
        #
429
        #
430
        @include = @::DEFBUILDPLATFORMS unless @include;
431
        @platforms = ( @include, @exclude );
432
    }
433
 
434
    $platform = "";                             # current platform
435
 
436
    #
437
    #   Process the directives expanded list of platforms
438
    #
439
 
440
    #
441
    #   Generate a HASH of lowercase known platform names
442
    #   This will be used to quickly validate platform names
443
    #
444
    my %lc_platforms;
445
    foreach  ( @::BUILDPLATFORMS )
446
    {
447
        $lc_platforms{ lc($_) } = $_;
448
    }
449
 
450
FILTER:
451
    foreach $_ ( @platforms )
452
    {
453
        if ( ! /^--(.*)/ )
454
        {
455
            $_ =~ s/^\s*//g;                    # leading white space
456
            $_ =~ s/\s*(\n|$)//;                # trailing white space
457
 
458
 
459
            #
460
            #   Remove specific platforms from the list
461
            #
462
            $defplatforms = 1;
463
            if ( m/!(.*)/ )
464
            {
465
                Verbose( "Excluded platform removed: $1" );
466
                delete $platforms{$1};
467
                next FILTER;
468
            }
469
 
470
 
471
            if ( exists $platforms{$_}  )
472
            {
473
                Warning( "duplicate platform '$_' -- ignored." );
474
                $platform = "";
475
                next FILTER;
476
            }
477
 
478
            #
479
            #   validate 'platform'
480
            #   Allow the user to have a bad case match ( Fred == fred == FRED )
481
            #
482
            my $lc_platform = lc($_);
483
            unless ( exists( $lc_platforms{$lc_platform}  ) )
484
            {
485
                Warning( "Platform '$_' not contained within BuildPlatforms -- ignored." )
486
                    unless ( exists( $::ScmBuildPlatforms{$_} ));
487
                $platform = "";
488
                next FILTER;
489
            }
490
 
491
            $lc_platform = $lc_platforms{$lc_platform};
492
            if ( $_ ne $lc_platform )
493
            {
494
                Warning( "Mixed case usage of platform '$_' -- corrected." );
495
                $_ = $lc_platform;
496
            }
497
 
498
                                                # filter 'platform'
499
            if ( $filter_present  )
500
            {
501
                if ( ! exists $filter{$_} )
502
                {
503
                    Verbose( "GBE_PLATFORM override $_ -- ignored" );
504
                    $platform = "";
505
                    next FILTER;
506
                }
507
            }
508
 
509
            #
510
            #   Platform not filtered out - must be using it.
511
            #
512
            Verbose( "Platform ... $_" );
513
            $platforms{$_} = 1;                 # Add to platform list
514
            $platform = $_;                     # new platform
515
        }
516
 
517
        elsif ( /^--NoPlatformBuilds$/ )
518
        {
519
            $noplatforms = 1;
520
        }
521
 
522
        elsif ( $platform ne "" )
523
        {                                       # other arguments
524
            Verbose( "          .. $_" );
525
 
526
            HashUniqueJoin( \%::PLATFORMARGS, $; , $platform, $1 ) ||
527
                Warning( "Duplicate argument '$platform=$_' -- ignored." );
528
        }
529
    }
530
    #
531
    #   Sort the platforms to ensure that the ordering is consistient throughout
532
    #
533
    @::PLATFORMS = sort keys %platforms;
534
 
535
    #
536
    #   Trap makefiles that don't have any platforms
537
    #   The user 'should' mark these as --NoPlatformBuilds
538
    #
539
    unless ( @::PLATFORMS )
540
    {
541
        Warning( "No platform definitions." )
542
            unless( $noplatforms || $defplatforms);
543
        $noplatforms = 1;
544
    }
545
 
546
#.. Common rules
547
#
548
    my( $file ) = Require( "$::GBE_CONFIG", "Rules", "Common rules " );
549
    push( @::ScmDepends, "$file" );
550
 
551
 
552
#.. Generate primary makefile
553
#
554
    $exitVal = Generate( $noplatforms );
555
    if ($::ROOTMAKEFILE == 1) {
556
        print STDERR "WARNING: problem generating Makefile ($exitVal)\n"
261 dpurdie 557
            if ($exitVal);
227 dpurdie 558
        return ($exitVal);
559
    }
560
 
561
    Debug( "Platform ExitVal:   $exitVal" );
562
    exit( $exitVal );
563
}
564
 
565
###############################################################################
566
# Private function section.
567
#       The following functions are used INTERNALLY by makelib.pl.
568
#
569
###############################################################################
570
 
571
#-------------------------------------------------------------------------------
572
# Function        : Generate
573
#
574
# Description     : Build makefiles ...
575
#                   Creates the command data files and the per-target .MK files
576
#
577
# Inputs          : $noplatforms    - 1 if this makefile does not have
578
#                                       any platforms
579
#
580
# Returns         : $exitVal
581
#
582
sub Generate
583
{
584
    my( $noplatforms ) = @_;
585
    my( $exitVal ) = 0;
586
 
587
    #.. Dont build platforms within root directory
588
    #
589
    $noplatforms = 1
590
        if ($::ROOTMAKEFILE == 1);
591
 
592
    #.. Build 'makefile'
593
    #
594
    $exitVal = GeneratePlatforms()
595
        unless ($noplatforms );
596
 
597
    GenerateMakefile( $noplatforms );
598
    return $exitVal;
599
}
600
 
601
 
602
#
603
#   Note:
604
#   Currently this function will create all .mk files in the current directory
605
#
606
#   Note: Cleanup of unused .mk files is done when the WriteCommonInfo  is
607
#         processed. Makefiles that are no lonker used will be purged
608
#
609
sub GeneratePlatforms
610
{
611
    my( $exitVal, $exitVal2 ) = 0;
612
 
613
    foreach my $platform ( @::PLATFORMS )
614
    {
261 dpurdie 615
        my @CmdLine;
616
        push @CmdLine, $::GBE_PERL, $0, $::ScmRoot;
617
        push @CmdLine, $::ScmMakelib . "2";
618
        push @CmdLine, $platform;
619
        push @CmdLine, "--interface=$::ScmInterface" if ( $::ScmInterface ne "" );
227 dpurdie 620
 
621
        #
622
        #   Insert platform local arguments
623
        #
624
        if ($::PLATFORMARGS{ $platform })
625
        {
261 dpurdie 626
            foreach my $arg (split( /$;/, $::PLATFORMARGS{ $platform } )) {
627
                push @CmdLine,"--arg=$arg";
227 dpurdie 628
            }
629
        }
630
 
261 dpurdie 631
        #
632
        #   Invoke the command
633
        #   Don't use a Shell. Don't need the overhead
634
        #
635
        $exitVal2 = System( '--NoShell', @CmdLine );
227 dpurdie 636
 
261 dpurdie 637
        #
638
        #   Warn on any error
639
        #   Overall return code will be set if any platform fails
640
        #
641
        if ( $exitVal2 )
642
        {
643
            Warning ("Problem generating $platform.mk in $::Cwd ($exitVal2)");
227 dpurdie 644
            $exitVal = $exitVal2;
645
        }
646
    }
647
 
648
    return $exitVal;
649
}
650
 
651
#-------------------------------------------------------------------------------
652
# Function        : GenerateMakefile
653
#
654
# Description     : Generate the non-platform specific makefile
655
#                   Once upon a time this was a real makefile
656
#                   Now its a simple file and a database as this offeres greater
657
#                   flexability.
658
#
659
#                   The file, "Makefile.gbe" contains enough info to get to the
660
#                   interface directory.
661
#
662
#                   The "database" is held in the interface directory as
663
#                       Makfile.cfg     - index to locate Makefile_nn.cfg
664
#                       Makefile_nn.cfg - data from a makefile.pl
665
#
666
# Inputs          : $noplatforms        - 1: no platform makefiles in this dir
667
#
668
# Returns         : Nothing
669
#
670
sub GenerateMakefile
671
{
672
    my( $noplatforms ) = @_;
673
    my %platform_info;
674
 
675
    #
676
    #   Determine targets that are limited to either debug or production builds
677
    #   This information may come from several places
678
    #
679
    foreach my $key ( @PLATFORMS )
680
    {
681
        my @args;
682
        UniquePush (\@args, split ( /$;/, $::PLATFORMARGS{$key} ))
683
            if ($::PLATFORMARGS{$key});
684
 
685
        UniquePush (\@args, map { s/^--//; $_} split ( /$;/, $::ScmBuildPlatforms{$key} ))
686
            if($::ScmBuildPlatforms{$key});
687
 
688
        my $hasOnlyProd  =  grep /^OnlyProd/, @args;
689
        my $hasOnlyDebug =  grep /^OnlyDebug/, @args;
690
 
691
        if ( $hasOnlyProd && $hasOnlyDebug )
692
        {
693
            Warning ("Target \"$key\" has both OnlyDebug and OnlyProd options",
694
                     "Both options ignored. Target will be built" );
695
 
696
            $hasOnlyProd = $hasOnlyDebug = 0;
697
        }
698
        $platform_info{$key}{prod}  = 1 unless $hasOnlyDebug;
699
        $platform_info{$key}{debug} = 1 unless $hasOnlyProd;
700
    }
701
 
702
    #
703
    #   Update common information in the Makefile_x.cfg file
704
    #
705
    WriteCommonInfo( \@::SUBDIRS, \%platform_info, $noplatforms, $::ROOTMAKEFILE );
706
 
707
    #
708
    #.. Maintain local information in Makefile.gbe
709
    #   This allows us to locate the interface directory
710
    #
711
    Message "[Control] $::Cwd";
712
    CreateMakeInfo();
713
}
714
 
715
1;
716