Subversion Repositories DevTools

Rev

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

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