Subversion Repositories DevTools

Rev

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

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