Subversion Repositories DevTools

Rev

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

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