Rev 4192 | Blame | Compare with Previous | Last modification | View Log | RSS feed
## Module name : CSHARP# Module type : Makefile system# Compiler(s) : ANSI C# Environment(s): WIN32## Description:# CSHARP for Windows##............................................................................#use strict;use warnings;use File::Basename;use File::Spec::Functions;use MakeEntry;## External data#our %SRC_DEPEND;## Global data#my %resource_files;my $pdb_none;my $toolset_name = 'csharp'; # Toolset name : Error reportingmy $toolset_info;my $toolset_version = '1.1';my %ToolsetVersion =('1.1' => { 'def' => 'CSHARP.DEF', # Def file to use'pragma' => 0, # True: Compiler supports #pragma'warnings' => '', # Comma sep list of warnings to ignore},'2.0' => { 'def' => 'CSHARP2005.DEF','pragma' => 1,'warnings' => '1668',},'3.5' => { 'def' => 'CSHARP2008.DEF','pragma' => 1,'warnings' => '1668',},'4.0' => { 'def' => 'CSHARP2010.DEF','pragma' => 1,'warnings' => '1668','platform' => 'x86',},'4.5' => { 'def' => 'CSHARP2012.DEF','pragma' => 1,'warnings' => '1668','platform' => 'x86',},'4.6' => { 'def' => 'CSHARP2015.DEF','pragma' => 1,'warnings' => '1668','platform' => 'x86',},);############################################################################### ToolsetInit()# Runtime initialisation###############################################################################ToolsetInit();sub ToolsetInit{#.. Parse arguments (Toolset arguments)#Debug( "$toolset_name(@::ScmToolsetArgs)" );foreach $_ ( @::ScmToolsetArgs ) {if (/^--Version=(.*)/) { # MS SDK Version$toolset_version = $1;} else {Message( "$toolset_name toolset: unknown option $_ -- ignored\n" );}}#.. Parse arguments (platform arguments)#Debug( "$toolset_name(@::ScmPlatformArgs)" );foreach $_ ( @::ScmPlatformArgs ) {if (/^--product=(.*)/) { # GBE product} elsif (/^--Version=(.*)/) { # MS SDK Version$toolset_version = $1;} else {Message( "$toolset_name toolset: unknown platform argument $_ -- ignored\n" );}}#.. Validate SDK version# Currently supported versions are described in a HASH#$toolset_info = $ToolsetVersion{$toolset_version};Error( "$toolset_name toolset: Unknown version: $toolset_version" ) unless ( defined $toolset_info );#.. Standard.rul requirements#$::s = undef;$::o = '';$::a = 'netmodule';$::so = 'dll';$::exe = '.exe';#.. Toolset configuration#$::ScmToolsetVersion = "1.0.0"; # our version$::ScmToolsetGenerate = 0; # generate optional$::ScmToolsetProgDependancies = 0; # handle Prog dependancies myself%::ScmToolsetProgSource = ( # handle these files directly'.cs' => '', # Will be flagged as "CSRCS"'.resx' => '--Resource=', # Will be passed with prefix'.dtd' => '--Dtd=', # Will be passed with prefix);#.. define Visual C/C+ environmentInit( "csharp" );ToolsetDefines( $toolset_info->{'def'} );ToolsetRules( "csharp.rul" );# ToolsetRules( "standard.rul" );#.. Extend the CompilerOption directive# Create a standard data structure# This is a hash of hashes# The first hash is keyed by CompileOption keyword# The second hash contains pairs of values to set or remove#%::ScmToolsetCompilerOptions =(## Control the thread model to use# This will affect the compiler options and the linker options#'noaddlibs' => { 'ADDLINKLIBS' , undef }, # Don't add link libs'addlibs' => { 'ADDLINKLIBS' , '1' }, # default'nowarn=' => { 'NOWARNLIST' ,\&NoWarns }, # Suppress warnings'nopdb' => { 'PDB_NONE', 1 }, # Disable all PDB files'pdb' => { 'PDB_NONE', undef }, # Enable PDB files: Default'subsystem:windows' => { 'LDSUBSYSTEM' , 'winexe' },'subsystem:console' => { 'LDSUBSYSTEM' , 'exe' },'platform:32' => { 'NET_PLATFORM', 'x86' },'platform:64' => { 'NET_PLATFORM', 'x64' },'platform:any' => { 'NET_PLATFORM', undef },'noversiondll' => { 'NO_VERSIONED_DLLS', 1 },);## Set default options#$::ScmCompilerOpts{'ADDLINKLIBS'} = '1';$::ScmCompilerOpts{'NOWARNLIST'} = $toolset_info->{'warnings'};$::ScmCompilerOpts{'LDSUBSYSTEM'} = 'winexe';$::ScmCompilerOpts{'NET_PLATFORM'} = $toolset_info->{'platform'};$::ScmCompilerOpts{'NO_VERSIONED_DLLS'} = undef;}#-------------------------------------------------------------------------------# Function : NoWarns## Description : ScmToolsetCompilerOptions extension function# Accumulates the NoWarn options as a comma seperated list## Inputs : $key - Name of the Option# $value - Option Value. Comma sep list of numbers# $ukey - User key (within $::ScmCompilerOpts)## Returns : New sting to save#sub NoWarns{my ($key, $value, $ukey) = @_;my @NoWarnList = split (',', $::ScmCompilerOpts{$ukey});UniquePush ( \@NoWarnList, split (',', $value) );return join ',', @NoWarnList;}############################################################################### ToolsetPreprocess()# Process collected data before the makefile is generated# This, optional, routine is called from within MakefileGenerate()# It allows the toolset to massage any of the collected data before# the makefile is created###############################################################################sub ToolsetPreprocess{## Extract the current state of PDB_NONE# Are PDB files to be constructed.#$pdb_none = $::ScmCompilerOpts{'PDB_NONE'};}############################################################################### ToolsetPostprocess# Process collected data as the makefile is generated# This, optional, routine is called from within MakefileGenerate()# It allows the toolset to massage any of the collected data before# the makefile is finally closed created###############################################################################sub ToolsetPostprocess{## Generate Recipes to create Resource Files# This is done outside of the Prog and Lib routines# so that they can be agregated## Note: don't make the makefile a dependant as changes to the# makefile won't affect the file#for my $resource ( sort keys %resource_files ){my $src = $resource_files{$resource}{src};my $root = $resource_files{$resource}{root};my $me = MakeEntry::New (*MAKEFILE, $resource );$me->AddComment ("Build Resource: $root" );# $me->AddDependancy ( '$(SCM_MAKEFILE)' );$me->AddDependancy ( $src );if ( exists $SRC_DEPEND{$src} ){$me->AddDependancy ( split( /$;/, $SRC_DEPEND{$src} ) );}$me->AddRecipe ( '$(RESGEN)' );$me->Print();## Add to the deletion list#ToolsetGenerate( $resource );}}#-------------------------------------------------------------------------------# Function : Toolset_genres## Description : Internal function to assist in the creation of a resource# In many cases it will create an entry for later processing## Inputs : $subdir - Root of the target directory for the generated# resource file# $src - Path to the source resource file## Returns : Path to the generated resource file# This will be FQN named file# Path to the associated .CS file## Notes : Create and maintain the %resource_files hash# Key is the path to the compiled file# Values are:# {src} - Path to the source file# {root} - Basic file name (Display Purposes Only)## Need to create a '.resource' file with a FQN name# This is not that simple. Need to# 1) Extract the (optional) ThisName from the .resx file# If not specified then the ThisName is the rootfilename# without any .as[pca]x extension.# 2) Extract the namespace from the associated .cs file# 3) FQN = NameSpace.ThisName##sub Toolset_genres{my ($subdir, $src ) = @_;## Ensure that the .cs file also exists# We may have a NAME.Designer.cs or a NAME.cs file - Different VS versions do it differently# The file 'should' be in the same directory, but may be in the parent#my $csfile;my @csNames = qw(.Designer.cs .cs);my @csDirs = qw( . ..);my($csfilename, $csdirectories, $cssuffix) = fileparse($src, '.resx');csScan:foreach my $dir (@csDirs){foreach my $name (@csNames) {my $testPath = catfile($csdirectories, $dir ,$csfilename . $name);if (-f $testPath){$csfile = $testPath;$csfile =~ s~\\~/~g;last csScan;}}}# Warn if we can't find one.# Create a dummy name - may fail later#unless ($csfile){Warning ("$toolset_name toolset: Resx File without a .cs or Designer.cs file", "File: $src");($csfile = $src) =~ s~\.resx$~.cs~;}## Scan the .resx file looking for the ThisName element# A very simple and crude parser#my $ThisName;my $ThisNameGuess;open ( SCAN, '<', $src ) || Error ("Cannot open file for reading: $!", "File: $src" );while ( <SCAN> ){if ( m~\<data name=\"\$this\.Name\"\>~ ){# Next line will contain the needed data itemmy $element = <SCAN>;$element =~ m~\<.+\>(.+)\</.+\>~;$ThisName = $1;Error ("$toolset_name toolset: Resx parsing: Bad this.Name", "File: $src") unless $ThisName;$ThisName =~ s~\s+~~g;last;}}close SCAN;## Name not found# Use a default. Filename with any .aspx, .asax, .ascx removed#unless ( $ThisName ){$ThisNameGuess = $ThisName;$ThisNameGuess = StripDirExt($src);$ThisNameGuess =~ s~\.as[pac]x~~i;}## Scan the.cs file looking for the namespace and class# A very simple and crude parser#my $NameSpace;my $ClassName;open ( SCAN, '<', $csfile ) || Error ("Cannot open file for reading: $!", "File: $csfile" );while ( <SCAN> ){next if ( m ~\s*//~);if ( m~namespace\s+(\S+)~ ) {$NameSpace = $1;} elsif ( m~\s+class\s+(\S+)~ ) {$ClassName = $1;}last if ( defined($NameSpace) && defined($ClassName) );}close SCAN;Error ("$toolset_name toolset: Resx parsing: NameSpace not found", "File: $csfile") unless $NameSpace;## Need to create an output file name that is a function of the FQN# To be backwardly compatible# Use the ClassName - if it was found# Else Use the ThisName - if it was found# Else Use the Guessed ThisName#if ( !defined($ClassName)) {$ClassName = $ThisName;if ( !defined($ClassName)) {$ClassName = $ThisNameGuess;}}my $root = "$NameSpace.$ClassName.resources";my $resource = $subdir . '/' . $root;$resource_files{$resource}{src} = $src;$resource_files{$resource}{root} = $root;return $resource, $csfile;}#-------------------------------------------------------------------------------# Function : Toolset_gensnk## Description : Function to create a wrapper file for the processing# of a StrongNameKey file## Create only one wrapper per SNK file## Inputs : $name - Name of component# $snk - Path to the SNK file## Returns : Path to the wrapper file#my %snk_data;sub Toolset_gensnk{my ($name, $snk ) = @_;my $file = StripDirExt( $snk );## Only create the file once# Otherwise we will get nasty make messages#if ( exists $snk_data{$snk} ){return $snk_data{$snk}{output};}## Determine the target name# Create the source file in the currentt directory# If we build it in the OBJ directory we get two files#my $snk_file = '$(OBJDIR)/' . "Jats_${file}.cs";$snk_data{$snk}{output} = $snk_file;ToolsetGenerate( $snk_file );## Determine the Tag Name# Used to conatin information in the makefile#my $tag = "${file}_snk";## Create Rules and Recipes to create the SNK wrapper file#my $me = MakeEntry::New (*MAKEFILE, $snk_file );$me->AddComment ("Build Strong Name Key File Wrapper: $snk" );$me->AddDependancy ( $snk );$me->AddDependancy ( '$(SCM_MAKEFILE)' );$me->AddRecipe ( '$(call GenSnkWrapper,' . $tag . ')' );$me->Print();## Create the data t be placed into the wrapper file#my ($io) = ToolsetPrinter::New();my $ms_snk = $snk;$io->Label( "SNK Wrapper file content", $tag ); # label$io->SetTag( $tag ); # macro tag$io->Cmd( '// This is JATS GENERATED FILE' );$io->Cmd( '// Do not edit' );$io->Cmd( '// Do not version control' );$io->Cmd( 'using System.Reflection;' );$io->Cmd( 'using System.Runtime.CompilerServices;' );$io->Cmd( '//' );$io->Cmd( '// In order to sign your assembly you must specify a key to use. Refer to the' );$io->Cmd( '// Microsoft .NET Framework documentation for more information on assembly signing.' );$io->Cmd( '//' );$io->Cmd( '// Use the attributes below to control which key is used for signing.' );$io->Cmd( '//' );$io->Cmd( '// Notes:' );$io->Cmd( '// (*) If no key is specified, the assembly is not signed.' );$io->Cmd( '// (*) KeyName refers to a key that has been installed in the Crypto Service' );$io->Cmd( '// Provider (CSP) on your machine. KeyFile refers to a file which contains' );$io->Cmd( '// a key.' );$io->Cmd( '// (*) If the KeyFile and the KeyName values are both specified, the' );$io->Cmd( '// following processing occurs:' );$io->Cmd( '// (1) If the KeyName can be found in the CSP, that key is used.' );$io->Cmd( '// (2) If the KeyName does not exist and the KeyFile does exist, the key' );$io->Cmd( '// in the KeyFile is installed into the CSP and used.' );$io->Cmd( '// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility.' );$io->Cmd( '// When specifying the KeyFile, the location of the KeyFile should be' );$io->Cmd( '// relative to the project output directory which is' );$io->Cmd( '// %Project Directory%\obj\<configuration>. For example, if your KeyFile is' );$io->Cmd( '// located in the project directory, you would specify the AssemblyKeyFile' );$io->Cmd( '// attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")]' );$io->Cmd( '// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework' );$io->Cmd( '// documentation for more information on this.' );$io->Cmd( '//' );$io->Cmd( '[assembly: AssemblyDelaySign(false)]' );$io->Cmd( '#pragma warning disable 1699' ) if ($toolset_info->{'pragma'});$io->Cmd( '[assembly: AssemblyKeyFile(@"'. $snk .'")]' );$io->Cmd( '#pragma warning restore 1699' ) if ($toolset_info->{'pragma'});$io->Cmd( '[assembly: AssemblyKeyName("")]' );$io->Newline();## Return the path to where the file will be created#return $snk_file;}################################################################################ ToolsetLD( $name, \@args, \@objs, \@libraries )# This subroutine takes the user options and builds the rules# required to link the program 'name'.## Arguments:# $name - Name of the target program# $pArgs - Ref to an array of argumennts# $pObjs - Ref to an array of object files# $pLibs - Ref to an array of libraries## Output:# Makefile recipes to create the Program## Notes:# This Program Builder will handle its own dependancies# It will also create rules and recipes to construct various# parts directly fromm source## Options:# --Resource=file.resx# --Dtd=file.dtd# --Icon=file# --Entry=xxxxx # Entry point# --Console # Console app# --Windows # Windows app (default)# --DLL # As a DLL (No P|D)# --Doc# --NoPDB# CSharpSourceFile#################################################################################sub ToolsetLD{my ( $name, $pArgs, $pObjs, $pLibs ) = @_;my ( @reslist, @resources, @csource, @dtd );my $no_pdb = $pdb_none;my $entry;my $noaddlibs;my $icon;my $docFile;my ($base, $root, $full );my $link_target = $::ScmCompilerOpts{'LDSUBSYSTEM'};my $snk;my $is_a_dll;#.. Parse arguments#foreach ( @$pArgs ) {if (/^--Resource=(.+)/) { # Resource definitionpush @reslist, MakeSrcResolve($1);} elsif (/^--Dtd=(.+)/) { # dtd definitionpush @dtd, MakeSrcResolve($1);} elsif (/^--Icon=(.+)/) {Error ("$toolset_name LD: Only one Icon file allowed") if ( $icon );$icon = MakeSrcResolve($1);} elsif (/^--StrongNameKey=(.+)/) {Error ("$toolset_name LD: Only one SNK file allowed") if ( $snk );$snk = MakeSrcResolve($1);} elsif (/^--Entry=(.+)/) {$entry = $1;} elsif (/^--Doc/) {$docFile = 1;} elsif (/^--Windows/) {$link_target = 'winexe';} elsif (/^--Console/) {$link_target = 'exe';} elsif (/^--DLL/) {$is_a_dll = 1;} elsif (/^--NoPDB$/) {$no_pdb = 1;} elsif ( !/^-/ ) {push @csource, MakeSrcResolve($_);} else {Message( "$toolset_name LD: unknown option $_ -- ignored\n" );}}## Determine the target output name#$base = $name;$root = "\$(BINDIR)/$base";$full = $root . $::exe;$docFile = "$root.xml" if ( $docFile );## Special case for DLLs that need to be created without a D or P mangled# into the name. Create them as Progs just to fool the system# Used when creating specialised web services#if ( $is_a_dll ){## Create a phony target# The EXE name is not actually created, but the EXE target needs to be retained#my $exe_name = $root . $::exe;my $dll_name = $root . '.' . $::so;$full = $dll_name;$link_target = 'library';my $me = MakeEntry::New (*MAKEFILE, $exe_name, '--Phony' );$me->AddComment ("Build Program: $name as a DLL" );$me->AddDependancy ( $dll_name );$me->Print();## Need to specifically clean this up, since we have fiddled with the# name of the generated file#ToolsetGenerate( $dll_name );}## Create Rules and Recipes to convert the .resx files to .resource files#foreach my $res ( @reslist ){my ($res, $cs) = Toolset_genres ('$(OBJDIR)', $res );UniquePush ( \@resources, $res );UniquePush ( \@csource, $cs );}## Create Rules and Recipes to provide Assembly instructions# for the creation of a StrongNameKey#if ( $snk ){UniquePush ( \@csource, Toolset_gensnk ($name, $snk ) );}my ($io) = ToolsetPrinter::New();my $dep = $io->SetLdTarget( $name );## Create Rules and Recipes to create the Program# This will be a combination of source, libraries and resources#my $me = MakeEntry::New (*MAKEFILE, $full );$me->AddComment ("Build Program: $name" );$me->AddName ( $docFile ) if ( $docFile );$me->AddDependancy ( $dep );$me->AddDependancy ( '$(SCM_MAKEFILE)' );$me->AddDependancy ( @resources );$me->AddDependancy ( @csource );$me->AddDependancy ( @dtd );$me->AddDependancy ( $icon );$me->AddRecipe ( '$(CSC)' );$me->Print();##.. Compiler command file# Now piece together a variable $(name_ld) which ends up in# the command file linking the application.#$io->Label( "Linker commands", $name ); # label$io->SetTag( "${name}_ld" ); # macro tag$io->Label( "Linker Command File", $name ); # label## Basic options#$io->Cmd( "/target:$link_target" );$io->Cmd("/doc:$docFile") if ( $docFile ) ;$io->Cmd( "/win32icon:\$(subst /,\\\\,$icon)" ) if $icon;$io->Cmd( "/main:$entry" ) if $entry;## Add in the Resource Files# the source files# the libraries#$io->Cmd( "/res:\$(subst /,\\\\,$_)" ) foreach @resources;$io->Cmd( "/res:\$(subst /,\\\\,$_)" ) foreach @dtd;$io->Cmd( "\$(subst /,\\\\,$_)" ) foreach @csource;$io->LibList( $name, $pLibs, \&ToolsetLibRecipe );$io->Newline();#.. Dependency link,# Create a library dependency file# Create command file to build applicaton dependency list# from the list of dependent libraries## Create makefile directives to include the dependency# list into the makefile.#$io->DepRules( $pLibs, \&ToolsetLibRecipe, $full );$io->LDDEPEND();## Files to clean up#ToolsetGenerate( "$root.ld" );ToolsetGenerate( "$root.pdb" );ToolsetGenerate( $docFile ) if $docFile;#.. Package up files that are a part of the program#PackageProgAddFiles ( $name, $full );PackageProgAddFiles ( $name, "$root.pdb", "Class=debug" ) unless ( $no_pdb );PackageProgAddFiles ( $name, $docFile, "Class=map" ) if ( $docFile );}################################################################################ ToolsetSHLD( $name, \@args, \@objs, \@libraries, $ver )# This subroutine takes the user options and builds the rules# required to link the program 'name'.## Arguments:# $name - Name of the target program# $pArgs - Ref to an array of argumennts# $pObjs - Ref to an array of object files# $pLibs - Ref to an array of libraries# $ver - Library Version string## Output:# Makefile recipes to create the DLL# Will create both versioned and unversioned DLLs## Notes:# This Library Builder will handle its own dependancies# It will also create rules and recipes to construct various# parts directly from source## This is SO close to the ToolsetLD function that its not funny## Options:# --Resource=file.resx# --Icon=file# --StrongNameKey=file# --Doc# --NoPDB# --NoVersionDll# CSharpSourceFile#################################################################################sub ToolsetSHLD{## Note: Use globals to kill warnings from internal sub# Use _ prefix so that they don't get saved in Makefile_x.cfg# Init as they are global#our ( $_name, $_pArgs, $_pObjs, $_pLibs, $_ver ) = @_;our ( @_reslist, @_resources, @_csource, @_dtd ) = ();our $_no_pdb = $pdb_none;our $_noaddlibs = 0;our $_icon = undef;our $_docFile = undef;our $_snk = undef;my $noVersionedDlls = $::ScmCompilerOpts{'NO_VERSIONED_DLLS'};#.. Parse arguments#foreach ( @$_pArgs ) {if (/^--Resource=(.+)/i) { # Resource definitionpush @_reslist, MakeSrcResolve($1);} elsif (/^--Dtd=(.+)/i) { # dtd definitionpush @_dtd, MakeSrcResolve($1);} elsif (/^--Icon=(.+)/i) {Error ("$toolset_name SHLD: Only one Icon file allowed") if ( $_icon );$_icon = MakeSrcResolve($1);} elsif (/^--StrongNameKey=(.+)/i) {Error ("$toolset_name SHLD: Only one SNK file allowed") if ( $_snk );$_snk = MakeSrcResolve($1);} elsif (/^--Doc/i) {$_docFile = 1;} elsif (/^--NoPDB$/i) {$_no_pdb = 1;} elsif (/^--NoVersionDll/i) {$noVersionedDlls = 1;} elsif ( !/^-/ ) {push @_csource, MakeSrcResolve($_);} else {Message( "$toolset_name SHLD: unknown option $_ -- ignored\n" );}}## Create Rules and Recipes to convert the .resx files to .resource files#foreach my $res ( @_reslist ){my ($res, $cs) = Toolset_genres ('$(OBJDIR)/' . $_name, $res );UniquePush ( \@_resources, $res );UniquePush ( \@_csource, $cs );}## Create Rules and Recipes to provide Assembly instructions# for the creation of a StrongNameKey#if ( $_snk ){UniquePush ( \@_csource, Toolset_gensnk ($_name, $_snk ) );}## Build Rules# $1 - Base Name# $2 - Name of the output DLL#sub BuildSHLD{my ($name, $lib ) = @_;my ($root, $full, $link_target);## Determine the target output name#$root = "\$(LIBDIR)/$lib";$full = "$root.$::so";$link_target = "library";$_docFile = "$full.xml" if ($_docFile);my ($io) = ToolsetPrinter::New();my $dep = $io->SetShldTarget( $lib );## Create Rules and Recipes to create the Program# This will be a combination of source, libraries and resources#my $me = MakeEntry::New (*MAKEFILE, $full );$me->AddComment ("Build Shared Library: $name" );$me->AddName ( $_docFile ) if ( $_docFile );$me->AddDependancy ( '$(SCM_MAKEFILE)' );$me->AddDependancy ( $dep );$me->AddDependancy ( @_resources );$me->AddDependancy ( @_csource );$me->AddDependancy ( @_dtd );$me->AddDependancy ( $_icon );$me->AddRecipe ( '$(CSC)' );$me->Print();##.. Compiler command file# Now piece together a variable $(name_ld) which ends up in# the command file linking the application.#$io->Label( "Linker commands", $name ); # label$io->SetTag( "${lib}_ld" ); # macro tag$io->Label( "Linker Command File", $lib ); # label## Basic options#$io->Cmd( "/target:$link_target" );$io->Cmd( "/doc:$_docFile") if ( $_docFile ) ;$io->Cmd( "/win32icon:\$(subst /,\\\\,$_icon)" ) if $_icon;## Add in the Resource Files# the source files# the libraries#$io->Cmd( "/res:\$(subst /,\\\\,$_)" ) foreach @_resources;$io->Cmd( "/res:\$(subst /,\\\\,$_)" ) foreach @_dtd;$io->Cmd( "\$(subst /,\\\\,$_)" ) foreach @_csource;$io->LibList( $name, $_pLibs, \&ToolsetLibRecipe );$io->Newline();#.. Dependency link,# Create a library dependency file# Create command file to build applicaton dependency list# from the list of dependent libraries## Create makefile directives to include the dependency# list into the makefile.#$io->DepRules( $_pLibs, \&ToolsetLibRecipe, $full );$io->SHLDDEPEND( $name, $lib );## Files to clean up#ToolsetGenerate( "$root.ld" );ToolsetGenerate( "$root.pdb" );ToolsetGenerate( $_docFile ) if $_docFile;#.. Package up files that are a part of the Library#PackageShlibAddFiles ( $name, $full );PackageShlibAddFiles ( $name, "$root.pdb", "Class=debug" ) unless ( $_no_pdb );PackageShlibAddFiles ( $name, $_docFile , "Class=map" ) if ( $_docFile );## Return the full name of the created DLL.#return $full;}## Generate DLLs## a) Unversioned DLL $_name$(GBE_TYPE).dll# b) Versioned DLL $_name$(GBE_TYPE).xx.xx.xx.dll#my $funver = BuildSHLD( "$_name", "$_name\$(GBE_TYPE)" );unless ($noVersionedDlls){my $fver = BuildSHLD( "$_name", "$_name\$(GBE_TYPE).$_ver" );## Create a dependancy between the version and unversioned DLLs#my $me = MakeEntry::New (*MAKEFILE, $fver );$me->AddComment ("Link Version and Unversioned Images: $_name" );$me->AddDependancy ( $funver );$me->Print();}}########################################################################## Generate a linker/depend library recipe. This is a helper function# used within this toolset.## Arguments:# $io I/O stream## $target Name of the target## $lib Library specification## $dp If building a depend list, the full target name.#########################################################################sub ToolsetLibRecipe{my ($io, $target, $lib, $dp) = @_;if ( !defined($dp) ) { # linker$io->Cmd( "/reference:\$(subst /,\\\\,\$(strip $lib)).$::so" );} else { # depend$io->Cmd( "$dp:\t@(vglob2,$lib.$::so,CS_LIB)" );}}########################################################################## Generate a project from the provided project solution file# This is aimed at .NET work## Arguments : $name - Base name of the project# $solution - Path to the solutionn file# $pArgs - Project specific options#########################################################################my $project_defines_done = 0;sub ToolsetPROJECT{my( $name, $solution ,$pArgs ) = @_;my $buildcmd = 'devenv =DSW= /build =TYPE= /useenv /out =LOG=';my $cleancmd = 'devenv =DSW= /clean =TYPE= /useenv';my $release = 'RELEASE';my $debug = 'DEBUG';## Process options#foreach ( @$pArgs ) {if ( m/^--TargetProd*=(.+)/ ) {$release = $1;} elsif ( m/^--TargetDebug=(.+)/ ) {$debug = $1;} else {Message( "$toolset_name PROJECT: unknown option $_ -- ignored\n" );}}my ($io) = ToolsetPrinter::New();## Setup toolset specific difinitions. Once#unless( $project_defines_done ){$project_defines_done = 1;$io->PrtLn( 'project_target = $(if $(findstring 1,$(DEBUG)),$2,$1)' );$io->Newline();}## Process the build and clean commands# Substitute arguments# =TYPE=# =LOG=# =DSW=#$buildcmd =~ s~=TYPE=~"\$(call project_target,$release,$debug)"~g;$buildcmd =~ s~=LOG=~$name\$(GBE_TYPE).log~g;$buildcmd =~ s~=DSW=~$solution~g;$cleancmd =~ s~=TYPE=~"\$(call project_target,$release,$debug)"~g;$cleancmd =~ s~=LOG=~$name\$(GBE_TYPE).log~g;$cleancmd =~ s~=DSW=~$solution~g;## Generate the recipe to create the project# Use the set_<PLATFORM>.sh file to extend the DLL search path#$io->Label( "Build project", $name );$io->PrtLn( "Project_$name: $solution \$(INTERFACEDIR)/set_$::ScmPlatform.sh" );$io->PrtLn( "\t\$(XX_PRE)( \$(rm) -f $name\$(GBE_TYPE).log; \\" );$io->PrtLn( "\t. \$(INTERFACEDIR)/set_$::ScmPlatform.sh; \\" );$io->PrtLn( "\t\$(show_environment); \\" );$io->PrtLn( "\t$buildcmd; \\" );$io->PrtLn( "\tret=\$\$?; \\" );$io->PrtLn( "\t\$(GBE_BIN)/cat $name\$(GBE_TYPE).log; \\" );$io->PrtLn( "\texit \$\$ret )" );$io->Newline();## Generate the recipe to clean the project#$io->Label( "Clean project", $name );$io->PrtLn( "ProjectClean_$name: $solution" );$io->PrtLn( "\t-\$(XX_PRE)$cleancmd" );$io->PrtLn( "\t-\$(XX_PRE)\$(rm) -f $name\$(GBE_TYPE).log" );$io->Newline();}#-------------------------------------------------------------------------------# Function : ToolsetTESTFRAMEWORK_NUNIT## Description : Toolset specfic support for the NUNIT Test FrameWork# Accessed with RunTest ('*', --FrameWork=nunit, ... );## Manipulates the pEntry structure to allow JATS to# construct a test entry to run Nunit tests## Inputs : $pEntry - Unit Test Hash## Returns : Modified Hash#sub ToolsetTESTFRAMEWORK_NUNIT{my ($pEntry) = @_;my $test_dll_name;my @copy_dlls;my %copy_dll_flags;## Extract base name of DLL under test# Thsi will not have any extension.#$test_dll_name = $pEntry->{'prog'};Error ("Nunit Framework. No TestDLL specified") unless $test_dll_name;## Process the FrameWork Options#foreach ( @{$pEntry->{'framework_opts'}} ){if ( m/^--Uses=(.+)/ ) {my ($dll, @opts) = split (',', $1 );push @copy_dlls, $dll;foreach ( @opts ){if ( m~^--NonJats~i ) {$copy_dll_flags{$dll}{'NonJats'} = 1;} elsif ( m~--Jats~ ) {$copy_dll_flags{$dll}{'NonJats'} = 0;} else {Error ("Nunit Framework. Unknown sub option to --Uses: $_");}}} else {Error ("Nunit Framework. Unknown option: $_");}}## Locate the Nunit essentials# This list may change with each version of nunit# Look for a known file and use its contents# Format:# One file name per line# Line comments only# Comment marker is a ## First one MUST be the executable#my @nunit_files;my $mfile = 'nunit-jats-manifest.txt';my $nunit_file = ToolExtensionProgram ( $mfile );Error ("Cannot find Nunit Jats Manifest: $mfile") unless ( $nunit_file );open (JM, $nunit_file ) || Error( "Cannot open file: $nunit_file", "Reason: $!" );while ( <JM> ){s~\s+$~~; # Remove trailing white spaces~^\s+~~; # Remove Leading whitespacenext unless ( $_ ); # Skip block linesnext if ( m~^#~ ); # Skip commentsVerbose ("Nunit File: $_");push @nunit_files, $_;}close JM;## Locate all the required files# The first one will be the console executable#my @nunit_framework;foreach my $file ( @nunit_files ){my $path = ToolExtensionProgram ($file );Error ("Cannot locate nunit file: $file") unless ( $path );push @nunit_framework, $path;}my $nunit_console = $nunit_framework[0];Error ("Nunit console executable not specified") unless ( $nunit_console );## Locate the test DLL.# This will be created locally within this makefile# It will be a known shared library#Errror( "TestDLL does not appear to be locally created: $test_dll_name" )unless ( $::SHLIBS->Get($test_dll_name) );## Hard bit. Determine the name/path of the DLL under test# It will have been created within this makefile# This is not a physical file.#$test_dll_name = $test_dll_name . '$(GBE_TYPE).' . $::so;my $test_dll = '$(LIBDIR)/' . $test_dll_name;## Other hard bit# Locate the other dll's needed by this test# Need to use P in production and D in Debug unless otherwise specified# These might be in:# an external package# within the local directory# the current makefile# ie: We can only determine the location of the files at run-time## The mechanism used is:# Create makefile recipe entries to# Use cmdfile to create a command file with copy command# Execute the command file## Complications include:# The windows shell used does not honour 'set -e', so we need to# detect error conditions ourselves#my $ofile = "\$(TESTDIR)/$pEntry->{test_name}.cmd";push @{$pEntry->{'ShellRecipe'}}, "rm -f $ofile";my @cmds;push @cmds, "\$(cmdfile) -wk1W1o$ofile";foreach my $dll ( @copy_dlls ){## Generate in-line commands to locate and copy in the required# DLL's. The 'cmdfile' utility can be used to do this at runtime#my $dll_name = $dll;$dll_name .= '$(GBE_TYPE)' unless ( $copy_dll_flags{$dll}{'NonJats'} );push @cmds, '"' . "cp -f @(vglob2,$dll_name.$::so,PATH,/) \$(TESTDIR) || exit 98" . '\n"';}push @cmds, "|| exit 99";push @{$pEntry->{'ShellRecipe'}}, \@cmds;push @{$pEntry->{'ShellRecipe'}}, ". $ofile";## Add items to the Unit Test Hash# command - command to execute to run the test program# prog - test command/script that must be in the test dir# copyprog - Prog must be copied in# args - Arguments to the test# copyin - Array of files to copy into the test directory# copyonce - Array of files to copy only once# prereq - Prerequiste conditions# testdir - Symbolic name of the test directory# ShellRecipe - Recipe Bits to add#$pEntry->{'command'} = $nunit_console . ' ' . $test_dll_name;unshift @{$pEntry->{args}}, "/xml=$pEntry->{test_name}.xml";$pEntry->{'prog'} = $test_dll_name;$pEntry->{'copyprog'} = 0;push @{$pEntry->{'copyin'}}, $test_dll;push @{$pEntry->{'copyonce'}}, @nunit_framework;$pEntry->{'testdir'} = 'TESTDIR';## Create the Test Directory# Tests will be done in a .NUNIT subdir#MkdirRule( "\$(TESTDIR)", 'TESTDIR', '--Path=$(GBE_PLATFORM)$(GBE_TYPE).NUNIT', '--RemoveAll' );## Files created by the Unit Test#ToolsetGenerate ( "\$(TESTDIR)/$pEntry->{test_name}.xml" );ToolsetGenerate ( $ofile );}#.. Successful termination1;