Subversion Repositories DevTools

Rev

Rev 279 | Rev 285 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
227 dpurdie 1
# -*- mode: perl; tabs: 8; indent-width: 4; show-tabs: yes; -*-
261 dpurdie 2
# Copyright (C) 1998-2008 ERG Transit Systems, All rights reserved
227 dpurdie 3
#
4
# Module name   : makelib.pl2
5
# Module type   : Makefile system
6
#
7
# Description:
8
#       This modules builds the platform definition makefiles(s)
9
#
10
# Notes:                *** DO NOT DETAB ***
11
#       Beware the use of space v's tab characters within the
12
#       makefile generation sessions.
13
#
14
##############################################################################
15
# Globals:
16
#  $ScmVersion          Makelib.pl2 version
17
#  $ScmRoot             Command line parameter that gives the root directory
18
#                       location for this directory tree.
19
#  $ScmMakelib          Command line parameter that points to the location
20
#                       of THIS script.  ie. location of makelib.pl.
21
#  $ScmPlatform         Current platform
22
#  $ScmProduct          Current product (if any)
23
#  $ScmTarget           Resulting target (derived from Platform)
24
#  @ScmPlatformArgs     Platform arguments
25
#  $ScmToolset          Toolset
26
#  @ScmToolsetArgs      Toolset arguments
27
#  $ScmDebug            Debug level
28
#  $ScmVerbose          Verbose setting
29
#  $ScmSourceTypes      Source types, aliasing for C, C++ and assembler
30
#                       source.
31
#  @CFLAGS              List containing all of the defined C flags
32
#  @CXXFLAGS            List containing all of the defined C++ flags
33
#  @ASFLAGS             List containing all of the defined assembler flags
34
#  @CLINTFLAGS          List containing all of the defined C lint flags
35
#  @CXXLINTFLAGS        List containing all of the defined C++ lint flags
36
#  @{G|L}_INCDIRS       List containing all of include paths
37
#  @{G|L}_SRCDIRS       List containing all of source search paths
38
#  @{G|L}_LIBDIRS       List containing all of library search paths
39
#  @LDFLAGS             List containing all of the defined linker flags
40
#  @SRCS                List of ALL source files. ie. C/C++ and other (eg .x)
41
#                       Key is source file, value is source path
42
#  @OBJS                List of ALL (non-shared) object files.
43
#  %SHOBJ_LIB           List of ALL shared library object files and there
44
#                       associated library.
45
#  %OBJSOURCE           List of ALL object files
46
#                       from that should result from later makes.
47
#                       Key is objectfile, value is source file
48
#  %OBJREFS             List of ALL object files, built options.
49
#  @PROGOBJS            List of ALL application object files.
50
#  %SRC_ARGS            List of arguments that are to be used when making the
51
#                       nominated source.  Key is the source name, the
52
#                       value is a string of arguments to apply.  The
53
#                       arguments are '$;' separated.
54
#  %SRC_TYPE            Source file type (user override).
55
#  @CHDRS               List of C header files.
56
#  @CSRCS               List of C files
57
#                       Key is objectfile, value is source file
58
#  @CXXSRCS             List of C++ files
59
#  @ASHDRS              List of assembler include files (.inc)
60
#  @ASSRCS              List of assembler source files
61
#  @GENERATED           List of files that should result from a 'generate'
62
#                       make rule.  The programmer is expected to provide
63
#                       the necessary rule(s).
64
#  @RULES               List of additional make rules the programmer
65
#                       has specified to be included in the make.
66
#  %INSTALL_HDRS        List of headers that are to be installed for later
67
#                       "public" consumption.
68
#  %INSTALL_CLSS        List of Java classes or JAR files that are to be installed
69
#                       for later "public" consumption.
70
#  @LIBS                List of libraries that are to be built.
71
#  %LIB_OBJS            List of objects that are to be combined to build the
72
#                       nominated library.  Key is the library name, the
73
#                       value is a string of object files to go into
74
#                       the library.  The object files are '$;' separated.
75
#  %LIB_ARGS            List of arguments that are to be used when making
76
#                       the nominated library.  Key is the library name, the
77
#                       value is a string of arguments to apply.  The
78
#                       arguments are '$;' separated.
79
#  %INSTALL_LIBS        List of libraries that are to be installed for later
80
#                       public consumption.
81
#  @MLIBS               List of libraries that are to be built via merging
82
#  %MLIB_LIBS           List of objects that are to be combined to build the
83
#                       nominated library.  Key is the library name, the
84
#                       value is a string of library files to go into
85
#                       the library.  The object files are '$;' separated.
86
#  @SHLIBS              List of shared libraries that are to be built.
87
#  %SHLIB_OBJS          List of objects that are to be combined to build the
88
#                       nominated library.  Key is the library name, the
89
#                       value is a string of object files to go into
90
#                       the library.  The object files are '$;' separated.
91
#  %SHLIB_ARGS          List of arguments that are to be used when making
92
#                       the nominated library.  Key is the library name, the
93
#                       value is a string of arguments to apply.  The
94
#                       arguments are '$;' separated.
95
#  %INSTALL_SHLIBS      List of libraries that are to be installed for later
96
#                       public consumption.
97
#  @PROGS               List of programs (binary executables) that are
98
#                       to be built
99
#  %PROG_OBJS           List of objects that are to be combined to build the
100
#                       nominated program.  Key is the program name, the
101
#                       value is a string of object files to go into
102
#                       the program.  The object files are '$;' separated.
103
#  %PROG_LIBS           List of libraries that are to be combined to
104
#                       build the nominated program.  Key is the program
105
#                       name, the value is a string of library files to
106
#                       go into the program.  The library files are '$;'
107
#                       separated.
108
#  %PROG_ARGS           List of arguments that are to be used when making the
109
#                       nominated program.  Key is the program name, the
110
#                       value is a string of arguments to apply.  The
111
#                       arguments are '$;' separated.
112
#  %SCRIPTS             List of scripts to 'create' (key) and whether they
113
#                       should be made executable or not (value).  Script
114
#                       set to executable is denoted by the value being
115
#                       defined AND true.
116
#  %INSTALL_PROGS       List of programs for "public" cosumption to install
117
#                       where (key) is the file and where to install it
118
#                       to vs. (value) which is composed of the original
119
#                       location of the file, the destination directory
120
#                       and a list of service providers this file applies to.
121
# $ProjectBase          Base of the user's project. This variable is designed to
122
#                       be used by the user.
123
#....
124
 
255 dpurdie 125
require 5.006_001;
227 dpurdie 126
use strict;
127
use warnings;
261 dpurdie 128
use Getopt::Long;
227 dpurdie 129
use Data::Dumper;
271 dpurdie 130
use JatsError;
227 dpurdie 131
use JatsEnv;
132
use MakeEntry;
133
use JatsLocateFiles;
134
use JatsDPackage;
271 dpurdie 135
use MakeIf;
227 dpurdie 136
 
137
 
271 dpurdie 138
 
227 dpurdie 139
our $ScmVersion             = "2.34";
140
our $ScmGlobal              = 0;
141
our $ScmExpert              = 0;
142
our $ScmInterface           = "interface";      # default 'interface'
143
our $ScmPackage             = 1;                # package active by default.
144
our $ScmProcessingRootMake  = 0;                # Processing root makefile.pl
145
our $ScmPlatformSeen        = 0;                # Platform directive has been seen
146
 
147
our $ScmToolsetVersion      = "";               # version of toolset
148
our $ScmToolsetGenerate     = 1;                # generate active by default.
149
our $ScmToolsetProgDependancies = 1;            # 1: Write program dependancies
150
                                                # 0: Don't write progdeps. Prog is Phony
151
our $ScmToolsetProgSource   = ();               # Toolset Program Source
152
our $ScmRoot                = "";
153
our $ScmMakelib             = "";
154
our $ScmPlatform            = "";
155
our $ScmMachType            = "";
156
our $ScmSrcDir              = "";
157
our @ScmPlatformDirs        = ();
158
our @ScmPlatformArgs        = ();
159
our $ScmProduct             = "";
160
our $ScmTarget              = "";
161
our $ScmTargetHost          = "";
162
our $ScmToolset             = "";
163
our @ScmToolsetArgs         = ();
164
our @ScmDepends             = ();
165
our %ScmSourceTypes         = ();
166
our $ScmDeploymentPatch     = "";
167
our $ProjectBase            = "";               # Base of the user's project
168
our $ScmNoToolsTest         = "";               # Supress compiler tests
169
our $ScmDependTags          = 0;                # Create dependancy scanning tag
170
 
171
our @CFLAGS                 = ();
172
our @CFLAGS_DEBUG           = ();
173
our @CFLAGS_PROD            = ();
174
our @CLINTFLAGS             = ();
175
our @CLINTFLAGS_DEBUG       = ();
176
our @CLINTFLAGS_PROD        = ();
177
our @CXXFLAGS               = ();
178
our @CXXFLAGS_DEBUG         = ();
179
our @CXXFLAGS_PROD          = ();
180
our @CXXLINTFLAGS           = ();
181
our @CXXLINTFLAGS_DEBUG     = ();
182
our @CXXLINTFLAGS_PROD      = ();
183
our @ASFLAGS                = ();
267 dpurdie 184
our @ASFLAGS_DEBUG          = ();
185
our @ASFLAGS_PROD           = ();
227 dpurdie 186
our @LDFLAGS                = ();
267 dpurdie 187
our @LDFLAGS_DEBUG          = ();
188
our @LDFLAGS_PROD           = ();
227 dpurdie 189
 
190
our @INCDIRS                = ();
191
our @NODEPDIRS              = ();
192
our @S_INCDIRS              = ();
193
our @G_INCDIRS              = ();
194
our @L_INCDIRS              = ();
195
our @SRCDIRS                = ();
196
our @S_SRCDIRS              = ();
197
our @G_SRCDIRS              = ();
198
our @L_SRCDIRS              = ();
199
our @LIBDIRS                = ();
200
our @S_LIBDIRS              = ();
201
our @G_LIBDIRS              = ();
202
our @L_LIBDIRS              = ();
203
 
204
our %SRCS                   = ();
205
our %SRC_ARGS               = ();
206
our %SRC_TYPE               = ();
207
our %SRC_DEPEND             = ();
208
our %SCRIPTS                = ();
209
our @COPYIN                 = ();
210
our @INITS                  = ();
211
our @DEFINES                = ();
212
our @OBJS                   = ();
213
our %SHOBJ_LIB              = ();
214
our @PROGOBJS               = ();
215
our %OBJSOURCE              = ();
216
our @CHDRS                  = ();
217
our @CSRCS                  = ();
218
our @CXXSRCS                = ();
219
our @ASHDRS                 = ();
220
our @ASSRCS                 = ();
221
our @GENERATED              = ();
222
our @GENERATED_NOTSRC       = ();
223
our @RULES                  = ();
224
our @TOOLSETRULES           = ();
225
our @TOOLSETDIRS            = ();
226
our @TOOLSETDIRTREES        = ();
227
our @TOOLSETGENERATED       = ();
228
our @USERGENERATED          = ();
229
our @TOOLSETOBJS            = ();
230
our @TOOLSETLIBS            = ();
231
our @TOOLSETPROGS           = ();
232
our %INSTALL_HDRS           = ();
233
our %INSTALL_CLSS           = ();
234
 
235
our @LIBS                   = ();
236
our %LIB_OBJS               = ();
237
our %LIB_ARGS               = ();
238
our %LIB_PKG                = ();
239
our %LIB_INS                = ();
240
our %INSTALL_LIBS           = ();
241
 
242
our @MLIBS                  = ();
243
our %MLIB_LIBS              = ();
244
our %MLIB_ARGS              = ();
245
 
246
our @SHLIBS                 = ();
247
our @SHLIB_TARGETS          = ();
248
our %SHLIB_VER              = ();
249
our %SHLIB_OBJS             = ();
250
our %SHLIB_LIBS             = ();
251
our %SHLIB_ARGS             = ();
252
our %SHLIB_PKG              = ();
253
our %SHLIB_INS              = ();
254
our %INSTALL_SHLIBS         = ();
255
 
256
our %TESTPROGS              = ();
257
our %TESTPROG_OBJS          = ();
258
our %TESTPROG_LIBS          = ();
259
our %TESTPROG_ARGS          = ();
260
 
261 dpurdie 261
our %PROGS                  = ();           # Simplify tracking of progs
227 dpurdie 262
our @PROGS                  = ();
263
our @PROGS_EXTRA            = ();
264
our %PROG_OBJS              = ();
265
our %PROG_LIBS              = ();
266
our %PROG_ARGS              = ();
267
our %PROG_PKG               = ();
268
our %PROG_INS               = ();
269
our %INSTALL_PROGS          = ();
270
 
271
our %PACKAGE_DIST           = ();
272
our %PACKAGE_SETS           = ();
273
our %PACKAGE_HDRS           = ();
274
our %PACKAGE_LIBS           = ();
275
our %PACKAGE_CLSS           = ();
276
our %PACKAGE_SHLIBS         = ();
277
our %PACKAGE_PROGS          = ();
278
our %PACKAGE_FILES          = ();
279
 
280
our @PACKAGE_VARS           = ( '%PACKAGE_CLSS',  '%PACKAGE_FILES', '%PACKAGE_HDRS',
281
                                '%PACKAGE_LIBS',  '%PACKAGE_PROGS', '%PACKAGE_SHLIBS' );
282
our @INSTALL_VARS           = ( '%INSTALL_CLSS',  '%INSTALL_HDRS',  '%INSTALL_LIBS',
283
                                '%INSTALL_PROGS', '%INSTALL_SHLIBS');
284
 
285
our @LINTLIBS               = ();
286
our @LINTSHLIBS             = ();
287
 
288
our @TESTS_TO_RUN           = ();
289
our @TESTPROJECT_TO_URUN    = ();
290
our @TESTPROJECT_TO_ARUN    = ();
291
my  $TESTS_TO_AUTORUN       = undef;
263 dpurdie 292
my  $TESTS_TO_RUN           = undef;
227 dpurdie 293
 
294
#our $CurrentTime           = "";
295
#our $CurrentDate           = "";
296
#our $Cwd                   = "";
297
 
298
our @GENERATE_FILES         = ();
299
our %DEPLOYPACKAGE          = ();
267 dpurdie 300
our $DEPLOYPACKAGE          = 0;
261 dpurdie 301
our %MakeTags;
227 dpurdie 302
 
303
#
304
#   Some toolset options that affect the generation of the makefile
305
#
306
our $UseAbsObjects          = 0;                # Default is relative paths to objects
307
our $UseRelativeRoot        = 0;                # Default is absolute paths to build root
308
 
271 dpurdie 309
#
310
#   Arrays of hook functions
311
#
312
our %MF_RegisterSrcHooks;                       # Hook source file discovery
313
 
314
 
227 dpurdie 315
###############################################################################
316
#
317
#   Packaging and Installation Information
318
#   Held in a structure as its used in a few places
319
#   Items
320
#       PBase   - Package Base directory. Used for user overrides
321
#       IBase   - Local Install Base directory
322
#       Dir     - Default directory suffix for components. Added to Pbase and IBase
323
#
324
#
325
our %PackageInfo = (
326
    'File' => { 'PBase' => '$(PKGDIR)'       ,'IBase' => '$(LOCALDIR)'       , 'Dir' => '' },
327
    'Hdr'  => { 'PBase' => '$(INCDIR_PKG)'   ,'IBase' => '$(INCDIR_LOCAL)'   , 'Dir' => ''},
328
    'Lib'  => { 'PBase' => '$(LIBDIR_PKG)'   ,'IBase' => '$(LIBDIR_LOCAL)'   , 'Dir' => '/$(GBE_PLATFORM)'},
329
    'Prog' => { 'PBase' => '$(BINDIR_PKG)'   ,'IBase' => '$(BINDIR_LOCAL)'   , 'Dir' => '/$(GBE_PLATFORM)$(GBE_TYPE)'},
330
    'Jar'  => { 'PBase' => '$(CLSDIR_PKG)'   ,'IBase' => '$(CLSDIR_LOCAL)'   , 'Dir' => ''},
241 dpurdie 331
    'Tool' => { 'PBase' => '$(PKGDIR)'       ,'IBase' => '$(LOCALDIR)'       , 'Dir' => '/tools/bin/$(GBE_HOSTMACH)'},
227 dpurdie 332
    );
333
 
334
MakeLib2Init();                                 # Runtime initialisation
335
 
336
sub MakeLib2Init
337
{
338
#.. Test environment
339
#
340
    EnvImport( "GBE_CORE" );
341
    EnvImport( "GBE_BIN" );
342
    EnvImport( "GBE_PERL" );
343
    EnvImport( "GBE_TOOLS" );
344
    EnvImport( "GBE_CONFIG" );
345
    EnvImport( "GBE_MACHTYPE" );
346
 
347
#.. Common stuff
348
#
349
    require "$::GBE_TOOLS/common.pl";           # Common stuff
350
    push( @ScmDepends, "$::GBE_TOOLS/common.pl" );
351
 
352
    CommonInit( "makelib2" );
353
    Debug( "version:   $ScmVersion" );
354
 
355
#.. Cache arguments
356
#
357
    CommandLine();
358
 
359
#.. Build defaults
360
#
361
    $ScmSourceTypes{ ".h" }     = ".h";
362
    $ScmSourceTypes{ ".hpp" }   = ".h";
363
    $ScmSourceTypes{ ".c" }     = ".c";
364
    $ScmSourceTypes{ ".C" }     = ".c";
365
    $ScmSourceTypes{ ".cpp" }   = ".cc";
366
    $ScmSourceTypes{ ".cc" }    = ".cc";
367
    $ScmSourceTypes{ ".asm" }   = ".asm";
368
    $ScmSourceTypes{ ".x" }     = "--Ignore";
369
    $ScmSourceTypes{ ".ini" }   = "--Ignore";
370
    $ScmSourceTypes{ ".sh" }    = "--Ignore";
371
    $ScmSourceTypes{ ".pl" }    = "--Ignore";
372
    $ScmSourceTypes{ ".awk" }   = "--Ignore";
373
 
374
#.. Get the stuff from the build configuration file
375
#
376
    ConfigLoad();
377
 
378
    if ( defined(%::ScmBuildPlatforms) )        # Interface/build.cfg
379
    {
380
        AddPlatformArg( split( /$;/, $::ScmBuildPlatforms{ $ScmPlatform } ));
381
    }
382
 
383
    if ( defined(%::ScmBuildIncludes) )         # Interface/build.cfg
384
    {
385
        my( @includes ) = split( ',', $::ScmBuildIncludes{ $ScmPlatform } );
386
        my( $global ) = $ScmGlobal;
387
 
388
        $ScmGlobal = 1;                         # Follow defs are "global's" ...
389
        foreach my $elem ( @includes )
390
        {
391
            AddIncDir( "*", $elem ) if ($elem);
392
        }
393
        $ScmGlobal = $global;                   # Restore global status ...
394
    }
395
 
396
    if ( defined(%::ScmBuildLibraries) )        # Interface/build.cfg
397
    {
398
        my( @libraries ) = split( ',', $::ScmBuildLibraries{ $ScmPlatform } );
399
        my( $global ) = $ScmGlobal;
400
 
401
        $ScmGlobal = 1;                         # Follow defs are "global's" ...
402
        foreach my $elem ( @libraries )
403
        {
404
            AddLibDir( "*", $elem ) if ($elem);
405
        }
406
        $ScmGlobal = $global;                   # Restore global status ...
407
    }
408
 
409
#.. Determine the value of $ScmMachType
410
#   In the makefile GBE_MACHTYPE will be set to $ScmMachType.
411
#
412
#   There is an compatibility issue here.
413
#   A lot of (legacy) package.pl files use GBE_MACHTYPE to specify platform
414
#   specfic directories and names. This is not to be encouraged.
415
#
416
#   Allow for a platformm specific override
417
#
418
    if ( exists( $::BUILDINFO{$ScmPlatform}{'SCMMACHTYPE'} ))
419
    {
420
        $ScmMachType = $::BUILDINFO{$ScmPlatform}{'SCMMACHTYPE'};
421
        Verbose("Override ScmMachType: $ScmMachType");
422
    }
423
    else
424
    {
425
        $ScmMachType = $ScmPlatform;
426
    }
427
 
428
 
429
#.. Get the stuff from the Package definition file
430
#   A convention is that package.pl provide a package name via $Pbase
431
#   This may be different to the BUILDNAME. Generate a default $Pbase
432
#   to allow the package.pl to use the package name part of the buildname
433
#
434
    $::Pbase = $::ScmBuildPackage;
435
    if ( -f "$ScmRoot/package.pl" )
436
    {
437
        Warning ("package.pl file used. Use is being deprecated");
438
 
439
        my( $global ) = $ScmGlobal;             # Follow defs are "global's" ...
440
        $ScmGlobal = 1;
441
        require "$ScmRoot/package.pl";
442
        $ScmGlobal = $global;                   # Restore global status ...
443
 
444
        if ( defined ($::ScmBuildPackage) && defined ($::Pbase) )
445
        {
446
            #   Special case.
447
            #   $Pbase is set to ".". Set $Pbase to the Build Name to force
448
            #   construction of a well formatted package.
449
            #
450
            $::Pbase = $::ScmBuildPackage
451
                if ( $::Pbase eq "." );
452
 
453
            #
454
            #   Error if Pbase has changed
455
            #
456
            Error ("Pbase is not the same as the BuildName (Check package.pl)",
457
                   "Pbase    : $::Pbase",
458
                   "BuildName: $::ScmBuildPackage")
459
                if ( $::Pbase ne $::ScmBuildPackage );
460
        }
461
    }
462
}
463
 
261 dpurdie 464
#-------------------------------------------------------------------------------
465
# Function        : CommandLine
466
#
467
# Description     : Process the command line.
468
#                   Arguments describes below
469
#
470
# Arguments       : ARG0        - Root of the project
471
#                   ARG1        - Path to this script
472
#                   ARG2        - Target Platform
473
#
474
#                   Options follow
475
#                       --interface=name    - Name of interface dir
476
#                       --arg=xxx           - Platform argument
477
#
478
#                   Otherwise display a usage message
479
#
480
# Returns         : Nothing
481
#
227 dpurdie 482
sub CommandLine
483
{
261 dpurdie 484
    Verbose ("Command Line: @ARGV");
227 dpurdie 485
 
261 dpurdie 486
    #
487
    #   Extract options first
488
    #
489
    my $opt_help = 0;
490
    my $result = GetOptions (
491
                "help+"         => \$opt_help,
492
                "interface=s"   => \$::ScmInterface,
493
                "arg=s"         => sub{ AddPlatformArg( "--$_[1]") }
494
                );
495
    Usage() if ( $opt_help || !$result );
496
 
497
    #
498
    # Need 3 Arguments
499
    #
227 dpurdie 500
    $ScmRoot     = ${ARGV[0]};
261 dpurdie 501
    $ScmRoot     = RelPath( $ScmRoot );
227 dpurdie 502
    $ProjectBase = $ScmRoot;
503
 
504
    $ScmMakelib  = ${ARGV[1]};
505
    $ScmPlatform = ${ARGV[2]};
506
    $ScmTarget   = $ScmPlatform;
507
 
508
    Message ("[$ScmPlatform] Generate Makefile");
509
    Debug( "root\t=$ScmRoot" );
510
    Debug( "makelib\t=$ScmMakelib" );
511
    Debug( "platform\t=$ScmPlatform" );
512
}
513
 
514
#   Usage ---
515
#       Command line usage help.
516
#..
517
 
518
sub Usage
519
{
261 dpurdie 520
    Error ( "Usage: perl makefile.pl2 <ROOTDIR> <makelib.pl2> <PLATFORM> [options ...]",
521
            "Valid options:",
522
            "    --interface=name  Set interface directory",
523
            "    --arg=text        Specify platform argument",
524
            );
227 dpurdie 525
}
526
 
527
 
528
#-------------------------------------------------------------------------------
529
# Function        : SubDir
530
#
531
# Description     : Include a sub-makefile
532
#                   When called when processing by this script this directive
533
#                   does nothing. The processing will be done by makelib.pl
534
#
535
#                   This directive MUST occur before the Platform directive
536
#
537
# Inputs          : None that are used
538
#
539
# Returns         : Nothing
540
#
541
 
542
sub SubDir
543
{
544
    Error ("SubDir directive not allowed after the Platform directive")
545
        if ( $ScmPlatformSeen );
546
}
547
 
548
 
549
###############################################################################
550
#   Platform support
551
###############################################################################
552
 
553
sub Platform
554
{
555
    my( $global, $file );
556
 
557
    Debug( "Platform( $ScmPlatform, @ScmPlatformArgs )" );
558
 
559
#.. Sanity test
560
#
561
    Error ("Platform directive is not allowed in common makefile.pl")
562
        if ( $ScmProcessingRootMake );
563
 
564
    Error ("Only one Platform directive is allowed")
565
        if ( $ScmPlatformSeen );
566
    $ScmPlatformSeen = 1;
567
 
568
#.. Arguments
569
#
570
    $ScmTargetHost = $::ScmHost;                # default
571
 
572
#.. Common configuration
573
#
574
    $global = $ScmGlobal;                       # Follow defs are "global's" ...
575
    $ScmGlobal = 1;
576
 
577
#.. Common rules (ScmHost specific)
578
#
579
    push( @ScmDepends, "$ScmMakelib" );         # parent
580
 
581
    $file = Require( "$::GBE_CONFIG", "Rules", "Common rules " );
582
    push( @ScmDepends, "$file" );
583
 
584
#.. Platform (defines ScmToolset)
585
#
586
    if ( defined( %::ScmBuildProducts ) &&      # interface/build.cfg
587
            $::ScmBuildProducts{ $ScmPlatform } )
588
    {
589
        my( @args ) = split( ',', $::ScmBuildProducts{ $ScmPlatform } );
590
 
591
        $ScmProduct = $args[0];
592
        $ScmTarget = $args[1];
593
 
594
        Debug( " mapping to product $ScmProduct" );
595
 
596
                                                # Platform/target specific
597
        MakeIf::PackageDirs( \@ScmPlatformDirs, $ScmPlatform, $ScmTarget );
598
        push @ScmPlatformDirs, "$::GBE_CONFIG"; # .. plus default
599
 
600
        @ScmPlatformArgs = ( "--product=$ScmProduct", @ScmPlatformArgs );
601
        $file = Require( "PLATFORM", $ScmTarget,
602
                    "Platform definition ", @ScmPlatformDirs );
603
    }
604
    else                                        # standard
605
    {
606
        Debug( " native platform" );
607
 
608
                                                # Platform specific
609
        MakeIf::PackageDirs( \@ScmPlatformDirs, $ScmPlatform );
610
        push @ScmPlatformDirs, "$::GBE_CONFIG"; # .. plus default
611
 
612
        $file = Require( "PLATFORM", $ScmPlatform,
613
                    "Platform definition ", @ScmPlatformDirs );
614
    }
615
    push( @ScmDepends, "$file" );
616
 
617
    Error( "Toolset undefined for platform $ScmPlatform ...")
618
        unless( $ScmToolset );
619
 
620
#.. Toolset
621
#
622
    $file = Require( "$::GBE_TOOLS/LIB", "ToolsetPrinter.pm", "Toolset common components " );
623
    push( @ScmDepends, "$file" );
624
 
625
    $file = Require( "$::GBE_CONFIG/TOOLSET", $ScmToolset, "Toolset definition " );
626
    push( @ScmDepends, "$file" );
627
 
628
#.. Package definitions
629
#
630
#   a)  Firstly the static buildlib.pl generated search paths, which
631
#       are $ScmPlatform specific.
632
#
633
#   b)  Secondly the global DPACKAGE definitions, which may pull in
634
#       $ScmTarget specific definitions.
635
#
636
    if ( -e "$ScmRoot/$ScmInterface/$ScmPlatform.rul" )
637
    {                                           # static configuration
638
        Defines( "$ScmRoot/$ScmInterface", "$ScmPlatform.rul" );
639
    }
640
 
641
    MakeIf::PackageLoad( $ScmPlatform );        # DPACKAGE's (if any)
642
 
643
 
644
#.. Package extensions
645
#   Import, into the current package, files of the form gbe/DIRECTIVES
646
#   These allow the JATS directives to be extended by the contents of a package
647
#   without the need to update the core JATS release.
648
#
649
#   Intended use: Associate a directive with a tool script, such that the
650
#   new directive simplifies the use of the tool script.
651
#
652
#
653
#   First: Extend the Perl Search Space to include the toolset extensions
654
#          Although the directives are in gbe/DIRECTIVES/*.pm, they may need
655
#          to reference other packages that are not.
656
#
657
    for my $path ( ToolExtensionPaths() )
658
    {
659
        UniquePush (\@INC, $path)
660
            if (glob( "$path/*.pm") || glob( "$path/*/*.pm"));
661
    }
662
 
663
    for my $entry (@{$::ScmBuildPkgRules{$ScmPlatform} })
664
    {
665
        my $cfgdir = $entry->{'CFGDIR'};
666
        next unless ( $cfgdir );
667
        my $base_dir = $entry->{'ROOT'} . $cfgdir . '/DIRECTIVES';
668
        next unless ( -d $base_dir );
669
        foreach my $file  ( glob ("$base_dir/*.pm") )
670
        {
671
            push( @ScmDepends, "$file" );
672
            require $file;
673
        }
674
    }
675
 
676
    #
271 dpurdie 677
    #   Include local toolset extensions
678
    #   These are rooted in the build directory and are not to be confused with
679
    #   extensions that may be packaged
680
    #
681
    my $local_base_dir = "$ScmRoot/gbe/DIRECTIVES";
682
    if ( -d $local_base_dir )
683
    {
684
        foreach my $file  ( glob ("$local_base_dir/*.pm") )
685
        {
686
            push( @ScmDepends, "$file" );
687
            require $file;
688
        }
689
    }
690
 
691
    #
227 dpurdie 692
    #   All makefile.pl's will include a makefile.pl found in the build
693
    #   root directory ( The same directory as build.pl ). This makefile.pl
694
    #   is a little bit different - It should not "require "$ARGV[1]", nor
695
    #   should it use a Platform directive.
696
    #
697
    #   Note: This makefile is processed AFTER the toolset has been initialised
698
    #         so that toolset extensions are available to the directives
699
    #
700
    $file = "$ScmRoot/makefile.pl";
701
    if ( -e $file ) {
702
        $ScmProcessingRootMake = 1;
703
        require "$file";
704
        $ScmProcessingRootMake = 0;
705
        push( @ScmDepends, "$file" );
706
    }
707
 
708
    #
709
    #   Restore global status ...
710
    #
711
    $ScmGlobal = $global;
712
}
713
 
714
 
715
sub PlatformRequire
716
{
717
    my( $script, @arguments ) = @_;
718
    my( $file );
719
 
720
    Debug( "PlatformRequire($script, @arguments)" );
721
 
722
    push( @ScmPlatformArgs, @arguments );       # additional arguments
723
 
724
    $file = Require( "PLATFORM", $script,
725
                "PlatformRequire ", @ScmPlatformDirs );
726
 
727
    push( @ScmDepends, "$file" );
728
}
729
 
730
 
731
sub PlatformInclude
732
{
733
    my( $script, @arguments ) = @_;
734
    my( $file );
735
 
736
    Debug( "PlatformInclude( @_ )" );
737
 
738
    $file = Require2( \@arguments, "PLATFORM", $script,
739
                "PlatformInclude ", @ScmPlatformDirs );
740
 
741
    push( @ScmDepends, "$file" );
742
}
743
 
744
 
745
sub PlatformDefine
746
{
747
    Debug2( "PlatformDefine(@_)" );
748
 
749
    Define( @_ );
750
}
751
 
752
 
753
sub PlatformDefines
754
{
755
    my( $script ) = @_;
756
    my( $line );
757
 
758
    Debug2( "PlatformDefine(@_)" );
759
 
760
    $script = Exists( "PLATFORM", $script,      # locate image
761
                "PlatformDefines", @ScmPlatformDirs );
762
 
271 dpurdie 763
    push( @DEFINES, "# PlatformDefines from: $script" );
227 dpurdie 764
    open( SCRIPT, $script ) || Error( "Opening $script" );
765
    while (<SCRIPT>) {
766
        $_ =~ s/\s*(\n|$)//;                    # kill trailing whitespace & nl
767
        push( @DEFINES, $_ );
768
    }
769
    push( @ScmDepends, "$script" );             # makefile dependencies
770
    close( SCRIPT );
771
}
772
 
773
 
774
sub PlatformEntry
775
{
776
    my( $prelim, $postlim, $prefix, $postfix, @elements ) = @_;
777
    my( $str, $element );
778
 
779
    $str = "$prelim";
780
    foreach $element ( @elements )
781
    {
782
        $str .= "${prefix}${element}${postfix}";
783
    }
784
    $str .= "$postlim";
785
    PlatformDefine( $str );
786
}
787
 
788
 
789
#
790
#   Add arguments to the ScmPlatformArgs, but remove "Global" arguments
791
#       --OnlyDebug
792
#       --OnlyProduction
793
#
794
sub AddPlatformArg
795
{
796
    Debug("AddPlatformArg: @_" );
797
 
798
    my @args = grep ( !/^--Only((Debug)|(Prod))/, @_ );
799
    UniquePush( \@::ScmPlatformArgs, @args );
800
 
801
    Debug("AddPlatformArg: Result: @::ScmPlatformArgs" );
802
    1;
803
}
804
 
805
###############################################################################
806
# Toolset support
807
#
808
#   Toolset( 'platform [, ... ]', name, [arg, ... ] )
809
#       Specify the toolset for a platform
810
#
811
#   ToolDefine( )
812
#   ToolDefines( )
813
#       Specifies toolset defines for insertion into the target makefile.
814
#
815
#   ToolsetDir
816
#       Define toolset created directory(s) for removal during
817
#       'clean' operations.
818
#
819
#   ToolsetGenerate
820
#       Define toolset created file(s) for removal during
821
#       'clean' operations.
822
#
823
#   ToolsetObj
824
#       Define toolset created object(s) for removal during
825
#       'clean' operations.
826
#
827
#   ToolsetLib
828
#       Define toolset created library(s) for removal during
829
#       'clean' operations.
830
#
831
#   ToolsetProg
832
#       Define toolset created prog(s) for removal during
833
#       'clean' operations.
834
#
835
#   ToolsetRule( )
836
#   ToolsetRules( )
837
#       Specifies toolset rules for insertion into the target makefile.
838
#
839
##############################################################################
840
 
841
sub Toolset
842
{
843
    my( $platforms, $toolset, @arguments ) = @_;
844
 
845
    Debug2( "Toolset(@_)" );
846
 
847
    return if ( ! ActivePlatform($platforms) );
848
 
849
    $ScmToolset = $toolset;
850
    @ScmToolsetArgs = @arguments;
851
}
852
 
853
 
854
sub ToolsetRequire
855
{
856
    my( $script, @arguments ) = @_;
857
    my( $file );
858
 
859
    Debug2( "ToolsetRequire(@_)" );
860
 
861
    @ScmToolsetArgs = @arguments;
862
    $file = Require( "",
863
                     $script,
864
                     "ToolsetRequire",
865
                     "$::GBE_CONFIG/TOOLSET", @::BUILDTOOLSPATH );
866
    push( @ScmDepends, "$file" );
867
}
868
 
869
 
870
sub ToolsetDefine
871
{
872
    Debug2( "ToolsetDefine(@_)" );
873
 
874
    Define( @_ );
875
}
876
 
877
 
878
sub ToolsetDefines
879
{
880
    Debug2( "ToolsetDefines(@_)" );
881
 
261 dpurdie 882
    Defines( "$::GBE_CONFIG/TOOLSET", @_ );
227 dpurdie 883
}
884
 
885
 
886
sub ToolsetDir
887
{
888
    Debug2( "ToolsetDir(@_)" );
889
 
261 dpurdie 890
    UniquePush ( \@TOOLSETDIRS, @_ );
227 dpurdie 891
}
892
 
893
 
894
sub ToolsetDirTree
895
{
896
    Debug2( "ToolsetDirTree(@_)" );
897
 
261 dpurdie 898
    UniquePush ( \@TOOLSETDIRTREES, @_);
227 dpurdie 899
}
900
 
901
 
902
sub ToolsetGenerate
903
{
904
    Debug2( "ToolsetGenerate(@_)" );
905
 
906
    UniquePush( \@TOOLSETGENERATED, @_ );
907
}
908
 
909
 
910
sub ToolsetObj
911
{
912
    Debug2( "ToolsetObj(@_)" );
913
 
261 dpurdie 914
    foreach my $obj ( @_ )
227 dpurdie 915
    {
261 dpurdie 916
        UniquePush( \@TOOLSETOBJS, "$obj.$::o"  );
227 dpurdie 917
    }
918
}
919
 
920
 
921
sub ToolsetLib
922
{
923
    Debug2( "ToolsetLib(@_)" );
924
 
261 dpurdie 925
    foreach my $lib ( @_ )
227 dpurdie 926
    {
261 dpurdie 927
        UniquePush( \@TOOLSETLIBS, "$lib.$::a" );
227 dpurdie 928
    }
929
}
930
 
931
 
932
sub ToolsetProg
933
{
934
    Debug2( "ToolsetProg(@_)" );
935
 
261 dpurdie 936
    foreach my $prog ( @_ )
227 dpurdie 937
    {
261 dpurdie 938
        UniquePush( \@TOOLSETPROGS, "$prog$::exe" );
227 dpurdie 939
    }
940
}
941
 
942
 
943
sub ToolsetRule
944
{
945
    Debug2( "ToolsetRule(@_)" );
946
 
947
    push( @TOOLSETRULES, @_ );
948
}
949
 
950
 
951
sub ToolsetRules
952
{
953
    my( $script ) = @_;
954
    my( $line );
955
 
956
    Debug2( "ToolsetRules(@_)" );
957
 
958
    $script = Exists( "$::GBE_CONFIG/TOOLSET", $script, "ToolsetRules" );
271 dpurdie 959
    push( @TOOLSETRULES, "# ToolsetRules from: $script" );
227 dpurdie 960
    open( SCRIPT, $script ) || Error( "Opening $script" );
961
    while (<SCRIPT>) {
962
        $_ =~ s/\s*(\n|$)//;                    # kill trailing whitespace & newline
963
        push( @TOOLSETRULES, $_ );
964
    }
965
    push( @ScmDepends, "$script" );             # makefile dependencies
966
    close( SCRIPT );
967
}
968
 
969
 
970
###############################################################################
971
# User interface:
972
#
973
#   AddFlags( 'platform [, ... ]', 'flags' [, 'flag' ... ] )
974
#       This subroutine takes the C and C++ compiler flags
975
#       specified adding them to a global list for later
976
#       inclusion in the built makefile.
977
#
978
#   AddCFlags( 'platform [, ... ]', 'flags' [, 'flag' ... ] )
979
#       This subroutine takes the C compiler flags
980
#       specified adding them to a global list for later
981
#       inclusion in the built makefile.
982
#
983
#   AddCXXFlags( 'platform [, ... ]', 'flags' [, 'flag' ... ] )
984
#       This subroutine takes the C++ compiler flags
985
#       specified adding them to a global list for later
986
#       inclusion in the built makefile.
987
#
988
#   AddLintFlags( 'platform [, ... ]', 'flags' [, ... ] )
989
#       This subroutine takes the Lint flags specified
990
#       adding them to a global list for later inclusion
991
#       in the built makefile.
992
#
993
#   AddASFlags( 'platform [, ... ]', 'flags' [, ... ] )
994
#       This subroutine takes the Assemler flags specified
995
#       adding them to a global list for later inclusion
996
#       in the built makefile.
997
#
998
#   AddLDFlags( 'platform [, ... ]', 'flags' [, ... ] )
999
#       This subroutine takes the Linker flags specified
1000
#       adding them to a global list for later inclusion
1001
#       in the built makefile.
1002
#
1003
#   AddDir
1004
#       This subroutine takes the directories specified adding
1005
#       them to a global include and source directory list for
1006
#       later inclusion in the built makefile.
1007
#
1008
#   AddIncDir( 'platform [, ... ]', 'dir' [, ... ] )
1009
#       This subroutine takes the include file directories
1010
#       specified adding them to a global list for later
1011
#       inclusion in the built makefile.
1012
#
1013
#   AddSrcDir( 'platform [, ... ]', 'dir' [, ... ] )
1014
#       This subroutine takes the source file directories
1015
#       specified adding them to a global list used to resolve
1016
#       Src() definitions.
1017
#
1018
#   AddLibDir( 'platform [, ... ]', 'dir' [, ... ] )
1019
#       This subroutine takes the library directories
1020
#       specified adding them to a global list for later
1021
#       inclusion in the built makefile.
1022
#
1023
#   AddSourceType( 'ext', '.c|.cc|.asm' )
1024
#       This subroutine takes the extension(s) specified by the
1025
#       programmer and adds them to a global list for later
1026
#       inclusion in the built makefile.  This list contains
1027
#       the extensions to be recognised as 'C', 'C++' or
1028
#       assembler file types.
1029
#
1030
#   AddSourceFile( 'platform [, ... ]', 'file' [, ... ] )
1031
#       This subroutine takes the non-standard source file(s)
1032
#       and adds them add it to either C, C++ or assembler
1033
#       sources and the object list.
1034
#
1035
#   Init( 'platform [, ... ]', 'rule' )
1036
#       Initialisation rule
1037
#
1038
#   Generate( 'platform [, ... ]', 'file' [, ... ] )
1039
#       This subroutine is used to add the list of given
1040
#       source files to the generate sources list, and if
1041
#       the generated source is of type C, C++ or assember
1042
#       also adds it to either C, C++ or assembler sources and
1043
#       the object lists.
1044
#
1045
#       --c             Treat as a C source file.
1046
#       --cpp           Treat as a C++ source file.
1047
#       --asm           Treat as a assembler source file.
1048
#
1049
#   Rule( 'platform [, ... ]', definition )
1050
#       This subroutine is used to add the non-standard make
1051
#       rules required to build the system.  eg. any rules
1052
#       necessary to produce a .cc & .h file from a .x file.
1053
#
1054
#   Src( 'platform [, ... ]', 'file' [, ... ], [ 'arg' [, ...]] )
1055
#       This subroutine is used to add the list of given source
1056
#       files to the sources list, and if the source is of type
1057
#       C, C++ or assember also adds it to either C, C++ or
1058
#       assembler sources and the object lists.  The optional
1059
#       list of arguments is assigned to all source files.
1060
#
1061
#       --c             Treat as a C source file.
1062
#       --cpp           Treat as a C++ source file.
1063
#       --asm           Treat as a assembler source file.
1064
#       --Shared        Shared, produces position-independent
1065
#                       code (on targets where required).
1066
#
1067
#   Lib( 'platform [, ... ]', 'name', 'obj' [, ... ] [, '-arg' [, ... ]] )
1068
#       This subroutine takes a library definition list and adds
1069
#       the  entries to the 3 libraries definition lists. 'name'
1070
#       of the library to be created.  List of the object files
1071
#       'obj' that make up this library.  List of special
1072
#       arguments 'arg' to pass to the librarian.
1073
#
1074
#   MergeLibrary( 'platform [, ... ]', 'name', 'lib' [, ... ] )
1075
#       This subroutine takes a library merge list and adds
1076
#       the  entries to the 2 merge libraries definition lists. 'name'
1077
#       of the library to be created.  List of the libraries to be merged
1078
#
1079
#   LocalScript( 'platform [, ... ]', name, ['1'] )
1080
#   Script( 'platform [, ... ]', name, ['1'] )
1081
#       This subroutine takes a list that defines the name of
1082
#       the script to be placed in the platform 'bin' directory,
1083
#       and an optional second element that defines whether the
1084
#       script should be made executable or not.
1085
#
1086
#   Prog( 'platform [, ... ]', 'name', ['obj', ... ],
1087
#               ['-llib', ... ], ['options'] )
1088
#       This subroutine takes a list that defines which program
1089
#       (binary) is to be made, what libraries and object it is
1090
#       made from, and any special commands required to perform
1091
#       the program creation.
1092
#
1093
#       @PROGS          Updated list of programs to create
1094
#       %PROG_OBJS      Updated list of [library-name (key) vs. objects]
1095
#                       used to generate this program
1096
#       %PROG_LIBS      Updated list of [library-name (key) vs. libraries]
1097
#                       used to generate this program
1098
#       %PROG_PARGS     Updated list of [library-name (key) vs. options]
1099
#                       used to generate this program
1100
#
1101
#   TestProg( 'platform [, ... ]', 'name', ['obj', ... ],
1102
#               ['-llib', ... ], ['options'] )
1103
#       This subroutine takes a list that defines which test program
1104
#       (binary) is to be made, what libraries and object it is
1105
#       made from, and any special commands required to perform
1106
#       the program creation.
1107
#
1108
#       @TESTPROGS      Updated list of programs to create
1109
#       %TESTPROG_OBJS  Updated list of [library-name (key) vs. objects]
1110
#                       used to generate this program
1111
#       %TESTPROG_LIBS  Updated list of [library-name (key) vs. libraries]
1112
#                       used to generate this program
1113
#       %TESTPROG_PARGS Updated list of [library-name (key) vs. options]
1114
#                       used to generate this program
1115
#
1116
#   InstallHdr( 'platform [, ... ]', 'file' [, ...], ['-arg'] )
1117
#       This subroutine takes the given list of files and adds them
1118
#       to the install header files list.  Files in this list will be
1119
#       installed into the 'local header directory' area for public
1120
#       consumption.  This is generally API files for other modules
1121
#       to use.
1122
#
1123
#       --Strip         Strip directory from source
1124
#       --Full          Install using full path
1125
#       --Subdir=subdir Install within the specified sub-directory
1126
#       --Prefix=subdir   "       "     "      "      "     "
1127
#
1128
#   InstallLib( 'platform [, ... ]', 'file', ['subdir'] )
1129
#       This subroutine takes the given list of files and adds them
1130
#       to the install libraries files list.  Files in this list will
1131
#       be installed into the 'local library directory' area for
1132
#       public consumption.
1133
#
1134
#   InstallProg( 'platform [, ... ]', 'file', ['subdir'] ) )
1135
#       This subroutine takes a list that defines the executable file
1136
#       that is to be installed.  The file in this list will be
1137
#       installed into the 'local executable directory' specified for
1138
#       public consumption.
1139
#
1140
###############################################################################
1141
 
1142
 
1143
sub Include                                     # User include
1144
{
1145
    my( $path, $name ) = @_;
1146
    my( $file );
1147
 
1148
    $file = Require( $path, $name, "Include" );
1149
    push( @ScmDepends, "$file" );
1150
}
1151
 
1152
sub ForceCCompile
1153
{
1154
    CompileOptions( $_[0], 'compile_as_c' );            # Backward compatability
1155
}
1156
 
1157
#-------------------------------------------------------------------------------
1158
#   Create a data structure to define the global compiler options
1159
#    The hash is keyed by compiler option
1160
#    The value contains another hash.
1161
#       The key is a makefile variable to set ( or remove )
1162
#       The value is the value to assign to the makefile variable
1163
#       If the value is 'undef' then the variable will be deleted
1164
#
1165
#   Keys of the form key=value are also supported
1166
#
1167
#   If the value is a CODE reference, then routine will be called with the key
1168
#   and value as arguments. The return value will be utilised.
1169
#
1170
our %ScmCompilerOptions =
1171
    (
1172
        'strict_ansi'           => { 'USE_STRICT_ANSI'    => '1' },
1173
        'no_strict_ansi'        => { 'USE_STRICT_ANSI'    => '' },      # Default
1174
 
1175
        'profile'               => { 'USE_PROFILE'        => '1' },
1176
        'no_profile'            => { 'USE_PROFILE'        => '' },       # Default
1177
 
1178
 
1179
        'prod_no_optimise'      => { 'PROD_USE_OPTIMISE'   => '' },
1180
        'prod_no_debuginfo'     => { 'PROD_USE_DEBUGINFO'  => '' },     # Default
1181
        'prod_optimise'         => { 'PROD_USE_OPTIMISE'   => '1' },    # Default
1182
        'prod_debuginfo'        => { 'PROD_USE_DEBUGINFO'  => '1' },
1183
 
1184
        'debug_no_optimise'     => { 'DEBUG_USE_OPTIMISE'  => '' },     # Default
1185
        'debug_no_debuginfo'    => { 'DEBUG_USE_DEBUGINFO' => '' },
1186
        'debug_optimise'        => { 'DEBUG_USE_OPTIMISE'  => '1' },
1187
        'debug_debuginfo'       => { 'DEBUG_USE_DEBUGINFO' => '1' },    # Default
1188
 
1189
        'compile_as_cpp'        => { 'FORCE_CC_COMPILE'    => '1',
1190
                                     'FORCE_C_COMPILE'     => undef },
1191
        'compile_as_c'          => { 'FORCE_C_COMPILE'     => '1',
1192
                                     'FORCE_CC_COMPILE'    => undef },
267 dpurdie 1193
 
1194
        'no_define_source_file' => { 'DISABLE__SOURCE__' => '1' },
1195
        'define_source_file'    => { 'DISABLE__SOURCE__' => undef },    # Default
1196
 
227 dpurdie 1197
    );
1198
 
1199
#
1200
#   The toolset can extend the options by setting the following hash
1201
#
1202
our %ScmToolsetCompilerOptions = ();
1203
 
1204
#
1205
#   Define default compiler options
1206
#   These are makefile variables that will be assigned
1207
#
1208
our %ScmCompilerOpts =
1209
    (
1210
        'USE_STRICT_ANSI'       => '',
1211
        'USE_PROFILE'           => '',
1212
        'PROD_USE_DEBUGINFO'    => '',
1213
        'PROD_USE_OPTIMISE'     => '1',
1214
        'DEBUG_USE_OPTIMISE'    => '',
1215
        'DEBUG_USE_DEBUGINFO'   => '1',
1216
    );
1217
 
1218
 
1219
sub CompileOptions
1220
{
1221
    my( $platforms, @elements ) = @_;
1222
    return if ( ! ActivePlatform($platforms) );
1223
 
1224
    for (@elements)
1225
    {
1226
        my $oref;
1227
 
1228
        #
1229
        #   The toolset option may be a text string or a definition
1230
        #       Name        - A text string
1231
        #       Name=Value  - A value
1232
        #
1233
        my $value;
1234
        my $key = $_;
1235
        if ( $key =~ m~(.*=)(.*)~ )
1236
        {
1237
            $key = $1;
1238
            $value = $2 || '';
1239
        }
247 dpurdie 1240
        $key = lc( $key );
227 dpurdie 1241
 
1242
        #
1243
        #   Examine the global flags
1244
        #   Then the toolset extensions
1245
        #   Then just drop it
1246
        #
1247
        unless ( $oref = ($ScmCompilerOptions{$key} || $ScmToolsetCompilerOptions{$key}) )
1248
        {
1249
            Warning ("Compile Option ignored: $_");
1250
            next;
1251
        }
1252
 
1253
        #
1254
        #   Parse the definition and adjust makefile variables as required
1255
        #   Set the value of a make variable or remove the definition
1256
        #
1257
        #   If the user value is a code reference, then call the code
1258
        #   and use the returned value as the value.
1259
        #
1260
        while ( (my($ukey, $uvalue)) = each %{$oref} )
1261
        {
1262
            if ( defined( $uvalue) )
1263
            {
1264
                if ( ref($uvalue) eq "CODE" )
1265
                {
255 dpurdie 1266
                    $uvalue = &$uvalue( $key, $value, $ukey);
227 dpurdie 1267
                    unless ( defined $uvalue )
1268
                    {
1269
                        Warning ("Compile Option ignored: $_");
1270
                        next;
1271
                    }
1272
                }
247 dpurdie 1273
                elsif ( defined $value )
1274
                {
1275
                    $uvalue = $value;
1276
                }
227 dpurdie 1277
 
1278
                $ScmCompilerOpts{$ukey} = $uvalue;
1279
            }
1280
            else
1281
            {
1282
                delete $ScmCompilerOpts{$ukey};
1283
            }
1284
        }
1285
    }
1286
}
1287
 
1288
#-------------------------------------------------------------------------------
1289
# Function        : AddFlags
1290
#                   AddCFlags
1291
#                   AddCXXFlags
1292
#                   AddASFlags
1293
#                   AddLDFlags
1294
#                   AddLintFlags
1295
#
1296
# Description     : Add target specfic flags to the C compiler
1297
#                   This SHOULD only be used to add Defines to the compiler
1298
#                   but it can be absued.
1299
#
1300
# Inputs          : $platform       - Platforms for which the directive is active
1301
#                   ...             - list of flags to add
1302
#
1303
#                   Embedded options include:
1304
#                       --Debug     - Following options are added to the debug build
1305
#                       --Prod      - Following options are added to the production build
1306
#
1307
# Returns         : Nothing
1308
#
1309
 
1310
sub AddFlags
1311
{
1312
    my( $platforms, @elements ) = @_;
1313
 
1314
    AddCFlags( $platforms, @elements );
1315
    AddCXXFlags( $platforms, @elements );
1316
}
1317
 
1318
sub AddCFlags
1319
{
1320
    my( $platforms, @elements ) = @_;
1321
 
1322
    Debug2( "AddCFlags($platforms, @elements)" );
1323
    return if ( ! ActivePlatform($platforms) );
1324
 
1325
    WarnIfNastyFlag( @elements );
1326
    __AddFlags( "CFLAGS", \@elements,
1327
                \@CFLAGS, \@CLINTFLAGS,
1328
                \@CFLAGS_DEBUG, \@CLINTFLAGS_DEBUG,
1329
                \@CFLAGS_PROD,  \@CLINTFLAGS_PROD );
1330
}
1331
 
1332
sub AddCXXFlags
1333
{
1334
    my( $platforms, @elements ) = @_;
1335
 
1336
    Debug2( "AddCXXFlags($platforms, @elements)" );
1337
    return if ( ! ActivePlatform($platforms) );
1338
 
1339
    WarnIfNastyFlag( @elements );
1340
    __AddFlags( "CXXFLAGS", \@elements,
1341
               \@CXXFLAGS, \@CXXLINTFLAGS,
1342
               \@CXXFLAGS_DEBUG, \@CXXLINTFLAGS_DEBUG,
1343
               \@CXXFLAGS_PROD,  \@CXXLINTFLAGS_PROD );
1344
}
1345
 
1346
sub AddASFlags
1347
{
1348
    my( $platforms, @elements ) = @_;
1349
 
1350
    Debug2( "AddASFlags($platforms, @elements)" );
1351
 
1352
    return if ( ! ActivePlatform($platforms) );
1353
 
267 dpurdie 1354
    __AddFlags( "ASFLAGS", \@elements,
1355
                \@ASFLAGS, undef,
1356
                \@ASFLAGS_DEBUG, undef,
1357
                \@ASFLAGS_PROD, undef );
227 dpurdie 1358
}
1359
 
1360
sub AddLDFlags
1361
{
1362
    my( $platforms, @elements ) = @_;
1363
 
1364
    Debug2( "AddLDFlags($platforms, @elements)" );
1365
 
1366
    return if ( ! ActivePlatform($platforms) );
1367
 
1368
    foreach  ( @elements )
1369
    {
267 dpurdie 1370
        next if ( m~^--(Debug|Prod)~ );
227 dpurdie 1371
        Warning("Use of linker flag discouraged (will be used): $_");
1372
    }
267 dpurdie 1373
    __AddFlags( "LDFLAGS", \@elements,
1374
                \@LDFLAGS, undef,
1375
                \@LDFLAGS_DEBUG, undef,
1376
                \@LDFLAGS_PROD, undef );
227 dpurdie 1377
 
1378
}
1379
 
1380
sub AddLintFlags
1381
{
1382
    my( $platforms, @elements ) = @_;
1383
 
1384
    return if ( ! ActivePlatform($platforms) );
1385
 
1386
    Debug2( "AddLintFlags($platforms, @elements)" );
1387
 
1388
    __AddFlags( "LINTFLAG", \@elements,
1389
                \@CLINTFLAGS, \@CXXLINTFLAGS,
1390
                \@CLINTFLAGS_DEBUG, \@CXXLINTFLAGS_DEBUG,
1391
                \@CLINTFLAGS_PROD, \@CXXLINTFLAGS_PROD  );
1392
}
1393
 
1394
 
1395
#-------------------------------------------------------------------------------
1396
# Function        : __AddFlags
1397
#
1398
# Description     : Generic flag adding to lists routine
1399
#                   Internal use only
1400
#
1401
#                   Supports --Debug and --Prod options
1402
#                   if the appropriate list is present.
1403
#
1404
# Inputs          : Lots
1405
#                   References to compiler and lint flags for
1406
#                   common, debug and product builds.
1407
#
1408
#                   Not all the lists are needed.
1409
#
1410
# Returns         : Nothing
1411
#
1412
sub __AddFlags
1413
{
1414
    my ($textname, $eref,
1415
                   $f_all,      $flint_all,
1416
                   $f_debug,    $flint_debug,
1417
                   $f_prod,     $flint_prod ) = @_;
1418
 
1419
    #
1420
    #   Start added flags to the ALL lists
1421
    #
1422
    my $list = $f_all;
1423
    my $lintlist = $flint_all;
1424
    my $nowarn = 0;
1425
 
1426
    #
1427
    #   Process flags up front
1428
    #
1429
    $nowarn = 1 if ( grep (/^--NoWarn$/, @$eref) );
1430
 
1431
    #
1432
    #   Process all the user arguments
1433
    #
1434
    ADD:
1435
    foreach my $element ( @$eref )
1436
    {
1437
        #
1438
        #   Skip flags
1439
        #
1440
        if ( $element eq '--NoWarn' )
1441
        {
1442
            next;
1443
        }
1444
 
1445
        #
1446
        #   Detect --Debug and --Prod options and swap
1447
        #   lists accordingly.
1448
        #
1449
        if ( $element eq '--Debug' )
1450
        {
1451
            Error ("--Debug not supported for $textname") unless ( $f_debug );
1452
            $list = $f_debug;
1453
            $lintlist = $flint_debug;
1454
            next;
1455
        }
1456
 
1457
        if ( $element eq '--Prod' )
1458
        {
1459
            Error ("--Prod not supported for $textname") unless ( $f_prod );
1460
            $list = $f_prod;
1461
            $lintlist = $flint_prod;
1462
            next;
1463
        }
1464
 
1465
        #
1466
        #   Scan all the lists for a possible duplicates
1467
        #
1468
        foreach my $temp ( @$f_all, @$f_debug, @$f_prod ) {
1469
            if ($temp eq $element) {
1470
                Warning( "Duplicate $textname ignored '$element'") unless $nowarn;
1471
                next ADD;
1472
            }
1473
        }
1474
 
1475
        #
1476
        #   Add the flag to the compiler and lint lists
1477
        #
1478
        push( @$list, $element ) if $list;
1479
        push( @$lintlist, $element ) if $lintlist;
1480
    }
1481
}
1482
 
1483
sub WarnIfNastyFlag
1484
{
1485
    foreach  ( @_ )
1486
    {
1487
        Warning("Use of compiler flags discouraged (will be used): $_")
1488
            unless ( m/^-[DU]/ || m/^--Debug/ || m/^--Prod/ || /^--NoWarn/ );
1489
    }
1490
}
1491
 
1492
 
1493
sub AddDir
1494
{
1495
    AddIncDir( @_);
1496
    AddSrcDir( @_ );
1497
}
1498
 
1499
 
1500
sub AddIncDir
1501
{
1502
    _AddDir( 'AddIncDir', 'INCDIR', \@INCDIRS, \@S_INCDIRS, \@G_INCDIRS, \@L_INCDIRS, @_ );
1503
}                                                           
1504
 
1505
sub AddSrcDir                                               
1506
{                                                           
1507
    _AddDir( 'AddSrcDir', 'SRCDIR', \@SRCDIRS, \@S_SRCDIRS, \@G_SRCDIRS, \@L_SRCDIRS, @_ );
1508
}                                                           
1509
 
1510
sub AddLibDir                                               
1511
{                                                           
1512
    _AddDir( 'AddLibDir', 'LIBDIR', \@LIBDIRS, \@S_LIBDIRS, \@G_LIBDIRS, \@L_LIBDIRS, @_ );
1513
}
1514
 
1515
#-------------------------------------------------------------------------------
1516
# Function        : _AddDir
1517
#
1518
# Description     : Internal routine to add a directory to list of directories
1519
#                   Common code to simplify implementation of other directives
1520
#
1521
# Inputs          : $name           - Name of function
1522
#                   $udir           - User name of dir list
1523
#                   $dirref         - Reference to directory array
1524
#                   $s_dirref       - Reference to system directory array
1525
#                   $g_dirref       - Reference to global directory array
1526
#                   $l_dirref       - Reference to local directory array
1527
#                   @args           - User arguments
1528
#                                       - platforms
1529
#                                       - Directories and --Options
1530
#
1531
sub _AddDir
1532
{
1533
    my( $name, $udir, $dirref, $s_dirref, $g_dirref, $l_dirref, $platforms, @elements ) = @_;
1534
 
1535
    Debug ( "$name($platforms, @elements)" );
1536
    Error ( "$name: Insufficient arguments") unless ( @elements );
1537
    return if ( ! ActivePlatform($platforms) );
1538
 
1539
    #
1540
    #   Cleanup user parameters
1541
    #
1542
    foreach ( @elements )
1543
    {
1544
        s/^\s+//;                               # Remove leading space
1545
        s/\s+$//;                               # Remove trailing spaces
1546
        s~/$~~;                                 # Remove trailing /
1547
        s~//~/~g;                               # Remove multiple /
1548
    }
1549
 
1550
#.. Collect arguments
1551
    my $tlist_ref = $ScmGlobal ? $g_dirref : $l_dirref; # "current" scope ....
1552
    my $nowarn = 0;
1553
    my $nodepend = 0;
1554
    my @dirs;
1555
 
1556
    foreach ( @elements )
1557
    {
1558
        if ( ! /^--/ ) {                        # Collect directories
1559
            push @dirs, $_;
1560
 
1561
        } elsif (/^--Local$/) {                 # "local" scope ....
1562
            $tlist_ref = $l_dirref;
1563
 
1564
        } elsif (/^--Global$/) {                # "global" scope ...
1565
            $tlist_ref = $g_dirref;
1566
 
1567
        } elsif (/^--System$/) {                # "system" scope ...
1568
            $tlist_ref = $s_dirref;
1569
 
1570
        } elsif (/^--NoDepend$/) {              # Split from dependency list
1571
            if ( $udir eq 'INCDIR' ) {          # AddIncDir only
1572
                $nodepend = 1;
1573
            }
1574
 
1575
        } elsif (/^--NoWarn$/) {                # Disable warnings
1576
            $nowarn = 1;
1577
 
1578
        } elsif (/^--(.*)/) {
1579
            Message( "$name: unknown option $_ -- ignored\n" );
1580
 
1581
        }
1582
    }
1583
 
1584
    Error ( "$name: No directory specified: ($platforms, @elements)" )
1585
        unless ( @dirs );
1586
 
1587
 
1588
#.. Push source path(s)
1589
    foreach ( @dirs )
1590
    {
1591
        #
1592
        #   Add to complete list of directories
1593
        #   Warn on duplicates
1594
        #
1595
        unless ( UniquePush( $dirref, $_) )
1596
        {
1597
            Warning( "Duplicate $udir ignored '$_'" )
1598
                unless ( $nowarn );
1599
            next;
1600
        }
1601
 
1602
        #
1603
        #   Check that the directory actually exists
1604
        #   If the path contains a $(XXXXX) then it can't be checked
1605
        #
1606
        if ( index( $_, '$' ) == -1 )
1607
        {
1608
            Warning( "$name. Directory not found: $_",
1609
                     "Current directory         : $::Cwd",
1610
                     "Cannot resolved Directory : " . AbsPath($_),
1611
                       )
1612
                unless ( $nowarn || -d $_ );
1613
        }
1614
 
1615
        #
1616
        #   Add to suitable list
1617
        #
1618
        push @{$tlist_ref}, $_;
1619
 
1620
        #
1621
        #   Add to the no dependancy list (ie generated depend file)
1622
        #   Only used by AddIncDir, accepted by AddSrcDir
1623
        #
1624
        push( @NODEPDIRS, $_ )
1625
            if ($nodepend);
1626
    }
1627
}
1628
 
1629
 
1630
sub AddProg
1631
{
1632
    my( $platforms, @progs ) = @_;
1633
    my( $prog, $temp );
1634
 
1635
    Debug2( "AddProg($platforms, @progs)" );
1636
 
1637
    return if ( ! ActivePlatform($platforms) );
1638
 
1639
    foreach $prog (@progs)
1640
    {
1641
        Warning( "Duplicate prog ignored '$prog'" )
1642
            unless ( UniquePush(\@PROGS, $prog) );
261 dpurdie 1643
        $PROGS{$prog} = 1;
227 dpurdie 1644
    }
1645
}
1646
 
1647
 
1648
sub AddSourceType
1649
{
1650
    my( $ext, $type ) = @_;
1651
 
1652
    Debug2( "AddSourceType(@_)" );
1653
 
1654
    #
1655
    #   Default Source Type (C)
1656
    #
1657
    $type = ".c" unless ( $type );
1658
 
1659
    Error ("Source type '$ext' not allowed")
1660
        if ( $ext !~ /^\.\w+$/ );
1661
 
1662
    $type = lc($type)
1663
        if ( $::ScmHost ne "Unix" );
1664
    $ScmSourceTypes{ $ext } = $type;
1665
}
1666
 
1667
 
1668
sub AddSourceFile
1669
{
1670
    my( $platforms, @elements ) = @_;
1671
    my( $path );
1672
 
1673
    Debug2( "AddSourceFile($platforms, @elements)" );
1674
    return if ( ! ActivePlatform($platforms) );
1675
 
1676
    foreach $path ( @elements )
1677
    {
1678
        __AddSourceFile( 1, $path );
1679
    }
1680
}
1681
 
1682
 
1683
#-------------------------------------------------------------------------------
1684
# Function        : __AddSourceFile
1685
#
1686
# Description     : Internal function
1687
#                   Add a source file to internal lists
1688
#
1689
#                   Assumes that the current platform is ACTIVE
1690
#
1691
# Inputs          : push    0: Don't push onto OBJS (non-shared objfiles)
1692
#                   path    Filename.extension
1693
#                   obj     object file name (optional)
1694
#                   type    Type of file. "" -> auto detect
1695
#
1696
# Returns         : True        - File is a 'known' source file
1697
#                   False       - File is not a 'known' source file
1698
#
1699
sub __AddSourceFile
1700
{
1701
    my( $push, $path, $obj, $type ) = @_;
271 dpurdie 1702
    my( $filename, $ext, $srcfile, $is_obj, $ext_type, $result );
227 dpurdie 1703
 
271 dpurdie 1704
    $filename = StripDir($path);                # file name
227 dpurdie 1705
 
1706
    $ext  = StripFile($path);                   # extension
1707
    $ext = lc($ext)
1708
        if ( $::ScmHost ne "Unix" );
1709
 
271 dpurdie 1710
    if (! ($srcfile = $SRCS{$filename})) {
227 dpurdie 1711
        $srcfile = $path;                       # generated
1712
    }
1713
 
271 dpurdie 1714
    $obj  = StripExt( $filename )               # Base name of object file
227 dpurdie 1715
        if ( ! defined($obj) || $obj eq "" );
1716
 
1717
    $type = ""                                  # optional type
1718
        if ( ! defined( $type ) );
1719
 
1720
    #
1721
    #   Push file onto a suitable source file list
1722
    #
1723
    $result = 0;
1724
    $ext_type = "";                             # map extension
1725
    $ext_type = $ScmSourceTypes{ $ext }
1726
        if ( exists( $ScmSourceTypes{ $ext } ) );
1727
    $result = 1 if ( $ext_type );
1728
 
1729
    if ( $type eq "" && defined $::ScmToolsetProgSource{$ext} )
1730
    {
1731
        Debug( "SourceFile: $path is ToolsetProgSource   -> $srcfile" );
1732
        push( @CSRCS, $srcfile );
1733
        $result = 1;
1734
    }
1735
    elsif ( ($type eq "" && $ext_type eq ".h") || ($type eq ".h") )
1736
    {
1737
        Debug( "SourceFile: $path is .h   -> $srcfile" );
1738
        push( @CHDRS, $srcfile );
1739
    }
1740
    elsif ( ($type eq "" && $ext_type eq ".inc") || ($type eq ".inc") )
1741
    {
1742
        Debug( "SourceFile: $path is .inc -> $srcfile" );
1743
        push( @ASHDRS, $srcfile );
1744
    }
1745
    elsif ( ($type eq "" && $ext_type eq ".c") || ($type eq ".c") )
1746
    {
1747
        Debug( "SourceFile: $path is .c   -> $srcfile=$obj" );
1748
        push( @CSRCS, $srcfile );
1749
        $is_obj = 1;
1750
    }
1751
    elsif ( ($type eq "" && $ext_type eq ".cc") || ($type eq ".cc") )
1752
    {
1753
        Debug( "SourceFile: $path is .cc  -> $srcfile=$obj" );
1754
        push( @CXXSRCS, $srcfile );
1755
        $is_obj = 1;
1756
    }
1757
    elsif ( ($type eq "" && $ext_type eq ".asm") || ($type eq ".asm") )
1758
    {
1759
        Debug( "SourceFile: $path is .asm -> $srcfile=$obj" );
1760
        push( @ASSRCS, $srcfile );
1761
        $is_obj = 1;
1762
    }
1763
    elsif ( $ext_type eq "--Ignore" )
1764
    {   # ignored ...
1765
        #   .x      "rpcgen" source files
1766
        #   .ini    Configuration
1767
        #   .sh     Shell script
1768
    }
1769
    else
1770
    {
1771
        Debug( "SourceFile: $path is unknown file type" );
1772
 
1773
        #
1774
        #   Insert source files with unknown extensions onto lists
1775
        #   of there own type
1776
        #
1777
        if ( $ext )
1778
        {
1779
            (my $varname = uc ( $ext . 'SRCS')) =~ s~\.~~g;
1780
            no strict 'refs';
1781
            push @$varname, $srcfile;
1782
            use strict 'refs';
1783
        }
1784
    }
1785
 
1786
    #
271 dpurdie 1787
    #   See if there is a hook function for this type of source file
1788
    #   Invoke user function to perform additional processing on the file
1789
    #
1790
    if ( %MF_RegisterSrcHooks )
1791
    {
1792
        my @listeners;
1793
        push @listeners, @{$MF_RegisterSrcHooks{$ext}} if ( exists $MF_RegisterSrcHooks{$ext} );
1794
        push @listeners, @{$MF_RegisterSrcHooks{'*'}}  if ( exists $MF_RegisterSrcHooks{'*'} );
1795
        while ( @listeners )
1796
        {
1797
            Debug( "RegisterSrcHook: Invoke SrcHook function" );
1798
            my ($fname, @args) = @{shift @listeners};
1799
            &$fname ( $srcfile ,$filename, $obj, $ext ,@args );
1800
        }
1801
    }
1802
 
1803
    #
227 dpurdie 1804
    #   Object files are saved in
1805
    #       OBJSOURCE   - Generate a recipe to create the object
1806
    #       OBJS        - A list of ALL non-shared object files
1807
    #
1808
    if ( $is_obj && $::o )
1809
    {
1810
        $OBJSOURCE{ "$obj" } = $srcfile;
1811
        push( @OBJS, $obj )
1812
            if ($push);
1813
    }
1814
 
1815
    #
1816
    #   Indicate to the user that the file is a 'known' source file
1817
    #   This implies that the file is required early in the build process
1818
    #   and may need to be generated early.
1819
    #
1820
    return $result;
1821
}
1822
 
1823
#-------------------------------------------------------------------------------
1824
# Function        : SetValue
1825
#
1826
# Description     : Defines a variable that can be used within the makefile.pl
1827
#                   Use sparingly
1828
#                   An attempt to formalise a mechanism that is used anyway, but
1829
#                   with correct platform detection
1830
#
1831
# Inputs          : $platform       - Platform selector
1832
#                   $name           - Name to set
1833
#                   $value          - Value to set
1834
#                   options         - Options
1835
#                                       --NoWarn
1836
#                                       --Project=xxxx[,xxxx]+
1837
#                                       --
1838
#
1839
sub SetValue
1840
{
1841
    my( $platforms, @elements ) = @_;
1842
    my $name;
1843
    my $value;
1844
    my $nowarn;
1845
    my $nomoreswicthes = 0;
1846
 
1847
    Debug2( "SetValue($platforms, @elements)" );
1848
 
1849
    return if ( ! ActivePlatform($platforms) );
1850
 
1851
    #
1852
    #   Process elements extracting values and options
1853
    #
1854
    foreach ( @elements )
1855
    {
1856
        if ( m/^--$/ ) {
1857
            $nomoreswicthes = ! $nomoreswicthes;
1858
            next;
1859
        }
1860
 
1861
        if ( m/^--/ && ! $nomoreswicthes )
1862
        {
1863
 
1864
            if ( m/^--NoWarn/ ) {
1865
                $nowarn = 1;
1866
 
1867
            } elsif ( m/^--Project=(.*)/ ) {
1868
                return unless ( ActiveProject( $1) );
1869
 
1870
            } else {
1871
                Error ("SetValue: Unknown option: $_");
1872
 
1873
            }
1874
 
1875
        } elsif ( ! defined $name ) {
1876
            $name = $_;
1877
 
1878
        } elsif ( ! defined $value ) {
1879
            $value = $_;
1880
 
1881
        } else {
1882
            Error ("SetValue: $name. Too many parameters" );
1883
 
1884
        }
1885
    }
1886
 
1887
    #
1888
    #   Warn if the named variable already exists
1889
    #   It may be a JATS internal or it may be a user.
1890
    #
1891
    unless ( $nowarn )
1892
    {
1893
        no strict 'refs';
1894
        Warning("SetValue: $name. Redefined") if defined ( $$name );
1895
        use strict 'refs';
1896
    }
1897
 
1898
    #
1899
    #   Set the value
1900
    #
1901
    no strict 'refs';
1902
    $$name = $value;
1903
    use strict 'refs';
1904
}
1905
 
1906
#-------------------------------------------------------------------------------
1907
# Function        : SetList
1908
#
1909
# Description     : Defines a list variable that can be used within the makefile.pl
1910
#                   Use sparingly
1911
#                   An attempt to formalise a mechanism that is used anyway, but
1912
#                   with correct platform detection
1913
#
1914
# Inputs          : $platform       - Platform selector
1915
#                   $name           - Name to set
1916
#                   $value,...      - Values to set
1917
#                   options         - Options
1918
#                                       --NoWarn
1919
#                                       --Project=xxxx[,xxxx]+
1920
#                                       --Unique
1921
#                                       --Clear
1922
#                                       --Append
1923
#                                       --
1924
#
1925
my %SetList_names;
1926
sub SetList
1927
{
1928
    my( $platforms, @elements ) = @_;
1929
    my $name;
1930
    my @value;
1931
    my $nowarn;
1932
    my $unique;
1933
    my $clear;
1934
    my $nomoreswicthes = 0;
1935
 
1936
    Debug2( "SetList($platforms, @elements)" );
1937
 
1938
    return if ( ! ActivePlatform($platforms) );
1939
 
1940
    #
1941
    #   Process elements extracting values and options
1942
    #
1943
    foreach ( @elements )
1944
    {
1945
        if ( m/^--$/ ) {
1946
            $nomoreswicthes = ! $nomoreswicthes;
1947
            next;
1948
        }
1949
 
1950
        if ( m/^--/ && ! $nomoreswicthes )
1951
        {
1952
            if ( m/^--NoWarn/ ) {
1953
                $nowarn = 1;
1954
 
1955
            } elsif ( m/^--Project=(.*)/ ) {
1956
                return unless ( ActiveProject( $1) );
1957
 
1958
            } elsif ( m/^--Unique/ ) {
1959
                $unique = 1;
1960
 
1961
            } elsif ( m/^--Clear/ ) {
1962
                $clear = 1;
1963
 
1964
            } elsif ( m/^--Append/ ) {
1965
                $clear = 0;
1966
 
1967
            } else {
1968
                Error ("SetList: Unknown option: $_");
1969
            }
1970
        } elsif ( ! defined $name ) {
1971
            $name = $_;
1972
 
1973
        } else {
1974
            push @value, $_;
1975
 
1976
        }
1977
    }
1978
 
1979
    Error ("SetList: No name specified") unless ( $name );
1980
 
1981
    #
1982
    #   Warn if the named variable already exists
1983
    #   It may be a JATS internal or it may be a user.
1984
    #
1985
    #   Only do this iff the name is not known to this function
1986
    #   Keep a list a names that have been set.
1987
    #
1988
    if ( ! $SetList_names{$name} && ! $nowarn )
1989
    {
1990
        no strict 'refs';
1991
        Warning("SetList: $name. Defined outside the ScanList/SetList directive","May clash with Jats internals") if defined ( @$name );
1992
        use strict 'refs';
1993
    }
1994
    $SetList_names{$name} = 1;
1995
 
1996
    #
1997
    #   Clear list
1998
    #
1999
    if ( $clear )
2000
    {
2001
        no strict 'refs';
2002
        @$name = ();
2003
        use strict 'refs';
2004
    }
2005
 
2006
    #
2007
    #   Set the value
2008
    #
2009
    no strict 'refs';
2010
    if ( $unique ) {
2011
        UniquePush( \@$name, @value);
2012
    } else {
2013
        push @$name, @value;
2014
    }
2015
    use strict 'refs';
2016
}
2017
 
2018
#-------------------------------------------------------------------------------
2019
# Function        : ScanList
2020
#
2021
# Description     : Create a list by scanning for files in a directory
2022
#                   The files may be in a local directory or within a package
2023
#                   Care must be taken when using a package as the results
2024
#                   may differ bewteen BuildPkgArchive and LinkPkgArchive
2025
#
2026
#                   Interworks with SetList
2027
#
2028
# Inputs          : $platform       - Platform selector
2029
#                   $name           - Name to set
2030
#                   $value,...      - Values to set
2031
#                   options         - Options
2032
#                                       --NoWarn
2033
#                                       --Project=xxxx[,xxxx]+
2034
#                                       --Unique
2035
#                                       --Clear
2036
#                                       --Append
2037
#
2038
#                                       --Package=xxxx[,ext]
2039
#                                       --Dir=xxx
2040
#
2041
#                                       --Subdir=yyy
2042
#                                       --DirListOnly
2043
#                                       --FileListOnly
2044
#                                       --Recurse
2045
#                                       --NoRecurse
2046
#
2047
#                                       --FilterIn=xxx
2048
#                                       --FilterInRe=xxx
2049
#                                       --FilterOut=xxx
2050
#                                       --FilterOutRe=xxx
2051
#
2052
# Returns         :
2053
#
2054
sub ScanList
2055
{
2056
    my( $platforms, @elements ) = @_;
2057
    my $name;
2058
    my $package;
2059
    my $dir;
2060
    my $subdir;
2061
    my @set_args;
2062
    my $search = JatsLocateFiles->new('Recurse','FullPath' );
2063
 
2064
    Debug2( "ScanList($platforms, @elements)" );
2065
 
2066
    return if ( ! ActivePlatform($platforms) );
2067
 
2068
    #
2069
    #   Process elements extracting values and options
2070
    #
2071
    foreach ( @elements )
2072
    {
2073
        if ( m/^--Unique|--Clear|--Append|--NoWarn/ ) {
2074
            push @set_args, $_;
2075
 
2076
        } elsif ( m/^--Project=(.*)/ ) {
2077
            return unless ( ActiveProject( $1) );
2078
 
2079
        } elsif ( m/^--Package=(.*)/ ) {
2080
            $package = $1;
2081
 
2082
        } elsif ( m/^--Dir=(.*)/ ) {
2083
            $dir = $1;
2084
 
2085
        } elsif ( m/^--Subdir=(.*)/ ) {
2086
            $subdir = $1;
2087
 
2088
        } elsif ( $search->option( $_ ) ) {
2089
            Verbose ("Search Option: $_" );
2090
 
2091
        } elsif ( m/^--/ ) {
2092
            Error ("ScanList: Unknown option: $_");
2093
 
2094
        } elsif ( ! defined $name ) {
2095
            $name = $_;
2096
 
2097
        } else {
2098
                Error ("ScanList $name: Unknown option: $_");
2099
 
2100
        }
2101
    }
2102
 
2103
    Error ("ScanList: No variable name specified") unless ( $name );
2104
    Error ("ScanList: Must Specify --Dir or --Package") unless ( $dir || $package );
2105
    Error ("ScanList: --Dir and --Package are mutually exclusive") if ( $dir && $package );
2106
 
2107
    #
2108
    #   Locate the base of the scan
2109
    #   This may be either a package name or a local directory
2110
    #
2111
    #   Its no use allowing the user to use OBJ/LIB/BIN directories as the
2112
    #   directories MUST exist at build time. Don't really want the user doing
2113
    #   that level of poking out of a package
2114
    #
2115
    if ( $package )
2116
    {
2117
        $dir = GetPackageBase( "ScanList", $package );
2118
        Error ("ScanList: Package not found: $package") unless ( $dir );
2119
    }
2120
    else
2121
    {
2122
        Error ("ScanList: Root directory not found: $dir") unless ( -d $dir );
2123
    }
2124
    if ( $subdir )
2125
    {
2126
        $dir .= "/" . $subdir;
2127
        Error ("ScanList: Sub directory not found: $subdir") unless ( -d $dir );
2128
    }
2129
 
2130
    #
2131
    #   Use SetList to do the rest of the work
2132
    #
2133
    SetList( $platforms, $name, @set_args, '--', $search->search($dir) );
2134
}
2135
 
2136
 
2137
sub Init
2138
{
2139
    push( @INITS, @_ );
2140
}
2141
 
2142
#-------------------------------------------------------------------------------
2143
# Function        : Generate
2144
#
2145
# Description     : Legacy Function - don't use unless you have too.
2146
#                   Flags files that are to be generated during the
2147
#                   early 'generate' make phase. Will also add named files
2148
#                   to various internal lists
2149
#
2150
#                   Intended to be used in conjunction with the 'Rule' directive
2151
#                   to flag header and source files that need to be created early
2152
#                   in the build process.
2153
#
2154
# Inputs          : See GenerateSrcFile
2155
#
2156
# Returns         : 
2157
#
2158
sub Generate
2159
{
2160
    my( $platforms, @elements ) = @_;
2161
 
2162
    Debug2( "Generate($platforms, @elements)" );
2163
 
2164
    return if ( ! ActivePlatform($platforms) );
2165
    Message("Generate directive used. Consider replacing with GenerateFiles");
2166
 
2167
    #
2168
    #   Use Non-warning version to do the hard work
2169
    #
2170
    GenerateSrcFile( 1, @elements );
2171
}
2172
 
2173
#-------------------------------------------------------------------------------
2174
# Function        : Generated
2175
#
2176
# Description     : Legacy Function - don't use unless you have too.
2177
#                   Flags files that are generated by misc Rules
2178
#
2179
#                   Intended to be used in conjunction with the 'Rule' directive
2180
#                   to mark files that have been generated, so that they can be
2181
#                   cleaned up.
2182
#
2183
#                   Note the difference to the 'Generate' directive which will
2184
#                   ensure that the Rule will be run in the 'generate' phase,
2185
#                   this directive doesn't.
2186
#
2187
# Inputs          : Files with internal Makefile Paths and codes
2188
#                   Eg: Generated( '*', "\$(LIBDIR)/libcsf\$(GBE_TYPE).\${a}" );
2189
#                   See why its YUK!
2190
#
2191
# Returns         : 
2192
#
2193
sub Generated
2194
{
2195
    my( $platforms, @elements ) = @_;
2196
    my( @args );
2197
 
2198
    return if ( ! ActivePlatform($platforms) );
2199
    Debug2( "Generated($platforms, @elements)" );
2200
 
2201
    #.. Collect arguments
2202
    #
2203
    foreach ( @elements )
2204
    {
2205
        if ( /^-(.*)/ )
2206
        {
2207
            Debug( "Gen: arg $_" );
2208
            push ( @args, $_);
2209
        }
2210
    }
2211
 
2212
    #.. Push source file(s)
2213
    #
2214
    foreach ( @elements )
2215
    {
2216
        if ( ! /^-(.*)/ )
2217
        {
2218
            Debug( "Generated: $_ (@args)" );
2219
            push (@USERGENERATED, $_);
2220
 
2221
            #
2222
            #   Add the file to the list of known source files
2223
            #   This will allow them to be packaged
2224
            #
2225
            GenerateSrcFile (0, $_ );
2226
        }
2227
    }
2228
}
2229
 
2230
 
2231
#-------------------------------------------------------------------------------
2232
# Function        : GenerateSrcFile
2233
#
2234
# Description     : Internal Function (No $platform)
2235
#                   Determine how to handle a 'Generated' file
2236
#
2237
#
2238
# Inputs          : $generated          - 0: Don't add to GENERATED List
2239
#                                         1: Add to GENERATED List
2240
#                                         2: Add to GENERATED List, if a source file
2241
#                   FileName(s)         - Name of one or more files to process
2242
#                                         All files are processed in the same way
2243
#                                         These file may contain Makefile prefixes
2244
#                                         ie: $(OBJDIR)/file.obj
2245
#                   Options:
2246
#                       --c             - Hint: Its a "C" file
2247
#                       --cpp           - Hint: Its a C++ file
2248
#                       --asm           - Hint: Its an ASM file
2249
#                       -*              - Save as argument attached to the file
2250
#
2251
# Returns         : 
2252
#
2253
sub GenerateSrcFile                             # Internal Function - no $platform
2254
{
2255
    my( $generated, @elements ) = @_;
2256
    my( $type, @args );
2257
 
2258
    Debug2( "GenerateSrcFile($generated,@elements)" );
2259
 
2260
    #.. Collect arguments
2261
    #
2262
    $type = "";
2263
    foreach ( @elements )
2264
    {
2265
        if ( /^--c$/ ) {
2266
            Debug( "Gen: --c" );
2267
            $type = ".c";
2268
 
2269
        } elsif ( /^--cpp$/ ) {
2270
            Debug( "Gen: --cpp" );
2271
            $type = ".cc";
2272
 
2273
        } elsif ( /^--asm$/ ) {
2274
            Debug( "Gen: --asm" );
2275
            $type = ".asm";
2276
 
2277
        } elsif ( /^-(.*)/ ) {
2278
            Debug( "Src: arg $_" );
2279
            push @args, $_;
2280
        }
2281
    }
2282
 
2283
    #.. Process source file(s)
2284
    #
2285
    #   Determine if file is already a known SRCS file - skip if already known
2286
    #   Update SRCS data
2287
    #   Update SRC_TYPE data
2288
    #   Update SRC_ARGS data
2289
    #   Add the file to a suitable source file list ie: @CHDRS,...
2290
    #   Flag as a GENERATED file - These will be processed during the 'generate' phase
2291
    #
2292
    foreach my $source ( @elements )
2293
    {
2294
        next if ( $source =~ /^-(.*)/ );                # Not a source file
2295
 
2296
        my $basename = StripDir( $source );
2297
        Debug( "Generate: $source=$basename (@args)" );
2298
 
2299
        if ($SRCS{ $basename }) {
2300
            Warning( "Duplicate src ignored '$source'" );
2301
            next;
2302
        }
2303
        $SRCS{ $basename } = $source;
2304
 
2305
        HashJoin( \%SRC_ARGS, $;, $basename, @args )
2306
            if (@args);
2307
 
2308
        $SRC_TYPE{ $basename } = $type
2309
            if ($type);
2310
 
2311
        #
2312
        #   Add the file to any source file lists that it may like to know
2313
        #   about this file.
2314
        #
2315
        #   If the file was a known source file, then it may need to be generated
2316
        #   very early in the build process.
2317
        #
2318
        my $src_file_type = __AddSourceFile( 1, $basename );
2319
        if ($generated eq 1 || $src_file_type && $generated > 1)
2320
        {
2321
            push(@GENERATED, $source);
2322
        }
2323
        else
2324
        {
2325
            push(@GENERATED_NOTSRC, $source);
2326
        }
2327
    }
2328
}
2329
 
2330
#-------------------------------------------------------------------------------
2331
# Function        : GenerateFiles
2332
#
2333
# Description     : Generate files in a controlled manner using a specified
2334
#                   tool to perform the task
2335
#
2336
# Inputs          : $1      - platform specifier '*' (comma delemitered)
2337
#                   $2      - Tool Name
2338
#                   $3...   - Command line argument to generate files with embedded information
2339
#                           - or options. Multiple command line arguments will be joind with
2340
#                             a single space
2341
#
2342
#                   The generated files will be placed in the OBJ directory for
2343
#                   the current target platform. This allows different files to
2344
#                   be generated for each platform, without collision.
2345
#
2346
#                   The full name of the generated files will be added to the list of
2347
#                   source files. Thus the user does not need to know the
2348
#                   full name of the file - it will be tracked by JATS.
2349
#
2350
#                   If a generated file is a header file, then the OBJ directory
2351
#                   will be added as AddIncDir() so that the header files can be
2352
#                   extracted
2353
#
2354
#                   If a generated file is a "C"/"C++" source file, then it will
2355
#                   compiled and the object file made available
2356
#
2357
#                   The tool name may be:
2358
#                       --Tool=name  or "name"
2359
#                               Look in the tool paths in Packages
2360
#                               Look in the JATS tool directory for named script
2361
#                               Look in the JATS bin directory for the named exe
2362
#                               Look in the users path ( and generate a warning )
2363
#                               Give up and hope magic happens later
2364
#                       --Script=name
2365
#                               Resolve the name using known Src paths
2366
#                               The script may be generated and need not exist
2367
#                               at the time the makefile is created.
2368
#                       --Shell
2369
#                               The command line argument is a shell script that
2370
#                               will be passed to a simple shell.
263 dpurdie 2371
#                       --Prog=name
2372
#                               Resolve to a program generated within this makefile
227 dpurdie 2373
#
2374
#
2375
#                   The command line argument contains keywords to allow
2376
#                   information to be extracted from the line. Keywords are:
2377
#
2378
#                       --Generated(xxx)        - xxx is a generated file
2379
#                                                 It will be placed in the OBJDIR
2380
#                       --GeneratedCommon(xxx)  - xxx is a generated file
2381
#                                                 File will be placed in the local directory
2382
#                                                 and will be shared by by all platforms
2383
#                       --GeneratedObject(xxx)  - xxx is a generated object file
2384
#                                                 It will be placed in the OBJDIR and will
2385
#                                                 have a suitable object suffix appended
2386
#                       --GeneratedProg(xxx)    - xxx is a generated program file
2387
#                                                 It will be placed in the BINDIR
2388
#                       --Prerequisite(xxx)     - xxx is a prerequisite file
2389
#                                                 The full name of the file will be located
2390
#                                                 and used within the command. The file will
2391
#                                                 be added to the list of recipe prerequisites
2392
#                       --GeneratedDirectory(xxx)
2393
#                       --GeneratedCommonDirectory(xxx)
2394
#                       --GeneratedObjectDirectory(xxx)
2395
#                       --GeneratedProgDirectory(xxx)
2396
#                                               - xxx is a generated file, but is not placed
2397
#                                                 on the command line. It is flagged as
2398
#                                                 a generated files
2399
#                       --PackageBase(xxx)      - xxx is a package. The keyword will be replaced
2400
#                                                 with the pathname to the package. If the package
2401
#                                                 has been copied in the the interface directory
2402
#                                                 then the interface directory will be used.
2403
#                       --PackageInfo(xxx,--opt)- xxx is a package. The keyword will be replaced
2404
#                                                 with the information requested.
2405
#                                                 Options are:
2406
#                                                   --path
2407
#                                                   --version
2408
#                                                   --fullversion
2409
#                                                   --project
2410
#
2411
#                       Where "xxx" may be of the form:
2412
#                           name,option[,option]
2413
#
2414
#                       Flag options are:
2415
#                           --file             - The file part of the full name
2416
#                           --dir              - The directory part of the full name
2417
#                           --abspath          - Abs path
2418
#                           --absdrive         - Abs path with drive letter
2419
#
2420
#                       --Var(Name,opt)         - Name is the name of a recognised varable
2421
#                                                 Refer to ExpandGenVar function for details
2422
#                                                 of Name and available options
2423
#                                                 The expanded text will be replaced with an
2424
#                                                 suitable makefile variables that will be
2425
#                                                 replaced at run-time.
2426
#
2427
#                   The keyword will be replaced with the resolved name. This may be a file,
2428
#                   a directory or other text.
2429
#
2430
#                   Options do not alter command line text. They do affect the way the command is
2431
#                   processed.
2432
#                   Options include:
2433
#                       --Prereq=name           - The name of a file to add as a prerequisite
2434
#                                                 The file does not form part of the command line
2435
#                       --Created=name          - The name of a file to treat as a generated file
2436
#                       --CreatedCommon=name      The file does not form part of the command line 
2437
#                       --CreatedObject=name
2438
#                       --CreatedProg=name
2439
#
2440
#                       --NoVarTag              - Modifes --Var operation to suppress tags
2441
#                       --NoWarn                - Don't warn if no prerequistes found
2442
#                       --NoGenerate            - Don't warn if no generated files are found
2443
#                                                 Will create a dummy rule name and the recipe will
2444
#                                                 always be executed during the 'GenerateFiles' phase
2445
#                       --UnknownPreq           - Prerequisites are not fully known.
2446
#                                                 Rebuild the target whenever it is required.
2447
#                       --AutoGenerate          - Examine the generated file to determine when the
2448
#                                                 tools is to be run.
261 dpurdie 2449
#                                                 Must be before any options that declare
2450
#                                                 creation of files.
227 dpurdie 2451
#                       --Text=<text>           - Display text for command
2452
#
263 dpurdie 2453
#                       --Clean[=arg]           - Call script with arg[-clean] for cleaning.
2454
#                       --PreDelete             - Delete generated files before running the command
227 dpurdie 2455
#
2456
#               Eg: GenerateFiles ( '*', "--Tool=mod_if.pl",
2457
#                                        "-src --Prerequisite(udh_module.cfg)",
2458
#                                        "-direct -hdr --Generated(udp.h) -quiet" );
2459
#
2460
my $NoGenIndex = 0;
2461
sub GenerateFiles
2462
{
2463
    my ( $platforms, $tool, @args) = @_;
2464
 
2465
    return if ( ! ActivePlatform($platforms) );
2466
 
2467
    Debug2( "GenerateFiles:($platforms, $tool, @args)" );
2468
 
2469
    my @preq_files;
2470
    my $preq_unknown;
2471
    my @gen_files;
2472
    my $shell_script;
2473
    my $shell_cmds;
2474
    my @tool_args;
2475
    my $no_warn;
2476
    my $clean_tag;
2477
    my $text;
2478
    my $gtype = 1;
2479
    my @var_opts;
261 dpurdie 2480
    my @genreq_seen;
263 dpurdie 2481
    my $predelete;
227 dpurdie 2482
 
2483
    #
2484
    #   Process the first argument - this describes the program that will be used
2485
    #   to generate the files. It may be:
2486
    #       --Tool          - A Jats Tool or Plugin
2487
    #       --Script        - A shell script file
2488
    #       --Shell         - Raw shell commands
2489
    #       --Prog          - A program created within the Makefile
2490
    #
2491
    #
2492
    if ( $tool =~ /^--Tool=(.*)/ || $tool =~ /^([^-].*)/)
2493
    {
2494
        $tool = $1;
2495
        my $tool_no_prereq = 0;
2496
 
2497
        #
2498
        #   Process the Tool name and determine the location of the tool
2499
        #   Support --Tool=name and "name"
2500
        #   Locate the tool one of the many well known locations
2501
        #       1) Tool paths from Package Archives
2502
        #       2) JATS tool and binaries
2503
        #       3) User PATH (!YUK)
2504
        #
2505
 
2506
        #
2507
        #   Create a list of known extensions to scan
2508
        #   Basically present so that we can use .exe files without the .exe name
2509
        #
2510
        my @extension_list;
2511
        push @extension_list, '.exe' if ( $::ScmHost ne "Unix" );
2512
        push @extension_list, '.pl', '.sh', '.ksh', '';
2513
 
2514
        TOOL_SEARCH:
2515
        {
2516
            #
2517
            #   Locate tool with package
2518
            #
2519
            if ( my $fname = ToolExtensionProgram( $tool, @extension_list ))
2520
            {
2521
                $tool = $fname;
2522
                last TOOL_SEARCH;
2523
            }
2524
 
2525
            #
2526
            #   Search the JATS tools and Bin directory
2527
            #   Retain the symbolic name of the JATS directory
2528
            #
2529
            for my $ext ( @extension_list )
2530
            {
2531
                foreach my $jdir ( qw( / /DEPLOY/ /LOCAL/ ) )
2532
                {
2533
                    if ( -f "$::GBE_TOOLS$jdir$tool$ext" )
2534
                    {
2535
                        $tool = "\$(GBE_TOOLS)$jdir$tool$ext";
2536
                        last TOOL_SEARCH;
2537
                    }
2538
                }
2539
 
2540
                if ( -f "$::GBE_BIN/$tool$ext" )
2541
                {
2542
                    $tool = "\$(GBE_BIN)/$tool$ext";
2543
                    last TOOL_SEARCH;
2544
                }
2545
            }
2546
 
2547
            #
2548
            #   Has the user provided an absolute PATH
2549
            #   This is not good, but for testing we can use it
2550
            #
2551
            if ( $tool =~ m~^/~ || $tool =~ m~^.:~ )
2552
            {
2553
                Warning("Absolute path program specified. Uncontrolled tool: $tool");
2554
                for my $ext ( @extension_list )
2555
                {
2556
                    if ( -f "$tool$ext" )
2557
                    {
2558
                        $tool = "$tool$ext";
2559
                        last TOOL_SEARCH;
2560
                    }
2561
                }
2562
            }
2563
 
2564
            #
2565
            #   May have a relative path to a local tool
2566
            #
2567
            if ( -f $tool )
2568
            {
2569
                UniquePush (\@preq_files, $tool);
2570
                last TOOL_SEARCH;
2571
            }
2572
 
2573
            #
2574
            #   Search the users PATH
2575
            #   Generate a warning if the program is found. These programs are
2576
            #   not nice as they are not really controlled.
2577
            #
2578
            for my $dir (split( $::ScmPathSep, $ENV{'PATH'} ) )
2579
            {
2580
                for my $ext ( @extension_list )
2581
                {
2582
                    if ( -f "$dir/$tool$ext" )
2583
                    {
2584
                        Warning("External program found in the user's PATH. Uncontrolled tool: $tool");
2585
                        $tool = "$dir/$tool$ext";
2586
 
2587
                        #
2588
                        #   Do not make the program a pre-requisite if we are running
2589
                        #   under Windows. This avoids two problems:
2590
                        #       1) May have spaces in pathname
2591
                        #       2) May have driver letter in pathname
2592
                        #
2593
                        $tool_no_prereq = 1 if ( $::ScmHost eq "WIN" );
2594
                        last TOOL_SEARCH;
2595
                    }
2596
                }
2597
            }
2598
 
2599
            #
2600
            #   Specified progrom not found
2601
            #   Generate a warning and use the raw name
2602
            #
2603
            Warning("Tool not found: $tool");
2604
            $tool_no_prereq = 1;
2605
        }
2606
        UniquePush (\@preq_files, $tool) unless ($tool_no_prereq);
2607
 
2608
    } elsif ( $tool =~ /^--Script=(.*)/ ) {
2609
 
2610
        #
2611
        #   Locate the script in a known source directory and make
2612
        #   the script a prerequisite of the target files, since the
2613
        #   script may be generated.
2614
        #
2615
        $tool = MakeSrcResolve ( $1 );
2616
        UniquePush (\@preq_files, $tool);
2617
 
2618
    } elsif ( $tool =~ /^--Shell$/ ) {
2619
        #
2620
        #   The user has provided a shell script within the command body
2621
        #   This will be executed directly by a shell
2622
        #   directores will need to use a "/" separator
2623
        #
2624
        $tool = "InternalShell";
2625
        $shell_script = 1;
2626
        $shell_cmds = 1;
2627
 
2628
 
2629
    } elsif ( $tool =~ /^--Prog=(.*)$/ ) {
2630
        #
2631
        #   Using a program that has been created within this script
2632
        #
2633
        my $prog = $1;
261 dpurdie 2634
        if ( exists $PROGS{$prog} )
227 dpurdie 2635
        {
2636
            $tool = "\$(BINDIR)/$prog$::exe"
2637
                unless ( $tool = $SRCS{$prog} );
2638
        UniquePush (\@preq_files, $tool);
2639
        }
2640
        else
2641
        {
2642
            Error ("Unknown program: $prog");
2643
        }
2644
 
2645
    } else {
2646
 
2647
        #
2648
        #   Currently generate a warning and then use the raw tool name
2649
        #
2650
        Error ("Unknown TOOL syntax: $tool");
2651
    }
2652
 
2653
    #
2654
    #   May need to quote the path
2655
    #   If the toolpath contains spaces then ugliness can occur - so quote the program
2656
    #
2657
    $tool = '"' . $tool . '"'
2658
        if ( (! $shell_script ) && $tool =~ m~\s~ );
2659
 
2660
    #
2661
    #   Determine special startup for various programs
2662
    #       Perl  - use known implemenatation
2663
    #       Shell - use known implemenatation
2664
    #       Otherwise - simply run it
2665
    #
2666
    #   Windows: Shell and Perl don't need '\' in paths
2667
    #
2668
    if ( $tool =~ /\.pl$/ )
2669
    {
2670
        $tool = "\$(GBE_PERL) $tool";
2671
        $shell_script = 1;
2672
    }
2673
    elsif ( $tool =~ /\.k?sh$/ )
2674
    {
2675
        $tool = "\$(GBE_BIN)/sh $tool";
2676
        $shell_script = 1;
2677
    }
2678
    Debug( "GenerateFiles: Tool: $tool" );
2679
 
2680
 
2681
    #
2682
    #   Process the remaining arguments
2683
    #   These will be command line arguments or options/flags
2684
    #   Command line arguments are concatenated together
2685
    #
2686
    for my $arg (@args)
2687
    {
263 dpurdie 2688
        if ( $arg =~ /^--PreDelete$/ )
2689
        {
2690
            #
2691
            #   Delete generated files before running the generation process
2692
            #   Some programs refuse to overwrite existing files
2693
            #
2694
            $predelete = 1;
2695
            next;
2696
        }
2697
 
227 dpurdie 2698
        if ( $arg =~ /^--NoVarTag$/ )
2699
        {
2700
            #
2701
            #   Modify the operation of --Var to supress the tags
2702
            #   Should be usd early as will only affect following --Var usage
2703
            #
2704
            push @var_opts, "--notag";
2705
            next;
2706
        }
2707
 
2708
        if ( $arg =~ /^--NoWarn$/ )
2709
        {
2710
            #
2711
            #   Supress warnings - No prequisites found
2712
            #   This is acceptable, but normally a tool should take an input
2713
            #   and create some output from it.
2714
            #
2715
            $no_warn = 1;
2716
            next;
2717
        }
2718
 
2719
        if ( $arg =~ /^--NoGenerate$/ )
2720
        {
2721
            #
2722
            #   Tool does generate a definable output
2723
            #   Should only be used internally
2724
            #
2725
            #   Need to create a dummy name for the rule
2726
            #   Use a base name and a number
2727
            #
2728
            my $dummy_target = 'generate_files_' . $NoGenIndex;
2729
            UniquePush (\@gen_files, $dummy_target );
2730
            UniquePush (\@GENERATED, $dummy_target);
2731
            next;
2732
        }
2733
 
2734
        if ( $arg =~ /^--UnknownPreq/ )
2735
        {
2736
            #
2737
            #   Indicate that the prequisites are not known, or too complex to
2738
            #   describe. ie: All files in a directory. May be used by packaging
2739
            #   tools.
2740
            #   The recipe will be run EVERY time we want to use the target.
2741
            #
2742
            $preq_unknown = 1;
2743
            $no_warn = 1;
2744
            next;
2745
        }
2746
 
2747
        if ( $arg =~ /^--AutoGenerate/ )
2748
        {
2749
            #
2750
            #   Determine when to run the tool based on the types of files that
2751
            #   are generated. Existance of a source file will force the tool
2752
            #   to be run during the 'generate' phase, othewise the tool will be run
2753
            #   when the generated components are required.
2754
            #
2755
            $gtype = 2;
261 dpurdie 2756
            Warning ("AutoGenerate MUST occur before options that declare generation of files",
2757
                     "Have seen:", @genreq_seen)
2758
                if (@genreq_seen);
227 dpurdie 2759
            next;
2760
        }
2761
 
2762
        if ( $arg =~ /^--Prereq=(.*)/ )
2763
        {
2764
            #
2765
            #   Specify a prerequisite file, that is not a part of the command line
2766
            #   Simply add the files to the list of preq files
2767
            #
2768
            my $fn = LocatePreReq ($1);
2769
            UniquePush ( \@preq_files, $fn );
2770
            Debug( "GenerateFiles: ExtraPrereq: $fn" );
2771
            next;
2772
        }
2773
 
2774
        if ( $arg =~ /^--Created(.*)=(.*)/ )
2775
        {
2776
            #
2777
            #   Specify a generated file, that is not a part of the command line
2778
            #   Add the files to the list of generated files
2779
            #
2780
            my $type = $1;
2781
            my $fn = $2;
2782
 
2783
            $fn .= '.' . $::o
2784
                if ( $type =~ m/Object/ );
2785
 
2786
            $fn = "\$(OBJDIR)/$fn"
2787
                if ( $type !~ m/Common/ );
2788
            $fn = "\$(BINDIR)/$fn"
2789
                if ( $type =~ m/Prog/ );
2790
 
2791
            #
2792
            #   Examine the file and see if it needs to be compiled
2793
            #   Add to the list of source files
2794
            #
261 dpurdie 2795
            push @genreq_seen, $arg;
227 dpurdie 2796
            GenerateSrcFile ( $gtype, $fn  )
2797
                if ( UniquePush (\@gen_files, $fn) );
2798
 
2799
            Debug( "GenerateFiles: ExtraCreated: $fn" );
2800
            next;
2801
        }
2802
 
2803
        if ( $arg =~ /^--Clean($|=(.*))/ )
2804
        {
2805
            #
2806
            #   Detect Clean option
2807
            #
2808
            $clean_tag = $2 ? $2 : '-clean';
2809
 
2810
            #
2811
            #   Shell command with a --Clean will only
2812
            #   be run during a clean phase. They should not have any prereq
2813
            #   and should not generate any files, so simplify the interface.
2814
            #
2815
            push @args, '--NoWarn', '--NoGenerate'
2816
                if ( $shell_cmds );
2817
 
2818
            next;
2819
        }
2820
 
2821
        if ( $arg =~ /^--Text=(.*)/ )
2822
        {
2823
            #
2824
            #   Display this text when executing commands
2825
            #
2826
            $text = $1;
2827
            next;
2828
        }
2829
 
2830
 
2831
        #   Not an option. Must be an argument to the tool/program
2832
        #   Process the tool arguments and extract file information
2833
        #   Extract all fields of the form:
2834
        #           --xxxxx(yyyyyy[,zzzzz])
2835
        #           --xxxxx{yyyyyyy}
2836
        #           --xxxxx[yyyyyyy] to allow embedded brackets
2837
        #
2838
        while ( $arg =~ m/--(\w+)               # --CommandWord         $1
2839
                                (               # Just for grouping
2840
                                \((.*?)\)   |   # Stuff like (yyyyy)    $3
2841
                                {(.*?)}     |   # or    like {yyyyy}    $4
2842
                                \[(.*?)\]       # or    like [yyyyy]    $5
2843
                                )/x )           # Allow comments and whitespace
2844
        {
2845
            my $all = $&;
2846
            my $cmd = $1;                       # The command
2847
            my $ufn = $3 || $4 || $5;           # User filename + options
2848
            my $mb = $-[0];                     # Match begin offset
2849
            my $me = $+[0];                     # Match end
2850
            my $flags = '';                     # Optional flags ( --dir or --file )
2851
            my $raw_arg = $ufn;                 # Raw arguments
2852
 
2853
            Error ("GenerateFiles. Empty element not allowed: $all")
2854
                unless ( defined($ufn) );
2855
 
2856
            $ufn =~ s/\s+$//;
2857
            $ufn =~ s/^\s+//;
2858
            $ufn =~ s~//~/~g;                   # Remove multiple /
2859
            if ( $ufn =~ m/(.*?),(.*)/ )        # Extract out any flags
2860
            {
2861
                $ufn = $1;
2862
                $flags = $2;
2863
            }
2864
 
2865
            my $fn = $ufn ;                     # Replacement filename
2866
            Error ("GenerateFiles. Empty element not allowed: $all" )
2867
                if ( length ($ufn) <= 0 );
2868
 
2869
            #
2870
            #   Process found user command
2871
            #
2872
            if ( $cmd =~ /^Generated/ )
2873
            {
2874
                my $use_dir = "";
2875
                #
2876
                #   Generated filename
2877
                #       Determine the target directory
2878
                #       Determine the full name of the file.
2879
                #       Flag the file as generated
2880
                #
2881
                if ( $cmd =~ /Prog/ )
2882
                {
2883
                    #
2884
                    #   Generated Prog are generated in the BIN directory
2885
                    #   Ensure the directory exists by using its symbolic name
2886
                    #   as a prerequisite.
2887
                    #
2888
                    $use_dir = "\$(BINDIR)";
2889
                    UniquePush (\@preq_files, "\$(GBE_BINDIR)");
2890
                }
2891
                elsif ( $cmd !~ /Common/ )
2892
                {
2893
                    #
2894
                    #   Files that are not Common are generated in the
2895
                    #   object directory. This directory must exist, so it
2896
                    #   symbolic name GBE_OBJDIR is made a prerequisite too.
2897
                    #
2898
                    #   If the file is a header file, then add the directory
2899
                    #   to the include search path too.
2900
                    #
2901
                    $use_dir = "\$(OBJDIR)";
2902
                    UniquePush (\@preq_files, "\$(GBE_OBJDIR)");
2903
                    AddIncDir( $platforms , "\$(OBJDIR)", '--NoWarn' )
2904
                        if ( $ScmSourceTypes{ StripFile($fn) } && $ScmSourceTypes{ StripFile($fn) } eq ".h" );
2905
                }
2906
 
2907
 
2908
                #
2909
                #   Append a toolset specfic object file name suffix
2910
                #   for Object files only
2911
                #
2912
                $fn .= ".$::o"
2913
                    if ( $cmd =~ /Object/ );
2914
 
2915
                #
2916
                #   Merge directory and filename parts
2917
                #
2918
                $fn = $use_dir . ( $use_dir ? "/" : ""  ) . $fn;
2919
 
2920
                #
2921
                #   Save for later user
2922
                #   Flag the file as a generated file
2923
                #
261 dpurdie 2924
                push @genreq_seen, $cmd;
227 dpurdie 2925
                GenerateSrcFile ( $gtype, $fn  )
2926
                    if ( UniquePush (\@gen_files, $fn) );
2927
 
2928
                #
2929
                #   Use the directory or the full name
2930
                #   If using the directory then ensure that we have a name
2931
                #   even if its "."
2932
                #
2933
                $fn = ($use_dir) ? "$use_dir" : "."
2934
                    if ( $cmd =~ /Directory/ );
2935
 
2936
                Debug( "GenerateFiles: Generate: $fn" );
2937
 
2938
            }
2939
            elsif ( $cmd =~ /^Prereq/ )
2940
            {
2941
                #
2942
                #   Prerequisite filename
2943
                #       Resolve the full name of the file. It may be known
2944
                #       as a source file (possibly generated) or it may be
2945
                #       located in a known source directory
2946
                #
2947
                $fn = LocatePreReq ($ufn);
2948
                UniquePush (\@preq_files, $fn);
2949
 
2950
                Debug( "GenerateFiles: Prereq: $fn" );
2951
 
2952
            }
2953
            elsif ( $cmd =~ /^PackageBase/ )
2954
            {
2955
                $fn = GetPackageBase( "GenerateFiles", $raw_arg );
2956
                UniquePush (\@preq_files, $fn);
2957
            }
2958
            elsif ( $cmd =~ /^PackageInfo/ )
2959
            {
2960
                $fn = GetPackageInfo( "GenerateFiles", $raw_arg );
2961
            }
2962
            elsif ( $cmd =~ /^Var/ )
2963
            {
2964
                $fn = ExpandGenVar( "GenerateFiles", $raw_arg, @var_opts );
2965
                $flags = '';
2966
            }
2967
            else
2968
            {
2969
                Warning ("GenerateFiles: Unknown replacement command: $cmd");
2970
                $fn = $ufn;
2971
            }
2972
 
2973
            #
2974
            #   Process path modification flags
2975
            #
2976
            $fn = ProcessPathName( $fn, $flags );
2977
 
2978
            #
2979
            #   Minor kludge under windows. Ensure directores have a "\" sep
2980
            #   Unless the user has specified a straight shell command
2981
            #
2982
            $fn =~ s~/~\\~g
2983
                if ( $::ScmHost eq "WIN" && ! defined($shell_script) );
2984
 
2985
            #
2986
            #   Replace the found string with the real name of the file
2987
            #   Note: 4 argument version of substr is not always available
2988
            #         so we must do it the hard way
2989
            #               substr( $arg, $mb, $me - $mb, $fn);
2990
            #
2991
            $arg = substr( $arg, 0, $mb ) . $fn . substr( $arg, $me );
2992
 
2993
            Debug2( "GenerateFiles: subs: $all -> $fn" );
2994
        }
2995
 
2996
        #
2997
        #   Save the tool arguments in an array
2998
        #
2999
        push @tool_args, $arg;
3000
    }
3001
 
3002
 
3003
    #
3004
    #   Sanity test. Ensure that some file have been marged as generated
3005
    #                Warn if no prerequisites found
3006
    #
3007
 
3008
    Warning( "No Prerequisite files found in $tool",@tool_args) unless ( $no_warn || $#preq_files >= 0 );
3009
    Error  ( "No generated files found in $tool",@tool_args) unless ($#gen_files >= 0);
3010
 
3011
 
3012
    #
3013
    #   Save information
3014
    #   Will be used to create makefile statements later
3015
    #
3016
    my %gen_data;
3017
 
3018
    $gen_data{'index'}      = $NoGenIndex++;
3019
    $gen_data{'shell'}      = $shell_cmds;
3020
    $gen_data{'gen'}        = \@gen_files;
3021
    $gen_data{'preq'}       = \@preq_files;
3022
    $gen_data{'tool'}       = $tool;
3023
    $gen_data{'toolargs'}   = \@tool_args;
3024
    $gen_data{'clean'}      = $clean_tag;
3025
    $gen_data{'text'}       = $text || $gen_files[0];
3026
    $gen_data{'preq_sus'}   = 1 if ( $preq_unknown );
263 dpurdie 3027
    $gen_data{'predelete'}  = 1 if ( $predelete );
227 dpurdie 3028
 
3029
    push(@GENERATE_FILES, \%gen_data);
3030
 
3031
    Debug2( "GenerateFiles: cmd: $tool @tool_args" );
3032
}
3033
 
3034
#-------------------------------------------------------------------------------
3035
# Function        : MakePerlModule
3036
#
3037
# Description     : Build Perl Module(s) using the Perl Build System
3038
#                   This is a thin wrapper around a specialised script
3039
#
3040
#                   The user can do the same job with correct use of
3041
#                   a GenerateFiles, but this is a lot tidier.
3042
#
3043
# Inputs          : $1      - platform specifier '*' (comma delemitered)
3044
#                   $*      - Paths to Perl Modules[,command options]
3045
#                             Options to the BuildPerl script
3046
#
3047
# Returns         :
3048
#
3049
sub MakePerlModule
3050
{
3051
    my ( $platforms, @args) = @_;
3052
 
3053
    return if ( ! ActivePlatform($platforms) );
3054
 
3055
    Debug2( "MakePerlModule:($platforms, @args)" );
3056
    my @opts;
3057
 
3058
    #
3059
    #   Extract options from paths to Perl Packages
3060
    #   Package names do not start with a '-'
3061
    #
3062
    foreach my $arg ( @args )
3063
    {
3064
        if ( $arg =~ /^-/ ) {
3065
            push @opts, $arg;
3066
 
3067
        } else {
3068
            #
3069
            #   Perl Package Directory Name
3070
            #   This may also contain embedded command to the Make command
3071
            #   These will be seperated with a comma
3072
            #       ie: module,-options=fred
3073
            #
3074
            my ($name,$options) = split( ',', $arg );
3075
            push @opts, "-PerlPackage=$arg";
3076
            push @opts, "--Prereq=$name/Makefile.PL";
3077
        }
3078
    }
3079
 
3080
    #
3081
    #   Invoke GenerateFiles with a bunch of additional arguments
3082
    #
3083
    GenerateFiles ($platforms, "--Tool=jats_buildperl.pl",
3084
                          '--Var(MachType)',                        # Build Machine type
3085
                          '--Var(PackageDir)',                      # Package dir
3086
                          '--NoGenerate',                           # Don't know the output
3087
                          '--Text=Make Perl Module',                # Pretty print
3088
                          '--NoWarn',
3089
                          '--Clean=-clean_build',                   # Jats clean support
3090
                          '--NoVarTag',                             # No more Tags
3091
                          @opts,
3092
                          );
3093
}
3094
 
3095
#-------------------------------------------------------------------------------
3096
# Function        : MakeLinuxDriver
3097
#
3098
# Description     : Build a Linux Device Driver using the Linux Device Driver
3099
#                   Build System
3100
#                   This is a thin wrapper around a specialised script
3101
#
3102
#                   The user can do the same job with correct use of
3103
#                   a GenerateFiles, but this is a lot tidier.
3104
#
3105
# Inputs          : $1      - platform specifier '*' (comma delemitered)
3106
#                   $2      - name of the driver. No extension
3107
#                   $*      - Driver sources
3108
#                             Options to the script
3109
#
3110
# Returns         :
3111
#
3112
sub MakeLinuxDriver
3113
{
3114
    my ( $platforms, $driver_name, @args) = @_;
3115
 
3116
    return if ( ! ActivePlatform($platforms) );
3117
 
3118
    Error ("No driver name specified"), unless ( $driver_name );
3119
    Debug2( "MakeLinuxDriver:($platforms, $driver_name ,@args)" );
3120
    my @srcs;
3121
    my @opts;
3122
 
3123
    #
3124
    #   Extract options from source files
3125
    #   Package names do not start with a '-'
3126
    #
3127
    foreach my $arg ( @args )
3128
    {
3129
         if ( $arg =~ /^--Define=(.)/ ) {
3130
            push @opts, $arg;
3131
 
3132
         } elsif ( $arg =~ /^-/ ) {
3133
            push @opts, $arg;
3134
            Warning ("MakeLinuxDriver: Unknown option: $arg. Passed to script");
3135
 
3136
        } else {
3137
            push @srcs, $arg;
3138
            push @opts, "--Prereq=$arg";
3139
        }
3140
    }
3141
 
3142
    #
3143
    #   Cleanup the drive name
3144
    #
3145
    $driver_name =~ s~\.ko$~~;
3146
 
3147
    #
3148
    #   Remove the specified sources from the list of object files
3149
    #   that will be build. This will ensure that some internal rules are
3150
    #   not generated.
3151
    #
3152
    foreach ( @srcs )
3153
    {
3154
        my $file = StripExt(StripDir( $_ ));
3155
        delete $OBJSOURCE{ $file };
3156
        @OBJS = grep(!/^$file$/, @OBJS);
3157
    }
3158
 
3159
    #
3160
    #   Invoke GenerateFiles with a bunch of additional arguments
3161
    #   At runtime the include directories will be added as
3162
    #   absolute paths
3163
    #
3164
    GenerateFiles ($platforms, "--Tool=jats_buildlinux.pl",
3165
                    "-Output=--GeneratedProg($driver_name.ko)",
3166
                    "-Driver=$driver_name",
3167
                    "-GccPath=\$(GCC_CC)",
3168
                    "-Arch=\$(HOST_CPU)",
3169
                    "-LeaveTmp=\$(LEAVETMP)",
3170
                    "-Verbose=\$(CC_PRE)",
3171
                    "-Type=\$(GBE_TYPE)",
3172
                    "-Platform=\$(GBE_PLATFORM)",
3173
                    '$(patsubst %,-Incdir=%,$(INCDIRS))',
3174
                    @opts,
3175
                    @srcs
3176
                    );
3177
}
3178
 
3179
#-------------------------------------------------------------------------------
3180
# Function        : GetPackageBase
3181
#
3182
# Description     : Helper routine
3183
#                   Given a package name, determine the base address of the
3184
#                   package
3185
#
3186
# Inputs          : $dname         - Directive name     (Reporting)
3187
#                   $name          - Required package
3188
#                                    Allows two forms:
3189
#                                       package_name
3190
#                                       package_name,ext
3191
#
3192
# Returns         : Path to the directory in which the files are installed
3193
#                   This may be the interface directory
3194
#
3195
sub GetPackageBase
3196
{
3197
    my ($dname, $fname) = @_;
3198
    my $pkg;
3199
    my ($name, $ext) = split(',', $fname);
3200
 
3201
    $pkg = GetPackageEntry( $name, $ext );
3202
    Error ("$dname: Package not found: $fname") unless ( $pkg );
3203
 
3204
    #
3205
    #   If a BuildPkgArchive then use the interface directory
3206
    #
3207
    return ( $pkg->{'TYPE'} eq 'link' ) ? $pkg->{'ROOT'} : '$(INTERFACEDIR)';
3208
}
3209
 
3210
#-------------------------------------------------------------------------------
3211
# Function        : GetPackageInfo
3212
#
3213
# Description     : Helper routine
3214
#                   Given a package name, return some information about the package
3215
#                   Only one information item is allowed with each call
3216
#
3217
# Inputs          : $dname         - Directive name     (Reporting)
3218
#                   $name          - Required package
3219
#                                    Allows two forms:
3220
#                                       package_name
3221
#                                       package_name,ext
3222
#                                    Selector
3223
#                                       --path
3224
#                                       --version
3225
#                                       --fullversion
3226
#                                       --project
3227
#
3228
# Returns         : Package information
3229
my %GetPackageInfo = qw(path ROOT
3230
                        version DVERSION
3231
                        fullversion VERSION
3232
                        project DPROJ);
3233
sub GetPackageInfo
3234
{
3235
    my ($dname, $args) = @_;
3236
    my $pkg;
3237
    my $name;
3238
    my $ext;
3239
    my $info;
3240
 
3241
    foreach ( split(',', $args) )
3242
    {
3243
        if ( m/^--(.*)/ ) {
3244
            Error( "$dname: Too many info requests: $args") if ( $info );
3245
            $info = $GetPackageInfo{$1};
3246
            Error( "$dname: Unknown info type: $_") unless ($info);
3247
        } elsif ( $ext ) {
3248
            Error("$dname: Too many names: $args");
3249
        } elsif ( $name ) {
3250
            $ext = $_;
3251
        } else {
3252
            $name = $_;
3253
        }
3254
    }
3255
 
3256
    $pkg = GetPackageEntry( $name, $ext );
3257
    Error ("$dname: Package not found: $args") unless ( $pkg );
3258
 
3259
    #
3260
    #   If a BuildPkgArchive then use the interface directory
3261
    #
3262
    if ( $info eq 'ROOT' &&  $pkg->{'TYPE'} eq 'link' )
3263
    {
3264
        return ( '$(INTERFACEDIR)');
3265
    }
3266
    return ( $pkg->{$info} );
3267
}
3268
 
3269
#-------------------------------------------------------------------------------
3270
# Function        : GetPackageEntry
3271
#
3272
# Description     : Return the package class pointer given a package name
3273
#
3274
# Inputs          : $name          - Required package
3275
#                   $ext           - Option package extension
3276
#
3277
# Returns         : Class pointer
3278
#
3279
sub GetPackageEntry
3280
{
3281
    my ($name, $ext) = @_;
3282
    $ext = '' unless ( $ext );
3283
 
3284
    for my $entry (@{$::ScmBuildPkgRules{$ScmPlatform} })
3285
    {
3286
        next unless ( $entry->{'NAME'} eq $name );
3287
        next if ( $ext && $entry->{'DPROJ'} ne $ext );
3288
        return $entry;
3289
    }
3290
    return undef;
3291
}
3292
 
3293
#-------------------------------------------------------------------------------
3294
# Function        : ExpandGenVar
3295
#
3296
# Description     : Expand a known variable for the Generate Files option
3297
#
3298
# Inputs          : $dname         - Directive name     (Reporting)
3299
#                   $arg           - Raw argument
3300
#                                    This of the form of
3301
#                                       Tag[,--option]+
3302
#                                    Tags are specified in %ExpandGenVarConvert
3303
#
3304
#                                   Options are:
3305
#                                       --tag
3306
#                                       --notag
3307
#                                       --tag=<SomeTag>
3308
#                                       --absdrive
3309
#                                       --abspath
3310
#                                   Not all options are avalaible on all variables
3311
#                   @opts           - Options
3312
#                                       --notag     - Default is --notag
3313
#
3314
# Returns         : String
3315
#
3316
 
3317
#
3318
#   Create a Hash to simplify the process of converting Var names
3319
#   into makefile variables.
3320
#
3321
my %ExpandGenVarConvert = (
3322
    'BuildName'         => '$(GBE_PBASE)',
3323
    'BuildVersion'      => '$(BUILDVER)',
3324
    'BuildVersionNum'   => '$(BUILDVERNUM)',
3325
 
3326
    'PackageDir'        => '$(PKGDIR),+',
3327
    'PackagePkgDir'     => '$(PKGDIR)/pkg/pkg.$(GBE_PLATFORM),+',
3328
    'PackageIncDir'     => '$(INCDIR_PKG),+',
3329
    'PackageLibDir'     => '$(LIBDIR_PKG)/$(GBE_PLATFORM),+',
3330
    'PackageBinDir'     => '$(BINDIR_PKG)/$(GBE_PLATFORM)$(GBE_TYPE),+',
3331
 
3332
    'PackageToolDir'    => '$(PKGDIR)/tools,+',
3333
    'PackageToolBin'    => '$(PKGDIR)/tools/bin/$(GBE_HOSTMACH),+',
3334
    'PackageToolScript' => '$(PKGDIR)/tools/scripts,+',
3335
 
3336
    'LibDir'            => '$(LIBDIR),+',
3337
    'BinDir'            => '$(BINDIR),+',
3338
    'ObjDir'            => '$(OBJDIR),+',
3339
 
3340
    'InterfaceDir'      => '$(INTERFACEDIR),+',
3341
    'InterfaceIncDir'   => '$(INCDIR_INTERFACE),+',
3342
    'InterfaceLibDir'   => '$(LIBDIR_INTERFACE)/$(GBE_PLATFORM),+',
3343
    'InterfaceBinDir'   => '$(BINDIR_INTERFACE)/$(GBE_PLATFORM)$(GBE_TYPE),+',
3344
 
3345
    'LocalDir'          => '$(LOCALDIR),+',
3346
    'LocalIncDir'       => '$(INCDIR_LOCAL),+',
3347
    'LocalLibDir'       => '$(LIBDIR_LOCAL)/$(GBE_PLATFORM),+',
3348
    'LocalBinDir'       => '$(BINDIR_LOCAL)/$(GBE_PLATFORM)$(GBE_TYPE),+',
3349
 
3350
    'Platform'          => '$(GBE_PLATFORM)',
3351
    'Product'           => '$(GBE_PRODUCT)',
3352
    'Target'            => '$(GBE_TARGET)',
3353
 
3354
    'Type'              => '$(GBE_TYPE)',
3355
    'Arch'              => '$(HOST_CPU)',
3356
    'Architecture'      => '$(HOST_CPU)',
3357
    'MachType'          => '$(GBE_HOSTMACH)',
3358
    'BuildRoot'         => '$(GBE_ROOT),+',
3359
 
3360
 
3361
    'Verbose'           => '$(CC_PRE)',
3362
    'LeaveTmp'          => '$(LEAVETMP)',
3363
    'Cwd'               => '$(CURDIR)',
3364
 
3365
    'CompilerPath'      => '$(SCM_COMPILERPATH)',
3366
    );
3367
 
3368
sub ExpandGenVar
3369
{
3370
    my ($dname, $args, @uopts) = @_;
3371
    my $expansion;
3372
    my $prefix='';
3373
    my ($tag, @opts) = split('\s*,\s*', $args);
3374
    my $no_prefix;
3375
 
3376
    foreach ( @uopts )
3377
    {
3378
        if ( m/^--notag$/ ) {
3379
            $no_prefix = 1;
3380
        } else{
3381
            Error ("$dname: Unknown option: $_")
3382
        }
3383
    }
3384
 
3385
 
3386
    #
3387
    #   Perform run-time update on the %ExpandGenVarConvert
3388
    #   Most of it can be initialised at startup - but not all of it.
3389
    #
3390
    $ExpandGenVarConvert{CompilerPath} = undef unless $::ScmToolsetCompilerPath;
3391
    $ExpandGenVarConvert{Product}      = '$(GBE_PLATFORM)' unless $ScmProduct;
3392
 
3393
    #
3394
    #   Look up a hash of conversions
3395
    #   Could allow for a code ref, but not needed yet
3396
    #
3397
    Error ("$dname: Unknown expansion --Var($tag)")
3398
        unless ( exists $ExpandGenVarConvert{$tag} );
3399
 
3400
    Error ("$dname: Expansion --Var($tag) not be supported by toolset: $ScmToolset")
3401
        unless ($expansion = $ExpandGenVarConvert{$tag});
3402
 
3403
    ($expansion,my $is_path) = split (',', $expansion );
3404
 
3405
    #
3406
    #   Process options
3407
    #   Assume that a tag will be provided
3408
    #
3409
    $prefix =  $no_prefix ? '' : "-$tag=";
3410
    foreach my $opt ( @opts )
3411
    {
3412
        if ( $opt =~ /^--tag=(.*)/i ) {
3413
            $prefix = "$1=";
3414
 
3415
        } elsif ( $opt =~ m/^--tag$/i ) {
3416
            $prefix = "-$tag=";
3417
 
3418
        } elsif ( $opt =~ m/^--notag/i ) {
3419
            $prefix = '';
3420
 
3421
        } elsif ( $is_path && $opt =~ /--abspath|--absdrive/i ) {
3422
            $expansion = '$(CURDIR)/' . $expansion;
3423
 
3424
        } else {
3425
            Error ("$dname: Unsupported option($opt) for --Var(@_)");
3426
        }
3427
    }
3428
 
3429
    Debug ("ExpandGenVar: args $args --> $prefix$expansion");
3430
    return $prefix . $expansion;
3431
 
3432
}
3433
 
3434
#-------------------------------------------------------------------------------
3435
# Function        : ProcessPathName
3436
#
3437
# Description     : Massage a pathname according to a set of flags
3438
#
3439
# Inputs          : $fn         - Patchname to massage
3440
#                   $flags      - Flags in a string
3441
#                                   --dir       - only the directory part ( or a "." )
3442
#                                   --file      - only the file part
3443
#                                   --abspath   - Absolute path
3444
#                                   --absdrive  - Absolute path with drive letter(WIN)
3445
#
3446
# Returns         : Massaged pathname
3447
#
3448
sub ProcessPathName
3449
{
3450
    my ( $fn, $flags ) = @_;
3451
    #
3452
    #   Process flags
3453
    #       --dir           - only the directory part ( or a "." )
3454
    #       --file          - only the file part
3455
    #       --abspath       - Absolute path
3456
    #       --absdrive      - Absolute path with drive letter(WIN)
3457
    #
3458
    if ( $flags =~ /--dir/ )
3459
    {
3460
        $fn = '.'
3461
            unless ( $fn =~ s~/[^/]*$~~);
3462
    }
3463
 
3464
    if ( $flags =~ /--file/ )
3465
    {
3466
        $fn =~ s~.*/~~;
3467
    }
3468
 
3469
    if ( $flags =~ /--abspath/ )
3470
    {
3471
        $fn = AbsPath( $fn );
3472
    }
3473
    elsif ( $flags =~ /--absdrive/ )
3474
    {
3475
        $fn = AbsPath( $fn );
3476
        if ( $::ScmHost eq "WIN" )
3477
        {
3478
            $fn = $::CwdDrive . '/' . $fn
3479
                unless ( $fn =~ m~^\w:/~  );
3480
            $fn =~ s~//~/~g;
3481
        }
3482
    }
3483
 
3484
  return $fn;
3485
}
3486
 
3487
#-------------------------------------------------------------------------------
3488
# Function        : LocatePreReq
3489
#
3490
# Description     : Locate a file known to JATS
3491
#                   There are many places to search
3492
#                       1) Src files - specified with a Src directive
3493
#                       2) Scripts - specified with a script directive
3494
#                       3) Search - Files in the specified search path
3495
#                       4) Programs specified with a 'Prog' directive
3496
#
3497
#                   Should also look in other locations (Libs, SharedLibs)
3498
#                   Not done yet. May be issues of a name clash if a program
3499
#                   and a library have the same name.
3500
#
3501
# Inputs          : Name to locate
3502
#
3503
# Returns         : Full pathname of file
3504
#
3505
sub LocatePreReq
3506
{
3507
    my ( $name ) = @_;
3508
    Debug ("LocatePreReq:Looking for $name");
3509
    #
3510
    #   Try a Src file first
3511
    #
3512
    if ( exists $SRCS{ $name } )
3513
    {
3514
        return $SRCS{ $name };
3515
    }
3516
 
3517
    #
3518
    #   Try a script
3519
    #
3520
    if ( exists $SCRIPTS{ $name } )
3521
    {
3522
        return $SCRIPTS{ $name };
3523
    }
3524
 
3525
    #
3526
    #   Try a PROG
3527
    #
261 dpurdie 3528
    if ( exists $PROGS{$name} )
227 dpurdie 3529
    {
3530
        return "\$(BINDIR)/$name$::exe"
3531
    }
3532
 
3533
    #
3534
    #   Try searching for the file
3535
    #   Uses Data from AddSrcDir
3536
    #
3537
    #   Done: last because it generates warning messages
3538
    #
3539
    return MakeSrcResolve( $name );
3540
}
3541
 
3542
#-------------------------------------------------------------------------------
3543
# Function        : ToolExtensionPaths
3544
#
3545
# Description     : Return a list of toolset extension directories
3546
#                   The data will have been discovered by the build process
3547
#                   and will have been saved for the makefile creation phase
3548
#
3549
# Inputs          : None
3550
#
3551
# Returns         : Return an ordered unique list
3552
#
3553
sub ToolExtensionPaths
3554
{
3555
    Debug( "ToolExtensionPaths:", @::BUILDTOOLSPATH );
3556
    return @::BUILDTOOLSPATH;
3557
}
3558
 
3559
#-------------------------------------------------------------------------------
3560
# Function        : ToolExtensionProgram
3561
#
3562
# Description     : Determine if the named program exists within the PATH
3563
#                   that also includes the toolset extension
3564
#
3565
# Inputs          : program             - Name of program
3566
#                   elist               - An array of possible program extensions
3567
#
3568
# Returns         : Full path the to program or undef
3569
#
3570
sub ToolExtensionProgram
3571
{
3572
    my ($program, @elist ) = @_;
3573
 
3574
    #
3575
    #   If elist is empty then insert a defined entry
3576
    #
3577
    push @elist, '' unless ( @elist );
3578
 
3579
    #
3580
    #   Scan all toolset directories
3581
    #   for the program
3582
    #
3583
    for my $dir ( ToolExtensionPaths() )
3584
    {
3585
        for my $ext ( @elist )
3586
        {
3587
            my $tool = "$dir/$program$ext";
3588
            Debug2( "ToolsetExtensionProgram: Look for: $tool" );
3589
 
3590
            return $tool if ( -f $tool );
3591
        }
3592
    }
3593
}
3594
 
3595
sub Define
3596
{
3597
    Debug2( "Define(@_)" );
3598
 
3599
    push( @DEFINES, @_ );
3600
}
3601
 
3602
 
3603
sub Defines
3604
{
3605
    my( $path, $script ) = @_;
3606
    my( $line );
3607
 
3608
    Debug2( "Defines($path, $script)" );
3609
 
3610
    $script = Exists( $path, $script, "Defines" );
271 dpurdie 3611
    push( @DEFINES, "# Defines from: $script" );
227 dpurdie 3612
    open( SCRIPT, $script ) || Error( "Opening $script" );
3613
    while (<SCRIPT>) {
3614
        $_ =~ s/\s*(\n|$)//;                    # kill trailing whitespace & nl
3615
        push( @DEFINES, $_ );
3616
    }
3617
    push( @ScmDepends, "$script" );             # makefile dependencies
3618
    close( SCRIPT );
3619
}
271 dpurdie 3620
#-------------------------------------------------------------------------------
3621
# Function        : Rule
3622
#
3623
# Description     : Add a Rule and Recipe to the generated makefile
3624
#                   This is not encouraged as it has been misused to create
3625
#                   unreadable and unmaintainable makefiles.
3626
#
3627
#                   Rules will be added to the makefile after the rules and
3628
#                   recipes created by JATS directives
3629
#
3630
# Inputs          : $platform               - Platform predicate
3631
#                   @rule                   - Array of rules to add
3632
#
3633
# Returns         : 
3634
#
227 dpurdie 3635
sub Rule
3636
{
3637
    my( $platforms, @rule ) = @_;
3638
 
3639
    return if ( ! ActivePlatform($platforms) );
3640
 
3641
    push( @RULES, @rule );
3642
    Message("Rule directive used. Consider replacing with GenerateFiles");
3643
}
3644
 
271 dpurdie 3645
#-------------------------------------------------------------------------------
3646
# Function        : Rules
3647
#
3648
# Description     : Add a file of Rules and Recipes to the generated makefile
3649
#                   Used internally ONLY as there is no platform predicate
3650
#                   Similar to 'Rule()'
3651
#
3652
# Inputs          : $path                   - path to script
3653
#                   $script                 - File fo Rules
3654
#
3655
# Returns         : 
3656
#
227 dpurdie 3657
sub Rules
3658
{
3659
    my( $path, $script ) = @_;
3660
    my( $line );
3661
 
3662
    $script = Exists( $path, $script, "Rules" );
271 dpurdie 3663
    push( @RULES, "# Rules from: $script" );
227 dpurdie 3664
    open( SCRIPT, $script ) || Error( "Opening $script" );
3665
    while (<SCRIPT>) {
3666
        $_ =~ s/\s*(\n|$)//;                    # kill trailing whitespace & nl
3667
        push( @RULES, $_ );
3668
    }
3669
    push( @ScmDepends, "$script" );             # makefile dependencies
3670
    close( SCRIPT );
3671
}
3672
 
271 dpurdie 3673
#-------------------------------------------------------------------------------
3674
# Function        : AddRule
3675
#
3676
# Description     : Inernal function
3677
#                   Add a line to the Rules area
3678
#
3679
# Inputs          : @elements                   - Array of lines to add
3680
#
3681
# Returns         : Nothing
3682
#
3683
sub AddRule
3684
{
3685
    push( @RULES, @_ );
3686
}
227 dpurdie 3687
 
271 dpurdie 3688
#-------------------------------------------------------------------------------
3689
# Function        : Src
3690
#
3691
# Description     : This directive is used to identify files to JATS
3692
#                   Once a file has been identified as a 'Source' file, then it
3693
#                   can be used by name, without the need to locate the file again.
3694
#                   This implies that filenames must be unique.
3695
#                   The directories cannot be used to make files of the same name
3696
#                   unqiue - this is not the JATS way
3697
#
3698
#                   Source files will be classified as one of:
3699
#                       c, c++, header, assembler or other
3700
#
3701
#
3702
# Inputs          : $platform               - Active Platform Predicate
3703
#                   @elements               - A list of files and options
3704
#
3705
#                   Valid options are:
3706
#                       --c                 - Specifies the type of file
3707
#                       --cpp
3708
#                       --h, --headers
3709
#                       --asm
3710
#                       --FromPackage       - Search packages for the file
3711
#                       --List=xxx          - Append file to a named list
3712
#                       --Depends=xxx       - Manually name a dependency
3713
#
3714
#                   Options are processed before file elements
3715
#                   Thus options apply to all files in the list
3716
#
3717
# Returns         : Nothing
3718
#
227 dpurdie 3719
sub Src
3720
{
3721
    my( $platforms, @elements ) = @_;
3722
    my( $type, @args, $source, $basename, $from_package, @lists );
3723
    my( @depends, @srcs );
3724
 
3725
    $platforms = '' unless ( $platforms );
3726
    Debug2( "Src($platforms, @elements)" );
3727
 
3728
    #
3729
    #   Ensure that there is a file within the list
3730
    #
3731
    Warning( "Src directive does not specify any files: Src($platforms, @elements)" )
3732
        unless (grep( /^[^-]/, @elements ) );
3733
 
3734
    return if ( ! ActivePlatform($platforms) );
3735
 
3736
    #
3737
    #   Remove spaces from both ends of the arguments.
3738
    #   It is easier to remove spaces now than to detect them later
3739
    #
3740
    foreach ( @elements )
3741
    {
3742
        s/^\s+//;
3743
        s/\s+$//;
3744
        s~//~/~g;                               # Remove multiple /
3745
    }
3746
 
3747
    #.. Collect arguments
3748
    #
3749
    $type = "";
3750
    foreach ( @elements )
3751
    {
3752
        if ( /^--c$/ )
3753
        {
3754
            Debug( "Src: --c" );
3755
            $type = ".c";
3756
        }
3757
        elsif ( /^--cpp$/ )
3758
        {
3759
            Debug( "Src: --cpp" );
3760
            $type = ".cc";
3761
        }
3762
        elsif ( /^--h$/ || /^--header$/ )
3763
        {
3764
            Debug( "Src: --h" );
3765
            $type = ".h";
3766
        }
3767
        elsif ( /^--asm$/ )
3768
        {
3769
            Debug( "Src: --asm" );
3770
            $type = ".asm";
3771
        }
3772
        elsif ( /^--FromPackage$/ )
3773
        {
3774
            $from_package = 1;
3775
        }
3776
        elsif ( /^--List=(.*)/ )
3777
        {
3778
            my $list_name = $1;
3779
            Error( "Bad list name: $list_name" )
3780
                unless ( $list_name =~ m/^[A-Za-z]\w+/ );
3781
            push @lists, $list_name;
3782
        }
3783
        elsif ( /^--Depends=(.*)/ )
3784
        {
3785
            foreach ( split( ',', $1) )
3786
            {
3787
                my $full = MakeSrcResolveExtended( $from_package, $_ );
3788
                push @depends, $full;
3789
            }
3790
        }
3791
        elsif ( /^-(.*)/ )
3792
        {
3793
            Debug( "Src: arg $_" );
3794
            push @args, $_;
3795
        }
3796
        else
3797
        {
3798
            push @srcs, $_;
3799
            Warning ("Src files contains a '\\' character: $_" ) if (m~\\~);
3800
        }
3801
    }
3802
 
3803
    #.. Push source file(s)
3804
    foreach ( @srcs )
3805
    {
3806
        if ( ! /^-(.*)/ )
3807
        {
3808
            $source = MakeSrcResolveExtended( $from_package, $_ );
3809
            $basename = StripDir( $source );
3810
            Debug( "Src: $_ -> $source=$basename (@args),(@depends)" );
3811
 
3812
            if ( $SRCS{ $basename } ) {
3813
                Warning( "Duplicate src ignored '$source'");
3814
                next;
3815
            }
3816
            $SRCS{ $basename } = $source;
3817
 
3818
            HashJoin( \%SRC_ARGS, $;, $basename, @args )
3819
                if (@args);
3820
 
3821
            HashJoin( \%SRC_DEPEND, $;, $basename, @depends )
3822
                if ( @depends );
3823
 
3824
            $SRC_TYPE{ $basename } = $type
3825
                if ($type);
3826
 
3827
 
3828
            foreach (@lists) {
3829
                my $lname_short = "LIST_$_";
3830
                my $lname_full = "LIST_FULL_$_";
3831
 
3832
                no strict 'refs';
3833
 
3834
                push @$lname_short,$basename;
3835
                push @$lname_full ,$source;
3836
 
3837
                use strict 'refs';
3838
            }
3839
 
3840
            __AddSourceFile( 1, $source, "", $type );
3841
        }
3842
    }
3843
}
3844
 
3845
 
3846
###############################################################################
3847
#  sub LibNameSplit
3848
#      Just a little help to deal with major/minor stuff for shared libs -
3849
#      given the name of the library as the argument, split out major and minor
3850
#      parts and return the basename, i.e name without major and minor and
3851
#      the pair of major and minor.
3852
###############################################################################
3853
 
3854
sub LibNameSplit
3855
{
3856
    my ( @bits ) = split('\.', $_[0]);
3857
    my ( $major, $minor );
3858
 
3859
    if ($#bits >= 1) {
3860
        $major = $bits[0]; $minor = $bits[1];
3861
    } elsif ($#bits >= 0) {
3862
        $major = $bits[0]; $minor = 0;
3863
    } else {
3864
        $major = 1; $minor = 0;
3865
    }
3866
    Debug( "LibName: $@_[0] ($major.$minor)" );
3867
    return ($major, $minor);
3868
}
3869
 
3870
#-------------------------------------------------------------------------------
3871
# Function        : Lib
3872
#
3873
# Description     : Generate a static library
3874
#
3875
# Inputs          : Platform specifier
3876
#                   Name of the library
3877
#                   Arguemnts ...
3878
#
3879
# Returns         :
3880
#
3881
sub Lib
3882
{
3883
    my( $platforms, $lib, @args ) = @_;
3884
    return if ( ! ActivePlatform($platforms) );
3885
 
3886
    Error ("Lib: Library name not defined") unless ( $lib );
3887
 
3888
    #
3889
    #   May be a shared library or a static library - for historic reasons
3890
    #   If the user has specified a --Shared then its a shared library
3891
    #
3892
    return SharedLib( @_ )
3893
        if ( grep (/^--Shared/, @args) );
3894
 
3895
    #
3896
    #   Does this toolset support libraries
3897
    #
3898
    Error ("Libraries are not supported") unless ( defined $::a );
3899
 
3900
    #.. Fully qualify library path for addition to library list.
3901
    $lib = "lib$lib"
3902
       if ( $ScmTargetHost eq "Unix" && $lib !~ m/^lib/);
3903
    Debug( "Lib: $lib" );
3904
 
3905
    #
3906
    #   Ensure that only one such lib exists
3907
    #
3908
    Error( "Library of the same name already defined: $lib" )
3909
        if ( grep /^$lib$/, @LIBS );
3910
 
3911
    #
3912
    #   Add the library to the list of static libraries
3913
    #   Process arguments
3914
    #
3915
    push( @LIBS, $lib );
3916
    push( @LINTLIBS, $lib );
3917
    _LibArgs( $lib, @args );
3918
}
3919
 
3920
 
3921
#-------------------------------------------------------------------------------
3922
# Function        : SharedLib
3923
#
3924
# Description     : Generate a shared library
3925
#
3926
# Inputs          : Platform specifier
3927
#                   Name of the library
3928
#                   Arguemnts ...
3929
#
3930
# Returns         :
3931
#
3932
sub SharedLib
3933
{
3934
    my( $platforms, $lib, @args ) = @_;
3935
 
3936
    return if ( ! ActivePlatform($platforms) );
3937
 
3938
    Error ("SharedLib: Library name not defined") unless ( $lib );
3939
    Error ("Shared Libraries are not supported") unless ( defined $::so );
3940
 
3941
#.. Fully qualify library path for addition to library list.
3942
    $lib = "lib$lib"
3943
       if ( $ScmTargetHost eq "Unix" && $lib !~ m/^lib/);
3944
    Debug( "ShLib: $lib" );
3945
 
3946
    #
3947
    #   Ensure that only one such lib exists
3948
    #
3949
    Error("Library of the same name already defined: $lib")
3950
        if ( grep /^$lib$/, @SHLIBS );
3951
 
3952
    #
3953
    #   If the user has not specified a --Shared parameter then provide one
3954
    #
3955
    push @args, "--Shared=Current"
3956
        unless ( grep (/^--Shared/, @args) );
3957
 
3958
    #
3959
    #   Add the library to the list of shared libraries
3960
    #   Process arguments
3961
    #
3962
    push( @SHLIBS, $lib );
3963
    push( @LINTSHLIBS, $lib );
3964
    _SharedLibArgs( $lib, @args );
3965
}
3966
 
3967
 
3968
#-------------------------------------------------------------------------------
3969
# Function        : LibArgs
3970
#
3971
# Description     : Add arguments to an existing library directive
3972
#
3973
# Inputs          : Platform specifier
3974
#                   Name of the library
3975
#                   Arguemnts ...
3976
#
3977
# Returns         :
3978
#
3979
sub LibArgs
3980
{
3981
    my( $platforms, $lib, @args ) = @_;
3982
    return if ( ! ActivePlatform($platforms) );
3983
 
3984
#.. Fully qualify library path for addition to library list.
3985
    $lib = "lib$lib"
3986
       if ( $ScmTargetHost eq "Unix" && $lib !~ m/^lib/);
3987
    Debug( "LibArgs: $lib" );
3988
 
3989
    #
3990
    #   Ensure that only one such lib exists
3991
    #
3992
    Error("Library name not defined: $lib")
3993
        unless ( grep /^$lib$/, @LIBS );
3994
 
3995
    #
3996
    #   Process the arguments
3997
    #
3998
    _LibArgs( $lib, @args );
3999
}
4000
 
4001
 
4002
#-------------------------------------------------------------------------------
4003
# Function        : _LibArgs
4004
#
4005
# Description     : Process static library arguments
4006
#                   Internal use only
4007
#
4008
# Inputs          : Name of the library
4009
#                   Arguments to process
4010
#
4011
sub _LibArgs
4012
{
4013
    my( $lib, @elements) = @_;
4014
    my $obj;
4015
 
4016
    #
4017
    #   Process each element
4018
    #
4019
    foreach (@elements)
4020
    {
4021
        if ( /^--Shared/ )
4022
        {
4023
            Error( "--Shared not valid for a static library" );
4024
        }
4025
 
4026
        if ( /^-l(.*)/ || /^--l(.*)/ || /^-L(.*)/ || /^--L(.*)/ )
4027
        {
4028
        #.. Target library specified - add to library list.
4029
        #
4030
            Warning( "$_ within non shared library specification" );
4031
            next;
4032
        }
4033
 
4034
        if ( /^--if(.*)/ )
4035
        {
4036
            Warning( "$_ within non shared library specification" );
4037
            next;
4038
        }
4039
 
4040
        if ( /^--(.*)/ )
4041
        {
4042
            Debug( "LibArgs: arg $_" );
4043
 
4044
            #.. Argument specified - add to argument list
4045
            #
4046
            HashJoin( \%LIB_ARGS, $;, $lib, "$_" );
4047
            next;
4048
        }
4049
 
4050
        if ( defined %::ScmToolsetProgSource )
4051
        {
4052
            #
4053
            #   Toolset provides support for some file types
4054
            #   to be passed directly to the librarian builder
4055
            #
4056
            my $ext  = StripFile($_);
4057
            if ( exists ($::ScmToolsetProgSource{$ext}) )
4058
            {
4059
                my $full_path = MakeSrcResolve ( $_ );
4060
                my $flag = $::ScmToolsetProgSource{$ext};
4061
                Debug( "LibArgs: src $_" );
4062
                HashJoin( \%LIB_ARGS, $;, $lib, "$flag$full_path" );
4063
                next;
4064
            }
4065
        }
4066
 
4067
        if ( $::o )
4068
        {
4069
        #.. Object specified - add to object list.
4070
        #
4071
            $obj = _LibObject( "", $_ );
4072
 
4073
        #.. Add to object list.
4074
        #   Note:   Object path must be explicit as several
4075
        #           toolsets add additional objects.
4076
        #
4077
            HashJoin( \%LIB_OBJS, $;, $lib, "\$(OBJDIR)/$obj" );
4078
            next;
4079
        }
4080
 
4081
        #
4082
        #   Don't know how to handle this type of argument
4083
        #
4084
        Error ("LibArgs: Don't know how to handle: $_" );
4085
    }
4086
}
4087
 
4088
 
4089
#-------------------------------------------------------------------------------
4090
# Function        : SharedLibArgs
4091
#
4092
# Description     : Add arguments to an existing shared library directive
4093
#
4094
# Inputs          : Platform specifier
4095
#                   Name of the library
4096
#                   Arguemnts ...
4097
#
4098
# Returns         :
4099
#
4100
sub SharedLibArgs
4101
{
4102
    my( $platforms, $lib, @args ) = @_;
4103
    return if ( ! ActivePlatform($platforms) );
4104
 
4105
#.. Fully qualify library path for addition to library list.
4106
    $lib = "lib$lib"
4107
       if ( $ScmTargetHost eq "Unix" && $lib !~ m/^lib/);
4108
    Debug( "ShLibArgs: $lib" );
4109
 
4110
    #
4111
    #   Ensure that only one such lib exists
4112
    #
4113
    Error ("Library name not defined: $lib\n")
4114
        unless ( grep /^$lib$/, @SHLIBS );
4115
 
4116
    _SharedLibArgs( $lib, @args );
4117
}
4118
 
4119
 
4120
#-------------------------------------------------------------------------------
4121
# Function        : _SharedLibArgs
4122
#
4123
# Description     : Process shared library arguments
4124
#                   Internal use only
4125
#
4126
# Inputs          : Name of the library
4127
#                   Arguments to process
4128
#
4129
sub _SharedLibArgs
4130
{
4131
    my ( $lib, @elements) = @_;
4132
    my ( $shared ) = $SHLIB_VER{ $lib };
4133
 
4134
    #
4135
    #.. Collect --shared arguments
4136
    #
4137
    foreach (@elements)
4138
    {
4139
        if ( /^--Shared$/ )
4140
        {
4141
        #.. Shared library, default library version 1.0
4142
        #
4143
            Warning( "multiple --Shared arguments" )
4144
               if ( $shared );
4145
            $shared = "1.0";
4146
            Debug( "ShLibArgs: shared $_ ($shared)" );
4147
            $SHLIB_VER{ $lib } = $shared;
4148
        }
4149
        elsif ( /^--Shared=Current$/ )
4150
        {
4151
        #.. Shared library, using 'current' build version
4152
        #
4153
            Warning( "multiple --Shared arguments" )
4154
               if ( $shared );
4155
            $shared = $::ScmBuildVersion;
4156
            $shared = "1.0"
4157
               if ($shared eq "");
4158
            Debug( "ShLibArgs: shared $_ ($shared)" );
4159
            $SHLIB_VER{ $lib } = $shared;
4160
        }
4161
        elsif ( /^--Shared=(.*)/ )
4162
        {
4163
        #.. Shared library, specific version
4164
        #
4165
            my($M, $m) = LibNameSplit($1);
4166
 
4167
            Warning( "multiple --Shared arguments" )
4168
            if ($shared);
4169
                $shared = "$M.$m";
4170
            Debug( "ShLibArgs: shared $_ ($shared)" );
4171
            $SHLIB_VER{ $lib } = $shared;
4172
        }
4173
    }
4174
 
4175
 
4176
#.. Parse all of the object and argument entries.
4177
#
4178
    foreach (@elements)
4179
    {
4180
        if ( /^--Shared(.*)/ )
4181
        {
4182
        #.. Preprocessed above
4183
        #
4184
            next;
4185
        }
4186
 
4187
        if ( /^[-]{1,2}([lL])(.*)/ )
4188
        {
4189
        #.. Target library specified - add to library list.
4190
        #
4191
            Debug( "ShLibArgs: lib  -$1$2" );
4192
            HashJoin( \%SHLIB_LIBS, $;, $lib, "-$1$2" );
4193
            next;
4194
        }
4195
 
4196
        if ( /^--if(.*)/ )
4197
        {
4198
        #.. Library conditional - add to library list.
4199
        #
4200
            Debug( "ShLibArgs: cond $_" );
4201
            HashJoin( \%SHLIB_LIBS, $;, $lib, "$_" );
4202
            next;
4203
        }
4204
 
4205
        if ( /^-(.*)/ )
4206
        {                           
4207
        #.. Argument specified - add to argument list
4208
        #
4209
            Debug( "ShLibArgs: arg  $_" );
4210
            $SHLIB_VER{ $lib } = $shared;
4211
            HashJoin( \%SHLIB_ARGS, $;, $lib, "$_" );
4212
            next;
4213
        }
4214
 
4215
        if ( defined %::ScmToolsetProgSource )
4216
        {
4217
            #
4218
            #   Toolset provides support for some file types
4219
            #   to be passed directly to the program builder
4220
            #
4221
            my $ext  = StripFile($_);
4222
            if ( exists ($::ScmToolsetProgSource{$ext}) )
4223
            {
4224
                my $full_path = MakeSrcResolve ( $_ );
4225
                my $flag = $::ScmToolsetProgSource{$ext};
4226
                Debug( "ShLibArgs: src $_" );
4227
                HashJoin( \%SHLIB_ARGS, $;, $lib, "$flag$full_path" );
4228
                next;
4229
            }
4230
        }
4231
 
4232
        if ( $::o )
4233
        {
4234
        #.. Object specified - add to object list.
4235
        #
4236
            my ($obj) = _LibObject( $lib, $_ );
4237
 
4238
        #.. Add to object list.
4239
        #   Note:   Object path must be explicit as several
4240
        #           toolsets add additional objects.
4241
        #
4242
            $SHOBJ_LIB{ $obj } = $lib;
4243
            HashJoin( \%SHLIB_OBJS, $;, $lib, "\$(OBJDIR)/$obj" );
4244
            next;
4245
        }
4246
 
4247
        #
4248
        #   Don't know how to handle this type of argument
4249
        #
4250
        Error ("SharedLib: Don't know how to handle: $_" );
4251
    }
4252
}
4253
 
4254
 
4255
#-------------------------------------------------------------------------------
4256
# Function        : _LibObject
4257
#
4258
# Description     : Process library object file
4259
#                   Common processing routine for static and shared library
4260
#                   Internal use only
4261
#
4262
# Inputs          : shared  - Name of the shared library is shared, if defined
4263
#                   fname   - Name of file
4264
#
4265
# Returns         : Name of the object file
4266
#
4267
sub _LibObject
4268
{
4269
    my ($shared, $fname) = @_;
4270
    my ($file, $ext, $obj, $srcfile, $delete_obj);
4271
 
4272
    #.. Object specified - add to object list.
4273
    #
4274
    $file = StripExt($fname);                   # file name, without extension
4275
    $ext  = StripFile($fname);                  # extension
4276
 
4277
    if ($shared) {
4278
        $obj = "$shared/$file";                 # library specific subdir
4279
    } else {
4280
        $obj = "$file";
4281
    }
4282
 
4283
    Debug( "LibObjs: obj [$shared]$fname ($file$ext)" );
4284
 
4285
    #.. Unqualified object name
4286
    #
4287
    if ( $ext eq "" )
4288
    {
4289
        #
4290
        #   Object file not covered by a "Src" statement
4291
        #   Assume that it will be created
4292
        #
4293
        unless ( $srcfile = $OBJSOURCE{ "$file" } )
4294
        {
4295
            #
4296
            #   If the object is "generated" then it will be is the
4297
            #   SRCS list
4298
            #
4299
            unless ( $srcfile = $SRCS{"$file.$::o"} )
4300
            {
4301
                Warning( "No source for object '$fname' ($file)" );
4302
            }
4303
        }
4304
        $delete_obj = 1;
4305
    }
4306
 
4307
    #.. Qualified object name (ie has extension)
4308
    #       Strip extension and resolve ...
4309
    #       Assume that the named file can be built into an object file
4310
    #
4311
    else
4312
    {
4313
        #.. Resolve
4314
        #
4315
        if ( !($srcfile = $OBJSOURCE{ "$file" }) )
4316
        {
4317
            $srcfile = MakeSrcResolve( $fname );
4318
            $SRCS{ $fname } = $srcfile;
4319
            __AddSourceFile( 0, $fname, $obj );
4320
            $delete_obj = 1;
4321
        }
4322
    }
4323
 
4324
    #.. Delete generated object file
4325
    #   Ensure that the object file is added to the delete list
4326
    #   Add it to the ToolsetObj deletion list as the main OBJ deleltion
4327
    #   list will aready have been processed
4328
    #
4329
    ToolsetObj( "\$(OBJDIR)/$obj" )
4330
        if ( $delete_obj );
4331
 
4332
 
4333
    #.. Shared library objects,
4334
    #       Must explicitly relate source and object, as shared libraries
4335
    #       objects are built within a library specific subdirs.
4336
    #
4337
    $OBJSOURCE{ $obj } = $srcfile
4338
        if ( $shared );
4339
 
4340
    return $obj;
4341
}
4342
 
4343
 
4344
# MergeLibrary
4345
#   Merge a list of libraries into one library
4346
#
4347
sub MergeLibrary
4348
{
4349
    my( $platforms, $lib, @elements ) = @_;
4350
 
4351
    return if ( ! ActivePlatform($platforms) );
4352
 
4353
 
4354
#.. Fully qualify library path for addition to library list.
4355
    $lib = "lib$lib"
4356
       if ( $ScmTargetHost eq "Unix" && $lib !~ m/^lib/);
4357
    Debug( "MergeLibrary: $lib" );
4358
 
4359
#.. Parse all of the object and argument entries.
4360
#
4361
    foreach (@elements)
4362
    {
4363
        if ( /^--(.*)/ )
4364
        {
4365
            HashJoin( \%MLIB_ARGS, $;, $lib, "$_" );
4366
        }
4367
        else
4368
        {
4369
            my ($llib);
4370
 
4371
            #
4372
            #   Collect the source libraries
4373
            #   These must have been installed and will be in a known area
4374
            #   Create full names for the libaries
4375
            #
4376
            if ( $ScmTargetHost eq "Unix" ) {
4377
                $llib = "lib$_";                # Prefix "lib" ....
4378
                $lib =~ s/^liblib/lib/;         # @LIBS already has lib added
4379
            } else {
4380
                $llib = $_;
4381
            }
4382
 
4383
            Debug( "MergeLibrary: merge $llib" );
4384
            HashJoin( \%MLIB_LIBS, $;, $lib, $llib );
4385
        }
4386
    }
4387
    UniquePush( \@MLIBS, $lib );
4388
}
4389
 
4390
#-------------------------------------------------------------------------------
4391
# Function        : Script
4392
#
4393
# Description     : Locate a script for test purposes
4394
#
4395
# Inputs          : $platforms      - Platform selector
4396
#                   $script         - A single script name
4397
#                   $execute        - Flag to indicate that the script is to
4398
#                                     marked as executable when used in a TestProg
4399
#                                     This flag is NOT used as the script will
4400
#                                     be forced executable
4401
#
4402
# Returns         : Nothing
4403
#
4404
sub Script
4405
{
4406
    my( $platforms, $script, $execute ) = @_;
4407
 
4408
    Debug2( "Script(@_)" );
4409
 
4410
    return if ( ! ActivePlatform($platforms) );
4411
 
4412
    #
4413
    #   Locate the script as a source file
4414
    #
4415
    my $file = MakeSrcResolve ( $script );
4416
    $script = StripDir( $file );
4417
    $SCRIPTS{ $script } = $file;
4418
}
4419
 
4420
#-------------------------------------------------------------------------------
4421
# Function        : RunTest
4422
#
4423
# Description     : Define a test to be run with the 'run_tests' and 'run_unit_tests'
4424
#
4425
# Inputs          : $platform       - Enabled for these platforms
4426
#                   $prog           - Program to run
4427
#                                     This SHOULD return a non-zero exit status
4428
#                                     on error. The program may be a 'TestProg'
4429
#                                     or a 'Script'.
4430
#                   @elements       - Options and test arguments
4431
#                                     Options are:
4432
#                                       --Auto          - Non interactive unit test
4433
#                                       --Unit          - Same and --Auto
4434
#                                       --CopyIn=file   - A file to be copied into
4435
#                                                         The test directory.
4436
#
4437
#                                     Non Options are passed to the test program.
4438
#                                     --PackageBase(xxx)    - Base of package
4439
#                                     --PackageInfo(xxx)    - Package information
4440
#                                     --File(xxx)           - Resolved name of file
4441
#                                     --Var(xxx)            - Expanded variable
4442
#                                     --Local(xxx)          - File within the local directory
4443
#
4444
# Returns         : Nothing
4445
#
4446
 
4447
sub RunTest
4448
{
4449
    my( $platforms, $prog, @elements ) = @_;
4450
    my $command = './';                 # program prefix / command
4451
    my $winprog = 1;                    # 1: Convert / -> \ (WIN32 only)
4452
    my $framework;
4453
    my @framework_opts;
4454
    my @copy = ();
4455
    my $auto;
4456
 
4457
    return if ( ! ActivePlatform($platforms) );
4458
 
4459
    #
4460
    #   Scan @elements and extract useful information
4461
    #   Need to process twice as some args will modify the
4462
    #   processing done later
4463
    #
4464
    my @args;
4465
    foreach ( @elements )
4466
    {
4467
        if ( m/^--FrameWork=(.+)/ ) {
4468
            $framework = $1;
4469
 
4470
        } elsif ( m/^--Auto/ || m/^--Unit/) {
4471
            $auto = 1;
4472
 
4473
        } elsif ( m/^--CopyIn=(.*)/ ) {
4474
            push @copy, MakeSrcResolve ( $1 );
4475
 
4476
 
4477
        } elsif ( $framework && m/^--\w+=(.+)/ ) {
4478
            push @framework_opts, $_;
4479
 
4480
        } else {
4481
            push @args, $_;
4482
        }
4483
    }
4484
    @elements = @args;
4485
    @args = ();
4486
 
4487
    #
4488
    #   Determine the source of the test prog
4489
    #   If using a plug-in framework, then we don;'t know
4490
    #   If not, then may be a script or a TESTPROGS
4491
    #
4492
 
4493
    unless ( $framework )
4494
    {
261 dpurdie 4495
        if ( exists $TESTPROGS{$prog} ||  exists $PROGS{$prog} ) {
227 dpurdie 4496
            #
4497
            #   Append a suitable EXE suffix
4498
            #
4499
            $prog .= "$::exe";
4500
 
4501
        } elsif ( exists $SCRIPTS{$prog} ) {
4502
            #
4503
            #   Script names are raw
4504
            #   Perl script are invoked directly
4505
            #
4506
            $command = "\$(GBE_PERL) -w "
4507
                if ( $prog =~ /\.pl$/ );
4508
 
4509
            #
4510
            #   Pass / to shells
4511
            #
4512
            $winprog = 0
4513
                unless ( $prog =~ m~\.bat$~ )
4514
 
4515
        } else {
4516
            Warning("RunTest program not known: $prog",
261 dpurdie 4517
                  "It is not a TestProg, Prog or a Script",
4518
                  "The test may fail" );
227 dpurdie 4519
        }
4520
    }
4521
 
4522
    #
4523
    #   Extract and process options
4524
    #
4525
    my @uargs = ();
4526
    my @preq_files;
4527
 
4528
    foreach my $arg (@elements) {
4529
        #
4530
        #   Process the tool arguments and extract file information
4531
        #   Extract all fields of the form:
4532
        #           --xxxxx(yyyyyy[,zzzzz])
4533
        #           --xxxxx{yyyyyyy}
4534
        #           --xxxxx[yyyyyyy] to allow embedded brackets
4535
        #
4536
        while ( $arg =~ m/--(\w+)               # --CommandWord         $1
4537
                                (               # Just for grouping
4538
                                \((.*?)\)   |   # Stuff like (yyyyy)    $3
4539
                                {(.*?)}     |   # or    like {yyyyy}    $4
4540
                                \[(.*?)\]       # or    like [yyyyy]    $5
4541
                                )/x )           # Allow comments and whitespace
4542
        {
4543
            my $all = $&;
4544
            my $cmd = $1;                       # The command
4545
            my $ufn = $3 || $4 || $5;           # User filename + options
4546
            my $mb = $-[0];                     # Match begin offset
4547
            my $me = $+[0];                     # Match end
4548
            my $flags = '';                     # Optional flags ( --dir or --file )
4549
            my $raw_arg = $ufn;                 # Raw arguments
4550
 
4551
            Error ("RunTest. Empty element not allowed: $all")
4552
                unless ( defined($ufn) );
4553
 
4554
            $ufn =~ s/\s+$//;
4555
            $ufn =~ s~//~/~g;                   # Remove multiple /
4556
            if ( $ufn =~ m/(.*?),(.*)/ )        # Extract out any flags
4557
            {
4558
                $ufn = $1;
4559
                $flags = $2;
4560
            }
4561
 
4562
            my $fn = $ufn ;                     # Replacement filename
4563
            Error ("RunTest. Empty element not allowed: $all" )
4564
                if ( length ($ufn) <= 0 );
4565
 
4566
            #
4567
            #   Process found user command
4568
            #
4569
            if ( $cmd =~ /^File/ )
4570
            {
4571
                #
4572
                #   Prerequisite filename
4573
                #       Resolve the full name of the file. It may be known
4574
                #       as a source file (possibly generated) or it may be
4575
                #       located in a known source directory
4576
                #
4577
                $fn = MakeSrcResolve ( $ufn );
4578
                UniquePush (\@preq_files, $fn);
4579
 
4580
                Debug( "RunTest: Prereq: $fn" );
4581
 
4582
            }
4583
            elsif ( $cmd =~ /^PackageBase/ )
4584
            {
4585
                $fn = GetPackageBase( "RunTest", $raw_arg );
4586
                UniquePush (\@preq_files, $fn);
4587
            }
4588
            elsif ( $cmd =~ /^PackageInfo/ )
4589
            {
4590
                $fn = GetPackageInfo( "RunTest", $raw_arg );
4591
            }
4592
            elsif ( $cmd =~ /^Var/ )
4593
            {
4594
                $fn = ExpandGenVar( "RunTest", $raw_arg );
4595
                $flags = '';
4596
            }
4597
            elsif ( $cmd =~ /^Local/ )
4598
            {
4599
                $fn = '$(LOCALDIR)/' . $ufn ;
4600
                UniquePush (\@preq_files, $fn);
4601
            }
4602
            else
4603
            {
4604
                Warning ("RunTest: Unknown replacement command: $cmd");
4605
                $fn = $ufn;
4606
            }
4607
 
4608
            #
4609
            #   Process path modification flags
4610
            #       --dir           - only the directory part ( or a "." )
4611
            #       --file          - only the file part
4612
            #       --abspath       - Absolute path
4613
            #       --absdrive      - Absolute path with drive letter(WIN)
4614
            #
4615
            $fn = ProcessPathName( $fn, $flags );
4616
 
4617
            #
4618
            #   The program is going to be executed within a subdirectory
4619
            #   so add one more level of indirection to the path, but only if
4620
            #   the path is relative
4621
            #
4622
            unless ( $fn =~ m~^/|\w:/~  )
4623
            {
4624
                $fn = '../' . $fn;
4625
                $fn =~ s~/.$~~;
4626
            }
4627
 
4628
            #
4629
            #   Minor kludge under windows. Ensure directores have a "\" sep
4630
            #   Unless the user has specified a straight shell command
4631
            #
4632
            $fn =~ s~/~\\~g
4633
                if ( $::ScmHost eq "WIN" && $winprog );
4634
 
4635
            #
4636
            #   Replace the found string with the real name of the file
4637
            #   Note: 4 argument version of substr is not always available
4638
            #         so we must do it the hard way
4639
            #               substr( $arg, $mb, $me - $mb, $fn);
4640
            #
4641
            $arg = substr( $arg, 0, $mb ) . $fn . substr( $arg, $me );
4642
 
4643
            Debug2( "RunTest: subs: $all -> $fn" );
4644
        }
4645
        push(@uargs, "'$arg'");
4646
    }
4647
 
4648
    #
4649
    #   Create the test entry
4650
    #   This is a structure that will be placed in an array
4651
    #   The array preserves order and uniqness
4652
    #
4653
    my %test_entry;
4654
    $test_entry{'framework'}= $framework if ( $framework );
4655
    $test_entry{'framework_opts'}= \@framework_opts if ( $framework );
4656
    $test_entry{'command'}  = $command . $prog unless ( $framework);
4657
 
4658
    $test_entry{'prog'}     = $prog;
4659
    $test_entry{'copyprog'} = 1;
4660
    $test_entry{'args'}     = \@uargs;
4661
    $test_entry{'auto'}     = $auto if ( $auto );
4662
    $test_entry{'copyin'}   = \@copy;
4663
    $test_entry{'copyonce'} = ();
4664
    $test_entry{'preq'}     = \@preq_files;
4665
    $test_entry{'testdir'}  = 'BINDIR';
4666
 
4667
    push ( @TESTS_TO_RUN, \%test_entry );
4668
 
4669
    #
4670
    #   Flag Auto Run processing required
4671
    #
4672
    $TESTS_TO_AUTORUN = 1 if ( $auto );
4673
}
4674
 
4675
 
4676
sub TestProg
4677
{
4678
    my( $platforms, $prog, @elements ) = @_;
4679
 
4680
    Debug2( "TestProg($platforms, $prog, @elements)" );
4681
 
4682
    return if ( ! ActivePlatform($platforms) );
4683
 
4684
    Error ("TestProg: Program name not defined") unless ( $prog );
4685
    Error ("Programs are not supported") unless ( defined $::exe );
4686
 
4687
 
4688
#.. Fully qualify program path for addition to program list
4689
    $TESTPROGS{$prog} = 1;
4690
 
4691
#.. Parse all of the object, library and argument entries
4692
    Debug( "TestProg: $prog" );
4693
    foreach (@elements)
4694
    {
4695
        if ( /^[-]{1,2}([lL])(.*)/ )
4696
        {
4697
        #.. Target Library specified - add to library list.
4698
        #  
4699
            Debug( "TestProg: lib  -$1$2" );
4700
            HashJoin( \%TESTPROG_LIBS, $;, $prog, "-$1$2" );
4701
            next;
4702
        }
4703
 
4704
        if ( /^--if(.*)/ )
4705
        {
4706
        #.. Library conditional - add to library list.
4707
        #
4708
            Debug( "TestProg: cond $_" );
4709
            HashJoin( \%TESTPROG_LIBS, $;, $prog, "$_" );
4710
            next;
4711
        }
4712
 
4713
        if ( /^-(.*)/ )
4714
        {
4715
        #.. Argument specified - add to argument list
4716
        #
4717
            Debug( "TestProg: arg $_" );
4718
            HashJoin( \%TESTPROG_ARGS, $;, $prog, "$_" );
4719
            next;
4720
        }
4721
 
4722
        if ( defined %::ScmToolsetProgSource )
4723
        {
4724
            #
4725
            #   Toolset provides support for some file types
4726
            #   to be passed directly to the program builder
4727
            #
4728
            my $ext  = StripFile($_);
4729
            if ( exists ($::ScmToolsetProgSource{$ext}) )
4730
            {
4731
                my $full_path = MakeSrcResolve ( $_ );
4732
                my $flag = $::ScmToolsetProgSource{$ext};
4733
                Debug( "TestProg: src $_" );
4734
                HashJoin( \%TESTPROG_ARGS, $;, $prog, "$flag$full_path" );
4735
                next;
4736
            }
4737
        }
4738
 
4739
        if ( $::o )
4740
        {
4741
        #.. Object specified - add to object list.
4742
        #
4743
            my $obj = _LibObject( "", $_ );
4744
 
4745
        #.. Add to program object list.
4746
            HashJoin( \%TESTPROG_OBJS, $;, $prog, "\$(OBJDIR)/$obj" );
4747
            next;
4748
        }
4749
 
4750
        #
4751
        #   Don't know how to handle this type of argument
4752
        #
4753
        Error ("TestProg: Don't know how to handle: $_" );
4754
    }
4755
}
4756
 
4757
 
4758
sub Prog
4759
{
4760
    my( $platforms, $prog, @elements ) = @_;
4761
 
4762
    Debug2( "Prog($platforms, $prog, @elements)" );
4763
 
4764
    return if ( ! ActivePlatform($platforms) );
4765
 
4766
    Error ("Prog: Program name not defined") unless ( $prog );
4767
    Error ("Programs are not supported") unless ( defined $::exe );
4768
 
4769
 
4770
#.. Fully qualify program path for addition to program list
4771
    UniquePush( \@PROGS, $prog );
261 dpurdie 4772
    $PROGS{$prog} = 1;
227 dpurdie 4773
 
4774
#.. Parse all of the object, library and argument entries
4775
    Debug( "Prog: $prog" );
4776
    foreach (@elements)
4777
    {
4778
        if ( /^[-]{1,2}([lL])(.*)/ )
4779
        {
4780
        #.. Target Library specified - add to library list.
4781
        #  
4782
            Debug( "Prog: lib  -$1$2" );
4783
            HashJoin( \%PROG_LIBS, $;, $prog, "-$1$2" );
4784
            next;
4785
        }
4786
 
4787
        if ( /^--if(.*)/ )
4788
        {
4789
        #.. Library conditional - add to library list.
4790
        #
4791
            Debug( "Prog: cond $_" );
4792
            HashJoin( \%PROG_LIBS, $;, $prog, "$_" );
4793
            next;
4794
        }
4795
 
4796
        if ( /^-(.*)/ )
4797
        {
4798
        #.. Argument specified - add to argument list
4799
        #
4800
            Debug( "Prog: arg $_" );
4801
            HashJoin( \%PROG_ARGS, $;, $prog, "$_" );
4802
            next;
4803
        }
4804
 
4805
        if ( defined %::ScmToolsetProgSource )
4806
        {
4807
            #
4808
            #   Toolset provides support for some file types
4809
            #   to be passed directly to the program builder
4810
            #
4811
            my $ext  = StripFile($_);
4812
            if ( exists ($::ScmToolsetProgSource{$ext}) )
4813
            {
4814
                my $full_path = MakeSrcResolve ( $_ );
4815
                my $flag = $::ScmToolsetProgSource{$ext};
4816
                Debug( "Prog: src $_" );
4817
                HashJoin( \%PROG_ARGS, $;, $prog, "$flag$full_path" );
4818
                next;
4819
            }
4820
        }
4821
 
4822
        if ( $::o )
4823
        {
4824
        #.. Object specified - add to object list.
4825
        #
4826
            my $obj = _LibObject( "", $_ );
4827
 
4828
        #.. Add to program object list.
4829
            push @PROGOBJS, $obj;
4830
            HashJoin( \%PROG_OBJS, $;, $prog, "\$(OBJDIR)/$obj" );
4831
            next;
4832
        }
4833
 
4834
        #
4835
        #   Don't know how to handle this type of argument
4836
        #
4837
        Error ("Prog: Don't know how to handle: $_" );
4838
    }
4839
}
4840
 
4841
#-------------------------------------------------------------------------------
4842
# Function        : ProgAddExtra
4843
#
4844
# Description     : This (internal) function allows a toolset to list additional
4845
#                   binaries as a part of a program. This will ensure that the
4846
#                   binaries are generated in the 'make_prog' phase with the main
4847
#                   program.
4848
#
4849
#                   The files are not listed for packaging, by this function
4850
#
4851
#                   The function does not ensure that the files are not already
4852
#                   listed as a @PROG ( as @PROGS is not fully resolved at this point )
4853
#
4854
# Inputs          :     $name               - Tag name of program being built
4855
#                                             Not used (yet)
4856
#                       $prog               - Fully resolved path to a file
4857
#
4858
# Returns         : Nothing
4859
#
4860
sub ProgAddExtra
4861
{
4862
    my ($name, $prog) = @_;
4863
    Debug2( "ProgAddExtra($name: $prog)" );
4864
 
4865
    UniquePush(\@PROGS_EXTRA, $prog);
4866
}
4867
 
4868
#-------------------------------------------------------------------------------
4869
# Function        : MakeProject
4870
#
4871
# Description     : A nasty directive that is intended to build a Microsoft
4872
#                   project for WINCE, WIN32 and .NET builds.
4873
#
4874
#                   There are many constraints:
4875
#                       Cannot be mixed with multi-platform builds
4876
#                       Some parameters are tool specific
4877
#
267 dpurdie 4878
#                   Allow programs to be Installed as well as Packaged
4879
#                   The 'Progect' is treated' as a program and it doesn't work
4880
#                   to well if we Install libraries.
227 dpurdie 4881
#
267 dpurdie 4882
#                   Only Reason to Install Programs is to allow the Cab Maker
4883
#                   to locate them.
4884
#
227 dpurdie 4885
# Inputs          : Platform        - Active platform
4886
#                   Project         - Project Name with extension
4887
#                   Options         - Many options
4888
#
4889
# Returns         :
4890
#
4891
our %PROJECTS;                          # Project information
4892
my  @PROJECTS_ORDER;
4893
sub MakeProject
4894
{
4895
    my( $platforms, $proj, @elements ) = @_;
4896
 
4897
    Debug2( "MakeProject($platforms, $proj, @elements)" );
4898
 
4899
    return if ( ! ActivePlatform($platforms) );
4900
 
4901
    #
4902
    #   Sanity test
4903
    #
4904
    Error ("MakeProject: Project name not defined") unless ( $proj );
4905
 
4906
    #
4907
    #   Take the project name and convert it into a full path
4908
    #
4909
    my $project = MakeSrcResolve ( $proj );
4910
    $proj = StripDir( $project );
237 dpurdie 4911
    Error ("Project File Not found: $project") unless ( -f $project );
227 dpurdie 4912
 
4913
    my $basedir = StripFileExt( $project );
4914
 
4915
    #
4916
    #   Collect user arguments
4917
    #   They are all processed within the toolset
4918
    #
4919
    my @tool_options;
4920
    foreach ( @elements )
4921
    {
4922
        if ( m/^--Debug/ ) {
4923
            $PROJECTS{$proj}{'Debug'} = 1;
4924
 
4925
        } elsif ( m/^--Prod/ ) {
4926
            $PROJECTS{$proj}{'Prod'} = 1;
4927
 
267 dpurdie 4928
        } elsif ( m/^--(Package|Install)ProgDebug=(.*)/ ) {
4929
            _PackageFromProject( $1, $proj, $basedir,'Prog', 'D', $2 );
227 dpurdie 4930
 
267 dpurdie 4931
        } elsif ( m/^--(Package|Install)Prog(Prod)*=(.*)/ ) {
4932
            _PackageFromProject( $1, $proj, $basedir, 'Prog', 'P', $3 );
227 dpurdie 4933
 
267 dpurdie 4934
        } elsif ( m/^--(Package)LibDebug=(.*)/ ) {
4935
            _PackageFromProject( $1, $proj, $basedir, 'Lib', 'D', $2 );
227 dpurdie 4936
 
267 dpurdie 4937
        } elsif ( m/^--(Package)Lib(Prod)*=(.*)/ ) {
4938
            _PackageFromProject( $1, $proj, $basedir, 'Lib', 'P', $3 );
227 dpurdie 4939
 
267 dpurdie 4940
        } elsif ( m/^--(Package)SharedLibDebug=(.*)/ ) {
4941
            _PackageFromProject( $1, $proj, $basedir, 'Lib', 'D', $2 );
227 dpurdie 4942
 
267 dpurdie 4943
        } elsif ( m/^--(Package)SharedLib(Prod)*=(.*)/ ) {
4944
            _PackageFromProject( $1, $proj, $basedir, 'Lib', 'P', $3 );
227 dpurdie 4945
 
267 dpurdie 4946
        } elsif ( m/^--(Package)Hdr=(.*)/ ) {
4947
            _PackageFromProject( $1, $proj, $basedir, 'Hdr', undef, $2 );
227 dpurdie 4948
 
267 dpurdie 4949
        } elsif ( m/^--(Package)File=(.*)/ ) {
4950
            _PackageFromProject( $1, $proj, $basedir, 'File', undef, $2 );
227 dpurdie 4951
 
267 dpurdie 4952
        } elsif ( m/^--(Package)Tool(Prod)*=(.*)/ ) {
4953
            _PackageFromProject( $1, $proj, $basedir, 'Tool', 'P', $3 );
241 dpurdie 4954
 
267 dpurdie 4955
        } elsif ( m/^--(Package)ToolDebug=(.*)/ ) {
4956
            _PackageFromProject( $1, $proj, $basedir, 'Tool', 'D', $2 );
241 dpurdie 4957
 
267 dpurdie 4958
        } elsif ( m/^--(Package|Install)/ ) {
4959
            Error("MakeProject. Unknown $1 option: $_");
227 dpurdie 4960
 
4961
        } else {
4962
            push @tool_options, $_;
4963
        }
4964
    }
4965
 
4966
    #
4967
    #   Save the information
4968
    #
4969
    $PROJECTS{$proj}{'options'} = \@tool_options;
4970
    $PROJECTS{$proj}{'name'} = $proj;
4971
    $PROJECTS{$proj}{'project'} = $project;
4972
    $PROJECTS{$proj}{'basedir'} = $basedir;
4973
    UniquePush (\@PROJECTS_ORDER, $proj);
4974
 
4975
    #
4976
    #   Validate some of the arguments
4977
    #
4978
    Error ("Makeproject. Conflicting options --Debug and --Prod" )
4979
        if ( $PROJECTS{$proj}{'Debug'}  && $PROJECTS{$proj}{'Prod'} );
4980
}
4981
 
4982
#-------------------------------------------------------------------------------
4983
# Function        : _PackageFromProject
4984
#
4985
# Description     : Save Packaged data from the project
4986
#
267 dpurdie 4987
# Inputs          : $tgt        - Install or Package
4988
#                   $proj       - Name of the project
227 dpurdie 4989
#                   $base       - Base directory of files
4990
#                   $etype      - Type of Package (Progs, Libs, ... )
4991
#                   $type       - Debug or Production or both
4992
#                   $items      - Item to add. It may be comma seperated
4993
#
267 dpurdie 4994
my %PackageToData = ( 'Package' =>
4995
                        { 'Hdr'   => \%PACKAGE_HDRS,
4996
                          'Lib'   => \%PACKAGE_LIBS,
4997
                          'Prog'  => \%PACKAGE_PROGS,
4998
                          'File'  => \%PACKAGE_FILES,
4999
                          'Tool'  => \%PACKAGE_FILES,
5000
                          '_BASE' => 'PBase',
5001
                        },
5002
                      'Install' =>
5003
                        { 'Hdr'   => \%INSTALL_HDRS,
5004
                          'Lib'   => \%INSTALL_LIBS,
5005
                          'Prog'  => \%INSTALL_PROGS,
5006
                          'File'  => undef,
5007
                          'Tool'  => undef,
5008
                          '_BASE' => 'IBase',
5009
                        },
227 dpurdie 5010
                    );
5011
 
5012
sub _PackageFromProject
5013
{
267 dpurdie 5014
    my( $tgt, $proj, $base, $etype, $type, $items ) = @_;
227 dpurdie 5015
    my $subdir = '';
5016
 
5017
    #
267 dpurdie 5018
    #   Sanity test
5019
    #
5020
    $type = '' unless ( $type );
5021
    Error ("INTERNAL. Bad packaging option: $tgt")   unless ( exists $PackageToData{$tgt} );
5022
    Error ("INTERNAL. Bad packaging option: $etype") unless ( exists $PackageToData{$tgt}{$etype} );
5023
    Error ("Unsupported packaging combination: $tgt$etype$type=$items") unless ( defined $PackageToData{$tgt}{$etype} );
5024
 
5025
    #
5026
    #   Determine the index into the 'PackageInfo' structure
5027
    #   This provides the symbolic name for the target package path
5028
    #   for Package or Install
5029
    #
5030
    #   The key '_BASE' is internal. Used only to provide this information
5031
    #
5032
    my $tbase = $PackageToData{$tgt}{'_BASE'};
5033
 
5034
    #
227 dpurdie 5035
    #   Process options
5036
    #
5037
    foreach my $item ( split (/,/, $items ) )
5038
    {
5039
        next unless ( $item =~ m/^--/ );
5040
        if ( $item =~ m/^--Subdir=(.*)/ )
5041
        {
5042
            $subdir = '/' . $1;
5043
            $subdir =~ s~//~/~g;
5044
            $subdir =~ s~/$~~g;
5045
        }
5046
        else
5047
        {
5048
            Warning( "MakeProject: Unknown packaging option ignored: $_" );
5049
        }
5050
    }
5051
 
5052
    #
5053
    #   Process files
5054
    #
5055
    foreach my $item ( split (/,/, $items ) )
5056
    {
5057
        next if ( $item =~ m/^--/ );
5058
 
267 dpurdie 5059
        my $tdir = $PackageInfo{$etype}{$tbase} . $PackageInfo{$etype}{'Dir'} . $subdir ;
227 dpurdie 5060
        my $fname = StripDir( $item );
5061
        my $target = $tdir . '/' . $fname;
5062
 
5063
        $item = "$base/$item" if ( $base );
5064
 
5065
        #
5066
        #   Do not use $(GBE_TYPE) in the target name
5067
        #   The existing package mechanism does not handle different
5068
        #   production and debug file naming mechanism, whereas the project
5069
        #   must. Convert $(GBE_TYPE) into P or D to ensure uniquness
5070
        #
5071
        $target =~ s~\$\(GBE_TYPE\)~$type~ if ($type);
5072
 
5073
        #
5074
        #   Create a PACKAGE entry suitable for processing by the normal packaging
5075
        #   routines. This is complicated because the Projects do not adhere to
267 dpurdie 5076
        #   the JATS file name conventions
227 dpurdie 5077
        #
5078
        my %package_entry;
5079
        $package_entry{'src'}   = $item;
5080
        $package_entry{'dir'}   = $tdir;
267 dpurdie 5081
        $package_entry{'set'}   = 'ALL' if ($tgt eq 'Package');
227 dpurdie 5082
        $package_entry{'type'}  = $type if ($type);
5083
 
267 dpurdie 5084
        $PackageToData{$tgt}{$etype}->{$target} = {%package_entry};
227 dpurdie 5085
    }
5086
}
5087
 
5088
#-------------------------------------------------------------------------------
5089
# Function        : MakeAnt
5090
#
5091
# Description     : A nasty directive to create JAR files via ANT
5092
#                   There are several limitations
5093
#                   This is closely related to the MakeProject directive
5094
#
5095
#
5096
# Inputs          : Platform            - Active platform
5097
#                   buildfile           - Name of the build.xml file
5098
#                   Options             - A few options
5099
#                                         --Jar=file
5100
#                                               Generated JAR file(s)
5101
#                                         --GeneratedFile=file
5102
#                                               Other generated files
5103
#                                               Used to flag JNI that must
5104
#                                               Occur early
5105
#                                          --AutoTest=<name>
5106
#                                               Supports unitAutomated unit test
5107
#                                               by calling build target <name>
5108
#                                          --UnitTest=<name>
5109
#                                               Supports unit test
5110
#                                               by calling build target <name>
5111
#                                          --PackageBase
5112
#                                               Provides path to base of all packages
5113
#
5114
# Returns         :
5115
#
5116
our %JAR_FILES;
5117
sub MakeAnt
5118
{
5119
    my( $platforms, $proj, @elements ) = @_;
5120
 
5121
    Debug2( "MakeAnt($platforms, $proj, @elements)" );
5122
 
5123
    return if ( ! ActivePlatform($platforms) );
5124
 
5125
    #
5126
    #   Sanity test
5127
    #
5128
    Error ("MakeAnt: build.xml name not defined") unless ( $proj );
5129
 
5130
    #
5131
    #   Take the project name and convert it into a full path
5132
    #
5133
    my $project;
5134
    $project = MakeSrcResolve ( $proj );
5135
    $proj = StripDir( $project );
237 dpurdie 5136
    Error ("Build File Not found: $project") unless ( -f $project );
227 dpurdie 5137
 
5138
    my $basedir = StripFileExt( $project );
5139
 
5140
    #
5141
    #   Collect user arguments
5142
    #   They are all processed within the toolset
5143
    #
5144
    my @tool_options;
5145
    my @generated;
5146
    my $unit_tests;
5147
    my $auto_tests;
5148
    my $package_base;
5149
 
5150
    foreach ( @elements )
5151
    {
5152
        if ( m/^--Debug/ ) {
5153
            $PROJECTS{$proj}{'Debug'} = 1;
5154
 
5155
        } elsif ( m/^--Prod/ ) {
5156
            $PROJECTS{$proj}{'Prod'} = 1;
5157
 
5158
        } elsif ( m/^--Jar=(.*)/ ) {
5159
            my $tgt = $1;
5160
               $tgt = "$basedir/$tgt" if ( $basedir );
5161
            my $fn = StripDir( $1 );
5162
            $JAR_FILES{$fn} = $tgt;
5163
            GenerateSrcFile( 0, $tgt );
5164
 
5165
        } elsif ( m/^--GeneratedFile=(.*)/ ) {
5166
            my $tgt = $1;
5167
            $tgt = "$basedir/$tgt" if ( $basedir );
5168
            push @generated, $tgt;
5169
            GenerateSrcFile( 2, $tgt );
5170
 
5171
        } elsif ( m/^--UnitTest=(.*)/ ) {
5172
            $unit_tests = $1
5173
 
5174
        } elsif ( m/^--AutoTest=(.*)/ ) {
5175
            $auto_tests = $1
5176
 
5177
        } elsif ( m/^--PackageBase/ ) {
5178
            $package_base = 1;
5179
 
5180
 
5181
        } elsif ( m/^--/ ) {
5182
            Error("MakeAnt. Unknown option ignored: $_");
5183
 
5184
        } else {
5185
            push @tool_options, $_;
5186
        }
5187
    }
5188
 
5189
    #
5190
    #   Extend option arguments to include the base dir of packages
5191
    #   Create definitions of the form PACKAGE_<name>
5192
    #
5193
    for my $entry (@{$::ScmBuildPkgRules{$ScmPlatform} })
5194
    {
5195
        next unless ( $entry->{'TYPE'} eq 'link' );
5196
        my $dir = $entry->{'ROOT'};
5197
        my $name = $entry->{'NAME'};
5198
        unless ( $package_base )
5199
        {
5200
            $dir .= '/jar';
5201
            next unless ( -d $dir );
5202
        }
5203
        push @tool_options, "-DPACKAGE_$name=$dir";
5204
    }
5205
    #
5206
    #   Extend options to include the base dir of the created package
5207
    #   Allows careful use for direct packaging of artifacts
5208
    #
5209
    push @tool_options, '-DPACKAGEDIR=$(PWD)/$(PKGDIR)';
5210
 
5211
    #
5212
    #   Save the information
5213
    #
5214
    $PROJECTS{$proj}{'options'} = \@tool_options;
5215
    $PROJECTS{$proj}{'generated'} = \@generated if ( @generated );
5216
    $PROJECTS{$proj}{'name'}    = $proj;
5217
    $PROJECTS{$proj}{'project'} = $project;
5218
    $PROJECTS{$proj}{'basedir'} = $basedir;
5219
    $PROJECTS{$proj}{'type'}    = 'ant';
5220
    $PROJECTS{$proj}{'unittest'} = $unit_tests if ( $unit_tests );
5221
    $PROJECTS{$proj}{'autotest'} = $auto_tests if ( $auto_tests );
5222
    UniquePush (\@PROJECTS_ORDER, $proj);
5223
 
5224
    $TESTS_TO_AUTORUN = 1 if ( $auto_tests );
263 dpurdie 5225
    $TESTS_TO_RUN = 1 if ( $unit_tests || $auto_tests );
227 dpurdie 5226
 
5227
    #
5228
    #   Validate some of the arguments
5229
    #
5230
    Error ("MakeAnt. Conflicting options --Debug and --Prod" )
5231
        if ( $PROJECTS{$proj}{'Debug'}  && $PROJECTS{$proj}{'Prod'} );
5232
}
5233
 
5234
###############################################################################
5235
#
5236
#   Installation/Packaging util functions
5237
#
5238
#-------------------------------------------------------------------------------
5239
# Function        : __TargetDir
5240
#
5241
# Description     : Internal function to process common arguments for
5242
#                   the PackageXxx directives
5243
#
5244
# Inputs          : flags           - Indicate how to handle this argument
5245
#                   base            - Base directory for this type of package
5246
#                   argument        - Argument to process
5247
#                   pdir            - Reference to resultant directory
5248
#                   ptype           - Reference to resultant type (P or D)(optional)
5249
#
5250
# Returns         : 0               - Agument not consumed
5251
#                   1               - Argument consumed
5252
#                   2               - Skip this directive
5253
#
5254
my $T_TYPE  = 0x0001;                           # Postfix GBE_TYPE
5255
my $T_PKG   = 0x0002;                           # Special --Dir handling
5256
my $T_MACH  = 0x0004;                           # Allow --Machine too
5257
my $T_GBE   = 0x0008;                           # Allow --Gbe too
5258
my $T_FILE  = 0x0010;                           # Suffix or prefix subdir
5259
 
5260
sub __TargetDir
5261
{
5262
    my( $flags, $base, $argument, $pdir, $ptype ) = @_;
5263
    my $dir  = "";
5264
    my $consumed = 0;
5265
 
5266
    #
5267
    #   Generate basic parts
5268
    #   Note Product will default to Platform
5269
    #
5270
    my $str_platform = '$(GBE_PLATFORM)';
5271
    my $str_product = $ScmProduct ? '$(GBE_PRODUCT)' : '$(GBE_PLATFORM)';
5272
    my $str_target = '$(GBE_TARGET)';
5273
    my $str_common = '$(GBE_OS_COMMON)';
5274
 
5275
    my $str_common_avail = 0;
5276
       $str_common_avail = 1 if ( exists( $::BUILDINFO{$ScmPlatform}{OS_COMMON} ));
5277
 
5278
 
5279
    #
5280
    #   Add requested suffix
5281
    #
5282
    if ($flags & $T_TYPE)
5283
    {
5284
        $str_platform .= '$(GBE_TYPE)';
5285
        $str_product  .= '$(GBE_TYPE)';
5286
        $str_target   .= '$(GBE_TYPE)';
5287
        $str_common   .= '$(GBE_TYPE)';
5288
    }
5289
 
5290
    #
5291
    #   Process the argument
5292
    #
5293
    $_ = $argument;
5294
    if ( /^--Debug/ ) {                         # In the Debug build only
5295
        if ( $ptype ) {
5296
            $$ptype = "D";
5297
            $consumed = 1;
5298
        }
5299
 
5300
    } elsif ( /^--Prod$/ || /^--Production$/ ) { # In the Production build only
5301
        if ( $ptype ) {
5302
            $$ptype = "P";
5303
            $consumed = 1;
5304
        }
5305
 
5306
    } elsif (/^--Prefix=(.*)/) {                # Prefix with subdir
5307
        $dir = "$base/$1";
5308
 
5309
    } elsif (/^--Subdir=(.*)/) {                # same as 'prefix'
5310
        $dir = "$base/$1";
5311
 
5312
    } elsif (/^--Platform$/) {                  # Platform installation
5313
        $dir = "$base/$str_platform";
5314
 
5315
    } elsif (/^--Platform=(.*?),(.*)/) {        # prefix and suffix with platform specific subdir
5316
        $dir = "$base/$1/$str_platform/$2";
5317
 
5318
    } elsif (/^--Platform=(.*)/) {              # prefix with platform specific subdir
5319
        if ($flags & $T_FILE) {
5320
            $dir = "$base/$1/$str_platform";
5321
        } else {
5322
            $dir = "$base/$str_platform/$1";
5323
        }
5324
 
5325
    } elsif (/^--Product$/) {                   # Product installation
5326
        $dir = "$base/$str_product";
5327
 
5328
    } elsif (/^--Product=(.*?),(.*)/) {         # prefix and suffix with product specific subdir
5329
        $dir = "$base/$1/$str_product/$2";
5330
 
5331
    } elsif (/^--Product=(.*)/) {               # prefix with product specific subdir
5332
        if ($flags & $T_FILE) {
5333
            $dir = "$base/$1/$str_product";
5334
        } else {
5335
            $dir = "$base/$str_product/$1";
5336
        }
5337
 
5338
    } elsif (/^--Target$/) {                    # Target installation
5339
        $dir = "$base/$str_target";
5340
 
5341
    } elsif (/^--Target=(.*?),(.*)/) {          # prefix and suffix with target specific subdir
5342
        $dir = "$base/$1/$str_target/$2";
5343
 
5344
    } elsif (/^--Target=(.*)/) {                # prefix with target specific subdir
5345
        if ($flags & $T_FILE) {
5346
            $dir = "$base/$1/$str_target";
5347
        } else {
5348
            $dir = "$base/$str_target/$1";
5349
        }
5350
 
5351
    } elsif (/^--OsCommon/) {
5352
 
5353
        unless ( $str_common_avail ) {
5354
            Warning("Packaging option --OsCommon not supported on this platform($ScmPlatform). Directive skipped");
5355
            $consumed = 2;
5356
 
5357
        } elsif (/^--OsCommon$/) {                  # OS installation
5358
            $dir = "$base/$str_common";
5359
 
5360
        } elsif (/^--OsCommon=(.*?),(.*)/) {        # prefix and suffix with target specific subdir
5361
            $dir = "$base/$1/$str_common/$2";
5362
 
5363
        } elsif (/^--OsCommon=(.*)/) {              # prefix with target specific subdir
5364
            if ($flags & $T_FILE) {
5365
                $dir = "$base/$1/$str_common";
5366
            } else {
5367
                $dir = "$base/$str_common/$1";
5368
            }
5369
        }
5370
 
5371
    } elsif (/^--Derived=(.*?),(.*?),(.*)/) {   # Derived target + prefix + subdir
5372
        $dir = "$base/$2/$1_$str_platform/$3";
5373
 
5374
    } elsif (/^--Derived=(.*?),(.*)/) {         # Derived target + subdir
5375
        if ($flags & $T_FILE) {
5376
            $dir = "$base/$2/$1_$str_platform";
5377
        } else {
5378
            $dir = "$base/$1_$str_platform/$2";
5379
        }
5380
 
5381
    } elsif (/^--Derived=(.*)/) {               # Derived target
5382
        $dir = "$base/$1_$str_platform";
5383
 
5384
    } elsif ($flags & $T_MACH && /^--Machine(([=])(.*))?$/) {   # Allow Machine and Machine=xxx specfic target
5385
        #
5386
        #   Special: Append machine type to user dir
5387
        #            Intended to create tools/bin/win32 and tools/bin/sparc directories
5388
        my $path = ( defined( $3) ) ? "/$3" : "";
5389
        $dir = "$base$path/\$(GBE_HOSTMACH)";
5390
 
5391
    } elsif ($flags & $T_GBE && /^--Gbe(([=])(.*))?$/) {   # Allow Gbe and Gbe=xxx specfic target
5392
        my $path = ( defined( $3) ) ? "/$3" : "";
5393
        $dir = "$base/gbe$path";
5394
 
5395
    } elsif (/^--Dir=(.*)/) {                   # prefix with target specific subdir
5396
        Error ('Packaging directive with --Dir option does not specify a directory.',
5397
               'Possible bad use of option of the form:--Dir=$xxx',
5398
               'Note: Use of package.pl and this construct is deprecated') unless ( $1 );
241 dpurdie 5399
        my $udir = $1;
5400
 
5401
        #
5402
        #   Remove leading ./
5403
        #   Check for leading ../
5404
        while ( $udir =~ s{^\./}{} ){};
5405
 
5406
        if ( $udir =~ m~^\.\./~ )
5407
        {
5408
            Warning("Packaging directive with --Dir option contains relative path (removed)", "Option: $_");
5409
            while ( $udir =~ s{^\.\./}{} ){};
5410
        }
227 dpurdie 5411
        if ($flags & $T_PKG) {
241 dpurdie 5412
            $dir = __PkgDir( $udir );
227 dpurdie 5413
        } else {
241 dpurdie 5414
            $dir = "\$(LOCALDIR)/$udir";
227 dpurdie 5415
        }
5416
    }
5417
 
5418
    return ($consumed) if ($dir eq "");
5419
    $dir =~ s~//~/~g;
5420
    $dir =~ s~/$~~;
5421
    $$pdir = $dir;
5422
    return (1);
5423
}
5424
 
5425
 
5426
#   __PkgDir ---
5427
#       Convert --Dir Package directives, removing leading subdir if
5428
#       matching the global $Pbase value.
5429
#
5430
#       Required as PKGDIR has the value 'GBE_ROOT/pkg/$Pbase'.
5431
#       Required to maintain compatability with older (package.pl) constructs
5432
#..
5433
 
5434
sub __PkgDir
5435
{
5436
    my( $dir ) = @_;
5437
    my $org = $dir;
5438
 
245 dpurdie 5439
    $dir =~ s~^\Q$::Pbase\E[/]?~~;
227 dpurdie 5440
    Debug2( "  PkgDir: converted \"$org\" to \"$dir\"" );
5441
 
5442
    $dir = "\$(PKGDIR)/$dir";
5443
    return $dir;
5444
}
5445
 
5446
 
5447
#   getMajorMinor ---
5448
#       Just a little help to deal with major/minor stuff for shared libs -
5449
#       given the name of the library as the argument, split out major and
5450
#       minor parts and return the basename, i.e name without major and minor
5451
#       and the pair of major and minor.
5452
#..
5453
 
5454
sub getMajorMinor ($)
5455
{
5456
    my @bits = split ('\.', $_[0]);
5457
    my $stop;
5458
    my $major;
5459
    my $minor;
5460
 
5461
    if ( $#bits > 2 )
5462
    {
5463
        $stop = $#bits - 2;
5464
        $major = $bits[$#bits-1];
5465
        $minor = $bits[$#bits];
5466
    }
5467
    elsif ($#bits > 1)
5468
    {
5469
        $stop = $#bits-1;
5470
        $major = $bits[$#bits];
5471
        $minor=0;
5472
    }
5473
    else
5474
    {
5475
        $stop = $#bits; $major = 1; $minor = 0;
5476
    }
5477
 
5478
    my $base = $bits[0];
5479
    for ( my $i=1; $i <= $stop; $i++ ) {
5480
        $base = join ('.', $base, $bits[$i]);
5481
    }
5482
 
5483
    return ($base, $major, $minor);
5484
}
5485
 
5486
###############################################################################
5487
#
5488
#   Installation
5489
#
5490
 
5491
sub InstallHdr
5492
{
5493
    my( $platforms, @elements ) = @_;
5494
    my( $base, $dir, $srcfile, $full, $abs, $strip, $package );
5495
    my( $len, $name, $basename );
5496
 
5497
    Debug2( "InstallHdr($platforms, @elements)" );
5498
 
5499
    return if ( ! ActivePlatform($platforms) );
5500
    Warning ("InstallHdr: Needs local directory specified in build.pl") unless ( $::ScmLocal );
5501
 
5502
#.. Arguments
5503
#
5504
    $base = $PackageInfo{'Hdr'}{'IBase'};       # Base of target
5505
    $dir = $base . $PackageInfo{'Hdr'}{'Dir'};  # Installation path (default)
5506
    $full = $abs = $strip = 0;
5507
 
5508
    foreach $_ ( @elements )
5509
    {
5510
                                                # Standard targets
5511
        my $rv = __TargetDir(0, $base, $_, \$dir);
5512
        next if ( $rv == 1 );
5513
        return if ( $rv == 2 );
5514
 
5515
        if (/^--Full/) {                        # using full (resolved) path
5516
            $full = 1;
5517
 
5518
        } elsif (/^--Abs$/) {                   # Override SRCS() checks
5519
            $abs = 1;
5520
 
5521
        } elsif (/^--Strip$/) {                 # Strip path from source files
5522
            $strip = 1;
5523
 
5524
                                                # Package
5525
        } elsif (/^--Package$/ || /^--Package=(.*)/) {
5526
            $package = 1;
5527
 
5528
        } elsif (/^--(.*)/) {
5529
            Message( "InstallHdr: unknown option $_ -- ignored\n" );
5530
        }
5531
    }
5532
 
5533
#.. Files
5534
#
5535
    foreach $_ ( @elements )
5536
    {
5537
        my %package_entry;
5538
        if ( ! /^--(.*)/ )
5539
        {
5540
            $name = $_;
5541
            $basename = StripDir( $name );
5542
            if ( $full )
5543
            {
5544
                if ($abs || !($srcfile = $SRCS{ $basename }) ||
5545
                        ($len = rindex($srcfile, "/")) == -1)
5546
                {
5547
                    $dir = $base;
5548
                    $srcfile = $name;
5549
                }
5550
                else
5551
                {
5552
                    if ( m#^\./# ) {
5553
                        $dir = substr($srcfile, 3, $len);
5554
                    } else {
5555
                        $dir = substr($srcfile, 0, $len);
5556
                    }
5557
                    $dir = "$base/$dir";
5558
                }
5559
            }
5560
            else
5561
            {
5562
                if ($abs || ! ($srcfile = $SRCS{ $basename })) {
5563
                    $srcfile = $name;
5564
                }
5565
            }
5566
 
5567
            $name = $basename
5568
                if ( $strip );
5569
 
5570
            Debug( "InstallHdr( $dir/$name, src: $srcfile, dest: $dir)" );
5571
 
5572
            $package_entry{'src'} = $srcfile;
5573
            $package_entry{'dir'} = StripFileExt( "$dir/$name" );
5574
            $INSTALL_HDRS{ "$dir/$name" } = {%package_entry};
5575
        }
5576
    }
5577
 
5578
#.. Package
5579
#
5580
    PackageHdr( @_ )                            # auto package
5581
        if ( $package );
5582
}
5583
 
5584
 
5585
sub InstallLib
5586
{
5587
    my( $platforms, @elements ) = @_;
5588
    my( $base, $dir, $package );
5589
    my( $lib, $strip );
5590
 
5591
    Debug2( "InstallLib($platforms, @elements)" );
5592
 
5593
    return if ( ! ActivePlatform($platforms) );
5594
    Warning ("InstallLib: Needs local directory specified in build.pl") unless ( $::ScmLocal );
5595
 
5596
#.. Arguments
5597
#
5598
    $base = $PackageInfo{'Lib'}{'IBase'};       # Base of target
5599
    $dir = $base . $PackageInfo{'Lib'}{'Dir'};  # Installation path (default)
5600
 
5601
    foreach $_ ( @elements )
5602
    {
5603
                                                # Standard targets
5604
        my $rv = __TargetDir(0, $base, $_, \$dir);
5605
        next if ( $rv == 1 );
5606
        return if ( $rv == 2 );
5607
 
5608
        if (/^--Package$/ || /^--Package=(.*)/) {
5609
            $package = 1;
5610
 
5611
        } elsif (/^--Strip$/) {                 # Strip path from source files
5612
            $strip = 1;
5613
 
5614
        } elsif (/^--(.*)/) {
5615
            Message( "InstallLib: unknown option $_ -- ignored\n" );
5616
        }
5617
    }
5618
 
5619
#.. Files
5620
#
5621
    foreach $_ ( @elements )
5622
    {
5623
        my %package_entry;
5624
        if ( ! /^--(.*)/ )
5625
        {
5626
            $_ = basename ($_)
5627
                if ( $strip );
5628
 
5629
            if ( $ScmTargetHost eq "Unix" ) {
5630
                $lib = "lib$_";                 # Prefix "lib" ....
5631
                $lib =~ s/^liblib/lib/;         # @LIBS already has lib added
5632
            } else {
5633
                $lib = $_;
5634
            }
5635
 
5636
            if ( exists $SHLIB_VER { $lib } )
5637
            {
5638
                Debug( "InstallLib( $dir/$lib\$(GBE_TYPE).$::so, " .
5639
                    "src: \$(LIBDIR)/$lib\$(GBE_TYPE).$::so, dest: $dir)" );
5640
 
5641
                #
5642
                #   Create a "placekeeper" entry within $INSTALL_SHLIBS
5643
                #   The exact format of the name of the shared library is
5644
                #   toolset specific. Create an entry to allow the toolset
5645
                #   to extend the packaging information when the shared library
5646
                #   recipe is constructed.
5647
                #
5648
                my $ver = $SHLIB_VER { $lib };
5649
                my $name = "$dir/$lib.$ver.PlaceKeeper";
5650
 
5651
 
5652
                push @{$SHLIB_INS{$lib}}, $name;
5653
 
5654
                $package_entry{'placekeeper'} = 1;
5655
                $package_entry{'version'} = $ver;
5656
                $package_entry{'lib'} = $lib;
5657
                $package_entry{'dir'} = $dir;
5658
                $INSTALL_SHLIBS{$name} = {%package_entry};
5659
            }
5660
 
5661
            if ( my $libfile = $SRCS{$lib} )
5662
            {
5663
                #
5664
                #   Allow the user to package a sourced file as a library
5665
                #
5666
                Debug( "InstallLib( $dir/$lib, " .
5667
                    "src: $libfile, dest: $dir )" );
5668
 
5669
                push @{$LIB_INS{$lib}}, "$dir/$lib";
5670
 
5671
                $package_entry{'src'} = "$libfile";
5672
                $package_entry{'dir'} = $dir;
5673
 
5674
                $INSTALL_LIBS{ "$dir/$lib" } = {%package_entry};
5675
            }
5676
            elsif ( exists $LIB_OBJS { $lib } || ! exists $SHLIB_VER { $lib } )
5677
            {
5678
                Debug( "InstallLib( $dir/$lib\$(GBE_TYPE).$::a, " .
5679
                    "src: \$(LIBDIR)/$lib\$(GBE_TYPE).$::a, dest: $dir )" );
5680
 
5681
                push @{$LIB_INS{$lib}}, "$dir/$lib\$(GBE_TYPE).$::a";
5682
 
5683
                $package_entry{'src'} = "\$(LIBDIR)/$lib\$(GBE_TYPE).$::a";
5684
                $package_entry{'dir'} = $dir;
5685
 
5686
                $INSTALL_LIBS{ "$dir/$lib\$(GBE_TYPE).$::a" } = {%package_entry};
5687
            }
5688
        }
5689
    }
5690
 
5691
#.. Package
5692
#
5693
    PackageLib( @_ )                            # auto package
5694
        if ( $package );
5695
}
5696
 
5697
 
5698
sub InstallJar
5699
{
5700
    my( $platforms, @elements ) = @_;
5701
    my( $base, $dir, $package );
5702
    my( $jar );
5703
 
5704
    Debug2( "InstallJar($platforms, @elements)" );
5705
 
5706
    return if ( ! ActivePlatform($platforms) );
5707
    Warning ("InstallJar: Needs local directory specified in build.pl") unless ( $::ScmLocal );
5708
 
5709
#.. Arguments
5710
#
5711
    $base = $PackageInfo{'Jar'}{'IBase'};       # Base of target
5712
    $dir = $base . $PackageInfo{'Jar'}{'Dir'};  # Installation path (default)
5713
 
5714
    foreach $_ ( @elements )
5715
    {
5716
                                                # Standard targets
5717
        my $rv = __TargetDir(0, $base, $_, \$dir);
5718
        next if ( $rv == 1 );
5719
        return if ( $rv == 2 );
5720
 
5721
        if (/^--Package$/ || /^--Package=(.*)/) {
5722
            $package = 1;
5723
 
5724
        } elsif (/^--(.*)/) {
5725
            Message( "InstallJar: unknown option $_ -- ignored\n" );
5726
        }
5727
    }
5728
 
5729
 
5730
#.. Files
5731
#
5732
    foreach $_ ( @elements )
5733
    {
5734
        my %package_entry;
5735
        if ( ! /^--(.*)/ )
5736
        {
5737
            $jar = $_;
5738
            my $src;
5739
            my $dest;
5740
 
5741
            if ( $JAR_FILES{$jar} )
5742
            {
5743
                $src = $JAR_FILES{$jar};
5744
                $dest = $jar;
5745
            }
5746
            else
5747
            {
5748
                $src = "\$(CLSDIR)/$jar\$(GBE_TYPE).jar";
5749
                $dest = "$jar\$(GBE_TYPE).jar";
5750
            }
5751
 
5752
 
5753
            Debug( "InstallJar( $dir/$dest, " .
5754
                "src: $src, dest: $dir)" );
5755
 
5756
            $package_entry{'src'} = $src;
5757
            $package_entry{'dir'} = $dir;
5758
            $INSTALL_CLSS{ "$dir/$dest" } = {%package_entry};
5759
 
5760
        }
5761
    }
5762
 
5763
#.. Package
5764
#
5765
    PackageJar( @_ )                            # auto package
5766
        if ( $package );
5767
}
5768
 
5769
 
5770
sub InstallProg
5771
{
5772
    my( $platforms, @elements ) = @_;
5773
    my( $base, $dir, $package );
5774
    my( $prog );
5775
 
5776
    Debug2( "InstallProg($platforms, @elements)" );
5777
 
5778
    return if ( ! ActivePlatform($platforms) );
5779
    Warning ("InstallProg: Needs local directory specified in build.pl") unless ( $::ScmLocal );
5780
 
5781
#.. Arguments
5782
#
5783
    $base = $PackageInfo{'Prog'}{'IBase'};       # Base of target
5784
    $dir = $base . $PackageInfo{'Prog'}{'Dir'};  # Installation path (default)
5785
 
5786
    foreach $_ ( @elements )
5787
    {
5788
                                                # Standard targets
5789
        my $rv = __TargetDir($T_TYPE, $base, $_, \$dir);
5790
        next if ( $rv == 1 );
5791
        return if ( $rv == 2 );
5792
 
5793
        if (/^--Package$/ || /^--Package=(.*)/) {
5794
            $package = 1;
5795
 
5796
        } elsif (/^--(.*)/) {
5797
            Message( "InstallProg: unknown option $_ -- ignored\n" );
5798
        }
5799
    }
5800
 
5801
#.. Files
5802
#
5803
    foreach $_ ( @elements )
5804
    {
5805
        my %package_entry;
5806
        if ( ! /^--(.*)/ )
5807
        {
5808
            my $ext = "";
5809
            $prog = $_;
5810
 
5811
            #
5812
            #   If the named target is a program then append the correct
5813
            #   extension. Otherwise assume that the target is either a script
5814
            #   or a some other file - and don't append an extension
5815
            #
5816
            #   A program may not have any object files, only libraries
5817
            #
5818
            $ext = $::exe
261 dpurdie 5819
                if ( exists $PROGS{$prog} );
227 dpurdie 5820
 
5821
            #
5822
            #   A "file" that is specified with a "Src" directive may be
5823
            #   installed as though it were a program
5824
            #
5825
            my $progfile;
5826
            $progfile = "\$(BINDIR)/$prog$ext"
5827
                unless ( $progfile = $SRCS{$prog} );
5828
 
5829
            Debug( "InstallProg( $dir/$prog$ext, " .
5830
                 "src: $progfile, dest: $dir)" );
5831
 
5832
            push @{$PROG_INS{$prog}}, "$dir/$prog$ext";
5833
 
5834
            $package_entry{'src'} = $progfile;
5835
            $package_entry{'dir'} = $dir;
5836
            $INSTALL_PROGS{ "$dir/$prog$ext" } = {%package_entry};
5837
        }
5838
    }
5839
 
5840
#.. Package
5841
#
5842
    PackageProg( @_ )                           # auto package
5843
        if ( $package );
5844
}
5845
 
5846
 
5847
###############################################################################
5848
#
5849
#   Packaging
5850
#
5851
sub PackageDist
5852
{
5853
    my( $name, @elements ) = @_;
5854
 
5855
    Debug2( "PackageDist($name, @elements)" );
5856
 
5857
    foreach ( @elements )
5858
    {
5859
    #.. Distribution sets
5860
    #
5861
        HashJoin( \%PACKAGE_DIST, $;, $name, "$_" );
5862
 
5863
    #.. Summary of distribution sets
5864
    #
267 dpurdie 5865
        $PACKAGE_SETS{ $_ }{'TAG'} = 1
5866
            if ( ! exists $PACKAGE_SETS{ $_ }{'TAG'} );
227 dpurdie 5867
    }
5868
}
5869
 
5870
sub PackageFile
5871
{
5872
    my( $platforms, @elements ) = @_;
5873
    my( $base, $dir, $full, $abs, $path, $dist, $strip, $exefile, $type );
5874
    my( $name, $basename, $len, $srcfile );
5875
    my( $dir_tree, @dir_tree_exclude, @dir_tree_include, $strip_base );
5876
 
5877
    Debug2( "PackageFile($platforms, @elements)" );
5878
 
5879
    return if ( !$ScmPackage );                 # Packaging enabled ?
5880
    return if ( ! ActivePlatform($platforms) );
5881
 
5882
#.. Arguments
5883
#
5884
    $dist = "ALL";                                  # Default set (ALL)
5885
    $base = $PackageInfo{'File'}{'PBase'};          # Base of target
5886
    $dir = $base . $PackageInfo{'File'}{'Dir'};     # Installation path (default)
5887
    $full = $abs = 0;
5888
    $strip = 0;
5889
    $strip_base = 0;
5890
    $exefile = 0;
5891
 
5892
    foreach $_ ( @elements )
5893
    {
5894
        my $rv = __TargetDir($T_PKG|$T_MACH|$T_GBE|$T_FILE, $base, $_, \$dir, \$type);
5895
        next if ( $rv == 1 );
5896
        return if ( $rv == 2 );
5897
 
5898
        if (/^--Full/) {                        # Using full (resolved) path
5899
            $full = 1;
5900
 
5901
        } elsif (/^--Set=(.*)/) {               # Distribution set
5902
            $dist = "$1";
5903
 
5904
        } elsif (/^--Package$/) {               # Package .. call by InstallFile
5905
        } elsif (/^--Package=(.*)/) {
5906
            $dist = "$1";
5907
 
5908
        } elsif (/^--Abs$/) {                   # Override SRCS() checks
5909
            $abs = 1;
5910
 
5911
        } elsif (/^--Strip$/) {                 # Strip path from source files
5912
            $strip = 1;
5913
 
5914
        } elsif (/^--Executable$/) {            # Mark the file as executable
5915
            $exefile = "X";
5916
 
5917
        } elsif ( /^--DirTree=(.*)/ ) {
5918
            Error("DirTree. Multiple directories not allowed.") if ( $dir_tree );
5919
            $dir_tree = $1;
5920
 
5921
            Error("DirTree cannot extend outside current subtree. '..' not allowed.",
5922
                  "Directory: $dir_tree") if ( $dir_tree =~ m~\.\.~ );
5923
            Error("DirTree. Absolute paths are not allowed",
5924
                  "Directory: $dir_tree") if ( $dir_tree =~ m~^/~ || $dir_tree =~ m~^.\:~ );
5925
            Error("DirTree. Directory not found",
5926
                  "Directory: $dir_tree") unless  ( -d $dir_tree );
5927
 
5928
        } elsif ( /^--FilterOut=(.*)/ ) {
5929
            push @dir_tree_exclude, $1;
5930
 
5931
        } elsif ( /^--FilterIn=(.*)/ ) {
5932
            push @dir_tree_include, $1;
5933
 
5934
        } elsif ( /^--StripDir/ ) {
5935
            $strip_base = 1;
5936
 
5937
        } elsif (/^--(.*)/) {
5938
            Message( "PackageFile: unknown option $_ -- ignored\n" );
5939
        }
5940
    }
5941
 
5942
 
5943
    #.. DirTree expansion
5944
    #   Note: Uses REs, not simple globs
5945
    #         Use JatsLocateFiles to do the hard work
5946
    if ( $dir_tree )
5947
    {
5948
        my $search = JatsLocateFiles->new('Recurse', 'FullPath' );
5949
        $search->filter_in_re ( $_ ) foreach ( @dir_tree_include );
5950
        $search->filter_out_re( $_ ) foreach ( @dir_tree_exclude );
5951
        @elements = $search->search ( $dir_tree );
5952
        $strip_base = length( $dir_tree ) if ( $strip_base );
5953
    }
5954
 
5955
#.. Files
5956
#
5957
    foreach $_ ( @elements )
5958
    {
5959
        my %package_entry;
5960
        #
5961
        #   Special cases: Provide make-style $ escape processing.
5962
        #       Allow files with a $ in the name
5963
        #       Allow files with a space in the name
263 dpurdie 5964
        #   Only for file names that don't look like $(GBE_...) as these
5965
        #   may be generated internally
227 dpurdie 5966
        #
263 dpurdie 5967
        unless ( m~\$\(GBE_.+\)~ )
5968
        {
5969
            s~\$~\$\$~g;
5970
            s~ ~\\ ~g;
5971
        }
227 dpurdie 5972
 
5973
        if ( ! /^--(.*)/ )
5974
        {
5975
            $name = $_;
5976
            $basename = StripDir( $name );
5977
            if ( $full )
5978
            {
5979
                if ($abs || ! ($srcfile = $SRCS{ $basename }) ||
5980
                        ($len = rindex($srcfile, "/")) == -1)
5981
                {
5982
                    #
5983
                    #   Either: --Abs
5984
                    #           the file is NOT known to JATS
5985
                    #           the file is known and and it does NOT contains a "/"
5986
                    #   Result: Use simple dir and name
5987
                    #
5988
                    $dir = $base;
5989
                    $srcfile = $name;
5990
                }
5991
                else
5992
                {
5993
                    #
5994
                    #   Using Full directory path.
5995
                    #   Ensure that ProjectBase is removed as this may have
5996
                    #   been added if the file was found in a directory with it
5997
                    #
5998
                    $srcfile = $1
5999
                        if ( $srcfile =~ m~^$ProjectBase/(.*)~ );
6000
 
6001
 
6002
                    if ( m#^\./# ) {
6003
                        $dir = substr($srcfile, 3, $len);
6004
                    } else {
6005
                        $dir = substr($srcfile, 0, $len);
6006
                    }
6007
                    $dir = "$base/$dir";
6008
                }
6009
            }
6010
            else
6011
            {
6012
                if ($abs || ! ($srcfile = $SRCS{ $basename })) {
6013
                    $srcfile = $name;
6014
                }
6015
            }
6016
 
6017
            $name = $basename
6018
                if ( $strip );
6019
 
6020
            if ( $strip_base )
6021
            {
6022
                $name = substr $name, $strip_base;
6023
                $name =~ s~^/~~;
6024
            }
6025
 
6026
            $dir =~ s~//~/~g;
6027
            $dir =~ s~/$~~;
6028
 
6029
            #
6030
            #   Sanity test the source filename
6031
            #   User may have misused an option
6032
            #
6033
            if ( ( $srcfile =~ m/=/ ) || ( $srcfile =~ m/^-/ ) || ( $srcfile =~ m~/-~ )  )
6034
            {
6035
               Warning ("PackageFile: Suspect source filename: $srcfile");
6036
            }
6037
 
6038
            Debug( "PackageFile( $dir/$name, " .
6039
                "src: $srcfile, dest: $dir, dist: $dist, exe: $exefile )" );
6040
 
6041
            $package_entry{'src'} = $srcfile;
6042
            $package_entry{'dir'} = StripFileExt( "$dir/$name" );
6043
            $package_entry{'set'} = $dist;
6044
            $package_entry{'exe'} = $exefile if $exefile;
6045
            $package_entry{'type'} = $type if ( $type );
6046
 
6047
            $PACKAGE_FILES{ "$dir/$name" } = {%package_entry};
6048
        }
6049
    }
6050
}
6051
 
6052
sub PackageHdr
6053
{
6054
    my( $platforms, @elements ) = @_;
6055
    my( $base, $dir, $full, $abs, $path, $dist, $strip );
6056
    my( $name, $basename, $len, $srcfile );
6057
 
6058
    Debug2( "PackageHdr($platforms, @elements)" );
6059
 
6060
    return if ( !$ScmPackage );                 # Packaging enabled ?
6061
    return if ( ! ActivePlatform($platforms) );
6062
 
6063
#.. Arguments
6064
#
6065
    $dist = "ALL";                                  # Default set (ALL)
6066
    $base = $PackageInfo{'Hdr'}{'PBase'};           # Base of target
6067
    $dir = $base . $PackageInfo{'Hdr'}{'Dir'};      # Installation path (default)
6068
    $full = $abs = 0;
6069
    $strip = 0;
6070
 
6071
    foreach $_ ( @elements )
6072
    {
6073
        my $rv = __TargetDir($T_PKG, $base, $_, \$dir);
6074
        next if ( $rv == 1 );
6075
        return if ( $rv == 2 );
6076
 
6077
        if (/^--Full/) {                        # Using full (resolved) path
6078
            $full = 1;
6079
 
6080
        } elsif (/^--Set=(.*)/) {               # Distribution set
6081
            $dist = "$1";
6082
 
6083
        } elsif (/^--Package$/) {               # Package .. call by InstallHdr
6084
        } elsif (/^--Package=(.*)/) {
6085
            $dist = "$1";
6086
 
6087
        } elsif (/^--Abs$/) {                   # Override SRCS() checks
6088
            $abs = 1;
6089
 
6090
        } elsif (/^--Strip$/) {                 # Strip path from source files
6091
            $strip = 1;
6092
 
6093
        } elsif (/^--(.*)/) {
6094
            Message( "PackageHdr: unknown option $_ -- ignored\n" );
6095
        }
6096
    }
6097
 
6098
#.. Files
6099
#
6100
    foreach $_ ( @elements )
6101
    {
6102
        my %package_entry;
6103
        if ( ! /^--(.*)/ )
6104
        {
6105
            $name = $_;
6106
            $basename = StripDir( $name );
6107
            if ( $full )
6108
            {
6109
                if ($abs || ! ($srcfile = $SRCS{ $basename }) ||
6110
                        ($len = rindex($srcfile, "/")) == -1)
6111
                {
6112
                    $dir = $base;
6113
                    $srcfile = $name;
6114
                }
6115
                else
6116
                {
6117
                    $srcfile = $1
6118
                        if ( $srcfile =~ m~^$ProjectBase/(.*)~ );
6119
 
6120
                    if ( m#^\./# ) {
6121
                        $dir = substr($srcfile, 3, $len);
6122
                    } else {
6123
                        $dir = substr($srcfile, 0, $len);
6124
                    }
6125
                    $dir = "$base/$dir";
6126
                }
6127
            }
6128
            else
6129
            {
6130
                if ($abs || ! ($srcfile = $SRCS{ $basename })) {
6131
                    $srcfile = $name;
6132
                }
6133
            }
6134
 
6135
            $name = $basename
6136
                if ( $strip );
6137
 
6138
            Debug( "PackageHdr( $dir/$name, " .
6139
                "src: $srcfile, dest: $dir, dist: $dist )" );
6140
 
6141
            $package_entry{'src'} = $srcfile;
6142
            $package_entry{'dir'} = StripFileExt( "$dir/$name" );
6143
            $package_entry{'set'} = $dist;
6144
 
6145
            $PACKAGE_HDRS{ "$dir/$name" } = {%package_entry};
6146
        }
6147
    }
6148
}
6149
 
6150
 
6151
sub PackageLib
6152
{
6153
    my( $platforms, @elements ) = @_;
6154
    my( $base, $dir, $dist, $type );
6155
    my( $lib, $org_lib, %extras, $strip );
6156
 
6157
    Debug2( "PackageLib($platforms, @elements)" );
6158
 
6159
    return if ( !$ScmPackage );                 # Packaging enabled ?
6160
    return if ( ! ActivePlatform($platforms) );
6161
 
6162
#.. Arguments
6163
#
6164
    $dist = "ALL";                              # Default set (ALL)
6165
    $base = $PackageInfo{'Lib'}{'PBase'};       # Base of target
6166
    $dir = $base . $PackageInfo{'Lib'}{'Dir'};  # Installation path (default)
6167
    $type = "";
6168
 
6169
    foreach $_ ( @elements )
6170
    {
6171
                                                # Standard targets
6172
        my $rv = __TargetDir($T_PKG, $base, $_, \$dir, \$type);
6173
        next if ( $rv == 1 );
6174
        return if ( $rv == 2 );
6175
 
6176
        if (/^--Set=(.*)/) {                    # Distribution set(s)
6177
            $dist = "$1";
6178
 
6179
        } elsif (/^--Package$/) {               # Package .. call by PackageLib
6180
        } elsif (/^--Package=(.*)/) {
6181
            $dist = "$1";
6182
 
6183
        } elsif (/^--Extras=(.*)/) {            # Extras=[none, .. ,all]
6184
            foreach my $elem ( split( ',', $1 ) )
6185
            {
6186
                Error ("PackageLib: Unknown Extras mode: $elem")
6187
                    unless ( grep m/$elem/, qw(none stub map lint debug all) );
6188
                $extras{$elem} = 1;
6189
            }
6190
            %extras = () if ( $extras{'all'} );
6191
 
6192
        } elsif (/^--Strip$/) {                 # Strip path from source files
6193
            $strip = 1;
6194
 
6195
        } elsif (/^--(.*)/) {
6196
            Message( "PackageLib: unknown option $_ -- ignored\n" );
6197
        }
6198
    }
6199
 
6200
#.. Files
6201
#
6202
    foreach $_ ( @elements )
6203
    {
6204
        my %package_entry;
6205
        if ( ! /^--(.*)/ )
6206
        {
6207
            $_ = StripDir( $_ )
6208
                if ( $strip );
6209
 
6210
            $org_lib = $_;                      # Original name
6211
            if ( $ScmTargetHost eq "Unix" ) {
6212
                $lib = "lib$_";                 # Prefix "lib" ....
6213
                $lib =~ s/^liblib/lib/;         # @LIBS already has lib added
6214
            } else {
6215
                $lib = $_;
6216
            }
6217
 
6218
            if ( exists $SHLIB_VER { $lib } )
6219
            {
6220
                Debug( "PackageLib( $dir/$lib\$(GBE_TYPE).$::so, " .
6221
                    "src: \$(LIBDIR)/$lib\$(GBE_TYPE).$::so, dest: $dir, dist: $dist, type: $type )" );
6222
 
6223
                #
6224
                #   Create a "placekeeper" entry within $PACKAGE_SHLIBS
6225
                #   The exact format of the name of the shared library is
6226
                #   toolset specific. Create an entry to allow the toolset
6227
                #   to extend the packaging information when the shared library
6228
                #   recipe is constructed.
6229
                #
6230
                #
6231
                my $ver = $SHLIB_VER{ $lib };
6232
                my $name = "$dir/$lib.$ver.PlaceKeeper";
6233
 
6234
                push @{$SHLIB_PKG{$lib}}, $name;
6235
 
6236
                $package_entry{'placekeeper'} = 1;
6237
                $package_entry{'version'} = $ver;
6238
                $package_entry{'lib'} = $lib;
6239
                $package_entry{'dir'} = $dir;
6240
                $package_entry{'set'} = $dist;
6241
                $package_entry{'type'} = $type if ( $type );
6242
                $package_entry{'extras'} = {%extras} if ( scalar %extras );
6243
                $PACKAGE_SHLIBS{$name} = {%package_entry};
6244
            }
6245
 
6246
            if ( my $libfile = $SRCS{$org_lib} )
6247
            {
6248
                #
6249
                #   Allow the user to package a sourced file as a library
6250
                #   But must be the un-massaged name of the file.
6251
                #
6252
                Debug( "PackageLib( $dir/$org_lib, " .
6253
                    "src: $libfile, dest: $dir, dist: $dist, type: $type )" );
6254
 
6255
                push @{$LIB_PKG{$lib}}, "$dir/$lib";
6256
 
6257
                $package_entry{'src'} = "$libfile";
6258
                $package_entry{'dir'} = $dir;
6259
                $package_entry{'set'} = $dist;
6260
                $package_entry{'extras'} = {%extras} if ( scalar %extras );
6261
                $package_entry{'type'} = $type if ( $type );
6262
 
6263
                $PACKAGE_LIBS{ "$dir/$org_lib" } = {%package_entry};
6264
            }
6265
            elsif ( exists $LIB_OBJS { $lib } || ! exists $SHLIB_VER { $lib } )
6266
            {
6267
                Debug( "PackageLib( $dir/$lib\$(GBE_TYPE).$::a, " .
6268
                    "src: \$(LIBDIR)/$lib\$(GBE_TYPE).$::a, dest: $dir, dist: $dist, type: $type )" );
6269
 
6270
                push @{$LIB_PKG{$lib}}, "$dir/$lib\$(GBE_TYPE).$::a";
6271
 
6272
                $package_entry{'src'} = "\$(LIBDIR)/$lib\$(GBE_TYPE).$::a";
6273
                $package_entry{'dir'} = $dir;
6274
                $package_entry{'set'} = $dist;
6275
                $package_entry{'extras'} = {%extras} if ( scalar %extras );
6276
                $package_entry{'type'} = $type if ( $type );
6277
 
6278
                $PACKAGE_LIBS{ "$dir/$lib\$(GBE_TYPE).$::a" } = {%package_entry};
6279
            }
6280
        }
6281
    }
6282
}
6283
 
6284
 
6285
sub PackageProg
6286
{
6287
    my( $platforms, @elements ) = @_;
6288
    my( $base, $dir, $dist, $type );
6289
    my( $prog, %extras, $strip );
6290
 
6291
    Debug2( "PackageProg($platforms, @elements)" );
6292
 
6293
    return if ( !$ScmPackage );                 # Packaging enabled ?
6294
    return if ( ! ActivePlatform($platforms) );
6295
 
6296
#.. Arguments
6297
#
6298
    $dist = "ALL";                              # Default set (ALL)
6299
    $base = $PackageInfo{'Prog'}{'PBase'};       # Base of target
6300
    $dir = $base . $PackageInfo{'Prog'}{'Dir'};  # Installation path (default)
6301
    $type = "";
6302
 
6303
    foreach $_ ( @elements )
6304
    {
6305
                                                # Standard targets
6306
        my $rv = __TargetDir($T_PKG|$T_TYPE, $base, $_, \$dir, \$type);
6307
        next if ( $rv == 1 );
6308
        return if ( $rv == 2 );
6309
 
6310
        if (/^--Set=(.*)/) {                    # Distribution set(s)
6311
            $dist = "$1";
6312
 
6313
        } elsif (/^--Package$/) {               # Package .. call by PackageLib
6314
        } elsif (/^--Package=(.*)/) {
6315
            $dist = "$1";
6316
 
6317
        } elsif (/^--Tool(([=])(.*))?$/) {      # Allow Tool and Tool=xxx specfic target
6318
            my $path = ( defined( $3) ) ? "/$3" : "";
261 dpurdie 6319
            $dir = "\$(PKGDIR)$path/\$(GBE_HOSTMACH)";
227 dpurdie 6320
 
6321
        } elsif (/^--Extras=(.*)/) {            # Extras=[none, .. ,all]
6322
            foreach my $elem ( split( ',', $1 ) )
6323
            {
6324
                Error ("PackageLib: Unknown Extras mode: $elem")
6325
                    unless ( grep m/$elem/, qw(none stub map lint debug all) );
6326
                $extras{$elem} = 1;
6327
            }
6328
            %extras = () if ( $extras{'all'} );
6329
 
6330
        } elsif (/^--Strip$/) {                 # Strip path from source files
6331
            $strip = 1;
6332
 
6333
        } elsif (/^--(.*)/) {
6334
            Message( "PackageProg: unknown option $_ -- ignored\n" );
6335
        }
6336
    }
6337
 
6338
#.. Files
6339
#
6340
    foreach $_ ( @elements )
6341
    {
6342
        my %package_entry;
6343
        if ( m~descpkg~ ) {
6344
            PackageFile($platforms, @elements);
6345
 
6346
        } elsif ( ! /^--(.*)/ ) {
6347
            $_ = StripDir( $_ )
6348
                if ( $strip );
6349
 
6350
            my $ext = "";
6351
            $prog = $_;
6352
 
6353
            #
6354
            #   If the named target is a program then append the correct
6355
            #   extension. Otherwise assume that the target is either a script
6356
            #   or a some other file - and don't append an extension
6357
            #
6358
            #   A program may not have any object files, only libraries
6359
            #
6360
            $ext = $::exe
261 dpurdie 6361
                if ( exists $PROGS{$prog} );
227 dpurdie 6362
 
6363
            #
6364
            #   A "file" that is specified with a "Src" directive may be
6365
            #   installed as though it were a program
6366
            #
6367
            my $progfile;
6368
            $progfile = "\$(BINDIR)/$prog$ext"
6369
                unless ( $progfile = $SRCS{$prog} );
6370
 
6371
            Debug( "PackageProg( $dir/$prog$ext, " .
6372
                 "src: $progfile, dest: $dir, dist: $dist, type: $type )" );
6373
 
6374
            my $target = "$dir/$prog$ext";
6375
            push @{$PROG_PKG{$prog}}, $target;
6376
 
6377
            $package_entry{'src'}   = $progfile;
6378
            $package_entry{'dir'}   = $dir;
6379
            $package_entry{'set'}   = $dist;
6380
            $package_entry{'extras'}= {%extras} if ( scalar %extras );
6381
            $package_entry{'type'}  = $type if ( $type );
6382
 
6383
            $PACKAGE_PROGS{$target} = {%package_entry};
6384
        }
6385
    }
6386
}
6387
 
6388
 
6389
sub PackageJar
6390
{
6391
    my( $platforms, @elements ) = @_;
6392
    my( $base, $dir, $dist, $type );
6393
    my( $jar );
6394
 
6395
    Debug2( "PackageJar($platforms, @elements)" );
6396
 
6397
    return if ( !$ScmPackage );                 # Packaging enabled ?
6398
    return if ( ! ActivePlatform($platforms) );
6399
 
6400
#.. Arguments
6401
#
6402
    $dist = "ALL";                              # Default set (ALL)
6403
    $base = $PackageInfo{'Jar'}{'PBase'};       # Base of target
6404
    $dir = $base . $PackageInfo{'Jar'}{'Dir'};  # Installation path (default)
6405
    $type = "";
6406
 
6407
    foreach $_ ( @elements )
6408
    {
6409
                                                # Standard targets
6410
        my $rv = __TargetDir($T_PKG, $base, $_, \$dir, \$type);
6411
        next if ( $rv == 1 );
6412
        return if ( $rv == 2 );
6413
 
6414
        if (/^--Set=(.*)/) {                    # Distribution set(s)
6415
            $dist = "$1";
6416
 
6417
        } elsif (/^--Package$/) {               # Package .. call by InstallJar
6418
        } elsif (/^--Package=(.*)/) {
6419
            $dist = "$1";
6420
 
6421
        } elsif (/^--(.*)/) {
6422
            Message( "PackageJar: unknown option $_ -- ignored\n" );
6423
        }
6424
    }
6425
 
6426
#.. Files
6427
#
6428
    foreach $_ ( @elements )
6429
    {
6430
        my %package_entry;
6431
        if ( ! /^--(.*)/ )
6432
        {
6433
            $jar = $_;
6434
            my $src;
6435
            my $dest;
6436
 
6437
            if ( $JAR_FILES{$jar} )
6438
            {
6439
                $src = $JAR_FILES{$jar};
6440
                $dest = $jar;
6441
            }
6442
            else
6443
            {
6444
                $src = "\$(CLSDIR)/$jar\$(GBE_TYPE).jar";
6445
                $dest = "$jar\$(GBE_TYPE).jar";
6446
            }
6447
 
6448
 
6449
            Debug( "PackageJar( $dir/$dest, " .
6450
                "src: $src, dest: $dir, dist: $dist, type: $type )" );
6451
 
6452
            $package_entry{'src'} = $src;;
6453
            $package_entry{'dir'} = $dir;
6454
            $package_entry{'set'} = $dist;
6455
            $package_entry{'type'} = $type if ( $type );
6456
 
6457
            $PACKAGE_CLSS{ "$dir/$dest" } = {%package_entry};
6458
 
6459
        }
6460
    }
6461
}
6462
 
6463
#-------------------------------------------------------------------------------
6464
# Function        : PackageProgAddFiles         - Add files to a PackageProg
6465
#                   PackageLibAddFiles          - Add files to a PackageLib
6466
#                   PackageShlibAddFiles        - Add files to a PackageLib (shared lib)
6467
#                   PackageShlibAddLibFiles     - Add files to a PackageLib (shared lib)
6468
#                                                 Add static library files
6469
#
6470
# Description     : Add files to a Program package or installation
6471
#                   For use by Tool sets to allow additional files to be
6472
#                   packaged with a program.
6473
#
6474
#                   The files are only added if the named program is being
6475
#                   packaged and/or installed.
6476
#
6477
#
6478
# Inputs          : prog        - program identifier
6479
#                   file        - A file to be add
6480
#                   args        - Additional packageing arguments
6481
#
6482
# Returns         : Nothing
6483
#
6484
 
6485
sub PackageProgAddFiles
6486
{
6487
    Debug("PackageProgAddFiles");
6488
 
6489
    PackageAddFiles ( \%PACKAGE_PROGS, \%PACKAGE_PROGS, \%PROG_PKG, @_);
6490
    PackageAddFiles ( \%INSTALL_PROGS, \%INSTALL_PROGS, \%PROG_INS, @_);
6491
}
6492
 
6493
sub PackageLibAddFiles
6494
{
6495
    Debug("PackageLibAddFiles");
6496
 
6497
    PackageAddFiles ( \%PACKAGE_LIBS, \%PACKAGE_LIBS, \%LIB_PKG, @_ );
6498
    PackageAddFiles ( \%INSTALL_LIBS, \%INSTALL_LIBS, \%LIB_INS, @_ );
6499
}
6500
 
6501
sub PackageShlibAddFiles
6502
{
6503
    my ($prog, $file, @args) = @_;
6504
    Debug("PackageShlibAddFiles");
6505
 
6506
    PackageAddFiles ( \%INSTALL_SHLIBS, \%INSTALL_SHLIBS, \%SHLIB_INS, @_ );
6507
    PackageAddFiles ( \%PACKAGE_SHLIBS, \%PACKAGE_SHLIBS, \%SHLIB_PKG, @_ );
6508
 
6509
    #
6510
    #   These files become the target of the "make_install_shlib" operation unless:
6511
    #       Conditionally packaged files are not always created
6512
    #       RemoveOnly files are not always generated
6513
    #
6514
    my $no_add;
6515
    foreach ( @args )
6516
    {
6517
        if ( m/^defined=/ or m/^RemoveOnly=/ )
6518
        {
6519
            $no_add = 1;
6520
            last;
6521
        }
6522
    }
6523
 
6524
    push (@SHLIB_TARGETS, $file ) unless $no_add;
6525
}
6526
 
6527
sub PackageShlibAddLibFiles
6528
{
6529
    Debug("PackageShlibAddLibFiles");
6530
 
6531
    PackageAddFiles ( \%PACKAGE_SHLIBS, \%PACKAGE_LIBS, \%SHLIB_PKG, @_ , 'Class=lib');
6532
    PackageAddFiles ( \%INSTALL_SHLIBS, \%INSTALL_LIBS, \%SHLIB_INS, @_ , 'Class=lib');
6533
}
6534
 
6535
#-------------------------------------------------------------------------------
6536
# Function        : PackageAddFiles
6537
#
6538
# Description     : Internal function to add files to the data structures that
6539
#                   describe a package or installation
6540
#
6541
#                   Use this function to package or install additional files with
6542
#                   the Progs and Libs
6543
#
6544
#                   ie: Add a LIB file to be packaged with a Shared Library
6545
#                   ie: Add a MAP file to be packaged with a program
6546
#
6547
# Inputs          : ref_spkg  - Reference to the hash that contains the package data
6548
#                   ref_dpkg  - Reference to the target package/install hash
6549
#                               Normally the same as ref_dpkg, but does allow
6550
#                               a static librry to be added to a dynamic library
6551
#                               package.
6552
#                   ref_list  - Reference to a hash that may contain package keys to process
6553
#                   prog      - Key for index to above
6554
#                   file      - A file to be added
6555
#                   args      - Additional packaging arguments
6556
#
6557
# Returns         :
6558
#
6559
sub PackageAddFiles
6560
{
6561
    my ($ref_spkg, $ref_dpkg, $ref_list, $prog, $file, @args ) = @_;
6562
 
6563
    #
6564
    #   Process entry
6565
    #   The files may need to be added to multiple packages
6566
    #
6567
    Debug("PackageAddFiles: $file");
6568
 
6569
    return unless ( $ref_list->{$prog} );
6570
 
6571
    #
6572
    #   Parse arguments and extract the "Class=xxx" argument. This may be used
6573
    #   to limit the extra files piggybacked with the base file
6574
    #   All files without a class will be treated as base files
6575
    #
6576
    my $class;
6577
    foreach ( @args )
6578
    {
6579
        next unless ( m~^Class=(.*)$~ );
6580
        $class = $1 unless ( $1 eq 'none' );
6581
    }
6582
    Debug("PackageAddFiles: Class: ", $class || 'Default=None');
6583
 
6584
    foreach my $entry_key ( @{$ref_list->{$prog}} )
6585
    {
6586
        Debug("PackageAddFiles: Entry found: $entry_key");
6587
 
6588
        #
6589
        #   Copy of the template entry
6590
        #
6591
        my %package_entry = %{$ref_spkg->{$entry_key}};
6592
        Error ("INTERNAL: Expected entry in PACKAGE_ hash not found: $entry_key" )
6593
            unless ( %package_entry );
6594
 
6595
        #
6596
        #   Do not add the file if the user has limited the extra files added
6597
        #   to the packaging list and the current file is not in the class list
6598
        #
6599
        if ( $class && $package_entry{'extras'} )
6600
        {
6601
            next unless ( $package_entry{'extras'}{$class} );
6602
        }
6603
 
6604
        #
6605
        #   Create new entries for the file
6606
        #
6607
        $package_entry{'src'} = $file;
6608
        foreach ( @args )
6609
        {
6610
            m~^(.*)=(.*)$~;
6611
            $package_entry{$1} = $2;
6612
        }
6613
 
6614
        #
6615
        #   Clean out useless fields
6616
        #   Must remove the placekeeper marker to allow the entry to be visible
6617
        #
6618
        delete $package_entry{'placekeeper'};
6619
        delete $package_entry{'version'};
6620
        delete $package_entry{'lib'};
261 dpurdie 6621
#       delete $package_entry{'extras'};                   # Keep these
227 dpurdie 6622
        delete $package_entry{'Class'};
6623
 
6624
        #
6625
        #   Add the entry
6626
        #
6627
        #   Under some conditions is it possible to attempt to add the same named
6628
        #   file. This will result in a circular dependancy in the makefile
6629
        #
6630
        #   The condition is when merged libaries with PDBs (WINCE+WIN32) are merged
261 dpurdie 6631
        #   and the source for the merge is the "local directory.
227 dpurdie 6632
        #
6633
        #
6634
        my $dst = $package_entry{'dir'} ;
6635
        ( my $dfile = $file) =~ s~.*/~~;
6636
        Debug( "    added $dst/$dfile = $file" );
6637
 
6638
        $ref_dpkg->{"$dst/$dfile"} = {%package_entry}
6639
            unless ( "$dst/$dfile" eq "$file" );
6640
    }
6641
}
6642
 
6643
#-------------------------------------------------------------------------------
6644
# Function        : PackageProgRemoveFiles
6645
#
6646
# Description     : Flag a Packaged program to be not packaged
6647
#                   This mechanism is used to remove a program from packageing
6648
#                   under conditions where the toolset has generated a different
6649
#                   program.
6650
#
6651
#                   The entry is flagged as a placeholder
6652
#
6653
# Inputs          : prog        - Program to process
6654
#
6655
# Returns         : Nothing
6656
#
6657
sub PackageProgRemoveFiles
6658
{
6659
    my ($prog) = @_;
6660
    Verbose ("PackageProgRemoveFiles: $prog" );
6661
    return unless (exists($PROG_PKG{$prog}));
6662
 
6663
    #
6664
    #   Must lookup the TAG to locate the  required entry
6665
    #
6666
    my $tag = $PROG_PKG{$prog};
6667
    foreach my $entry ( @$tag )
6668
    {
6669
        Verbose("Do not package: $entry");
6670
        if ( exists $PACKAGE_PROGS{$entry} )
6671
        {
6672
            $PACKAGE_PROGS{$entry}{placekeeper} = 'ProgRemoved';
6673
        }
6674
    }
6675
}
6676
 
6677
#-------------------------------------------------------------------------------
6678
# Function        : DPackageLibrary
6679
#
6680
# Description     : Collect information to allow the generation of a DPACKAGE
6681
#                   file. This directive allows the gneration of "Library"
6682
#                   directives within the final DPACKAGE
6683
#
6684
#                   This directive does generate the DPACKAGE file.
6685
#
6686
# Inputs          : platform    - This does not need to be an active platform
6687
#                                 it is simply passed to the DPACKAGE builder
6688
#
6689
#                   using       - The "using" target
6690
#
6691
#                   ...         - Arguments for the Library directive
6692
#
6693
# Returns         :
6694
#
6695
sub DPackageLibrary
6696
{
6697
    JatsDPackage::DPackageAdd ( @_ );
6698
}
6699
 
6700
#-------------------------------------------------------------------------------
6701
# Function        : SetProjectBase
6702
#
6703
# Description     : Allows the user to modify the build's concept of the Base
6704
#                   of the build. By default the base is the same directory as
6705
#                   the build.pl file, but in some contorted environments it
6706
#                   is a great deal simpler to specify a differnt base.
6707
#
6708
#                   The use may use the variable $ProjectBase as a path
6709
#                   specifier to locate files and directories
6710
#
6711
#                   Both absolute and relative paths are supported
6712
#                   If the initial value of $ProjectBase is relative then
6713
#                   it will be maintained as a relative path.
6714
#
6715
# Inputs          : elements        path to base
6716
#                                   These may be:
6717
#                                       --Up=xx
6718
#                                       name
6719
#
6720
# Returns         : Nothing
6721
#
6722
 
6723
#
6724
#   Allow the user to modify the project base variable
6725
#
6726
sub SetProjectBase
6727
{
6728
    my $rip = 0;
6729
    my $path = "";
6730
    my $is_relative;
6731
 
6732
    Debug("ProjectBase Initial: $ProjectBase, @_");
6733
 
6734
    #
6735
    #   Ensure that the ProjectBase is in a "nice" form
6736
    #   1) No /./ bits
6737
    #   2) No trailing /
6738
    #   3) Not equal to .
6739
    #   4) No training /.
6740
    #   5) No //
6741
    #
6742
    $ProjectBase =~ s~/\./~/~g;
6743
    $ProjectBase =~ s~/$~~g;
6744
    $ProjectBase =~ s~^\.$~~g;
6745
    $ProjectBase =~ s~/\.$~~g;
6746
    $ProjectBase =~ s~//$~/~g;
6747
 
6748
    #
6749
    #   ProjectBase may be absolute or relative
6750
    #   Determine this before we mess with it
6751
    #
6752
    $is_relative = ($ProjectBase !~ m~^/~);
6753
 
6754
    #
6755
    #   Process each argument
6756
    #
6757
    foreach ( @_ )
6758
    {
6759
        if ( /^--Up=([0-9]*)/ ) {
6760
            $rip = $1;
6761
        } elsif ( /^--/ ) {
6762
            Warning( "SetProjectBase - unknown option \"$_\" - ignored" );
6763
        } else {
6764
            $path = $_;
6765
        }
6766
    }
6767
 
6768
    #
6769
    #   Process the UP requests
6770
    #   If the tail directory is a ".." then up is done by adding another ".."
6771
    #   If the tail directory is not a "..", then up is done by removing it
6772
    #
6773
    #   If we go past the start of the path then simply add ".."
6774
    #
6775
    while ( $rip-- > 0 )
6776
    {
6777
        Debug2("ProjectBase: $ProjectBase, Up: $rip, IsRel: $is_relative");
6778
 
6779
        #
6780
        #   If ending in a /.. or is exactly equal to ..
6781
        #   Then its a dot-dot and the way to go UP is to append another ..
6782
        #
6783
        if ( $ProjectBase =~ m~(/\.\.$)|(^\.\.$)~ )
6784
        {
6785
            $ProjectBase .= '/..';
6786
        }
6787
        else
6788
        {
6789
            #
6790
            #   Not a dot-dot ending
6791
            #   Attempt to remove the last directory of the form
6792
            #       /xxxxx
6793
            #   Where the leading / is optional
6794
            #   Note: Must have at least one character in the dirname
6795
            #         This prevents leading / from matching - which is needed
6796
            #
6797
            unless ($ProjectBase =~ s~/?[^/]+$~~)
6798
            {
6799
                #
6800
                #   Removal failed
6801
                #   If a relative path then we can keep on going up,
6802
                #   otherwise we are dead.
6803
                #
6804
                Error ("ProjectBase outside project") unless ($is_relative);
6805
                $ProjectBase = '..';
6806
            }
6807
 
6808
            #
6809
            #   Ensure that the leading / in an absolute path is not deleted
6810
            #
6811
            $ProjectBase = '/'
6812
                unless ( $is_relative || $ProjectBase );
6813
        }
6814
    }
6815
 
6816
    #
6817
    #   Append the user path
6818
    #
6819
    $ProjectBase .= '/' . $path if ( $path );
6820
    $ProjectBase = '.' unless ( $ProjectBase );
6821
    Debug("ProjectBase set to : $ProjectBase");
6822
 
6823
    #
6824
    #   Once upon a time I tried to convert paths that contained spaces into
6825
    #   short (mangled) names. This was not sucessful because:
6826
    #       1) Clearcase dynamic views do not support name mangling
6827
    #       2) Samba file system does not appear to support name mangling
6828
    #
6829
    #   Spaces in paths are not good for MAKE
6830
    #   Now I simple generate a message
6831
    #
6832
    Warning( "ProjectBase contains a space: $ProjectBase")
6833
        if ( $ProjectBase =~ m/ / );
6834
 
6835
    #
6836
    #   Sanity check
6837
    #   Absolute paths can be checked easily
6838
    #   Checking of relative paths does not appear to work
6839
    #   When I tested it chdir, opendir and stat would limit themselves
6840
    #   and drop into the root directory ( under windows )
6841
    #
6842
    #   Solution: Check the path does not extend beyond the file tree
6843
    #
6844
    my $distance = 1;
6845
    my $tpath = $ProjectBase;
6846
 
6847
    if ( $is_relative && $tpath ne '.' )
6848
    {
6849
        #
6850
        #   Build up the complete pathname by merging it with the
6851
        #   current directory. Then clean it up.
6852
        #
6853
        $tpath = $::Cwd . '/' . $ProjectBase;
6854
 
6855
        #
6856
        #   Scan the list of diretories and count the distance from the root
6857
        #   This should not be greater than zero for sanity
6858
        #   Note: Get an empty elemement from the split due to
6859
        #         the leading / of the ABS path
6860
        #
6861
        $distance = 0;
6862
        foreach (  split ('/', $tpath) )
6863
        {
6864
            if ( m~\.\.~ )
6865
            {
6866
                $distance--;
6867
            }
6868
            else
6869
            {
6870
                $distance++;
6871
            }
6872
        }
6873
    }
6874
 
6875
    #
6876
    #   Warn if not a valid directory
6877
    #
6878
    Warning( "ProjectBase is not a directory: $ProjectBase")
6879
        if ( $distance <= 0 || !  -d $tpath  );
6880
 
6881
    #
6882
    #   $ProjectBase will always be a valid directory, but if its the top
6883
    #   directory (/) and it is added to a path we will get //path
6884
    #   This is not good, so // will be removed later in the AddIncDir and
6885
    #   AddSrcDir commands where $ProjectBase is really used.
6886
    #
6887
    #   Alternatively we could set $ProjectBase to an empty string, but then
6888
    #   this may be confused with an empty relative directory
6889
    #
6890
    Debug("ProjectBase Final  : $ProjectBase");
6891
}
6892
 
6893
#-------------------------------------------------------------------------------
6894
# Function        : DeployPackage
6895
#
6896
# Description     : Generate a deployed package
6897
#                   This is a gateway to a different packaging system
6898
#
6899
#                  DeployPackage and PackageXxxxx directives are mutually
6900
#                  exclusive. Only one person can play in the package area.
6901
#
6902
# Inputs          : Platform Specifier
6903
#                   Package Name    (Optional)
6904
#                   Options
6905
#                       --Name : Base name of the package. The default is taken
6906
#                                from the build.pl file
6907
#                       --Dir  : Package directory
6908
#                                The default is based on the package name
6909
#
6910
# Returns         :
6911
#
6912
sub DeployPackage
6913
{
6914
    my( $platforms, @elements ) = @_;
6915
    my $dir;
6916
    my $name;
6917
 
267 dpurdie 6918
    #
6919
    #   Flag that this build creates a deployable package, even if its not
6920
    #   active on this platform.
6921
    #
6922
    $DEPLOYPACKAGE = 1;
6923
 
6924
 
227 dpurdie 6925
    Debug2( "DeployPackage($platforms, @elements)" );
6926
    return if ( ! ActivePlatform($platforms) );
6927
 
6928
    #
6929
    #   Only allow one use of this directive
6930
    #
6931
    Error("DeployPackage can only be used once" ) if ( %DEPLOYPACKAGE );
267 dpurdie 6932
    $DEPLOYPACKAGE = 2;
227 dpurdie 6933
 
6934
    #
6935
    #   Ensure that the deployment file is available
6936
    #
6937
    my $command_file = $ScmDeploymentPatch ? "deploypatch.pl" : "deployfile.pl";
6938
    Error("DeployPackage: $command_file not found") unless (-f "./$command_file");
6939
    #
6940
    #   Collect arguments
6941
    #
6942
    foreach (@elements )
6943
    {
6944
        if ( m/^--Dir=(.*)/ ) {
6945
            Error ("DeployPackage: Package directory defined multiple times") if $dir;
6946
            $dir = $1;
6947
 
6948
        } elsif ( m/^--Name=(.*)/ ) {
6949
            Error ("DeployPackage: Package name defined multiple times") if $name;
6950
            $name = $1;
6951
 
6952
        } elsif ( m/^--/ ) {
6953
            Warning( "DeployPackage: Unknown option ignored: $_");
6954
 
6955
        } else {
6956
            Error ("DeployPackage: Package name defined multiple times") if $name;
6957
            $name = $_;
6958
 
6959
        }
6960
    }
6961
 
6962
    $name = $::ScmBuildPackage unless ( $name );
6963
 
6964
    #
6965
    #   Save the deployment data
6966
    #
6967
    $dir = lc($name) unless ( $dir );
6968
    $DEPLOYPACKAGE{'name'} = $name;
6969
    $DEPLOYPACKAGE{'dir'} = $dir;
6970
    $DEPLOYPACKAGE{'cmdfile'} = $command_file;
6971
 
6972
    #
6973
    #   Flag that toolset tests should be supressed
6974
    #   The Deploy world does not really use the full makefiles and if the
6975
    #   compilers are not installed will not be able to create deployment
6976
    #   packages
6977
    #
6978
    $ScmNoToolsTest = 1;
6979
}
6980
 
6981
 
6982
###############################################################################
6983
###############################################################################
6984
# Private function section.
6985
#       The following functions are used INTERNALLY by makelib.pl2.
6986
###############################################################################
6987
 
6988
###############################################################################
6989
#   A collection of functions to write to the MAKEFILE handle
6990
#
6991
#   MakeHeader          - Write a nice section header
6992
#   MakeNewLine         - Print a new line
6993
#   MakePrint           - Print a line ( without trailing \n)
6994
#   MakeQuote           - Escape \ and " character, then print a line
6995
#   MakePrintList       - Print an array
6996
#   MakeEntry           - Complex line printer
6997
#   MakePadded          - Padded line printer (internal)
6998
#   PadToPosn           - Calc space+tabs to tabstop (internal)
6999
#   MakeEntry3          - Complex Line Printer
7000
#   MakeDefEntry        - Print a definition line (Production + Debug support)
7001
#   MakeIfDefEntry      - Print ifdef entry
261 dpurdie 7002
#   MakeIfnDefEntry     - Print ifndef entry
7003
#   MakeIfZeroEntry     - Print ifeq entry
227 dpurdie 7004
#
7005
###############################################################################
7006
 
7007
sub MakeHeader
7008
{
7009
    my ($text, @rest) = @_;
7010
    my $length = length ($text);
7011
 
7012
    print MAKEFILE "\n";
7013
    print MAKEFILE "#--------- $text ", '-' x (80 - 12 - $length)  ,"\n";
7014
    print MAKEFILE "#    $_\n" foreach  ( @rest ) ;
7015
    print MAKEFILE "#\n";
7016
}
7017
 
7018
sub MakeNewLine         # Print a newline to the current 'Makefile'
7019
{
7020
    print MAKEFILE "\n";
7021
}
7022
 
7023
sub MakePrint           # Print to the current 'Makefile'
7024
{
7025
    print MAKEFILE @_
7026
        if ( defined $_[0] );
7027
}
7028
 
7029
sub MakeQuote           # Quote a makefile text line
7030
{
7031
    my( $line ) = @_;
7032
    $line =~ s/\\/\\\\/g;                       # quote all '\' characters
7033
    $line =~ s/"/\\"/g;                         # Then quote '"' characters
255 dpurdie 7034
    $line =~ s/=#/=\\#/g;                       # Then quote '=#' sequence
227 dpurdie 7035
    print MAKEFILE $line;
7036
}
7037
 
7038
sub MakePrintList
7039
{
7040
    print MAKEFILE $_ . "\n" foreach (@{$_[0]});
7041
}
7042
 
7043
 
7044
#-------------------------------------------------------------------------------
7045
# Function        : MakeEntry
7046
#
7047
# Description     : Build a entry based on the element list
7048
#                   Creates text of the form
7049
#                       $(BINDIR)/prog.exe: object1.obj \
7050
#                                           object2.obj
7051
#
7052
#
7053
# Inputs          : $prelim         - Preamble (one-off)
7054
#                   $postlim        - Postamble (one-off)
7055
#                   $prefix         - Pefix (to each element of array)
7056
#                   $postfix        - Postfix (to each element of array )
7057
#                   @elements       - Array of element to wrap
7058
#
7059
# Returns         :   1 Always
7060
#
7061
# Notes:
7062
#       The above description means that the following entry format is
7063
#       produced:
7064
#
7065
#           <preliminary><prefix><variant1><prefix><variant2>...<final>
7066
#
7067
#       With judicious use of newline and tab characters, a target
7068
#       and dependency list along with the command(s) to build the
7069
#       target can be constructed.
7070
#
7071
sub MakeEntry
7072
{
7073
    my( $prelim, $postlim, $prefix, $postfix, @elements ) = @_;
7074
 
7075
    MakePrint $prelim;
7076
    MakePrint "${prefix}${_}${postfix}" foreach ( @elements );
7077
    MakePrint $postlim if ($postlim);
7078
    return 1;
7079
}
7080
 
7081
#-------------------------------------------------------------------------------
7082
# Function        : MakePadded
7083
#
7084
# Description     : Generate aligned output of the form
7085
#                       Prefix_text           Aligned_text
7086
#                   where the aligned text is at a specified TAB boundary
7087
#
7088
# Inputs          : $align      - Tab stop (One tab = 8 chars)
7089
#                   $prefix     - Text to print before alignment occurs
7090
#                   @line       - Remainder of the line
7091
#
7092
sub MakePadded          # Print to the current 'Makefile', tab aligning
7093
{
7094
    my( $align, $prefix, @line ) = @_;
7095
 
7096
    my $strlen = length( $prefix );
7097
    my $pad = PadToPosn( $strlen, $align * 8 );
7098
 
7099
    print MAKEFILE $prefix . $pad;
7100
    print MAKEFILE @line;
7101
}
7102
 
7103
#-------------------------------------------------------------------------------
7104
# Function        : PadToPosn
7105
#
7106
# Description     : Given that we are at $startposn return a tab and space
7107
#                   string to place us at $endposn
7108
#
7109
sub PadToPosn
7110
{
7111
    my ($startposn, $endposn ) = @_;
7112
 
7113
 
7114
    #
7115
    #   Case where we are already too far into the line
7116
    #
7117
    return ( ' ' )if ( $endposn <= $startposn );
7118
 
7119
    my $tcount = 0;
7120
    my $scount = 0;
7121
 
7122
    while ( $startposn < $endposn )
7123
    {
7124
        $tcount ++;
7125
        $startposn = ($startposn >> 3) * 8 + 8;
7126
 
7127
        my $delta = $endposn - $startposn;
7128
        if ( $delta < 8 )
7129
        {
7130
            $scount = $delta;
7131
            last;
7132
        }
7133
 
7134
    }
7135
    return ( "\t" x $tcount .  ' ' x $scount );
7136
}
7137
 
7138
#-------------------------------------------------------------------------------
7139
# Function        : MakeEntry3
7140
#
7141
# Description     : Build a makefile entry based on the element list, tab aligned
7142
#                   Can creat text of the form:
7143
#                       TAG = NAME0 \       TAG : NAME0 \ 
7144
#                             NAME1               NAME1
7145
#
7146
#
7147
# Inputs          : $prelim             - Preliminary text
7148
#                   $presep             - Preliminary seperator
7149
#                   $elem_ref           - Either a single name or a reference to
7150
#                                         and array of names, or a hash.
7151
#
7152
# Returns         : Writes directly to the Makefile
7153
#
7154
sub MakeEntry3
7155
{
7156
    my( $prelim, $presep, $elem_ref ) = @_;
7157
 
7158
    #
7159
    #   The prelim may have some "\n" characters at the start
7160
    #   These simplify formatting, but mess up the nice formatting
7161
    #
7162
    if ($prelim =~ m~(^\n+)(.*)~ )
7163
    {
7164
        MakePrint $1;
7165
        $prelim = $2;
7166
    }
7167
 
7168
    #
7169
    #   Print the definition and the sep with nice padding
7170
    #
7171
    MakePadded ( 3, $prelim, $presep );
7172
    my $leadin = ' ';
7173
 
7174
    #
7175
    #   If a HASH reference then use a sorted list of keys from the hash.
7176
    #
7177
    if ( ref ($elem_ref) eq "HASH" )
7178
    {
7179
        my @hash_list;
7180
        @hash_list = sort keys ( %{$elem_ref} );
7181
        $elem_ref = \@hash_list;
7182
    }
7183
 
7184
    #
7185
    #   If the list is only one element long, then create a simple form
7186
    #   If the list is not an array ref, then treat it as a single element
7187
    #
7188
    if ( ref ($elem_ref) eq "ARRAY" )
7189
    {
7190
        my $line = 0;
7191
        foreach my $element ( @$elem_ref )
7192
        {
7193
            print MAKEFILE $leadin . $element;
7194
            $leadin = " \\\n" . PadToPosn(0,24 + length( $presep ) + 1 ) unless ($line++);
7195
        }
7196
    }
7197
    elsif ( defined $elem_ref )
7198
    {
7199
            print MAKEFILE $leadin . $elem_ref;
7200
    }
7201
    MakeNewLine();
7202
    return 1;
7203
}
7204
 
7205
#-------------------------------------------------------------------------------
7206
# Function        : MakeDefEntry
7207
#
7208
# Description     : Make a definition entry of the form
7209
#
7210
#                       TAG = NAME0 \
7211
#                             NAME1
7212
#
7213
#                   Support a list of definitions that will always be created
7214
#                   as well as a production and a debug list.
7215
#
7216
#                   Will always generate the "TAG = " string, even if the list
7217
#                   is empty.
7218
#
7219
#                   Will supress the TAG if there is no data if the FIRST opr starts with a '+'
7220
#
7221
# Inputs          : TAG         - Text tag to create
7222
#                   FIRST       - First assignement opr. = or +=
7223
#                   ALL_LIST    - A reference to a list of names to assign
7224
#                                 or a single name.
7225
#                   PROD_LIST   - Optional list to extend the definition with for a production build
7226
#                   DEBUG_LIST  - Optional list to extend the definition with for a debug build
7227
#
7228
# Returns         : Nothing
7229
#
7230
 
7231
sub MakeDefEntry
7232
{
7233
    my( $tag, $assign, $all, $prod, $debug ) = @_;
7234
 
7235
    #
7236
    #   Do not generate anything if the $opr is "+=" and there is no data
7237
    #   to output. ie: Supress empty TAG += statements
7238
    #
7239
    return if ( $assign =~ m/\+/ && ( ref($all) && ! defined $all->[0] ) );
7240
 
7241
    #
7242
    #   TAG for all entries
7243
    #
7244
    MakeEntry3( $tag, $assign, $all );
7245
 
7246
 
7247
    #
7248
    #   TAGs for PROD build
7249
    #   TAGs for DEBUG build
7250
    #
7251
    if ( defined $prod && defined $prod->[0] )
7252
    {
7253
        print MAKEFILE 'ifeq "$(DEBUG)" "0"' . "\n";
7254
        MakeEntry3( $tag, "+=", $prod );
267 dpurdie 7255
        print MAKEFILE 'endif' . "\n";
227 dpurdie 7256
    }
7257
 
7258
    if ( defined $debug && defined $debug->[0] )
7259
    {
7260
        print MAKEFILE 'ifeq "$(DEBUG)" "1"' . "\n";
7261
        MakeEntry3( $tag, "+=", $debug );
267 dpurdie 7262
        print MAKEFILE 'endif' . "\n";
227 dpurdie 7263
    }
7264
 
7265
}
7266
 
7267
sub MakeIfDefEntry
7268
{
7269
    my( $iftag, @rest ) = @_;
7270
 
7271
    print MAKEFILE "ifdef $iftag\n";
7272
    MakeDefEntry (@rest);
7273
    print MAKEFILE "endif\n\n";
7274
}
7275
 
7276
sub MakeIfnDefEntry
7277
{
7278
    my( $iftag, @rest ) = @_;
7279
 
7280
    print MAKEFILE "ifndef $iftag\n";
7281
    MakeDefEntry (@rest);
7282
    print MAKEFILE "endif\n\n";
7283
}
7284
 
261 dpurdie 7285
sub MakeIfZeroEntry
7286
{
7287
    my( $iftag, @rest ) = @_;
7288
 
7289
    print MAKEFILE "ifeq (\$($iftag),0)\n";
7290
    MakeDefEntry (@rest);
7291
    print MAKEFILE "endif\n\n";
7292
}
7293
 
227 dpurdie 7294
#-------------------------------------------------------------------------------
7295
# Function        : CreateNameList
7296
#
7297
# Description     : Create a list of names by adding a prefix and suffix to a
7298
#                   list of items. This is used to add a directory prefix and a
7299
#                   file suffix to a list of files.
7300
#
7301
# Inputs          : $prefix             ie: '$(OBJDIR)/'
7302
#                   $suffix             ie: '.obj'
7303
#                   $elem_ref           ie: A list of files ( passed be ref )
7304
#                                           If a Hash then its sorted keys is used
7305
#
7306
# Returns         : A ref to the resulting list
7307
#
7308
sub CreateNameList
7309
{
7310
    my( $prefix, $suffix, $elem_ref ) = @_;
7311
    my @result;
7312
 
7313
    if ( ref ($elem_ref) eq "HASH" )
7314
    {
7315
        my @hash_list;
7316
        @hash_list = sort keys ( %{$elem_ref} );
7317
        $elem_ref = \@hash_list;
7318
    }
7319
 
7320
    foreach  ( @$elem_ref )
7321
    {
7322
        push @result, $prefix . $_ . $suffix;
7323
    }
7324
    return \@result;
7325
}
7326
 
7327
#-------------------------------------------------------------------------------
7328
# Function        : ListGeneratedProjects
7329
#
7330
# Description     : Return a list of generated/nongenerated projects
7331
#                   Used in conjunction with CreateNameList
7332
#
7333
# Inputs          : $type       - TRUE : Generated
7334
#                                 FALSE: Not Generated
7335
#
7336
# Returns         : A reference to a list of projects
7337
#                   undef will be retuend if there are no projects
7338
#
7339
sub ListGeneratedProjects
7340
{
7341
    my ($type) = @_;
7342
    my @list;
7343
    foreach my $project ( @PROJECTS_ORDER )
7344
    {
7345
        if ( exists($PROJECTS{$project}->{'generated'}) xor $type )
7346
        {
7347
            push @list, $project;
7348
        }
7349
    }
7350
    return @list ? \@list : undef;
7351
}
7352
 
7353
#-------------------------------------------------------------------------------
7354
# Function        : ListCleanGenerated
7355
#
7356
# Description     : return a list of generated targets that have 'clean'
7357
#                   operations. This is used in conjunction with CreateNameList
7358
#
7359
# Inputs          : None
7360
#
7361
# Returns         : A list of project indexes, that can be cleaned
7362
#
7363
sub ListCleanGenerated
7364
{
7365
    my @list;
7366
    foreach my $i ( @GENERATE_FILES )
7367
    {
7368
        push @list, $i->{'index'}
7369
            if ( $i->{'clean'} );
7370
    }
7371
    return \@list;
7372
}
7373
 
251 dpurdie 7374
#-------------------------------------------------------------------------------
7375
# Function        : MakeResolve
7376
#
7377
# Description     : Internal Function
7378
#                   Locate a source file by examining a list of directories
7379
#
7380
#                   Don't use directly
7381
#                   Use MakeSrcResolve or MakeSrcResolveExtended
7382
#
7383
# Inputs          : $dirs           - Ref to an array of directories to scan
7384
#                   $source         - File to locate
7385
#
7386
# Returns         : Resolved path to the file
7387
#                   Will warn if multiple instances of the file are found
7388
#
227 dpurdie 7389
sub MakeResolve
7390
{
7391
    my( $dirs, $source ) = @_;
7392
    my( $first, $dir, $count, $temp );
7393
 
237 dpurdie 7394
    #
7395
    #   If the path contains a '$' then its assumed to be
7396
    #   a variable name in the path. Just assume that it exists
7397
    #
7398
    return $source if ( $source =~ m#\$# );
7399
 
7400
    #
7401
    #   If the path is absolute or contains a leading ., then don't search
7402
    #   Warn if it can't be found
7403
    #
7404
    if ( $source =~ m#^(/|\.)# )
7405
    {
7406
        Warning( "Unable to resolve '$source' path" ) unless -f $source;
7407
        return $source;
227 dpurdie 7408
    }
7409
 
237 dpurdie 7410
 
227 dpurdie 7411
#.. search local path first
7412
#
7413
    $count = 0;
7414
    $first = "";
7415
    $first = "$source"                          # was ./$source
7416
        if (-r "$source");
7417
 
7418
#.. search directory paths
7419
#
7420
    foreach $dir (@$dirs)
7421
    {
7422
        $temp = "$dir/$source";                 # was ./$dir/$source
7423
        Debug2( "MakeResolve: Looking in: $temp" );
7424
        if (-r "$temp")
7425
        {
7426
            if ($first eq "") {
7427
                $first = $temp;
7428
            } else {
7429
                Warning( "Duplicate '$source' image - '$temp'" );
7430
                $count++;
7431
            }
7432
        }
7433
        Debug3( "MakeResolve: $count, $temp" );
7434
    }
7435
 
7436
    if ($first eq "") {
7437
        $first = $source;
7438
        Warning( "Unable to resolve '$source' path" );
7439
    } else {
7440
        Warning( "          using '$first'" )
7441
            if ($count);
7442
    }
7443
    return $first;
7444
}
7445
 
251 dpurdie 7446
#-------------------------------------------------------------------------------
7447
# Function        : MakeSrcResolve
7448
#
7449
# Description     : Locate a source file by examining the list of source
7450
#                   directories. There are a few frills
7451
#
7452
#                   Look for a source file in
7453
#                       1) %::BUILD_KNOWNFILES
7454
#                       2) %SRCS
7455
#                       3) Dirs specified by the array @SRCSDIRS
7456
#
7457
# Inputs          : Name of a file to resolve
7458
#
7459
# Returns         : Resolved path.
283 dpurdie 7460
#                   Input file - if not found at all
251 dpurdie 7461
#
227 dpurdie 7462
sub MakeSrcResolve
7463
{
7464
    my ($name) = @_;
7465
    my $file;
7466
 
251 dpurdie 7467
    if ( exists ( $::BUILD_KNOWNFILES{$name} ) ) {
7468
        #
7469
        #   The Known Files list is relative to ScmRoot
7470
        #   This must be included in the full path
7471
        #
7472
        $file = $ScmRoot . '/' . $::BUILD_KNOWNFILES{$name};
7473
 
7474
    } elsif ( exists $SRCS{$name} ) {
7475
        $file = $SRCS{$name};
7476
 
7477
    } else {
7478
        $file = MakeResolve( \@SRCDIRS, @_ )
7479
    }
227 dpurdie 7480
    return $file;
7481
}
7482
 
7483
 
7484
# MakeSrcResolveExtended
7485
#   from_global = 0 : Search user specified directories
7486
#               = 1 : Search LinkPkgArchive list
7487
#
7488
our @PkgSrcDirList;
7489
sub MakeSrcResolveExtended
7490
{
7491
    my ( $from_global, $file ) = @_;
7492
 
7493
    #
7494
    #   Simple Case. Resolve source from known source directories
7495
    #
7496
    #
7497
    return MakeSrcResolve( $file )
7498
        unless ( $from_global );
7499
 
7500
    #
7501
    #   Not so simple Case
7502
    #   Resolve the source from the imported packages
7503
    #
7504
    #   Create a list of directores to search, but only the first time
7505
    #       - LnkPkgArchive directories
7506
    #       - Interface directories - from BuildPkgArchive
7507
    #         Using target,product,platform include directories
7508
    #
7509
    unless ( @PkgSrcDirList )
7510
    {
7511
 
7512
        for my $entry (@{$::ScmBuildPkgRules{$ScmPlatform} })
7513
        {
7514
            next if ( $entry->{'TYPE'} eq 'build' );                    # Ignore BuildPkgArchives
7515
            for (@{$entry->{'PINCDIRS'}}, @{$entry->{'THXDIRS'}}, '' )
7516
            {
7517
                my $dir = $entry->{'ROOT'} . "/" . $_ ;
7518
                $dir =~ s~//~/~g;
7519
                $dir =~ s~/$~~;
7520
                push ( @PkgSrcDirList, $dir);
7521
            }
7522
        }
7523
        foreach ( @{$::BUILDINFO{$ScmPlatform}{PARTS}} )
7524
        {
7525
            my $dir = "$ScmRoot/$ScmInterface/include/$_";
7526
            push ( @PkgSrcDirList,  $dir )
7527
                if ( -d  $dir );
7528
        }
7529
 
7530
        foreach ( "/include" , "" )
7531
        {
7532
            my $dir = "$ScmRoot/$ScmInterface$_";
7533
            push ( @PkgSrcDirList,  $dir )
7534
                if ( -d  $dir );
7535
        }
7536
    }
7537
    return MakeResolve( \@PkgSrcDirList, $file );
7538
}
7539
 
7540
#-------------------------------------------------------------------------------
7541
# Function        : GetPackageRoot
7542
#
7543
# Description     : Determine the root directory for a given package
7544
#                   This routine is intended for non-standard JATS scripts that
7545
#                   access package contents directly
7546
#
7547
#                   Note: This routine does not attempt to handle multiple
7548
#                         instances of a package ( sysbasetypes ).
7549
#
7550
# Inputs          : $pname          - Name of the package
7551
#
7552
# Returns         :
7553
#
7554
sub GetPackageRoot
7555
{
7556
    my( $pname ) = @_;
7557
    Debug( "GetPackageRoot(@_)" );
7558
 
7559
    my $result = undef;
7560
    my $pkg = GetPackageEntry( $pname );
7561
    if ( $pkg )
7562
    {
7563
        $result = $pkg->{'ROOT'};
7564
        Debug( "GetPackageRoot: $result" );
7565
    }
7566
 
7567
    return $result;
7568
}
7569
 
7570
#-------------------------------------------------------------------------------
7571
# Function        : ActiveProject
7572
#
7573
# Description     : Determine if the specified project is currenly 'active'
7574
#
7575
# Inputs          : A list of projects. The projects may be comma seperated
7576
#
7577
# Returns         : TRUE    if the project is active
7578
#
7579
sub ActiveProject
7580
{
7581
    my ($project) = @_;
7582
    foreach (  split( '\s*,\s*', $project ) )
7583
    {
7584
        return 1
7585
            if ( $_ eq $::ScmBuildProject );
7586
    }
7587
    return 0;
7588
}
7589
 
7590
 
7591
#-------------------------------------------------------------------------------
7592
# Function        : ActivePlatform
7593
#
7594
# Description     : Determine if the specified platform is currently 'active'
7595
#                   This is used by all user directives in order to determine
7596
#                   if the directive should be ignored for the current platform
7597
#
7598
# Inputs          : $platform_spec      - A platform specifier
7599
#                                         This is a bit complex.
7600
#
241 dpurdie 7601
#                   Format of platform_spec. One or more of
7602
#                       PlatformName
7603
#                       AliasName
7604
#                       TargetName,--Target
7605
#                       --Project=ProjectName
7606
#                       --Defined=SomeValue
277 dpurdie 7607
#                       --MachType=SomeValue
227 dpurdie 7608
#
241 dpurdie 7609
#                   Each can be prefxied with a '!' to negate the test
7610
#
7611
#                   Valid options are:
271 dpurdie 7612
#                       --Target        - indicates that the platform is a 'target'
241 dpurdie 7613
#
7614
# Returns         : TRUE if the platform spec is satisfied
7615
#
227 dpurdie 7616
sub ActivePlatform
7617
{
7618
    my( $platform_spec ) = @_;
7619
    my( @platforms, $scmplatform, $platform );
7620
    my( %arguments, @args, $filter );
241 dpurdie 7621
    my @plist;
7622
    my ($match_count, $count_invert, $count_vert) = (0,0,0);
227 dpurdie 7623
 
241 dpurdie 7624
    #
7625
    #   Short circuit check
7626
    #   '*' is used so often that it pays to check it first
7627
    #
7628
    if ( $platform_spec eq '*' )
7629
    {
7630
        Debug3( " ActivePlatform(@_) = TRUE" );
7631
        return 1;
7632
    }
227 dpurdie 7633
 
241 dpurdie 7634
 
7635
    #
7636
    #   Platform specifier may be a comma seperated list
7637
    #   ie:  WIN32,MOS,XXX
7638
    #   Extract non-platform arguments
279 dpurdie 7639
    #   Process to yield a dummy platform of '0' or '1' - these will be seen later
241 dpurdie 7640
    #
7641
    foreach ( split( '\s*,\s*', $platform_spec ) )
7642
    {
7643
        if ( m~^(!?)--Project=(.+)~ ) {
7644
            my $result = ActiveProject( $2);
7645
            $result = $result ? 1 : 0;
7646
            push @plist, "$1$result";
7647
            next;
277 dpurdie 7648
 
7649
        } elsif ( m~^(!?)--Defined=(.+)~ ) {
241 dpurdie 7650
            my $result = 0;
7651
            no strict 'refs';
7652
            $result = 1 if ( defined( $$2 ) || defined( @$2 ) );
7653
            use strict 'refs';
7654
 
7655
            $result = $result ? 1 : 0;
7656
            push @plist, "$1$result";
7657
            next;
277 dpurdie 7658
 
7659
        } elsif ( m~^(!?)--MachType=(.+)~ ) {
7660
            my $result = ( uc($2) eq uc($::GBE_MACHTYPE) );
7661
            $result = $result ? 1 : 0;
7662
            push @plist, "$1$result";
7663
            next;
241 dpurdie 7664
        }
7665
 
7666
        #
7667
        #   Must be a platform argument
7668
        #   Add to a list
7669
        #
7670
        push @platforms, $_;
7671
    }
7672
 
7673
    #   Platform specified may be an Alias
7674
    #   Perform alias expansion
7675
    #
7676
    @platforms = ExpandPlatforms( @platforms );         # aliasing
227 dpurdie 7677
    Debug3( " ActivePlatform(@_)" );
7678
 
7679
#.. Arguments
241 dpurdie 7680
#   At this point we have a list of platforms and arguments
7681
#   Build up a hash of arguments for each platform being parsed
227 dpurdie 7682
#   Multiple arguments can follow a platform name
241 dpurdie 7683
#   Arguments apply to the preceeding platform name
227 dpurdie 7684
#
241 dpurdie 7685
    $platform = undef;
227 dpurdie 7686
    foreach ( @platforms )
7687
    {
241 dpurdie 7688
        if ( /^--Target/ ) {                     # Arguments
7689
            if ( $platform ) {
7690
                $arguments{$platform}{'Target'} = 1;
7691
            } else {
7692
                Warning ("No Platform preceedig platform option: $_");
7693
            }
7694
 
273 dpurdie 7695
        } elsif ( /^--Only(Prod)|(Debug)/ ) {
7696
            # Known arguments
7697
 
241 dpurdie 7698
        } elsif ( /^--/ ) {
7699
            Warning ("Unknown platform option: $_");
7700
 
227 dpurdie 7701
        } else {                                # Target
7702
            $platform = $_;
241 dpurdie 7703
            push @plist, $platform;
227 dpurdie 7704
        }
7705
    }
7706
 
241 dpurdie 7707
#.. Scan the expression
227 dpurdie 7708
#
7709
    $scmplatform = uc( $ScmPlatform );          # current platform
241 dpurdie 7710
    foreach ( @plist )
227 dpurdie 7711
    {
7712
        $platform = uc( Trim( $_ ) );           # trim white and convert case
7713
 
7714
        #
241 dpurdie 7715
        #   Determine filter comparison
7716
        #   Either a Platform or a Target
7717
        #
7718
        if ( $arguments{$platform}{'Target'} )
227 dpurdie 7719
        {
241 dpurdie 7720
            $filter = uc( $ScmTarget );
227 dpurdie 7721
        }
241 dpurdie 7722
        else
7723
        {
7724
            $filter = $scmplatform;             # filter specification
7725
        }
7726
 
227 dpurdie 7727
        Debug3( "   Platform=$platform, Filter=$filter" );
7728
 
7729
        #
7730
        #   Examine platform names
7731
        #   Allow negation of name (!), but all the names must be negated
7732
        #   as a mix does not make sense.
7733
        #   ie:     !P1,!P2,!P3     - All except P1,P2 or P3
7734
        #            P1,P2,P2       - Only P1,P2,P3
7735
        #
241 dpurdie 7736
        my $invert = 0;
7737
        if ( substr($platform, 0, 1) eq '!' )
7738
        {
7739
            $count_invert++;
7740
            $platform = substr($platform, 1);
227 dpurdie 7741
        }
7742
        else
241 dpurdie 7743
        {
7744
            $count_vert++;
7745
        }
227 dpurdie 7746
 
241 dpurdie 7747
        $match_count++ if ( $platform eq ''  ||
7748
                            $platform eq '*' ||
7749
                            $platform eq '1' ||
7750
                            $platform eq $filter );
227 dpurdie 7751
    }
7752
 
241 dpurdie 7753
    #
7754
    #   Sanity test
7755
    #   Force failure on bad sanity
7756
    #
7757
    if ( $count_vert && $count_invert )
7758
    {
7759
        Warning( "Platform expression makes no sense. Mixed use of '!' operator",
7760
                 "Expression: @_" );
7761
        return 0;
7762
    }
7763
 
7764
    #
7765
    #   Test for pass
7766
    #   If not using '!', then any match passes : P1 or P2 or P3
7767
    #   If are using '!', then any match is bad : !P1 and !P2 and !P3 == !(P1 or P2 or P3)
7768
    #
7769
    if ( ( $count_vert && $match_count ) || ( $count_invert && ( not $match_count) )   )
7770
    {
227 dpurdie 7771
        Debug3( " ActivePlatform(@_ == $ScmPlatform) = TRUE" );
7772
        return 1;
7773
    }
241 dpurdie 7774
 
227 dpurdie 7775
    Debug3( " ActivePlatform(@_ == $ScmPlatform) = FALSE" );
7776
    return 0;
7777
}
7778
 
7779
#-------------------------------------------------------------------------------
7780
# Function        : RegisterMakefileGenerate
7781
#
7782
# Description     : Register a function to be called at the start of the
7783
#                   makefile generation process
7784
#
7785
# Inputs          : $fname      - Name of the function
7786
#                   $args       - Function Arguments
7787
#
7788
# Returns         : Nothing
7789
#
7790
our @MF_Generators;
7791
sub RegisterMakefileGenerate
7792
{
7793
   my ($fref) = @_;
7794
   my $rtype = ref($fref) || 'not a reference';
7795
 
7796
   Error ("RegisterMakefileGenerate called incorrectly",
7797
          "First argument MUST be a code reference",
7798
          "It is a $rtype"
7799
          ) unless ( $rtype eq 'CODE' );
7800
 
7801
   #
7802
   #    Save the arguments by reference in an array
7803
   #    The array will be processed later
7804
   #
7805
   push @MF_Generators, \@_;
7806
}
7807
 
7808
#-------------------------------------------------------------------------------
271 dpurdie 7809
# Function        : RegisterSrcHook
7810
#
7811
# Description     : Register a function to be called when a source file is
7812
#                   declared
7813
#
7814
# Inputs          : $ext        - Extension of interest
7815
#                                 '*' will be used by all
7816
#                   $fname      - Name of the function
7817
#                   $args       - Function Arguments
7818
#
7819
# Returns         : Nothing
7820
#
7821
sub RegisterSrcHook
7822
{
7823
    my $ext = shift;
7824
    my ($fref) = @_;
7825
    my $rtype = ref($fref) || 'not a reference';
7826
 
7827
    Error ("RegisterSrcHook called incorrectly",
7828
           "Second argument MUST be a code reference",
7829
           "It is a $rtype"
7830
           ) unless ( $rtype eq 'CODE' );
7831
 
7832
    #
7833
    #    Save the arguments by reference in an array
7834
    #    The array will be processed later
7835
    #
7836
    push @{$MF_RegisterSrcHooks{$ext}}, \@_;
7837
}
7838
 
7839
 
7840
#-------------------------------------------------------------------------------
227 dpurdie 7841
# Function        : MakefileHeader
7842
#
7843
# Description:    : Generate a "standard" makefile header.
7844
#
7845
#..
7846
 
7847
sub MakefileHeader
7848
{
7849
    my ($file, $desc, $by, @trailing) = @_;
7850
    my ($diff);
7851
 
7852
    $diff = 0 if (($diff = ((80-5) - length($desc))) < 0);
7853
    $desc .= ' ' . ('-' x $diff);
7854
 
7855
    print $file <<EOF;
7856
# -*- mode: mak; -*-
7857
#-- $desc
7858
#
7859
#                   -- Please do not edit this file. --
7860
#
7861
#       To do so may result in a system failure, in additional to any
7862
#       changes made shall be overwritten.
7863
#
7864
# Created by $by
7865
#         on $::CurrentTime
7866
#
7867
EOF
7868
    #
7869
    #   Print out the trailer
7870
    #   This is an array. Place each entry on a new line
7871
    #
7872
    print $file $_ . "\n" for ( @trailing );
7873
}
7874
 
7875
###############################################################################
7876
# MakeFileGenerate:
7877
#       This subroutine does all of the actual make file generation based
7878
#       on information provided in the calls to the various public
7879
#       interface routines.
7880
#
7881
# Inputs:
7882
#
7883
# Returns:
7884
###############################################################################
7885
 
7886
my $MakefileGenerate_once = 0;
7887
sub MakefileGenerate
7888
{
7889
    my $Makefile = "$ScmPlatform.mk";
7890
    Debug( "MakefileGenerate: $Makefile" );
7891
 
7892
    #
7893
    #   Nasty things happen when we generate a makefile twice
7894
    #   Just warn the user and do nothing
7895
    #   If its in the common makefile.pl then just ignore it
7896
    #
7897
    if ( $ScmProcessingRootMake )
7898
    {
7899
        Warning ("MakefileGenerate directive is not allowed in common makefile.pl");
7900
        return;
7901
    }
7902
 
7903
    if ( $MakefileGenerate_once )
7904
    {
7905
        Warning ("MakefileGenerate should only be called once.",
7906
                 "Dir: $::Cwd");
7907
        return;
7908
    }
7909
    $MakefileGenerate_once = 1;
7910
 
7911
    #
7912
    #   Invoke all registered Makefile Generator functions
7913
    #   These allow clever directives to collect information to be
7914
    #   processed before the makefiles are created
7915
    #
7916
    while ( @MF_Generators )
7917
    {
7918
        Debug( "MakefileGenerate: Invoke RegisterMakefileGenerate function" );
7919
        my ($fname, @args) = @{shift @MF_Generators};
7920
        &$fname ( @args );
7921
    }
7922
 
7923
    #
7924
    #   Allow the toolset the opportunity to process all the collected data
7925
    #   before the makefile is created. This is optional
7926
    #
7927
    my( $if ) = MakeIf::Factory();              # build interface
7928
    $if->Preprocess();
7929
 
7930
    #
7931
    #   Auto package the 'descpkg' file
7932
    #   If this makefile packages any files, then it can also package the descpkg file
7933
    #   The descpkg will be piggybacked into all makefiles that do a package
7934
    #
7935
    if ( %PACKAGE_FILES || %PACKAGE_HDRS || %PACKAGE_CLSS || %PACKAGE_LIBS
7936
                        || %PACKAGE_SHLIBS || %PACKAGE_PROGS )
7937
    {
251 dpurdie 7938
        Src ('*', 'descpkg') unless ($SRCS{ descpkg });
7939
        PackageFile ('*', 'descpkg');
227 dpurdie 7940
    }
7941
 
7942
    #
7943
    #   Some toolsets NEED a relative root
261 dpurdie 7944
    #   Note: At the moment ScmRoot is relative anyway, thus this code
7945
    #         does nothing
227 dpurdie 7946
    #
7947
    my $gbe_root = $::ScmRoot;
7948
    if ( $::UseRelativeRoot )
7949
    {
7950
        $gbe_root =  RelPath( $::ScmRoot );
7951
    }
7952
 
7953
    #
7954
    #   Now start to create the makefile
7955
    #
7956
    open( MAKEFILE, ">$Makefile" ) || Error( "Cannot create $Makefile" );
7957
    ::MakefileHeader( *MAKEFILE,
7958
                      'Auto-generated Platform Dependent Makefile',
7959
                      "$ScmMakelib (version $ScmVersion)",
7960
                      "# Copyright (C) 1995-$::CurrentYear ERG Transit Systems, All rights reserved",
7961
                      '#',
7962
                      "# Located in $::Cwd",
7963
                      "# Platform $::ScmPlatform",
7964
                      '#' . ('-' x 79),
7965
                      );
7966
 
7967
    #
7968
    #   Ensure that some essential variables are set
7969
    #
7970
    print MAKEFILE <<EOF;
7971
#
7972
#   Validate essential environment variables
7973
#
7974
ifndef GBE_BIN
7975
    \$(error ERROR: GBE_BIN is not available)
7976
endif
7977
ifndef GBE_PERL
7978
    \$(error ERROR: GBE_PERL is not available)
7979
endif
7980
ifndef DEBUG
7981
    \$(error ERROR: DEBUG is not defined)
7982
endif
7983
EOF
7984
 
7985
 
7986
    print MAKEFILE <<EOF;
7987
 
7988
#
7989
#   Basic definitions
7990
#
261 dpurdie 7991
GBE_ROOT	:= $gbe_root
7992
GBE_ROOT_ABS	:= \$(abspath \$(GBE_ROOT))
227 dpurdie 7993
GBE_HOST	:= $::ScmHost
7994
GBE_HOSTMACH	:= $::GBE_MACHTYPE
7995
GBE_TARGET	:= $::ScmTarget
7996
GBE_MACHTYPE	:= $::ScmMachType
7997
GBE_PLATFORM	:= $::ScmPlatform
7998
GBE_PBASE	:= $::Pbase
7999
ifeq "\$(DEBUG)" "0"
8000
GBE_TYPE	:= P
8001
else
8002
GBE_TYPE	:= D
8003
endif
8004
EOF
8005
 
8006
MakePrint( "GBE_ARGS	:= @ScmPlatformArgs\n" )
8007
    if ( scalar @ScmPlatformArgs );
8008
 
8009
MakePrint( "GBE_PRODUCT	:= $ScmProduct\n" )
8010
    if ( $ScmProduct ne "" );
8011
 
8012
MakePrint( "GBE_OS_COMMON	:= $::BUILDINFO{$ScmPlatform}{OS_COMMON}\n" )
8013
    if ( exists($::BUILDINFO{$ScmPlatform}{OS_COMMON}) );
8014
 
8015
 
8016
    print MAKEFILE <<EOF;
8017
 
8018
SHELL           := \$(GBE_BIN)/sh
8019
SHELLARGS       :=
8020
EXTENDED_LINE   := \$(GBE_BIN)/extend.lst
8021
export EXTENDED_LINE MAKE
8022
 
8023
MFLAGS		:= --no-print --warn -r
8024
BUILDNAME	:= $::ScmBuildName
8025
BUILDVER	:= $::ScmBuildVersionFull
261 dpurdie 8026
BUILDVERNUM	:= $::ScmBuildVersion
227 dpurdie 8027
BUILDPREVIOUSVER := $::ScmBuildPreviousVersion
8028
DEPLOYPATCH	:= $ScmDeploymentPatch
8029
GBE_NOTOOLSTEST := $ScmNoToolsTest
8030
 
8031
#
8032
#   Ensure PWD is correctly set
8033
#
8034
PWD             := \$(CURDIR)
8035
export PWD
8036
 
261 dpurdie 8037
#
8038
#   NOSCMDEPEND - Used to remove dependency checking of build files
8039
#                 Used internally by the build system
8040
#   NODEPEND    - Used to suppress generated dependency file checking
8041
#                 Mostly done in jmake.pl
8042
#   EXPERT      - Used to suppress dependency on this makefile
8043
#
8044
EOF
8045
 
8046
MakePrint( "NOSCMDEPEND	?= " . ($ScmExpert ? '1' : '0' ) . "\n" );
8047
MakePrint( "EXPERT		?= " . ($ScmExpert ? '1' : '0' ) . "\n" );
8048
MakePrint( "NODEPEND	?= 0\n" );
8049
 
8050
print MAKEFILE <<EOF;
8051
 
8052
#
8053
#   SCM_MAKEFILE - The name of the file to depend upon
8054
#                  Supressed in EXPERT mode
8055
#
8056
ifneq (\$(EXPERT),0)
8057
SCM_MAKEFILE	:=
8058
NOSCMDEPEND	:= 1
8059
else
8060
SCM_MAKEFILE	:= $Makefile
8061
endif
8062
EOF
8063
 
267 dpurdie 8064
#
8065
#   Setup the base directory for the packaging process
8066
#   When building a deployable package the base directory is changed to match
8067
#   that used by the deployment world. This is done so that the descpkg file
8068
#   can be created in the correct location
8069
#
8070
my  $PKGDIR = "pkg/$::Pbase";
8071
    $PKGDIR = "build/deploy" if ( $DEPLOYPACKAGE );
8072
Verbose("Setting PKGDIR: $PKGDIR");
8073
 
261 dpurdie 8074
print MAKEFILE <<EOF;
8075
 
227 dpurdie 8076
#--------- Targets -------------------------------------------------------------
8077
 
8078
.PHONY: 	default all build install package unpackage uninstall \\
8079
		clean unbuild clobber deploy
8080
 
8081
default:	make_usage
8082
all:		install package deploy
8083
build:		make_init generate install_hdr depend make_lib \\
8084
		install_lib make_install_shlib make_prog install_class
8085
install:	build install_prog
8086
package:	package_files package_hdr package_lib package_shlib package_prog \\
8087
		package_class
8088
unpackage:	unpackage_class unpackage_prog unpackage_shlib \\
8089
		unpackage_lib unpackage_hdr unpackage_files
8090
uninstall:	uninstall_class uninstall_prog uninstall_shlib \\
8091
		uninstall_lib uninstall_hdr
8092
clean:		make_clean unmake_prog unmake_test unmake_lib unobj \\
261 dpurdie 8093
		undepend ungenerate rmlitter unmake_dir
227 dpurdie 8094
unbuild:	clean uninstall
8095
clobber:	unpackage unbuild
8096
deploy:		install run_deploy
8097
 
8098
#--------- Macros --------------------------------------------------------------
8099
 
8100
OBJDIR		= \$(GBE_PLATFORM)\$(GBE_TYPE).OBJ
8101
LIBDIR		= \$(GBE_PLATFORM).LIB
8102
BINDIR		= \$(GBE_PLATFORM)\$(GBE_TYPE).BIN
8103
CLSDIR		= classes\$(GBE_TYPE)
8104
 
267 dpurdie 8105
PKGDIR		= \$(GBE_ROOT)/$PKGDIR
227 dpurdie 8106
INCDIR_PKG	= \$(PKGDIR)/include
8107
LIBDIR_PKG	= \$(PKGDIR)/lib
8108
BINDIR_PKG	= \$(PKGDIR)/bin
8109
CLSDIR_PKG	= \$(PKGDIR)/classes
8110
 
8111
LOCALDIR	= \$(GBE_ROOT)/local
8112
INCDIR_LOCAL	= \$(LOCALDIR)/inc
8113
LIBDIR_LOCAL	= \$(LOCALDIR)/lib
8114
BINDIR_LOCAL	= \$(LOCALDIR)/bin
8115
CLSDIR_LOCAL	= \$(LOCALDIR)/classes
8116
BINDIR_LOCAL_PATH = \$(GBE_ROOT_ABS)/local/bin/\$(GBE_PLATFORM)\$(GBE_TYPE)
8117
 
8118
INTERFACEDIR	= \$(GBE_ROOT)/$ScmInterface
8119
INCDIR_INTERFACE= \$(INTERFACEDIR)/include
8120
LIBDIR_INTERFACE= \$(INTERFACEDIR)/lib
8121
BINDIR_INTERFACE= \$(INTERFACEDIR)/bin
8122
CLSDIR_INTERFACE= \$(INTERFACEDIR)/classes
8123
 
8124
.SUFFIXES:		# Delete the default suffixes
8125
 
8126
EOF
8127
 
8128
    MakePrintList( \@DEFINES );
8129
    MakeNewLine();
8130
 
8131
#-------------------------------------------------------------------------------
8132
#
8133
#
261 dpurdie 8134
    MakeHeader ("Defines, flags and file sets");
227 dpurdie 8135
 
8136
    # Flags
261 dpurdie 8137
    foreach my $opt ( keys %ScmCompilerOpts )
8138
    {
8139
        MakeDefEntry ( $opt, "=", $ScmCompilerOpts{$opt} );
8140
    }
227 dpurdie 8141
 
261 dpurdie 8142
    MakeDefEntry( "CFLAGS",         "=", \@CFLAGS, \@CFLAGS_PROD, \@CFLAGS_DEBUG );
8143
    MakeDefEntry( "CLINTFLAGS",     "=", \@CLINTFLAGS, \@CLINTFLAGS_PROD, \@CLINTFLAGS_DEBUG );
8144
    MakeDefEntry( "CDEPENDFLAGS",   "=", \@CFLAGS, \@CFLAGS_PROD, \@CFLAGS_DEBUG );
8145
    MakeDefEntry( "CXXFLAGS",       "=", \@CXXFLAGS, \@CXXFLAGS_PROD, \@CXXFLAGS_DEBUG );
8146
    MakeDefEntry( "CXXLINTFLAGS",   "=", \@CXXLINTFLAGS, \@CXXLINTFLAGS_PROD, \@CXXLINTFLAGS_DEBUG );
8147
    MakeDefEntry( "CXXDEPENDFLAG",  "=", \@CXXFLAGS, \@CXXFLAGS_PROD, \@CXXFLAGS_DEBUG );
267 dpurdie 8148
    MakeDefEntry( "ASFLAGS",        "=", \@ASFLAGS, \@ASFLAGS_PROD, \@ASFLAGS_DEBUG );
8149
    MakeDefEntry( "LDFLAGS",        "=", \@LDFLAGS, \@LDFLAGS_PROD, \@LDFLAGS_DEBUG );
227 dpurdie 8150
 
8151
 
8152
#-------------------------------------------------------------------------------
8153
#   
8154
#
261 dpurdie 8155
    MakeHeader ("Tool Search Path",
8156
                "Extend the PATH seen by all the tools to include",
8157
                "The tools/bin directories discovered in Packages" );
8158
    my $put_PATH;
8159
    my $put_LD_LIBRARY_PATH;
8160
    for my $path ( ToolExtensionPaths() )
8161
    {
8162
        MakePrint( "PATH := $path$::ScmPathSep\$(PATH)\n" );
8163
        $put_PATH = 1;
227 dpurdie 8164
 
261 dpurdie 8165
        if ( $::ScmHost eq "Unix" )
8166
        {
227 dpurdie 8167
        MakePrint( "LD_LIBRARY_PATH ?= \n" );
8168
        MakePrint( "LD_LIBRARY_PATH := $path$::ScmPathSep\$(LD_LIBRARY_PATH)\n" );
261 dpurdie 8169
            $put_LD_LIBRARY_PATH =1;
8170
        }
227 dpurdie 8171
    }
8172
 
261 dpurdie 8173
    #   Export the appropriate environment variables
8174
    #   Note: Windows has an issue with PATH and Path
8175
    #         Haven't got to the bottom of it yet, but it would appear that DLL
8176
    #         searching uses Path and other stuff uses PATH. Not too sure how we
8177
    #         end up with two (or more in the environment)
8178
    #
8179
    #
8180
    if ( $put_LD_LIBRARY_PATH )
8181
    {
227 dpurdie 8182
    MakePrint( "export LD_LIBRARY_PATH\n" );
261 dpurdie 8183
    }
227 dpurdie 8184
 
261 dpurdie 8185
    if ( $put_PATH )
8186
    {
227 dpurdie 8187
    MakePrint( "Path := \$(PATH)\n" );
8188
    MakePrint( "export PATH Path\n" );
261 dpurdie 8189
    }
227 dpurdie 8190
 
8191
#-------------------------------------------------------------------------------
8192
#   
8193
#
261 dpurdie 8194
    MakeHeader ("Perl Module Search Path",
8195
                "Extend the PERL5LIB seen by invocations of perl");
227 dpurdie 8196
 
261 dpurdie 8197
    my $perl_module_found;
8198
    for my $path ( ToolExtensionPaths() )
227 dpurdie 8199
    {
261 dpurdie 8200
        if (glob( "$path/*.pm"))
8201
        {
227 dpurdie 8202
        MakePrint( "PERL5LIB := $path$::ScmPathSep\$(PERL5LIB)\n" );
261 dpurdie 8203
            $perl_module_found = 1;
8204
        }
227 dpurdie 8205
    }
261 dpurdie 8206
    if ( $perl_module_found  )
8207
    {
227 dpurdie 8208
    MakePrint( "export PERL5LIB\n" );
261 dpurdie 8209
    }
227 dpurdie 8210
 
261 dpurdie 8211
#-------------------------------------------------------------------------------
8212
#   Internal Helper Functions
8213
#   Creating INCLUDE and LIBRARY paths
8214
#
8215
 
8216
# Assist in creating a list paths
8217
#   $pList  - Reference to an array to which $data will be added
8218
#   $pSeen  - Hash Ref to track tags that have been seen
8219
#   $data   - Data item to add, if tag is defined, but not seen
8220
#   $tag    - Resolved name for item
8221
#
227 dpurdie 8222
    sub PushPath
8223
    {
8224
        my ($pList, $pSeen, $data, $tag) = @_;
8225
        if ( $tag )
8226
        {
8227
            unless ( exists $pSeen->{$tag} )
8228
            {
8229
                $pSeen->{$tag} = 1;
8230
                push @{$pList}, $data;
8231
            }
8232
        }
8233
    }
8234
 
8235
    #
8236
    # Search paths for include files and libraries
8237
    # Currently symbolic paths are created, but there is very little need for this
8238
    #
8239
    sub MakePaths
8240
    {
8241
        my( $root ) = @_;
8242
        my @pathlist;
8243
        my %seen;
8244
 
8245
 
8246
        #   eg. SCA_WIN32   and SCA_WIN32       and SCA_SOLARIS
8247
        #       SCA             WIN32_i386          SPARC
8248
        #       WIN32           SCA                 SCA
8249
        #       .               WIN32               SOLARIS
8250
        #                       .                   .
8251
        #..
8252
        PushPath( \@pathlist, \%seen, "$root/\$(GBE_PLATFORM)",   $ScmPlatform );
8253
        PushPath( \@pathlist, \%seen, "$root/\$(GBE_PRODUCT)",    $ScmProduct );
8254
 
8255
        #
8256
        #   Insert extra path elements found in BUILDPLATFORM_PARTS
8257
        #   These will be present for BuildProduct (XXXX,-Uses=YYYY)
8258
        #   Note: Don't do for LOCAL paths, only INTERFACE
8259
        #
8260
        if ( $root =~ /INTERFACE/ ) {
8261
            my @parts = @{$::BUILDINFO{$ScmPlatform}{PARTS}};
8262
            foreach ( @parts ) {
8263
                PushPath( \@pathlist, \%seen, "$root/$_",   $_ );
8264
            }
8265
        }
8266
 
8267
        PushPath( \@pathlist, \%seen, "$root/\$(GBE_TARGET)",     $ScmTarget );
8268
 
8269
        push @pathlist, "$root";
8270
 
8271
        return \@pathlist;
8272
    }
8273
 
8274
#-------------------------------------------------------------------------------
8275
#   
8276
#
261 dpurdie 8277
    MakeHeader ("Include Search Paths",
8278
                "Local Include Paths" );
227 dpurdie 8279
 
8280
    # Include search path
8281
    #
8282
    #   user-local
8283
    #   local/
8284
    #           see above
8285
    #   interface/
8286
    #           see above
8287
    #   user-global
8288
    #
8289
 
261 dpurdie 8290
    MakeDefEntry ( "\nLINCDIRS",    "=", \@L_INCDIRS );     # .. Local
8291
    MakeDefEntry ( "LINCDIRS",      "+=", MakePaths( '$(INCDIR_LOCAL)' ));     # .. Sandbox interface
8292
    MakeDefEntry ( "LINCDIRS",      "+=", MakePaths( '$(INCDIR_INTERFACE)' )); # .. Sandbox interface
8293
    MakeDefEntry ( "LINCDIRS",      "+=", \@G_INCDIRS );    # .. Global
227 dpurdie 8294
 
261 dpurdie 8295
    MakeDefEntry   ( "INCDIRS",  "= ",  '$(LINCDIRS)' );
8296
    MakeIfDefEntry ( "PINCDIRS", "INCDIRS", "+=", '$(PINCDIRS)' );
8297
    MakeDefEntry   ( "LINCDIRS",    "+=", \@S_INCDIRS );    # .. System
227 dpurdie 8298
 
8299
    # Source search path
8300
 
261 dpurdie 8301
    MakeDefEntry( "\nNODEPDIRS",        "=", \@NODEPDIRS );
227 dpurdie 8302
 
261 dpurdie 8303
    MakeDefEntry( "\nSRCDIRS",          "=" , [ @L_SRCDIRS, @G_SRCDIRS ] );
8304
    MakeIfDefEntry ( "PINCDIRS", "SRCDIRS", "+= ", '$(PINCDIRS)' );
8305
    MakeDefEntry   ( "SRCDIRS",    "+=", \@S_INCDIRS );    # .. System
227 dpurdie 8306
 
8307
    # Library search path
8308
    #
8309
    #   user-local
8310
    #   local/
8311
    #           see above
8312
    #   interface/
8313
    #           see above
8314
    #   user-global
8315
 
261 dpurdie 8316
    MakeDefEntry( "\nLIBDIRS",  "=",  '$(LIBDIR)' );                    # User Local
8317
    MakeDefEntry( "LIBDIRS",    "+=", \@L_LIBDIRS );                    # Local
8318
    MakeDefEntry( "LIBDIRS",    "+=", MakePaths( '$(LIBDIR_LOCAL)' ));  # Sandbox/interface
8319
    MakeDefEntry( "LIBDIRS",    "+=", MakePaths( '$(LIBDIR_INTERFACE)' ));
8320
    MakeDefEntry( "LIBDIRS",    "+=", \@G_LIBDIRS );                    # Global
8321
    MakeIfDefEntry ( "PLIBDIRS", "LIBDIRS", "+= ", '$(PLIBDIRS)' );
8322
    MakeDefEntry( "LIBDIRS",    "+=", \@S_LIBDIRS );                    # System
227 dpurdie 8323
 
8324
#-------------------------------------------------------------------------------
8325
#
8326
#   Subdir creation and deletion
8327
#   Creation is done on the fly
8328
#   Deletion is done AFTER the toolset functions have been invoked to create the
8329
#   build artifacts so that the toolsets can create directories too
8330
 
8331
    MakeHeader ("Subdir creation");
8332
    CreateMkdirRules();
8333
    MkdirRule( "\$(OBJDIR)", 'OBJDIR' );                # Object build directory
8334
    MkdirRule( "\$(OBJDIR)/$_" ) foreach (@SHLIBS);     # Shared library build directory
8335
    MkdirRule( "\$(LIBDIR)", 'LIBDIR' );                # Library directory
8336
    MkdirRule( "\$(BINDIR)", 'BINDIR' );                # Binary directory
8337
 
261 dpurdie 8338
    #
8339
    #   Create a directory for library merge tool to work within
8340
    #
8341
    MkdirRule( "\$(MLIBDIR)", 'MLIBDIR', '--Path=$(GBE_PLATFORM).MRG', '--RemoveAll' ) if (@MLIBS);
8342
 
227 dpurdie 8343
#-------------------------------------------------------------------------------
8344
#   Generate rules and recipes to create all the toolset specific parts
8345
#   This is done fairly early to allow the toolsets to extend various
8346
#   definitions that may be used later in the makefile construction
8347
#
8348
    MakeHeader ("Construct Programs");
8349
 
8350
    sub argsplit
8351
    {
8352
        my ($ref) = @_;
8353
        my (@ret) = ();
8354
 
8355
        @ret = split( /$;/, $ref )              # split, only if defined
8356
            if ( defined($ref) );
8357
        return @ret;
8358
    }
8359
 
8360
    foreach my $i ( @PROGS )
8361
    {
261 dpurdie 8362
        my( @args, @objects, @libs, $l );
227 dpurdie 8363
 
8364
        @args    = argsplit( $PROG_ARGS{ $i } );
8365
        @objects = argsplit( $PROG_OBJS{ $i } );
8366
        @libs    = argsplit( $PROG_LIBS{ $i } );
8367
 
8368
 
8369
        MakePrint( "#---- (${i})\n\n" );
8370
        if ( $ScmToolsetProgDependancies )
8371
        {
261 dpurdie 8372
            #
8373
            #   Original style Prog Interface
271 dpurdie 8374
            #   Write some dependency information here and some in the toolset
8375
            #   Problems:
8376
            #       1) Errors in library dependency generation will be
8377
            #          reported after all the object files have been created
8378
            #          Thus the error message and the make-stop are seperated
8379
            #          by many,many lines of output. This makes it difficult
8380
            #          to see the error.
261 dpurdie 8381
            #
271 dpurdie 8382
            #       2) Lack of Flexability
8383
            #
261 dpurdie 8384
            MakeEntry( "\$(BINDIR)/$i$::exe: ", "", "\\\n\t\t", ".$::o ", @objects );
227 dpurdie 8385
        }
8386
        else
8387
        {
261 dpurdie 8388
            #
8389
            #   New Style Prog Interface
8390
            #   The toolset does it all
8391
            #
8392
            #   Flag the progam packaging as a placeholder.
8393
            #   The toolset will replace/update it.
8394
            #
227 dpurdie 8395
            PackageProgRemoveFiles( $i );
8396
        }
8397
 
8398
        $if->LD( $i, \@args, \@objects, \@libs );
8399
        $if->LDLINT( $i, \@args, \@objects, \@libs );
8400
    }
8401
 
8402
#-------------------------------------------------------------------------------
8403
#   
8404
#
8405
    MakeHeader ("Construct Test Programs");
8406
    foreach my $i ( keys %TESTPROGS )
8407
    {
261 dpurdie 8408
        my( @args, @objects, @libs, $l );
227 dpurdie 8409
 
8410
        @args    = argsplit( $TESTPROG_ARGS{ $i } );
8411
        @objects = argsplit( $TESTPROG_OBJS{ $i } );
8412
        @libs    = argsplit( $TESTPROG_LIBS{ $i } );
8413
 
8414
        MakePrint( "#---- (${i})\n\n" );
8415
        if ( $ScmToolsetProgDependancies )
8416
        {
261 dpurdie 8417
            MakeEntry( "\$(BINDIR)/$i$::exe: ", "", "\\\n\t\t", ".$::o ", @objects );
227 dpurdie 8418
        }
8419
        else
8420
        {
8421
            PackageProgRemoveFiles( $i );
8422
        }
8423
 
8424
        $if->LD( $i, \@args, \@objects, \@libs );
8425
        $if->LDLINT( $i, \@args, \@objects, \@libs );
8426
    }
8427
 
8428
#-------------------------------------------------------------------------------
8429
#
8430
#
8431
    MakeHeader ("Transfer Scripts to BINDIR");
8432
    foreach my $i ( sort ( values %SCRIPTS ))
8433
    {
8434
        my $tname = "\$(BINDIR)/" . StripDir( $i );
8435
 
8436
 
8437
        MakePrint( "$i:\t\tmakefile.pl\n" .
261 dpurdie 8438
            "\t\$(XX_PRE)if [ ! -f \"$i\" ]; then echo Script [$i] not found; exit 2; fi\n\n" );
227 dpurdie 8439
 
8440
        #
8441
        #   Create a rule to copy the script into the BIN directory
8442
        #   Mark the script as executable - It can't hurt and its there
8443
        #   to be run as part of a test.
8444
        #
8445
        MakePrint "$tname:\t\$(GBE_BINDIR) $i\n" .
8446
                  "\t\$(XX_PRE)\$(cp) -f $i $tname\n" .
8447
                  "\t\$(XX_PRE)\$(chmod) -f +wx $tname\n\n"
8448
    }
8449
 
8450
#-------------------------------------------------------------------------------
8451
#   
8452
#
8453
    MakeHeader ("Construct Libraries");
8454
    foreach my $i ( @LIBS )
8455
    {
8456
        my( @args, @objects );
8457
 
8458
        @objects = argsplit( $LIB_OBJS{ $i } );
8459
        @args    = argsplit( $LIB_ARGS{ $i } );
8460
 
8461
        MakePrint "#---- (${i})\n\n";
8462
        $if->AR( $i, \@args, \@objects );
8463
        $if->ARLINT( $i, \@args, \@objects );
8464
    }
8465
 
8466
    sub MlibEntry
8467
    {
8468
        my( $mlib, @libs ) = @_;
8469
        my @flib;
8470
 
8471
        MakePrint "\$(LIBDIR)/$mlib\$(GBE_TYPE).$::a:\t";
8472
        foreach my $lib ( @libs )
8473
        {
8474
            my ($slib, $sdir) = split( ',', $lib );
8475
 
8476
            #
283 dpurdie 8477
            #   By default the librares are pulled from LOCAL unless the
8478
            #   library is built in this directory, in which case it will
227 dpurdie 8479
            #
283 dpurdie 8480
            #
8481
            unless ( $sdir )
8482
            {
8483
                $sdir = ( exists $LIB_OBJS { $slib } ) ? '--Here' : '--Local';
8484
            }
227 dpurdie 8485
 
8486
            #
8487
            #   --Interface     - Pull library from the interface directory
8488
            #   --Local         - Pull library from the local directory
8489
            #   --SubDir=xxxx   - Pull library from specified subdirectory
283 dpurdie 8490
            #   --Here          - Pull from local directory if built locally
227 dpurdie 8491
            #   otherwise       - Pull library from specified subdirectory
8492
            #
8493
            if ($sdir eq '--Interface') {
8494
                $sdir = '$(LIBDIR_INTERFACE)/$(GBE_PLATFORM)';
8495
 
8496
            } elsif ( $sdir eq '--Local') {
8497
                $sdir = $PackageInfo{'Lib'}{'IBase'} .  # Base of Installed libs
8498
                        $PackageInfo{'Lib'}{'Dir'};     # Default subdir
8499
 
8500
            } elsif ( $sdir =~ m~^--SubDir=(.*)~ ) {
8501
                $sdir = $1 . '/$(LIBDIR)';
8502
 
283 dpurdie 8503
            } elsif ( $sdir eq '--Here') {
8504
                $sdir = '$(LIBDIR)';
8505
 
227 dpurdie 8506
            } else {
8507
                $sdir .= '/$(LIBDIR)';
8508
            }
8509
 
8510
            MakePrint "\\\n\t\t${sdir}/${slib}\$(GBE_TYPE).$::a";
8511
            push @flib, "${sdir}/${slib}";
8512
        }
8513
        return @flib;
8514
    }
8515
 
8516
    foreach my $i ( @MLIBS )
8517
    {
8518
        my( @args, @libs );
8519
 
261 dpurdie 8520
        MakePrint "#---- (${i})\n\n";
8521
 
227 dpurdie 8522
        @libs    = argsplit( $MLIB_LIBS{ $i } );
8523
        @args    = argsplit( $MLIB_ARGS{ $i } );
8524
 
8525
        unless ( defined &ToolsetARMerge )
8526
        {
8527
            Warning( "Merging of libraries not supported in this toolset yet" );
8528
            Warning( "MergeLibrary: \"$i\" will not be created" );
8529
        }
8530
        else
8531
        {
8532
            #
8533
            #   Create the dependency rule
8534
            #       Target library : source library list
8535
            #           Recipe - generated by the toolset
8536
            #
8537
            foreach ( @args )
8538
            {
8539
                Warning( "Ignoring unknown argument to MergeLibrary. $_" );
8540
            }
8541
            @libs = MlibEntry( $i, @libs );
8542
            $if->ARMerge( $i, \@args, \@libs );
8543
        }
8544
    }
8545
 
8546
    foreach my $i ( @SHLIBS )
8547
    {
8548
        my( @args, @objects, @libs );
8549
 
8550
        @args    = argsplit( $SHLIB_ARGS{ $i } );
8551
        @objects = argsplit( $SHLIB_OBJS{ $i } );
8552
        @libs    = argsplit( $SHLIB_LIBS{ $i } );
8553
 
8554
        $if->SHLD( $i, \@args, \@objects, \@libs );
8555
        $if->SHLDLINT( $i, \@args, \@objects, \@libs );
8556
    }
8557
 
8558
#-------------------------------------------------------------------------------
8559
#   Construct Objects
8560
#   For each object within OBJSOURCE construct the following:
8561
#
8562
#   $(OBJDIR)/object-name:     source-name [makefile]
8563
#       Toolset ...
8564
#
8565
#   
8566
#
8567
    MakeHeader ("Construct Objects");
8568
    foreach my $i ( sort keys %OBJSOURCE )
8569
    {
8570
        my( $src, $sname, $ext, $type, @args );
8571
 
8572
        $src  = $OBJSOURCE{ $i };
8573
        $sname = StripDir( $src );
8574
        $ext  = StripFile( $src );
8575
        $ext = lc($ext)
8576
            if ( $::ScmHost ne "Unix" );
8577
        $type = $ScmSourceTypes{ $ext }
8578
            unless (( $type = $SRC_TYPE{ $sname }) );
8579
 
8580
        #
8581
        #   Object source is an object file
8582
        #   No need the generate the object, just create makefile rule
261 dpurdie 8583
        #   [ddp] Not too sure how we get here
227 dpurdie 8584
        #
8585
        if ( $ext eq ".$::o" )
8586
        {
8587
            MakePrint "$src:";
261 dpurdie 8588
            MakePrint " \$(SCM_MAKEFILE)";
227 dpurdie 8589
            MakeNewLine();
8590
            next;
8591
        }
8592
 
8593
        #
8594
        #   Need to create object file
8595
        #
8596
        @args = split( /$;/, $SRC_ARGS{ StripDir( $sname ) } )
8597
            if $SRC_ARGS{ $sname };
8598
 
8599
        push( @args, "--Shared" )
8600
            if ( exists $SHOBJ_LIB{$i} );
8601
 
8602
        #
8603
        #   Convert relative paths to absolute paths if required by the
8604
        #   toolset. Some compilers need ABS paths to generate nice debug
8605
        #   information.
8606
        #
8607
        $src = AbsPath($src)
8608
            if ( $UseAbsObjects );
8609
 
8610
        #
8611
        #   Extract any user specified dependancies
261 dpurdie 8612
        #   These will be added to the dependency list
227 dpurdie 8613
        #
8614
        my @dlist;
8615
        @dlist = split( /$;/, $SRC_DEPEND{$sname} )
8616
            if ( exists $SRC_DEPEND{$sname} );
8617
 
261 dpurdie 8618
        #
8619
        #   Create the dependency part of the object rule
8620
        #   The source file MUST be the first dependent recipes
8621
        #   may assume that $< is the name source file
8622
        #
8623
        MakeEntry( "\$(OBJDIR)/$i.$::o: $src \$(SCM_MAKEFILE)", "", " \\\n\t", "", @dlist );
227 dpurdie 8624
 
8625
        if ( $type eq ".c" ) {
8626
            $if->CC(  $src, $i, \@args );
261 dpurdie 8627
 
227 dpurdie 8628
        } elsif ( $type eq ".cc" ) {
8629
            $if->CXX( $src, $i, \@args );
261 dpurdie 8630
 
227 dpurdie 8631
        } elsif ( $type eq ".asm" ) {
8632
            $if->AS( $src, $i, \@args );
261 dpurdie 8633
 
227 dpurdie 8634
        } else {
8635
            $if->EXT( $src, $i, \@args ) ||
8636
                Warning( "Don't know how to build '$ext' images' for $src, $i" );
8637
            MakeNewLine();
8638
        }
8639
    }
8640
 
8641
#-------------------------------------------------------------------------------
8642
#   Construct Projects
8643
#   Construct toolset specific projects
8644
#
8645
    MakeHeader ("Construct Projects");
8646
    while ( my($project, $entry) = each %PROJECTS)
8647
    {
8648
        $if->PROJECT( $entry );
8649
    }
8650
 
8651
#-------------------------------------------------------------------------------
8652
#   Automated tests
8653
#
8654
    MakeHeader ("Automated tests");
8655
 
8656
    my $idx = 0;
8657
    my @test_set = ("makefile.pl");
8658
    my @test_set_auto = ("makefile.pl");
8659
    my @copy_set = ();
8660
 
8661
    foreach my $pEntry ( @TESTS_TO_RUN )
8662
    {                                           # Foreach test
8663
        $idx++;
8664
        $pEntry->{'index'} = $idx;
8665
        $pEntry->{'test_name'} = "run_test_$idx";
8666
 
8667
        #
8668
        #   If the test is being run within a 'FrameWork' then the underlying
8669
        #   toolset must instantiate the frame work.
8670
        #
8671
        #   This may change. Perhaps frameworks shouldn't be a part of the
8672
        #   toolset. Perhaps they should be standalone. May change
8673
        #
8674
        if ( $pEntry->{framework} )
8675
        {
8676
            $if->TESTFRAMEWORK( $pEntry );
8677
        }
8678
 
8679
        #
8680
        #   Create a rule to run the test
8681
        #
8682
 
8683
        my $tdir_alias = $pEntry->{'testdir'};
8684
        my $tdir = '$(' . $tdir_alias . ')';
8685
 
8686
        my $test_name = $pEntry->{'test_name'};
8687
        push @test_set, $test_name;
8688
        push @test_set_auto, $test_name if ($pEntry->{'auto'} );
8689
 
8690
        my $tprog = $tdir . '/' . StripDir( $pEntry->{'prog'} );
8691
 
8692
        my $me = MakeEntry::New( *MAKEFILE, $test_name, '--Phony' );
8693
        $me->AddDependancy( "\$(GBE_$tdir_alias)" );
8694
        $me->AddDependancy( "\$(INTERFACEDIR)/set_$::ScmPlatform.sh" );
8695
        $me->AddDependancy( $tprog ) if $pEntry->{'copyprog'};
8696
        $me->AddDependancy( @{ $pEntry->{'copyin' } } );
8697
        $me->AddDependancy( map { $tdir . '/' . StripDir($_) } @{ $pEntry->{'copyonce' } } );
8698
        $me->AddDependancy( @{ $pEntry->{'preq'} } );
8699
        $me->RecipePrefix ('$(XX_PRE)');
8700
        $me->RecipeComment( "------ Running test [$idx] ..." );
8701
 
8702
        #
8703
        #   Extend the PATH seen by the script to include the local/bin directory
8704
        #   Allows programs and tests that have been created elsewhere in the component
8705
        #   to be accessed within the script.
8706
        #
8707
        $me->AddShellRecipe ( ". \$(INTERFACEDIR)/set_$::ScmPlatform.sh" );
8708
 
8709
        #
8710
        #   Copy in the files that we need
8711
        #
8712
        foreach my $file ( @{$pEntry->{'copyin'}} )
8713
        {
8714
            my $dst = $tdir . '/' . StripDir( $file );
8715
            UniquePush( \@COPYIN, $dst );
8716
            UniquePush( \@copy_set, $file );
8717
            $me->AddShellRecipe ( "\$(cp) -f $file $dst" );
8718
            $me->AddShellRecipe ( "\$(chmod) -f +wx $dst" );
8719
        }
8720
 
8721
        #
8722
        #   Insert and FrameWork Recipe bits
8723
        #
8724
        $me->AddShellRecipe ( @{$pEntry->{'ShellRecipe'}} );
8725
 
8726
        $me->AddShellRecipe ( "cd $tdir" );
8727
        $me->AddShellRecipe ( ["GBE_TYPE=\$(GBE_TYPE)",
8728
                               "GBE_HOST=\$(GBE_HOST)",
8729
                               "GBE_ROOT=\$(GBE_ROOT_ABS)",
8730
                    		   "PATH=.\\$::ScmPathSep\$(BINDIR_LOCAL_PATH)\\$::ScmPathSep\$\$PATH",
8731
                               $pEntry->{'command'},
8732
                               @{$pEntry->{'args'}},
8733
                               ] );
8734
        $me->Print();
8735
 
8736
 
8737
        #
8738
        #   Create entries to handle the copy-once files
8739
        #
8740
        foreach my $file ( @{ $pEntry->{'copyonce' } } )
8741
        {
8742
            my $tname = $tdir . '/' . StripDir($file);
8743
            my $me = MakeEntry::New( *MAKEFILE, $tname  );
8744
            $me->AddDependancy( $file );
8745
            $me->AddRecipe ( "\$(call CopyFile,CopyIn,$tname,$file,$tdir,)"  );
8746
            $me->Print();
8747
 
8748
            UniquePush( \@COPYIN, $tname );
8749
            UniquePush( \@copy_set, $file );
8750
 
8751
        }
8752
    }
8753
 
8754
    #
8755
    #   Generate a target that specifies the tests to be run
8756
    #   Each test is provided with a dummy name
8757
    #
8758
    push @test_set, @TESTPROJECT_TO_ARUN;
8759
    push @test_set, @TESTPROJECT_TO_URUN;
8760
    MakeEntry3("\nrun_tests", ":", \@test_set )
8761
        if (@test_set);
8762
 
8763
    push @test_set_auto, @TESTPROJECT_TO_ARUN;
8764
    MakeEntry3("\nrun_unit_tests", ":", \@test_set_auto )
8765
        if (@test_set_auto);
8766
 
8767
    #
8768
    #   Generate sanity test for each copyin script
8769
    #   Simply to provide a nice error message for generated scripts
8770
    #   that do not exist at run-time
8771
    #
8772
    test_copy_in:
8773
    foreach my $i ( @copy_set )
8774
    {
8775
        next if ( $SCRIPTS{$i} );
8776
        foreach (  @SHLIB_TARGETS )
8777
        {
8778
            next test_copy_in if ( $i eq $_ );
8779
        }
8780
        MakePrint( "\n$i:\t\tmakefile.pl\n" .
8781
            "\t\@if [ ! -f \"$i\" ]; then echo ERROR: CopyIn Script [$i] not found; exit 2; fi\n" );
8782
    }
8783
 
261 dpurdie 8784
#-------------------------------------------------------------------------------
8785
#   Deploy rules
8786
#
8787
MakeHeader ("Deploy Rules");
227 dpurdie 8788
 
261 dpurdie 8789
print MAKEFILE <<EOF;
8790
.PHONY:		run_deploy
8791
EOF
227 dpurdie 8792
 
261 dpurdie 8793
#
8794
#   Build up the deployfile.pl command line from the available pieces
8795
#
8796
my $command_file = "";
8797
my @command_line;
8798
 
8799
if ( %DEPLOYPACKAGE )
8800
{
8801
    $command_file = $DEPLOYPACKAGE{'cmdfile'};
8802
 
8803
    push @command_line, "\$(XX_PRE)\$(GBE_PERL) -w $command_file";
8804
    push @command_line, "-r \"\$(GBE_ROOT)\"";
8805
    push @command_line, "-n \"$DEPLOYPACKAGE{'name'}\"";
8806
    push @command_line, "-d \"$DEPLOYPACKAGE{'dir'}\"";
8807
    push @command_line, "-v \"\$(BUILDVER)\"";
8808
    push @command_line, "-t \"\$(GBE_TYPE)\"";
8809
    push @command_line, "-o \"\$(BUILDPREVIOUSVER)\"";
8810
    push @command_line, "-m \"\$(GBE_PLATFORM)\"";
8811
    push @command_line, "-g \"\$(GBE_TARGET)\"";
8812
    push @command_line, "-k \"\$(GBE_PRODUCT)\""        if ( $ScmProduct );
8813
    push @command_line, "-p \"\$(DEPLOYPATCH)\""        if ( $ScmDeploymentPatch );
8814
 
8815
}
8816
 
8817
MakeEntry( "run_deploy:\t$command_file\n", "\n", "\t\t", " \\\n", @command_line );
8818
 
227 dpurdie 8819
#-------------------------------------------------------------------------------
261 dpurdie 8820
#   Custom Rules
8821
#
8822
    MakeHeader ("Custom Rules");
8823
    MakePrintList ( \@RULES );
8824
 
8825
#-------------------------------------------------------------------------------
8826
#   Generated Files
8827
#
8828
    MakeHeader ("Generated Files");
8829
    MakePrint ("\n.PHONY: phony_generate\n\n" );
8830
 
8831
    foreach my $i ( @GENERATE_FILES )
8832
    {
8833
        my $gen_tag = $i->{'index'};
8834
 
8835
        #
263 dpurdie 8836
        #   If predelete is enabled, then create a list of files to delete
8837
        #
8838
        if ( $i->{'predelete'}  )
8839
        {
8840
            MakeDefEntry( "generate_gen_$gen_tag", "=",  $i->{'gen'} );
8841
            MakePrint("\n")
8842
        }
8843
 
8844
 
8845
        #
261 dpurdie 8846
        #   Generate the basic generate rule and recipe
8847
        #   together with the prerequisites
8848
        #
8849
        MakeEntry ( "", ":", "", " ", @{$i->{'gen'}} );
8850
 
8851
        unless ( $i->{'clean'} && $i->{'shell'} )
8852
        {
8853
            MakeEntry ( "", "", " \\\n\t\t", "", @{$i->{'preq'}} );
8854
            MakeEntry ( "", "", " \\\n\t\t", "", "phony_generate" ) if $i->{'preq_sus'};
8855
            MakeEntry ( "", "", " \\\n\t\t", "", "\$(SCM_MAKEFILE)" );
8856
 
8857
            MakePrint ("\n\t" . "\@\$(echo) [$i->{'text'}] generating.." );
263 dpurdie 8858
            if ( $i->{'predelete'}  )
8859
            {
8860
                MakePrint ("\n\t" . "\$(XX_PRE)\$(call RmFiles,generate_gen_$gen_tag)" );
8861
            }
261 dpurdie 8862
            MakePrint ("\n\t" . "\$(XX_PRE)\$(call generate_$gen_tag,)" );
8863
        }
8864
 
8865
        #
8866
        #   Generate 'clean' rules and recipes
8867
        #
8868
        if ( $i->{'clean'} )
8869
        {
8870
            MakePrint ("\n\nPHONY: clean_generate_$gen_tag" );
8871
            MakePrint ("\nclean_generate_$gen_tag:" );
8872
            MakePrint ("\n\t" . "\@\$(call generate_$gen_tag,$i->{'clean'})" );
8873
        }
8874
 
8875
        #
8876
        #   Define a function to contain the body of the generation call
8877
        #   The first argument will be a 'clean' argument
8878
        #
8879
        MakePrint ("\n\ndefine generate_$gen_tag" );
8880
        if ( $i->{'shell'} )
8881
        {
8882
            MakeEntry ("\n\t(" , "\\\n\t)\n", " \\\n\t", ";" , @{$i->{'toolargs'}} );
8883
        }
8884
        else
8885
        {
8886
            MakeEntry ("\n\t" . $i->{'tool'} . ' $1', "\n", " \\\n\t\t", "" , @{$i->{'toolargs'}} );
8887
        }
8888
        MakePrint ("endef\n\n" );
8889
    }
8890
 
8891
#-------------------------------------------------------------------------------
8892
#   Toolset Post Processing
8893
#   Allow the toolset to perform any post processing, before we finally write
8894
#   out any definitions.
8895
#
8896
#   We will not interprete any more user directives, but new stuff may get added
8897
#
8898
#
8899
MakeHeader ("Toolset Post Processing");
8900
$if->Postprocess();
8901
 
8902
################################################################################
8903
#   All interactions with the toolset are now complete
8904
#   All lists are now complete
8905
#
8906
#   Can now create internal definitions
8907
#   
8908
################################################################################
8909
 
8910
    #
8911
    #   Would be nice if this would work
8912
    #   Unfortunatelty we still need $if for the CCDEPENDS and CTAGS work
8913
    #   These must be defined AFTER the definitions
8914
    #
8915
    #   Ideally we should construct our makefile in sections
8916
    #   and then we can order the sections when we write them out
8917
    #
8918
#$if = 0;                            # Ensure the MakeIf class is not called
8919
                                     # If this file is modified
8920
 
8921
#-------------------------------------------------------------------------------
227 dpurdie 8922
#   Sources
8923
#
8924
MakeHeader  ( "Sources");
8925
MakeDefEntry( "CSRCS",      "=",  \@CSRCS );
8926
MakeDefEntry( "CXXSRCS",    "=",  \@CXXSRCS );
8927
MakeDefEntry( "ASSRCS",     "=",  \@ASSRCS );
8928
 
8929
#-------------------------------------------------------------------------------
8930
#   Generated, Installed and Packaged components
8931
#
8932
MakeHeader  ("Generated, Installed and Packaged components");
8933
MakeDefEntry( "INITS",           "=",  \@INITS )   if ( @INITS );
8934
MakeDefEntry( "GENERATED",       "=",  \@GENERATED ) if ( @GENERATED );
8935
MakeDefEntry( "GENERATED_NOTSRC","=",  \@GENERATED_NOTSRC ) if ( @GENERATED_NOTSRC );
8936
MakeDefEntry( "GENERATEDCLEAN",  "=",  CreateNameList( 'clean_generate_', '', ListCleanGenerated() ));
8937
MakeDefEntry( "INSTALL_HDRS",    "=",  \%INSTALL_HDRS ) if ( %INSTALL_HDRS );
8938
MakeDefEntry( "INSTALL_CLSS",    "=",  \%INSTALL_CLSS ) if ( %INSTALL_CLSS );
8939
MakeDefEntry( "OBJS",            "=", CreateNameList( '$(OBJDIR)/', ".$::o", \@OBJS) );
8940
MakeDefEntry( "SHOBJS",          "=", CreateNameList( '$(OBJDIR)/', ".$::o", \%SHOBJ_LIB ));
8941
MakeDefEntry( "PROGOBJS",        "=", CreateNameList( '$(OBJDIR)/', ".$::o", \@PROGOBJS ));
8942
MakeDefEntry( "TESTPROGOBJS",    "=", CreateNameList( '$(OBJDIR)/', ".$::o", \%TESTPROG_OBJS ));
8943
MakeDefEntry( "LIBS",            "=", CreateNameList( '$(LIBDIR)/', "\$(GBE_TYPE).$::a", \@LIBS)) if ($::a);
8944
MakeDefEntry( "MLIBS",           "=", CreateNameList( '$(LIBDIR)/', "\$(GBE_TYPE).$::a", \@MLIBS)) if ($::a);
8945
MakeDefEntry( "SHNAMES",         "=", \@SHLIBS );
8946
MakeDefEntry( "SHDIRS",          "=", CreateNameList( '$(OBJDIR)/', "", \@SHLIBS ));
8947
MakeDefEntry( "SHLIBS",          "=", \@SHLIB_TARGETS );
8948
MakeDefEntry( "SCRIPTS",         "=", CreateNameList( '$(BINDIR)/', "", \%SCRIPTS ));
8949
MakeDefEntry( "COPYIN",          "=", \@COPYIN );
8950
MakeDefEntry( "PROGS",           "=", CreateNameList( '$(BINDIR)/', "$::exe", \@PROGS ));
8951
MakeDefEntry( "PROGS_EXTRA",     "=", \@PROGS_EXTRA );
8952
MakeDefEntry( "TESTPROGS",       "=", CreateNameList( '$(BINDIR)/', "$::exe", \%TESTPROGS ));
8953
MakeDefEntry( "LINTLIBS",        "=", CreateNameList( 'lib_', '_lint', \@LINTLIBS ));
8954
MakeDefEntry( "LINTSHLIBS",      "=", CreateNameList( 'shlib_', '_lint', \@LINTSHLIBS ));
8955
MakeDefEntry( "LINTPROGS",       "=", CreateNameList( 'prog_', '_lint', \@PROGS ));
8956
MakeDefEntry( "LINTPROGS",      "+=", CreateNameList( 'prog_', '_lint', \%TESTPROGS ));
8957
MakeDefEntry( "PROJECTS",        "=", CreateNameList( 'Project_', '', ListGeneratedProjects(1) ));
8958
MakeDefEntry( "PROJECTSGEN",     "=", CreateNameList( 'Project_', '', ListGeneratedProjects(0) ));
8959
MakeDefEntry( "PROJECTSCLEAN",   "=", CreateNameList( 'ProjectClean_', '', \%PROJECTS ));
8960
 
261 dpurdie 8961
MakeHeader ("Toolset components");
8962
MakeDefEntry( "USERGENERATED",        "=", \@USERGENERATED )    if ( @USERGENERATED );
8963
MakeDefEntry( "TOOLSETGENERATED",     "=", \@TOOLSETGENERATED ) if ( @TOOLSETGENERATED );
8964
MakeDefEntry( "TOOLSETOBJS",          "=", \@TOOLSETOBJS )      if ( @TOOLSETOBJS );
8965
MakeDefEntry( "TOOLSETLIBS",          "=", \@TOOLSETLIBS )      if ( @TOOLSETLIBS );
8966
MakeDefEntry( "TOOLSETPROGS",         "=", \@TOOLSETPROGS )     if ( @TOOLSETPROGS );
8967
MakeDefEntry( "TOOLSETDIRS",          "=", \@TOOLSETDIRS )      if ( @TOOLSETDIRS );
8968
MakeDefEntry( "TOOLSETDIRTREES",      "=", \@TOOLSETDIRTREES )  if ( @TOOLSETDIRTREES );
227 dpurdie 8969
 
8970
#--------- Determine compiler flag groups to use ----------------------------
8971
#
8972
#   Allows the compiler options to be controlled for both the debug and
8973
#   the production builds. Allows control over
8974
#       1) Optimisations
8975
#       2) Debug Information
8976
#
8977
MakeHeader ("Determine compiler flag groups to use");
8978
 
8979
print MAKEFILE <<EOF;
8980
 
8981
ifneq "\$(DEBUG)" "1"
8982
USE_OPTIMISE	:= \$(PROD_USE_OPTIMISE)
8983
USE_DEBUGINFO	:= \$(PROD_USE_DEBUGINFO)
8984
else
8985
USE_OPTIMISE	:= \$(DEBUG_USE_OPTIMISE)
8986
USE_DEBUGINFO	:= \$(DEBUG_USE_DEBUGINFO)
8987
endif
8988
 
8989
EOF
8990
 
261 dpurdie 8991
#-------------------------------------------------------------------------------
8992
#   Source browsing tools
8993
#
8994
MakeHeader ("Source browsing tools");
8995
    print MAKEFILE <<EOF;
8996
.PHONY:			ctags
8997
ctags:
8998
EOF
8999
    $if->CTAGS()
9000
        if (@CSRCS || @CXXSRCS);
227 dpurdie 9001
 
261 dpurdie 9002
#-------------------------------------------------------------------------------
9003
#   Depend
9004
#   If we are build C or C++ source files then create rules and recipes
9005
#   to invoke a dependency generator.
227 dpurdie 9006
#
261 dpurdie 9007
#   NODEPEND is used to disable, at make-time, the dependency generation
9008
#   and inclusion process.
9009
#
9010
#
9011
MakeHeader ("Depend");
9012
if ($::o && (@CSRCS || @CXXSRCS))
9013
{
9014
    $ScmDependTags = 1;
9015
    print MAKEFILE <<EOF;
9016
depend:			\$(OBJDIR)/depend
9017
 
9018
\$(OBJDIR)/depend:	\$(SCM_MAKEFILE) \$(GBE_OBJDIR)
9019
\$(OBJDIR)/depend:	\$(CSRCS) \$(CXXSRCS)
9020
ifeq (\$(NODEPEND),0)
9021
	\@echo [\$@] Doing a make depend..
9022
	-\$(XX_PRE)\$(rm) -f \$(OBJDIR)/depend
9023
EOF
9024
    $if->CCDepend( "\$(OBJDIR)/depend", "\$(CSRCS)" )
9025
        if ( @CSRCS );
9026
    $if->CXXDepend( "\$(OBJDIR)/depend", "\$(CXXSRCS)" )
9027
        if ( @CXXSRCS );
9028
    MakePrint
9029
        "\t-\@\$(touch) -f \$(OBJDIR)/depend\n";
9030
    print MAKEFILE <<EOF;
9031
else
9032
	\@echo [\$@] Skipping make depend..
9033
	-\$(XX_PRE)\$(rm) -f \$(OBJDIR)/depend
9034
endif
9035
EOF
9036
}
9037
else
9038
{
9039
    print MAKEFILE <<EOF;
9040
depend:
9041
EOF
9042
}
9043
 
9044
#
9045
#   Rule to unmake the depend file
9046
#
9047
    print MAKEFILE <<EOF;
9048
 
9049
undepend:
9050
	-\$(XX_PRE)\$(rm) -f \$(OBJDIR)/depend
9051
EOF
9052
 
9053
#--------- IFLAG Documentation -------------------------------------------------
9054
#
9055
#   IFLAG - iteration flag. This is setting by the calling process
9056
#                           and is a function of the phase being processed
227 dpurdie 9057
#       0   No external dependencies.
9058
#       1   Source dependency list.
261 dpurdie 9059
#       2   Shared library dependency list
9060
#       3   Application dependency list
227 dpurdie 9061
#
9062
#
261 dpurdie 9063
#--------- Dependencies --------------------------------------------------------
9064
#   Include the 'depend' file if required
9065
#
9066
    MakeHeader ("Dependency Inclusion");
9067
    print MAKEFILE <<EOF;
9068
ifeq (\$(NODEPEND),0)
9069
 ifdef IFLAG
9070
  ifneq "\$(IFLAG)" "0"
9071
-include	\$(OBJDIR)/depend
9072
  endif
227 dpurdie 9073
 endif
9074
endif
9075
 
9076
EOF
9077
 
9078
#-------------------------------------------------------------------------------
9079
#   Special targets
9080
#
261 dpurdie 9081
MakeHeader ("Special targets",
9082
            "These targets are not used by JATS",
9083
            "They can only used when the makefile is used directly",
9084
            "This is not the intended use of this makefile",
9085
           );
227 dpurdie 9086
 
9087
print MAKEFILE <<EOF;
9088
.PHONY:		debug
9089
debug:
9090
	@\$(MAKE) -f \$(GBE_PLATFORM).mk DEBUG=1 build
9091
 
9092
.PHONY:		prod
9093
prod:
9094
	@\$(MAKE) -f \$(GBE_PLATFORM).mk DEBUG=0 build
9095
 
9096
EOF
9097
 
9098
    #
9099
    #   It would appear that these targets are not directly available
9100
    #   They can only be accessed if the makefile is used directly, and this
9101
    #   is not the intended use
9102
    #
261 dpurdie 9103
    MakePrint("#   PROGS\n");
227 dpurdie 9104
    foreach my $i ( @PROGS ) {
9105
        MakePrint "${i}:\tmake_init \$(BINDIR)/${i}$::exe\n";
9106
    }
261 dpurdie 9107
    MakeNewLine();
227 dpurdie 9108
 
261 dpurdie 9109
    MakePrint("#   TESTPROGS\n");
227 dpurdie 9110
    foreach my $i ( sort keys %TESTPROGS ) {
9111
        MakePrint "${i}:\tmake_init \$(BINDIR)/${i}$::exe\n";
9112
    }
9113
    MakeNewLine();
9114
 
261 dpurdie 9115
    MakePrint("#   PACKAGE_DIST\n");
227 dpurdie 9116
    foreach my $i ( sort keys %PACKAGE_DIST ) {
9117
        my(@sets) = split( /$;/, $PACKAGE_DIST{$i} );
9118
 
9119
        MakeEntry( "package-${i}:\tmake_init package_setALL",
9120
                "\n", " package_set", "", @sets );
9121
    }
9122
    MakeNewLine();
9123
 
9124
#-------------------------------------------------------------------------------
9125
#   Standard rules
9126
#
9127
MakeHeader ("Standard rules");
9128
 
9129
    print MAKEFILE <<EOF;
9130
.PHONY:		make_usage
9131
make_usage:
9132
	\@echo -e \\
9133
	" make [SHOWENV=1] [LEAVETMP=1] [OPTIONS=[opt][,...]] {DEBUG=0|1} target(s)\\n"\\
9134
	"\\n"\\
9135
	"Build one or more of the following targets for the platform\\n"\\
9136
	"$ScmPlatform, recursively checking each configured sub directories.\\n"\\
9137
	"\\n"\\
9138
	"Valid targets include:\\n"\\
9139
	"  all:             build, install and package\\n"\\
9140
	"  build:           build everything\\n"\\
9141
	"  debug:           build all things for debug\\n"\\
9142
	"  prod:            build all things for production\\n"\\
9143
	"  install:         install of public usage\\n"\\
9144
	"  depend:          construct the dependencies\\n"\\
9145
	"  lint:            lints C and C++ source\\n"\\
9146
	"  package:         build all packages\\n"\\
9147
	"  package-{set}:   build specific package\\n"\\
9148
	"  unpackage:       remove all packages\\n"\\
9149
	"  run_tests:       Run the tests specified in the makefile\\n"\\
9150
	"  run_unit_tests:  Run the automatic unit tests specified in the makefile\\n"\\
9151
	"  deploy:          Run the deployment scripts\\n"\\
9152
	"  rmlitter:        remove litter (core, bak, tmp, err and cmd files)\\n"\\
9153
	"  clean:           delete generate, obj, libraries and programs\\n"\\
9154
	"  unbuild:         delete everything which can be remade\\n"\\
9155
	"  clobber:         unbuilds and deletes packages\\n"\\
9156
EOF
9157
if ( scalar @PROGS ) {
9158
    print MAKEFILE <<EOF;
9159
	"\\n"\\
9160
	"Application targets:\\n"\\
9161
	"  @PROGS\\n"\\
9162
EOF
9163
}
9164
if ( %TESTPROGS ) {
9165
    print MAKEFILE <<EOF;
9166
	"\\n"\\
9167
	"Test Application targets:\\n"\\
9168
EOF
9169
        MakeEntry( "\t\"   ", "\\n\"\\\n", " ", "", sort keys(%TESTPROGS) );
9170
}
9171
if ( %PACKAGE_DIST ) {
9172
    print MAKEFILE <<EOF;
9173
	"\\n"\\
9174
	"Package distributions:\\n"\\
9175
EOF
9176
    foreach my $i ( sort keys %PACKAGE_DIST ) {
9177
        my(@sets) = split( /$;/, $PACKAGE_DIST{$i} );
9178
        MakeEntry( "\t\"   ${i}, using set(s)", "\\n\"\\\n", " ", "", @sets );
9179
    }
9180
}
9181
 
9182
    print MAKEFILE <<EOF;
9183
	"\\n"
9184
 
9185
make_clean:
9186
	-\@echo "Removing generated files (objects, libraries, binaries etc)";
9187
 
9188
#
9189
#   Under windows/cygwin, there is a problem with the rm being used
9190
#   The expansion of wildcards will terminate the command if:
9191
#       1) No files exist to expand  : Solution : touch a file of that type
9192
#       2) A directory is involved   : Solution : cd to directory
9193
#
9194
#   Cannot use make's wildcard function as this only operates in the current directory
9195
#
9196
.PHONY:		rmlitter
9197
rmlitter:
9198
	-\$(XX_PRE)( echo "Removing litter"; \\
9199
		\$(touch) _delete.bak _delete.tmp _delete.err ;\\
9200
		\$(rm) -f core *.bak *.tmp *.err ;\\
9201
		for subdir in \$(SHDIRS) \$(OBJDIR) ; do \\
9202
			if [ -d \$\$subdir ] ; then \\
9203
				( cd \$\$subdir ;\\
9204
				\$(touch) _delete.err _delete.cmd ;\\
9205
				\$(rm) -r *.err *.cmd ; );\\
9206
			fi ;\\
9207
		done;\\
9208
	)
9209
 
261 dpurdie 9210
.PHONY:		lint_init
9211
lint_init:
9212
 
227 dpurdie 9213
EOF
9214
 
261 dpurdie 9215
#
9216
#   Dependencies for 'make_init'
9217
#
9218
#
9219
my @initdep;
9220
push @initdep, '$(INITS)' if ( @INITS );
227 dpurdie 9221
 
261 dpurdie 9222
#
9223
#   Dependencies for 'make_dir'
9224
#
9225
my @mkdirdep;
9226
push @mkdirdep, '$(GBE_OBJDIR)' if ( @CSRCS || @CXXSRCS || @OBJS || %PROG_OBJS || %TESTPROG_OBJS );
9227
push @mkdirdep, '$(SHDIRS)'     if ( %SHOBJ_LIB || @SHLIBS);
9228
push @mkdirdep, '$(GBE_LIBDIR)' if ( @LIBS || @MLIBS || @SHLIBS || %INSTALL_LIBS || %PACKAGE_LIBS );
9229
push @mkdirdep, '$(GBE_BINDIR)' if ( @SHLIBS || %SCRIPTS || @PROGS || %TESTPROGS || %INSTALL_PROGS || %PACKAGE_PROGS );
227 dpurdie 9230
 
261 dpurdie 9231
#
9232
#   Actions for for 'unobj'
9233
#
9234
my @unobjact;
9235
push @unobjact, RmFilesCmd( 'OBJS' )            if ( @OBJS );
9236
push @unobjact, RmFilesCmd( 'SHOBJS' )          if ( %SHOBJ_LIB );
9237
push @unobjact, RmFilesCmd( 'PROGOBJS' )        if ( @PROGOBJS );
9238
push @unobjact, RmFilesCmd( 'TESTPROGOBJS' )    if ( %TESTPROG_OBJS );
9239
push @unobjact, RmFilesCmd( 'TOOLSETOBJS' )     if ( @TOOLSETOBJS );
227 dpurdie 9240
 
261 dpurdie 9241
#
9242
#   Dependencies for 'make_lib'
9243
#
9244
my @libdep;
9245
push @libdep, '$(GBE_OBJDIR)', '$(GBE_LIBDIR)', '$(LIBS)' if ( @LIBS );
227 dpurdie 9246
 
261 dpurdie 9247
#
9248
#   Dependencies for 'lint_lib'
9249
#
9250
my @liblintdep;
9251
push @liblintdep, 'lint_init', '$(GBE_OBJDIR)', '$(GBE_LIBDIR)', '$(LINTLIBS)' if ( @LIBS );
227 dpurdie 9252
 
261 dpurdie 9253
#
9254
#   Dependencies for 'make_mlib'
9255
#
9256
my @mlibdep;
9257
push @mlibdep, '$(GBE_OBJDIR)', '$(GBE_LIBDIR)', '$(GBE_MLIBDIR)', '$(MLIBS)' if ( @MLIBS );
227 dpurdie 9258
 
261 dpurdie 9259
#
9260
#   Dependencies for 'make_install_shlib' (tag)
9261
#
9262
my @shlibdep;
9263
push @shlibdep, '$(SHDIRS)', '$(SHLIBS)' if ( @SHLIBS );
227 dpurdie 9264
 
261 dpurdie 9265
#
9266
#   Dependencies for 'lint_shlib'
9267
#
9268
my @shliblintdep;
9269
push @shliblintdep, 'lint_init', '$(GBE_LIBDIR)', '$(LINTSHLIBS)' if ( @SHLIBS );
227 dpurdie 9270
 
261 dpurdie 9271
#
9272
#   Actions for 'unmake_lib'
9273
#
9274
my @unlibact;
9275
push @unlibact, RmFilesCmd( 'SHLIBS' )      if ( @SHLIBS );
9276
push @unlibact, RmFilesCmd( 'MLIBS' )       if ( @MLIBS );
9277
push @unlibact, RmFilesCmd( 'LIBS' )        if ( @LIBS );
9278
push @unlibact, RmFilesCmd( 'TOOLSETLIBS' ) if ( @TOOLSETLIBS );
227 dpurdie 9279
 
261 dpurdie 9280
#
9281
#   Actions for 'unmake_mlib'
9282
#
9283
my @unmlibact;
9284
push @unmlibact, RmFilesCmd( 'MLIBS' ) if ( @MLIBS );
227 dpurdie 9285
 
261 dpurdie 9286
#
9287
#   Dependencies for 'make_script'
9288
#
9289
my @scriptdep;
9290
push @scriptdep, '$(GBE_BINDIR)', '$(SCRIPTS)' if ( %SCRIPTS );
227 dpurdie 9291
 
261 dpurdie 9292
#
9293
#   Actions for 'unmake_script'
9294
#
9295
my @unscriptact;
9296
push @unscriptact , RmFilesCmd( 'SCRIPTS' ) if ( %SCRIPTS );
9297
push @unscriptact , RmFilesCmd( 'COPYIN' )  if ( @COPYIN );
227 dpurdie 9298
 
261 dpurdie 9299
#
9300
#   Dependencies for 'make_prog'
9301
#
9302
my @progdep;
9303
push @progdep, '$(GBE_OBJDIR)', '$(GBE_BINDIR)', '$(PROGS)' if ( @PROGS );
9304
push @progdep, '$(PROGS_EXTRA)' if (@PROGS_EXTRA);
227 dpurdie 9305
 
261 dpurdie 9306
#
9307
#   Dependencies for 'make_prog' created for 'projects'
9308
#
9309
my @projectdep;
9310
push @projectdep, '$(PROJECTS)' if (ListGeneratedProjects(1) );
227 dpurdie 9311
 
261 dpurdie 9312
#
9313
#   Dependencies for 'generate' created for 'projects'
9314
#
9315
my @projectgendep;
9316
push @projectgendep, '$(PROJECTSGEN)' if (ListGeneratedProjects(0) );
227 dpurdie 9317
 
261 dpurdie 9318
#
9319
#   Dependencies for 'unmake_prog' created for 'projects'
9320
#
9321
my @projectcleandep;
9322
push @projectcleandep, '$(PROJECTSCLEAN)' if (%PROJECTS);
227 dpurdie 9323
 
261 dpurdie 9324
#
9325
#   Dependencies for 'lint_prog'
9326
#
9327
my @proglintdep;
9328
push @proglintdep, 'lint_init', '$(GBE_OBJDIR)', '$(GBE_BINDIR)', '$(LINTPROGS)' if ( @PROGS || %TESTPROGS );
227 dpurdie 9329
 
261 dpurdie 9330
#
9331
#   Actions for 'unmake_prog'
9332
#
9333
my @unprogact;
9334
push @unprogact, RmFilesCmd( 'PROGS' )        if ( @PROGS );
9335
push @unprogact, RmFilesCmd( 'TOOLSETPROGS' ) if ( @TOOLSETPROGS );
227 dpurdie 9336
 
261 dpurdie 9337
#
9338
#   Dependencies for 'lint_prog'
9339
#
9340
my @testprogdep;
9341
push @testprogdep, '$(GBE_OBJDIR)', '$(GBE_BINDIR)', '$(TESTPROGS)' if ( %TESTPROGS );
227 dpurdie 9342
 
9343
#
261 dpurdie 9344
#   Dependencies for 'run_tests' and friends
9345
#
9346
my @untestprogact;
9347
push @untestprogact ,RmFilesCmd( 'TESTPROGS' ) if ( %TESTPROGS );
227 dpurdie 9348
 
261 dpurdie 9349
#
9350
#   Dependencies for 'generated'
9351
#
9352
my @generatedep;
9353
push @generatedep, '$(GENERATED)' if ( @GENERATED );
9354
 
9355
#
9356
#   Actions for 'ungenerate'
9357
#
9358
my @ungenact;
9359
push @ungenact, RmFilesCmd( 'GENERATED' ) if ( @GENERATED );
9360
push @ungenact, RmFilesCmd( 'GENERATED_NOTSRC' ) if ( @GENERATED_NOTSRC );
9361
push @ungenact, RmFilesCmd( 'TOOLSETGENERATED' ) if ( @TOOLSETGENERATED );
9362
push @ungenact, RmFilesCmd( 'USERGENERATED' ) if ( @USERGENERATED );
9363
 
9364
#
9365
#   Dependencies for 'ungenerate'
9366
#
9367
my @ungeneratedep;
9368
push @ungeneratedep, '$(GENERATEDCLEAN)';
9369
 
227 dpurdie 9370
#-------------------------------------------------------------------------------
261 dpurdie 9371
# Function        : PrintPhonyRule
227 dpurdie 9372
#
261 dpurdie 9373
# Description     : Helper function to print some internal phony makefile targets
9374
#                   These are used to hold the basic makefile together
9375
#
9376
# Inputs          : $target         - Name of the phony target
9377
#                   $prereq         - Prerequisites
9378
#                                     Leading spaces removed
9379
#                   $recipe         - Optional Reference to an array of recipes
9380
#                                     Will be printed one per line
9381
#
9382
#
9383
sub PrintPhonyRule
227 dpurdie 9384
{
261 dpurdie 9385
    my ($target, $prereq, $recipe) = @_;
9386
    $prereq =~ s/^\s+//;
227 dpurdie 9387
 
261 dpurdie 9388
    MakePadded( 2, '.PHONY:', $target, "\n");
9389
    MakePadded( 2,"$target:", $prereq, "\n");
9390
    MakePrint ("\t\t" . $_ . "\n") foreach ( @{$recipe} );
9391
    MakePrint ("\n");
227 dpurdie 9392
}
9393
 
261 dpurdie 9394
my %MakeTargets;
227 dpurdie 9395
 
261 dpurdie 9396
#   make_init - Test toolset presence and sanity
9397
#   Will only be called ONCE for each platform in a recursive build
9398
#   Should be used to ensure that the required toolset is present
9399
#
9400
PrintPhonyRule ('make_init',       "@initdep" );
227 dpurdie 9401
 
261 dpurdie 9402
#   make_dir    - Create required subdirectories
9403
#   Will be invoked as a part of most targets that create files
9404
#   Will be invoked by the calling wrappers
9405
#   Should not be invoked when cleaning
9406
#
9407
PrintPhonyRule ('make_dir',       "@mkdirdep" );
9408
 
9409
 
9410
PrintPhonyRule ('generate',       "@generatedep @projectgendep" );
9411
PrintPhonyRule ('ungenerate',     "@ungeneratedep",  \@ungenact);
9412
PrintPhonyRule ('unobj',          "",  \@unobjact);
9413
PrintPhonyRule ('make_lib',       "@libdep" );
9414
PrintPhonyRule ('lint_lib',       "@liblintdep" );
9415
PrintPhonyRule ('make_mlib',      "@mlibdep" );
9416
PrintPhonyRule ('lint_shlib',     "@shliblintdep" );
9417
PrintPhonyRule ('unmake_lib',     "", \@unlibact );
9418
PrintPhonyRule ('unmake_mlib',    "", \@unmlibact );
9419
PrintPhonyRule ('make_script',    "@scriptdep" );
9420
PrintPhonyRule ('unmake_script',  "", \@unscriptact );
9421
PrintPhonyRule ('make_prog',      "@scriptdep @progdep @projectdep" );
9422
PrintPhonyRule ('lint_prog',      "@proglintdep" );
9423
PrintPhonyRule ('run_tests',      "@scriptdep @testprogdep" );
9424
PrintPhonyRule ('run_unit_tests', "@scriptdep @testprogdep" );
9425
PrintPhonyRule ('unmake_prog',    "unmake_script @projectcleandep", \@unprogact );
9426
PrintPhonyRule ('make_test',      "@scriptdep @testprogdep" );
9427
PrintPhonyRule ('unmake_test',    "unmake_script", \@untestprogact );
9428
 
227 dpurdie 9429
#-------------------------------------------------------------------------------
9430
#   Package and Installation Summary
9431
#
9432
    MakeHeader ("Package and Installation Summary");
9433
    sub InstallTarget
9434
    {
9435
        my( $target, $hashp, $prereq, $fprereq ) = @_;
9436
        my( $element );
9437
 
9438
        MakePrint "$target:";
9439
        MakePrint "\t$fprereq" if ($fprereq);
9440
 
9441
        foreach my $element ( sort keys %{$hashp} )
9442
        {
9443
            #
9444
            #   Skip placekeepers
9445
            #
9446
            next if ( $hashp->{$element}{'placekeeper'} );
9447
 
9448
            #
9449
            #   Prepend any prerequisites (once)
9450
            #
9451
            if ( $prereq )
9452
            {
9453
                MakePrint " \\\n\t${prereq}";
9454
                $prereq = 0;
9455
            }
9456
 
9457
            MakePrint " \\\n\t${element}";
9458
        }
9459
        MakePrint "\n\n";
9460
    }
9461
 
9462
InstallTarget( "install_hdr",       \%INSTALL_HDRS );
9463
InstallTarget( "install_lib",       \%INSTALL_LIBS,  'make_mlib' );
261 dpurdie 9464
InstallTarget( "make_install_shlib",\%INSTALL_SHLIBS, '', "@shlibdep" );
227 dpurdie 9465
InstallTarget( "install_prog",      \%INSTALL_PROGS, 'make_script' );
9466
InstallTarget( "install_class",     \%INSTALL_CLSS );
9467
 
9468
InstallTarget( "package_files",     \%PACKAGE_FILES );
9469
InstallTarget( "package_hdr",       \%PACKAGE_HDRS );
9470
InstallTarget( "package_lib",       \%PACKAGE_LIBS );
9471
InstallTarget( "package_shlib",     \%PACKAGE_SHLIBS );
9472
InstallTarget( "package_prog",      \%PACKAGE_PROGS, 'make_script' );
9473
InstallTarget( "package_class",     \%PACKAGE_CLSS );
9474
 
9475
#-------------------------------------------------------------------------------
9476
#   Installations
9477
 
9478
MakeHeader ("Installations");
9479
PackageRule ( \&InstallCmd, \%INSTALL_HDRS  );
9480
PackageRule ( \&InstallCmd, \%INSTALL_CLSS  );
9481
PackageRule ( \&InstallCmd, \%INSTALL_LIBS  );
9482
PackageRule ( \&InstallCmd, \%INSTALL_SHLIBS  );
9483
PackageRule ( \&InstallCmd, \%INSTALL_PROGS  );
9484
 
9485
 
9486
#-------------------------------------------------------------------------------
9487
#   Packaging
9488
#
9489
MakeHeader ("Packaging");
9490
PackageRule ( \&PackageCmd, \%PACKAGE_FILES );
9491
PackageRule ( \&PackageCmd, \%PACKAGE_HDRS );
9492
PackageRule ( \&PackageCmd, \%PACKAGE_CLSS );
9493
PackageRule ( \&PackageCmd, \%PACKAGE_LIBS );
9494
PackageRule ( \&PackageCmd, \%PACKAGE_SHLIBS );
9495
PackageRule ( \&PackageCmd, \%PACKAGE_PROGS );
9496
 
9497
#-------------------------------------------------------------------------------
9498
#   Uninstall/unpackaging
9499
#
9500
MakeHeader ("Uninstall/unpackaging");
9501
 
9502
UnpackageRule( "uninstall_hdr",         \&UninstallCmd, \%INSTALL_HDRS );
9503
UnpackageRule( "uninstall_lib",         \&UninstallCmd, \%INSTALL_LIBS );
9504
UnpackageRule( "uninstall_shlib",       \&UninstallCmd, \%INSTALL_SHLIBS );
9505
UnpackageRule( "uninstall_prog",        \&UninstallCmd, \%INSTALL_PROGS );
9506
UnpackageRule( "uninstall_class",       \&UninstallCmd, \%INSTALL_CLSS );
9507
 
9508
UnpackageRule( "unpackage_files",       \&UnpackageCmd, \%PACKAGE_FILES );
9509
UnpackageRule( "unpackage_hdr",         \&UnpackageCmd, \%PACKAGE_HDRS );
9510
UnpackageRule( "unpackage_lib",         \&UnpackageCmd, \%PACKAGE_LIBS );
9511
UnpackageRule( "unpackage_shlib",       \&UnpackageCmd, \%PACKAGE_SHLIBS );
9512
UnpackageRule( "unpackage_prog",        \&UnpackageCmd, \%PACKAGE_PROGS );
9513
UnpackageRule( "unpackage_class",       \&UnpackageCmd, \%PACKAGE_CLSS );
9514
 
261 dpurdie 9515
#-------------------------------------------------------------------------------
267 dpurdie 9516
#   Distribution Sets
261 dpurdie 9517
#
267 dpurdie 9518
MakeHeader ("Distribution Sets");
9519
PackageSetRules();
9520
 
9521
#-------------------------------------------------------------------------------
9522
#
261 dpurdie 9523
#   Subdir deletion
9524
#   This is done AFTER the toolset functions have been invoked to create the
9525
#   build artifacts so that the toolsets can create directories too
9526
#
9527
#   Note: Toolset directories are deleted first
9528
#   Note: User Directories are deleted in the reverse order of creation
9529
#
9530
    MakeHeader ("Subdir deletion");
9531
    MakePrint( ".PHONY:		unmake_dir\n" );
9532
    MakePrint( "unmake_dir:\n" );
9533
    MakePrint( "\t-\$(AA_PRE)echo Removing directories;" );
9534
    MakePrint( " \\\n\t\$(rmdir) \$(TOOLSETDIRS);" )            if ( @TOOLSETDIRS );
9535
    MakePrint( " \\\n\t\$(rm) -rf \$(TOOLSETDIRTREES);" )       if ( @TOOLSETDIRTREES );
9536
    RmdirRules();
9537
    MakeNewLine();
227 dpurdie 9538
 
261 dpurdie 9539
#--------- Toolset Rules -------------------------------------------------------
9540
    MakeHeader ("Toolset Rules");
9541
    MakePrintList ( \@TOOLSETRULES );
9542
 
227 dpurdie 9543
#-------------------------------------------------------------------------------
9544
#   Makefile targets
9545
#
261 dpurdie 9546
MakeHeader ("Makefile targets",
9547
            "These targets are not used by JATS",
9548
            "They can only used when the makefile is used directly",
9549
            "This is not the intended use of this makefile",
9550
           );
227 dpurdie 9551
 
9552
#
9553
#   Examine %INC and extract included files within JATS
9554
#   These will be added to the list of dependent files
9555
#
9556
foreach  (  values %INC)
9557
{
9558
    next if ( m/Makefile.*\.cfg$/ );    # Skip my config
9559
    if ( ( m/^\./)          ||
9560
         ( m/^$::GBE_CORE/) ||
9561
         ( m/^$::GBE_BIN/)  ||
9562
         ( m/^$::GBE_PERL/) ||
9563
         ( m/^$::GBE_TOOLS/) )
9564
    {
9565
        UniquePush (\@ScmDepends, $_ )
9566
    }
9567
}
9568
 
9569
MakeDefEntry    ( "GBE_DEPENDS", "=" );
261 dpurdie 9570
MakeIfZeroEntry ( "NOSCMDEPEND", "GBE_DEPENDS", "+=", \@ScmDepends );
227 dpurdie 9571
 
9572
    print MAKEFILE <<EOF;
9573
 
9574
\$(GBE_PLATFORM).mk:	\$(GBE_DEPENDS)
9575
	\@echo One or more JATS source or internal files have changed, "rebuild" required
261 dpurdie 9576
	\@for i in \$? ; do echo "      Changed: \$\$i"; done
227 dpurdie 9577
	\@exit 10
9578
 
9579
EOF
9580
 
261 dpurdie 9581
#--------- Maketags ------------------------------------------------------------
227 dpurdie 9582
 
9583
    Maketag( "make_init",           @INITS );
261 dpurdie 9584
    Maketag( "make_dir",            @mkdirdep );
9585
    Maketag( "generate",            @generatedep || @projectgendep || @USERGENERATED || ($ScmToolsetGenerate != 0) );
227 dpurdie 9586
    Maketag( "depend",              $ScmDependTags != 0 );
261 dpurdie 9587
    Maketag( "make_lib",            @libdep );
9588
    Maketag( "make_mlib",           @mlibdep );
9589
    Maketag( "make_install_shlib",  %INSTALL_SHLIBS || @shlibdep);
9590
    Maketag( "make_script",         @scriptdep );
9591
    Maketag( "make_prog",           @progdep || @projectdep );
9592
    Maketag( "make_test",           @testprogdep );
263 dpurdie 9593
    Maketag( "run_tests",           @TESTS_TO_RUN || @TESTPROJECT_TO_URUN || $TESTS_TO_RUN);
227 dpurdie 9594
    Maketag( "run_unit_tests",      $TESTS_TO_AUTORUN || @TESTPROJECT_TO_ARUN);
9595
    Maketag( "install_hdr",         %INSTALL_HDRS );
9596
    Maketag( "install_class",       %INSTALL_CLSS );
9597
    Maketag( "install_lib",         %INSTALL_LIBS );
9598
    Maketag( "install_prog",        %INSTALL_PROGS );
9599
    Maketag( "deploy",              %DEPLOYPACKAGE );
9600
    Maketag( "package",             %PACKAGE_FILES || %PACKAGE_HDRS || %PACKAGE_CLSS ||
9601
                                    %PACKAGE_LIBS || %PACKAGE_SHLIBS || %PACKAGE_PROGS );
9602
 
261 dpurdie 9603
    #
9604
    #   Display tags in the MAKEFILE
9605
    #   Not used here - just for show
9606
    #
9607
    MakeHeader ("Maketags");
9608
    foreach my $tag ( sort keys %MakeTags )
9609
    {
9610
        MakePadded( 2, "#   $tag:", defined ($MakeTags{$tag}) ? 1 : 0, "\n");
9611
    }
9612
 
227 dpurdie 9613
#-------------------------------------------------------------------------------
9614
#   End of Makefile
9615
#
9616
    MakeHeader ("End of Makefile");
9617
    close( MAKEFILE );
9618
 
9619
#
9620
#   Save all platform information
9621
#   Done after the makefile is written as toolsets can extend the data
9622
#
9623
    WriteParsedConfig();
9624
 
9625
#
9626
#   Write out any accumulated DPACKAGE data
9627
#
9628
    JatsDPackage::DPackageSave();
9629
 
9630
    return 0;
9631
}
9632
 
9633
#-------------------------------------------------------------------------------
9634
# Function        : Maketag
9635
#
9636
# Description     : Create Makefile tags to speed up recursive makes
9637
#
9638
# Inputs          : tag_name
9639
#                   dep
9640
#
9641
# Returns         : 
9642
#
9643
sub Maketag
9644
{
9645
    my( $tag, $dep ) = @_;
9646
    $MakeTags{$tag} = 1 if ( defined($dep) && $dep );
9647
}
9648
 
9649
#-------------------------------------------------------------------------------
9650
#   Function to create and delete directories within the build system
9651
#
9652
#    To stop make regenerating directory dependent targets each time the
9653
#    directory content is modified, rule should only be dependent on a internally
9654
#    created alias file 'gbedir', which represents the time a dir was created not
9655
#    last modified.
9656
#
9657
#    Must use tags like GBE_BINDIR, GBE_LIBDIR and GBE_OBJDIR to ensure that the
9658
#    directories are created correctly.
9659
#
9660
my %MkdirRuleData;
9661
my @MkdirRuleOrder;
9662
my $MkdirRulePrinting = 0;
9663
my $MkdirRuleGbeFile = ( $::ScmHost eq "Unix" ) ? ".gbedir" : "_gbedir";
9664
 
9665
#-------------------------------------------------------------------------------
9666
# Function        : MkdirRule
9667
#
9668
# Description     : Create Rules and Recipes to create a directory at make-time
9669
#                   Mark the information for such that the directories will
9670
#                   be deleted in a 'clean'
9671
#
9672
#                   Can be called before we start writing the makefile
9673
#                   Such entries will be retained and dumped at a known time
9674
#
9675
# Inputs          : $subdir     - Symbolic name of the subdir $(OBJDIR)
9676
#                   $alias      - Optional script alias for the dir 'OBJDIR' --> GBE_OBJDIR
9677
#                   Options:
9678
#                       --Path=path     Optional value of $subdir '$(GBE_PLATFORM)$(GBE_TYPE).OBJ'
9679
#                       --RemoveAll     Remove all files on clean
9680
#
9681
# Returns         : Nothing
9682
#
9683
 
9684
sub MkdirRule
9685
{
9686
    my( $subdir, $alias, @opts ) = @_;
9687
 
9688
    #
9689
    #   Create data entry once
9690
    #
9691
    $alias =~ s~^GBE_~~ if $alias;
9692
    unless ( $MkdirRuleData{$subdir}  )
9693
    {
9694
        my %data;
9695
 
9696
        #
9697
        #   Parse options
9698
        #
9699
        foreach ( @opts )
9700
        {
9701
            if ( /^--Path=(.+)/ ) {
9702
                $data{path} = $1;
9703
            } elsif ( /^--RemoveAll/ ) {
9704
                $data{remove_all} = 1;
9705
            } else {
9706
                Error ("MkdirRule: Unknown option: $_");
9707
            }
9708
        }
9709
        $data{alias} = $alias if ( $alias );
9710
 
9711
        $MkdirRuleData{$subdir} = \%data;
9712
        push @MkdirRuleOrder, $subdir;
9713
    }
9714
 
9715
    #
9716
    #   Save or print
9717
    #
9718
    return unless ( $MkdirRulePrinting );
9719
 
9720
    #
9721
    #   Create a definition of the physical directory
9722
    #
9723
    my $path = $MkdirRuleData{$subdir}{path};
261 dpurdie 9724
    MakePadded (2, $alias, ":= $path\n") if ( $path && $alias );
227 dpurdie 9725
 
9726
    #   Create an alias to be used within rules
9727
    #   The defined aliase will be prefixed with 'GBE_'
9728
    #
261 dpurdie 9729
    MakePadded (2, "GBE_$alias", ":= $subdir/$MkdirRuleGbeFile\n") if ( $alias );
227 dpurdie 9730
 
9731
    #
9732
    #   Create a recipe to create the directory
9733
    #   This is not as simple as it sounds
9734
    #   The touch is required.
9735
    #       Had 'timestamp' issues on solaris'. The 'echo' did not appear
9736
    #       to be enough. Perhaps the output was not flushed
9737
    #
261 dpurdie 9738
    MakePadded (2, "$subdir", ": $subdir/$MkdirRuleGbeFile\n");
227 dpurdie 9739
    MakePrint
9740
        "$subdir/$MkdirRuleGbeFile:\n".
9741
        "\t\$(XX_PRE)if [ ! -d $subdir ]; then \$(mkdir) -p $subdir; fi; \\\n".
9742
        "\t\$(echo) '# DO NOT REMOVE.' > \$@; \\\n".
9743
        "\t\$(touch) \$@\n\n";
9744
}
9745
 
9746
#-------------------------------------------------------------------------------
9747
# Function        : RmdirRules
9748
#
9749
# Description     : Create the body of a recipe to delete the directoeis that
9750
#                   have been created.
9751
#
9752
#                   The rule header will have been written to the makefile
9753
#
9754
# Inputs          : Uses $MkdirRuleData
9755
#
9756
# Returns         : Nothing.
9757
#                   Prints to the makefile
9758
#
9759
sub RmdirRules
9760
{
9761
    #
9762
    #   Determine the list of directories to delete
9763
    #   Sort such that subdirs are deleted files
9764
    #
9765
    foreach my $subdir ( reverse sort keys %MkdirRuleData )
9766
    {
9767
        MakePrint "\\\n";                       # join to previous line
261 dpurdie 9768
        MakePrint "\tif [ -d $subdir ]; then \\\n";
9769
        unless ( $MkdirRuleData{$subdir}{remove_all} )
9770
        {
9771
            MakePrint "\t\t\$(rm) -f $subdir/$MkdirRuleGbeFile; \\\n";
9772
            MakePrint "\t\t\$(rmdir) $subdir; \\\n";
9773
        }
9774
        else
9775
        {
9776
            MakePrint "\t\t\$(rm) -rf $subdir; \\\n";
9777
        }
227 dpurdie 9778
        MakePrint "\tfi;";
9779
    }
9780
}
9781
 
9782
#-------------------------------------------------------------------------------
9783
# Function        : CreateMkdirRules
9784
#
9785
# Description     : Create Rules to make dirs at runtime
9786
#                   This function is called to instantiate those entries
9787
#                   That have been requested before the makefile has has
9788
#                   started to be created.
9789
#
9790
#                   Once this function has been called all new MkdirRule calls
9791
#                   will result in the recipes being created in-line.
9792
#
9793
# Inputs          : Nothing
9794
#
9795
# Returns         : Even Less
9796
#
9797
#
9798
sub CreateMkdirRules
9799
{
9800
    $MkdirRulePrinting = 1;
9801
    foreach my $subdir ( @MkdirRuleOrder )
9802
    {
9803
        my $data = $MkdirRuleData{$subdir};
9804
        MkdirRule($subdir, $data->{alias}, $data->{path} );
9805
    }
9806
}
9807
 
9808
#-------------------------------------------------------------------------------
9809
# Function        : PackageRule
9810
#
9811
# Description     : Generate rules and recipes to "install" and "package" files
9812
#
9813
# Inputs          : codecmd     - A code reference to the actual installer routine
9814
#                   hashp       - A reference to a INSTALL or PACKAGE hash
9815
#
9816
#                   hasp is a reference to a hash
9817
#                       The key is the full path of the install target
9818
#                       The value is (another) hash that describes the install options
9819
#
9820
#                   Valid keys are:
9821
#                       src                 - Path of the source file [Mandatory]
9822
#                       dir                 - Target directory [Mandatory]
9823
#
9824
#                       defined             - Copy the file only if value is defined
9825
#                       exe                 - Mark the file as executable
9826
#                       Mode                - File modes. Default is -w
9827
#                       placekeeper         - Marks SHARED library placekeepers
9828
#                       set                 - Distribution sets
9829
#                       type                - Copy the file in DEBUG or PROD mode
9830
#                                             Valid values are "D" or "P"         
9831
#                       version             - Shared library version information
9832
#                       RemoveOnly          - Do not install the file. Entries are
9833
#                                             created to allow the removal of the file
9834
#
9835
# Returns         :
9836
#
9837
sub PackageRule
9838
{
9839
    my ($codecmd, $hashp) = @_;
9840
 
9841
    foreach my $dest ( keys %{$hashp} )
9842
    {
9843
 
9844
        my $entry = $hashp->{$dest};
9845
 
9846
        #
9847
        #   Skip placekeepers
9848
        #
9849
        next if ( $entry->{'placekeeper'} );
9850
 
9851
        #
9852
        #   Some entries are not installed via this mechanism, but can be removed
9853
        #   if they exist. Mark these as PHONY to keep targets happy
9854
        #
9855
        if ( $entry->{'RemoveOnly'} )
9856
        {
9857
            MakePrint ".PHONY:\t$dest\n";
9858
            MakePrint "$dest:\n\n";
9859
            next;
9860
        }
9861
 
9862
        my $fname = $entry->{'src'};
9863
        my $fmode = $entry->{'Mode'};
9864
        $fmode .= "+x" if ( $entry->{'exe'}  );
9865
 
9866
        #
9867
        #   User conditionional
9868
        #   Mark both the source and the target as PHONY if the condition is not met
9869
        #   This will ensure that the target need not be built.
9870
        #
9871
        my $udef = $entry->{'defined'};
9872
        if ( $udef )
9873
        {
9874
            MakePrint "ifndef $udef \n";
9875
            MakePrint ".PHONY:\t\t$dest\n";
9876
            MakePrint ".PHONY:\t\t$fname\n";
9877
            MakePrint "$dest:\n";
9878
            MakePrint "else\n"
9879
        }
9880
 
9881
        #
9882
        #   Conditional installation for DEBUG/PRODUCTION
9883
        #
9884
        my $type = $entry->{'type'};
9885
        if ( $type )
9886
        {
9887
            if ( $type eq "D" ) {
9888
                MakePrint 'ifeq "$(DEBUG)" "0"'."\n";
9889
            } elsif ( $type eq "P" ) {
9890
                MakePrint 'ifneq "$(DEBUG)" "0"'."\n";
9891
            } else {
9892
                Error("INTERNAL: Unexpected packaging type: $type");
9893
            }
9894
            MakePrint ".PHONY:\t\t$dest\n";
9895
            MakePrint "$dest:\n";
9896
            MakePrint "else\n"
9897
        }
9898
 
9899
        #
9900
        #   The body of the copy
9901
        #
9902
        MakePadded( 4, "$dest:" );
9903
        MakePrint "\t$fname\n";
9904
        MakePrint $codecmd->( $dest, $fname, $entry->{'dir'}, $fmode );
9905
        MakeNewLine();
9906
 
9907
 
9908
        #
9909
        #   Unwind conditionals
9910
        #
9911
        MakePrint "endif\n" if ( $type );
9912
        MakePrint "endif\n" if ( $udef );
9913
 
9914
        #
9915
        #   Distribution sets
9916
        #
9917
        my $dist = $entry->{'set'};
9918
        if ( $dist )
9919
        {
267 dpurdie 9920
            foreach my $set ( split( ',', $dist ) )
9921
            {
9922
                push @{$PACKAGE_SETS{$set}{LIST}}, $dest;
227 dpurdie 9923
            }
9924
            MakeNewLine();
9925
        }
9926
    }
9927
}
9928
 
9929
#-------------------------------------------------------------------------------
267 dpurdie 9930
# Function        : PackageSetRules
9931
#
9932
# Description     : Generate the packageset rules
9933
#                   These appear to be a now-defuct feature
9934
#
9935
#                   By default all packaged files are a part of package_setALL
9936
#
9937
# Inputs          : None
9938
#                   Takes data from %PACKAGE_SET
9939
#
9940
# Returns         : Nothing
9941
#
9942
sub PackageSetRules
9943
{
9944
    foreach my $set ( sort keys %PACKAGE_SETS )
9945
    {
9946
        my $me = MakeEntry::New( *MAKEFILE, "package_set$set", '--Phony' );
9947
        $me->AddDependancy( @{$PACKAGE_SETS{$set}{LIST}} );
9948
        $me->Print();
9949
    }
9950
}
9951
 
9952
#-------------------------------------------------------------------------------
227 dpurdie 9953
# Function        : UnPackageRule
9954
#
9955
# Description     : Generate rules and recipes to "uninstall" and "unpackage" files
9956
#
9957
# Inputs          : target      - Name of the target
9958
#                   codecmd     - A code reference to the actual installer routine
9959
#                   hashp       - A reference to a INSTALL or PACKAGE hash
9960
#
9961
# Returns         :
9962
#
9963
sub UnpackageRule
9964
{
9965
    my ($target, $codecmd, $hashp) = @_;
9966
 
9967
    MakePrint ".PHONY:\t\t"."$target\n";
9968
    MakePrint "$target:\t";
9969
 
9970
    foreach my $dest ( sort keys %{$hashp} )
9971
    {
9972
 
9973
        my $entry = $hashp->{$dest};
9974
 
9975
        #
9976
        #   Skip placekeepers
9977
        #
9978
        next if ( $entry->{'placekeeper'} );
9979
 
9980
        MakePrint "\n" . $codecmd->($dest);
9981
    }
9982
    MakePrint "\n\n";
9983
}
9984
 
9985
 
9986
#
9987
#   Internal macro interface, see RULE.STD for definitions:
9988
#
9989
sub RmFilesCmd
9990
{
9991
    my ( $list ) = @_;
261 dpurdie 9992
    return "\$(call RmFiles,$list)";
227 dpurdie 9993
}
9994
 
9995
sub InstallCmd
9996
{
9997
    my( $dest, $file, $path, $fmode ) = @_;
9998
 
9999
    $path =~ s~/$~~;                        # remove trailing "/"
10000
    $fmode = "-w"                           # default, read-only
10001
        if ( !defined( $fmode ) || $fmode eq "" );
10002
 
10003
    return "\t\$(call InstallFile,$dest,$file,$path,$fmode)";
10004
}
10005
 
10006
sub UninstallCmd
10007
{
10008
    my( $file ) = @_;
10009
 
10010
    return "\t\$(call UninstallFile,$file)";
10011
}
10012
 
10013
sub PackageCmd
10014
{
10015
    my( $dest, $file, $path, $fmode ) = @_;
10016
 
10017
    $path =~ s~/$~~;                        # remove trailing "/"
10018
    $fmode = "-w"                           # default, read-only
10019
        if ( !defined( $fmode ) || $fmode eq "" );
10020
 
10021
    return "\t\$(call PackageFile,$dest,$file,$path,$fmode)";
10022
}
10023
 
10024
sub UnpackageCmd
10025
{
10026
    my( $file ) = @_;
10027
    return "\t\$(call UnpackageFile,$file)";
10028
}
10029
 
10030
 
10031
1;
10032