Subversion Repositories DevTools

Rev

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

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