Rev 7322 | Blame | Compare with Previous | Last modification | View Log | RSS feed
############################################################################### COPYRIGHT - VIX IP PTY LTD ("VIX"). ALL RIGHTS RESERVED.## Module name : makelib.pl2# Module type : Makefile system## Description:# This modules builds the platform definition makefiles(s)## Notes: *** DO NOT DETAB ***# Beware the use of space v's tab characters within the# makefile generation sessions.################################################################################ Globals:# $ScmVersion Makelib.pl2 version# $ScmRoot Command line parameter that gives the root directory# location for this directory tree.# $ScmMakelib Command line parameter that points to the location# of THIS script. ie. location of makelib.pl.# $ScmPlatform Current platform# $ScmProduct Current product (if any)# $ScmTarget Resulting target (derived from Platform)# @ScmPlatformArgs Platform arguments# $ScmToolset Toolset# @ScmToolsetArgs Toolset arguments# $ScmDebug Debug level# $ScmVerbose Verbose setting# $ScmSourceTypes Source types, aliasing for C, C++ and assembler# source.# @CFLAGS List containing all of the defined C flags# @CXXFLAGS List containing all of the defined C++ flags# @ASFLAGS List containing all of the defined assembler flags# @CLINTFLAGS List containing all of the defined C lint flags# @CXXLINTFLAGS List containing all of the defined C++ lint flags# @{G|L}_INCDIRS List containing all of include paths# @{G|L}_SRCDIRS List containing all of source search paths# @{G|L}_LIBDIRS List containing all of library search paths# @LDFLAGS List containing all of the defined linker flags# @SRCS List of ALL source files. ie. C/C++ and other (eg .x)# Key is source file, value is source path# @OBJS List of ALL (non-shared) object files.# %SHOBJ_LIB List of ALL shared library object files and associated library.# %OBJSOURCE List of ALL object files# from that should result from later makes.# Key is objectfile, value is source file# %OBJREFS List of ALL object files, built options.# @PROGOBJS List of ALL application object files.# %SRC_ARGS List of arguments that are to be used when making the# nominated source. Key is the source name, the# value is a string of arguments to apply. The# arguments are '$;' separated.# %SRC_TYPE Source file type (user override).# @CHDRS List of C header files.# @CSRCS List of C files# Key is objectfile, value is source file# @CXXSRCS List of C++ files# @ASHDRS List of assembler include files (.inc)# @ASSRCS List of assembler source files# @GENERATED List of files that should result from a 'generate'# make rule. The programmer is expected to provide# the necessary rule(s).# @RULES List of additional make rules the programmer# has specified to be included in the make.# %INSTALL_HDRS List of headers that are to be installed for later# "public" consumption.# %INSTALL_CLSS List of Java classes or JAR files that are to be installed# for later "public" consumption.# @LIBS List of libraries that are to be built.# $LIBS Ref to a collection of static library descriptors# Indexed by lib name# %INSTALL_LIBS List of libraries that are to be installed for later# public consumption.# @MLIBS List of libraries that are to be built via merging# $MLIBS Ref to a collection of merged lib descriptors# @SHLIBS List of shared libraries that are to be built.# $SHLIBS Ref to collection of shared library information# %INSTALL_SHLIBS List of libraries that are to be installed for later# public consumption.# @PROGS List of programs (binary executables) that are# to be built# $PROGS Ref to collection of program information# %SCRIPTS List of scripts to 'create' (key) and whether they# should be made executable or not (value). Script# set to executable is denoted by the value being# defined AND true.# %INSTALL_PROGS List of programs for "public" cosumption to install# where (key) is the file and where to install it# to vs. (value) which is composed of the original# location of the file, the destination directory# and a list of service providers this file applies to.# $ProjectBase Base of the user's project. This variable is designed to# be used by the user.#....require 5.006_001;use strict;use warnings;use Getopt::Long;use Data::Dumper;use JatsError;use JatsEnv;use MakeEntry;use JatsLocateFiles;use JatsDPackage;use MakeIf;use ToolsetPrinter;use MakeObject;use JatsVersionUtils;use ToolsetFiles;our $ScmVersion = "2.34";our $ScmGlobal = 0;our $ScmExpert = 0;our $ScmInterface = "interface"; # default 'interface'our $ScmPackage = 1; # package active by default.our $ScmProcessingRootMake = 0; # Processing root makefile.plour $ScmPlatformSeen = 0; # Platform directive has been seenmy $ScmNotGeneric = 1; # Not a generic buildour $ScmToolsetVersion = ""; # version of toolsetour $ScmToolsetGenerate = 1; # generate active by default.our $ScmToolsetProgDependancies = 1; # 1: Write program dependancies# 0: Don't write progdeps. Prog is Phonyour $ScmToolsetSingleType = 0; # Toolset does not support Debug and Productionour $ScmToolsetProgSource = (); # Toolset Program Sourceour $ScmToolsetSoName = 0; # 1: Shared library supports SoNameour $ScmToolsetNillLibSrc = 0; # 1: Librarys created without source specifiedour %ScmToolsetProperties = (); # Toolset specific features and limitations# Known values: UnitTests, AutoUnitTests, LdFlagSpaceour %ScmGlobalOptions = (); # Hash of Global(platform) options. Access via functionsour %ScmRecipeTags = (); # Hash of exposed recipe namesour $ScmRoot = "";our $ScmMakelib = "";our $ScmPlatform = "";our $ScmMachType = "";our $ScmSrcDir = "";our @ScmPlatformDirs = ();our @ScmPlatformArgs = ();our $ScmBuildType = 0; # 0, P, D. 0 == P and Dour $ScmProduct = "";our $ScmTarget = "";our $ScmTargetHost = "";our $ScmToolset = "";our @ScmToolsetArgs = ();our @ScmDepends = ();our %ScmSourceTypes = ();our $ScmDeploymentPatch = "";our $ProjectBase = ""; # Base of the user's projectour $ScmNoToolsTest = ""; # Supress compiler testsour $ScmDependTags = 0; # Create dependancy scanning tagour $ScmMakeUid; # Unique makefile id (number 1 .. )our @CFLAGS = ();our @CFLAGS_DEBUG = ();our @CFLAGS_PROD = ();our @CLINTFLAGS = ();our @CLINTFLAGS_DEBUG = ();our @CLINTFLAGS_PROD = ();our @CXXFLAGS = ();our @CXXFLAGS_DEBUG = ();our @CXXFLAGS_PROD = ();our @CXXLINTFLAGS = ();our @CXXLINTFLAGS_DEBUG = ();our @CXXLINTFLAGS_PROD = ();our @ASFLAGS = ();our @ASFLAGS_DEBUG = ();our @ASFLAGS_PROD = ();our @LDFLAGS = ();our @LDFLAGS_DEBUG = ();our @LDFLAGS_PROD = ();our @INCDIRS = ();our @NODEPDIRS = ();our @S_INCDIRS = ();our @G_INCDIRS = ();our @L_INCDIRS = ();our @SRCDIRS = ();our @S_SRCDIRS = ();our @G_SRCDIRS = ();our @L_SRCDIRS = ();our @LIBDIRS = ();our @S_LIBDIRS = ();our @G_LIBDIRS = ();our @L_LIBDIRS = ();our %SRCS = ();our %SRC_ARGS = ();our %SRC_TYPE = ();our %SRC_DEPEND = ();our %SCRIPTS = ();our @COPYIN = ();our @INITS = ();our @DEFINES = ();our @OBJS = ();our %SHOBJ_LIB = ();our @PROGOBJS = ();our @TESTPROGOBJS = ();our %OBJSOURCE = ();our @CHDRS = ();our @CSRCS = ();our @CXXSRCS = ();our @ASHDRS = ();our @ASSRCS = ();our @GENERATED = ();our @GENERATED_NOTSRC = ();our @RULES = ();our @TOOLSETRULES = ();our @TOOLSETDIRS = ();our @TOOLSETDIRTREES = ();our @TOOLSETGENERATED = ();our @USERGENERATED = ();our @TOOLSETOBJS = ();our @TOOLSETLIBS = ();our @TOOLSETPROGS = ();our %INSTALL_HDRS = ();our %INSTALL_CLSS = ();our @CLOBBERFILES = ();our @CLOBBERDIRS = ();our @TOOLSET_UTF_PRE = (); # Toolsets can extend rules run before all unit testsour @TOOLSET_UTF_POST = (); # Toolsets can extend rules run after all unit testsour @TOOLSET_UTF_COLLATE = (); # Toolsets can extend rules run to collate unit tests resultsour @LIBS = ();our $LIBS = ();our %LIB_PKG = ();our %LIB_INS = ();our %INSTALL_LIBS = ();our @MLIBS = ();our $MLIBS = ();our @SHLIBS = ();our $SHLIBS = ();our @SHLIB_TARGETS = ();our %SHLIB_PKG = ();our %SHLIB_INS = ();our %INSTALL_SHLIBS = ();our @INSTALL_DIRS = ();our $TESTPROGS = ();our @TESTPROGS = ();our $PROGS = (); # Simplify tracking of progsour @PROGS = ();our @PROGS_EXTRA = (); # Look at doing better !!our %PROG_PKG = ();our %PROG_INS = ();our %INSTALL_PROGS = ();our %PACKAGE_DIST = ();our %PACKAGE_SETS = ();our %PACKAGE_HDRS = ();our %PACKAGE_LIBS = ();our %PACKAGE_CLSS = ();our %PACKAGE_SHLIBS = ();our %PACKAGE_PROGS = ();our %PACKAGE_FILES = ();our @PACKAGE_DIRS = ();our @LINTLIBS = ();our @LINTSHLIBS = ();our @TESTS_TO_RUN = (); # Info from 'RunTest' directivesour @TESTPROJECT_TO_URUN = (); # List of Unit Tests and Projects names (Auto and Non Auto in order defined in makefile)our @TESTPROJECT_TO_ARUN = (); # List of Auto Tests and Projects names in order defined in makefilemy $TESTS_TO_AUTORUN = undef; # Flag - Auto Test foundmy $TESTS_TO_RUN = undef; # Flag - Unit Test found#our $CurrentTime = "";#our $CurrentDate = "";#our $Cwd = "";our @GENERATE_FILES = ();our %DEPLOYPACKAGE = ();our $DEPLOYPACKAGE = 0;our %MakeTags;## Some toolset options that affect the generation of the makefile#our $UseAbsObjects = 0; # Default is relative paths to objectsour $UseRelativeRoot = 0; # Default is absolute paths to build rootour $DPackageDirective = 0;## Arrays of hook functions#our %MF_RegisterSrcHooks; # Hook source file discovery################################################################################# Packaging and Installation Information# Held in a structure as its used in a few places# Items# PBase - Package Base directory. Used for user overrides# IBase - Local Install Base directory# Dir - Default directory suffix for components. Added to Pbase and IBase##our %PackageInfo = ('File' => { 'PBase' => '$(PKGDIR)' ,'IBase' => '$(LOCALDIR)' , 'Dir' => '' },'Hdr' => { 'PBase' => '$(INCDIR_PKG)' ,'IBase' => '$(INCDIR_LOCAL)' , 'Dir' => ''},'Lib' => { 'PBase' => '$(LIBDIR_PKG)' ,'IBase' => '$(LIBDIR_LOCAL)' , 'Dir' => '/$(GBE_PLATFORM)'},'Prog' => { 'PBase' => '$(BINDIR_PKG)' ,'IBase' => '$(BINDIR_LOCAL)' , 'Dir' => '/$(GBE_PLATFORM)$(GBE_TYPE)'},'Jar' => { 'PBase' => '$(CLSDIR_PKG)' ,'IBase' => '$(CLSDIR_LOCAL)' , 'Dir' => ''},'Tool' => { 'PBase' => '$(PKGDIR)' ,'IBase' => '$(LOCALDIR)' , 'Dir' => '/tools/bin/$(GBE_HOSTMACH)'},);################################################################################# An array of reserved names# Used to attempt to prevent developers from naming toolset targets with names reserved# within the build systemour @reservedMakeTargets = qw (preprocess_tests postprocess_tests collate_test_results);MakeLib2Init(); # Runtime initialisationsub MakeLib2Init{#.. Test environment#EnvImport( "GBE_CORE" );EnvImport( "GBE_BIN" );EnvImport( "GBE_PERL" );EnvImport( "GBE_TOOLS" );EnvImport( "GBE_CONFIG" );EnvImport( "GBE_MACHTYPE" );#.. Common stuff#require "$::GBE_TOOLS/common.pl"; # Common stuffpush( @ScmDepends, "$::GBE_TOOLS/common.pl" );CommonInit( "makelib2" );Debug( "version: $ScmVersion" );#.. Cache arguments#CommandLine();#.. Build defaults#$ScmSourceTypes{ ".h" } = ".h";$ScmSourceTypes{ ".hpp" } = ".h";$ScmSourceTypes{ ".c" } = ".c";$ScmSourceTypes{ ".C" } = ".c";$ScmSourceTypes{ ".cpp" } = ".cc";$ScmSourceTypes{ ".cc" } = ".cc";$ScmSourceTypes{ ".asm" } = ".asm";$ScmSourceTypes{ ".x" } = "--Ignore";$ScmSourceTypes{ ".ini" } = "--Ignore";$ScmSourceTypes{ ".sh" } = "--Ignore";$ScmSourceTypes{ ".pl" } = "--Ignore";$ScmSourceTypes{ ".awk" } = "--Ignore";#.. Get the stuff from the build configuration file#ConfigLoad();$ScmMakeUid = GetMakfilefileUid();Debug("ScmMakeUid: $ScmMakeUid");if ( (%::ScmBuildPlatforms) ) # Interface/build.cfg{AddPlatformArg( split( /$;/, $::ScmBuildPlatforms{ $ScmPlatform } ));}if ( (%::ScmBuildIncludes) ) # Interface/build.cfg{my( @includes ) = split( ',', $::ScmBuildIncludes{ $ScmPlatform } );my( $global ) = $ScmGlobal;$ScmGlobal = 1; # Follow defs are "global's" ...foreach my $elem ( @includes ){AddIncDir( "*", $elem ) if ($elem);}$ScmGlobal = $global; # Restore global status ...}if ( (%::ScmBuildLibraries) ) # Interface/build.cfg{my( @libraries ) = split( ',', $::ScmBuildLibraries{ $ScmPlatform } );my( $global ) = $ScmGlobal;$ScmGlobal = 1; # Follow defs are "global's" ...foreach my $elem ( @libraries ){AddLibDir( "*", $elem ) if ($elem);}$ScmGlobal = $global; # Restore global status ...}#.. Determine the value of $ScmMachType# In the makefile GBE_MACHTYPE will be set to $ScmMachType.## There is an compatibility issue here.# A lot of (legacy) package.pl files use GBE_MACHTYPE to specify platform# specfic directories and names. This is not to be encouraged.## Allow for a platformm specific override#if ( exists( $::BUILDINFO{$ScmPlatform}{'SCMMACHTYPE'} )){$ScmMachType = $::BUILDINFO{$ScmPlatform}{'SCMMACHTYPE'};Verbose("Override ScmMachType: $ScmMachType");}else{$ScmMachType = $ScmPlatform;}#.. Get the stuff from the Package definition file# A convention is that package.pl provide a package name via $Pbase# This may be different to the BUILDNAME. Generate a default $Pbase# to allow the package.pl to use the package name part of the buildname#$::Pbase = $::ScmBuildPackage;if ( -f "$ScmRoot/package.pl" ){Warning ("package.pl file used. Use is being deprecated");my( $global ) = $ScmGlobal; # Follow defs are "global's" ...$ScmGlobal = 1;require "$ScmRoot/package.pl";$ScmGlobal = $global; # Restore global status ...if ( defined ($::ScmBuildPackage) && defined ($::Pbase) ){# Special case.# $Pbase is set to ".". Set $Pbase to the Build Name to force# construction of a well formatted package.#$::Pbase = $::ScmBuildPackageif ( $::Pbase eq "." );## Error if Pbase has changed#Error ("Pbase is not the same as the BuildName (Check package.pl)","Pbase : $::Pbase","BuildName: $::ScmBuildPackage")if ( $::Pbase ne $::ScmBuildPackage );}}## Create objects to keep track of Libraies and Programs#$LIBS = MakeObject::NewType( 'Library', \@LIBS, '$(LIBDIR)/', \&GenLibName);$MLIBS = MakeObject::NewType( 'MergedLibrary', \@MLIBS, '$(LIBDIR)/', \&GenLibName);$SHLIBS = MakeObject::NewType( 'SharedLibrary', \@SHLIBS, '$(LIBDIR)/', \&GenLibName);$PROGS = MakeObject::NewType( 'Program', \@PROGS, '$(BINDIR)/', \&GenProgName);$TESTPROGS = MakeObject::NewType( 'TestProgram', \@TESTPROGS,'$(BINDIR)/', \&GenProgName);}#-------------------------------------------------------------------------------# Function : GenLibName## Description : Helper function to generate a (static) library name# Used by MakeObject::NewType## If the toolset doesn't support Debug and Prod, then# The library name will not have the suffix## Inputs : arg0 - Base name of the library# arg1 - Mode: 1 == Plain. No P or D## Returns : Name of the library as used in the makefiles# Does not include base directory#sub GenLibName{if ( $ScmToolsetSingleType || $_[1] ) {return "$_[0].$::a"} else {return "$_[0]\$(GBE_TYPE).$::a"}}#-------------------------------------------------------------------------------# Function : GenProgName## Description : Helper function to generate a program name# Used by MakeObject::NewType## Inputs : arg0 - Base name of the library## Returns : Name of the program as used in the makefiles# Does not include base directory#sub GenProgName{return "$_[0]$::exe"}#-------------------------------------------------------------------------------# Function : CommandLine## Description : Process the command line.# Arguments describes below## Arguments : ARG0 - Root of the project# ARG1 - Path to this script# ARG2 - Target Platform## Options follow# --interface=name - Name of interface dir# --arg=xxx - Platform argument## Otherwise display a usage message## Returns : Nothing#sub CommandLine{Verbose ("Command Line: @ARGV");## Extract options first#my $opt_help = 0;my $result = GetOptions ("help+" => \$opt_help,"interface=s" => \$::ScmInterface,"arg=s" => sub{ AddPlatformArg( "--$_[1]") });Usage() if ( $opt_help || !$result );## Need 3 Arguments#$ScmRoot = ${ARGV[0]};$ScmRoot = RelPath( $ScmRoot );$ProjectBase = $ScmRoot;$ScmMakelib = ${ARGV[1]};$ScmPlatform = ${ARGV[2]};$ScmTarget = $ScmPlatform;Message ("[$ScmPlatform] Generate Makefile");Debug( "root\t=$ScmRoot" );Debug( "makelib\t=$ScmMakelib" );Debug( "platform\t=$ScmPlatform" );}# Usage ---# Command line usage help.#..sub Usage{Error ( "Usage: perl makefile.pl2 <ROOTDIR> <makelib.pl2> <PLATFORM> [options ...]","Valid options:"," --interface=name Set interface directory"," --arg=text Specify platform argument",);}#-------------------------------------------------------------------------------# Function : SubDir## Description : Include a sub-makefile# When called when processing by this script this directive# does nothing. The processing will be done by makelib.pl## This directive MUST occur before the Platform directive## Inputs : None that are used## Returns : Nothing#sub SubDir{Error ("SubDir directive not allowed after the Platform directive")if ( $ScmPlatformSeen );}################################################################################ Platform support###############################################################################sub Platform{my( $global, $file );Debug( "Platform( $ScmPlatform, @ScmPlatformArgs )" );#.. Sanity test#Error ("Platform directive is not allowed in common makefile.pl")if ( $ScmProcessingRootMake );Error ("Only one Platform directive is allowed")if ( $ScmPlatformSeen );$ScmPlatformSeen = 1;#.. Arguments#$ScmTargetHost = $::ScmHost; # default#.. Common configuration#$global = $ScmGlobal; # Follow defs are "global's" ...$ScmGlobal = 1;#.. Common rules (ScmHost specific)#push( @ScmDepends, "$ScmMakelib" ); # parent$file = Require( "$::GBE_CONFIG", "Rules", "Common rules " );push( @ScmDepends, "$file" );#.. Platform (defines ScmToolset)#if ( ( %::ScmBuildProducts ) && # interface/build.cfg$::ScmBuildProducts{ $ScmPlatform } ){my( @args ) = split( ',', $::ScmBuildProducts{ $ScmPlatform } );$ScmProduct = $args[0];$ScmTarget = $args[1];Debug( " mapping to product $ScmProduct" );# Platform/target specificMakeIf::PackageDirs( \@ScmPlatformDirs, $ScmPlatform, $ScmTarget );push @ScmPlatformDirs, "$::GBE_CONFIG"; # .. plus default@ScmPlatformArgs = ( "--product=$ScmProduct", @ScmPlatformArgs );$file = Require( "PLATFORM", $ScmTarget,"Platform definition ", @ScmPlatformDirs );}else # standard{Debug( " native platform" );# Platform specificMakeIf::PackageDirs( \@ScmPlatformDirs, $ScmPlatform );push @ScmPlatformDirs, "$::GBE_CONFIG"; # .. plus default# Map all GENERIC builds onto the one platform definitionmy $platformDefs = $ScmPlatform;if ($::BUILDINFO{$ScmPlatform}{IS_GENERIC}){$ScmNotGeneric = 0;$platformDefs = 'GENERIC' ;}$file = Require( "PLATFORM", $platformDefs,"Platform definition ", @ScmPlatformDirs );}push( @ScmDepends, "$file" );Error( "Toolset undefined for platform $ScmPlatform ...")unless( $ScmToolset );#.. Toolset#$file = Require( "$::GBE_CONFIG/TOOLSET", $ScmToolset, "Toolset definition " );push( @ScmDepends, "$file" );#.. Package definitions## Global DPACKAGE definitions, which may pull in $ScmTarget specific definitions.#MakeIf::PackageLoad( $ScmPlatform ); # DPACKAGE's (if any)#.. Package extensions# Import, into the current package, files of the form gbe/DIRECTIVES# These allow the JATS directives to be extended by the contents of a package# without the need to update the core JATS release.## Intended use: Associate a directive with a tool script, such that the# new directive simplifies the use of the tool script.### First: Extend the Perl Search Space to include the toolset extensions# Although the directives are in gbe/DIRECTIVES/*.pm, they may need# to reference other packages that are not.## Look in the 'interface' and 'link' packages# The 'build' packages are duplicated into the 'interface'#for my $path ( ToolExtensionPaths() ){UniquePush (\@INC, $path)if (glob( "$path/*.pm") || glob( "$path/*/*.pm"));}for my $entry (@{$::ScmBuildPkgRules{$ScmPlatform} }){next if ( $entry->{'TYPE'} eq 'build' );my $cfgdir = $entry->{'CFGDIR'};next unless ( $cfgdir );my $base_dir = $entry->{'ROOT'} . $cfgdir . '/DIRECTIVES';next unless ( -d $base_dir );foreach my $file ( glob ("$base_dir/*.pm") ){push( @ScmDepends, "$file" );require $file;}}## Include local toolset extensions# These are rooted in the build directory and are not to be confused with# extensions that may be packaged# Simplify life - add the directory to the BUILDTOOLSPATH#my $local_base_dir = "$ScmRoot/gbe/DIRECTIVES";if ( -d $local_base_dir ){unshift @::BUILDTOOLSPATH, AbsPath($local_base_dir);foreach my $file ( glob ("$local_base_dir/*.pm") ){push( @ScmDepends, "$file" );require $file;}}## All makefile.pl's will include a makefile.pl found in the build# root directory ( The same directory as build.pl ). This makefile.pl# is a little bit different - It should not "require "$ARGV[1]", nor# should it use a Platform directive.## Note: This makefile is processed AFTER the toolset has been initialised# so that toolset extensions are available to the directives#$file = "$ScmRoot/makefile.pl";if ( -e $file ) {$ScmProcessingRootMake = 1;require "$file";$ScmProcessingRootMake = 0;push( @ScmDepends, "$file" );}## Sanity Test for platforms that do not support both debug and production# builds at the same time. This information is flagged by the toolset# which we have now loaded.#if ( $ScmToolsetSingleType ){unless ( $ScmBuildType ){Error ("The toolset used by the \"$ScmPlatform\" platform does not support","both Production and Debug Builds" );}}## Restore global status ...#$ScmGlobal = $global;}sub PlatformRequire{my( $script, @arguments ) = @_;my( $file );Debug( "PlatformRequire($script, @arguments)" );push( @ScmPlatformArgs, @arguments ); # additional arguments$file = Require( "PLATFORM", $script,"PlatformRequire ", @ScmPlatformDirs );push( @ScmDepends, "$file" );}sub PlatformInclude{my( $script, @arguments ) = @_;my( $file );Debug( "PlatformInclude( @_ )" );$file = Require2( \@arguments, "PLATFORM", $script,"PlatformInclude ", @ScmPlatformDirs );push( @ScmDepends, "$file" );}sub PlatformDefine{Debug2( "PlatformDefine(@_)" );Define( @_ );}sub PlatformDefines{my( $script ) = @_;my( $line );Debug2( "PlatformDefine(@_)" );$script = Exists( "PLATFORM", $script, # locate image"PlatformDefines", @ScmPlatformDirs );push( @DEFINES, "# PlatformDefines from: $script" );open( my $fh, '<', $script ) || Error( "Opening $script" );while (<$fh>) {$_ =~ s/\s*(\n|$)//; # kill trailing whitespace & nlpush( @DEFINES, $_ );}push( @ScmDepends, "$script" ); # makefile dependenciesclose( $fh );}sub PlatformEntry{my( $prelim, $postlim, $prefix, $postfix, @elements ) = @_;my $str = "$prelim";foreach my $element ( @elements ){$str .= "${prefix}${element}${postfix}";}$str .= "$postlim";PlatformDefine( $str );}## Add arguments to the ScmPlatformArgs, but remove "Global" arguments# --OnlyDebug# --OnlyProduction# --NoToolSet## Capture OnlyDebug and OnlyProd information# Will be sanitized by caller.#sub AddPlatformArg{Debug("AddPlatformArg: @_" );foreach ( @_ ){if ( m~^--OnlyDebug~ ) {$ScmBuildType = 'D';} elsif ( m~--OnlyProd~ ) {$ScmBuildType = 'P';} elsif ( m~--NoToolSet~ ) {$ScmNoToolsTest = 1;} else {UniquePush( \@::ScmPlatformArgs, $_ );}}Debug("AddPlatformArg: Result: @::ScmPlatformArgs" );1;}################################################################################ Toolset support## Toolset( 'platform [, ... ]', name, [arg, ... ] )# Specify the toolset for a platform## ToolDefine( )# ToolDefines( )# Specifies toolset defines for insertion into the target makefile.## ToolsetDir# Define toolset created directory(s) for removal during# 'clean' operations.## ToolsetGenerate# Define toolset created file(s) for removal during# 'clean' operations.## ToolsetObj# Define toolset created object(s) for removal during# 'clean' operations.## ToolsetLib# Define toolset created library(s) for removal during# 'clean' operations.## ToolsetProg# Define toolset created prog(s) for removal during# 'clean' operations.## ToolsetRule( )# ToolsetRules( )# Specifies toolset rules for insertion into the target makefile.###############################################################################sub Toolset{my( $platforms, $toolset, @arguments ) = @_;Debug2( "Toolset(@_)" );return 1 if ( ! ActivePlatform($platforms) );$ScmToolset = $toolset;@ScmToolsetArgs = @arguments;return 1;}sub ToolsetRequire{my( $script, @arguments ) = @_;my( $file );Debug2( "ToolsetRequire(@_)" );@ScmToolsetArgs = @arguments;$file = Require( "",$script,"ToolsetRequire","$::GBE_CONFIG/TOOLSET", @::BUILDTOOLSPATH );push( @ScmDepends, "$file" );}sub ToolsetDefine{Debug2( "ToolsetDefine(@_)" );Define( @_ );}sub ToolsetDefines{Debug2( "ToolsetDefines(@_)" );Defines( "$::GBE_CONFIG/TOOLSET", @_ );}sub ToolsetDir{Debug2( "ToolsetDir(@_)" );UniquePush ( \@TOOLSETDIRS, @_ );}sub ToolsetDirTree{Debug2( "ToolsetDirTree(@_)" );UniquePush ( \@TOOLSETDIRTREES, @_);}sub ToolsetGenerate{Debug2( "ToolsetGenerate(@_)" );UniquePush( \@TOOLSETGENERATED, @_ );}sub ToolsetClobberFile{Debug( "ToolsetClobberFile(@_)" );UniquePush( \@CLOBBERFILES, @_ );}sub ToolsetClobberDir{Debug( "ToolsetClobberDir(@_)" );UniquePush( \@CLOBBERDIRS, @_ );}sub ToolsetObj{Debug2( "ToolsetObj(@_)" );foreach my $obj ( @_ ){UniquePush( \@TOOLSETOBJS, "$obj.$::o" );}}sub ToolsetLib{Debug2( "ToolsetLib(@_)" );foreach my $lib ( @_ ){UniquePush( \@TOOLSETLIBS, GenLibName( $lib ) );}}sub ToolsetProg{Debug2( "ToolsetProg(@_)" );foreach my $prog ( @_ ){UniquePush( \@TOOLSETPROGS, GenProgName( $prog ) );}}sub ToolsetRule{Debug2( "ToolsetRule(@_)" );push( @TOOLSETRULES, @_ );}sub ToolsetRules{my( $script ) = @_;my( $line );Debug2( "ToolsetRules(@_)" );$script = Exists( "$::GBE_CONFIG/TOOLSET", $script, "ToolsetRules" );push( @TOOLSETRULES, "# ToolsetRules from: $script" );open( my $fh, '<', $script ) || Error( "Opening $script" );while (<$fh>) {$_ =~ s/\s*(\n|$)//; # kill trailing whitespace & newlinepush( @TOOLSETRULES, $_ );}push( @ScmDepends, "$script" ); # makefile dependenciesclose( $fh );}#-------------------------------------------------------------------------------# Function : SetGlobalOption## Description : Set a global toolset option# The global options are intended to allow platform-specific# operation of various tools and utilities. The scope is wider than# just the underlying tooolset## Inputs : $name - Name of the option# $value - Value to save## Returns : Nothing#sub SetGlobalOption{my ($name, $value) = @_;Debug( "SetGlobalOption.", $name, $value );$ScmGlobalOptions{$name} = $value;}#-------------------------------------------------------------------------------# Function : GetGlobalOption## Description : Get a global toolset option## Inputs : $name - Name of the option to fetch# $default - Default value to return, if the option# is not present.## Returns : The value of the option, or the default value#sub GetGlobalOption{my ($name, $default) = @_;if (exists $ScmGlobalOptions{$name}){$default = $ScmGlobalOptions{$name};}Debug( "GetGlobalOption .", $name, $default );return $default;}#-------------------------------------------------------------------------------# Function : ToolsetAddUnitTestPreProcess# ToolsetAddUnitTestPostProcess# ToolsetAddUnitTestCollateProcess## Description : Functions to allow toolsets to add recipes to be run before# and after Unit Tests are run.## Inputs : $target - Name of the recipe to be run## Returns : Nothing#sub ToolsetAddUnitTestPreProcess{_ToolsetAddUnitTest(\@TOOLSET_UTF_PRE, @_ );}sub ToolsetAddUnitTestPostProcess{_ToolsetAddUnitTest(\@TOOLSET_UTF_POST, @_ );}sub ToolsetAddUnitTestCollateProcess{_ToolsetAddUnitTest(\@TOOLSET_UTF_COLLATE, @_ );}#-------------------------------------------------------------------------------# Function : _ToolsetAddUnitTest## Description : Internal helper function used by ToolsetAddUnitTest*## Inputs : $aref - Ref to an array of names to extend# $target - Name of recipe to run## Returns : Nothing#sub _ToolsetAddUnitTest{my ($aref, $target ) = @_;# Determine name of parent functionmy $fname = (caller(1))[3];$fname =~ s~.*::~~;Debug2( "$fname ($target)" );## Ensure user is not using a reserved target#if (grep {$_ eq $target} @reservedMakeTargets) {Error("Internal: $fname uses reserved make taget: $target");}push @$aref, $target;}################################################################################ User interface:## AddFlags( 'platform [, ... ]', 'flags' [, 'flag' ... ] )# This subroutine takes the C and C++ compiler flags# specified adding them to a global list for later# inclusion in the built makefile.## AddCFlags( 'platform [, ... ]', 'flags' [, 'flag' ... ] )# This subroutine takes the C compiler flags# specified adding them to a global list for later# inclusion in the built makefile.## AddCXXFlags( 'platform [, ... ]', 'flags' [, 'flag' ... ] )# This subroutine takes the C++ compiler flags# specified adding them to a global list for later# inclusion in the built makefile.## AddLintFlags( 'platform [, ... ]', 'flags' [, ... ] )# This subroutine takes the Lint flags specified# adding them to a global list for later inclusion# in the built makefile.## AddASFlags( 'platform [, ... ]', 'flags' [, ... ] )# This subroutine takes the Assemler flags specified# adding them to a global list for later inclusion# in the built makefile.## AddLDFlags( 'platform [, ... ]', 'flags' [, ... ] )# This subroutine takes the Linker flags specified# adding them to a global list for later inclusion# in the built makefile.## AddDir# This subroutine takes the directories specified adding# them to a global include and source directory list for# later inclusion in the built makefile.## AddIncDir( 'platform [, ... ]', 'dir' [, ... ] )# This subroutine takes the include file directories# specified adding them to a global list for later# inclusion in the built makefile.## AddSrcDir( 'platform [, ... ]', 'dir' [, ... ] )# This subroutine takes the source file directories# specified adding them to a global list used to resolve# Src() definitions.## AddLibDir( 'platform [, ... ]', 'dir' [, ... ] )# This subroutine takes the library directories# specified adding them to a global list for later# inclusion in the built makefile.## AddSourceType( 'ext', '.c|.cc|.asm' )# This subroutine takes the extension(s) specified by the# programmer and adds them to a global list for later# inclusion in the built makefile. This list contains# the extensions to be recognised as 'C', 'C++' or# assembler file types.## AddSourceFile( 'platform [, ... ]', 'file' [, ... ] )# This subroutine takes the non-standard source file(s)# and adds them add it to either C, C++ or assembler# sources and the object list.## Init( 'platform [, ... ]', 'rule' )# Initialisation rule## Generate( 'platform [, ... ]', 'file' [, ... ] )# This subroutine is used to add the list of given# source files to the generate sources list, and if# the generated source is of type C, C++ or assember# also adds it to either C, C++ or assembler sources and# the object lists.## --c Treat as a C source file.# --cpp Treat as a C++ source file.# --asm Treat as a assembler source file.## Rule( 'platform [, ... ]', definition )# This subroutine is used to add the non-standard make# rules required to build the system. eg. any rules# necessary to produce a .cc & .h file from a .x file.## Src( 'platform [, ... ]', 'file' [, ... ], [ 'arg' [, ...]] )# This subroutine is used to add the list of given source# files to the sources list, and if the source is of type# C, C++ or assember also adds it to either C, C++ or# assembler sources and the object lists. The optional# list of arguments is assigned to all source files.## --c Treat as a C source file.# --cpp Treat as a C++ source file.# --asm Treat as a assembler source file.# --Shared Shared, produces position-independent# code (on targets where required).## Lib( 'platform [, ... ]', 'name', 'obj' [, ... ] [, '-arg' [, ... ]] )# This subroutine takes a library definition list and adds# the entries to the 3 libraries definition lists. 'name'# of the library to be created. List of the object files# 'obj' that make up this library. List of special# arguments 'arg' to pass to the librarian.## MergeLibrary( 'platform [, ... ]', 'name', 'lib' [, ... ] )# This subroutine takes a library merge list and adds# the entries to the 2 merge libraries definition lists. 'name'# of the library to be created. List of the libraries to be merged## LocalScript( 'platform [, ... ]', name, ['1'] )# Script( 'platform [, ... ]', name, ['1'] )# This subroutine takes a list that defines the name of# the script to be placed in the platform 'bin' directory,# and an optional second element that defines whether the# script should be made executable or not.## Prog( 'platform [, ... ]', 'name', ['obj', ... ],# ['-llib', ... ], ['options'] )# This subroutine takes a list that defines which program# (binary) is to be made, what libraries and object it is# made from, and any special commands required to perform# the program creation.## @PROGS Updated list of programs to create## TestProg( 'platform [, ... ]', 'name', ['obj', ... ],# ['-llib', ... ], ['options'] )# This subroutine takes a list that defines which test program# (binary) is to be made, what libraries and object it is# made from, and any special commands required to perform# the program creation.## @TESTPROGS Updated list of programs to create## InstallHdr( 'platform [, ... ]', 'file' [, ...], ['-arg'] )# This subroutine takes the given list of files and adds them# to the install header files list. Files in this list will be# installed into the 'local header directory' area for public# consumption. This is generally API files for other modules# to use.## --Strip Strip directory from source# --Strip=n Strip part of directory from source# --Full Install using full path# --Subdir=subdir Install within the specified sub-directory# --Prefix=subdir " " " " " "## InstallLib( 'platform [, ... ]', 'file', ['subdir'] )# This subroutine takes the given list of files and adds them# to the install libraries files list. Files in this list will# be installed into the 'local library directory' area for# public consumption.## InstallProg( 'platform [, ... ]', 'file', ['subdir'] ) )# This subroutine takes a list that defines the executable file# that is to be installed. The file in this list will be# installed into the 'local executable directory' specified for# public consumption.################################################################################sub Include # User include{my( $path, $name ) = @_;my( $file );$file = Require( $path, $name, "Include" );push( @ScmDepends, "$file" );}sub ForceCCompile{CompileOptions( $_[0], 'compile_as_c' ); # Backward compatability}#-------------------------------------------------------------------------------# Create a data structure to define the global compiler options# The hash is keyed by compiler option# The value contains another hash.# The key is a makefile variable to set ( or remove )# The value is the value to assign to the makefile variable# If the value is 'undef' then the variable will be deleted## Keys of the form key=value are also supported## If the value is a CODE reference, then routine will be called with the key# and value as arguments. The return value will be utilised.#our %ScmCompilerOptions =('strict_ansi' => { 'USE_STRICT_ANSI' => '1' },'no_strict_ansi' => { 'USE_STRICT_ANSI' => '' }, # Default'profile' => { 'USE_PROFILE' => '1' },'no_profile' => { 'USE_PROFILE' => '' }, # Default'prod_no_optimise' => { 'PROD_USE_OPTIMISE' => '' },'prod_no_debuginfo' => { 'PROD_USE_DEBUGINFO' => '' }, # Default'prod_optimise' => { 'PROD_USE_OPTIMISE' => '1' }, # Default'prod_debuginfo' => { 'PROD_USE_DEBUGINFO' => '1' },'debug_no_optimise' => { 'DEBUG_USE_OPTIMISE' => '' }, # Default'debug_no_debuginfo' => { 'DEBUG_USE_DEBUGINFO' => '' },'debug_optimise' => { 'DEBUG_USE_OPTIMISE' => '1' },'debug_debuginfo' => { 'DEBUG_USE_DEBUGINFO' => '1' }, # Default'compile_as_cpp' => { 'FORCE_CC_COMPILE' => '1','FORCE_C_COMPILE' => undef },'compile_as_c' => { 'FORCE_C_COMPILE' => '1','FORCE_CC_COMPILE' => undef },'no_define_source_file' => { 'DISABLE__SOURCE__' => '1' },'define_source_file' => { 'DISABLE__SOURCE__' => undef }, # Default'warnings_as_errors' => { 'WARNINGS_AS_ERRORS' => '1' },'no_warnings_as_errors' => { 'WARNINGS_AS_ERRORS' => undef }, # Default);## The toolset can extend the options by setting the following hash#our %ScmToolsetCompilerOptions = ();## Define default compiler options# These are makefile variables that will be assigned#our %ScmCompilerOpts =('USE_STRICT_ANSI' => '','USE_PROFILE' => '','PROD_USE_DEBUGINFO' => '','PROD_USE_OPTIMISE' => '1','DEBUG_USE_OPTIMISE' => '','DEBUG_USE_DEBUGINFO' => '1',);sub CompileOptions{my( $platforms, @elements ) = @_;return if ( ! ActivePlatform($platforms) );for (@elements){my $oref;## The toolset option may be a text string or a definition# Name - A text string# Name=Value - A value#my $value;my $key = $_;if ( $key =~ m~(.*=)(.*)~ ){$key = $1;$value = $2 || '';}$key = lc( $key );## Examine the global flags# Then the toolset extensions# Then just drop it#unless ( $oref = ($ScmCompilerOptions{$key} || $ScmToolsetCompilerOptions{$key}) ){Warning ("Compile Option ignored: $_");next;}## Parse the definition and adjust makefile variables as required# Set the value of a make variable or remove the definition## If the user value is a code reference, then call the code# and use the returned value as the value.#while ( (my($ukey, $uvalue)) = each %{$oref} ){if ( defined( $uvalue) ){if ( ref($uvalue) eq "CODE" ){$uvalue = &$uvalue( $key, $value, $ukey);unless ( defined $uvalue ){Warning ("Compile Option ignored: $_");next;}}elsif ( defined $value ){$uvalue = $value;}$ScmCompilerOpts{$ukey} = $uvalue;}else{delete $ScmCompilerOpts{$ukey};}}}}#-------------------------------------------------------------------------------# Function : AddFlags# AddCFlags# AddCXXFlags# AddASFlags# AddLDFlags# AddLintFlags## Description : Add target specfic flags to the C compiler# This SHOULD only be used to add Defines to the compiler# but it can be absued.## Inputs : $platform - Platforms for which the directive is active# ... - list of flags to add## Embedded options include:# --Debug - Following options are added to the debug build# --Prod - Following options are added to the production build## Returns : Nothing#sub AddFlags{my( $platforms, @elements ) = @_;AddCFlags( $platforms, @elements );AddCXXFlags( $platforms, @elements );}sub AddCFlags{my( $platforms, @elements ) = @_;Debug2( "AddCFlags($platforms, @elements)" );return if ( ! ActivePlatform($platforms) );WarnIfNastyFlag( @elements );__AddFlags( "CFLAGS", \@elements,\@CFLAGS, \@CLINTFLAGS,\@CFLAGS_DEBUG, \@CLINTFLAGS_DEBUG,\@CFLAGS_PROD, \@CLINTFLAGS_PROD );}sub AddCXXFlags{my( $platforms, @elements ) = @_;Debug2( "AddCXXFlags($platforms, @elements)" );return if ( ! ActivePlatform($platforms) );WarnIfNastyFlag( @elements );__AddFlags( "CXXFLAGS", \@elements,\@CXXFLAGS, \@CXXLINTFLAGS,\@CXXFLAGS_DEBUG, \@CXXLINTFLAGS_DEBUG,\@CXXFLAGS_PROD, \@CXXLINTFLAGS_PROD );}sub AddASFlags{my( $platforms, @elements ) = @_;Debug2( "AddASFlags($platforms, @elements)" );return if ( ! ActivePlatform($platforms) );__AddFlags( "ASFLAGS", \@elements,\@ASFLAGS, undef,\@ASFLAGS_DEBUG, undef,\@ASFLAGS_PROD, undef );}sub AddLDFlags{my( $platforms, @elements ) = @_;Debug2( "AddLDFlags($platforms, @elements)" );return if ( ! ActivePlatform($platforms) );foreach ( @elements ){next if ( m~^--(Debug|Prod)~ );Warning("Use of linker flag discouraged (will be used): $_");if ( $ScmToolsetProperties{'LdFlagSpace'} ) {$_ =~ s/\s/\$(spacealt)/g;}}__AddFlags( "LDFLAGS", \@elements,\@LDFLAGS, undef,\@LDFLAGS_DEBUG, undef,\@LDFLAGS_PROD, undef );}sub AddLintFlags{my( $platforms, @elements ) = @_;return if ( ! ActivePlatform($platforms) );Debug2( "AddLintFlags($platforms, @elements)" );__AddFlags( "LINTFLAG", \@elements,\@CLINTFLAGS, \@CXXLINTFLAGS,\@CLINTFLAGS_DEBUG, \@CXXLINTFLAGS_DEBUG,\@CLINTFLAGS_PROD, \@CXXLINTFLAGS_PROD );}#-------------------------------------------------------------------------------# Function : __AddFlags## Description : Generic flag adding to lists routine# Internal use only## Supports --Debug and --Prod options# if the appropriate list is present.## Inputs : Lots# References to compiler and lint flags for# common, debug and product builds.## Not all the lists are needed.## Returns : Nothing#sub __AddFlags{my ($textname, $eref,$f_all, $flint_all,$f_debug, $flint_debug,$f_prod, $flint_prod ) = @_;## Start added flags to the ALL lists#my $list = $f_all;my $lintlist = $flint_all;my $nowarn = 0;## Process flags up front#$nowarn = 1 if ( grep (/^--NoWarn$/, @$eref) );## Process all the user arguments#ADD:foreach my $element ( @$eref ){## Skip flags#if ( $element eq '--NoWarn' ){next;}## Detect --Debug and --Prod options and swap# lists accordingly.#if ( $element eq '--Debug' ){Error ("--Debug not supported for $textname") unless ( $f_debug );$list = $f_debug;$lintlist = $flint_debug;next;}if ( $element eq '--Prod' ){Error ("--Prod not supported for $textname") unless ( $f_prod );$list = $f_prod;$lintlist = $flint_prod;next;}## Scan all the lists for a possible duplicates#foreach my $temp ( @$f_all, @$f_debug, @$f_prod ) {if ($temp eq $element) {Warning( "Duplicate $textname ignored '$element'") unless $nowarn;next ADD;}}## Add the flag to the compiler and lint lists#push( @$list, $element ) if $list;push( @$lintlist, $element ) if $lintlist;}}sub WarnIfNastyFlag{foreach ( @_ ){Warning("Use of compiler flags discouraged (will be used): $_")unless ( m/^-[DU]/ || m/^--Debug/ || m/^--Prod/ || /^--NoWarn/ );}}sub AddDir{AddIncDir( @_);AddSrcDir( @_ );}sub AddIncDir{_AddDir( 'AddIncDir', 'INCDIR', \@INCDIRS, \@S_INCDIRS, \@G_INCDIRS, \@L_INCDIRS, @_ );}sub AddSrcDir{_AddDir( 'AddSrcDir', 'SRCDIR', \@SRCDIRS, \@S_SRCDIRS, \@G_SRCDIRS, \@L_SRCDIRS, @_ );}sub AddLibDir{_AddDir( 'AddLibDir', 'LIBDIR', \@LIBDIRS, \@S_LIBDIRS, \@G_LIBDIRS, \@L_LIBDIRS, @_ );}#-------------------------------------------------------------------------------# Function : _AddDir## Description : Internal routine to add a directory to list of directories# Common code to simplify implementation of other directives## Inputs : $name - Name of function# $udir - User name of dir list# $dirref - Reference to directory array# $s_dirref - Reference to system directory array# $g_dirref - Reference to global directory array# $l_dirref - Reference to local directory array# @args - User arguments# - platforms# - Directories and --Options#sub _AddDir{my( $name, $udir, $dirref, $s_dirref, $g_dirref, $l_dirref, $platforms, @elements ) = @_;Debug ( "$name($platforms, @elements)" );Error ( "$name: Insufficient arguments") unless ( @elements );return if ( ! ActivePlatform($platforms) );## Cleanup user parameters#foreach ( @elements ){s/^\s+//; # Remove leading spaces/\s+$//; # Remove trailing spacess~/$~~; # Remove trailing /s~//~/~g; # Remove multiple /}#.. Collect argumentsmy $tlist_ref = $ScmGlobal ? $g_dirref : $l_dirref; # "current" scope ....my $nowarn = 0;my $nodepend = 0;my @dirs;foreach ( @elements ){if ( ! /^--/ ) { # Collect directoriespush @dirs, $_;} elsif (/^--Local$/) { # "local" scope ....$tlist_ref = $l_dirref;} elsif (/^--Global$/) { # "global" scope ...$tlist_ref = $g_dirref;} elsif (/^--System$/) { # "system" scope ...$tlist_ref = $s_dirref;} elsif (/^--NoDepend$/) { # Split from dependency listif ( $udir eq 'INCDIR' ) { # AddIncDir only$nodepend = 1;}} elsif (/^--NoWarn$/) { # Disable warnings$nowarn = 1;} elsif (/^--(.*)/) {Message( "$name: unknown option $_ -- ignored\n" );}}Error ( "$name: No directory specified: ($platforms, @elements)" )unless ( @dirs );#.. Push source path(s)foreach ( @dirs ){## Add to complete list of directories# Warn on duplicates#unless ( UniquePush( $dirref, $_) ){Warning( "Duplicate $udir ignored '$_'" )unless ( $nowarn );next;}## Check that the directory actually exists# If the path contains a $(XXXXX) then it can't be checked#if ( index( $_, '$' ) == -1 ){Warning( "$name. Directory not found: $_","Current directory : $::Cwd","Cannot resolved Directory : " . AbsPath($_, $::Cwd, 1),)unless ( $nowarn || -d $_ );}## Add to suitable list#push @{$tlist_ref}, $_;ToolsetFiles::AddDir($_, 'Include');## Add to the no dependancy list (ie generated depend file)# Only used by AddIncDir, accepted by AddSrcDir#push( @NODEPDIRS, $_ )if ($nodepend);}}#-------------------------------------------------------------------------------# Function : ExtendIncDir## Description : Allow the directory search paths to be extended into sub# directories.## Limit use, but ...## Inputs : $platform - Active platforms# ... - Path extensions## Returns :#my %ExtendIncDirSeen;sub ExtendIncDir{my( $platforms, @paths ) = @_;Debug2( "ExtendIncDir($platforms, @paths)" );return if ( ! ActivePlatform($platforms) );Error ('ExtendIncDir. No extensions listed') unless @paths;## Ensure the user only extends the paths once.# Could silently discard excess - better to force the user to get it right#foreach my $path ( @paths) {ReportError ('ExtendIncDir. Multiple defintions for: ' . $path) if exists $ExtendIncDirSeen{$path};$ExtendIncDirSeen{$path} = 0;}ErrorDoExit();## Zip though all the packages and extend the search paths# Also gets those in the interface directory#for my $package (@{$::ScmBuildPkgRules{$ScmPlatform} }){#DebugDumpData("package", $package);foreach my $path ( @paths){if ( $package->{PINCDIRS}){my @output;foreach my $pdir ( @{$package->{PINCDIRS}}){my $tdir = catdir ($pdir, $path);my $adir = catdir ($package->{ROOT}, $tdir);if ( -d $adir) {Verbose("Extending $package->{DNAME} $package->{VERSION}: $tdir");push @output, $tdir;$ExtendIncDirSeen{$path}++;}push @output, $pdir;}@{$package->{PINCDIRS}} = @output;}}}## Report extensions that have not been used#foreach my $path ( @paths) {ReportError ('ExtendIncDir. Search path not extendable: ' . $path) unless $ExtendIncDirSeen{$path};}ErrorDoExit();}sub AddProg{my( $platforms, @progs ) = @_;Debug2( "AddProg($platforms, @progs)" );return if ( ! ActivePlatform($platforms) );foreach my $prog (@progs){my $pProg = $PROGS->Get($prog);Warning( "Duplicate prog ignored '$prog'" )if ( $pProg );$pProg = $PROGS->NewAdd($prog)}}sub AddSourceType{my( $ext, $type ) = @_;Debug2( "AddSourceType(@_)" );## Default Source Type (C)#$type = ".c" unless ( $type );Error ("Source type '$ext' not allowed")if ( $ext !~ /^\.\w+$/ );$type = lc($type)if ( $::ScmHost ne "Unix" );$ScmSourceTypes{ $ext } = $type;}sub AddSourceFile{my( $platforms, @elements ) = @_;Debug2( "AddSourceFile($platforms, @elements)" );return if ( ! ActivePlatform($platforms) );foreach my $path ( @elements ){__AddSourceFile( 1, $path );}}#-------------------------------------------------------------------------------# Function : __AddSourceFile## Description : Internal function# Add a source file to internal lists## Assumes that the current platform is ACTIVE## Inputs : push 0: Don't push onto OBJS (non-shared objfiles)# path Filename.extension# obj object file name (optional)# type Type of file. "" -> auto detect## Returns : True - File is a 'known' source file# False - File is not a 'known' source file#sub __AddSourceFile{my( $push, $path, $obj, $type ) = @_;my( $filename, $ext, $srcfile, $is_obj, $ext_type, $result );$filename = StripDir($path); # file name$ext = StripFile($path); # extension$ext = lc($ext)if ( $::ScmHost ne "Unix" );if (! ($srcfile = $SRCS{$filename})) {$srcfile = $path; # generated}$obj = StripExt( $filename ) # Base name of object fileif ( ! defined($obj) || $obj eq "" );$type = "" # optional typeif ( ! defined( $type ) );## Push file onto a suitable source file list#$result = 0;$ext_type = ""; # map extension$ext_type = $ScmSourceTypes{ $ext }if ( exists( $ScmSourceTypes{ $ext } ) );$result = 1 if ( $ext_type );if ( $type eq "" && defined $::ScmToolsetProgSource{$ext} ){Debug( "SourceFile: $path is ToolsetProgSource -> $srcfile" );push( @CSRCS, $srcfile );$result = 1;}elsif ( ($type eq "" && $ext_type eq ".h") || ($type eq ".h") ){Debug( "SourceFile: $path is .h -> $srcfile" );push( @CHDRS, $srcfile );}elsif ( ($type eq "" && $ext_type eq ".inc") || ($type eq ".inc") ){Debug( "SourceFile: $path is .inc -> $srcfile" );push( @ASHDRS, $srcfile );}elsif ( ($type eq "" && $ext_type eq ".c") || ($type eq ".c") ){Debug( "SourceFile: $path is .c -> $srcfile=$obj" );push( @CSRCS, $srcfile );$is_obj = 1;}elsif ( ($type eq "" && $ext_type eq ".cc") || ($type eq ".cc") ){Debug( "SourceFile: $path is .cc -> $srcfile=$obj" );push( @CXXSRCS, $srcfile );$is_obj = 1;}elsif ( ($type eq "" && $ext_type eq ".asm") || ($type eq ".asm") ){Debug( "SourceFile: $path is .asm -> $srcfile=$obj" );push( @ASSRCS, $srcfile );$is_obj = 1;}elsif ( $ext_type eq "--Ignore" ){ # ignored ...# .x "rpcgen" source files# .ini Configuration# .sh Shell script}else{Debug( "SourceFile: $path is unknown file type" );## Insert source files with unknown extensions onto lists# of there own type#if ( $ext ){(my $varname = uc ( $ext . 'SRCS')) =~ s~\.~~g;no strict 'refs';push @$varname, $srcfile;use strict 'refs';}}## See if there is a hook function for this type of source file# Invoke user function to perform additional processing on the file#if ( %MF_RegisterSrcHooks ){my @listeners;push @listeners, @{$MF_RegisterSrcHooks{$ext}} if ( exists $MF_RegisterSrcHooks{$ext} );push @listeners, @{$MF_RegisterSrcHooks{'*'}} if ( exists $MF_RegisterSrcHooks{'*'} );while ( @listeners ){Debug( "RegisterSrcHook: Invoke SrcHook function" );my ($fname, @args) = @{shift @listeners};&$fname ( $srcfile ,$filename, $obj, $ext ,@args );}}## Object files are saved in# OBJSOURCE - Generate a recipe to create the object# OBJS - A list of ALL non-shared object files#if ( $is_obj && $::o && $ScmNotGeneric ){$OBJSOURCE{ "$obj" } = $srcfile;push( @OBJS, $obj )if ($push);}## Indicate to the user that the file is a 'known' source file# This implies that the file is required early in the build process# and may need to be generated early.#return $result;}#-------------------------------------------------------------------------------# Function : SetValue## Description : Defines a variable that can be used within the makefile.pl# Use sparingly# An attempt to formalise a mechanism that is used anyway, but# with correct platform detection## Inputs : $platform - Platform selector# $name - Name to set# $value - Value to set# options - Options# --NoWarn# --Project=xxxx[,xxxx]+# --#sub SetValue{my( $platforms, @elements ) = @_;my $name;my $value;my $nowarn;my $nomoreswicthes = 0;Debug2( "SetValue($platforms, @elements)" );return if ( ! ActivePlatform($platforms) );## Process elements extracting values and options#foreach ( @elements ){if ( m/^--$/ ) {$nomoreswicthes = ! $nomoreswicthes;next;}if ( m/^--/ && ! $nomoreswicthes ){if ( m/^--NoWarn/ ) {$nowarn = 1;} elsif ( m/^--Project=(.*)/ ) {return unless ( ActiveProject( $1) );} else {Error ("SetValue: Unknown option: $_");}} elsif ( ! defined $name ) {$name = $_;} elsif ( ! defined $value ) {$value = $_;} else {Error ("SetValue: $name. Too many parameters" );}}## Warn if the named variable already exists# It may be a JATS internal or it may be a user.#unless ( $nowarn ){no strict 'refs';Warning("SetValue: $name. Redefined") if defined ( $$name );use strict 'refs';}## Set the value#no strict 'refs';$$name = $value;use strict 'refs';}#-------------------------------------------------------------------------------# Function : SetList## Description : Defines a list variable that can be used within the makefile.pl# Use sparingly# An attempt to formalise a mechanism that is used anyway, but# with correct platform detection## Inputs : $platform - Platform selector# $name - Name to set# $value,... - Values to set# options - Options# --NoWarn# --Project=xxxx[,xxxx]+# --Unique# --Clear# --Append# --#my %SetList_names;sub SetList{my( $platforms, @elements ) = @_;my $name;my @value;my $nowarn;my $unique;my $clear;my $nomoreswicthes = 0;Debug2( "SetList($platforms, @elements)" );return if ( ! ActivePlatform($platforms) );## Process elements extracting values and options#foreach ( @elements ){if ( m/^--$/ ) {$nomoreswicthes = ! $nomoreswicthes;next;}if ( m/^--/ && ! $nomoreswicthes ){if ( m/^--NoWarn/ ) {$nowarn = 1;} elsif ( m/^--Project=(.*)/ ) {return unless ( ActiveProject( $1) );} elsif ( m/^--Unique/ ) {$unique = 1;} elsif ( m/^--Clear/ ) {$clear = 1;} elsif ( m/^--Append/ ) {$clear = 0;} else {Error ("SetList: Unknown option: $_");}} elsif ( ! defined $name ) {$name = $_;} else {push @value, $_;}}Error ("SetList: No name specified") unless ( $name );## Warn if the named variable already exists# It may be a JATS internal or it may be a user.## Only do this iff the name is not known to this function# Keep a list a names that have been set.#if ( ! $SetList_names{$name} && ! $nowarn ){no strict 'refs';Warning("SetList: $name. Defined outside the ScanList/SetList directive","May clash with Jats internals") if ( @$name );use strict 'refs';}$SetList_names{$name} = 1;## Clear list#if ( $clear ){no strict 'refs';@$name = ();use strict 'refs';}## Set the value#no strict 'refs';if ( $unique ) {UniquePush( \@$name, @value);} else {push @$name, @value;}use strict 'refs';}#-------------------------------------------------------------------------------# Function : ScanList## Description : Create a list by scanning for files in a directory# The files may be in a local directory or within a package# Care must be taken when using a package as the results# may differ bewteen BuildPkgArchive and LinkPkgArchive## Interworks with SetList## Inputs : $platform - Platform selector# $name - Name to set# $value,... - Values to set# options - Options# --NoWarn# --Project=xxxx[,xxxx]+# --Unique# --Clear# --Append## --Package=xxxx[,ext]# --Dir=xxx## --Subdir=yyy# --DirListOnly# --FileListOnly# --Recurse (default)# --NoRecurse# --FullPath (default)# --NoFullPath## --FilterIn=xxx# --FilterInRe=xxx# --FilterOut=xxx# --FilterOutRe=xxx## Returns :#sub ScanList{my( $platforms, @elements ) = @_;my $name;my $package;my $dir;my $subdir;my @set_args;my $search = JatsLocateFiles->new('Recurse','FullPath' );Debug2( "ScanList($platforms, @elements)" );return if ( ! ActivePlatform($platforms) );## Process elements extracting values and options#foreach ( @elements ){if ( m/^--Unique|--Clear|--Append|--NoWarn/ ) {push @set_args, $_;} elsif ( m/^--Project=(.*)/ ) {return unless ( ActiveProject( $1) );} elsif ( m/^--Package=(.*)/ ) {$package = $1;} elsif ( m/^--Dir=(.*)/ ) {$dir = $1;} elsif ( m/^--Subdir=(.*)/ ) {$subdir = $1;} elsif ( $search->option( $_ ) ) {Verbose ("Search Option: $_" );} elsif ( m/^--/ ) {Error ("ScanList: Unknown option: $_");} elsif ( ! defined $name ) {$name = $_;} else {Error ("ScanList $name: Unknown option: $_");}}Error ("ScanList: No variable name specified") unless ( $name );Error ("ScanList: Must Specify --Dir or --Package") unless ( $dir || $package );Error ("ScanList: --Dir and --Package are mutually exclusive") if ( $dir && $package );## Locate the base of the scan# This may be either a package name or a local directory## Its no use allowing the user to use OBJ/LIB/BIN directories as the# directories MUST exist at build time. Don't really want the user doing# that level of poking out of a package#if ( $package ){$dir = GetPackageBase( "ScanList", $package );Error ("ScanList: Package not found: $package") unless ( $dir );}else{Error ("ScanList: Root directory not found: $dir") unless ( -d $dir );}if ( $subdir ){$dir .= "/" . $subdir;Error ("ScanList: Sub directory not found: $subdir") unless ( -d $dir );}## Use SetList to do the rest of the work#SetList( $platforms, $name, @set_args, '--', $search->search($dir) );}sub Init{push( @INITS, @_ );}#-------------------------------------------------------------------------------# Function : Generate## Description : Legacy Function - don't use unless you have too.# Flags files that are to be generated during the# early 'generate' make phase. Will also add named files# to various internal lists## Intended to be used in conjunction with the 'Rule' directive# to flag header and source files that need to be created early# in the build process.## Inputs : See GenerateSrcFile## Returns :#sub Generate{my( $platforms, @elements ) = @_;Debug2( "Generate($platforms, @elements)" );return if ( ! ActivePlatform($platforms) );Message("Generate directive used. Consider replacing with GenerateFiles");## Use Non-warning version to do the hard work#GenerateSrcFile( 1, @elements );}#-------------------------------------------------------------------------------# Function : Generated## Description : Legacy Function - don't use unless you have too.# Flags files that are generated by misc Rules## Intended to be used in conjunction with the 'Rule' directive# to mark files that have been generated, so that they can be# cleaned up.## Note the difference to the 'Generate' directive which will# ensure that the Rule will be run in the 'generate' phase,# this directive doesn't.## Inputs : Files with internal Makefile Paths and codes# Eg: Generated( '*', "\$(LIBDIR)/libcsf\$(GBE_TYPE).\${a}" );# See why its YUK!## Returns :#sub Generated{my( $platforms, @elements ) = @_;my( @args );return if ( ! ActivePlatform($platforms) );Debug2( "Generated($platforms, @elements)" );#.. Collect arguments#foreach ( @elements ){if ( /^-(.*)/ ){Debug( "Gen: arg $_" );push ( @args, $_);}}#.. Push source file(s)#foreach ( @elements ){if ( ! /^-(.*)/ ){Debug( "Generated: $_ (@args)" );push (@USERGENERATED, $_);## Add the file to the list of known source files# This will allow them to be packaged#GenerateSrcFile (0, $_ );}}}#-------------------------------------------------------------------------------# Function : GenerateSrcFile## Description : Internal Function (No $platform)# Determine how to handle a 'Generated' file### Inputs : $generated - 0: Don't add to GENERATED List# 1: Add to GENERATED List# 2: Add to GENERATED List, if a source file# FileName(s) - Name of one or more files to process# All files are processed in the same way# These file may contain Makefile prefixes# ie: $(OBJDIR)/file.obj# Options:# --c - Hint: Its a "C" file# --cpp - Hint: Its a C++ file# --asm - Hint: Its an ASM file# -* - Save as argument attached to the file## Returns : Number of 'source' file#sub GenerateSrcFile # Internal Function - no $platform{my( $generated, @elements ) = @_;my( $type, @args );my $result = 0;Debug2( "GenerateSrcFile($generated,@elements)" );#.. Collect arguments#$type = "";foreach ( @elements ){if ( /^--c$/ ) {Debug( "Gen: --c" );$type = ".c";} elsif ( /^--cpp$/ ) {Debug( "Gen: --cpp" );$type = ".cc";} elsif ( /^--asm$/ ) {Debug( "Gen: --asm" );$type = ".asm";} elsif ( /^-(.*)/ ) {Debug( "Src: arg $_" );push @args, $_;}}#.. Process source file(s)## Determine if file is already a known SRCS file - skip if already known# Update SRCS data# Update SRC_TYPE data# Update SRC_ARGS data# Add the file to a suitable source file list ie: @CHDRS,...# Flag as a GENERATED file - These will be processed during the 'generate' phase#foreach my $source ( @elements ){next if ( $source =~ /^-(.*)/ ); # Not a source filemy $basename = StripDir( $source );Debug( "Generate: $source=$basename (@args)" );if ($SRCS{ $basename }) {Warning( "Duplicate src ignored '$source'" );next;}$SRCS{ $basename } = $source;HashJoin( \%SRC_ARGS, $;, $basename, @args )if (@args);$SRC_TYPE{ $basename } = $typeif ($type);## Add the file to any source file lists that may like to know# about this file.## If the file was a known source file, then it may need to be generated# very early in the build process.#my $src_file_type = __AddSourceFile( 1, $basename );if ($generated == 1 || ($src_file_type && $generated > 1) ){push(@GENERATED, $source);$result++;}else{push(@GENERATED_NOTSRC, $source);}}return $result;}#-------------------------------------------------------------------------------# Function : GenerateFiles## Description : Generate files in a controlled manner using a specified# tool to perform the task## Inputs : $1 - platform specifier '*' (comma delemitered)# $2 - Tool Name# $3... - Command line argument to generate files with embedded information# - or options. Multiple command line arguments will be joind with# a single space## The generated files will be placed in the OBJ directory for# the current target platform. This allows different files to# be generated for each platform, without collision.## The full name of the generated files will be added to the list of# source files. Thus the user does not need to know the# full name of the file - it will be tracked by JATS.## If a generated file is a header file, then the OBJ directory# will be added as AddIncDir() so that the header files can be# extracted## If a generated file is a "C"/"C++" source file, then it will# compiled and the object file made available## The tool name may be:# --Tool=name or "name"# Look in the tool paths in Packages# Look in the JATS tool directory for named script# Look in the JATS bin directory for the named exe# Look in the users path ( and generate a warning )# Give up and hope magic happens later# --Script=name# Resolve the name using known Src paths# The script may be generated and need not exist# at the time the makefile is created.# --Shell# The command line argument is a shell script that# will be passed to a simple shell.# --Prog=name# Resolve to a program generated within this makefile### The command line argument contains keywords to allow# information to be extracted from the line. Keywords are:## --Generated(xxx) - xxx is a generated file# It will be placed in the OBJDIR# --GeneratedCommon(xxx) - xxx is a generated file# File will be placed in the local directory# and will be shared by by all platforms# --GeneratedObject(xxx) - xxx is a generated object file# It will be placed in the OBJDIR and will# have a suitable object suffix appended# --GeneratedProg(xxx) - xxx is a generated program file# It will be placed in the BINDIR# --Prerequisite(xxx) - xxx is a prerequisite file# The full name of the file will be located# and used within the command. The file will# be added to the list of recipe prerequisites# --GeneratedDirectory(xxx)# --GeneratedCommonDirectory(xxx)# --GeneratedObjectDirectory(xxx)# --GeneratedProgDirectory(xxx)# - xxx is a generated file# The containing directory will be placed on the command line# --PackageBase(xxx) - xxx is a package. The keyword will be replaced# with the pathname to the package. If the package# has been copied in the the interface directory# then the interface directory will be used.# --PackageInfo(xxx,--opt)- xxx is a package. The keyword will be replaced# with the information requested.# Options are:# --path# --version# --fullversion# --project## Where "xxx" may be of the form:# name,option[,option]## Flag options are:# --file - The file part of the full name# --dir - The directory part of the full name# --abspath - Abs path# --absdrive - Abs path with drive letter## --Var(Name,opt) - Name is the name of a recognised varable# Refer to ExpandGenVar function for details# of Name and available options# The expanded text will be replaced with an# suitable makefile variables that will be# replaced at run-time.## --Tool(Name,opt) - Name is the name of a 'tool' found withnin a package# The argument is replaced with the full path of the# tool. opt may be# --dir# --file# --abspath# --absdrive## The keyword will be replaced with the resolved name. This may be a file,# a directory or other text.## Options do not alter command line text. They do affect the way the command is# processed.# Options include:# --Prereq=name - The name of a file to add as a prerequisite# The file does not form part of the command line# --Created=name - The name of a file to treat as a generated file# --CreatedCommon=name The file does not form part of the command line# --CreatedObject=name# --CreatedProg=name## --NoVarTag - Modifes --Var operation to suppress tags# --NoWarn - Don't warn if no prerequistes found# --NoGenerate - Don't warn if no generated files are found# Will create a dummy rule name and the recipe will# always be executed during the 'GenerateFiles' phase# --UnknownPreq - Prerequisites are not fully known.# Rebuild the target whenever it is required.# --AutoGenerate - Examine the generated file to determine when the# tools is to be run.# Must be before any options that declare# creation of files.# --Text=<text> - Display text for command## --Clean[=arg] - Call script with arg[-clean] for cleaning.# --PreDelete - Delete generated files before running the command# --RecipeTag=Name - Name the recipe# Allows recipe to be called by Name and clean_Name## --UtfFormat=name - Flags the program as a 'test' to be run in the Test Phase# Intended to support things like Gradle that run tests in there own world# Enables support for (Must occur first)# --AutoUtf - Non interactive unit test# --NoAutoUtf - Interactive unit Test# --UtfArg=nnn - Argument passed into the UTF formatter# --UtfDir=path - SUbdir in which the Unit Tests will be run### Eg: GenerateFiles ( '*', "--Tool=mod_if.pl",# "-src --Prerequisite(udh_module.cfg)",# "-direct -hdr --Generated(udp.h) -quiet" );#my $NoGenIndex = 0;my %recipeTags;sub GenerateFiles{## Remove undfined arguments# Simplifies programatic construction of argument lists#my ( $platforms, $tool, @args) = grep defined, @_;return if ( ! ActivePlatform($platforms) );Debug( "GenerateFiles:($platforms, $tool, @args)" );my @preq_files;my $preq_unknown;my @gen_files;my $shell_script;my $shell_cmds;my @tool_args;my $no_warn;my $clean_tag;my $text;my $gtype = 1;my @has_source;my @var_opts;my @genreq_seen;my $predelete;my $recipeTag;my $utfAuto;my $utfFormat;my $utfDir;my @utfArgs;my $isaUtf;my $noGenerate;## Process the first argument - this describes the program that will be used# to generate the files. It may be:# --Tool - A Jats Tool or Plugin# --Script - A shell script file# --Shell - Raw shell commands# --Prog - A program created within the Makefile##if ( $tool =~ /^--Tool=(.*)/ || $tool =~ /^([^-].*)/){$tool = $1;my $tool_no_prereq = 0;## Process the Tool name and determine the location of the tool# Support --Tool=name and "name"# Locate the tool one of the many well known locations# 1) Tool paths from Package Archives# 2) JATS tool and binaries# 3) User PATH (!YUK)### Create a list of known extensions to scan# Basically present so that we can use .exe files without the .exe name#my @extension_list;push @extension_list, '.exe' if ( $::ScmHost ne "Unix" );push @extension_list, '.pl', '.sh', '.ksh', '';TOOL_SEARCH:{## Locate tool with package#if ( my $fname = ToolExtensionProgram( $tool, @extension_list )){$tool = $fname;last TOOL_SEARCH;}## Search the JATS tools and Bin directory# Retain the symbolic name of the JATS directory#for my $ext ( @extension_list ){foreach my $jdir ( qw( / /DEPLOY/ /LOCAL/ ) ){if ( -f "$::GBE_TOOLS$jdir$tool$ext" ){$tool = "\$(GBE_TOOLS)$jdir$tool$ext";last TOOL_SEARCH;}}if ( -f "$::GBE_BIN/$tool$ext" ){$tool = "\$(GBE_BIN)/$tool$ext";last TOOL_SEARCH;}}## Has the user provided an absolute PATH# This is not good, but for testing we can use it#if ( $tool =~ m~^/~ || $tool =~ m~^.:~ ){Warning("Absolute path program specified. Uncontrolled tool: $tool");for my $ext ( @extension_list ){if ( -f "$tool$ext" ){$tool = "$tool$ext";last TOOL_SEARCH;}}}## May have a relative path to a local tool#if ( -f $tool ){UniquePush (\@preq_files, $tool);last TOOL_SEARCH;}## Search the users PATH# Generate a warning if the program is found. These programs are# not nice as they are not really controlled.#for my $dir (split( $::ScmPathSep, $ENV{'PATH'} ) ){for my $ext ( @extension_list ){if ( -f "$dir/$tool$ext" ){Warning("External program found in the user's PATH. Uncontrolled tool: $tool");$tool = "$dir/$tool$ext";## Do not make the program a pre-requisite if we are running# under Windows. This avoids two problems:# 1) May have spaces in pathname# 2) May have driver letter in pathname#$tool_no_prereq = 1 if ( $::ScmHost eq "WIN" );last TOOL_SEARCH;}}}## Specified progrom not found# Generate a warning and use the raw name#Warning("Tool not found: $tool");$tool_no_prereq = 1;}UniquePush (\@preq_files, $tool) unless ($tool_no_prereq);} elsif ( $tool =~ /^--Script=(.*)/ ) {## Locate the script in a known source directory and make# the script a prerequisite of the target files, since the# script may be generated.#$tool = MakeSrcResolve ( $1 );UniquePush (\@preq_files, $tool);} elsif ( $tool =~ /^--Shell$/ ) {## The user has provided a shell script within the command body# This will be executed directly by a shell# directores will need to use a "/" separator#$tool = "InternalShell";$shell_script = 1;$shell_cmds = 1;} elsif ( $tool =~ /^--Prog=(.*)$/ ) {## Using a program that has been created within this script#my $prog = $1;if ( my $pProg = $PROGS->Get($prog) ){$tool = $pProg->getPath()unless ( $tool = $SRCS{$prog} );UniquePush (\@preq_files, $tool);}else{Error ("Unknown program: $prog");}} else {## Currently generate a warning and then use the raw tool name#Error ("Unknown TOOL syntax: $tool");}## May need to quote the path# If the toolpath contains spaces then ugliness can occur - so quote the program#$tool = '"' . $tool . '"'if ( (! $shell_script ) && $tool =~ m~\s~ );## Determine special startup for various programs# Perl - use known implemenatation# Shell - use known implemenatation# Otherwise - simply run it## Windows: Shell and Perl don't need '\' in paths#if ( $tool =~ /\.pl$/ ){$tool = "\$(GBE_PERL) $tool";$shell_script = 1;}elsif ( $tool =~ /\.k?sh$/ ){$tool = "\$(GBE_BIN)/sh $tool";$shell_script = 1;}Debug( "GenerateFiles: Tool: $tool" );## Process the remaining arguments# These will be command line arguments or options/flags# Command line arguments are concatenated together#for my $arg (@args){if ( $arg =~ /^--PreDelete$/ ){## Delete generated files before running the generation process# Some programs refuse to overwrite existing files#$predelete = 1;next;} elsif ( $arg =~ /^--NoVarTag$/ ) {## Modify the operation of --Var to supress the tags# Should be used early as will only affect following --Var usage#push @var_opts, "--notag";next;} elsif ( $arg =~ /^--NoWarn$/ ) {## Supress warnings - No prequisites found# This is acceptable, but normally a tool should take an input# and create some output from it.#$no_warn = 1;next;} elsif ( $arg =~ /^--NoGenerate$/ ) {## Tool does generate a definable output# Should only be used internally#$noGenerate = 1;next;} elsif ( $arg =~ /^--UnknownPreq/ ) {## Indicate that the prequisites are not known, or too complex to# describe. ie: All files in a directory. May be used by packaging# tools.# The recipe will be run EVERY time we want to use the target.#$preq_unknown = 1;$no_warn = 1;next;} elsif ( $arg =~ /^--AutoGenerate/ ) {## Determine when to run the tool based on the types of files that# are generated. Existance of a source file will force the tool# to be run during the 'generate' phase, othewise the tool will be run# when the generated components are required.#$gtype = 2;Warning ("AutoGenerate MUST occur before options that declare generation of files","Have seen:", @genreq_seen)if (@genreq_seen);next;} elsif ( $arg =~ /^--Prereq=(.*)/ ) {## Specify a prerequisite file, that is not a part of the command line# Simply add the files to the list of preq files#my $fn = LocatePreReq ($1);UniquePush ( \@preq_files, $fn );Debug( "GenerateFiles: ExtraPrereq: $fn" );next;} elsif ( $arg =~ /^--Created(.*)=(.*)/ ) {## Specify a generated file, that is not a part of the command line# Add the files to the list of generated files#my $type = $1;my $fn = $2;## Append object suffix to CreatedObject#$fn .= '.' . $::oif ( $type =~ m/Object/ );## If the files is 'created' in a subdir, then add the dir# as a prerequisite.#if ( $type =~ m/Prog/ ) {$fn = "\$(BINDIR)/$fn";UniquePush (\@preq_files, '$(GBE_BINDIR)');} elsif ( $type !~ m/Common/ ) {$fn = "\$(OBJDIR)/$fn";UniquePush (\@preq_files, '$(GBE_OBJDIR)');}## Examine the file and see if it needs to be compiled# Add to the list of source files#push @genreq_seen, $arg;if ( UniquePush (\@gen_files, $fn) ){if ( GenerateSrcFile ( $gtype, $fn ) && $gtype == 2 ){push @has_source, $fn;}}Debug( "GenerateFiles: ExtraCreated: $fn" );next;} elsif ( $arg =~ /^--Clean($|=(.*))/ ) {## Detect Clean option#$clean_tag = $2 ? $2 : '-clean';## Shell command with a --Clean will only# be run during a clean phase. They should not have any prereq# and should not generate any files, so simplify the interface.#push @args, '--NoWarn', '--NoGenerate'if ( $shell_cmds );next;} elsif ( $arg =~ /^--Text=(.*)/ ) {## Display this text when executing commands#$text = $1;next;} elsif ( $arg =~ /^--RecipeTag=(.*)/ ) {## Tag the generated Recipe# Only use the last tag - allow users to overwrite system tags#$recipeTag = $1;Error ("Duplicate RecipeTag - $recipeTag") if ($recipeTags{$recipeTag}++ > 1);next;} elsif ( $arg =~ m/^--AutoUtf$/i) {$utfAuto = 1;$isaUtf = 1;next;} elsif ( $arg =~ m/^--NoAutoUtf$/i ) {$utfAuto = 0;$isaUtf = 1;next;} elsif ( $arg =~ m/^--UtfFormat=(.*)/i) {$utfFormat = $1;$isaUtf = 1;next;} elsif ( $arg =~ m/^--UtfDir=(.*)/i) {$utfDir = $1;$isaUtf = 1;next;} elsif ( $arg =~ m/^--UtfArg=(.*)/i) {push @utfArgs, $1;$isaUtf = 1;next;}# Not an option. Must be an argument to the tool/program# Process the tool arguments and extract file information# Extract all fields of the form:# --xxxxx(yyyyyy[,zzzzz])# --xxxxx{yyyyyyy}# --xxxxx[yyyyyyy] to allow embedded brackets#while ( $arg =~ m/--(\w+) # --CommandWord $1( # Just for grouping\((.*?)\) | # Stuff like (yyyyy) $3{(.*?)} | # or like {yyyyy} $4\[(.*?)\] # or like [yyyyy] $5)/x ) # Allow comments and whitespace{my $cmd = $1; # The commandmy $ufn = $3 || $4 || $5; # User filename + optionsmy $mb = $-[0]; # Match begin offsetmy $me = $+[0]; # Match endmy $flags = ''; # Optional flags ( --dir or --file )my $raw_arg = $ufn; # Raw argumentsmy $all = substr( $arg, $mb, $me - $mb ); # All of match. Avoid use of $&my $is_path = 1;Error ("GenerateFiles. Empty element not allowed: $all")unless ( defined($ufn) );$ufn =~ s/\s+$//;$ufn =~ s/^\s+//;$ufn =~ s~//~/~g; # Remove multiple /if ( $ufn =~ m/(.*?),(.*)/ ) # Extract out any flags{$ufn = $1;$flags = $2;}my $fn = $ufn ; # Replacement filenamemy $fnp = ''; # Prefix to $fnError ("GenerateFiles. Empty element not allowed: $all" )if ( length ($ufn) <= 0 );## Process found user command#if ( $cmd =~ /^Generated/ ){my $use_dir = "";## Generated filename# Determine the target directory# Determine the full name of the file.# Flag the file as generated#if ( $cmd =~ /Prog/ ){## Generated Prog are generated in the BIN directory# Ensure the directory exists by using its symbolic name# as a prerequisite.#$use_dir = '$(BINDIR)';UniquePush (\@preq_files, '$(GBE_BINDIR)');}elsif ( $cmd !~ /Common/ ){## Files that are not Common are generated in the# object directory. This directory must exist, so it# symbolic name GBE_OBJDIR is made a prerequisite too.## If the file is a header file, then add the directory# to the include search path too.#$use_dir = '$(OBJDIR)';UniquePush (\@preq_files, '$(GBE_OBJDIR)');AddIncDir( $platforms , '$(OBJDIR)', '--NoWarn' )if ( $ScmSourceTypes{ StripFile($fn) } && $ScmSourceTypes{ StripFile($fn) } eq ".h" );}## Append a toolset specfic object file name suffix# for Object files only#$fn .= ".$::o"if ( $cmd =~ /Object/ );## Merge directory and filename parts#$fn = $use_dir . ( $use_dir ? "/" : "" ) . $fn;## Save for later user# Flag the file as a generated file#push @genreq_seen, $cmd;if ( UniquePush (\@gen_files, $fn) ){if ($SRCS{ StripDir( $fn ) }){abtWarning(1,"GenerateFiles. Generated File also a Src file: $fn");}elsif ( GenerateSrcFile ( $gtype, $fn ) ){push ( @has_source, $fn ) if ($gtype == 2);}}## Use the directory or the full name# If using the directory then ensure that we have a name# even if its "."#$fn = ($use_dir) ? "$use_dir" : "."if ( $cmd =~ /Directory/ );Debug( "GenerateFiles: Generate: $fn" );}elsif ( $cmd =~ /^Prereq/ ){## Prerequisite filename# Resolve the full name of the file. It may be known# as a source file (possibly generated) or it may be# located in a known source directory#$fn = LocatePreReq ($ufn);UniquePush (\@preq_files, $fn);Debug( "GenerateFiles: Prereq: $fn" );}elsif ( $cmd =~ /^PackageBase/ ){$fn = GetPackageBase( "GenerateFiles", $raw_arg );UniquePush (\@preq_files, $fn);}elsif ( $cmd =~ /^PackageInfo/ ){$fn = GetPackageInfo( "GenerateFiles", $raw_arg );}elsif ( $cmd =~ /^Var/ ){# --Var(...)($fnp, $fn, $is_path) = ExpandGenVar( "GenerateFiles", $raw_arg, @var_opts );$flags = '';if ( $raw_arg eq 'ObjDir' ) {UniquePush (\@preq_files, '$(GBE_OBJDIR)');} elsif ( $raw_arg eq 'BinDir' ) {UniquePush (\@preq_files, '$(GBE_BINDIR)');} elsif ( $raw_arg eq 'LibDir' ) {UniquePush (\@preq_files, '$(GBE_LIBDIR)');}}elsif ( $cmd =~ /^Tool/ ) {# --Tool(toolName)($fn, $is_path) = ExpandTool( "GenerateFiles", $raw_arg );}else{Warning ("GenerateFiles: Unknown replacement command: $cmd");$fn = $ufn;}## Process path modification flags#$fn = ProcessPathName( $fn, $flags );## Minor kludge under windows. Ensure directores have a "\" sep# Unless the user has specified a straight shell command#$fn = "\$(subst /,\$(dirsep),$fn)"if ( $is_path && $::ScmHost eq "WIN" && ! defined($shell_script) );## Prepend any $fn Prefix# This will be a tag and is not subject to path processing#$fn = $fnp . $fn;## Replace the found string with the real name of the file# Note: 4 argument version of substr is not always available# so we must do it the hard way# substr( $arg, $mb, $me - $mb, $fn);#$arg = substr( $arg, 0, $mb ) . $fn . substr( $arg, $me );Debug2( "GenerateFiles: subs: $all -> $fn" );}## Save the tool arguments in an array#push @tool_args, $arg;}## Sanity test. Ensure that some file have been marked as generated# Warn if no prerequisites found#Warning( "GenerateFiles. --AutoGenerate option has no effect","The following files are 'source' files", @has_source ) if ( @has_source );Warning( "No Prerequisite files found in $tool",@tool_args) unless ( $isaUtf || $no_warn || $#preq_files >= 0 );## These would be nice tests - but break too much## ReportError("Mixed use of --NoGenerate and generated files") if (@gen_files && $noGenerate);# ReportError ( "No generated files found in $tool",@tool_args) unless ($isaUtf || $noGenerate || $#gen_files > 0);## Sanity test. If a UTF then we shouldn't generate files#if ($isaUtf ) {ReportError('In UTF mode generated files are not supported:', @gen_files) if @gen_files;}# Invocation does not generate and files# Need to create a dummy name for the rule# Use a base name and a number#if ($noGenerate){my $dummy_target = 'generate_files_' . $NoGenIndex;UniquePush (\@gen_files, $dummy_target );UniquePush (\@GENERATED, $dummy_target) unless $isaUtf;}ErrorDoExit();## Determine the text to display while generating files# Will be either user-text or the first target file (default)# Suffix with RecipeTag, if provided#my $txtSuffix = '';$txtSuffix = "($recipeTag)" if defined $recipeTag;$text = $gen_files[0] unless defined $text;$text .= $txtSuffix;## Save information# Will be used to create makefile statements later#my %gen_data;$gen_data{'index'} = $NoGenIndex++;$gen_data{'recipeTag'} = $recipeTag if defined $recipeTag;$gen_data{'shell'} = $shell_cmds;$gen_data{'gen'} = \@gen_files;$gen_data{'preq'} = \@preq_files;$gen_data{'tool'} = $tool;$gen_data{'toolargs'} = \@tool_args;$gen_data{'clean'} = $clean_tag;$gen_data{'text'} = $text;$gen_data{'preq_sus'} = 1 if ( $preq_unknown );$gen_data{'predelete'} = 1 if ( $predelete );if ($isaUtf){$gen_data{'isautf'} = 1;$gen_data{'utfauto'} = $utfAuto if ( $utfAuto );$gen_data{'utfformat'} = $utfFormat if ( $utfFormat );$gen_data{'utfdir'} = $utfDir if ( $utfDir );$gen_data{'utfargs'} = \@utfArgs;$TESTS_TO_RUN = 1;$TESTS_TO_AUTORUN = 1 if ( $utfAuto );}push(@GENERATE_FILES, \%gen_data);#DebugDumpData("GenerateFiles", \%gen_data);Debug2( "GenerateFiles: cmd: $tool @tool_args" );}#-------------------------------------------------------------------------------# Function : MakePerlModule## Description : Build Perl Module(s) using the Perl Build System# This is a thin wrapper around a specialised script## The user can do the same job with correct use of# a GenerateFiles, but this is a lot tidier.## Inputs : $1 - platform specifier '*' (comma delemitered)# $* - Paths to Perl Modules[,command options]# Options to the BuildPerl script## Returns :#sub MakePerlModule{my ( $platforms, @args) = @_;return if ( ! ActivePlatform($platforms) );Debug2( "MakePerlModule:($platforms, @args)" );my @opts;## Extract options from paths to Perl Packages# Package names do not start with a '-'#foreach my $arg ( @args ){if ( $arg =~ /^-/ ) {push @opts, $arg;} else {## Perl Package Directory Name# This may also contain embedded command to the Make command# These will be seperated with a comma# ie: module,-options=fred#my ($name,$options) = split( ',', $arg );push @opts, "-PerlPackage=$arg";push @opts, "--Prereq=$name/Makefile.PL";}}## Invoke GenerateFiles with a bunch of additional arguments#GenerateFiles ($platforms, "--Tool=jats_buildperl.pl",'--Var(MachType)', # Build Machine type'--Var(PackageDir)', # Package dir'--NoGenerate', # Don't know the output'--Text=Make Perl Module', # Pretty print'--NoWarn','--Clean=-clean_build', # Jats clean support'--NoVarTag', # No more Tags@opts,);}#-------------------------------------------------------------------------------# Function : MakeLinuxDriver## Description : Build a Linux Device Driver using the Linux Device Driver# Build System# This is a thin wrapper around a specialised script## The user can do the same job with correct use of# a GenerateFiles, but this is a lot tidier.## Inputs : $1 - platform specifier '*' (comma delemitered)# $2 - name of the driver. No extension# $* - Driver sources# Options to the script## Returns :#sub MakeLinuxDriver{my ( $platforms, $driver_name, @args) = @_;return if ( ! ActivePlatform($platforms) );Error ("No driver name specified") unless ( $driver_name );Debug2( "MakeLinuxDriver:($platforms, $driver_name ,@args)" );my @srcs;my @opts;## Extract options from source files# Package names do not start with a '-'#foreach my $arg ( @args ){if ( $arg =~ /^--Define=(.)/ ) {push @opts, $arg;} elsif ( $arg =~ /^--ExternalModule=(.)/ ) {push @opts, $arg;} elsif ( $arg =~ /^-/ ) {push @opts, $arg;Warning ("MakeLinuxDriver: Unknown option: $arg. Passed to script");} else {push @srcs, $arg;push @opts, "--Prereq=$arg";}}## Cleanup the drive name#$driver_name =~ s~\.ko$~~;## Remove the specified sources from the list of object files# that will be build. This will ensure that some internal rules are# not generated.#foreach ( @srcs ){my $file = StripExt(StripDir( $_ ));delete $OBJSOURCE{ $file };@OBJS = grep(!/^$file$/, @OBJS);}## Invoke GenerateFiles with a bunch of additional arguments# At runtime the include directories will be added as# absolute paths#GenerateFiles ($platforms, "--Tool=jats_buildlinux.pl","-Output=--GeneratedProg($driver_name.ko)","-Driver=$driver_name","-GccPath=\$(GCC_CC)","-Arch=\$(HOST_CPU)","-LeaveTmp=\$(LEAVETMP)","-Verbose=\$(CC_PRE)","-Type=\$(GBE_TYPE)","-Platform=\$(GBE_PLATFORM)","--Var(LocalBinDir)",'$(patsubst %,-Incdir=%,$(INCDIRS))','--Clean',@opts,@srcs);}#-------------------------------------------------------------------------------# Function : GetPackageBase## Description : Helper routine# Given a package name, determine the base address of the# package## Inputs : $dname - Directive name (Reporting)# $name - Required package# Allows two forms:# package_name# package_name,ext## Returns : Path to the directory in which the files are installed# This may be the interface directory#sub GetPackageBase{my ($dname, $fname) = @_;my $pkg;my ($name, $ext) = split(',', $fname);$pkg = GetPackageEntry( $name, $ext );Error ("$dname: Package not found: $fname") unless ( $pkg );## If a BuildPkgArchive then use the interface directory#return ( $pkg->{'TYPE'} eq 'link' ) ? $pkg->{'ROOT'} : '$(INTERFACEDIR)';}#-------------------------------------------------------------------------------# Function : GetPackageInfo## Description : Helper routine# Given a package name, return some information about the package# Only one information item is allowed with each call## Inputs : $dname - Directive name (Reporting)# $name - Required package# Allows two forms:# package_name# package_name,ext# Selector# --path# --version# --fullversion# --project## Returns : Package informationmy %GetPackageInfo = qw(path ROOTversion DVERSIONfullversion VERSIONproject DPROJ);sub GetPackageInfo{my ($dname, $args) = @_;my $pkg;my $name;my $ext;my $info;## Split up the arguments# Options start with '--'# First non-option is the package name# 2nd non-option is the packag extension## Only one option allowed# Convert it into a known package info item##foreach ( split(',', $args) ){if ( m/^--(.*)/ ) {Error( "$dname: Too many info requests: $args") if ( $info );$info = $GetPackageInfo{$1};Error( "$dname: Unknown info type: $_") unless ($info);} elsif ( $ext ) {Error("$dname: Too many names: $args");} elsif ( $name ) {$ext = $_;} else {$name = $_;}}$pkg = GetPackageEntry( $name, $ext );Error ("$dname: Package not found: $args") unless ( $pkg );## If a BuildPkgArchive then use the interface directory# Default data item - path to the package#$info = 'ROOT' unless ( $info );if ( $info eq 'ROOT' && $pkg->{'TYPE'} ne 'link' ){return ( '$(INTERFACEDIR)');}return ( $pkg->{$info} );}#-------------------------------------------------------------------------------# Function : GetPackageEntry## Description : Return the package class pointer given a package name## Inputs : $name - Required package# $ext - Option package extension## Returns : Class pointer#sub GetPackageEntry{my ($name, $ext) = @_;$ext = '' unless ( $ext );for my $entry (@{$::ScmBuildPkgRules{$ScmPlatform} }){next unless ( $entry->{'NAME'} eq $name );next if ( $ext && $entry->{'DPROJ'} ne $ext );return $entry;}return;}#-------------------------------------------------------------------------------# Function : ExpandGenVar## Description : Expand a known variable for the Generate Files option## Inputs : $dname - Directive name (Reporting)# $arg - Raw argument# This of the form of# Tag[,--option]+# Tags are specified in %ExpandGenVarConvert## Options are:# --tag# --notag# --tag=<SomeTag># --absdrive# --abspath# --default=text# --allownone# Not all options are avalaible on all variables# @opts - Options# --notag - Default is --notag## Returns : Tag - Any tag component of the expansion# Path/Value - Path/Value of the component# is_path - Above is a path# is_abs - Path is absolute### Create a Hash to simplify the process of converting Var names# into makefile variables. There are two data items, separated by a comma.# The first is the runtime expansion value# The second describes the first:# NotPresent - Expansion is not a path# '-' - Expansion is a path and is relative to CWD# '+' - Expansion is a path and is absolute#my %ExpandGenVarConvert = ('BuildName' => '$(GBE_PBASE)','BuildVersion' => '$(BUILDVER)','BuildVersionNum' => '$(BUILDVERNUM)','PackageDir' => '$(PKGDIR),+','PackagePkgDir' => '$(PKGDIR)/pkg/pkg.$(GBE_PLATFORM),+','PackageIncDir' => '$(INCDIR_PKG),+','PackageIncPlatDir' => '$(INCDIR_PKG)/$(GBE_PLATFORM),+','PackageLibDir' => '$(LIBDIR_PKG)/$(GBE_PLATFORM),+','PackageBinDir' => '$(BINDIR_PKG)/$(GBE_PLATFORM)$(GBE_TYPE),+','PackageToolDir' => '$(PKGDIR)/tools,+','PackageToolBin' => '$(PKGDIR)/tools/bin/$(GBE_HOSTMACH),+','PackageToolScript' => '$(PKGDIR)/tools/scripts,+','LibDir' => '$(LIBDIR),+','BinDir' => '$(BINDIR),+','ObjDir' => '$(OBJDIR),+','InterfaceDir' => '$(INTERFACEDIR),+','InterfaceIncDir' => '$(INCDIR_INTERFACE),+','InterfaceLibDir' => '$(LIBDIR_INTERFACE)/$(GBE_PLATFORM),+','InterfaceBinDir' => '$(BINDIR_INTERFACE)/$(GBE_PLATFORM)$(GBE_TYPE),+','LocalDir' => '$(LOCALDIR),+','LocalIncDir' => '$(INCDIR_LOCAL),+','LocalLibDir' => '$(LIBDIR_LOCAL)/$(GBE_PLATFORM),+','LocalBinDir' => '$(BINDIR_LOCAL)/$(GBE_PLATFORM)$(GBE_TYPE),+','Platform' => '$(GBE_PLATFORM)','Product' => '$(GBE_PRODUCT)','Target' => '$(GBE_TARGET)','Type' => '$(GBE_TYPE)','Arch' => '$(HOST_CPU)','Architecture' => '$(HOST_CPU)','MachType' => '$(GBE_HOSTMACH)','BuildRoot' => '$(GBE_ROOT),+','Verbose' => '$(CC_PRE)','LeaveTmp' => '$(LEAVETMP)','Cwd' => '$(CURDIR),-',# Generated when used'CompilerPath' => '$(SCM_COMPILERPATH)','PkgArch' => '$(PACKAGE_ARCH)','Native' => '0','Toolset' => '0',);sub ExpandGenVar{my ($dname, $args, @uopts) = @_;my $expansion;my $prefix='';my ($tag, @opts) = split('\s*,\s*', $args);my $no_prefix;my $default_value;my $allow_none;my $is_abs = 0;## Parse options lists# Options provided by the caller# Options embedded in the argumentforeach ( @uopts ){if ( m/^--notag$/ ) {$no_prefix = 1;} else{Error ("$dname: Unknown option: $_")}}foreach ( @opts ){if ( m/^--default=(.+)/i ) {$default_value = $1;} elsif ( m/^--allownone$/i ) {$allow_none = 1;}}## Perform run-time update on the %ExpandGenVarConvert# Most of it can be initialised at startup - but not all of it.#$ExpandGenVarConvert{CompilerPath} = undef unless $::ScmToolsetCompilerPath;$ExpandGenVarConvert{Product} = '$(GBE_PLATFORM)' unless $ScmProduct;$ExpandGenVarConvert{Native} = '1' if isAnAlias ('NATIVE');$ExpandGenVarConvert{Toolset} = '1' if isAnAlias ('TOOLSET');## Look up a hash of conversions# Could allow for a code ref, but not needed yet#Error ("$dname: Unknown expansion --Var($tag)")unless ( exists $ExpandGenVarConvert{$tag} );## Handle undefined expansions# Only 'CompilerPath', but it can be a pain in user land#$expansion = $ExpandGenVarConvert{$tag};unless ( defined $expansion ){return '','',0,0 if ( $allow_none );$expansion = $default_value;Error ("$dname: Expansion --Var($tag) not be supported by toolset: $ScmToolset")unless ( $expansion );}($expansion,my $is_path) = split (',', $expansion );$is_abs = 1if ($is_path && $is_path eq '-' );## Process options# Assume that a tag will be provided#$prefix = $no_prefix ? '' : "-$tag=";foreach my $opt ( @opts ){if ( $opt =~ /^--tag=(.*)/i ) {$prefix = "$1=";} elsif ( $opt =~ m/^--tag$/i ) {$prefix = "-$tag=";} elsif ( $opt =~ m/^--notag/i ) {$prefix = '';} elsif ( $is_path && !$is_abs && $opt =~ /--abspath|--absdrive/i ) {$expansion = '$(CURDIR)/' . $expansion;$is_abs = 1;} elsif ( $opt =~ m/^--default=(.+)/i ) {# Already processed} elsif ( $opt =~ m/^--allownone$/i ) {# Already processed} else {Error ("$dname: Unsupported option($opt) for --Var(@_)");}}Debug ("ExpandGenVar: args $args --> $prefix$expansion");return $prefix , $expansion, $is_path ? 1 : 0, $is_abs;}#-------------------------------------------------------------------------------# Function : ExpandTool## Description : Locate a 'tool' and provide the complete path## Inputs : $dname - Directive name (Reporting)# $arg - Name of the tool to locate (no extension) with# embedded options. Options are:# --dir# --file# --abspath# --absdrive### Returns : Path/Value - Path/Value of the component# is_path - Above is a path# is_abs - Path is absolute#sub ExpandTool{my ($dname, $args) = @_;my ($toolName, @opts) = split('\s*,\s*', $args);my $is_abs = 1;my $is_path = 1;## Locate the tool in one of the dependent packages#my @extension_list;push @extension_list, '.exe' if ( $::ScmHost ne "Unix" );my $toolFullPath = ToolExtensionProgram( $toolName, @extension_list );if ($toolFullPath) {$toolName = $toolFullPath;} else {Warning("$dname. Tool not found: $toolName", "Searched:", ToolExtensionPaths());}## Process options#foreach my $opt ( @opts ){if ( $opt =~ m/^--dir/i ) {$toolName = StripFileExt($toolName);} elsif ( $opt =~ m/^--file/i ) {$toolName = StripDir($toolName);$is_abs = 0;$is_path = 0;} elsif ( $opt =~ m/^--abspath/i ) {$toolName = AbsPath($toolName);} elsif ( $opt =~ m/^--absdrive/i ) {$toolName = FullPath($toolName);} else {Error ("$dname: Unsupported option($opt) for --Tool(@_)");}}Debug ("ExpandTool: $args --> $toolName");return $toolName, $is_path ? 1 : 0, $is_abs;}#-------------------------------------------------------------------------------# Function : isAnAlias## Description : Internal Helper# Determine if this platform is an alias for ...## Inputs : $target - Test against this target## Returns : True - Is an alais for $target.#sub isAnAlias{my ($target) = @_;if (exists ($::BUILDINFO{$ScmPlatform}{'USERALIAS'}) ){if ( grep /^$target$/, @{$::BUILDINFO{$ScmPlatform}{'USERALIAS'}} ){return 1;}}if (exists ($::BUILDINFO{$ScmPlatform}{'ALIAS'}) ){if ( $target eq $::BUILDINFO{$ScmPlatform}{'ALIAS'} ){return 1;}}return 0;}#-------------------------------------------------------------------------------# Function : ProcessPathName## Description : Massage a pathname according to a set of flags## Inputs : $fn - Patchname to massage# $flags - Flags in a string# --dir - only the directory part ( or a "." )# --file - only the file part# --abspath - Absolute path# --absdrive - Absolute path with drive letter(WIN)## Returns : Massaged pathname#sub ProcessPathName{my ( $fn, $flags ) = @_;## Process flags# --dir - only the directory part ( or a "." )# --file - only the file part# --abspath - Absolute path# --absdrive - Absolute path with drive letter(WIN)#if ( $flags =~ /--dir/ ){$fn = '.'unless ( $fn =~ s~/[^/]*$~~);}if ( $flags =~ /--file/ ){$fn =~ s~.*/~~;}if ( $flags =~ /--abspath/ ){$fn = AbsPath( $fn );}elsif ( $flags =~ /--absdrive/ ){$fn = AbsPath( $fn );if ( $::ScmHost eq "WIN" ){$fn = $::CwdDrive . '/' . $fnunless ( $fn =~ m~^\w:/~ );$fn =~ s~//~/~g;}}return $fn;}#-------------------------------------------------------------------------------# Function : LocatePreReq## Description : Locate a file known to JATS# There are many places to search# 1) Src files - specified with a Src directive# 2) Scripts - specified with a script directive# 3) Search - Files in the specified search path# 4) Programs specified with a 'Prog' directive## Should also look in other locations (Libs, SharedLibs)# Not done yet. May be issues of a name clash if a program# and a library have the same name.## Inputs : Name to locate## Returns : Full pathname of file#sub LocatePreReq{my ( $name ) = @_;Debug ("LocatePreReq:Looking for $name");## Try a Src file first#if ( exists $SRCS{ $name } ){return $SRCS{ $name };}## Try a script#if ( exists $SCRIPTS{ $name } ){return $SCRIPTS{ $name };}## Try a PROG#if ( my $pProg = $PROGS->Get($name) ){return $pProg->getPath();}## Try searching for the file# Uses Data from AddSrcDir## Done: last because it generates warning messages#return MakeSrcResolve( $name );}#-------------------------------------------------------------------------------# Function : ToolExtensionPaths## Description : Return a list of toolset extension directories# The data will have been discovered by the build process# and will have been saved for the makefile creation phase## Inputs : None## Returns : Return an ordered unique list#sub ToolExtensionPaths{Debug( "ToolExtensionPaths:", @::BUILDTOOLSPATH );return @::BUILDTOOLSPATH;}#-------------------------------------------------------------------------------# Function : ToolExtensionProgram## Description : Determine if the named program exists within the PATH# that also includes the toolset extension## Inputs : program - Name of program# elist - An array of possible program extensions## Returns : Full path the to program or an empty element (not undef)#sub ToolExtensionProgram{my ($program, @elist ) = @_;## If elist is empty then insert a defined entry#push @elist, '' unless ( @elist );## Scan all toolset directories# for the program#for my $dir ( ToolExtensionPaths() ){for my $ext ( @elist ){my $tool = "$dir/$program$ext";Debug( "ToolsetExtensionProgram: Look for: $tool" );return $tool if ( -f $tool );}}}sub Define{Debug2( "Define(@_)" );push( @DEFINES, @_ );}sub Defines{my( $path, $script ) = @_;my( $line );Debug2( "Defines($path, $script)" );$script = Exists( $path, $script, "Defines" );push( @DEFINES, "# Defines from: $script" );open( my $fh, '<', $script ) || Error( "Opening $script" );while (<$fh>) {$_ =~ s/\s*(\n|$)//; # kill trailing whitespace & nlpush( @DEFINES, $_ );}push( @ScmDepends, "$script" ); # makefile dependenciesclose( $fh );}#-------------------------------------------------------------------------------# Function : Rule## Description : Add a Rule and Recipe to the generated makefile# This is not encouraged as it has been misused to create# unreadable and unmaintainable makefiles.## Rules will be added to the makefile after the rules and# recipes created by JATS directives## Inputs : $platform - Platform predicate# @rule - Array of rules to add## Returns :#sub Rule{my( $platforms, @rule ) = @_;return if ( ! ActivePlatform($platforms) );push( @RULES, @rule );Message("Rule directive used. Consider replacing with GenerateFiles");}#-------------------------------------------------------------------------------# Function : Rules## Description : Add a file of Rules and Recipes to the generated makefile# Used internally ONLY as there is no platform predicate# Similar to 'Rule()'## Inputs : $path - path to script# $script - File fo Rules## Returns :#sub Rules{my( $path, $script ) = @_;my( $line );$script = Exists( $path, $script, "Rules" );push( @RULES, "# Rules from: $script" );open( my $fh, '<', $script ) || Error( "Opening $script" );while (<$fh>) {$_ =~ s/\s*(\n|$)//; # kill trailing whitespace & nlpush( @RULES, $_ );}push( @ScmDepends, "$script" ); # makefile dependenciesclose( $fh );}#-------------------------------------------------------------------------------# Function : AddRule## Description : Inernal function# Add a line to the Rules area## Inputs : @elements - Array of lines to add## Returns : Nothing#sub AddRule{push( @RULES, @_ );}#-------------------------------------------------------------------------------# Function : Src## Description : This directive is used to identify files to JATS# Once a file has been identified as a 'Source' file, then it# can be used by name, without the need to locate the file again.# This implies that filenames must be unique.# The directories cannot be used to make files of the same name# unqiue - this is not the JATS way## Source files will be classified as one of:# c, c++, header, assembler or other### Inputs : $platform - Active Platform Predicate# @elements - A list of files and options## Valid options are:# --c - Specifies the type of file# --cpp# --h, --headers# --asm# --FromPackage - Search packages for the file# --List=xxx - Append file to a named list# --Depends=xxx - Manually name a dependency# --IgnoreDuplicates - Ignore duplicates (mostly internal use)## Options are processed before file elements# Thus options apply to all files in the list## Returns : Nothing#sub Src{my( $platforms, @elements ) = @_;my( $type, @args, $source, $basename, $from_package, @lists, $ignoreDups );my( @depends, @srcs );$platforms = '' unless ( $platforms );Debug2( "Src($platforms, @elements)" );## Ensure that there is a file within the list#Warning( "Src directive does not specify any files: Src($platforms, @elements)" )unless (grep( /^[^-]/, @elements ) );return if ( ! ActivePlatform($platforms) );## Remove spaces from both ends of the arguments.# It is easier to remove spaces now than to detect them later#foreach ( @elements ){s/^\s+//;s/\s+$//;s~//~/~g; # Remove multiple /}#.. Collect arguments#$type = "";foreach ( @elements ){if ( /^--c$/ ){Debug( "Src: --c" );$type = ".c";}elsif ( /^--cpp$/ ){Debug( "Src: --cpp" );$type = ".cc";}elsif ( /^--h$/ || /^--header$/ ){Debug( "Src: --h" );$type = ".h";}elsif ( /^--asm$/ ){Debug( "Src: --asm" );$type = ".asm";}elsif ( /^--IgnoreDup/ ){$ignoreDups = 1;}elsif ( /^--FromPackage$/ ){$from_package = 1;}elsif ( /^--List=(.*)/ ){my $list_name = $1;Error( "Bad list name: $list_name" )unless ( $list_name =~ m/^[A-Za-z]\w+/ );push @lists, $list_name;}elsif ( /^--Depends=(.*)/ ){foreach ( split( ',', $1) ){my $full = MakeSrcResolveExtended( $from_package, $_ );push @depends, $full;}}elsif ( /^-(.*)/ ){Debug( "Src: arg $_" );push @args, $_;}else{push @srcs, $_;Warning ("Src files contains a '\\' character: $_" ) if (m~\\~);}}#.. Push source file(s)foreach ( @srcs ){if ( ! /^-(.*)/ ){$source = MakeSrcResolveExtended( $from_package, $_ );$basename = StripDir( $source );Debug( "Src: $_ -> $source=$basename (@args),(@depends)" );if ( $SRCS{ $basename } ) {Warning( "Duplicate src ignored '$source'") unless $ignoreDups;next;}$SRCS{ $basename } = $source;HashJoin( \%SRC_ARGS, $;, $basename, @args )if (@args);HashJoin( \%SRC_DEPEND, $;, $basename, @depends )if ( @depends );$SRC_TYPE{ $basename } = $typeif ($type);foreach (@lists) {my $lname_short = "LIST_$_";my $lname_full = "LIST_FULL_$_";no strict 'refs';push @$lname_short,$basename;push @$lname_full ,$source;use strict 'refs';}__AddSourceFile( 1, $source, "", $type );}}}#-------------------------------------------------------------------------------# Function : AddToSrc## Description : Internal function# Used by plugins and tools## Will test if specified file is known to JATS, before# adding to the the list of known (Src) files## Inputs : $platform# $file - Only one file# @srcOpts - Same as Src## Returns : True if any file can be found# Returns full path to the file#sub AddToSrc{my( $platforms, $file, @args ) = @_;Debug2( "AddToSrc($platforms, $file, @args)" );## Process files#my $basename = StripDir( $file );unless (exists $SRCS{$file} || exists $SRCS{$basename} ) {Src ('*', $file, @args);}return $SRCS{$basename};}################################################################################ sub LibNameSplit# Just a little help to deal with major/minor stuff for shared libs -# given the name of the library as the argument, split out major and minor# parts and return the basename, i.e name without major and minor and# the pair of major and minor.###############################################################################sub LibNameSplit{my ( @bits ) = split('\.', $_[0]);my ( $major, $minor );if ($#bits >= 1) {$major = $bits[0]; $minor = $bits[1];} elsif ($#bits >= 0) {$major = $bits[0]; $minor = 0;} else {$major = 1; $minor = 0;}Debug( "LibName: $@_[0] ($major.$minor)" );return ($major, $minor);}#-------------------------------------------------------------------------------# Function : Lib## Description : Generate a static library## Inputs : Platform specifier# Name of the library# Arguemnts ...## Returns :#sub Lib{my( $platforms, $lib, @args ) = @_;return if ( ! ActivePlatform($platforms) );Error ("Lib: Library name not defined") unless ( $lib );## May be a shared library or a static library - for historic reasons# If the user has specified a --Shared then its a shared library#return SharedLib( @_ )if ( grep (/^--Shared/, @args) );## Does this toolset support libraries#Error ("Libraries are not supported") unless ( defined $::a );#.. Fully qualify library path for addition to library list.$lib = "lib$lib"if ( $ScmTargetHost eq "Unix" && $lib !~ m/^lib/);Debug( "Lib: $lib" );## Create a new object to describe the library# Ensure that only one such lib exists# Add the library to the list of static libraries#Error( "Library of the same name already defined: $lib" )if ( $LIBS->Get($lib) );$LIBS->NewAdd($lib);## Process arguments#push( @LINTLIBS, $lib );_LibArgs( $lib, @args );}#-------------------------------------------------------------------------------# Function : SharedLib## Description : Generate a shared library## Inputs : Platform specifier# Name of the library# Arguemnts ...## Returns :#sub SharedLib{my( $platforms, $lib, @args ) = @_;return if ( ! ActivePlatform($platforms) );Error ("SharedLib: Library name not defined") unless ( $lib );Error ("Shared Libraries are not supported") unless ( defined $::so );#.. Fully qualify library path for addition to library list.$lib = "lib$lib"if ( $ScmTargetHost eq "Unix" && $lib !~ m/^lib/);Debug( "ShLib: $lib" );## Ensure that only one such lib exists#Error( "Library of the same name already defined: $lib" )if ( $SHLIBS->Get($lib) );$SHLIBS->NewAdd($lib);## If the user has not specified a --Shared parameter then provide one#push @args, "--Shared=Current"unless ( grep (/^--Shared/, @args) );## Process arguments#push( @LINTSHLIBS, $lib );_SharedLibArgs( $lib, @args );}#-------------------------------------------------------------------------------# Function : LibArgs## Description : Add arguments to an existing library directive## Inputs : Platform specifier# Name of the library# Arguemnts ...## Returns :#sub LibArgs{my( $platforms, $lib, @args ) = @_;return if ( ! ActivePlatform($platforms) );#.. Fully qualify library path for addition to library list.$lib = "lib$lib"if ( $ScmTargetHost eq "Unix" && $lib !~ m/^lib/);Debug( "LibArgs: $lib" );## Process the arguments#_LibArgs( $lib, @args );}#-------------------------------------------------------------------------------# Function : _LibArgs## Description : Process static library arguments# Internal use only## Inputs : Name of the library# Arguments to process#sub _LibArgs{my( $lib, @elements) = @_;my $obj;## Ensure that only one such lib exists#my $libp = $LIBS->Get($lib);Error("Library name not defined: $lib")unless ( $libp );## Process each element#foreach (@elements){if ( /^\s+/ ){Error ("Argument cannot start with a space: '$_'");}if ( /^--Shared/ ){Error( "--Shared not valid for a static library" );}if ( /^-l(.*)/ || /^--l(.*)/ || /^-L(.*)/ || /^--L(.*)/ ){#.. Target library specified - add to library list.#Warning( "$_ within non shared library specification" );next;}if ( /^--if(.*)/ ){Warning( "$_ within non shared library specification" );next;}if ( /^--(.*)/ ){Debug( "LibArgs: arg $_" );#.. Argument specified - add to argument list#$libp->addItem('ARGS', $_);next;}if ( %::ScmToolsetProgSource ){## Toolset provides support for some file types# to be passed directly to the librarian builder#my $ext = StripFile($_);if ( exists ($::ScmToolsetProgSource{$ext}) ){my $full_path = MakeSrcResolve ( $_ );my $flag = $::ScmToolsetProgSource{$ext};Debug( "LibArgs: src $_" );$libp->addItem('ARGS', "$flag$full_path" );next;}}if ( $::o ){#.. Object specified - add to object list.#$obj = _LibObject( "", $_ );#.. Add to object list.# Note: Object path must be explicit as several# toolsets add additional objects.#$libp->addItem('OBJS', "\$(OBJDIR)/$obj" );next;}## Don't know how to handle this type of argument#Error ("LibArgs: Don't know how to handle: $_" );}}#-------------------------------------------------------------------------------# Function : SharedLibArgs## Description : Add arguments to an existing shared library directive## Inputs : Platform specifier# Name of the library# Arguemnts ...## Returns :#sub SharedLibArgs{my( $platforms, $lib, @args ) = @_;return if ( ! ActivePlatform($platforms) );#.. Fully qualify library path for addition to library list.$lib = "lib$lib"if ( $ScmTargetHost eq "Unix" && $lib !~ m/^lib/);Debug( "ShLibArgs: $lib" );_SharedLibArgs( $lib, @args );}#-------------------------------------------------------------------------------# Function : _SharedLibArgs## Description : Process shared library arguments# Internal use only## Inputs : Name of the library# Arguments to process#sub _SharedLibArgs{my ( $lib, @elements) = @_;my $libp = $SHLIBS->Get($lib);Error("Library name not defined: $lib")unless ( $libp );##.. Collect --Shared arguments# Need to process this one first so that we have a version number#foreach (@elements){if ( /^\s+/ ){Error ("Argument cannot start with a space: '$_'");}next unless ( /^--Shared/ );my $shared;if ( /^--Shared$/ ){#.. Shared library, default library version 1.0#$shared = "1.0";}elsif ( /^--Shared=Current$/ ){#.. Shared library, using 'current' build version#$shared = $::ScmBuildVersion;$shared = "1.0" if ($shared eq "");}elsif ( /^--Shared=(.*)/ ){#.. Shared library, specific version#my($M, $m) = LibNameSplit($1);$shared = "$M.$m";}## Update the shared Names#if ( defined $shared ){Warning( "multiple --Shared arguments" )if (exists $libp->{ VERSION });Debug( "ShLibArgs: shared $_ ($shared)" );$libp->{ VERSION } = $shared;}else{Error ("ShLibArgs: --Shared argument not understood");}}#.. Parse all of the object and argument entries.#foreach (@elements){next if ( /^--Shared(.*)/ );if ( /^[-]{1,2}([lL])(.*)/ ){#.. Target library specified - add to library list.# Support --L and -L and --l and -l#Debug( "ShLibArgs: lib -$1$2" );$libp->addItem('LIBS', "-$1$2" );next;}if ( /^--if(.*)/ ){#.. Library conditional - add to library list.#Debug( "ShLibArgs: cond $_" );$libp->addItem('LIBS', $_);next;}if ( /^--SoName=(.*)/i ){#.. Specify the SoName of the library# Not supported by all toolsets#my $soMode = $1;if ( !$ScmToolsetSoName ){Warning ("Toolset does not support --SoName. Option ignored");next;}Error ("SharedLib: $lib. Multiple --SoName arguments not allowed")if ( $libp->{ SONAME } );my ($major, $minor, $patch, $build, $raw_patch) = SplitVersion($::ScmBuildVersionFull);my $soname = '.';if ( $soMode =~ m/Major/i ) {$soname .= $major;} elsif ( $soMode =~ m/^Minor/i ) {$soname .= "$major.$minor";} elsif ( $soMode =~ m/^Patch/i ) {$soname .= "$major.$minor.$patch";} elsif ( $soMode =~ m/^Build/i ) {$soname .= "$major.$minor.$patch.$build";} elsif ( $soMode =~ m/^Full/i ) {$soname .= $libp->{ VERSION };} elsif ( $soMode =~ m/^None/i ) {$soname = '';} elsif ( $soMode =~ m/^[0-9.]+$/ ) {$soname .= $soMode;} else {Error ("Unknown --SoName mode: $soMode");}$libp->addItem('ARGS', '--SoNameSuffix=' . $soname);$libp->{ SONAME } = 1;next;}if ( /^-(.*)/ ){#.. Argument specified - add to argument list#Debug( "ShLibArgs: arg $_" );$libp->addItem('ARGS', $_);next;}if ( %::ScmToolsetProgSource ){## Toolset provides support for some file types# to be passed directly to the program builder#my $ext = StripFile($_);if ( exists ($::ScmToolsetProgSource{$ext}) ){my $full_path = MakeSrcResolve ( $_ );my $flag = $::ScmToolsetProgSource{$ext};Debug( "ShLibArgs: src $_" );$libp->addItem('ARGS', "$flag$full_path");next;}}if ( $::o ){#.. Object specified - add to object list.#my ($obj) = _LibObject( $lib, $_ );#.. Add to object list.# Note: Object path must be explicit as several# toolsets add additional objects.#$SHOBJ_LIB{ $obj } = $lib;$libp->addItem('OBJS', "\$(OBJDIR)/$obj");next;}## Don't know how to handle this type of argument#Error ("SharedLib: Don't know how to handle: $_" );}}#-------------------------------------------------------------------------------# Function : _LibObject## Description : Process library object file# Common processing routine for static and shared library# Internal use only## Inputs : shared - Name of the shared library is shared, if defined# fname - Name of file## Returns : Name of the object file#sub _LibObject{my ($shared, $fname) = @_;my ($file, $ext, $obj, $srcfile, $delete_obj);#.. Object specified - add to object list.## Want to handle several cases# Normal - User has provided the name of an object file (without the obj suffix)# Other - User has provided the name of a source file# Need to perform implicit source file processing## The hard part is detecting the difference# Just can't use the existence of a '.'#if ($OBJSOURCE{$fname}) {$file = $fname; # Already know about this file$ext = ''; # Don't need to split it} else {$file = StripDirExt($fname); # file name, without extension or Dir$ext = StripFile($fname); # extension}if ($shared) {$obj = "$shared/$file"; # library specific subdir} else {$obj = "$file";}Debug( "LibObjs: obj [$shared]$fname ($file$ext)" );#.. Unqualified object name#if ( $ext eq '' ) {## Object file not covered by a "Src" statement# Assume that it will be created#unless ( $srcfile = $OBJSOURCE{$file} ){## If the object is "generated" then it will be in the# SRCS list#unless ( $srcfile = $SRCS{"$file.$::o"} ){Warning( "No source for object '$fname' ($file)" );}}$delete_obj = 1;}#.. Qualified object name (ie has extension)# Strip extension and resolve ...# Assume that the named file can be built into an object file#else{#.. Resolve#if ( !($srcfile = $OBJSOURCE{ "$file" }) ){$srcfile = MakeSrcResolve( $fname );$SRCS{ $fname } = $srcfile;__AddSourceFile( 0, $fname, $obj );$delete_obj = 1;}}#.. Delete generated object file# Ensure that the object file is added to the delete list# Add it to the ToolsetObj deletion list as the main OBJ deleltion# list will aready have been processed#ToolsetObj( "\$(OBJDIR)/$obj" )if ( $delete_obj );#.. Shared library objects,# Must explicitly relate source and object, as shared libraries# objects are built within a library specific subdirs.#$OBJSOURCE{ $obj } = $srcfileif ( $shared && defined $srcfile );return $obj;}# MergeLibrary# Merge a list of libraries into one library#sub MergeLibrary{my( $platforms, $lib, @elements ) = @_;return if ( ! ActivePlatform($platforms) );#.. Fully qualify library path for addition to library list.$lib = "lib$lib"if ( $ScmTargetHost eq "Unix" && $lib !~ m/^lib/);Debug( "MergeLibrary: $lib" );## Create a new object to describe the library# Ensure that only one such lib exists# Add the library to the list of static libraries#Error( "Merged Library of the same name already defined: $lib" )if ( $MLIBS->Get($lib) );my $libp = $MLIBS->NewAdd($lib);#.. Parse all of the object and argument entries.#foreach (@elements){if ( /^--(.*)/ ){$libp->addItem('ARGS', $_);}else{my ($llib);## Collect the source libraries# These must have been installed and will be in a known area# Create full names for the libaries#if ( $ScmTargetHost eq "Unix" ) {$llib = "lib$_"; # Prefix "lib" ....$lib =~ s/^liblib/lib/; # @LIBS already has lib added} else {$llib = $_;}Debug( "MergeLibrary: merge $llib" );$libp->addItem('LIBS', $llib);}}}#-------------------------------------------------------------------------------# Function : Script## Description : Locate a script for test purposes## Inputs : $platforms - Platform selector# $script - A single script name# $execute - Flag to indicate that the script is to# marked as executable when used in a TestProg# This flag is NOT used as the script will# be forced executable## Returns : Nothing#sub Script{my( $platforms, $script, $execute ) = @_;Debug2( "Script(@_)" );return if ( ! ActivePlatform($platforms) );## Locate the script as a source file#my $file = MakeSrcResolve ( $script );$script = StripDir( $file );$SCRIPTS{ $script } = $file;}#-------------------------------------------------------------------------------# Function : RunTest## Description : Define a test to be run with the 'run_tests' and 'run_unit_tests'## Inputs : $platform - Enabled for these platforms# $prog - Program to run# This SHOULD return a non-zero exit status# on error. The program may be a 'TestProg'# or a 'Script'.# @elements - Options and test arguments# Options are:# --Auto - Non interactive unit test# --Unit - Same and --Auto# --UtfFormat=nnn - Specifies Automated Unit Test,# results post processed with formatter# --UtfArg=nnn - Argument passed into the UTF formatter# --Name=nnn - Test Name.# --CopyIn=file - A file to be copied into the test directory.# --MaxTime=fff.ff[smhd] - Max Test Time. Default 30m## Non Options are passed to the test program.# --PackageBase(xxx) - Base of package# --PackageInfo(xxx) - Package information# --File(xxx) - Resolved name of file# --Var(xxx) - Expanded variable# --Local(xxx) - File within the local directory## Toolset Framework support (ie NUNIT in csharp.pl)# --FrameWork=name - Name of framework# --xxxx - Args passed to framework constructor## Returns : Nothing#my %RunTestNames; # Unique Name Testssub RunTest{my( $platforms, $prog, @elements ) = @_;my $command = './'; # program prefix / commandmy $winprog = 1; # 1: Convert / -> \ (WIN32 only)my $framework;my @framework_opts;my @copy = ();my $auto;my $utfFormat;my @utfArgs;my $utfName;my $maxTime;return if ( ! ActivePlatform($platforms) );## Scan @elements and extract useful information# Need to process twice as some args will modify the# processing done later#my @args;foreach ( @elements ){if ( m/^--FrameWork=(.+)/ ) {$framework = $1;} elsif ( m/^--Auto/ || m/^--Unit/) {$auto = 1;} elsif ( m/^--Name=(.*)/) {$utfName = $1;Error("Duplicate Test Name: $utfName")if (exists $RunTestNames{$utfName} );$RunTestNames{$utfName} = 1;} elsif ( m/^--UtfFormat=(.*)/) {$utfFormat = $1;} elsif ( m/^--UtfArg=(.*)/) {push @utfArgs, $1;} elsif ( m/^--MaxTime=(.*)/) {$maxTime = $1;unless ($maxTime =~ m~^[0-9]*\.?[0-9]+[smhd]?$~) {Error("MaxTime invalid: $maxTime");}} elsif ( m/^--CopyIn=(.*)/ ) {push @copy, MakeSrcResolve ( $1 );} elsif ( $framework && m/^--\w+=(.+)/ ) {push @framework_opts, $_;} else {push @args, $_;}}@elements = @args;@args = ();## Determine the source of the test prog# If using a plug-in framework, then we don't know# If not, then may be a script or a TESTPROGS#unless ( $framework ){if ( $TESTPROGS->Get($prog) || $PROGS->Get($prog) ) {## Append a suitable EXE suffix#$prog = GenProgName( $prog );} elsif ( exists $SCRIPTS{$prog} ) {## Script names are raw# Perl script are invoked directly#$command = "\$(GBE_PERL) -w "if ( $prog =~ /\.pl$/ );## Pass / to shells#$winprog = 0unless ( $prog =~ m~\.bat$~ )} else {Warning("RunTest program not known: $prog","It is not a TestProg, Prog or a Script","The test may fail" );}}## Extract and process options#my @uargs = ();my @preq_files;foreach my $arg (@elements) {## Process the tool arguments and extract file information# Extract all fields of the form:# --xxxxx(yyyyyy[,zzzzz])# --xxxxx{yyyyyyy}# --xxxxx[yyyyyyy] to allow embedded brackets#while ( $arg =~ m/--(\w+) # --CommandWord $1( # Just for grouping\((.*?)\) | # Stuff like (yyyyy) $3{(.*?)} | # or like {yyyyy} $4\[(.*?)\] # or like [yyyyy] $5)/x ) # Allow comments and whitespace{my $cmd = $1; # The commandmy $ufn = $3 || $4 || $5; # User filename + optionsmy $mb = $-[0]; # Match begin offsetmy $me = $+[0]; # Match endmy $flags = ''; # Optional flags ( --dir or --file )my $raw_arg = $ufn; # Raw argumentsmy $all = substr( $arg, $mb, $me - $mb ); # All of match. Avoid use of $&my $is_abs;my $is_path = 1;Error ("RunTest. Empty element not allowed: $all")unless ( defined($ufn) );$ufn =~ s/\s+$//;$ufn =~ s~//~/~g; # Remove multiple /if ( $ufn =~ m/(.*?),(.*)/ ) # Extract out any flags{$ufn = $1;$flags = $2;}my $fn = $ufn ; # Replacement filenamemy $fnp = ''; # Prefix to $fnError ("RunTest. Empty element not allowed: $all" )if ( length ($ufn) <= 0 );## Process found user command#if ( $cmd =~ /^File/ ){## Prerequisite filename# Resolve the full name of the file. It may be known# as a source file (possibly generated) or it may be# located in a known source directory#$fn = MakeSrcResolve ( $ufn );UniquePush (\@preq_files, $fn);Debug( "RunTest: Prereq: $fn" );}elsif ( $cmd =~ /^PackageBase/ ){$fn = GetPackageBase( "RunTest", $raw_arg );UniquePush (\@preq_files, $fn);}elsif ( $cmd =~ /^PackageInfo/ ){$fn = GetPackageInfo( "RunTest", $raw_arg );}elsif ( $cmd =~ /^Var/ ){($fnp, $fn, $is_path, $is_abs) = ExpandGenVar( "RunTest", $raw_arg );$flags = '';}elsif ( $cmd =~ /^Tool/ ){($fn, $is_path, $is_abs) = ExpandTool( "RunTest", $raw_arg );$flags = '';}elsif ( $cmd =~ /^Local/ ){$fn = '$(LOCALDIR)/' . $ufn ;UniquePush (\@preq_files, $fn);}elsif ( $cmd =~ /^Dir/ ){# Item is a directory.# Must be massaged so that it will be correct within the context# Modified path is simply added to the command line#$fn = $ufn;unless (-d $fn) {if (-f $fn) {Warning ("Not a directory. Its a file: $arg") ;} else {Warning ("Directory not found: $arg");}}}else{Warning ("RunTest: Unknown replacement command: $cmd");$fn = $ufn;}## Process path modification flags# --dir - only the directory part ( or a "." )# --file - only the file part# --abspath - Absolute path# --absdrive - Absolute path with drive letter(WIN)#$fn = ProcessPathName( $fn, $flags );## The program is going to be executed within a subdirectory# so add one more level of indirection to the path, but only if# the path is relative#if ( $is_path && ! $is_abs ){unless ( $fn =~ m~^/|^\w:/~ ){$fn = '../' . $fnunless( $fn =~ s~=~=../~ );$fn =~ s~/.$~~;}}## Minor kludge under windows. Ensure directores have a "\" sep# Unless the user has specified a straight shell command#$fn = "\$(subst /,\$(dirsep),$fn)"if ( $::ScmHost eq "WIN" && $winprog );## Prepend any $fn Prefix# This will be a tag and is not subject to path processing#$fn = $fnp . $fn;## Replace the found string with the real name of the file# Note: 4 argument version of substr is not always available# so we must do it the hard way# substr( $arg, $mb, $me - $mb, $fn);#$arg = substr( $arg, 0, $mb ) . $fn . substr( $arg, $me );Debug2( "RunTest: subs: $all -> $fn" );}push(@uargs, "'$arg'");}## Create the test entry# This is a structure that will be placed in an array# The array preserves order and uniqness#my %test_entry;$test_entry{'framework'}= $framework if ( $framework );$test_entry{'framework_opts'}= \@framework_opts if ( $framework );$test_entry{'command'} = $command . $prog unless ( $framework);$test_entry{'prog'} = $prog;$test_entry{'copyprog'} = 1;$test_entry{'args'} = \@uargs;$test_entry{'auto'} = $auto if ( $auto );$test_entry{'utfformat'}= $utfFormat if ( $utfFormat );$test_entry{'utfargs'} = \@utfArgs;$test_entry{'utfname'} = $utfName;$test_entry{'maxtime'} = $maxTime if ($maxTime);$test_entry{'copyin'} = \@copy;$test_entry{'copyonce'} = ();$test_entry{'preq'} = \@preq_files;$test_entry{'testdir'} = 'BINDIR';push ( @TESTS_TO_RUN, \%test_entry );## Flag Auto Run processing required#$TESTS_TO_RUN = 1;$TESTS_TO_AUTORUN = 1 if ( $auto );}sub TestProg{my( $platforms, $prog, @elements ) = @_;Debug2( "TestProg($platforms, $prog, @elements)" );return if ( ! ActivePlatform($platforms) );Error ("TestProg: Program name not defined") unless ( $prog );Error ("Programs are not supported") unless ( defined $::exe );## Create a new Prog object, or retrieve any existing one#my $pProg = $TESTPROGS->Get($prog);$pProg = $TESTPROGS->NewAdd($prog)unless ( $pProg );#.. Parse all of the object, library and argument entriesDebug( "TestProg: $prog" );foreach (@elements){if ( /^[-]{1,2}([lL])(.*)/ ){#.. Target Library specified - add to library list.#Debug( "TestProg: lib -$1$2" );$pProg->addItem('LIBS', "-$1$2");next;}if ( /^--if(.*)/ ){#.. Library conditional - add to library list.#Debug( "TestProg: cond $_" );$pProg->addItem('LIBS', $_);next;}if ( /^-(.*)/ ){#.. Argument specified - add to argument list#Debug( "TestProg: arg $_" );$pProg->addItem('ARGS', $_);next;}if ( %::ScmToolsetProgSource ){## Toolset provides support for some file types# to be passed directly to the program builder#my $ext = StripFile($_);if ( exists ($::ScmToolsetProgSource{$ext}) ){my $full_path = MakeSrcResolve ( $_ );my $flag = $::ScmToolsetProgSource{$ext};Debug( "TestProg: src $_" );$pProg->addItem('ARGS', "$flag$full_path");next;}}if ( $::o ){#.. Object specified - add to object list.#my $obj = _LibObject( "", $_ );#.. Add to program object list.$pProg->addItem('OBJS', "\$(OBJDIR)/$obj");next;}## Don't know how to handle this type of argument#Error ("TestProg: Don't know how to handle: $_" );}}sub Prog{my( $platforms, $prog, @elements ) = @_;Debug2( "Prog($platforms, $prog, @elements)" );return if ( ! ActivePlatform($platforms) );Error ("Prog: Program name not defined") unless ( $prog );Error ("Programs are not supported") unless ( defined $::exe );## Create a new Prog object, or retrieve any existing one#my $pProg = $PROGS->Get($prog);$pProg = $PROGS->NewAdd($prog)unless ( $pProg );#.. Parse all of the object, library and argument entriesDebug( "Prog: $prog" );foreach (@elements){if ( /^[-]{1,2}([lL])(.*)/ ){#.. Target Library specified - add to library list.#Debug( "Prog: lib -$1$2" );$pProg->addItem('LIBS', "-$1$2");next;}if ( /^--if(.*)/ ){#.. Library conditional - add to library list.#Debug( "Prog: cond $_" );$pProg->addItem('LIBS', $_);next;}if ( /^-(.*)/ ){#.. Argument specified - add to argument list#Debug( "Prog: arg $_" );$pProg->addItem('ARGS', $_);next;}if ( %::ScmToolsetProgSource ){## Toolset provides support for some file types# to be passed directly to the program builder#my $ext = StripFile($_);if ( exists ($::ScmToolsetProgSource{$ext}) ){my $full_path = MakeSrcResolve ( $_ );my $flag = $::ScmToolsetProgSource{$ext};Debug( "Prog: src $_" );$pProg->addItem('ARGS', "$flag$full_path");next;}}if ( $::o ){#.. Object specified - add to object list.#my $obj = _LibObject( "", $_ );#.. Add to program object list.$pProg->addItem('OBJS', "\$(OBJDIR)/$obj");next;}## Don't know how to handle this type of argument#Error ("Prog: Don't know how to handle: $_" );}}#-------------------------------------------------------------------------------# Function : ProgAddExtra## Description : This (internal) function allows a toolset to list additional# binaries as a part of a program. This will ensure that the# binaries are generated in the 'make_prog' phase with the main# program.## The files are not listed for packaging, by this function## The function does not ensure that the files are not already# listed as a @PROG ( as @PROGS is not fully resolved at this point )## Inputs : $name - Tag name of program being built# Not used (yet)# $prog - Fully resolved path to a file## Returns : Nothing#sub ProgAddExtra{my ($name, $prog) = @_;Debug2( "ProgAddExtra($name: $prog)" );UniquePush(\@PROGS_EXTRA, $prog);}our %PROJECTS; # Project informationmy @PROJECTS_ORDER;#-------------------------------------------------------------------------------# Function : MakeProjectName## Description : Create a uniq project name## Inputs : srcPath## Returns : A unique project name#sub MakeProjectName{my ($srcPath) = @_;my $suffix = "";my $index = 1;my $proj = StripDir( $srcPath );while (exists $PROJECTS{$proj . $suffix}){$suffix = '.' . $index++;}return $proj . $suffix;}#-------------------------------------------------------------------------------# Function : MakeProject## Description : A nasty directive that is intended to build a Microsoft# project for WINCE, WIN32 and .NET builds.## There are many constraints:# Cannot be mixed with multi-platform builds# Some parameters are tool specific## Allow programs to be Installed as well as Packaged# The 'Progect' is treated' as a program and it doesn't work# to well if we Install libraries.## Only Reason to Install Programs is to allow the Cab Maker# to locate them.## Inputs : Platform - Active platform# Project - Project Name with extension# Options - Many options## Returns :#sub MakeProject{my( $platforms, $proj, @elements ) = @_;Debug2( "MakeProject($platforms, $proj, @elements)" );return if ( ! ActivePlatform($platforms) );## Sanity test#Error ("MakeProject: Project name not defined") unless ( $proj );## Take the project name and convert it into a full path# Need to create a uniq project name - allowing for multiple uses#my $project = MakeSrcResolve ( $proj );$proj = MakeProjectName($project);Error ("Project File Not found: $project") unless ( -f $project );my $basedir = StripFileExt( $project );## Collect user arguments# They are all processed within the toolset#my @tool_options;my $unit_tests;my $auto_tests;foreach ( @elements ){if ( m/^--Debug/ ) {$PROJECTS{$proj}{'Debug'} = 1;} elsif ( m/^--Prod/ ) {$PROJECTS{$proj}{'Prod'} = 1;} elsif ( m/^--(Package|Install)ProgDebug=(.*)/ ) {_PackageFromProject( $1, $proj, $basedir,'Prog', 'D', $2 );} elsif ( m/^--(Package|Install)Prog(Prod)*=(.*)/ ) {_PackageFromProject( $1, $proj, $basedir, 'Prog', 'P', $3 );} elsif ( m/^--(Package)LibDebug=(.*)/ ) {_PackageFromProject( $1, $proj, $basedir, 'Lib', 'D', $2 );} elsif ( m/^--(Package)Lib(Prod)*=(.*)/ ) {_PackageFromProject( $1, $proj, $basedir, 'Lib', 'P', $3 );} elsif ( m/^--(Package)SharedLibDebug=(.*)/ ) {_PackageFromProject( $1, $proj, $basedir, 'Lib', 'D', $2 );} elsif ( m/^--(Package)SharedLib(Prod)*=(.*)/ ) {_PackageFromProject( $1, $proj, $basedir, 'Lib', 'P', $3 );} elsif ( m/^--(Package)Hdr=(.*)/ ) {_PackageFromProject( $1, $proj, $basedir, 'Hdr', undef, $2 );} elsif ( m/^--(Package)File=(.*)/ ) {_PackageFromProject( $1, $proj, $basedir, 'File', undef, $2 );} elsif ( m/^--(Package)Tool(Prod)*=(.*)/ ) {_PackageFromProject( $1, $proj, $basedir, 'Tool', 'P', $3 );} elsif ( m/^--(Package)ToolDebug=(.*)/ ) {_PackageFromProject( $1, $proj, $basedir, 'Tool', 'D', $2 );} elsif ( m/^--(Package|Install)/ ) {Error("MakeProject. Unknown $1 option: $_");} elsif ( m/^--UnitTest/ ) {$unit_tests = 1;} elsif ( m/^--AutoTest/ ) {$auto_tests = 1;} else {push @tool_options, $_;}}## Validate some of the arguments# Ensure has not specified both --Prod and --Debug#Error ("Makeproject. Conflicting options --Debug and --Prod" )if ( $PROJECTS{$proj}{'Debug'} && $PROJECTS{$proj}{'Prod'} );# Ensure that global --OnlyProd/Debug don't prevent builds$PROJECTS{$proj}{'Debug'} = 1 if ($ScmBuildType eq 'D');$PROJECTS{$proj}{'Prod'} = 1 if ($ScmBuildType eq 'P');Error ("Makeproject. Global and Local options --Debug and --Prod prevent project being built" )if ( $PROJECTS{$proj}{'Debug'} && $PROJECTS{$proj}{'Prod'} );## Save the information#$PROJECTS{$proj}{'options'} = \@tool_options;$PROJECTS{$proj}{'name'} = $proj;$PROJECTS{$proj}{'project'} = $project;$PROJECTS{$proj}{'basedir'} = $basedir;$PROJECTS{$proj}{'unittest'} = $unit_tests if ( $unit_tests );$PROJECTS{$proj}{'autotest'} = $auto_tests if ( $auto_tests );UniquePush (\@PROJECTS_ORDER, $proj);}#-------------------------------------------------------------------------------# Function : _PackageFromProject## Description : Save Packaged data from the project## Inputs : $tgt - Install or Package# $proj - Name of the project# $base - Base directory of files# $etype - Type of Package (Progs, Libs, ... )# $type - Debug or Production or both# $items - Item to add. It may be comma seperated#my %PackageToData = ( 'Package' =>{ 'Hdr' => \%PACKAGE_HDRS,'Lib' => \%PACKAGE_LIBS,'Prog' => \%PACKAGE_PROGS,'File' => \%PACKAGE_FILES,'Tool' => \%PACKAGE_FILES,'_BASE' => 'PBase',},'Install' =>{ 'Hdr' => \%INSTALL_HDRS,'Lib' => \%INSTALL_LIBS,'Prog' => \%INSTALL_PROGS,'File' => undef,'Tool' => undef,'_BASE' => 'IBase',},);sub _PackageFromProject{my( $tgt, $proj, $base, $etype, $type, $items ) = @_;my $subdir = '';## Sanity test#$type = '' unless ( $type );Error ("INTERNAL. Bad packaging option: $tgt") unless ( exists $PackageToData{$tgt} );Error ("INTERNAL. Bad packaging option: $etype") unless ( exists $PackageToData{$tgt}{$etype} );Error ("Unsupported packaging combination: $tgt$etype$type=$items") unless ( defined $PackageToData{$tgt}{$etype} );## Determine the index into the 'PackageInfo' structure# This provides the symbolic name for the target package path# for Package or Install## The key '_BASE' is internal. Used only to provide this information#my $tbase = $PackageToData{$tgt}{'_BASE'};## Process options#foreach my $item ( split (/,/, $items ) ){next unless ( $item =~ m/^--/ );if ( $item =~ m/^--Subdir=(.*)/ ){$subdir = '/' . $1;$subdir =~ s~//~/~g;$subdir =~ s~/$~~g;}else{Warning( "MakeProject: Unknown packaging option ignored: $_" );}}## Process files#foreach my $item ( split (/,/, $items ) ){next if ( $item =~ m/^--/ );my $tdir = $PackageInfo{$etype}{$tbase} . $PackageInfo{$etype}{'Dir'} . $subdir ;my $fname = StripDir( $item );my $target = $tdir . '/' . $fname;$item = "$base/$item" if ( $base );## Do not use $(GBE_TYPE) in the target name# The existing package mechanism does not handle different# production and debug file naming mechanism, whereas the project# must. Convert $(GBE_TYPE) into P or D to ensure uniquness#$target =~ s~\$\(GBE_TYPE\)~$type~ if ($type);## Create a PACKAGE entry suitable for processing by the normal packaging# routines. This is complicated because the Projects do not adhere to# the JATS file name conventions#my %package_entry;$package_entry{'src'} = $item;$package_entry{'dir'} = $tdir;$package_entry{'set'} = 'ALL' if ($tgt eq 'Package');$package_entry{'type'} = $type if ($type);$PackageToData{$tgt}{$etype}->{$target} = {%package_entry};}}#-------------------------------------------------------------------------------# Function : MakeAnt## Description : A nasty directive to create JAR files via ANT# There are several limitations# This is closely related to the MakeProject directive### Inputs : Platform - Active platform# buildfile - Name of the build.xml file# Options - A few options# --Jar=file# Generated JAR file(s)# --GeneratedFile=file# Other generated files# Used to flag JNI that must# Occur early# --AutoTest=<name># Supports unitAutomated unit test# by calling build target <name># --UnitTest=<name># Supports unit test# by calling build target <name># --PackageBase# Provides path to base of all packages# --AllPackages# Provide paths to both LinkPkgArchive and BuildPkgArchive## Returns :#our %JAR_FILES;sub MakeAnt{my( $platforms, $proj, @elements ) = @_;Debug2( "MakeAnt($platforms, $proj, @elements)" );return if ( ! ActivePlatform($platforms) );## Sanity test#Error ("MakeAnt: build.xml name not defined") unless ( $proj );## Take the project name and convert it into a full path#my $project;$project = MakeSrcResolve ( $proj );$proj = MakeProjectName($project);Error ("Build File Not found: $project") unless ( -f $project );my $basedir = StripFileExt( $project );## Collect user arguments# They are all processed within the toolset#my @tool_options;my @generated;my $unit_tests;my $auto_tests;my $package_base;my $allPackages;foreach ( @elements ){if ( m/^--Debug/ ) {$PROJECTS{$proj}{'Debug'} = 1;} elsif ( m/^--Prod/ ) {$PROJECTS{$proj}{'Prod'} = 1;} elsif ( m/^--Jar=(.*)/ ) {my $tgt = $1;$tgt = "$basedir/$tgt" if ( $basedir );my $fn = StripDir( $1 );$JAR_FILES{$fn} = $tgt;GenerateSrcFile( 0, $tgt );} elsif ( m/^--GeneratedFile=(.*)/ ) {my $tgt = $1;$tgt = "$basedir/$tgt" if ( $basedir );push @generated, $tgt;GenerateSrcFile( 2, $tgt );} elsif ( m/^--UnitTest=(.*)/ ) {$unit_tests = $1} elsif ( m/^--AutoTest=(.*)/ ) {$auto_tests = $1} elsif ( m/^--PackageBase/ ) {$package_base = 1;} elsif ( m/^--AllPackages/i ) {$allPackages = 1;} elsif ( m/^--/ ) {Error("MakeAnt. Unknown option ignored: $_");} else {push @tool_options, $_;}}## Extend option arguments to include the base dir of packages# Create definitions of the form PACKAGE_<name>#for my $entry (getPackageList()){my $pkgType = $entry->getType();next if $pkgType eq 'interface' ;next unless ( ( $pkgType eq 'link') || $allPackages);my $dir = $entry->getBase(2);my $name = $entry->getName();unless ( $package_base ){$dir .= '/jar';next unless ( -d $dir );}push @tool_options, "-DPACKAGE_$name=\$(call myabspath,$dir)";}## Extend options to include the base dir of the created package# Allows careful use for direct packaging of artifacts#push @tool_options, '-DPACKAGEDIR=$(call myabspath,$(PKGDIR))';## Save the information#$PROJECTS{$proj}{'options'} = \@tool_options;$PROJECTS{$proj}{'generated'} = \@generated if ( @generated );$PROJECTS{$proj}{'name'} = $proj;$PROJECTS{$proj}{'project'} = $project;$PROJECTS{$proj}{'basedir'} = $basedir;$PROJECTS{$proj}{'type'} = 'ant';$PROJECTS{$proj}{'unittest'} = $unit_tests if ( $unit_tests );$PROJECTS{$proj}{'autotest'} = $auto_tests if ( $auto_tests );UniquePush (\@PROJECTS_ORDER, $proj);$TESTS_TO_AUTORUN = 1 if ( $auto_tests );$TESTS_TO_RUN = 1 if ( $unit_tests || $auto_tests );## Validate some of the arguments#Error ("MakeAnt. Conflicting options --Debug and --Prod" )if ( $PROJECTS{$proj}{'Debug'} && $PROJECTS{$proj}{'Prod'} );}################################################################################# Installation/Packaging util functions##-------------------------------------------------------------------------------# Function : __TargetDir## Description : Internal function to process common arguments for# the PackageXxx directives## Inputs : flags - Indicate how to handle this argument# base - Base directory for this type of package# argument - Argument to process# pdir - Reference to resultant directory# ptype - Reference to resultant type (P or D)(optional)## Returns : 0 - Agument not consumed# 1 - Argument consumed# 2 - Skip this directive#my $T_TYPE = 0x0001; # Postfix GBE_TYPEmy $T_PKG = 0x0002; # Special --Dir handlingmy $T_MACH = 0x0004; # Allow --Machine toomy $T_GBE = 0x0008; # Allow --Gbe toomy $T_FILE = 0x0010; # Suffix or prefix subdirsub __TargetDir{my( $flags, $base, $argument, $pdir, $ptype ) = @_;my $dir = "";my $consumed = 0;## Generate basic parts# Note Product will default to Platform#my $str_platform = '$(GBE_PLATFORM)';my $str_product = $ScmProduct ? '$(GBE_PRODUCT)' : '$(GBE_PLATFORM)';my $str_target = '$(GBE_TARGET)';my $str_common = '$(GBE_OS_COMMON)';my $str_common_avail = 0;$str_common_avail = 1 if ( exists( $::BUILDINFO{$ScmPlatform}{OS_COMMON} ));## Add requested suffix#if ($flags & $T_TYPE){$str_platform .= '$(GBE_TYPE)';$str_product .= '$(GBE_TYPE)';$str_target .= '$(GBE_TYPE)';$str_common .= '$(GBE_TYPE)';}## Process the argument#$_ = $argument;if ( /^--Debug/ ) { # In the Debug build onlyif ( $ptype ) {$$ptype = "D";$consumed = 1;}} elsif ( /^--Prod$/ || /^--Production$/ ) { # In the Production build onlyif ( $ptype ) {$$ptype = "P";$consumed = 1;}} elsif (/^--Prefix=(.*)/) { # Prefix with subdir$dir = "$base/$1";} elsif (/^--Subdir=(.*)/) { # same as 'prefix'$dir = "$base/$1";} elsif (/^--Platform$/) { # Platform installation$dir = "$base/$str_platform";} elsif (/^--Platform=(.*?),(.*)/) { # prefix and suffix with platform specific subdir$dir = "$base/$1/$str_platform/$2";} elsif (/^--Platform=(.*)/) { # prefix with platform specific subdirif ($flags & $T_FILE) {$dir = "$base/$1/$str_platform";} else {$dir = "$base/$str_platform/$1";}} elsif (/^--Product$/) { # Product installation$dir = "$base/$str_product";} elsif (/^--Product=(.*?),(.*)/) { # prefix and suffix with product specific subdir$dir = "$base/$1/$str_product/$2";} elsif (/^--Product=(.*)/) { # prefix with product specific subdirif ($flags & $T_FILE) {$dir = "$base/$1/$str_product";} else {$dir = "$base/$str_product/$1";}} elsif (/^--Target$/) { # Target installation$dir = "$base/$str_target";} elsif (/^--Target=(.*?),(.*)/) { # prefix and suffix with target specific subdir$dir = "$base/$1/$str_target/$2";} elsif (/^--Target=(.*)/) { # prefix with target specific subdirif ($flags & $T_FILE) {$dir = "$base/$1/$str_target";} else {$dir = "$base/$str_target/$1";}} elsif (/^--OsCommon/) {unless ( $str_common_avail ) {Warning("Packaging option --OsCommon not supported on this platform($ScmPlatform). Directive skipped");$consumed = 2;} elsif (/^--OsCommon$/) { # OS installation$dir = "$base/$str_common";} elsif (/^--OsCommon=(.*?),(.*)/) { # prefix and suffix with target specific subdir$dir = "$base/$1/$str_common/$2";} elsif (/^--OsCommon=(.*)/) { # prefix with target specific subdirif ($flags & $T_FILE) {$dir = "$base/$1/$str_common";} else {$dir = "$base/$str_common/$1";}}} elsif (/^--Derived=(.*?),(.*?),(.*)/) { # Derived target + prefix + subdir$dir = "$base/$2/$1_$str_platform/$3";} elsif (/^--Derived=(.*?),(.*)/) { # Derived target + subdirif ($flags & $T_FILE) {$dir = "$base/$2/$1_$str_platform";} else {$dir = "$base/$1_$str_platform/$2";}} elsif (/^--Derived=(.*)/) { # Derived target$dir = "$base/$1_$str_platform";} elsif ($flags & $T_MACH && /^--Machine(([=])(.*))?$/) { # Allow Machine and Machine=xxx specfic target## Special: Append machine type to user dir# Intended to create tools/bin/win32 and tools/bin/sparc directoriesmy $path = ( defined( $3) ) ? "/$3" : "";$dir = "$base$path/\$(GBE_HOSTMACH)";} elsif ($flags & $T_GBE && /^--Gbe(([=])(.*))?$/) { # Allow Gbe and Gbe=xxx specfic targetmy $path = ( defined( $3) ) ? "/$3" : "";$dir = "$base/gbe$path";} elsif (/^--Dir=(.*)/) { # prefix with target specific subdirError ('Packaging directive with --Dir option does not specify a directory.','Possible bad use of option of the form:--Dir=$xxx','Note: Use of package.pl and this construct is deprecated') unless ( $1 );my $udir = $1;## Remove leading ./# Check for leading ../## Remove any stupid path manipulation elements#if ($udir =~ s~^([./]*/)~~){Warning("Packaging directive with --Dir option contains path manipulation elements (removed)", "Option: $_");}if ($flags & $T_PKG) {$dir = __PkgDir( $udir );} else {$dir = $base . "/" . $udir;}}return ($consumed) if ($dir eq "");$dir =~ s~//~/~g;$dir =~ s~/$~~;$$pdir = $dir;return (1);}# __PkgDir ---# Convert --Dir Package directives, removing leading subdir if# matching the global $Pbase value.## Required as PKGDIR has the value 'GBE_ROOT/pkg/$Pbase'.# Required to maintain compatability with older (package.pl) constructs#..sub __PkgDir{my( $dir ) = @_;my $org = $dir;$dir =~ s~^\Q$::Pbase\E[/]?~~;Debug2( " PkgDir: converted \"$org\" to \"$dir\"" );$dir = "\$(PKGDIR)/$dir";return $dir;}# getMajorMinor ---# Just a little help to deal with major/minor stuff for shared libs -# given the name of the library as the argument, split out major and# minor parts and return the basename, i.e name without major and minor# and the pair of major and minor.#..sub getMajorMinor{my @bits = split ('\.', $_[0]);my $stop;my $major;my $minor;if ( $#bits > 2 ){$stop = $#bits - 2;$major = $bits[$#bits-1];$minor = $bits[$#bits];}elsif ($#bits > 1){$stop = $#bits-1;$major = $bits[$#bits];$minor=0;}else{$stop = $#bits; $major = 1; $minor = 0;}my $base = $bits[0];for ( my $i=1; $i <= $stop; $i++ ) {$base = join ('.', $base, $bits[$i]);}return ($base, $major, $minor);}################################################################################# Installation#sub InstallHdr{my( $platforms, @elements ) = @_;my( $base, $dir, $srcfile, $full, $strip, $package );my( $len, $name, $basename );Debug2( "InstallHdr($platforms, @elements)" );return if ( ! ActivePlatform($platforms) );Warning ("InstallHdr: Needs local directory specified in build.pl") unless ( $::ScmLocal );#.. Arguments#$base = $PackageInfo{'Hdr'}{'IBase'}; # Base of target$dir = $base . $PackageInfo{'Hdr'}{'Dir'}; # Installation path (default)$full = $strip = 0;foreach ( @elements ){# Standard targetsmy $rv = __TargetDir(0, $base, $_, \$dir);next if ( $rv == 1 );return if ( $rv == 2 );if (/^--Full/) { # using full (resolved) path$full = 1;} elsif (/^--Strip$/) { # Strip path from source files$strip = -1;} elsif (/^--Strip=(\d+)$/) { # Strip some f the path from source files$strip = $1;# Package} elsif (/^--Package$/ || /^--Package=(.*)/) {$package = 1;} elsif (/^--(.*)/) {Message( "InstallHdr: unknown option $_ -- ignored\n" );}}#.. Files#foreach ( @elements ){my %package_entry;if ( ! /^--(.*)/ ){$name = $_;$basename = StripDir( $name );if ( !($srcfile = $SRCS{ $basename }) ) {$srcfile = $name;}if ( $full ){my $subdir = StripFileExt($srcfile);$subdir = $1if ( $subdir =~ m~^$ProjectBase/(.*)~ );$dir .= '/' . $subdir;$dir =~ s~//~/~g;$dir =~ s~/./~/~g;$dir =~ s~/$~~g;$name = $basename;}$name = StripPath($name, $strip) if ($strip);Debug( "InstallHdr( $dir/$name, src: $srcfile, dest: $dir)" );$package_entry{'src'} = $srcfile;$package_entry{'dir'} = StripFileExt( "$dir/$name" );$INSTALL_HDRS{ "$dir/$name" } = {%package_entry};}}#.. Package#PackageHdr( @_ ) # auto packageif ( $package );}sub InstallLib{my( $platforms, @elements ) = @_;my( $base, $dir, $package );my( $lib, $strip );my $org_lib;Debug2( "InstallLib($platforms, @elements)" );return if ( ! ActivePlatform($platforms) );Warning ("InstallLib: Needs local directory specified in build.pl") unless ( $::ScmLocal );#.. Arguments#$base = $PackageInfo{'Lib'}{'IBase'}; # Base of target$dir = $base . $PackageInfo{'Lib'}{'Dir'}; # Installation path (default)foreach ( @elements ){# Standard targetsmy $rv = __TargetDir(0, $base, $_, \$dir);next if ( $rv == 1 );return if ( $rv == 2 );if (/^--Package$/ || /^--Package=(.*)/) {$package = 1;} elsif (/^--Strip$/) { # Strip path from source files$strip = -1;} elsif (/^--Strip=(\d+)$/) { # Strip some f the path from source files$strip = $1;} elsif (/^--(.*)/) {Message( "InstallLib: unknown option $_ -- ignored\n" );}}#.. Files#foreach ( @elements ){my %package_entry;if ( ! /^--(.*)/ ){$_ = StripPath($_, $strip) if ($strip);$org_lib = $_; # Original nameif ( $ScmTargetHost eq "Unix" ) {$lib = "lib$_"; # Prefix "lib" ....$lib =~ s/^liblib/lib/; # @LIBS already has lib added} else {$lib = $_;}if ( my $libp = $SHLIBS->Get($lib) ){Debug( "InstallLib( $dir/$lib\$(GBE_TYPE).$::so, " ."src: \$(LIBDIR)/$lib\$(GBE_TYPE).$::so, dest: $dir)" );## Create a "placekeeper" entry within $INSTALL_SHLIBS# The exact format of the name of the shared library is# toolset specific. Create an entry to allow the toolset# to extend the packaging information when the shared library# recipe is constructed.#my $ver = $libp->{ VERSION };my $name = "$dir/$lib.$ver.PlaceKeeper";$package_entry{'placekeeper'} = 1;$package_entry{'version'} = $ver;$package_entry{'lib'} = $lib;$package_entry{'dir'} = $dir;push @{$SHLIB_INS{$lib}}, $name;$INSTALL_SHLIBS{$name} = {%package_entry};}## Clean up the package_entry# Insert common items#%package_entry = ();$package_entry{'lib'} = $lib;$package_entry{'dir'} = $dir;if ( my $libfile = $SRCS{$org_lib} ){## Allow the user to package a sourced file as a library# But must be the un-massaged name of the file.#$package_entry{'dst'} = "$dir/$org_lib";$package_entry{'src'} = $libfile;}elsif ( $LIBS->Get($lib) ){## Install a library known to the makefile#my $libp = $LIBS->Get($lib);$package_entry{'dst'} = $dir . '/' . $libp->getFullName();$package_entry{'src'} = $libp->getPath();}elsif ( ! $SHLIBS->Get($lib) ){## Not a known shared lib# Not a known static lib# Not a 'sourced' file# Assume the a static library has magically appeared# in the standard LIB directory. May have been placed there# by a 'rule'#my $libp = $LIBS->New($lib);$package_entry{'dst'} = $dir . '/' . $libp->getFullName();$package_entry{'src'} = $libp->getPath();}## Add entry to various lists if required#PackageLib_AddEntry ('InstallLib', \%LIB_INS, \%INSTALL_LIBS, \%package_entry )if ( exists $package_entry{'dst'} );}}#.. Package#PackageLib( @_ ) # auto packageif ( $package );}sub InstallJar{my( $platforms, @elements ) = @_;my( $base, $dir, $package );my( $jar );Debug2( "InstallJar($platforms, @elements)" );return if ( ! ActivePlatform($platforms) );Warning ("InstallJar: Needs local directory specified in build.pl") unless ( $::ScmLocal );#.. Arguments#$base = $PackageInfo{'Jar'}{'IBase'}; # Base of target$dir = $base . $PackageInfo{'Jar'}{'Dir'}; # Installation path (default)foreach ( @elements ){# Standard targetsmy $rv = __TargetDir(0, $base, $_, \$dir);next if ( $rv == 1 );return if ( $rv == 2 );if (/^--Package$/ || /^--Package=(.*)/) {$package = 1;} elsif (/^--(.*)/) {Message( "InstallJar: unknown option $_ -- ignored\n" );}}#.. Files#foreach ( @elements ){my %package_entry;if ( ! /^--(.*)/ ){$jar = $_;my $src;my $dest;if ( $JAR_FILES{$jar} ){$src = $JAR_FILES{$jar};$dest = $jar;}else{$src = "\$(CLSDIR)/$jar\$(GBE_TYPE).jar";$dest = "$jar\$(GBE_TYPE).jar";}Debug( "InstallJar( $dir/$dest, " ."src: $src, dest: $dir)" );$package_entry{'src'} = $src;$package_entry{'dir'} = $dir;$INSTALL_CLSS{ "$dir/$dest" } = {%package_entry};}}#.. Package#PackageJar( @_ ) # auto packageif ( $package );}sub InstallProg{my( $platforms, @elements ) = @_;my( $base, $dir, $package );my( $prog );Debug2( "InstallProg($platforms, @elements)" );return if ( ! ActivePlatform($platforms) );Warning ("InstallProg: Needs local directory specified in build.pl") unless ( $::ScmLocal );#.. Arguments#$base = $PackageInfo{'Prog'}{'IBase'}; # Base of target$dir = $base . $PackageInfo{'Prog'}{'Dir'}; # Installation path (default)foreach ( @elements ){# Standard targetsmy $rv = __TargetDir($T_TYPE, $base, $_, \$dir);next if ( $rv == 1 );return if ( $rv == 2 );if (/^--Package$/ || /^--Package=(.*)/) {$package = 1;} elsif (/^--(.*)/) {Message( "InstallProg: unknown option $_ -- ignored\n" );}}#.. Files#foreach ( @elements ){my %package_entry;if ( ! /^--(.*)/ ){my $ext = "";$prog = $_;## If the named target is a program then append the correct# extension. Otherwise assume that the target is either a script# or a some other file - and don't append an extension#$ext = $::exeif ( $PROGS->Get($prog) );## A "file" that is specified with a "Src" directive may be# installed as though it were a program#my $progfile;$progfile = "\$(BINDIR)/$prog$ext"unless ( $progfile = $SRCS{$prog} );Debug( "InstallProg( $dir/$prog$ext, " ."src: $progfile, dest: $dir)" );push @{$PROG_INS{$prog}}, "$dir/$prog$ext";$package_entry{'src'} = $progfile;$package_entry{'dir'} = $dir;$INSTALL_PROGS{ "$dir/$prog$ext" } = {%package_entry};}}#.. Package#PackageProg( @_ ) # auto packageif ( $package );}#-------------------------------------------------------------------------------# Function : StripPath## Description : Internal function to strip bits from a pathname# Will never strip the filename, even if asked to strip too much## Inputs : $name - Name to process# $stripCount - Strip part# <0 - strip all paths# =0 - Do nothing# >0 - Strip count## Returns : Processed name#sub StripPath{my( $name, $stripCount) = @_;if ($stripCount){$name =~ s~\\~/~g;$name =~ s~//~/~g;my @items = split('/', $name);if ($stripCount > 0){my $len = scalar @items;my $remove = $stripCount;if ($stripCount >= $len ) {$remove = $len - 1;}splice @items, 0, $remove;$name = join('/', @items);}else{$name = pop @items;}}return $name;}################################################################################# Packaging#sub PackageDist{my( $name, @elements ) = @_;Debug2( "PackageDist($name, @elements)" );foreach ( @elements ){#.. Distribution sets#HashJoin( \%PACKAGE_DIST, $;, $name, "$_" );#.. Summary of distribution sets#$PACKAGE_SETS{ $_ }{'TAG'} = 1if ( ! exists $PACKAGE_SETS{ $_ }{'TAG'} );}}#-------------------------------------------------------------------------------# Function : PackageDir# InstallDir## Description : Directive to package an entire directory tree# Will package the contents of the directory without regard as to there content## Differs from PackageFile (... --DirTree ) in that the process is dynamic# It will support the packaging of files that are generated## NOT intended to support the JATS BIN and LIB structure# It knows nothing of these types of files## Inputs : platforms - Active platform list# Options: - Many from PackageFile# --DirTree=xxx Source Tree [Mandatory]# --Subdir=yyy Target [ Mandatory]#sub PackageDir {return if ( !$ScmPackage ); # Packaging enabled ?_PackageInstallDir('PackageDir', 'PBase', \@PACKAGE_DIRS, @_);}sub InstallDir {Warning ("InstallDir: Needs local directory specified in build.pl") unless ( $::ScmLocal );_PackageInstallDir('InstallDir', 'IBase', \@INSTALL_DIRS, @_);}sub _PackageInstallDir{my( $cmdName, $tbase, $dirRef, $platforms, @elements ) = @_;my( $base, $dir, $path, $type );my %data;Debug2( "$cmdName($platforms, @elements)" );return if ( ! ActivePlatform($platforms) );#.. Arguments#$base = $PackageInfo{'File'}{$tbase}; # Base of target$dir = $base . $PackageInfo{'File'}{'Dir'}; # Installation path (default)foreach ( @elements ){my $rv = __TargetDir($T_MACH|$T_GBE|$T_FILE, $base, $_, \$dir, \$type);next if ( $rv == 1 );return if ( $rv == 2 );if (/^--Executable$/) { # Mark the file as executable$data{exefile} = "X";} elsif (/^--PreserveSymlink/i) { # Preserve symlink to local filedelete $data{noPreserveSymlink};} elsif (/^--NoPreserveSymlink/i) { # Preserve symlink to local file$data{noPreserveSymlink} = 1;} elsif ( /^--DirTree=(.*)/ ) {Error("DirTree. Multiple directories not allowed.") if ( $data{dirTree} );$data{dirTree} = $1;} elsif ( /^--FilterOut=(.*)/ ) {push @{$data{exclude}}, $1;} elsif ( /^--FilterIn=(.*)/ ) {push @{$data{include}}, $1;} elsif ( /^--FilterOutRe=(.*)/ ) {push @{$data{excludeRe}}, $1;} elsif ( /^--FilterInRe=(.*)/ ) {push @{$data{includeRe}}, $1;} elsif ( /^--StripDir/ ) {$data{strip_base} = 1;} elsif ( m/^--Recurse/ ) {delete $data{noRecurse};} elsif ( m/^--NoRecurse/ ) {$data{noRecurse} = 1;} elsif (/^--(.*)/) {Message( "$cmdName: unknown option $_ -- ignored\n" );}}Error("DirTree. No path specified") unless ( defined($data{dirTree}) && $data{dirTree} ne "" );Debug2( "$cmdName. Raw DirTree: $data{dirTree}" );# Prevent the user from escaping from the current directoryError("$cmdName. Absolute paths are not allowed","Directory: $data{dirTree}") if ( $data{dirTree} =~ m~^/~ || $data{dirTree} =~ m~^.\:~ );## Convert the relative path to one that is truely relative to the current# directory. This may occur when the user uses $ProjectBase#my $abs_dir_tree = AbsPath($data{dirTree});$data{dirTree} = RelPath($abs_dir_tree);## Ensure that the user is not trying to escape the package# Don't allow the user to attempt to package the entire package either## Calculate the relative path from $ProjectBase to the target directory# It must not be above the $ProjectBase#if ( $data{dirTree} =~ m~^\.\.~){my $dirFromBase = RelPath($abs_dir_tree, AbsPath($ProjectBase));Error("$cmdName. DirTree cannot extend outside current package.","Directory: $dirFromBase") if ( $dirFromBase =~ m~\.\.~ );Error("$cmdName. DirTree cannot package entire package.","Directory: $dirFromBase") if ( $dirFromBase eq '.' );}Debug( "$cmdName( $data{dirTree}");$data{dir} = $dir;$data{type} = $type if defined $type;#DebugDumpData("$cmdName", \%data);push @{$dirRef}, \%data;}#-------------------------------------------------------------------------------# Function : PackageFile## Description : Directive to package files# Not to be used to package libraries, executables, headers# as this should be done by specialised directives## Use to package other files# Can package an entire tree (ugly)## Inputs :##sub PackageFile{my( $platforms, @elements ) = @_;my( $base, $dir, $full, $path, $dist, $strip, $exefile, $type );my( $name, $basename, $len, $srcfile );my( $dir_tree, @dir_tree_exclude, @dir_tree_include, $strip_base, $strip_dots );my $recurse = 1;my $preserveSymlink = 0;Debug2( "PackageFile($platforms, @elements)" );return if ( !$ScmPackage ); # Packaging enabled ?return if ( ! ActivePlatform($platforms) );#.. Arguments#$dist = "ALL"; # Default set (ALL)$base = $PackageInfo{'File'}{'PBase'}; # Base of target$dir = $base . $PackageInfo{'File'}{'Dir'}; # Installation path (default)$full = 0;$strip = 0;$strip_base = 0;$strip_dots = 0;$exefile = 0;foreach ( @elements ){my $rv = __TargetDir($T_PKG|$T_MACH|$T_GBE|$T_FILE, $base, $_, \$dir, \$type);next if ( $rv == 1 );return if ( $rv == 2 );if (/^--Full/) { # Using full (resolved) path$full = 1;} elsif (/^--Set=(.*)/) { # Distribution set$dist = "$1";} elsif (/^--Package$/) { # Package .. call by InstallFile} elsif (/^--Package=(.*)/) {$dist = "$1";} elsif (/^--Strip$/) { # Strip path from source files$strip = -1;} elsif (/^--Strip=(\d+)$/) { # Strip path from source files$strip = $1;} elsif (/^--Executable$/) { # Mark the file as executable$exefile = "X";} elsif (/^--PreserveSymlink/i) { # Preserve symlink to local file$preserveSymlink = 1;} elsif ( /^--DirTree=(.*)/ ) {Error("DirTree. Multiple directories not allowed.") if ( $dir_tree );$dir_tree = $1;Error("DirTree. No path specified") unless ( defined($dir_tree) && $dir_tree ne "" );# Prevent the user from escaping from the current directoryError("DirTree. Absolute paths are not allowed","Directory: $dir_tree") if ( $dir_tree =~ m~^/~ || $dir_tree =~ m~^.\:~ );## Convert the relative path to one that is truely relative to the current# directory. This may occur when the user uses $ProjectBase#my $abs_dir_tree = AbsPath($dir_tree);$dir_tree = RelPath($abs_dir_tree);## Ensure that the user is not trying to escape the package# Don't allow the user to attempt to package the entire package either## Calculate the relative path from $ProjectBase to the target directory# It must not be above the $ProjectBase#if ( $dir_tree =~ m~^\.\.~){my $dirFromBase = RelPath($abs_dir_tree, AbsPath($ProjectBase));Error("DirTree cannot extend outside current package.","Directory: $dirFromBase") if ( $dirFromBase =~ m~\.\.~ );Error("DirTree cannot package entire package.","Directory: $dirFromBase") if ( $dirFromBase eq '.' );}Debug2( "PackageFile. DirTree: $dir_tree" );Error("DirTree. Directory not found","Directory: $dir_tree") unless ( -d $dir_tree );# If packaging a parent directory then force dot_stripping of the base directory# strip_base will have precedence if both are activeif ( $dir_tree =~ m~\.\.~ ){$dir_tree =~ m~(\.\./)+~;$strip_dots = length($1);}} elsif ( /^--FilterOut=(.*)/ ) {push @dir_tree_exclude, $1;} elsif ( /^--FilterIn=(.*)/ ) {push @dir_tree_include, $1;} elsif ( /^--StripDir/ ) {$strip_base = 1;} elsif ( m/^--Recurse/ ) {$recurse = 1;} elsif ( m/^--NoRecurse/ ) {$recurse = 0;} elsif (/^--(.*)/) {Message( "PackageFile: unknown option $_ -- ignored\n" );}}#.. DirTree expansion# Note: Uses REs, not simple globs# Use JatsLocateFiles to do the hard workif ( $dir_tree ){my $search = JatsLocateFiles->new('FullPath' );$search->recurse($recurse);$search->filter_in_re ( $_ ) foreach ( @dir_tree_include );$search->filter_out_re( $_ ) foreach ( @dir_tree_exclude );$search->filter_out_re( '/\.svn/' );$search->filter_out_re( '/\.git/' );@elements = $search->search ( $dir_tree );if ($strip_base){$strip_base = length( $dir_tree ) if ( $strip_base );} elsif ($strip_dots) {$strip_base = $strip_dots;}} else {$strip_base = 0;}#.. Files#foreach ( @elements ){my %package_entry;$name = $_;my $symlink;## Trap special files# DPACKAGE - but only if we have a DPackageLibrary directive# in the same makefile.#if ( m~^DPACKAGE$~ && $DPackageDirective ) {$name = 'DPACKAGE.' . $::GBE_MACHTYPE;}if ( ! /^--(.*)/ ){$basename = StripDir( $name );if ( !($srcfile = $SRCS{ $basename }) ) {$srcfile = $name;}if ( $full ){my $subdir = StripFileExt($srcfile);$subdir = $1if ( $subdir =~ m~^$ProjectBase/(.*)~ );$dir .= '/' . $subdir;$dir =~ s~//~/~g;$dir =~ s~/./~/~g;$dir =~ s~/$~~g;$name = $basename;}$name = StripPath($name, $strip) if ($strip);if ( $strip_base ){$name = substr $name, $strip_base;$name =~ s~^/~~;}$dir =~ s~//~/~g;$dir =~ s~/$~~;## Preserve Symlink#if ($preserveSymlink && -l $srcfile){$symlink = 1;}## Sanity test the source filename# User may have misused an option#if ( !$dir_tree && ( ( $srcfile =~ m/=/ ) || ( $srcfile =~ m/^-/ ) || ( $srcfile =~ m~/-~ )) ){Warning ("PackageFile: Suspect source filename: $srcfile");}Debug( "PackageFile( $dir/$name, " ."src: $srcfile, dest: $dir, dist: $dist, exe: $exefile )" );$package_entry{'src'} = $srcfile;$package_entry{'dir'} = StripFileExt( "$dir/$name" );$package_entry{'set'} = $dist;$package_entry{'exe'} = $exefile if $exefile;$package_entry{'type'} = $type if ( $type );$package_entry{'symlink'} = 1 if ( $symlink );$PACKAGE_FILES{ "$dir/$name" } = {%package_entry};}}}sub PackageHdr{my( $platforms, @elements ) = @_;my( $base, $dir, $full, $path, $dist, $strip );my( $name, $basename, $len, $srcfile );Debug2( "PackageHdr($platforms, @elements)" );return if ( !$ScmPackage ); # Packaging enabled ?return if ( ! ActivePlatform($platforms) );#.. Arguments#$dist = "ALL"; # Default set (ALL)$base = $PackageInfo{'Hdr'}{'PBase'}; # Base of target$dir = $base . $PackageInfo{'Hdr'}{'Dir'}; # Installation path (default)$full = 0;$strip = 0;foreach ( @elements ){my $rv = __TargetDir($T_PKG, $base, $_, \$dir);next if ( $rv == 1 );return if ( $rv == 2 );if (/^--Full/) { # Using full (resolved) path$full = 1;} elsif (/^--Set=(.*)/) { # Distribution set$dist = "$1";} elsif (/^--Package$/) { # Package .. call by InstallHdr} elsif (/^--Package=(.*)/) {$dist = "$1";} elsif (/^--Strip$/) { # Strip path from source files$strip = -1;} elsif (/^--Strip=(\d+)$/) { # Strip some f the path from source files$strip = $1;} elsif (/^--(.*)/) {Message( "PackageHdr: unknown option $_ -- ignored\n" );}}#.. Files#foreach ( @elements ){my %package_entry;if ( ! /^--(.*)/ ){$name = $_;$basename = StripDir( $name );if ( !($srcfile = $SRCS{ $basename }) ) {$srcfile = $name;}if ( $full ){my $subdir = StripFileExt($srcfile);$subdir = $1if ( $subdir =~ m~^$ProjectBase/(.*)~ );$dir .= '/' . $subdir;$dir =~ s~//~/~g;$dir =~ s~/./~/~g;$dir =~ s~/$~~g;$name = $basename;}$name = StripPath($name, $strip) if ($strip);Debug( "PackageHdr( $dir/$name, " ."src: $srcfile, dest: $dir, dist: $dist )" );$package_entry{'src'} = $srcfile;$package_entry{'dir'} = StripFileExt( "$dir/$name" );$package_entry{'set'} = $dist;$PACKAGE_HDRS{ "$dir/$name" } = {%package_entry};}}}sub PackageLib{my( $platforms, @elements ) = @_;my( $base, $dir, $dist, $type );my( $lib, $org_lib, %extras, $strip );Debug2( "PackageLib($platforms, @elements)" );return if ( !$ScmPackage ); # Packaging enabled ?return if ( ! ActivePlatform($platforms) );#.. Arguments#$dist = "ALL"; # Default set (ALL)$base = $PackageInfo{'Lib'}{'PBase'}; # Base of target$dir = $base . $PackageInfo{'Lib'}{'Dir'}; # Installation path (default)$type = "";foreach ( @elements ){# Standard targetsmy $rv = __TargetDir($T_PKG, $base, $_, \$dir, \$type);next if ( $rv == 1 );return if ( $rv == 2 );if (/^--Set=(.*)/) { # Distribution set(s)$dist = "$1";} elsif (/^--Package$/) { # Package .. call by PackageLib} elsif (/^--Package=(.*)/) {$dist = "$1";} elsif (/^--Extras=(.*)/) { # Extras=[none, .. ,all]foreach my $elem ( split( ',', $1 ) ){Error ("PackageLib: Unknown Extras mode: $elem")unless ( grep m/$elem/, qw(none stub map lint debug all) );$extras{$elem} = 1;}%extras = () if ( $extras{'all'} );} elsif (/^--Strip$/) { # Strip path from source files$strip = -1;} elsif (/^--Strip=(\d+)$/) { # Strip some f the path from source files$strip = $1;} elsif (/^--(.*)/) {Message( "PackageLib: unknown option $_ -- ignored\n" );}}#.. Files#foreach ( @elements ){my %package_entry;if ( ! /^--(.*)/ ){$_ = StripPath($_, $strip) if ($strip);$org_lib = $_; # Original nameif ( $ScmTargetHost eq "Unix" ) {$lib = "lib$_"; # Prefix "lib" ....$lib =~ s/^liblib/lib/; # @LIBS already has lib added} else {$lib = $_;}if ( my $libp = $SHLIBS->Get($lib) ){Debug( "PackageLib( $dir/$lib\$(GBE_TYPE).$::so, " ."src: \$(LIBDIR)/$lib\$(GBE_TYPE).$::so, dest: $dir, dist: $dist, type: $type )" );## Create a "placekeeper" entry within $PACKAGE_SHLIBS# The exact format of the name of the shared library is# toolset specific. Create an entry to allow the toolset# to extend the packaging information when the shared library# recipe is constructed.##my $ver = $libp->{ VERSION };my $name = "$dir/$lib.$ver.PlaceKeeper";$package_entry{'placekeeper'} = 1;$package_entry{'version'} = $ver;$package_entry{'lib'} = $lib;$package_entry{'dir'} = $dir;$package_entry{'set'} = $dist;$package_entry{'type'} = $type if ( $type );$package_entry{'extras'} = {%extras} if ( scalar %extras );push @{$SHLIB_PKG{$lib}}, $name;$PACKAGE_SHLIBS{$name} = {%package_entry};}## Clean up the package_entry# Insert common items#%package_entry = ();$package_entry{'lib'} = $lib;$package_entry{'dir'} = $dir;$package_entry{'set'} = $dist;$package_entry{'extras'} = {%extras} if ( scalar %extras );$package_entry{'type'} = $type if ( $type );if ( my $libfile = $SRCS{$org_lib} ){## Allow the user to package a sourced file as a library# But must be the un-massaged name of the file.#$package_entry{'dst'} = "$dir/$org_lib";$package_entry{'src'} = $libfile;}elsif ( $LIBS->Get($lib) ){## Package up a library known to the makefile#my $libp = $LIBS->Get($lib);$package_entry{'dst'} = $dir . '/' . $libp->getFullName();$package_entry{'src'} = $libp->getPath();}elsif ( ! $SHLIBS->Get($lib) ){## Not a known shared lib# Not a known static lib# Not a 'sourced' file# Assume the a static library has magically appeared# in the standard LIB directory. May have been placed there# by a 'rule'#my $libp = $LIBS->New($lib);$package_entry{'dst'} = $dir . '/' . $libp->getFullName();$package_entry{'src'} = $libp->getPath();}## Add entry to various lists if required#PackageLib_AddEntry ('PackageLib', \%LIB_PKG, \%PACKAGE_LIBS, \%package_entry )if ( exists $package_entry{'dst'} );}}}#-------------------------------------------------------------------------------# Function : PackageLib_AddEntry## Description : Helper function to add a package entry# to the lists## Inputs : $directive - Directive name# $pList - Ref to array list to maintain# $pHash - Ref to hash to maintain# $pData - Packaging Data# Must Take a copy.## Returns :#sub PackageLib_AddEntry{my ($directive, $pList, $pHash, $pData) = @_;my $lib = delete $pData->{'lib'};my $dst = delete $pData->{'dst'};Error ("INTERNAL PackageLib_AddEntry: lib or dst not defined")unless ( $lib && $dst );Debug( "$directive( ",$dst,", src: " ,$pData->{'src'},", dest: ",$pData->{'dir'},", dist: ",$pData->{'set'},", type: ",$pData->{'type'} || ''," )" );push @{$pList->{$lib }}, $dst;$pHash->{$dst } = {%$pData};}sub PackageProg{my( $platforms, @elements ) = @_;my( $base, $dir, $dist, $type );my( $prog, %extras, $strip );Debug2( "PackageProg($platforms, @elements)" );return if ( !$ScmPackage ); # Packaging enabled ?return if ( ! ActivePlatform($platforms) );#.. Arguments#$dist = "ALL"; # Default set (ALL)$base = $PackageInfo{'Prog'}{'PBase'}; # Base of target$dir = $base . $PackageInfo{'Prog'}{'Dir'}; # Installation path (default)$type = "";foreach ( @elements ){# Standard targetsmy $rv = __TargetDir($T_PKG|$T_TYPE, $base, $_, \$dir, \$type);next if ( $rv == 1 );return if ( $rv == 2 );if (/^--Set=(.*)/) { # Distribution set(s)$dist = "$1";} elsif (/^--Package$/) { # Package .. call by PackageLib} elsif (/^--Package=(.*)/) {$dist = "$1";} elsif (/^--Tool(([=])(.*))?$/) { # Allow Tool and Tool=xxx specfic targetmy $path = ( defined( $3) ) ? "/$3" : "";$dir = "\$(PKGDIR)$path/\$(GBE_HOSTMACH)";} elsif (/^--Extras=(.*)/) { # Extras=[none, .. ,all]foreach my $elem ( split( ',', $1 ) ){Error ("PackageLib: Unknown Extras mode: $elem")unless ( grep m/$elem/, qw(none stub map lint debug all) );$extras{$elem} = 1;}%extras = () if ( $extras{'all'} );} elsif (/^--Strip$/) { # Strip path from source files$strip = -1;} elsif (/^--Strip=(\d+)$/) { # Strip some f the path from source files$strip = $1;} elsif (/^--(.*)/) {Message( "PackageProg: unknown option $_ -- ignored\n" );}}#.. Files#foreach ( @elements ){my %package_entry;if ( m~descpkg~ ) {PackageFile($platforms, @elements);} elsif ( ! /^--(.*)/ ) {$_ = StripPath($_, $strip) if ($strip);my $ext = "";$prog = $_;## If the named target is a program then append the correct# extension. Otherwise assume that the target is either a script# or a some other file - and don't append an extension## A program may not have any object files, only libraries#$ext = $::exeif ( $PROGS->Get($prog) );## A "file" that is specified with a "Src" directive may be# installed as though it were a program#my $progfile;if ( $progfile = $SRCS{$prog} ){$progfile = $progfile;$prog = $prog;}else{$progfile = "\$(BINDIR)/$prog$ext";}Debug( "PackageProg( $dir/$prog$ext, " ."src: $progfile, dest: $dir, dist: $dist, type: $type )" );my $target = "$dir/$prog$ext";push @{$PROG_PKG{$prog}}, $target;$package_entry{'src'} = $progfile;$package_entry{'dir'} = $dir;$package_entry{'set'} = $dist;$package_entry{'extras'}= {%extras} if ( scalar %extras );$package_entry{'type'} = $type if ( $type );$PACKAGE_PROGS{$target} = {%package_entry};}}}sub PackageJar{my( $platforms, @elements ) = @_;my( $base, $dir, $dist, $type );my( $jar );Debug2( "PackageJar($platforms, @elements)" );return if ( !$ScmPackage ); # Packaging enabled ?return if ( ! ActivePlatform($platforms) );#.. Arguments#$dist = "ALL"; # Default set (ALL)$base = $PackageInfo{'Jar'}{'PBase'}; # Base of target$dir = $base . $PackageInfo{'Jar'}{'Dir'}; # Installation path (default)$type = "";foreach ( @elements ){# Standard targetsmy $rv = __TargetDir($T_PKG, $base, $_, \$dir, \$type);next if ( $rv == 1 );return if ( $rv == 2 );if (/^--Set=(.*)/) { # Distribution set(s)$dist = "$1";} elsif (/^--Package$/) { # Package .. call by InstallJar} elsif (/^--Package=(.*)/) {$dist = "$1";} elsif (/^--(.*)/) {Message( "PackageJar: unknown option $_ -- ignored\n" );}}#.. Files#foreach ( @elements ){my %package_entry;if ( ! /^--(.*)/ ){$jar = $_;my $src;my $dest;if ( $JAR_FILES{$jar} ){$src = $JAR_FILES{$jar};$dest = $jar;}else{$src = "\$(CLSDIR)/$jar\$(GBE_TYPE).jar";$dest = "$jar\$(GBE_TYPE).jar";}Debug( "PackageJar( $dir/$dest, " ."src: $src, dest: $dir, dist: $dist, type: $type )" );$package_entry{'src'} = $src;;$package_entry{'dir'} = $dir;$package_entry{'set'} = $dist;$package_entry{'type'} = $type if ( $type );$PACKAGE_CLSS{ "$dir/$dest" } = {%package_entry};}}}#-------------------------------------------------------------------------------# Function : PackageProgAddFiles - Add files to a PackageProg# PackageLibAddFiles - Add files to a PackageLib# PackageShlibAddFiles - Add files to a PackageLib (shared lib)# PackageShlibAddLibFiles - Add files to a PackageLib (shared lib)# Add static library files## Description : Add files to a Program package or installation# For use by Tool sets to allow additional files to be# packaged with a program.## The files are only added if the named program is being# packaged and/or installed.### Inputs : prog - program identifier# file - A file to be add# args - Additional packageing arguments## Returns : Nothing#sub PackageProgAddFiles{Debug("PackageProgAddFiles");PackageAddFiles ( \%PACKAGE_PROGS, \%PACKAGE_PROGS, \%PROG_PKG, @_);PackageAddFiles ( \%INSTALL_PROGS, \%INSTALL_PROGS, \%PROG_INS, @_);}sub PackageLibAddFiles{Debug("PackageLibAddFiles");PackageAddFiles ( \%PACKAGE_LIBS, \%PACKAGE_LIBS, \%LIB_PKG, @_ );PackageAddFiles ( \%INSTALL_LIBS, \%INSTALL_LIBS, \%LIB_INS, @_ );}sub PackageShlibAddFiles{my ($prog, $file, @args) = @_;Debug("PackageShlibAddFiles");PackageAddFiles ( \%INSTALL_SHLIBS, \%INSTALL_SHLIBS, \%SHLIB_INS, @_ );PackageAddFiles ( \%PACKAGE_SHLIBS, \%PACKAGE_SHLIBS, \%SHLIB_PKG, @_ );## These files become the target of the "make_install_shlib" operation unless:# Conditionally packaged files are not always created# RemoveOnly files are not always generated#my $no_add;foreach ( @args ){if ( m/^defined=/ or m/^RemoveOnly=/ or /NoTarget=/ ){$no_add = 1;last;}}push (@SHLIB_TARGETS, $file ) unless $no_add;}sub PackageShlibAddLibFiles{Debug("PackageShlibAddLibFiles");PackageAddFiles ( \%PACKAGE_SHLIBS, \%PACKAGE_LIBS, \%SHLIB_PKG, @_ , 'Class=lib');PackageAddFiles ( \%INSTALL_SHLIBS, \%INSTALL_LIBS, \%SHLIB_INS, @_ , 'Class=lib');}#-------------------------------------------------------------------------------# Function : PackageAddFiles## Description : Internal function to add files to the data structures that# describe a package or installation## Use this function to package or install additional files with# the Progs and Libs## ie: Add a LIB file to be packaged with a Shared Library# ie: Add a MAP file to be packaged with a program## Inputs : ref_spkg - Reference to the hash that contains the package data# ref_dpkg - Reference to the target package/install hash# Normally the same as ref_dpkg, but does allow# a static library to be added to a dynamic library# package.# ref_list - Reference to a hash that may contain package keys to process# prog - Key for index to above# file - A file to be added# args - Additional packaging arguments## Returns :#sub PackageAddFiles{my ($ref_spkg, $ref_dpkg, $ref_list, $prog, $file, @args ) = @_;## Process entry# The files may need to be added to multiple packages#Debug("PackageAddFiles: $file");return unless ( $ref_list->{$prog} );## Parse arguments and extract the "Class=xxx" argument. This may be used# to limit the extra files piggybacked with the base file# All files without a class will be treated as base files#my $class;foreach ( @args ){next unless ( m~^Class=(.*)$~ );$class = $1 unless ( $1 eq 'none' );}Debug("PackageAddFiles: Class: ", $class || 'Default=None');foreach my $entry_key ( @{$ref_list->{$prog}} ){Debug("PackageAddFiles: Entry found: $entry_key");## Copy of the template entry#my %package_entry = %{$ref_spkg->{$entry_key}};Error ("INTERNAL: Expected entry in PACKAGE_ hash not found: $entry_key" )unless ( %package_entry );## Do not add the file if the user has limited the extra files added# to the packaging list and the current file is not in the class list#if ( $class && $package_entry{'extras'} ){next unless ( $package_entry{'extras'}{$class} );}## Create new entries for the file#$package_entry{'src'} = $file;foreach ( @args ){m~^(.*)=(.*)$~;$package_entry{$1} = $2;}## Clean out useless fields# Must remove the placekeeper marker to allow the entry to be visible#delete $package_entry{'placekeeper'};delete $package_entry{'version'};delete $package_entry{'lib'};# delete $package_entry{'extras'}; # Keep thesedelete $package_entry{'Class'};## Add the entry## Under some conditions is it possible to attempt to add the same named# file. This will result in a circular dependancy in the makefile## The condition is when merged libaries with PDBs (WINCE+WIN32) are merged# and the source for the merge is the "local directory.##my $dst = $package_entry{'dir'} ;( my $dfile = $file) =~ s~.*/~~;Debug( " added $dst/$dfile = $file" );$ref_dpkg->{"$dst/$dfile"} = {%package_entry}unless ( "$dst/$dfile" eq "$file" );}}#-------------------------------------------------------------------------------# Function : PackageProgRemoveFiles## Description : Flag a Packaged program to be not packaged# This mechanism is used to remove a program from packageing# under conditions where the toolset has generated a different# program.## The entry is flagged as a placeholder## Inputs : prog - Program to process## Returns : Nothing#sub PackageProgRemoveFiles{my ($prog) = @_;Verbose ("PackageProgRemoveFiles: $prog" );return unless (exists($PROG_PKG{$prog}));## Must lookup the TAG to locate the required entry#my $tag = $PROG_PKG{$prog};foreach my $entry ( @$tag ){Verbose("Do not package: $entry");if ( exists $PACKAGE_PROGS{$entry} ){$PACKAGE_PROGS{$entry}{placekeeper} = 'ProgRemoved';}}}#-------------------------------------------------------------------------------# Function : DPackageLibrary## Description : Collect information to allow the generation of a DPACKAGE# file. This directive allows the generation of "Library"# directives within the final DPACKAGE## This directive does generate the DPACKAGE file.## Inputs : platform - This does not need to be an active platform# it is simply passed to the DPACKAGE builder## using - The "using" target## ... - Arguments for the Library directive## Returns :#sub DPackageLibrary{JatsDPackage::DPackageAdd ( @_ );$DPackageDirective = 1;}#-------------------------------------------------------------------------------# Function : SetProjectBase## Description : Allows the user to modify the build's concept of the Base# of the build. By default the base is the same directory as# the build.pl file, but in some contorted environments it# is a great deal simpler to specify a differnt base.## The use may use the variable $ProjectBase as a path# specifier to locate files and directories## Both absolute and relative paths are supported# If the initial value of $ProjectBase is relative then# it will be maintained as a relative path.## Inputs : elements path to base# These may be:# --Up=xx# name## Returns : Nothing### Allow the user to modify the project base variable#sub SetProjectBase{my $rip = 0;my $path = "";my $is_relative;Debug("ProjectBase Initial: $ProjectBase, @_");## Ensure that the ProjectBase is in a "nice" form# 1) No /./ bits# 2) No trailing /# 3) Not equal to .# 4) No training /.# 5) No //#$ProjectBase =~ s~/\./~/~g;$ProjectBase =~ s~/$~~g;$ProjectBase =~ s~^\.$~~g;$ProjectBase =~ s~/\.$~~g;$ProjectBase =~ s~//$~/~g;## ProjectBase may be absolute or relative# Determine this before we mess with it#$is_relative = ($ProjectBase !~ m~^/~);## Process each argument#foreach ( @_ ){if ( /^--Up=([0-9]*)/ ) {$rip = $1;} elsif ( /^--/ ) {Warning( "SetProjectBase - unknown option \"$_\" - ignored" );} else {$path = $_;}}## Process the UP requests# If the tail directory is a ".." then up is done by adding another ".."# If the tail directory is not a "..", then up is done by removing it## If we go past the start of the path then simply add ".."#while ( $rip-- > 0 ){Debug2("ProjectBase: $ProjectBase, Up: $rip, IsRel: $is_relative");## If ending in a /.. or is exactly equal to ..# Then its a dot-dot and the way to go UP is to append another ..#if ( $ProjectBase =~ m~(/\.\.$)|(^\.\.$)~ ){$ProjectBase .= '/..';}else{## Not a dot-dot ending# Attempt to remove the last directory of the form# /xxxxx# Where the leading / is optional# Note: Must have at least one character in the dirname# This prevents leading / from matching - which is needed#unless ($ProjectBase =~ s~/?[^/]+$~~){## Removal failed# If a relative path then we can keep on going up,# otherwise we are dead.#Error ("ProjectBase outside project") unless ($is_relative);$ProjectBase = '..';}## Ensure that the leading / in an absolute path is not deleted#$ProjectBase = '/'unless ( $is_relative || $ProjectBase );}}## Append the user path#$ProjectBase .= '/' . $path if ( $path );$ProjectBase = '.' unless ( $ProjectBase );Debug("ProjectBase set to : $ProjectBase");## Once upon a time I tried to convert paths that contained spaces into# short (mangled) names. This was not sucessful because:# 1) Clearcase dynamic views do not support name mangling# 2) Samba file system does not appear to support name mangling## Spaces in paths are not good for MAKE# Now I simple generate a message#Warning( "ProjectBase contains a space: $ProjectBase")if ( $ProjectBase =~ m/ / );## Sanity check# Absolute paths can be checked easily# Checking of relative paths does not appear to work# When I tested it chdir, opendir and stat would limit themselves# and drop into the root directory ( under windows )## Solution: Check the path does not extend beyond the file tree#my $distance = 1;my $tpath = $ProjectBase;if ( $is_relative && $tpath ne '.' ){## Build up the complete pathname by merging it with the# current directory. Then clean it up.#$tpath = $::Cwd . '/' . $ProjectBase;## Scan the list of diretories and count the distance from the root# This should not be greater than zero for sanity# Note: Get an empty elemement from the split due to# the leading / of the ABS path#$distance = 0;foreach ( split ('/', $tpath) ){if ( m~\.\.~ ){$distance--;}else{$distance++;}}}## Warn if not a valid directory#Warning( "ProjectBase is not a directory: $ProjectBase")if ( $distance <= 0 || ! -d $tpath );## $ProjectBase will always be a valid directory, but if its the top# directory (/) and it is added to a path we will get //path# This is not good, so // will be removed later in the AddIncDir and# AddSrcDir commands where $ProjectBase is really used.## Alternatively we could set $ProjectBase to an empty string, but then# this may be confused with an empty relative directory#Debug("ProjectBase Final : $ProjectBase");}#-------------------------------------------------------------------------------# Function : DeployPackage## Description : Generate a deployed package# This is a gateway to a different packaging system## DeployPackage and PackageXxxxx directives are mutually# exclusive. Only one person can play in the package area.## Inputs : Platform Specifier# Package Name (Optional)# Options# --Name : Base name of the package. The default is taken# from the build.pl file# --Dir : Package directory# The default is based on the package name## Returns :#sub DeployPackage{my( $platforms, @elements ) = @_;my $dir;my $name;## Flag that this build creates a deployable package, even if its not# active on this platform.#$DEPLOYPACKAGE = 1;Debug2( "DeployPackage($platforms, @elements)" );return if ( ! ActivePlatform($platforms) );## Only allow one use of this directive#Error("DeployPackage can only be used once" ) if ( %DEPLOYPACKAGE );$DEPLOYPACKAGE = 2;## Ensure that the deployment file is available#my $command_file = $ScmDeploymentPatch ? "deploypatch.pl" : "deployfile.pl";Error("DeployPackage: $command_file not found") unless (-f "./$command_file");## Collect arguments#foreach (@elements ){if ( m/^--Dir=(.*)/ ) {Error ("DeployPackage: Package directory defined multiple times") if $dir;$dir = $1;} elsif ( m/^--Name=(.*)/ ) {Error ("DeployPackage: Package name defined multiple times") if $name;$name = $1;} elsif ( m/^--/ ) {Warning( "DeployPackage: Unknown option ignored: $_");} else {Error ("DeployPackage: Package name defined multiple times") if $name;$name = $_;}}$name = $::ScmBuildPackage unless ( $name );## Save the deployment data#$dir = lc($name) unless ( $dir );$DEPLOYPACKAGE{'name'} = $name;$DEPLOYPACKAGE{'dir'} = $dir;$DEPLOYPACKAGE{'cmdfile'} = $command_file;## Flag that toolset tests should be supressed# The Deploy world does not really use the full makefiles and if the# compilers are not installed will not be able to create deployment# packages#$ScmNoToolsTest = 1;}############################################################################################################################################################### Private function section.# The following functions are used INTERNALLY by makelib.pl2.############################################################################################################################################################### A collection of functions to write to the MAKEFILE handle## MakeHeader - Write a nice section header# MakeNewLine - Print a new line# MakePrint - Print a line ( without trailing \n)# MakeQuote - Escape \ and " character, then print a line# MakePrintList - Print an array# MakeEntry - Complex line printer# MakePadded - Padded line printer (internal)# PadToPosn - Calc space+tabs to tabstop (internal)# MakeEntry3 - Complex Line Printer# MakeDefEntry - Print a definition line (Production + Debug support)# MakeIfDefEntry - Print ifdef entry# MakeIfnDefEntry - Print ifndef entry# MakeIfZeroEntry - Print ifeq entry################################################################################sub MakeHeader{my ($text, @rest) = @_;my $length = length ($text);print MAKEFILE "\n";print MAKEFILE "#--------- $text ", '-' x (80 - 12 - $length) ,"\n";print MAKEFILE "# $_\n" foreach ( @rest ) ;print MAKEFILE "#\n";}sub MakeNewLine # Print a newline to the current 'Makefile'{print MAKEFILE "\n";}sub MakePrint # Print to the current 'Makefile'{print MAKEFILE @_if ( defined $_[0] );}sub MakeQuote # Quote a makefile text line{my( $line ) = @_;$line =~ s/\\/\\\\/g; # quote all '\' characters$line =~ s/"/\\"/g; # Then quote '"' characters$line =~ s/=#/=\\#/g; # Then quote '=#' sequenceprint MAKEFILE $line;}sub MakePrintList{print MAKEFILE $_ . "\n" foreach (@{$_[0]});}sub QuoteArray{my $quote = "'";if ( @_ ) {return ($quote . join("$quote $quote", @_) . $quote);}return '';}#-------------------------------------------------------------------------------# Function : MakeEntry## Description : Build a entry based on the element list# Creates text of the form# $(BINDIR)/prog.exe: object1.obj \# object2.obj### Inputs : $prelim - Preamble (one-off)# $postlim - Postamble (one-off)# $prefix - Pefix (to each element of array)# $postfix - Postfix (to each element of array )# @elements - Array of element to wrap## Returns : 1 Always## Notes:# The above description means that the following entry format is# produced:## <preliminary><prefix><variant1><prefix><variant2>...<final>## With judicious use of newline and tab characters, a target# and dependency list along with the command(s) to build the# target can be constructed.#sub MakeEntry{my( $prelim, $postlim, $prefix, $postfix, @elements ) = @_;MakePrint $prelim;MakePrint "${prefix}${_}${postfix}" foreach ( @elements );MakePrint $postlim if ($postlim);return 1;}#-------------------------------------------------------------------------------# Function : MakePadded## Description : Generate aligned output of the form# Prefix_text Aligned_text# where the aligned text is at a specified TAB boundary## Inputs : $align - Tab stop (One tab = 8 chars)# $prefix - Text to print before alignment occurs# @line - Remainder of the line#sub MakePadded # Print to the current 'Makefile', tab aligning{my( $align, $prefix, @line ) = @_;my $strlen = length( $prefix );my $pad = PadToPosn( $strlen, $align * 8 );print MAKEFILE $prefix . $pad;print MAKEFILE @line;}#-------------------------------------------------------------------------------# Function : PadToPosn## Description : Given that we are at $startposn return a tab and space# string to place us at $endposn#sub PadToPosn{my ($startposn, $endposn ) = @_;## Case where we are already too far into the line#return ( ' ' )if ( $endposn <= $startposn );my $tcount = 0;my $scount = 0;while ( $startposn < $endposn ){$tcount ++;$startposn = ($startposn >> 3) * 8 + 8;my $delta = $endposn - $startposn;if ( $delta < 8 ){$scount = $delta;last;}}return ( "\t" x $tcount . ' ' x $scount );}#-------------------------------------------------------------------------------# Function : MakeEntry3## Description : Build a makefile entry based on the element list, tab aligned# Can creat text of the form:# TAG = NAME0 \ TAG : NAME0 \# NAME1 NAME1### Inputs : $prelim - Preliminary text# $presep - Preliminary seperator# $elem_ref - Either a single name or a reference to# and array of names, or a hash.## Returns : Writes directly to the Makefile#sub MakeEntry3{my( $prelim, $presep, $elem_ref ) = @_;## The prelim may have some "\n" characters at the start# These simplify formatting, but mess up the nice formatting#if ($prelim =~ m~(^\n+)(.*)~ ){MakePrint $1;$prelim = $2;}## Print the definition and the sep with nice padding#MakePadded ( 3, $prelim, $presep );my $leadin = ' ';## If a HASH reference then use a sorted list of keys from the hash.#if ( ref ($elem_ref) eq "HASH" ){my @hash_list;@hash_list = sort keys ( %{$elem_ref} );$elem_ref = \@hash_list;}## If the list is only one element long, then create a simple form# If the list is not an array ref, then treat it as a single element#if ( ref ($elem_ref) eq "ARRAY" ){my $line = 0;foreach my $element ( @$elem_ref ){print MAKEFILE $leadin . $element;$leadin = " \\\n" . PadToPosn(0,24 + length( $presep ) + 1 ) unless ($line++);}}elsif ( defined $elem_ref ){print MAKEFILE $leadin . $elem_ref;}MakeNewLine();return 1;}#-------------------------------------------------------------------------------# Function : MakeDefEntry## Description : Make a definition entry of the form## TAG = NAME0 \# NAME1## Support a list of definitions that will always be created# as well as a production and a debug list.## Will always generate the "TAG = " string, even if the list# is empty.## Will supress the TAG if there is no data if the FIRST opr starts with a '+'## Inputs : TAG - Text tag to create# FIRST - First assignement opr. = or +=# ALL_LIST - A reference to a list of names to assign# or a single name.# PROD_LIST - Optional list to extend the definition with for a production build# DEBUG_LIST - Optional list to extend the definition with for a debug build## Returns : Nothing#sub MakeDefEntry{my( $tag, $assign, $all, $prod, $debug ) = @_;## Do not generate anything if the $opr is "+=" and there is no data# to output. ie: Supress empty TAG += statements#return if ( $assign =~ m/\+/ && ( ref($all) && ! defined $all->[0] ) );## TAG for all entries#MakeEntry3( $tag, $assign, $all );## TAGs for PROD build# TAGs for DEBUG build#if ( defined $prod && defined $prod->[0] ){print MAKEFILE 'ifeq "$(DEBUG)" "0"' . "\n";MakeEntry3( $tag, "+=", $prod );print MAKEFILE 'endif' . "\n";}if ( defined $debug && defined $debug->[0] ){print MAKEFILE 'ifeq "$(DEBUG)" "1"' . "\n";MakeEntry3( $tag, "+=", $debug );print MAKEFILE 'endif' . "\n";}}sub MakeIfDefEntry{my( $iftag, @rest ) = @_;print MAKEFILE "ifdef $iftag\n";MakeDefEntry (@rest);print MAKEFILE "endif\n\n";}sub MakeIfnDefEntry{my( $iftag, @rest ) = @_;print MAKEFILE "ifndef $iftag\n";MakeDefEntry (@rest);print MAKEFILE "endif\n\n";}sub MakeIfZeroEntry{my( $iftag, @rest ) = @_;print MAKEFILE "ifeq (\$($iftag),0)\n";MakeDefEntry (@rest);print MAKEFILE "endif\n\n";}#-------------------------------------------------------------------------------# Function : CreateNameList## Description : Create a list of names by adding a prefix and suffix to a# list of items. This is used to add a directory prefix and a# file suffix to a list of files.## Inputs : $prefix ie: '$(OBJDIR)/'# $suffix ie: '.obj'# $elem_ref ie: A list of files ( passed be ref )# If a Hash then its sorted keys is used## Returns : A ref to the resulting list#sub CreateNameList{my( $prefix, $suffix, $elem_ref ) = @_;my @result;if ( ref ($elem_ref) eq "HASH" ){my @hash_list;@hash_list = sort keys ( %{$elem_ref} );$elem_ref = \@hash_list;}foreach ( @$elem_ref ){push @result, $prefix . $_ . $suffix;}return \@result;}#-------------------------------------------------------------------------------# Function : ListGeneratedProjects## Description : Return a list of generated/nongenerated projects# Used in conjunction with CreateNameList## Inputs : $type - TRUE : Generated# FALSE: Not Generated## Returns : A reference to a list of projects# undef will be retuend if there are no projects#sub ListGeneratedProjects{my ($type) = @_;my @list;foreach my $project ( @PROJECTS_ORDER ){if ( exists($PROJECTS{$project}->{'generated'}) xor $type ){push @list, $project;}}return @list ? \@list : undef;}#-------------------------------------------------------------------------------# Function : ListCleanGenerated## Description : return a list of generated targets that have 'clean'# operations. This is used in conjunction with CreateNameList## Inputs : None## Returns : A list of project indexes, that can be cleaned#sub ListCleanGenerated{my @list;foreach my $i ( @GENERATE_FILES ){push @list, $i->{'index'}if ( $i->{'clean'} );}return \@list;}#-------------------------------------------------------------------------------# Function : MakeResolve## Description : Internal Function# Locate a source file by examining a list of directories## Don't use directly# Use MakeSrcResolve or MakeSrcResolveExtended## Inputs : $dirs - Ref to an array of directories to scan# $source - File to locate## Returns : Resolved path to the file# Will warn if multiple instances of the file are found#sub MakeResolve{my( $dirs, $source ) = @_;my( $first, $count );## If the path contains a '$' then its assumed to be# a variable name in the path. Just assume that it exists#return $source if ( $source =~ m#\$# );## If the path is absolute or contains a leading ., then don't search# Warn if it can't be found#if ( $source =~ m#^(/|\.)# ){Warning( "Unable to resolve '$source' path" ) unless -f $source;return $source;}my @found;# Search the local path firstpush (@found, $source ) if -f ($source);foreach my $dir (@$dirs){next if ( $dir eq '.' );my $temp = $dir . '/' . $source;Debug2( "MakeResolve: Looking in: $temp" );push (@found, $temp) if (-f $temp);}Warning( "Unable to resolve path to '$source'" ) unless $found[0];if (scalar @found > 1){Warning("Duplicates for '$source'. Using the first", @found);}return $found[0] || $source;}#-------------------------------------------------------------------------------# Function : MakeSrcResolve## Description : Locate a source file by examining the list of source# directories. There are a few frills## Look for a source file in# 1) %::BUILD_KNOWNFILES# 2) %SRCS# 3) Dirs specified by the array @SRCSDIRS## Inputs : Name of a file to resolve## Returns : Resolved path.# Input file - if not found at all#sub MakeSrcResolve{my ($name) = @_;my $file;if ( exists ( $::BUILD_KNOWNFILES{$name} ) ) {## The Known Files list is relative to ScmRoot# This must be included in the full path#$file = $ScmRoot . '/' . $::BUILD_KNOWNFILES{$name};} elsif ( exists $SRCS{$name} ) {$file = $SRCS{$name};} else {$file = MakeResolve( \@SRCDIRS, @_ );}return $file;}# MakeSrcResolveExtended# from_global = 0 : Search user specified directories# = 1 : Search LinkPkgArchive list#our @PkgSrcDirList;sub MakeSrcResolveExtended{my ( $from_global, $file ) = @_;## Simple Case. Resolve source from known source directories##return MakeSrcResolve( $file )unless ( $from_global );## Not so simple Case# Resolve the source from the imported packages## Create a list of directores to search, but only the first time# - Interface directories - from BuildPkgArchive# - LnkPkgArchive directories# Using target,product,platform include directories#unless ( @PkgSrcDirList ){for my $entry (@{$::ScmBuildPkgRules{$ScmPlatform} }){next if ( $entry->{'TYPE'} eq 'build' ); # Ignore BuildPkgArchivesfor (@{$entry->{'PINCDIRS'}}, @{$entry->{'THXDIRS'}}, '' ){my $dir = $entry->{'ROOT'} . "/" . $_ ;$dir =~ s~//~/~g;$dir =~ s~/$~~;push ( @PkgSrcDirList, $dir );}}}return MakeResolve( \@PkgSrcDirList, $file );}#-------------------------------------------------------------------------------# Function : GetPackageRoot## Description : Determine the root directory for a given package# This routine is intended for non-standard JATS scripts that# access package contents directly## Note: This routine does not attempt to handle multiple# instances of a package ( sysbasetypes ).## Inputs : $pname - Name of the package## Returns :#sub GetPackageRoot{my( $pname ) = @_;Debug( "GetPackageRoot(@_)" );my $result = undef;my $pkg = GetPackageEntry( $pname );if ( $pkg ){$result = $pkg->{'ROOT'};Debug( "GetPackageRoot: $result" );}return $result;}#-------------------------------------------------------------------------------# Function : ActiveProject## Description : Determine if the specified project is currenly 'active'## Inputs : $project - one or more project names separated# by either a comma or a colon## Returns : TRUE if the project is active#sub ActiveProject{my ($project) = @_;foreach ( split( '\s*[:,]\s*', $project ) ){return 1if ( $_ eq $::ScmBuildProject );}return 0;}#-------------------------------------------------------------------------------# Function : ActiveDefine## Description : Determine if the specified definition is currenly 'active'## Inputs : $defs - one or more variable names separated# by either a comma or a colon## Returns : TRUE if any of the definitions are known#sub ActiveDefine{my ($defs) = @_;no strict 'refs';foreach ( split( '\s*[:,]\s*', $defs ) ){return 1if ( defined( $$_ ) || ( @$_ ) );}use strict 'refs';return 0;}#-------------------------------------------------------------------------------# Function : ActiveMachType## Description : Determine if the specified MachType is currenly 'active'## Inputs : $mtype - one or more machine names separated# by either a comma or a colon## Returns : TRUE if any of the current MachType is in the list#sub ActiveMachType{my ($mtype) = @_;foreach ( split( '\s*[:,]\s*', $mtype ) ){return 1if ( uc($_) eq uc($::GBE_MACHTYPE) );}return 0;}#-------------------------------------------------------------------------------# Function : ActiveAlias## Description : Determine if the specified Alias is currenly 'active'## Inputs : $mtype - one or more alias names separated# by either a comma or a colon## Returns : TRUE if any of the current Aliases is in the list#sub ActiveAlias{my ($mtype) = @_;foreach ( split( '\s*[:,]\s*', $mtype ) ){return 1if ( isAnAlias( uc($_) ) );}return 0;}#-------------------------------------------------------------------------------# Function : ActivePlatform## Description : Determine if the specified platform is currently 'active'# This is used by all user directives in order to determine# if the directive should be ignored for the current platform## Inputs : $platform_spec - A platform specifier# This is a bit complex.## Format of platform_spec. One or more of# PlatformName# AliasName# TargetName[,--Target]# Special Options (Must all be True)# --Project=ProjectName[:ProjectName]+# --Defined=SomeValue[:SomeValue]+# --MachType=SomeMachType[:SomeMachType]+# --Alias=SomeAlias[:SomeAlias]+# Some shortcuts# '*' ==> Always true## Each can be prefixed with a '!' to negate the test## PlatformNames are either additive or negative(prefixed with !)# Order is not important# All additive names are accumulated before the negative items are considered.# ie: aa,!bb => !bb,aa# If only negative names are provided then JATS assumes a leading '*'# ie: !aaa => *,!aaa## Valid options are:# --Target - indicates that the platform is a 'target'## Returns : TRUE if the platform spec is satisfied#sub ActivePlatform{my( $platform_spec ) = @_;my( @platforms, $scmplatform, $platform );my( %arguments, @args );my @plist;## Short circuit check# '*' is used so often that it pays to check it first#if ( $platform_spec eq '*' ){Debug3( " ActivePlatform(@_) = TRUE" );return 1;}## Platform specifier may be a comma seperated list# ie: WIN32,MOS,XXX# Extract non-platform arguments# Process to yield a dummy platform of '0' or '1' - these will be seen later#foreach ( split( '\s*,\s*', $platform_spec ) ){my ($result, $not);if ( m~^(!?)--Project=(.+)~ ) {$not = $1;$result = ActiveProject($2);} elsif ( m~^(!?)--Defined=(.+)~ ) {$not = $1;$result = ActiveDefine($2);} elsif ( m~^(!?)--MachType=(.+)~ ) {$not = $1;$result = ActiveMachType($2);} elsif ( m~^(!?)--Alias=(.+)~ ) {$not = $1;$result = ActiveAlias($2);} else {## Must be a platform argument# Add to a list#push @platforms, $_;next;}## Continue processing non-platform arguments# Each one must be TRUE, allowing for negation.#$result = $result ? 1 : 0;$result = ! $result if ( $not );return 0 unless ( $result );}## If we have no platforms then the test was purely non-platform arguments.#if ($platform_spec ne '' && ! @platforms) {Debug3( " ActivePlatform(@_ == $ScmPlatform) = TRUE" );return 1;}unless (@platforms) {Debug3( " ActivePlatform(@_ == $ScmPlatform) = FALSE" );return 0;}# Platform specified may be an Alias# Perform alias expansion#@platforms = ExpandPlatforms( @platforms ); # aliasingDebug3( " ActivePlatform(@_)" );# Debug0( " Platforms(@platforms)" );#.. Arguments# At this point we have a list of platforms and arguments# Build up a hash of arguments for each platform being parsed# Multiple arguments can follow a platform name# Arguments apply to the preceeding platform name#$platform = undef;foreach ( @platforms ){if ( /^--Target/ ) { # Argumentsif ( $platform ) {$arguments{$platform}{'Target'} = 1;} else {Warning ("No Platform preceding platform option: $_");}} elsif ( /^--Only(Prod)|(Debug)/ || /--board=/ ) {# Known arguments# Bit of a kludge. Must be a better way} elsif ( /^--/ ) {Warning ("Unknown platform option: $_");} else { # Target$platform = $_;push @plist, $platform;}}#.. Scan the expression#$scmplatform = uc( $ScmPlatform ); # current platformmy @add;my @remove;foreach ( @plist ) {my $platform = uc( Trim( $_ ) ); # trim white and convert casemy $pname = $platform;my $invert = 0;if (substr($platform, 0, 1) eq '!') {$invert = 1;$pname = substr($platform, 1)}## Determine filter comparison# Either a Platform or a Target#if ( $arguments{$platform}{'Target'} ) {$pname = $scmplatform if ($pname eq uc( $ScmTarget ));}## Catch some historically bad practices#$pname = $scmplatform if ( $pname eq '*' || $pname eq '1' );Debug3( " Platform=$platform, PName=$pname" );## Examine platform names# Allow negation (removal) of the name#if ( substr($platform, 0, 1) eq '!' ) {push @remove, $pname;} else {push @add, $pname;}}## Build complete list of allowed platforms# Process additive rules before removal rules# If there are no additive rules, then assume all protaforms#my %calcList;@add = @::BUILDPLATFORMS unless @add;$calcList{uc $_} = 1 foreach (@add);delete $calcList{uc $_} foreach (@remove);#DebugDumpData("Add", \@add);#DebugDumpData("Remove", \@remove);#DebugDumpData("calcList", \%calcList);## If the current build target is left in the platform list, then we are building for it#if (exists $calcList{$scmplatform}) {Debug3( " ActivePlatform(@_ == $ScmPlatform) = TRUE" );return 1;}Debug3( " ActivePlatform(@_ == $ScmPlatform) = FALSE" );return 0;}#-------------------------------------------------------------------------------# Function : If## Description : Function for embedding arguments in directives# To be used within another directive# ie:# AnyDirective ('*', arg1, arg2, ...# If (SomePlatform, arg1, .. ,argn))## Inputs : $platform - Active Platform specifier# @args - Args## Returns : @args or nothing#sub If{my $platform = shift;return @_if ( ActivePlatform( $platform ));return;}#-------------------------------------------------------------------------------# Function : RegisterMakefileGenerate## Description : Register a function to be called at the start of the# makefile generation process## Inputs : $fname - Name of the function# $args - Function Arguments## Returns : Nothing#our @MF_Generators;sub RegisterMakefileGenerate{my ($fref) = @_;my $rtype = ref($fref) || 'not a reference';Error ("RegisterMakefileGenerate called incorrectly","First argument MUST be a code reference","It is a $rtype") unless ( $rtype eq 'CODE' );## Save the arguments by reference in an array# The array will be processed later#push @MF_Generators, \@_;}#-------------------------------------------------------------------------------# Function : RegisterSrcHook## Description : Register a function to be called when a source file is# declared## Inputs : $ext - Extension of interest# '*' will be used by all# $fname - Name of the function# $args - Function Arguments## Returns : Nothing#sub RegisterSrcHook{my $ext = shift;my ($fref) = @_;my $rtype = ref($fref) || 'not a reference';Error ("RegisterSrcHook called incorrectly","Second argument MUST be a code reference","It is a $rtype") unless ( $rtype eq 'CODE' );## Save the arguments by reference in an array# The array will be processed later#push @{$MF_RegisterSrcHooks{$ext}}, \@_;}#-------------------------------------------------------------------------------# Function : MakefileHeader## Description: : Generate a "standard" makefile header.##..sub MakefileHeader{my ($file, $desc, $by, @trailing) = @_;my ($diff);$diff = 0 if (($diff = ((80-5) - length($desc))) < 0);$desc .= ' ' . ('-' x $diff);print $file <<EOF;#-- $desc## -- Please do not edit this file. --## To do so may result in a system failure, in additional to any# changes made shall be overwritten.## Created by $by# on $::CurrentTime#EOF## Print out the trailer# This is an array. Place each entry on a new line#print $file $_ . "\n" for ( @trailing );}################################################################################ MakeFileGenerate:# This subroutine does all of the actual make file generation based# on information provided in the calls to the various public# interface routines.## Inputs:## Returns:###############################################################################my $MakefileGenerate_once = 0;sub MakefileGenerate{my $Makefile = "$ScmPlatform.mk";Debug( "MakefileGenerate: $Makefile" );## Nasty things happen when we generate a makefile twice# Just warn the user and do nothing# If its in the common makefile.pl then just ignore it#if ( $ScmProcessingRootMake ){Warning ("MakefileGenerate directive is not allowed in common makefile.pl");return;}if ( $MakefileGenerate_once ){Warning ("MakefileGenerate should only be called once.","Dir: $::Cwd");return;}$MakefileGenerate_once = 1;## Invoke all registered Makefile Generator functions# These allow clever directives to collect information to be# processed before the makefiles are created#while ( @MF_Generators ){Debug( "MakefileGenerate: Invoke RegisterMakefileGenerate function" );my ($fname, @args) = @{shift @MF_Generators};&$fname ( @args );}## Allow the toolset the opportunity to process all the collected data# before the makefile is created. This is optional#my( $if ) = MakeIf::Factory(); # build interface$if->Preprocess();## If we have supressed the Toolset use, then we need to sanity test# the use of the toolset#if ( $ScmNoToolsTest ){ReportError ("Building programs not supported with --NoToolset") if ( @PROGS || @TESTPROGS );ReportError ("Building libraries not supported with --NoToolset") if ( @LIBS || @MLIBS || @SHLIBS );ReportError ("Building projects not supported with --NoToolset") if ( %PROJECTS );ErrorDoExit();}## Auto package the 'descpkg' file# If this makefile packages any files, then it can also package the descpkg file# The descpkg will be piggybacked into all makefiles that do a package#if ( %PACKAGE_FILES || %PACKAGE_HDRS || %PACKAGE_CLSS || %PACKAGE_LIBS|| %PACKAGE_SHLIBS || %PACKAGE_PROGS || @PACKAGE_DIRS ){Src ('*', 'descpkg') unless ($SRCS{ descpkg });PackageFile ('*', 'descpkg');}## Some toolsets NEED a relative root# Note: At the moment ScmRoot is relative anyway, thus this code# does nothing#my $gbe_root = $::ScmRoot;if ( $::UseRelativeRoot ){$gbe_root = RelPath( $::ScmRoot );}## Now start to create the makefile#ToolsetFiles::AddFile($Makefile);open( MAKEFILE, '>', $Makefile ) || Error( "Cannot create $Makefile" );::MakefileHeader( *MAKEFILE,'Auto-generated Platform Dependent Makefile',"$ScmMakelib (version $ScmVersion)","# COPYRIGHT - VIX IP PTY LTD (\"VIX\"). ALL RIGHTS RESERVED.",'#',"# Located in $::Cwd","# Platform $::ScmPlatform",'#' . ('-' x 79),);## Ensure that some essential variables are set#print MAKEFILE <<EOF;## Validate essential environment variables#ifndef GBE_BIN\$(error ERROR: GBE_BIN is not available)endififndef GBE_PERL\$(error ERROR: GBE_PERL is not available)endififndef DEBUG\$(error ERROR: DEBUG is not defined)endifEOFprint MAKEFILE <<EOF;## Basic definitions#GBE_ROOT := $gbe_rootGBE_ROOT_ABS := \$(abspath \$(GBE_ROOT))GBE_HOST := $::ScmHostGBE_HOSTMACH := $::GBE_MACHTYPEGBE_TARGET := $::ScmTargetGBE_MACHTYPE := $::ScmMachTypeGBE_PLATFORM := $::ScmPlatformGBE_PBASE := $::PbaseGBE_TYPE := \$(if \$(findstring 1,\$(DEBUG)),D,P)EOFMakePrint( "GBE_ARGS := @ScmPlatformArgs\n" )if ( scalar @ScmPlatformArgs );MakePrint( "GBE_PRODUCT := $ScmProduct\n" )if ( $ScmProduct ne "" );MakePrint( "GBE_OS_COMMON := $::BUILDINFO{$ScmPlatform}{OS_COMMON}\n" )if ( exists($::BUILDINFO{$ScmPlatform}{OS_COMMON}) );print MAKEFILE <<EOF;SHELL := \$(GBE_BIN)/shSHELLARGS :=EXTENDED_LINE := \$(GBE_BIN)/extend.lstexport EXTENDED_LINE MAKEMFLAGS := --no-print --warn -rBUILDNAME := $::ScmBuildNameBUILDVER := $::ScmBuildVersionFullBUILDVERNUM := $::ScmBuildVersionBUILDPREVIOUSVER := $::ScmBuildPreviousVersionDEPLOYPATCH := $ScmDeploymentPatchGBE_NOTOOLSTEST := $ScmNoToolsTestMAKEFILEUID := $ScmMakeUidexport MAKEFILEUID## Ensure PWD is correctly set#PWD := \$(CURDIR)export PWD## NODEPEND - Used to suppress generated dependency file checking# Mostly done in jmake.pl# EXPERT - Used to suppress dependency on this makefile#EOFMakePrint( "EXPERT\t\t?= " . ($ScmExpert ? '1' : '0' ) . "\n" );MakePrint( "NODEPEND\t?= 0\n" );print MAKEFILE <<EOF;## SCM_MAKEFILE - The name of the file to depend upon# Supressed in EXPERT mode#ifneq (\$(EXPERT),0)SCM_MAKEFILE :=elseSCM_MAKEFILE := $MakefileendifEOF## Setup the base directory for the packaging process# When building a deployable package the base directory is changed to match# that used by the deployment world. This is done so that the descpkg file# can be created in the correct location#my $PKGDIR = "pkg/$::Pbase";$PKGDIR = "build/deploy" if ( $DEPLOYPACKAGE );Verbose("Setting PKGDIR: $PKGDIR");print MAKEFILE <<EOF;#--------- Targets -------------------------------------------------------------.PHONY: default all build install package unpackage uninstall \\clean unbuild clobber deploydefault:all: install package deploybuild: make_init generate install_hdr depend make_lib \\install_lib make_install_shlib make_prog install_class install_dirsinstall: build install_progpackage: package_dirs package_files package_hdr package_lib package_shlib \\package_prog package_classunpackage: unpackage_class unpackage_prog unpackage_shlib \\unpackage_lib unpackage_hdr unpackage_files unpackage_dirsuninstall: uninstall_dirs uninstall_class uninstall_prog uninstall_shlib \\uninstall_lib uninstall_hdrclean: make_clean unmake_prog unmake_test unmake_lib unobj \\undepend ungenerate rmlitter unmake_dirunbuild: clean uninstallclobber: unpackage unbuild clobberfiles clobberdirsdeploy: install run_deploy#--------- Macros --------------------------------------------------------------OBJDIR = \$(GBE_PLATFORM)\$(GBE_TYPE).OBJLIBDIR = \$(GBE_PLATFORM).LIBBINDIR = \$(GBE_PLATFORM)\$(GBE_TYPE).BINCLSDIR = classes\$(GBE_TYPE)PKGDIR = \$(GBE_ROOT)/$PKGDIRINCDIR_PKG = \$(PKGDIR)/includeLIBDIR_PKG = \$(PKGDIR)/libBINDIR_PKG = \$(PKGDIR)/binCLSDIR_PKG = \$(PKGDIR)/classesUTFDIR_PKG = \$(GBE_ROOT_ABS)/$PKGDIR/utfResultsLOCALDIR = \$(GBE_ROOT)/localINCDIR_LOCAL = \$(LOCALDIR)/incLIBDIR_LOCAL = \$(LOCALDIR)/libBINDIR_LOCAL = \$(LOCALDIR)/binCLSDIR_LOCAL = \$(LOCALDIR)/classesBINDIR_LOCAL_PATH = \$(GBE_ROOT_ABS)/local/bin/\$(GBE_PLATFORM)\$(GBE_TYPE)INTERFACEDIR = \$(GBE_ROOT)/$ScmInterfaceINCDIR_INTERFACE= \$(INTERFACEDIR)/includeLIBDIR_INTERFACE= \$(INTERFACEDIR)/libBINDIR_INTERFACE= \$(INTERFACEDIR)/binCLSDIR_INTERFACE= \$(INTERFACEDIR)/classes.SUFFIXES: # Delete the default suffixesEOFMakePrintList( \@DEFINES );MakeNewLine();#-------------------------------------------------------------------------------##MakeHeader ("Defines, flags and file sets");# Flagsforeach my $opt ( sort keys %ScmCompilerOpts ){MakeDefEntry ( $opt, "=", $ScmCompilerOpts{$opt} );}MakeDefEntry( "CFLAGS", "=", \@CFLAGS, \@CFLAGS_PROD, \@CFLAGS_DEBUG );MakeDefEntry( "CLINTFLAGS", "=", \@CLINTFLAGS, \@CLINTFLAGS_PROD, \@CLINTFLAGS_DEBUG );MakeDefEntry( "CDEPENDFLAGS", "=", \@CFLAGS, \@CFLAGS_PROD, \@CFLAGS_DEBUG );MakeDefEntry( "CXXFLAGS", "=", \@CXXFLAGS, \@CXXFLAGS_PROD, \@CXXFLAGS_DEBUG );MakeDefEntry( "CXXLINTFLAGS", "=", \@CXXLINTFLAGS, \@CXXLINTFLAGS_PROD, \@CXXLINTFLAGS_DEBUG );MakeDefEntry( "CXXDEPENDFLAG", "=", \@CXXFLAGS, \@CXXFLAGS_PROD, \@CXXFLAGS_DEBUG );MakeDefEntry( "ASFLAGS", "=", \@ASFLAGS, \@ASFLAGS_PROD, \@ASFLAGS_DEBUG );MakeDefEntry( "LDFLAGS", "=", \@LDFLAGS, \@LDFLAGS_PROD, \@LDFLAGS_DEBUG );#-------------------------------------------------------------------------------##MakeHeader ("Tool Search Path","Extend the PATH seen by all the tools to include","The tools/bin directories discovered in Packages" );my $put_PATH;my $put_LD_LIBRARY_PATH;MakePrint( "PATH := \$(BINDIR_LOCAL_PATH)$::ScmPathSep\$(PATH)\n" );$put_PATH = 1;for my $path ( ToolExtensionPaths() ){MakePrint( "PATH := $path$::ScmPathSep\$(PATH)\n" );$put_PATH = 1;if ( $::ScmHost eq "Unix" ){MakePrint( "LD_LIBRARY_PATH ?= \n" );MakePrint( "LD_LIBRARY_PATH := $path$::ScmPathSep\$(LD_LIBRARY_PATH)\n" );$put_LD_LIBRARY_PATH =1;}}# Export the appropriate environment variables# Note: Windows has an issue with PATH and Path# Haven't got to the bottom of it yet, but it would appear that DLL# searching uses Path and other stuff uses PATH. Not too sure how we# end up with two (or more in the environment)##if ( $put_LD_LIBRARY_PATH ){MakePrint( "export LD_LIBRARY_PATH\n" );}if ( $put_PATH ){MakePrint( "Path := \$(PATH)\n" );MakePrint( "export PATH Path\n" );}#-------------------------------------------------------------------------------##MakeHeader ("Perl Module Search Path","Extend the PERL5LIB seen by invocations of perl");my $perl_module_found;for my $path ( ToolExtensionPaths() ){if (my @results = glob( "$path/*.pm")){MakePrint( "PERL5LIB := $path$::ScmPathSep\$(PERL5LIB)\n" );$perl_module_found = 1;}}if ( $perl_module_found ){MakePrint( "export PERL5LIB\n" );}#-------------------------------------------------------------------------------##MakeHeader ("Include Search Paths","Package Include Paths for header files and libraries" );MakeDefEntry( 'PINCDIRS' , '=', '# includes');MakeDefEntry( 'PINCDIRS_INTERFACE', '=', '# Interface includes');MakeDefEntry( 'PINCDIRS_LOCAL', '=', '# Local includes');MakeDefEntry( 'PLIBDIRS' , '=', '# libraries');MakeDefEntry( 'PLIBDIRS_INTERFACE', '=', '# Interface libraries');MakeDefEntry( 'PLIBDIRS_LOCAL', '=', '# Local libraries');for my $package (@{$::ScmBuildPkgRules{$ScmPlatform} }){## Skip the pseudo package that encapsulates the interface# directory. Currently the makefiles do this in a different# manner - to be resolved## Just comment out the lines so that the data is visible# Its a hint to make use of the data#my $prefix = '';my $suffix = '';$prefix = '# ' if ( $package->{'TYPE'} eq 'build' );## The interface directory is a little bit different#my ($name,$base);if ( $package->{'TYPE'} eq 'interface' ) {$base = '$(INTERFACEDIR)';$name = 'Interface Directory';$suffix = '_INTERFACE';} else {$name = $package->{'NAME'} . '/' . $package->{'VERSION'};$base = $package->{'ROOT'};}my @doc;push (@doc, "From: $base");push (@doc, 'BuildPkgArchive via Interface' )if $package->{'TYPE'} eq 'build' ;MakeHeader ("Source: $name", @doc);## List include and library directories# Note: Need the True Path for windows.# Some makefile functions (wildcard) only work as expected# if the case of the pathname is correct. Really only a problem# with badly formed legacy packages where the Windows user# guessed at the package format.## The conversion to a TruePath is done when ScmBuildPkgRules# is created. Create once, use many time.#for my $type (qw (PINCDIRS PLIBDIRS) ) {for my $path ( @{$package->{$type}} ) {MakeDefEntry ( "$prefix$type$suffix", "+=", $base . $path);}}}## Local Paths# These are a little bit special#MakeHeader ('Source: Local', 'From: Package Local');sub MakeLocalPaths{my ($name, $root, $addRoot) = @_;my @pathlist;foreach my $tag ( $ScmPlatform, $ScmProduct, $ScmTarget ) {UniquePush( \@pathlist, "$root/$tag" ) if ( $tag );}# Add the root directory tooUniquePush( \@pathlist, $root) if $addRoot;MakeDefEntry ( $name , "+=", \@pathlist);}MakeLocalPaths ( 'PINCDIRS_LOCAL', '$(INCDIR_LOCAL)', 1 );MakeLocalPaths ( 'PLIBDIRS_LOCAL', '$(LIBDIR_LOCAL)', 0 );#-------------------------------------------------------------------------------##MakeHeader ("Include Search Paths","Local Include Paths"," LINKDIRS - Local include search path (short)"," INCDIRS - Include search path (complete)"," NODEPDIRS - "," SRCDIRS - "," LIBDIRS - Library search path",);# Include search path## user-local# local# interface# BuildPkgArchive# LinkPkgArchive# user-global#MakeDefEntry ( "\nLINCDIRS", "= ", \@L_INCDIRS ); # .. LocalMakeDefEntry ( "LINCDIRS", "+=", '$(PINCDIRS_LOCAL)'); # .. Sandbox localMakeDefEntry ( "LINCDIRS", "+=", '$(PINCDIRS_INTERFACE)'); # .. Sandbox interfaceMakeDefEntry ( "LINCDIRS", "+=", \@G_INCDIRS ); # .. GlobalMakeDefEntry ( "INCDIRS", "= ", '$(LINCDIRS)' ); # LocalMakeDefEntry ( "INCDIRS", "+=", '$(PINCDIRS)' ); # PackageMakeDefEntry ( "LINCDIRS", "+=", \@S_INCDIRS ); # System# Source search pathMakeDefEntry( "\nNODEPDIRS", "=", \@NODEPDIRS );MakeDefEntry( "\nSRCDIRS","= " , [ @L_SRCDIRS, @G_SRCDIRS ] ); # LocalMakeDefEntry ( "SRCDIRS", "+=" , '$(PINCDIRS)' ); # PackageMakeDefEntry ( "SRCDIRS", "+=" , \@S_INCDIRS ); # System# Library search path## user-local# local# interface# BuildPkgArchive# LinkPkgArchive# user-global## Kludge Note:# The LIBDIRS path needs an element with a directory seperator in it# Needed by (broken) cmdfile o determine the file seperator to use#MakeDefEntry( "\nLIBDIRS", "= ", '$(LIBDIR)' ); # User LocalMakeDefEntry( "LIBDIRS", "+=", \@L_LIBDIRS ); # LocalMakeDefEntry( "LIBDIRS", "+=", '$(PLIBDIRS_LOCAL)' ); # Sandbox/localMakeDefEntry( "LIBDIRS", "+=", '$(PLIBDIRS_INTERFACE)' ); # Sandbox/interfaceMakeDefEntry( "LIBDIRS", "+=", '$(LIBDIR_INTERFACE)' ); # Kludge. See note aboveMakeDefEntry( "LIBDIRS", "+=", \@G_LIBDIRS ); # GlobalMakeDefEntry( "LIBDIRS", "+=", '$(PLIBDIRS)' ); # PackageMakeDefEntry( "LIBDIRS", "+=", \@S_LIBDIRS ); # System#-------------------------------------------------------------------------------## Subdir creation and deletion# Creation is done on the fly# Deletion is done AFTER the toolset functions have been invoked to create the# build artifacts so that the toolsets can create directories tooMakeHeader ("Subdir creation");CreateMkdirRules();MkdirRule( '$(OBJDIR)', 'OBJDIR', '--Extra=depend,depend.err' ); # Object build directoryMkdirRule( '$(OBJDIR)/'.$_ ) foreach (@SHLIBS); # Shared library build directoryMkdirRule( '$(LIBDIR)', 'LIBDIR' ); # Library directoryMkdirRule( '$(BINDIR)', 'BINDIR' ); # Binary directory## Create a directory for library merge tool to work within#MkdirRule( "\$(MLIBDIR)", 'MLIBDIR', '--Path=$(GBE_PLATFORM).MRG', '--RemoveAll' ) if (@MLIBS);#-------------------------------------------------------------------------------# Generate rules and recipes to create all the toolset specific parts# This is done fairly early to allow the toolsets to extend various# definitions that may be used later in the makefile construction#MakeHeader ("Construct Programs");foreach my $i ( @PROGS ){my $pProg = $PROGS->Get($i);my $pArgs = $pProg->getItems('ARGS');my $pObjs = $pProg->getItems('OBJS');my $pLibs = $pProg->getItems('LIBS');## Create a list of program object files#push @PROGOBJS, @$pObjs;MakePrint( "#---- (${i})\n\n" );if ( $ScmToolsetProgDependancies ){## Original style Prog Interface# Write some dependency information here and some in the toolset# Problems:# 1) Errors in library dependency generation will be# reported after all the object files have been created# Thus the error message and the make-stop are seperated# by many,many lines of output. This makes it difficult# to see the error.## 2) Lack of Flexability#MakeEntry( "\$(BINDIR)/$i$::exe: ", "", "\\\n\t\t", ".$::o ", @$pObjs );}else{## New Style Prog Interface# The toolset does it all## Flag the progam packaging as a placeholder.# The toolset will replace/update it.#PackageProgRemoveFiles( $i );}$if->LD ( $i, $pArgs, $pObjs, $pLibs );$if->LDLINT( $i, $pArgs, $pObjs, $pLibs );}#-------------------------------------------------------------------------------##MakeHeader ("Construct Test Programs");foreach my $i ( @TESTPROGS ){my $pProg = $TESTPROGS->Get($i);my $pArgs = $pProg->getItems('ARGS');my $pObjs = $pProg->getItems('OBJS');my $pLibs = $pProg->getItems('LIBS');## Create a list of program object files#push @TESTPROGOBJS, @$pObjs;MakePrint( "#---- (${i})\n\n" );if ( $ScmToolsetProgDependancies ){MakeEntry( "\$(BINDIR)/$i$::exe: ", "", "\\\n\t\t", ".$::o ", @$pObjs );}else{PackageProgRemoveFiles( $i );}$if->LD ( $i, $pArgs, $pObjs, $pLibs );$if->LDLINT( $i, $pArgs, $pObjs, $pLibs );}#-------------------------------------------------------------------------------##MakeHeader ("Transfer Scripts to BINDIR");foreach my $i ( sort ( values %SCRIPTS )){my $tname = "\$(BINDIR)/" . StripDir( $i );MakePrint( "$i:\t\tmakefile.pl\n" ."\t\$(XX_PRE)if [ ! -f \"$i\" ]; then echo 'Script [$i] not found'; exit 2; fi\n\n" );## Create a rule to copy the script into the BIN directory# Mark the script as executable - It can't hurt and its there# to be run as part of a test.#MakePrint "$tname:\t\$(GBE_BINDIR) $i\n" ."\t\$(XX_PRE)\$(cp) -f $i $tname\n" ."\t\$(XX_PRE)\$(chmod) -f +wx $tname\n\n"}#-------------------------------------------------------------------------------##MakeHeader ("Construct Libraries");foreach my $i ( @LIBS ){my $pLib = $LIBS->Get($i);my $pArgs = $pLib->getItems('ARGS');my $pObjs = $pLib->getItems('OBJS');unless ( $ScmToolsetNillLibSrc ){Error ("Library has no component objects: $i")if ( scalar @$pObjs <= 0 );}MakePrint "#---- (${i})\n\n";$if->AR( $i, $pArgs, $pObjs, $pLib);$if->ARLINT( $i, $pArgs, $pObjs, $pLib );}#-------------------------------------------------------------------------------##MakeHeader ("Construct Merged Libraries");sub MlibEntry{my( $mlib, $plib, $pLibs ) = @_;my @flib;MakePrint '$(LIBDIR)/' . GenLibName($mlib) . ":";foreach my $lib ( @$pLibs ){## Each library name may contains one embedded option which# specifies the source directory# libname[,--Option | BaseSubdir]#my ($slib, $sdir) = split( ',', $lib );my $mode;## By default the librares are pulled from LOCAL unless the# library is built in this directory, in which case it will# be used.#$sdir = ( $LIBS->Get($slib) ) ? '--Here' : '--Local'unless ( $sdir );## --Interface - Pull library from the interface directory# --Local - Pull library from the local directory# --SubDir=xxxx - Pull library from specified subdirectory# --Here - Pull from local directory if built locally# otherwise - Pull library from specified subdirectory#if ($sdir eq '--Interface') {$sdir = '$(LIBDIR_INTERFACE)/$(GBE_PLATFORM)';} elsif ($sdir eq '--InterfacePlain') {$sdir = '$(LIBDIR_INTERFACE)/$(GBE_PLATFORM)';$mode = 1;} elsif ( $sdir eq '--Local') {$sdir = $PackageInfo{'Lib'}{'IBase'} . # Base of Installed libs$PackageInfo{'Lib'}{'Dir'}; # Default subdir} elsif ( $sdir =~ m~^--SubDir=(.*)~ ) {$sdir = $1 . '/$(LIBDIR)';} elsif ( $sdir eq '--Here') {$sdir = '$(LIBDIR)';} else {$sdir .= '/$(LIBDIR)';}MakePrint " \\\n\t\t${sdir}/" . GenLibName($slib, $mode);push @flib, "${sdir}/${slib}";}return \@flib;}foreach my $i ( @MLIBS ){my $pLib = $MLIBS->Get($i);my $pArgs = $pLib->getItems('ARGS');my $pLibs = $pLib->getItems('LIBS');MakePrint "#---- (${i})\n\n";unless ( defined &ToolsetARMerge ){Warning( "Merging of libraries not supported in this toolset yet" );Warning( "MergeLibrary: \"$i\" will not be created" );}else{## Create the dependency rule# Target library : source library list# Recipe - generated by the toolset#foreach ( @$pArgs ){Warning( "Ignoring unknown argument to MergeLibrary. $_" );}$pLibs = MlibEntry( $i, $pLib, $pLibs );$if->ARMerge( $i, $pArgs, $pLibs, $pLib );}}#-------------------------------------------------------------------------------##MakeHeader ("Construct Shared Libraries");foreach my $i ( @SHLIBS ){my $pShlib = $SHLIBS->Get($i);my $pArgs = $pShlib->getItems('ARGS');my $pObjs = $pShlib->getItems('OBJS');my $pLibs = $pShlib->getItems('LIBS');my $version = $pShlib->{VERSION};$if->SHLD ( $i, $pArgs, $pObjs, $pLibs, $version );$if->SHLDLINT( $i, $pArgs, $pObjs, $pLibs, $version );}#-------------------------------------------------------------------------------# Construct Objects# For each object within OBJSOURCE construct the following:## $(OBJDIR)/object-name: source-name [makefile]# Toolset ...###MakeHeader ("Construct Objects");foreach my $i ( sort keys %OBJSOURCE ){my( $src, $sname, $ext, $type, @args );$src = $OBJSOURCE{ $i };$sname = StripDir( $src );$ext = StripFile( $src );$ext = lc($ext)if ( $::ScmHost ne "Unix" );$type = ($ScmSourceTypes{ $ext } || '')unless (( $type = $SRC_TYPE{ $sname }) );## Object source is an object file# No need the generate the object, just create makefile rule# [ddp] Not too sure how we get here#if ( $ext eq ".$::o" ){MakePrint "$src:";MakePrint " \$(SCM_MAKEFILE)";MakeNewLine();next;}## Need to create object file#@args = split( /$;/, $SRC_ARGS{ StripDir( $sname ) } )if $SRC_ARGS{ $sname };push( @args, "--Shared" )if ( exists $SHOBJ_LIB{$i} );## Convert relative paths to absolute paths if required by the# toolset. Some compilers need ABS paths to generate nice debug# information.#$src = AbsPath($src)if ( $UseAbsObjects );## Extract any user specified dependancies# These will be added to the dependency list#my @dlist;@dlist = split( /$;/, $SRC_DEPEND{$sname} )if ( exists $SRC_DEPEND{$sname} );## Create the dependency part of the object rule# The source file MUST be the first dependent recipes# may assume that $< is the name source file#MakeEntry( "\$(OBJDIR)/$i.$::o: $src \$(SCM_MAKEFILE)", "", " \\\n\t", "", @dlist );if ( $type eq ".c" ) {$if->CC( $src, $i, \@args );} elsif ( $type eq ".cc" ) {$if->CXX( $src, $i, \@args );} elsif ( $type eq ".asm" ) {$if->AS( $src, $i, \@args );} else {$if->EXT( $src, $i, \@args ) ||Warning( "Don't know how to build '$ext' images' for $src, $i" );MakeNewLine();}}#-------------------------------------------------------------------------------# Construct Projects# Construct toolset specific projects#MakeHeader ("Construct Projects");while ( my($project, $entry) = each %PROJECTS){$if->PROJECT( $entry );}#-------------------------------------------------------------------------------# Automated tests#MakeHeader ("Automated tests");my $idx = 0;my @copy_set = ();foreach my $pEntry ( @TESTS_TO_RUN ){ # Foreach test$idx++;$pEntry->{'index'} = $idx;$pEntry->{'test_name'} = "run_test_$idx";$pEntry->{'echoname'} = $pEntry->{'utfname'} || '';$pEntry->{'utfname'} = $pEntry->{'test_name'} unless defined $pEntry->{'utfname'};## If the test is being run within a 'FrameWork' then the underlying# toolset must instantiate the frame work.## This may change. Perhaps frameworks shouldn't be a part of the# toolset. Perhaps they should be standalone. May change#if ( $pEntry->{framework} ){$if->TESTFRAMEWORK( $pEntry );}## Create a rule to run the test#my $tdir_alias = $pEntry->{'testdir'};my $tdir = '$(' . $tdir_alias . ')';my $test_name = $pEntry->{'test_name'};push @TESTPROJECT_TO_URUN, $test_name;push @TESTPROJECT_TO_ARUN, $test_name if ($pEntry->{'auto'} );my $tprog = $tdir . '/' . StripDir( $pEntry->{'prog'} );## Determine the maximum time that the automated test should run# Default is 30 minutes# Non-auto tests are not time limited#my $timeout = '';if ($pEntry->{'auto'}){$timeout = 'timeout -Time:' . ($pEntry->{'maxtime'} || '30m') . ' ';}my $me = MakeEntry::New( *MAKEFILE, $test_name, '--Phony' );## Export GBE_UTF... for the duration of the test#$me->AddDefn('export GBE_UTFNAME', $pEntry->{'utfname'});$me->AddDefn('export GBE_UTFUID', '$(MAKEFILEUID)' . '_' . $pEntry->{'index'});$me->AddDefn('export GBE_UTFFILE','$(UTFDIR_PKG)/$(GBE_PLATFORM)-$(GBE_TYPE)-$(GBE_UTFUID)' . '.xml');$me->AddDefn('export GBE_UTFTEST','TEST-$(GBE_UTFNAME)-$(GBE_TYPE)-$(GBE_UTFUID)' );## A bit of a kludge for 'googletest'# If we have another kludge like then then consider placing this work into a module based on the filter name# with some sort of interface to allow the ENVvars and format and command line args to be massaged## For googletest# Set EnvVar and then post process with junit#if ($pEntry->{'utfformat'}){if ($pEntry->{'utfformat'} eq 'gtest') {$pEntry->{'utfformat'} = 'junit';$me->AddDefn('export GTEST_OUTPUT ', 'xml:${GBE_UTFTEST}.xml');}}# Workaround for dirsep under windows when being wrapped in a timeout$me->AddDefn('dirsep', '$(dirsep)$(dirsep)') if ($timeout && ($::ScmHost ne "Unix"));$me->AddDependancy( "\$(GBE_$tdir_alias)" );$me->AddDependancy( "\$(INTERFACEDIR)/set_$::ScmPlatform.sh" );$me->AddDependancy( $tprog ) if $pEntry->{'copyprog'};$me->AddDependancy( @{ $pEntry->{'copyin' } } );$me->AddDependancy( map { $tdir . '/' . StripDir($_) } @{ $pEntry->{'copyonce' } } );$me->AddDependancy( @{ $pEntry->{'preq'} } );$me->RecipePrefix ('$(XX_PRE)');$me->RecipeWrapper( $timeout . 'sh -c \'', '\'') if $timeout;$me->RecipeComment( "------ Running test [$idx] $pEntry->{'echoname'} ..." );## Create package utfResults directory# Simplify use of the file#$me->AddShellRecipe ( 'mkdir -p $(UTFDIR_PKG)' );## Extend the PATH seen by the script to include the local/bin directory# Allows programs and tests that have been created elsewhere in the component# to be accessed within the script.#$me->AddShellRecipe ( ". \$(INTERFACEDIR)/set_$::ScmPlatform.sh" );## Copy in the files that we need#foreach my $file ( @{$pEntry->{'copyin'}} ){my $dst = $tdir . '/' . StripDir( $file );UniquePush( \@COPYIN, $dst );UniquePush( \@copy_set, $file );$me->AddShellRecipe ( "\$(cp) -f $file $dst" );$me->AddShellRecipe ( "\$(chmod) -f +wx $dst" );}## Insert any FrameWork Recipe bits#$me->AddShellRecipe ( @{$pEntry->{'ShellRecipe'}} );## Insert command# Save result code to a known file#$me->AddShellRecipe ( "cd $tdir" );$me->AddShellRecipe ( ["GBE_TYPE=\$(GBE_TYPE)","GBE_HOST=\$(GBE_HOST)","GBE_ROOT=\$(GBE_ROOT_ABS)","PATH=.\\$::ScmPathSep\$(BINDIR_LOCAL_PATH)\\$::ScmPathSep\$\$PATH",$pEntry->{'command'},@{$pEntry->{'args'}},] ,'echo $$? > utf.$${GBE_UTFUID}.rc' );## Create the basic command line for 'jats_runutf'# Use the simplistic 'internal' filter unless the user has provided one#my @cmdline;push @cmdline, '--';push @cmdline, '$(VERBOSE_OPT)';push @cmdline, '-filter=' . ($pEntry->{'utfformat'} || 'internal');push @cmdline, '-root=$(GBE_ROOT_ABS)' ;push @cmdline, "-dir=$tdir";push @cmdline, '-target=$(GBE_PLATFORM)';push @cmdline, '-pkgdir=$(PKGDIR)';push @cmdline, '-local=$(LOCALDIR)';push @cmdline, '-interface=$(INTERFACEDIR)';push @cmdline, "-rcfile=$tdir/utf.\$\${GBE_UTFUID}.rc";push @cmdline, map { '-arg='. $_ } @{$pEntry->{'utfargs' }};## Insert commands to post process the test results according to the specified formatter#$me->NewSection ();$me->SectionIfDef ('UTF_POSTPROCESS');$me->RecipePrefix ('$(XX_PRE)');$me->AddOneRecipe ( "\$(GBE_PERL) -Mjats_runutf -e processUtf", @cmdline );$me->Print();## Create entries to handle the copy-once files#foreach my $file ( @{ $pEntry->{'copyonce' } } ){my $tname = $tdir . '/' . StripDir($file);my $me = MakeEntry::New( *MAKEFILE, $tname );$me->AddDependancy( $file );$me->AddRecipe ( "\$(call CopyFile,CopyIn,$tname,$file,$tdir,)" );$me->Print();UniquePush( \@COPYIN, $tname );UniquePush( \@copy_set, $file );}}## Generate sanity test for each copyin script# Simply to provide a nice error message for generated scripts# that do not exist at run-time#test_copy_in:foreach my $i ( @copy_set ){next if ( $SCRIPTS{$i} );foreach ( @SHLIB_TARGETS ){next test_copy_in if ( $i eq $_ );}MakePrint( "\n$i:\t\tmakefile.pl\n" ."\t\@if [ ! -f \"$i\" ]; then echo 'ERROR: CopyIn Script [$i] not found'; exit 2; fi\n" );}#-------------------------------------------------------------------------------# Deploy rules#MakeHeader ("Deploy Rules");print MAKEFILE <<EOF;.PHONY: run_deployEOF## Build up the deployfile.pl command line from the available pieces#my $command_file = "";my @command_line;if ( %DEPLOYPACKAGE ){$command_file = $DEPLOYPACKAGE{'cmdfile'};push @command_line, "\$(XX_PRE)\$(GBE_PERL) -w $command_file";push @command_line, "-r \"\$(GBE_ROOT)\"";push @command_line, "-n \"$DEPLOYPACKAGE{'name'}\"";push @command_line, "-d \"$DEPLOYPACKAGE{'dir'}\"";push @command_line, "-v \"\$(BUILDVER)\"";push @command_line, "-t \"\$(GBE_TYPE)\"";push @command_line, "-o \"\$(BUILDPREVIOUSVER)\"";push @command_line, "-m \"\$(GBE_PLATFORM)\"";push @command_line, "-g \"\$(GBE_TARGET)\"";push @command_line, "-k \"\$(GBE_PRODUCT)\"" if ( $ScmProduct );push @command_line, "-p \"\$(DEPLOYPATCH)\"" if ( $ScmDeploymentPatch );}MakeEntry( "run_deploy:\t$command_file\n", "\n", "\t\t", " \\\n", @command_line );#-------------------------------------------------------------------------------# Custom Rules#MakeHeader ("Custom Rules");MakePrintList ( \@RULES );#-------------------------------------------------------------------------------# Generated Files#MakeHeader ("Generated Files");MakePrint ("\n.PHONY: phony_generate\n\n" );my $generateMustAddTestPostProcess;foreach my $i ( @GENERATE_FILES ){my $gen_tag = $i->{'index'};my $genName = 'generate_' . $gen_tag;my $me = MakeEntry::New( *MAKEFILE );$me->AddComment ('Generate Files');$me->AddName(@{$i->{'gen'}});## Generate user-provided recipe names to allow the rule to be called by name.#my $recipeTag = $i->{'recipeTag'} || '';my $recipeName = '';my $recipeCleanName = '';if ($recipeTag) {$recipeName = $recipeTag;$recipeCleanName = 'clean_' . $recipeTag;# for 'jats make help'$ScmRecipeTags{$recipeTag} = defined $i->{'clean'} ? 1 : 0;$me->Phony() ;$me->AddName($recipeName);}## If predelete is enabled, then create a list of files to delete#if ( $i->{'predelete'} ) {$me->AddDefn("generate_gen_$gen_tag", join(' ', @{$i->{'gen'}} ) );}my $target = join (' ', @{$i->{'gen'}}, $recipeName);## If a UnitTest then insert runtime defs#if ($i->{'isautf'}){my $test_name = $i->{'gen'}[0];$generateMustAddTestPostProcess = 1;push @TESTPROJECT_TO_URUN, $test_name;push @TESTPROJECT_TO_ARUN, $test_name if ($i->{'utfauto'} );$me->AddComment (' This is a Unit Test');$me->AddDefn('export GBE_UTFNAME', $test_name );$me->AddDefn('export GBE_UTFUID', 'G$(MAKEFILEUID)' . '_' . $i->{'index'});$me->AddDefn('export GBE_UTFFILE','$(UTFDIR_PKG)/$(GBE_PLATFORM)-$(GBE_TYPE)-$(GBE_UTFUID)' . '.xml');$me->AddDefn('export GBE_UTFTEST','TEST-$(GBE_UTFNAME)-$(GBE_TYPE)-$(GBE_UTFUID)' );}## Generate the basic generate rule and recipe# together with the prerequisites#unless ( $i->{'clean'} && $i->{'shell'} ){$me->AddDependancy(@{$i->{'preq'}});$me->AddDependancy("phony_generate") if $i->{'preq_sus'};$me->AddDependancy("\$(SCM_MAKEFILE)");$me->RecipePrefix ('$(AA_PRE)');$me->AddRecipe("\$(echo) '[$i->{'text'}] generating..'");$me->RecipePrefix ('$(XX_PRE)');$me->AddRecipe("\$(call RmFiles,generate_gen_$gen_tag)") if ( $i->{'predelete'} );if ($i->{'isautf'}) {my $filter = $i->{'utfformat'} || 'internal';my $uargs = join(' ', map { '-arg='. $_ } @{$i->{'utfargs' }});my $tdir = $i->{'utfdir'} || '.';$me->AddShellRecipe ( ["PATH=.\\$::ScmPathSep\$(BINDIR_LOCAL_PATH)\\$::ScmPathSep\$\$PATH","\$(call $genName,)"] ,'echo $$? > ${INTERFACEDIR}/utf.$${GBE_UTFUID}.rc',"\$(call UtfPostProcess,$filter,$tdir,$uargs)" );} else {$me->AddRecipe("\$(call $genName,)");}}$me->Print();## Generate 'clean' rules and recipes#if ( $i->{'clean'} ){my $me = MakeEntry::New( *MAKEFILE, "clean_$genName", '--Phony' );$me->AddName($recipeCleanName) if $recipeCleanName;$me->RecipePrefix('$(XX_PRE)');$me->AddRecipe("-\$(call $genName,$i->{'clean'})");$me->Print();}## Define a function to contain the body of the generation call# The first argument will be a 'clean' argument#my $md = MakeEntry::New( *MAKEFILE, $genName, '--Define' );if ( $i->{'shell'} ) {$md->AddShellRecipe( @{$i->{'toolargs'}} );} else {$md->AddOneRecipe( $i->{'tool'} . ' $1' ,@{$i->{'toolargs'}} );}$md->Print();}if ($generateMustAddTestPostProcess){## Define the UTF post processing# Define amacro thattakes two arguments# $1 - name of the filter# $2 - Directory to process# $3 - additional arguments### Create the basic command line for 'jats_runutf'# Use the simplistic 'internal' filter unless the user has provided one#my @cmdline;push @cmdline, '--';push @cmdline, '$(VERBOSE_OPT)';push @cmdline, '-filter=$1';push @cmdline, '-root=$(GBE_ROOT_ABS)' ;push @cmdline, '-dir=$2';push @cmdline, '-target=$(GBE_PLATFORM)';push @cmdline, '-pkgdir=$(PKGDIR)';push @cmdline, '-local=$(LOCALDIR)';push @cmdline, '-interface=$(INTERFACEDIR)';push @cmdline, '-rcfile=${INTERFACEDIR}/utf.$${GBE_UTFUID}.rc';push @cmdline, '$3';## Insert commands to post process the test results according to the specified formatter#my $me = MakeEntry::New( *MAKEFILE, 'UtfPostProcess', '--Define' );$me->AddComment ('Post Process a UNIT TEST');$me->AddComment (' arg1 - utffile name');$me->AddComment (' arg2 - Directory to start scan for Unit Test Results');$me->AddComment (' arg3 - Additional arguments to the filter');$me->SectionIfDef ('UTF_POSTPROCESS');$me->AddOneRecipe ("\$(GBE_PERL) -Mjats_runutf -e processUtf", @cmdline );$me->Print();}#-------------------------------------------------------------------------------# Toolset Post Processing# Allow the toolset to perform any post processing, before we finally write# out any definitions.## We will not interprete any more user directives, but new stuff may get added##MakeHeader ("Toolset Post Processing");$if->Postprocess();################################################################################# All interactions with the toolset are now complete# All lists are now complete## Can now create internal definitions################################################################################### Would be nice if this would work# Unfortunatelty we still need $if for the CCDEPENDS and CTAGS work# These must be defined AFTER the definitions## Ideally we should construct our makefile in sections# and then we can order the sections when we write them out##$if = 0; # Ensure the MakeIf class is not called# If this file is modified#-------------------------------------------------------------------------------# Sources#MakeHeader ( "Sources");MakeDefEntry( "CSRCS", "=", \@CSRCS );MakeDefEntry( "CXXSRCS", "=", \@CXXSRCS );MakeDefEntry( "ASSRCS", "=", \@ASSRCS );#-------------------------------------------------------------------------------# Generated, Installed and Packaged components#MakeHeader ("Generated, Installed and Packaged components");MakeDefEntry( "INITS", "=", \@INITS ) if ( @INITS );MakeDefEntry( "GENERATED", "=", \@GENERATED ) if ( @GENERATED );MakeDefEntry( "GENERATED_NOTSRC","=", \@GENERATED_NOTSRC ) if ( @GENERATED_NOTSRC );MakeDefEntry( "GENERATEDCLEAN", "=", CreateNameList( 'clean_generate_', '', ListCleanGenerated() ));MakeDefEntry( "INSTALL_HDRS", "=", \%INSTALL_HDRS ) if ( %INSTALL_HDRS );MakeDefEntry( "INSTALL_CLSS", "=", \%INSTALL_CLSS ) if ( %INSTALL_CLSS );MakeDefEntry( "OBJS", "=", CreateNameList( '$(OBJDIR)/', ".$::o", \@OBJS) );MakeDefEntry( "SHOBJS", "=", CreateNameList( '$(OBJDIR)/', ".$::o", \%SHOBJ_LIB ));MakeDefEntry( "PROGOBJS", "=", CreateNameList( '', ".$::o", \@PROGOBJS ));MakeDefEntry( "TESTPROGOBJS", "=", CreateNameList( '', ".$::o", \@TESTPROGOBJS ));MakeDefEntry( "LIBS", "=", $LIBS->AllTargets() ) if ($::a);MakeDefEntry( "MLIBS", "=", $MLIBS->AllTargets() ) if ($::a);MakeDefEntry( "SHNAMES", "=", \@SHLIBS );MakeDefEntry( "SHDIRS", "=", CreateNameList( '$(OBJDIR)/', "", \@SHLIBS ));MakeDefEntry( "SHLIBS", "=", \@SHLIB_TARGETS );MakeDefEntry( "SCRIPTS", "=", CreateNameList( '$(BINDIR)/', "", \%SCRIPTS ));MakeDefEntry( "COPYIN", "=", \@COPYIN );MakeDefEntry( "PROGS", "=", $PROGS->AllTargets() );MakeDefEntry( "PROGS_EXTRA", "=", \@PROGS_EXTRA );MakeDefEntry( "TESTPROGS", "=", $TESTPROGS->AllTargets());MakeDefEntry( "LINTLIBS", "=", CreateNameList( 'lib_', '_lint', \@LINTLIBS ));MakeDefEntry( "LINTSHLIBS", "=", CreateNameList( 'shlib_', '_lint', \@LINTSHLIBS ));MakeDefEntry( "LINTPROGS", "=", CreateNameList( 'prog_', '_lint', \@PROGS ));MakeDefEntry( "LINTPROGS", "+=", CreateNameList( 'prog_', '_lint', \@TESTPROGS ));MakeDefEntry( "PROJECTS", "=", CreateNameList( 'Project_', '', ListGeneratedProjects(1) ));MakeDefEntry( "PROJECTSGEN", "=", CreateNameList( 'Project_', '', ListGeneratedProjects(0) ));MakeDefEntry( "PROJECTSCLEAN", "=", CreateNameList( 'ProjectClean_', '', \%PROJECTS ));MakeDefEntry( "UNITTESTS", "=", \@TESTPROJECT_TO_URUN );MakeDefEntry( "AUTOUNITTESTS", "=", \@TESTPROJECT_TO_ARUN );MakeDefEntry( "AUTOUNITTESTS_PRE", "=", \@TOOLSET_UTF_PRE );MakeDefEntry( "AUTOUNITTESTS_POST", "=", \@TOOLSET_UTF_POST );MakeDefEntry( "AUTOUNITTESTS_COLLATE","=", \@TOOLSET_UTF_COLLATE );MakeHeader ("Toolset components");MakeDefEntry( "USERGENERATED", "=", \@USERGENERATED ) if ( @USERGENERATED );MakeDefEntry( "TOOLSETGENERATED", "=", \@TOOLSETGENERATED ) if ( @TOOLSETGENERATED );MakeDefEntry( "TOOLSETOBJS", "=", \@TOOLSETOBJS ) if ( @TOOLSETOBJS );MakeDefEntry( "TOOLSETLIBS", "=", \@TOOLSETLIBS ) if ( @TOOLSETLIBS );MakeDefEntry( "TOOLSETPROGS", "=", \@TOOLSETPROGS ) if ( @TOOLSETPROGS );MakeDefEntry( "TOOLSETDIRS", "=", \@TOOLSETDIRS ) if ( @TOOLSETDIRS );MakeDefEntry( "TOOLSETDIRTREES", "=", \@TOOLSETDIRTREES ) if ( @TOOLSETDIRTREES );MakeDefEntry( "TOOLSETCLOBFILES", "=", \@CLOBBERFILES ) if ( @CLOBBERFILES );MakeDefEntry( "TOOLSETCLOBDIRS", "=", \@CLOBBERDIRS ) if ( @CLOBBERDIRS );#--------- Determine compiler flag groups to use ----------------------------## Allows the compiler options to be controlled for both the debug and# the production builds. Allows control over# 1) Optimisations# 2) Debug Information#MakeHeader ("Determine compiler flag groups to use");print MAKEFILE <<EOF;ifneq "\$(DEBUG)" "1"USE_OPTIMISE := \$(PROD_USE_OPTIMISE)USE_DEBUGINFO := \$(PROD_USE_DEBUGINFO)elseUSE_OPTIMISE := \$(DEBUG_USE_OPTIMISE)USE_DEBUGINFO := \$(DEBUG_USE_DEBUGINFO)endifEOF#-------------------------------------------------------------------------------# Source browsing tools#MakeHeader ("Source browsing tools");print MAKEFILE <<EOF;.PHONY: ctagsctags:EOF$if->CTAGS()if (@CSRCS || @CXXSRCS);#-------------------------------------------------------------------------------# Depend# If we are build C or C++ source files then create rules and recipes# to invoke a dependency generator.## NODEPEND is used to disable, at make-time, the dependency generation# and inclusion process.##MakeHeader ("Depend");if ($::o && (@CSRCS || @CXXSRCS) && $ScmNotGeneric){$ScmDependTags = 1;print MAKEFILE <<EOF;depend: \$(OBJDIR)/depend\$(OBJDIR)/depend: \$(SCM_MAKEFILE) \$(GBE_OBJDIR)\$(OBJDIR)/depend: \$(CSRCS) \$(CXXSRCS)ifeq (\$(NODEPEND),0)\@echo '[\$@] Doing a make depend..'-\$(XX_PRE)\$(rm) -f \$(OBJDIR)/dependEOF$if->CCDepend( "\$(OBJDIR)/depend", "\$(CSRCS)" )if ( @CSRCS );$if->CXXDepend( "\$(OBJDIR)/depend", "\$(CXXSRCS)" )if ( @CXXSRCS );MakePrint"\t-\@\$(touch) -f \$(OBJDIR)/depend\n";print MAKEFILE <<EOF;else\@echo '[\$@] Skipping make depend..'-\$(XX_PRE)\$(rm) -f \$(OBJDIR)/dependendifEOF}else{print MAKEFILE <<EOF;depend:EOF}## Rule to unmake the depend file# No longer neeed.# The file is deleted as a part of the OBJDIR cleanup#print MAKEFILE <<EOF;undepend:EOF#--------- IFLAG Documentation -------------------------------------------------## IFLAG - iteration flag. This is setting by the calling process# and is a function of the phase being processed# 0 No external dependencies.# 1 Source dependency list.# 2 Shared library dependency list# 3 Application dependency list###--------- Dependencies --------------------------------------------------------# Include the 'depend' file if required#MakeHeader ("Dependency Inclusion");print MAKEFILE <<EOF;ifeq (\$(NODEPEND),0)ifdef IFLAGifneq "\$(IFLAG)" "0"-include \$(OBJDIR)/dependendifendifendifEOF#-------------------------------------------------------------------------------# Standard rules#MakeHeader ("Standard rules");print MAKEFILE <<EOF;.PHONY: make_cleanmake_clean:-\@echo "Removing generated files (objects, libraries, binaries etc)";.PHONY: rmlitterrmlitter:-\$(AA_PRE)JatsFileUtil 'D0' 'Removing litter' '.' 'core' '*.bak' '*.tmp' '*.err'.PHONY: lint_initlint_init:EOF## Dependencies for 'make_init'##my @initdep;push @initdep, '$(INITS)' if ( @INITS );## Dependencies for 'make_dir'#my @mkdirdep;push @mkdirdep, '$(GBE_OBJDIR)' if ( @CSRCS || @CXXSRCS || @OBJS || @PROGOBJS || @TESTPROGOBJS );push @mkdirdep, '$(SHDIRS)' if ( %SHOBJ_LIB || @SHLIBS);push @mkdirdep, '$(GBE_LIBDIR)' if ( @LIBS || @MLIBS || @SHLIBS || %INSTALL_LIBS || %PACKAGE_LIBS );push @mkdirdep, '$(GBE_BINDIR)' if ( @SHLIBS || %SCRIPTS || @PROGS || @TESTPROGS || %INSTALL_PROGS || %PACKAGE_PROGS );## Actions for for 'unobj'#my @unobjact;push @unobjact, RmFilesCmd( 'OBJS' ) if ( @OBJS );push @unobjact, RmFilesCmd( 'SHOBJS' ) if ( %SHOBJ_LIB );push @unobjact, RmFilesCmd( 'PROGOBJS' ) if ( @PROGOBJS );push @unobjact, RmFilesCmd( 'TESTPROGOBJS' ) if ( @TESTPROGOBJS );push @unobjact, RmFilesCmd( 'TOOLSETOBJS' ) if ( @TOOLSETOBJS );## Dependencies for 'make_lib'#my @libdep;push @libdep, '$(GBE_OBJDIR)', '$(GBE_LIBDIR)', '$(LIBS)' if ( @LIBS );## Dependencies for 'lint_lib'#my @liblintdep;push @liblintdep, 'lint_init', '$(GBE_OBJDIR)', '$(GBE_LIBDIR)', '$(LINTLIBS)' if ( @LIBS );## Dependencies for 'make_mlib'#my @mlibdep;push @mlibdep, '$(GBE_OBJDIR)', '$(GBE_LIBDIR)', '$(GBE_MLIBDIR)', '$(MLIBS)' if ( @MLIBS );## Dependencies for 'make_install_shlib' (tag)#my @shlibdep;push @shlibdep, '$(SHDIRS)', '$(SHLIBS)' if ( @SHLIBS );## Dependencies for 'lint_shlib'#my @shliblintdep;push @shliblintdep, 'lint_init', '$(GBE_LIBDIR)', '$(LINTSHLIBS)' if ( @SHLIBS );## Actions for 'unmake_lib'#my @unlibact;push @unlibact, RmFilesCmd( 'SHLIBS' ) if ( @SHLIBS );push @unlibact, RmFilesCmd( 'MLIBS' ) if ( @MLIBS );push @unlibact, RmFilesCmd( 'LIBS' ) if ( @LIBS );push @unlibact, RmFilesCmd( 'TOOLSETLIBS' ) if ( @TOOLSETLIBS );## Actions for 'unmake_mlib'#my @unmlibact;push @unmlibact, RmFilesCmd( 'MLIBS' ) if ( @MLIBS );## Dependencies for 'make_script'#my @scriptdep;push @scriptdep, '$(GBE_BINDIR)', '$(SCRIPTS)' if ( %SCRIPTS );## Actions for 'unmake_script'#my @unscriptact;push @unscriptact , RmFilesCmd( 'SCRIPTS' ) if ( %SCRIPTS );push @unscriptact , RmFilesCmd( 'COPYIN' ) if ( @COPYIN );## Dependencies for 'make_prog'#my @progdep;push @progdep, '$(GBE_OBJDIR)', '$(GBE_BINDIR)', '$(PROGS)' if ( @PROGS );push @progdep, '$(PROGS_EXTRA)' if (@PROGS_EXTRA);## Dependencies for 'make_prog' created for 'projects'#my @projectdep;push @projectdep, '$(PROJECTS)' if (ListGeneratedProjects(1) );## Dependencies for 'generate' created for 'projects'#my @projectgendep;push @projectgendep, '$(PROJECTSGEN)' if (ListGeneratedProjects(0) );## Dependencies for 'unmake_prog' created for 'projects'#my @projectcleandep;push @projectcleandep, '$(PROJECTSCLEAN)' if (%PROJECTS);## Dependencies for 'lint_prog'#my @proglintdep;push @proglintdep, 'lint_init', '$(GBE_OBJDIR)', '$(GBE_BINDIR)', '$(LINTPROGS)' if ( @PROGS || @TESTPROGS );## Actions for 'unmake_prog'#my @unprogact;push @unprogact, RmFilesCmd( 'PROGS' ) if ( @PROGS );push @unprogact, RmFilesCmd( 'TOOLSETPROGS' ) if ( @TOOLSETPROGS );## Dependencies for 'exec_tests'#my @testprogdep;push @testprogdep, '$(GBE_OBJDIR)', '$(GBE_BINDIR)', '$(TESTPROGS)' if ( @TESTPROGS );my @autoruntestdep;push @autoruntestdep, 'makefile.pl', '$(AUTOUNITTESTS)' if ( @TESTPROJECT_TO_ARUN );my @runtestdep;push @runtestdep , 'makefile.pl', '$(UNITTESTS)' if ( @TESTPROJECT_TO_URUN );## Dependencies for 'exec_tests' and friends#my @untestprogact;push @untestprogact ,RmFilesCmd( 'TESTPROGS' ) if ( @TESTPROGS );## Dependencies for 'generated'#my @generatedep;push @generatedep, '$(GENERATED)' if ( @GENERATED );## Actions for 'ungenerate'#my @ungenact;push @ungenact, RmFilesCmd( 'GENERATED' ) if ( @GENERATED );push @ungenact, RmFilesCmd( 'GENERATED_NOTSRC' ) if ( @GENERATED_NOTSRC );push @ungenact, RmFilesCmd( 'TOOLSETGENERATED' ) if ( @TOOLSETGENERATED );push @ungenact, RmFilesCmd( 'USERGENERATED' ) if ( @USERGENERATED );## Dependencies for 'ungenerate'#my @ungeneratedep;push @ungeneratedep, '$(GENERATEDCLEAN)';## Actions for clobberfiles#my @clobberfiles;push @clobberfiles, RmFilesCmd('TOOLSETCLOBFILES') if (@CLOBBERFILES);#-------------------------------------------------------------------------------# Function : PrintPhonyRule## Description : Helper function to print some internal phony makefile targets# These are used to hold the basic makefile together## Inputs : $target - Name of the phony target# $prereq - Prerequisites# Leading spaces removed# $recipe - Optional Reference to an array of recipes# Will be printed one per line##sub PrintPhonyRule{my ($target, $prereq, $recipe) = @_;$prereq =~ s/^\s+//;MakePadded( 2, '.PHONY:', $target, "\n");MakePadded( 2,"$target:", $prereq, "\n");MakePrint ("\t\t" . $_ . "\n") foreach ( @{$recipe} );MakePrint ("\n");}# make_init - Test toolset presence and sanity# Will only be called ONCE for each platform in a recursive build# Should be used to ensure that the required toolset is present#PrintPhonyRule ('make_init', "@initdep" );# make_dir - Create required subdirectories# Will be invoked as a part of most targets that create files# Will be invoked by the calling wrappers# Should not be invoked when cleaning#PrintPhonyRule ('make_dir', "@mkdirdep" );PrintPhonyRule ('generate', "@generatedep @projectgendep" );PrintPhonyRule ('ungenerate', "@ungeneratedep", \@ungenact);PrintPhonyRule ('unobj', "", \@unobjact);PrintPhonyRule ('make_lib', "@libdep" );PrintPhonyRule ('lint_lib', "@liblintdep" );PrintPhonyRule ('make_mlib', "@mlibdep" );PrintPhonyRule ('lint_shlib', "@shliblintdep" );PrintPhonyRule ('unmake_lib', "", \@unlibact );PrintPhonyRule ('unmake_mlib', "", \@unmlibact );PrintPhonyRule ('make_script', "@scriptdep" );PrintPhonyRule ('unmake_script', "", \@unscriptact );PrintPhonyRule ('make_prog', "make_script @progdep @projectdep" );PrintPhonyRule ('unmake_prog', "unmake_script @projectcleandep", \@unprogact );PrintPhonyRule ('lint_prog', "@proglintdep" );PrintPhonyRule ('exec_tests', "make_script @testprogdep @runtestdep" );PrintPhonyRule ('exec_unit_tests', "make_script @testprogdep @autoruntestdep" );PrintPhonyRule ('make_test', "make_script @testprogdep" );PrintPhonyRule ('unmake_test', "unmake_script", \@untestprogact );PrintPhonyRule ('preprocess_tests', '$(AUTOUNITTESTS_PRE)' );PrintPhonyRule ('postprocess_tests', '$(AUTOUNITTESTS_POST)' );PrintPhonyRule ('collate_test_results', '$(AUTOUNITTESTS_COLLATE)' );PrintPhonyRule ('clobberfiles', "",\@clobberfiles );#-------------------------------------------------------------------------------# Package and Installation Summary#MakeHeader ("Package and Installation Summary");sub InstallTarget{my( $target, $hashp, $prereq, $fprereq ) = @_;my( $element );my $me = MakeEntry::New( *MAKEFILE, $target, '--Phony' );$me->AddDependancy( $fprereq ) if ($fprereq);foreach my $element ( sort keys %{$hashp} ){## Skip placekeepers#next if ( $hashp->{$element}{'placekeeper'} );## Prepend any prerequisites (once)#$me->AddDependancy( $prereq ) if ( $prereq );$prereq = 0;$me->AddDependancyEscaped( $element );}$me->Print();}InstallTarget( "install_hdr", \%INSTALL_HDRS );InstallTarget( "install_lib", \%INSTALL_LIBS, 'make_mlib' );InstallTarget( "make_install_shlib",\%INSTALL_SHLIBS, '', "@shlibdep" );InstallTarget( "install_prog", \%INSTALL_PROGS, 'make_script' );InstallTarget( "install_class", \%INSTALL_CLSS );InstallTarget( "package_files", \%PACKAGE_FILES );InstallTarget( "package_hdr", \%PACKAGE_HDRS );InstallTarget( "package_lib", \%PACKAGE_LIBS );InstallTarget( "package_shlib", \%PACKAGE_SHLIBS );InstallTarget( "package_prog", \%PACKAGE_PROGS, 'make_script' );InstallTarget( "package_class", \%PACKAGE_CLSS );#-------------------------------------------------------------------------------# InstallationsMakeHeader ("Installations");PackageRule ( \&InstallCmd, \%INSTALL_HDRS );PackageRule ( \&InstallCmd, \%INSTALL_CLSS );PackageRule ( \&InstallCmd, \%INSTALL_LIBS );PackageRule ( \&InstallCmd, \%INSTALL_SHLIBS );PackageRule ( \&InstallCmd, \%INSTALL_PROGS );PackageDirRule ('install_dirs', \@INSTALL_DIRS);#-------------------------------------------------------------------------------# Packaging#MakeHeader ("Packaging");PackageRule ( \&PackageCmd, \%PACKAGE_FILES );PackageRule ( \&PackageCmd, \%PACKAGE_HDRS );PackageRule ( \&PackageCmd, \%PACKAGE_CLSS );PackageRule ( \&PackageCmd, \%PACKAGE_LIBS );PackageRule ( \&PackageCmd, \%PACKAGE_SHLIBS );PackageRule ( \&PackageCmd, \%PACKAGE_PROGS );PackageDirRule ('package_dirs', \@PACKAGE_DIRS);#-------------------------------------------------------------------------------# Uninstall/unpackaging#MakeHeader ("Uninstall/unpackaging");UnpackageRule ( 'uninstall_hdr', \&UninstallCmd, \%INSTALL_HDRS );UnpackageRule ( 'uninstall_lib', \&UninstallCmd, \%INSTALL_LIBS );UnpackageRule ( 'uninstall_shlib', \&UninstallCmd, \%INSTALL_SHLIBS );UnpackageRule ( 'uninstall_prog', \&UninstallCmd, \%INSTALL_PROGS );UnpackageRule ( 'uninstall_class', \&UninstallCmd, \%INSTALL_CLSS );PackageDirRule ( 'uninstall_dirs', \@INSTALL_DIRS);UnpackageRule ( 'unpackage_files', \&UnpackageCmd, \%PACKAGE_FILES );UnpackageRule ( 'unpackage_hdr', \&UnpackageCmd, \%PACKAGE_HDRS );UnpackageRule ( 'unpackage_lib', \&UnpackageCmd, \%PACKAGE_LIBS );UnpackageRule ( 'unpackage_shlib', \&UnpackageCmd, \%PACKAGE_SHLIBS );UnpackageRule ( 'unpackage_prog', \&UnpackageCmd, \%PACKAGE_PROGS );UnpackageRule ( 'unpackage_class', \&UnpackageCmd, \%PACKAGE_CLSS );PackageDirRule ( 'unpackage_dirs', \@PACKAGE_DIRS);#-------------------------------------------------------------------------------# Distribution Sets#MakeHeader ("Distribution Sets");PackageSetRules();#-------------------------------------------------------------------------------## Subdir deletion# This is done AFTER the toolset functions have been invoked to create the# build artifacts so that the toolsets can create directories too## Note: Toolset directories are deleted first# Note: User Directories are deleted in the reverse order of creation## Add them into the directory data structure#foreach my $path ( @TOOLSETDIRS ){MkdirRule( $path, '', '--NoCreate' );}foreach my $path ( @TOOLSETDIRTREES ){MkdirRule( $path, '', '--NoCreate' , '--RemoveAll');}MakeHeader ("Subdir deletion");RmdirRules();ClobberDirsRule();MakeNewLine();#--------- Toolset Rules -------------------------------------------------------MakeHeader ("Toolset Rules");MakePrintList ( \@TOOLSETRULES );#--------- Maketags ------------------------------------------------------------Maketag( "make_init", @INITS );Maketag( "make_dir", @mkdirdep );Maketag( "generate", @generatedep || @projectgendep || @USERGENERATED || ($ScmToolsetGenerate != 0) );Maketag( "depend", $ScmDependTags != 0 );Maketag( "make_lib", @libdep );Maketag( "make_mlib", @mlibdep );Maketag( "make_install_shlib", %INSTALL_SHLIBS || @shlibdep);Maketag( "make_script", @scriptdep );Maketag( "make_prog", @progdep || @projectdep );Maketag( "make_test", @testprogdep );Maketag( "exec_tests", $TESTS_TO_RUN || @TESTPROJECT_TO_URUN );Maketag( "exec_unit_tests", $TESTS_TO_AUTORUN || @TESTPROJECT_TO_ARUN );Maketag( "process_tests", @TOOLSET_UTF_PRE || @TOOLSET_UTF_POST || @TOOLSET_UTF_COLLATE);Maketag( "install_hdr", %INSTALL_HDRS );Maketag( "install_class", %INSTALL_CLSS );Maketag( "install_lib", %INSTALL_LIBS );Maketag( "install_prog", %INSTALL_PROGS );Maketag( "install_dirs", @INSTALL_DIRS );Maketag( "deploy", %DEPLOYPACKAGE );Maketag( "package", %PACKAGE_FILES || %PACKAGE_HDRS || %PACKAGE_CLSS ||%PACKAGE_LIBS || %PACKAGE_SHLIBS || %PACKAGE_PROGS );## Display tags in the MAKEFILE# Not used here - just for show#MakeHeader ("Maketags");foreach my $tag ( sort keys %MakeTags ){MakePadded( 3, "# $tag:", '1', "\n");}#-------------------------------------------------------------------------------# End of Makefile#MakeHeader ("End of Makefile");close( MAKEFILE );## Save all platform information# Done after the makefile is written as toolsets can extend the data#WriteParsedConfig();## Write out any accumulated DPACKAGE data#JatsDPackage::DPackageSave();return 0;}#-------------------------------------------------------------------------------# Function : QuoteForMake## Description : Escape/Quote a pathname for make# Allow files with a $ in the name# Allow files with a space in the name# Allow files with a comma in the name# Allow for paths that have make-varible prefixes# $(GBE_...) or ${GBE_...} or $(OBJDIR) or $(BUILDVERNUM)# as these may be generated internally# Allow for files with a colon in the name# Mode dependent# 0 - No effect# T - \\\:# S = \:## Must also allow $(GBE_TYPE) in the remainder## Inputs : uarg - Arg to quote# mode - Mode of operation# T - Makefile target# S - Makefile source# 0 - Neither## Returns : Quoted arg#sub QuoteForMake($;$){my ($uarg, $mode) = @_;$mode = '0' unless defined $mode;## Split into two# $(xxx)/ - Makefile variables# Remainder - Stuff to quote#$uarg =~ m~^((\$\(.*?\)/)*)(.*)~;my $prefix = defined $1 ? $1 : '';my $arg = defined $3 ? $3 : '';$arg =~ s~\$(?!\(GBE_[A-Z]+\)|{GBE_[A-Z]+}|\(OBJDIR\)|\(BUILDVERNUM\))~\$\$~g; # $, not followed by (GBE_ or ${GBE_ or (OBJDIR)- is not $(GBE_ AND not $(OBJDIR)$arg =~ s~ ~\\ ~g;$arg =~ s~,~\$(comma)~g;$arg =~ s~%~\\%~g;$arg =~ s~:~\\\\\\:~g if ($mode eq 'T' && $::ScmHost eq "Unix");$arg =~ s~:~\\:~g if ($mode eq 'S' && $::ScmHost eq "Unix");return $prefix . $arg;}#-------------------------------------------------------------------------------# Function : Maketag## Description : Create Makefile tags to speed up recursive makes## Inputs : tag_name# dep## Returns :#sub Maketag{my( $tag, $dep ) = @_;$MakeTags{$tag} = 1 if ( defined($dep) && $dep );}#-------------------------------------------------------------------------------# Function to create and delete directories within the build system## To stop make regenerating directory dependent targets each time the# directory content is modified, rule should only be dependent on a internally# created alias file 'gbedir', which represents the time a dir was created not# last modified.## Must use tags like GBE_BINDIR, GBE_LIBDIR and GBE_OBJDIR to ensure that the# directories are created correctly.#my %MkdirRuleData;my @MkdirRuleOrder;my $MkdirRulePrinting = 0;my $MkdirRuleGbeFile = ( $::ScmHost eq "Unix" ) ? ".gbedir" : "_gbedir";#-------------------------------------------------------------------------------# Function : MkdirRule## Description : Create Rules and Recipes to create a directory at make-time# Mark the information for such that the directories will# be deleted in a 'clean'## Can be called before we start writing the makefile# Such entries will be retained and dumped at a known time## Inputs : $subdir - Symbolic name of the subdir $(OBJDIR)# $alias - Optional script alias for the dir 'OBJDIR' --> GBE_OBJDIR# Options:# --Path=path Optional value of $subdir '$(GBE_PLATFORM)$(GBE_TYPE).OBJ'# --RemoveAll Remove all files on clean# --Extra=file[,file] Additional files to remove# --NoCreate Do not Create the Directory, just delete it## Returns : Nothing#sub MkdirRule{my( $subdir, $alias, @opts ) = @_;## Create data entry once#$alias =~ s~^GBE_~~ if $alias;unless ( $MkdirRuleData{$subdir} ){my %data;## Parse options#foreach ( @opts ){if ( /^--Path=(.+)/ ) {$data{path} = $1;} elsif ( /^--RemoveAll/ ) {$data{remove_all} = 1;} elsif ( /^--NoCreate/ ) {$data{noCreate} = 1;} elsif ( /^--Extra=(.+)/ ) {@{$data{extraFiles}} = split(/,/, $1);} else {Error ("MkdirRule: Unknown option: $_");}}$data{alias} = $alias if ( $alias );$MkdirRuleData{$subdir} = \%data;push @MkdirRuleOrder, $subdir;}## Save or print#return unless ( $MkdirRulePrinting );return if ( $MkdirRuleData{$subdir}{noCreate} );## Create a definition of the physical directory#my $path = $MkdirRuleData{$subdir}{path};MakePadded (2, $alias, ":= $path\n") if ( $path && $alias );# Create an alias to be used within rules# The defined aliase will be prefixed with 'GBE_'#MakePadded (2, "GBE_$alias", ":= $subdir/$MkdirRuleGbeFile\n") if ( $alias );## Create a recipe to create the directory# This is not as simple as it sounds# The touch is required.# Had 'timestamp' issues on solaris'. The 'echo' did not appear# to be enough. Perhaps the output was not flushed#MakePadded (2, "$subdir", ": $subdir/$MkdirRuleGbeFile\n");MakePrint"$subdir/$MkdirRuleGbeFile:\n"."\t\$(XX_PRE)if [ ! -d $subdir ]; then \$(mkdir) -p $subdir; fi; \\\n"."\t\$(echo) '# DO NOT REMOVE.' > \$@; \\\n"."\t\$(touch) \$@\n\n";}#-------------------------------------------------------------------------------# Function : RmdirRules## Description : Create the body of a recipe to delete the directories that# have been created.## Use JatsFileUtil rather than shell script# Faster under windows (and others)# Solved long pathname issues# Simpler to use and control## Inputs : Uses $MkdirRuleData## Returns : Nothing.# Prints to the makefile#sub RmdirRules{MakePrint( ".PHONY:\tunmake_dir\n" );MakePrint( "unmake_dir:\n" );## Determine the list of directories to delete# Sort such that subdirs are deleted first#my $txt = 'Removing directories';foreach my $subdir ( reverse sort keys %MkdirRuleData ){my @args = $subdir;push (@args, $MkdirRuleGbeFile, 'core', '*.bak', '*.tmp', '*.err', 'utf.*.rc')unless $MkdirRuleData{$subdir}{remove_all};push (@args, @{$MkdirRuleData{$subdir}{extraFiles}})if ( $MkdirRuleData{$subdir}{extraFiles} );my $mode = $MkdirRuleData{$subdir}{remove_all} ? 'T0' : 'D0';MakePrint ("\t-\$(AA_PRE)JatsFileUtil ", QuoteArray( $mode, $txt, @args ), "\n");$txt = '';}}#-------------------------------------------------------------------------------# Function : ClobberDirsRule## Description : Create the body of a recipe to delete the directories that# will be removed in a clobber## Use JatsFileUtil rather than shell script# Faster under windows (and others)# Solved long pathname issues# Simpler to use and control## Inputs : @CLOBBERDIRS## Returns : Nothing.# Prints to the makefile#sub ClobberDirsRule{MakeNewLine();MakePrint( ".PHONY:\tclobberdirs\n" );MakePrint( "clobberdirs:\n" );## Determine the list of directories to delete# Sort such that subdirs are deleted first#my $txt = 'Removing toolset directories';foreach my $subdir ( reverse sort @CLOBBERDIRS ){my @args = $subdir;MakePrint ("\t-\$(AA_PRE)JatsFileUtil ", QuoteArray( 'T0', $txt, @args ), "\n");$txt = '';}}#-------------------------------------------------------------------------------# Function : CreateMkdirRules## Description : Create Rules to make dirs at runtime# This function is called to instantiate those entries# That have been requested before the makefile has has# started to be created.## Once this function has been called all new MkdirRule calls# will result in the recipes being created in-line.## Inputs : Nothing## Returns : Even Less##sub CreateMkdirRules{$MkdirRulePrinting = 1;foreach my $subdir ( @MkdirRuleOrder ){my $data = $MkdirRuleData{$subdir};MkdirRule($subdir, $data->{alias}, $data->{path} );}}#-------------------------------------------------------------------------------# Function : PackageRule## Description : Generate rules and recipes to "install" and "package" files## Inputs : codecmd - A code reference to the actual installer routine# hashp - A reference to a INSTALL or PACKAGE hash## hashp is a reference to a hash# The key is the full path of the install target# The value is (another) hash that describes the install options## Valid keys are:# src - Path of the source file [Mandatory]# dir - Target directory [Mandatory]## defined - Copy the file only if value is defined# Exists - Copy the file only if it exists# exe - Mark the file as executable# Mode - File modes. Default is -w# placekeeper - Marks SHARED library placekeepers# set - Distribution sets# type - Copy the file in DEBUG or PROD mode# Valid values are "D" or "P"# version - Shared library version information# symlink - File is a symlink# RemoveOnly - Do not install the file. Entries are# created to allow the removal of the file# NoTarget - Reserved - Implemented elsewhere## Returns :#sub PackageRule{my ($codecmd, $hashp) = @_;foreach my $dest ( keys %{$hashp} ){my $entry = $hashp->{$dest};my $destText = QuoteForMake($dest,'T');## Skip placekeepers#next if ( $entry->{'placekeeper'} );## Some entries are not installed via this mechanism, but can be removed# if they exist. Mark these as PHONY to keep targets happy#if ( $entry->{'RemoveOnly'} ){MakePrint ".PHONY:\t$destText\n";MakePrint "$destText:\n\n";next;}my $fname = $entry->{'src'};my $fnameText = QuoteForMake($fname,'S');my $fmode = $entry->{'Mode'};$fmode .= "+x" if ( $entry->{'exe'} );$fmode .= "+l" if ( $entry->{'symlink'} );## User conditionional# Mark both the source and the target as PHONY if the condition is not met# This will ensure that the target need not be built.#my $udef = $entry->{'defined'};if ( $udef ){MakePrint "ifndef $udef \n";MakePrint ".PHONY:\t\t$destText\n";MakePrint ".PHONY:\t\t$fnameText\n";MakePrint "$destText:\n";MakePrint "else\n"}## File exists# Only package the file if it has been generated. ie: .exe.manifest#my $fexist = $entry->{'Exists'};if ($fexist){MakePrint "ifeq (\"\$(wildcard $fnameText)\",\"\")\n";MakePrint ".PHONY:\t\t$destText\n";MakePrint "$destText:\n";MakePrint "else\n"}## Conditional installation for DEBUG/PRODUCTION#my $type = $entry->{'type'};if ( $type ){if ( $type eq "D" ) {MakePrint 'ifeq "$(DEBUG)" "0"'."\n";} elsif ( $type eq "P" ) {MakePrint 'ifneq "$(DEBUG)" "0"'."\n";} else {Error("INTERNAL: Unexpected packaging type: $type");}MakePrint ".PHONY:\t\t$destText\n";MakePrint "$destText:\n";MakePrint "else\n"}## The body of the copy#MakePadded( 4, $destText . ':' );MakePrint "\t" . $fnameText . "\n";MakePrint $codecmd->( $dest, $fname, $fmode );MakeNewLine();## Unwind conditionals#MakePrint "endif\n" if ( $type );MakePrint "endif\n" if ( $fexist );MakePrint "endif\n" if ( $udef );## Distribution sets#my $dist = $entry->{'set'};if ( $dist ){foreach my $set ( split( ',', $dist ) ){push @{$PACKAGE_SETS{$set}{LIST}}, $dest;}MakeNewLine();}}}#-------------------------------------------------------------------------------# Function : PackageDirRule## Description : Generate special rules for dynamic packaging/installation of directories## Inputs : $mode - package_dirs/unpackage_dirs/install_dirs/uninstall_dirs# $dataRef - Ref to package/install list### Returns :#sub PackageDirRule{my ($mode, $dataRef) = @_;my $me = MakeEntry::New( *MAKEFILE, $mode , '--Phony' );my $modeText = 'packaging';my $cmdText = 'PackageDir';if ($mode =~ m~install~) {$modeText = 'installing';$cmdText = 'InstallDir';}my $cmd = 'copyDir';if ($mode =~ m~^un~) {$cmd = 'unCopyDir';$modeText = 'un' . $modeText;$cmdText = 'Un' . $cmdText;}foreach my $entry ( @{$dataRef}) {$me->NewSection();## Conditional installation for DEBUG/PRODUCTION#my $type = $entry->{'type'};if ( $type ){if ( $type eq "D" ) {$me->SectionIfNeq('$(DEBUG)','0');} elsif ( $type eq "P" ) {$me->SectionIfEq('$(DEBUG)','0');} else {Error("INTERNAL: Unexpected packaging type: $type");}}## Quote the REs so that they can be passed to a command line# Replace $ with $$#my $QuoteRe = sub {my ($arg) = @_;$arg=~ s~\$~\$\$~g;return $arg;};## The body of the copy# Create a command line for run-time command#my @cmd;push @cmd, '$(JatsRunTime)', $cmd, '--', '-$(VERBOSE_OPT)', '--Name='. $cmdText, '--';push @cmd, '-mode=' . $modeText;push @cmd, "'" . '-src=' . $entry->{dirTree} . "'";push @cmd, "'" . '-dst=' . $entry->{dir} . "'";push (@cmd, '-execute' ) if $entry->{exefile};push (@cmd, '-noSymlink' ) if $entry->{noPreserveSymlink};push (@cmd, '-noRecurse' ) if $entry->{noRecurse};push (@cmd, '-stripBase' ) if $entry->{strip_base};push (@cmd, "'" . '-exclude+=' . $QuoteRe->($_) . "'" ) foreach @{$entry->{exclude}};push (@cmd, "'" . '-include+=' . $QuoteRe->($_) . "'" ) foreach @{$entry->{include}};push (@cmd, "'" . '-excludeRe+=' . $QuoteRe->($_) . "'" ) foreach @{$entry->{excludeRe}};push (@cmd, "'" . '-includeRe+=' . $QuoteRe->($_) . "'" ) foreach @{$entry->{includeRe}};$me->AddRecipe(join(' ', @cmd ) );}$me->Print();}#-------------------------------------------------------------------------------# Function : PackageSetRules## Description : Generate the packageset rules# These appear to be a now-defuct feature## By default all packaged files are a part of package_setALL## Inputs : None# Takes data from %PACKAGE_SET## Returns : Nothing#sub PackageSetRules{foreach my $set ( sort keys %PACKAGE_SETS ){my $me = MakeEntry::New( *MAKEFILE, "package_set$set", '--Phony' );$me->AddDependancyEscaped( @{$PACKAGE_SETS{$set}{LIST}} );$me->Print();}}#-------------------------------------------------------------------------------# Function : UnPackageRule## Description : Generate rules and recipes to "uninstall" and "unpackage" files## Inputs : target - Name of the target# codecmd - A code reference to the actual installer routine# hashp - A reference to a INSTALL or PACKAGE hash## Returns :#sub UnpackageRule{my ($target, $codecmd, $hashp) = @_;MakePrint ".PHONY:\t\t"."$target\n";MakePrint "$target:\t";foreach my $dest ( sort keys %{$hashp} ){my $entry = $hashp->{$dest};## Skip placekeepers#next if ( $entry->{'placekeeper'} );MakePrint "\n" . $codecmd->($dest);}MakePrint "\n\n";}## Internal macro interface, see RULE.STD for definitions:#sub RmFilesCmd{my ( $list ) = @_;return "\$(call RmFiles,$list)";}sub InstallCmd{my( $dest, $file, $fmode ) = @_;$fmode = "-w" # default, read-onlyif ( !defined( $fmode ) || $fmode eq "" );$dest = QuoteForMake($dest);$file = QuoteForMake($file);return "\t\$(call InstallFile,$dest,$file,$fmode)";}sub UninstallCmd{my( $file ) = @_;$file = QuoteForMake($file);return "\t\$(call UninstallFile,$file)";}sub PackageCmd{my( $dest, $file, $fmode ) = @_;$fmode = "-w" # default, read-onlyif ( !defined( $fmode ) || $fmode eq "" );$dest = QuoteForMake($dest);$file = QuoteForMake($file);return "\t\$(call PackageFile,$dest,$file,$fmode)";}sub UnpackageCmd{my( $file ) = @_;$file = QuoteForMake($file);return "\t\$(call UnpackageFile,$file)";}1;