Subversion Repositories DevTools

Rev

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