Subversion Repositories DevTools

Rev

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

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