Subversion Repositories DevTools

Rev

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

Rev Author Line No. Line
227 dpurdie 1
#
2
# Module name   : CSHARP
3
# Module type   : Makefile system
4
# Compiler(s)   : ANSI C
5
# Environment(s): WIN32
6
#
7
# Description:
8
#       CSHARP for Windows
9
#
10
#............................................................................#
11
use strict;
12
use warnings;
4097 dpurdie 13
use File::Basename;
14
use File::Spec::Functions;
227 dpurdie 15
use MakeEntry;
16
 
17
#
4074 dpurdie 18
#   External data
19
#
20
our %SRC_DEPEND;
21
 
22
#
227 dpurdie 23
#   Global data
24
#
25
my %resource_files;
26
my $pdb_none;
27
 
343 dpurdie 28
my $toolset_name = 'csharp';                           # Toolset name : Error reporting
255 dpurdie 29
my $toolset_info;
30
my $toolset_version = '1.1';
31
my %ToolsetVersion =
32
    (
33
    '1.1' => { 'def'      => 'CSHARP.DEF',              # Def file to use
34
               'pragma'   => 0,                         # True: Compiler supports #pragma
35
               'warnings' => '',                        # Comma sep list of warnings to ignore
36
             },
37
 
38
    '2.0' => { 'def'      => 'CSHARP2005.DEF',
39
               'pragma'   => 1,
40
               'warnings' => '1668',
41
             },
291 dpurdie 42
 
43
    '3.5' => { 'def'      => 'CSHARP2008.DEF',
44
               'pragma'   => 1,
45
               'warnings' => '1668',
46
             },
347 dpurdie 47
 
48
    '4.0' => { 'def'      => 'CSHARP2010.DEF',
49
               'pragma'   => 1,
50
               'warnings' => '1668',
351 dpurdie 51
               'platform' => 'x86',
347 dpurdie 52
             },
4192 dpurdie 53
 
54
     '4.5' => { 'def'      => 'CSHARP2012.DEF',
55
                'pragma'   => 1,
56
                'warnings' => '1668',
57
                'platform' => 'x86',
58
              },
255 dpurdie 59
    );
60
 
61
 
227 dpurdie 62
##############################################################################
63
#   ToolsetInit()
64
#       Runtime initialisation
65
#
66
##############################################################################
67
 
68
ToolsetInit();
69
 
70
sub ToolsetInit
71
{
72
 
73
    #.. Parse arguments (Toolset arguments)
74
    #
343 dpurdie 75
    Debug( "$toolset_name(@::ScmToolsetArgs)" );
227 dpurdie 76
 
77
    foreach $_ ( @::ScmToolsetArgs ) {
78
        if (/^--Version=(.*)/) {                # MS SDK Version
79
            $toolset_version = $1;
80
 
81
        } else {
343 dpurdie 82
            Message( "$toolset_name toolset: unknown option $_ -- ignored\n" );
227 dpurdie 83
        }
84
    }
85
 
86
    #.. Parse arguments (platform arguments)
87
    #
343 dpurdie 88
    Debug( "$toolset_name(@::ScmPlatformArgs)" );
227 dpurdie 89
 
90
    foreach $_ ( @::ScmPlatformArgs ) {
91
        if (/^--product=(.*)/) {                # GBE product
92
 
93
        } elsif (/^--Version=(.*)/) {           # MS SDK Version
94
            $toolset_version = $1;
95
 
96
        } else {
343 dpurdie 97
            Message( "$toolset_name toolset: unknown platform argument $_ -- ignored\n" );
227 dpurdie 98
        }
99
    }
100
 
255 dpurdie 101
    #.. Validate SDK version
102
    #   Currently supported versions are described in a HASH
227 dpurdie 103
    #
255 dpurdie 104
    $toolset_info = $ToolsetVersion{$toolset_version};
343 dpurdie 105
    Error( "$toolset_name toolset: Unknown version: $toolset_version" ) unless ( defined $toolset_info );
255 dpurdie 106
 
227 dpurdie 107
    #.. Standard.rul requirements
108
    #
109
    $::s    = undef;
110
    $::o    = '';
111
    $::a    = 'netmodule';
112
    $::so   = 'dll';
113
    $::exe  = '.exe';
114
 
115
    #.. Toolset configuration
116
    #
117
    $::ScmToolsetVersion = "1.0.0";             # our version
118
    $::ScmToolsetGenerate = 0;                  # generate optional
119
    $::ScmToolsetProgDependancies = 0;          # handle Prog dependancies myself
120
    %::ScmToolsetProgSource = (                 # handle these files directly
121
            '.cs'       => '',                  # Will be flagged as "CSRCS"
122
            '.resx'     => '--Resource=',       # Will be passed with prefix
123
            '.dtd'      => '--Dtd=',            # Will be passed with prefix
124
            );
125
 
126
    #.. define Visual C/C+ environment
127
    Init( "csharp" );
255 dpurdie 128
    ToolsetDefines( $toolset_info->{'def'} );
227 dpurdie 129
    ToolsetRules( "csharp.rul" );
130
#    ToolsetRules( "standard.rul" );
131
 
132
 
133
    #.. Extend the CompilerOption directive
134
    #   Create a standard data structure
135
    #   This is a hash of hashes
136
    #       The first hash is keyed by CompileOption keyword
137
    #       The second hash contains pairs of values to set or remove
138
    #
139
    %::ScmToolsetCompilerOptions =
140
    (
141
        #
142
        #   Control the thread model to use
143
        #   This will affect the compiler options and the linker options
144
        #
145
        'noaddlibs'          => { 'ADDLINKLIBS' , undef },      # Don't add link libs
146
        'addlibs'            => { 'ADDLINKLIBS' , '1' },        # default
147
        'nowarn='            => { 'NOWARNLIST'  ,\&NoWarns },   # Suppress warnings
148
        'nopdb'              => { 'PDB_NONE', 1 },              # Disable all PDB files
149
        'pdb'                => { 'PDB_NONE', undef },          # Enable PDB files: Default
150
        'subsystem:windows'  => { 'LDSUBSYSTEM' , 'winexe' },
151
        'subsystem:console'  => { 'LDSUBSYSTEM' , 'exe' },
351 dpurdie 152
        'platform:32'        => { 'NET_PLATFORM', 'x86' },
153
        'platform:64'        => { 'NET_PLATFORM', 'x64' },
154
        'platform:any'       => { 'NET_PLATFORM', undef },
2931 dpurdie 155
        'noversiondll'       => { 'NO_VERSIONED_DLLS', 1 },
227 dpurdie 156
    );
157
 
158
    #
159
    #   Set default options
160
    #
161
    $::ScmCompilerOpts{'ADDLINKLIBS'} = '1';
255 dpurdie 162
    $::ScmCompilerOpts{'NOWARNLIST'} = $toolset_info->{'warnings'};
227 dpurdie 163
    $::ScmCompilerOpts{'LDSUBSYSTEM'} = 'winexe';
351 dpurdie 164
    $::ScmCompilerOpts{'NET_PLATFORM'} = $toolset_info->{'platform'};
2931 dpurdie 165
    $::ScmCompilerOpts{'NO_VERSIONED_DLLS'} = undef;
227 dpurdie 166
}
167
 
168
 
169
#-------------------------------------------------------------------------------
170
# Function        : NoWarns
171
#
172
# Description     : ScmToolsetCompilerOptions  extension function
255 dpurdie 173
#                   Accumulates the NoWarn options as a comma seperated list
227 dpurdie 174
#
175
# Inputs          : $key        - Name of the Option
176
#                   $value      - Option Value. Comma sep list of numbers
255 dpurdie 177
#                   $ukey       - User key (within $::ScmCompilerOpts)
227 dpurdie 178
#
179
# Returns         : New sting to save
180
#
181
sub NoWarns
182
{
255 dpurdie 183
    my ($key, $value, $ukey) = @_;
184
    my @NoWarnList =  split (',', $::ScmCompilerOpts{$ukey});
261 dpurdie 185
    UniquePush ( \@NoWarnList, split (',', $value) );
227 dpurdie 186
    return join ',', @NoWarnList;
187
}
188
 
189
##############################################################################
190
#   ToolsetPreprocess()
191
#       Process collected data before the makefile is generated
192
#       This, optional, routine is called from within MakefileGenerate()
193
#       It allows the toolset to massage any of the collected data before
194
#       the makefile is created
195
#
196
##############################################################################
197
sub ToolsetPreprocess
198
{
199
    #
200
    #   Extract the current state of PDB_NONE
201
    #   Are PDB files to be constructed.
202
    #
203
    $pdb_none = $::ScmCompilerOpts{'PDB_NONE'};
204
}
205
 
206
##############################################################################
207
#   ToolsetPostprocess
208
#       Process collected data as the makefile is generated
209
#       This, optional, routine is called from within MakefileGenerate()
210
#       It allows the toolset to massage any of the collected data before
211
#       the makefile is finally closed created
212
#
213
##############################################################################
214
 
215
sub ToolsetPostprocess
216
{
217
    #
218
    #   Generate Recipes to create Resource Files
219
    #   This is done outside of the Prog and Lib routines
220
    #   so that they can be agregated
221
    #
222
    #   Note: don't make the makefile a dependant as changes to the
223
    #         makefile won't affect the file
224
    #
225
    for my $resource ( sort keys %resource_files )
226
    {
227
        my $src  = $resource_files{$resource}{src};
228
        my $root = $resource_files{$resource}{root};
229
 
230
        my $me = MakeEntry::New (*MAKEFILE, $resource );
231
        $me->AddComment ("Build Resource: $root" );
261 dpurdie 232
#        $me->AddDependancy ( '$(SCM_MAKEFILE)' );
227 dpurdie 233
        $me->AddDependancy ( $src );
4074 dpurdie 234
        if ( exists $SRC_DEPEND{$src} )
235
        {
236
            $me->AddDependancy ( split( /$;/, $SRC_DEPEND{$src} ) );
237
        }
227 dpurdie 238
        $me->AddRecipe ( '$(RESGEN)' );
239
        $me->Print();
240
 
241
        #
242
        #   Add to the deletion list
243
        #
244
        ToolsetGenerate( $resource );
245
    }
246
}
247
 
248
#-------------------------------------------------------------------------------
249
# Function        : Toolset_genres
250
#
251
# Description     : Internal function to assist in the creation of a resource
252
#                   In many cases it will create an entry for later processing
253
#
254
# Inputs          : $subdir         - Root of the target directory for the generated
255
#                                     resource file
4097 dpurdie 256
#                   $src            - Path to the source resource file
227 dpurdie 257
#
258
# Returns         : Path to the generated resource file
259
#                   This will be FQN named file
260
#                   Path to the associated .CS file
261
#
262
# Notes           : Create and maintain the %resource_files hash
263
#                   Key is the path to the compiled file
264
#                   Values are:
265
#                       {src}   - Path to the source file
266
#                       {root}  - Basic file name (Display Purposes Only)
267
#
268
#                   Need to create a '.resource' file with a FQN name
269
#                   This is not that simple. Need to
270
#                       1) Extract the (optional) ThisName from the .resx file
271
#                          If not specified then the ThisName is the rootfilename
272
#                          without any .as[pca]x extension.
273
#                       2) Extract the namespace from the associated .cs file
274
#                       3) FQN = NameSpace.ThisName
275
#
276
#
277
sub Toolset_genres
278
{
279
    my ($subdir, $src ) = @_;
280
 
281
    #
282
    #   Ensure that the .cs file also exists
4097 dpurdie 283
    #   We may have a NAME.Designer.cs or a NAME.cs file - Different VS versions do it differently
284
    #   The file 'should' be in the same directory, but may be in the parent
227 dpurdie 285
    #
4097 dpurdie 286
    my $csfile;
287
    my @csNames = qw(.Designer.cs .cs);
288
    my @csDirs = qw( . ..);
289
    my($csfilename, $csdirectories, $cssuffix) = fileparse($src, '.resx');
290
    csScan:
291
    foreach my $dir (@csDirs){
292
        foreach my $name (@csNames) {
293
            my $testPath = catfile($csdirectories, $dir ,$csfilename . $name);
294
            if (-f $testPath)
295
            {
296
                $csfile = $testPath;
297
                $csfile =~ s~\\~/~g;
298
                last csScan;
299
            }
300
        }
301
    }
3967 dpurdie 302
 
4097 dpurdie 303
    # Warn if we can't find one.
304
    # Create a dummy name - may fail later
227 dpurdie 305
    #
4097 dpurdie 306
    unless ($csfile)
307
    {
308
        Warning ("$toolset_name toolset: Resx File without a .cs or Designer.cs file", "File: $src");
309
        ($csfile = $src) =~ s~\.resx$~.cs~;
310
    }
311
 
312
    #
227 dpurdie 313
    #   Scan the .resx file looking for the ThisName element
314
    #   A very simple and crude parser
315
    #
316
    my $ThisName;
3967 dpurdie 317
    my $ThisNameGuess;
227 dpurdie 318
    open ( SCAN, '<', $src ) || Error ("Cannot open file for reading: $!", "File: $src" );
319
    while ( <SCAN> )
320
    {
321
        if ( m~\<data name=\"\$this\.Name\"\>~ )
322
        {
323
            # Next line will contain the needed data item
324
            my $element = <SCAN>;
325
            $element =~ m~\<.+\>(.+)\</.+\>~;
326
            $ThisName = $1;
343 dpurdie 327
            Error ("$toolset_name toolset: Resx parsing: Bad this.Name", "File: $src") unless $ThisName;
227 dpurdie 328
            $ThisName =~ s~\s+~~g;
329
            last;
330
        }
331
    }
332
    close SCAN;
333
 
334
    #
335
    #   Name not found
336
    #   Use a default. Filename with any .aspx, .asax, .ascx removed
337
    #
338
    unless ( $ThisName )
339
    {
3967 dpurdie 340
        $ThisNameGuess = $ThisName;
341
        $ThisNameGuess = StripDirExt($src);
342
        $ThisNameGuess =~ s~\.as[pac]x~~i;
227 dpurdie 343
    }
344
 
345
    #
3967 dpurdie 346
    #   Scan the.cs file looking for the namespace and class
227 dpurdie 347
    #   A very simple and crude parser
348
    #
349
    my $NameSpace;
3967 dpurdie 350
    my $ClassName;
351
 
227 dpurdie 352
    open ( SCAN, '<', $csfile ) || Error ("Cannot open file for reading: $!", "File: $csfile" );
353
    while ( <SCAN> )
354
    {
3967 dpurdie 355
        next if ( m ~\s*//~);
356
 
357
        if ( m~namespace\s+(\S+)~ ) {
227 dpurdie 358
            $NameSpace = $1;
3967 dpurdie 359
 
360
        } elsif ( m~\s+class\s+(\S+)~ ) {
361
            $ClassName = $1;
362
 
227 dpurdie 363
        }
3967 dpurdie 364
        last if ( defined($NameSpace) && defined($ClassName) );
365
 
227 dpurdie 366
    }
367
    close SCAN;
343 dpurdie 368
    Error ("$toolset_name toolset: Resx parsing: NameSpace not found", "File: $csfile") unless $NameSpace;
227 dpurdie 369
 
370
    #
371
    #   Need to create an output file name that is a function of the FQN
3967 dpurdie 372
    #   To be backwardly compatible
373
    #       Use the ClassName - if it was found
374
    #       Else Use the ThisName - if it was found
375
    #       Else Use the Guessed ThisName
227 dpurdie 376
    #
3967 dpurdie 377
    if ( !defined($ClassName)) {
378
        $ClassName = $ThisName;
379
        if ( !defined($ClassName)) {
380
            $ClassName = $ThisNameGuess;
381
        }
382
    }
383
 
384
    my $root = "$NameSpace.$ClassName.resources";
227 dpurdie 385
    my $resource = $subdir . '/' . $root;
386
    $resource_files{$resource}{src} = $src;
387
    $resource_files{$resource}{root} = $root;
388
 
389
    return $resource, $csfile;
390
}
391
 
392
 
393
#-------------------------------------------------------------------------------
394
# Function        : Toolset_gensnk
395
#
396
# Description     : Function to create a wrapper file for the processing
397
#                   of a StrongNameKey file
398
#
399
#                   Create only one wrapper per SNK file
400
#
401
# Inputs          : $name       - Name of component
402
#                   $snk        - Path to the SNK file
403
#
404
# Returns         : Path to the wrapper file
405
#
406
my %snk_data;
407
sub Toolset_gensnk
408
{
409
    my ($name, $snk ) = @_;
410
    my $file = StripDirExt( $snk );
411
 
412
    #
413
    #   Only create the file once
414
    #   Otherwise we will get nasty make messages
415
    #
416
 
417
    if ( exists $snk_data{$snk} )
418
    {
419
        return $snk_data{$snk}{output};
420
    }
421
 
422
    #
423
    #   Determine the target name
424
    #   Create the source file in the currentt directory
425
    #   If we build it in the OBJ directory we get two files
426
    #
427
    my $snk_file = '$(OBJDIR)/' . "Jats_${file}.cs";
428
    $snk_data{$snk}{output} = $snk_file;
429
    ToolsetGenerate( $snk_file );
430
 
431
    #
432
    #   Determine the Tag Name
433
    #   Used to conatin information in the makefile
434
    #
435
    my $tag = "${file}_snk";
436
 
437
    #
438
    #   Create Rules and Recipes to create the SNK wrapper file
439
    #
440
    my $me = MakeEntry::New (*MAKEFILE, $snk_file );
441
    $me->AddComment ("Build Strong Name Key File Wrapper: $snk" );
442
    $me->AddDependancy ( $snk );
261 dpurdie 443
    $me->AddDependancy ( '$(SCM_MAKEFILE)' );
227 dpurdie 444
    $me->AddRecipe ( '$(call GenSnkWrapper,' . $tag .  ')' );
445
    $me->Print();
446
 
447
    #
448
    #   Create the data t be placed into the wrapper file
449
    #
450
    my ($io) = ToolsetPrinter::New();
451
 
452
    my $ms_snk = $snk;
453
 
454
    $io->Label( "SNK Wrapper file content", $tag );    # label
455
    $io->SetTag( $tag );                                # macro tag
255 dpurdie 456
    $io->Cmd( '// This is JATS GENERATED FILE' );
457
    $io->Cmd( '//    Do not edit' );
458
    $io->Cmd( '//    Do not version control' );
459
 
227 dpurdie 460
    $io->Cmd( 'using System.Reflection;' );
461
    $io->Cmd( 'using System.Runtime.CompilerServices;' );
462
 
463
    $io->Cmd( '//' );
464
    $io->Cmd( '// In order to sign your assembly you must specify a key to use. Refer to the' );
465
    $io->Cmd( '// Microsoft .NET Framework documentation for more information on assembly signing.' );
466
    $io->Cmd( '//' );
467
    $io->Cmd( '// Use the attributes below to control which key is used for signing.' );
468
    $io->Cmd( '//' );
469
    $io->Cmd( '// Notes:' );
470
    $io->Cmd( '//   (*) If no key is specified, the assembly is not signed.' );
471
    $io->Cmd( '//   (*) KeyName refers to a key that has been installed in the Crypto Service' );
472
    $io->Cmd( '//       Provider (CSP) on your machine. KeyFile refers to a file which contains' );
473
    $io->Cmd( '//       a key.' );
474
    $io->Cmd( '//   (*) If the KeyFile and the KeyName values are both specified, the' );
475
    $io->Cmd( '//       following processing occurs:' );
476
    $io->Cmd( '//       (1) If the KeyName can be found in the CSP, that key is used.' );
477
    $io->Cmd( '//       (2) If the KeyName does not exist and the KeyFile does exist, the key' );
478
    $io->Cmd( '//           in the KeyFile is installed into the CSP and used.' );
479
    $io->Cmd( '//   (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility.' );
480
    $io->Cmd( '//       When specifying the KeyFile, the location of the KeyFile should be' );
481
    $io->Cmd( '//       relative to the project output directory which is' );
482
    $io->Cmd( '//       %Project Directory%\obj\<configuration>. For example, if your KeyFile is' );
483
    $io->Cmd( '//       located in the project directory, you would specify the AssemblyKeyFile' );
484
    $io->Cmd( '//       attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")]' );
485
    $io->Cmd( '//   (*) Delay Signing is an advanced option - see the Microsoft .NET Framework' );
486
    $io->Cmd( '//       documentation for more information on this.' );
487
    $io->Cmd( '//' );
488
 
489
    $io->Cmd( '[assembly: AssemblyDelaySign(false)]' );
255 dpurdie 490
    $io->Cmd( '#pragma warning disable 1699' ) if ($toolset_info->{'pragma'});
227 dpurdie 491
    $io->Cmd( '[assembly: AssemblyKeyFile(@"'. $snk  .'")]' );
255 dpurdie 492
    $io->Cmd( '#pragma warning restore 1699' ) if ($toolset_info->{'pragma'});
227 dpurdie 493
    $io->Cmd( '[assembly: AssemblyKeyName("")]' );
494
    $io->Newline();
495
 
496
    #
497
    #   Return the path to where the file will be created
498
    #
499
    return $snk_file;
500
}
501
 
502
 
503
###############################################################################
504
#   ToolsetLD( $name, \@args, \@objs, \@libraries )
505
#       This subroutine takes the user options and builds the rules
506
#       required to link the program 'name'.
507
#
508
#   Arguments:
509
#       $name       - Name of the target program
510
#       $pArgs      - Ref to an array of argumennts
511
#       $pObjs      - Ref to an array of object files
512
#       $pLibs      - Ref to an array of libraries
513
#
514
#   Output:
515
#       Makefile recipes to create the Program
516
#
517
#   Notes:
518
#       This Program Builder will handle its own dependancies
519
#       It will also create rules and recipes to construct various
520
#       parts directly fromm source
521
#
522
#   Options:
523
#       --Resource=file.resx
524
#       --Dtd=file.dtd
525
#       --Icon=file
526
#       --Entry=xxxxx                   # Entry point
527
#       --Console                       # Console app
528
#       --Windows                       # Windows app (default)
529
#       --DLL                           # As a DLL (No P|D)
530
#       --Doc
531
#       --NoPDB
532
#       CSharpSourceFile
533
#
534
#
535
###############################################################################
536
 
537
sub ToolsetLD
538
{
539
    my ( $name, $pArgs, $pObjs, $pLibs ) = @_;
540
    my ( @reslist, @resources, @csource, @dtd );
541
    my $no_pdb = $pdb_none;
542
    my $entry;
543
    my $noaddlibs;
544
    my $icon;
545
    my $docFile;
546
    my ($base, $root, $full );
547
    my $link_target = $::ScmCompilerOpts{'LDSUBSYSTEM'};
548
    my $snk;
549
    my $is_a_dll;
550
 
551
    #.. Parse arguments
552
    #
553
    foreach ( @$pArgs ) {
554
        if (/^--Resource=(.+)/) {               # Resource definition
555
            push @reslist, MakeSrcResolve($1);
556
 
557
        } elsif (/^--Dtd=(.+)/) {               # dtd definition
558
            push @dtd, MakeSrcResolve($1);
559
 
560
        } elsif (/^--Icon=(.+)/) {
343 dpurdie 561
            Error ("$toolset_name LD: Only one Icon file allowed") if ( $icon );
227 dpurdie 562
            $icon = MakeSrcResolve($1);
563
 
564
        } elsif (/^--StrongNameKey=(.+)/) {
343 dpurdie 565
            Error ("$toolset_name LD: Only one SNK file allowed") if ( $snk );
227 dpurdie 566
            $snk = MakeSrcResolve($1);
567
 
568
        } elsif (/^--Entry=(.+)/) {
569
            $entry = $1;
570
 
571
        } elsif (/^--Doc/) {
572
            $docFile = 1;
573
 
574
        } elsif (/^--Windows/) {
575
            $link_target = 'winexe';
576
 
577
        } elsif (/^--Console/) {
578
            $link_target = 'exe';
579
 
580
        } elsif (/^--DLL/) {
581
            $is_a_dll = 1;
582
 
583
        } elsif (/^--NoPDB$/) {
584
            $no_pdb = 1;
585
 
586
        } elsif ( !/^-/ ) {
587
            push @csource, MakeSrcResolve($_);
588
 
589
        } else {
343 dpurdie 590
            Message( "$toolset_name LD: unknown option $_ -- ignored\n" );
227 dpurdie 591
 
592
        }
593
    }
594
 
595
    #
596
    #   Determine the target output name
597
    #
598
    $base = $name;
599
    $root = "\$(BINDIR)/$base";
600
    $full = $root . $::exe;
601
    $docFile = "$root.xml" if ( $docFile );
602
 
603
    #
604
    #   Special case for DLLs that need to be created without a D or P mangled
605
    #   into the name. Create them as Progs just to fool the system
606
    #   Used when creating specialised web services
607
    #
608
    if ( $is_a_dll )
609
    {
610
        #
611
        #   Create a phony target
612
        #   The EXE name is not actually created, but the EXE target needs to be retained
613
        #
614
        my $exe_name = $root . $::exe;
615
        my $dll_name = $root . '.' . $::so;
616
        $full = $dll_name;
617
        $link_target = 'library';
618
 
619
        my $me = MakeEntry::New (*MAKEFILE, $exe_name, '--Phony' );
620
        $me->AddComment ("Build Program: $name as a DLL" );
621
        $me->AddDependancy ( $dll_name );
622
        $me->Print();
255 dpurdie 623
 
624
        #
625
        #   Need to specifically clean this up, since we have fiddled with the
626
        #   name of the generated file
627
        #
628
        ToolsetGenerate( $dll_name );
227 dpurdie 629
    }
630
 
631
    #
632
    #   Create Rules and Recipes to convert the .resx files to .resource files
633
    #
634
    foreach my $res ( @reslist )
635
    {
636
        my ($res, $cs) = Toolset_genres ('$(OBJDIR)', $res );
637
 
638
        UniquePush ( \@resources, $res );
639
        UniquePush ( \@csource, $cs );
640
    }
641
 
642
    #
643
    #   Create Rules and Recipes to provide Assembly instructions
644
    #   for the creation of a StrongNameKey
645
    #
646
    if ( $snk )
647
    {
648
        UniquePush ( \@csource, Toolset_gensnk ($name, $snk ) );
649
    }
650
 
335 dpurdie 651
    my ($io) = ToolsetPrinter::New();
652
    my $dep = $io->SetLdTarget( $name );
653
 
227 dpurdie 654
    #
655
    #   Create Rules and Recipes to create the Program
656
    #   This will be a combination of source, libraries and resources
657
    #
658
    my $me = MakeEntry::New (*MAKEFILE, $full );
659
    $me->AddComment ("Build Program: $name" );
660
    $me->AddName    ( $docFile ) if ( $docFile );
335 dpurdie 661
    $me->AddDependancy ( $dep );
261 dpurdie 662
    $me->AddDependancy ( '$(SCM_MAKEFILE)' );
227 dpurdie 663
    $me->AddDependancy ( @resources );
664
    $me->AddDependancy ( @csource );
665
    $me->AddDependancy ( @dtd );
666
    $me->AddDependancy ( $icon );
667
    $me->AddRecipe ( '$(CSC)' );
668
    $me->Print();
669
 
670
 
671
    #
672
    #.. Compiler command file
673
    #       Now piece together a variable $(name_ld) which ends up in
674
    #       the command file linking the application.
675
    #
676
    $io->Label( "Linker commands", $name );     # label
677
    $io->SetTag( "${name}_ld" );                # macro tag
678
 
679
    $io->Label( "Linker Command File", $name ); # label
680
 
681
    #
682
    #   Basic options
683
    #
684
    $io->Cmd( "/target:$link_target" );
685
    $io->Cmd("/doc:$docFile") if ( $docFile ) ;
686
    $io->Cmd( "/win32icon:\$(subst /,\\\\,$icon)" ) if $icon;
687
    $io->Cmd( "/main:$entry" ) if $entry;
688
 
689
    #
690
    #   Add in the Resource Files
691
    #          the source files
692
    #          the libraries
693
    #
694
    $io->Cmd( "/res:\$(subst /,\\\\,$_)" ) foreach @resources;
695
    $io->Cmd( "/res:\$(subst /,\\\\,$_)" ) foreach @dtd;
696
    $io->Cmd( "\$(subst /,\\\\,$_)" ) foreach @csource;
697
    $io->LibList( $name, $pLibs, \&ToolsetLibRecipe );
335 dpurdie 698
    $io->Newline();
227 dpurdie 699
 
700
 
335 dpurdie 701
    #.. Dependency link,
702
    #   Create a library dependency file
703
    #       Create command file to build applicaton dependency list
704
    #       from the list of dependent libraries
227 dpurdie 705
    #
335 dpurdie 706
    #       Create makefile directives to include the dependency
707
    #       list into the makefile.
227 dpurdie 708
    #
335 dpurdie 709
    $io->DepRules( $pLibs, \&ToolsetLibRecipe, $full );
710
    $io->LDDEPEND();
227 dpurdie 711
 
712
    #
713
    #   Files to clean up
714
    #
715
    ToolsetGenerate( "$root.ld" );
716
    ToolsetGenerate( "$root.pdb" );
717
    ToolsetGenerate( $docFile ) if $docFile;
718
 
719
 
720
    #.. Package up files that are a part of the program
721
    #
722
    PackageProgAddFiles ( $name, $full );
723
    PackageProgAddFiles ( $name, "$root.pdb", "Class=debug" ) unless ( $no_pdb );
724
    PackageProgAddFiles ( $name, $docFile, "Class=map" ) if ( $docFile );
725
}
726
 
727
###############################################################################
289 dpurdie 728
#   ToolsetSHLD( $name, \@args, \@objs, \@libraries, $ver )
227 dpurdie 729
#       This subroutine takes the user options and builds the rules
730
#       required to link the program 'name'.
731
#
732
#   Arguments:
733
#       $name       - Name of the target program
734
#       $pArgs      - Ref to an array of argumennts
735
#       $pObjs      - Ref to an array of object files
736
#       $pLibs      - Ref to an array of libraries
289 dpurdie 737
#       $ver        - Library Version string
227 dpurdie 738
#
739
#   Output:
740
#       Makefile recipes to create the DLL
741
#       Will create both versioned and unversioned DLLs
742
#
743
#   Notes:
744
#       This Library Builder will handle its own dependancies
745
#       It will also create rules and recipes to construct various
746
#       parts directly from source
747
#
748
#       This is SO close to the ToolsetLD function that its not funny
749
#
750
#   Options:
751
#       --Resource=file.resx
752
#       --Icon=file
753
#       --StrongNameKey=file
754
#       --Doc
755
#       --NoPDB
2931 dpurdie 756
#       --NoVersionDll
227 dpurdie 757
#       CSharpSourceFile
758
#
759
#
760
###############################################################################
761
sub ToolsetSHLD
762
{
763
    #
764
    #   Note: Use globals to kill warnings from internal sub
765
    #         Use _ prefix so that they don't get saved in Makefile_x.cfg
766
    #         Init as they are global
767
    #
289 dpurdie 768
    our ( $_name, $_pArgs, $_pObjs, $_pLibs, $_ver ) = @_;
227 dpurdie 769
    our ( @_reslist, @_resources, @_csource, @_dtd ) = ();
770
    our $_no_pdb = $pdb_none;
771
    our $_noaddlibs = 0;
772
    our $_icon = undef;
773
    our $_docFile = undef;
774
    our $_snk = undef;
775
 
2931 dpurdie 776
    my $noVersionedDlls = $::ScmCompilerOpts{'NO_VERSIONED_DLLS'};
777
 
227 dpurdie 778
    #.. Parse arguments
779
    #
780
    foreach ( @$_pArgs ) {
4031 dpurdie 781
        if (/^--Resource=(.+)/i) {               # Resource definition
227 dpurdie 782
            push @_reslist, MakeSrcResolve($1);
783
 
4031 dpurdie 784
        } elsif (/^--Dtd=(.+)/i) {               # dtd definition
227 dpurdie 785
            push @_dtd, MakeSrcResolve($1);
786
 
4031 dpurdie 787
        } elsif (/^--Icon=(.+)/i) {
343 dpurdie 788
            Error ("$toolset_name SHLD: Only one Icon file allowed") if ( $_icon );
227 dpurdie 789
            $_icon = MakeSrcResolve($1);
790
 
4031 dpurdie 791
        } elsif (/^--StrongNameKey=(.+)/i) {
343 dpurdie 792
            Error ("$toolset_name SHLD: Only one SNK file allowed") if ( $_snk );
227 dpurdie 793
            $_snk = MakeSrcResolve($1);
794
 
4031 dpurdie 795
        } elsif (/^--Doc/i) {
227 dpurdie 796
            $_docFile = 1;
797
 
4031 dpurdie 798
        } elsif (/^--NoPDB$/i) {
227 dpurdie 799
            $_no_pdb = 1;
800
 
4031 dpurdie 801
        } elsif (/^--NoVersionDll/i) {
2931 dpurdie 802
            $noVersionedDlls = 1;
803
 
227 dpurdie 804
        } elsif ( !/^-/ ) {
805
            push @_csource, MakeSrcResolve($_);
806
 
807
        } else {
343 dpurdie 808
            Message( "$toolset_name SHLD: unknown option $_ -- ignored\n" );
227 dpurdie 809
 
810
        }
811
    }
812
 
813
    #
814
    #   Create Rules and Recipes to convert the .resx files to .resource files
815
    #
816
    foreach my $res ( @_reslist )
817
    {
818
        my ($res, $cs) = Toolset_genres ('$(OBJDIR)/' . $_name, $res );
819
 
820
        UniquePush ( \@_resources, $res );
821
        UniquePush ( \@_csource, $cs );
822
    }
823
 
824
    #
825
    #   Create Rules and Recipes to provide Assembly instructions
826
    #   for the creation of a StrongNameKey
827
    #
828
    if ( $_snk )
829
    {
830
        UniquePush ( \@_csource, Toolset_gensnk ($_name, $_snk ) );
831
    }
832
 
833
    #
834
    #   Build Rules
835
    #   $1  - Base Name
836
    #   $2  - Name of the output DLL
837
    #
838
    sub BuildSHLD
839
    {
840
        my ($name, $lib ) = @_;
841
        my ($root, $full, $link_target);
842
 
843
        #
844
        #   Determine the target output name
845
        #
846
        $root = "\$(LIBDIR)/$lib";
847
        $full = "$root.$::so";
848
        $link_target = "library";
849
        $_docFile = "$full.xml" if ($_docFile);
850
 
335 dpurdie 851
        my ($io) = ToolsetPrinter::New();
852
        my $dep = $io->SetShldTarget( $lib );
853
 
227 dpurdie 854
        #
855
        #   Create Rules and Recipes to create the Program
856
        #   This will be a combination of source, libraries and resources
857
        #
858
        my $me = MakeEntry::New (*MAKEFILE, $full );
859
        $me->AddComment ("Build Shared Library: $name" );
860
        $me->AddName    ( $_docFile ) if ( $_docFile );
261 dpurdie 861
        $me->AddDependancy ( '$(SCM_MAKEFILE)' );
335 dpurdie 862
        $me->AddDependancy ( $dep );
227 dpurdie 863
        $me->AddDependancy ( @_resources );
864
        $me->AddDependancy ( @_csource );
865
        $me->AddDependancy ( @_dtd );
866
        $me->AddDependancy ( $_icon );
867
        $me->AddRecipe ( '$(CSC)' );
868
        $me->Print();
869
 
870
 
871
        #
872
        #.. Compiler command file
873
        #       Now piece together a variable $(name_ld) which ends up in
874
        #       the command file linking the application.
875
        #
876
 
877
        $io->Label( "Linker commands", $name );     # label
878
        $io->SetTag( "${lib}_ld" );                 # macro tag
879
 
880
        $io->Label( "Linker Command File", $lib ); # label
881
 
882
        #
883
        #   Basic options
884
        #
885
        $io->Cmd( "/target:$link_target" );
886
        $io->Cmd( "/doc:$_docFile")                    if ( $_docFile ) ;
887
        $io->Cmd( "/win32icon:\$(subst /,\\\\,$_icon)" ) if $_icon;
888
 
889
        #
890
        #   Add in the Resource Files
891
        #          the source files
892
        #          the libraries
893
        #
894
        $io->Cmd( "/res:\$(subst /,\\\\,$_)" ) foreach @_resources;
895
        $io->Cmd( "/res:\$(subst /,\\\\,$_)" ) foreach @_dtd;
896
        $io->Cmd( "\$(subst /,\\\\,$_)" ) foreach @_csource;
897
        $io->LibList( $name, $_pLibs, \&ToolsetLibRecipe );
335 dpurdie 898
        $io->Newline();
227 dpurdie 899
 
335 dpurdie 900
        #.. Dependency link,
901
        #   Create a library dependency file
902
        #       Create command file to build applicaton dependency list
903
        #       from the list of dependent libraries
227 dpurdie 904
        #
335 dpurdie 905
        #       Create makefile directives to include the dependency
906
        #       list into the makefile.
227 dpurdie 907
        #
335 dpurdie 908
        $io->DepRules( $_pLibs, \&ToolsetLibRecipe, $full );
909
        $io->SHLDDEPEND( $name, $lib  );
227 dpurdie 910
 
911
        #
912
        #   Files to clean up
913
        #
914
        ToolsetGenerate( "$root.ld" );
915
        ToolsetGenerate( "$root.pdb" );
916
        ToolsetGenerate( $_docFile ) if $_docFile;
917
 
918
 
919
        #.. Package up files that are a part of the Library
920
        #
921
        PackageShlibAddFiles ( $name, $full );
922
        PackageShlibAddFiles ( $name, "$root.pdb", "Class=debug" ) unless ( $_no_pdb );
923
        PackageShlibAddFiles ( $name, $_docFile  , "Class=map" ) if ( $_docFile );
924
 
925
        #
926
        #   Return the full name of the created DLL.
927
        #
928
        return $full;
929
    }
930
 
931
    #
932
    #   Generate DLLs
933
    #
934
    #       a) Unversioned DLL  $_name$(GBE_TYPE).dll
935
    #       b) Versioned DLL    $_name$(GBE_TYPE).xx.xx.xx.dll
936
    #
937
    my $funver = BuildSHLD( "$_name", "$_name\$(GBE_TYPE)" );
2931 dpurdie 938
    unless ($noVersionedDlls)
939
    {
940
        my $fver   = BuildSHLD( "$_name", "$_name\$(GBE_TYPE).$_ver" );
227 dpurdie 941
 
2931 dpurdie 942
        #
943
        #   Create a dependancy between the version and unversioned DLLs
944
        #
945
        my $me = MakeEntry::New (*MAKEFILE, $fver );
946
        $me->AddComment ("Link Version and Unversioned Images: $_name" );
947
        $me->AddDependancy ( $funver );
948
        $me->Print();
949
    }
227 dpurdie 950
}
951
 
952
########################################################################
953
#
954
#   Generate a linker/depend library recipe.  This is a helper function
955
#   used within this toolset.
956
#
957
#   Arguments:
958
#       $io         I/O stream
959
#
960
#       $target     Name of the target
961
#
962
#       $lib        Library specification
963
#
964
#       $dp         If building a depend list, the full target name.
965
#
966
########################################################################
967
 
968
sub ToolsetLibRecipe
969
{
970
    my ($io, $target, $lib, $dp) = @_;
971
 
972
    if ( !defined($dp) ) {                      # linker
973
        $io->Cmd( "/reference:\$(subst /,\\\\,\$(strip $lib)).$::so" );
974
 
975
    } else {                                    # depend
255 dpurdie 976
        $io->Cmd( "$dp:\t@(vglob2,$lib.$::so,CS_LIB)" );
227 dpurdie 977
    }
978
}
979
 
980
########################################################################
981
#
982
#   Generate a project from the provided project solution file
983
#   This is aimed at .NET work
984
#
985
#   Arguments   : $name             - Base name of the project
986
#                 $solution         - Path to the solutionn file
987
#                 $pArgs            - Project specific options
988
#
989
########################################################################
990
 
991
my $project_defines_done = 0;
992
sub ToolsetPROJECT
993
{
994
    my( $name, $solution ,$pArgs ) = @_;
995
    my $buildcmd = 'devenv =DSW= /build =TYPE= /useenv /out =LOG=';
996
    my $cleancmd = 'devenv =DSW= /clean =TYPE= /useenv';
343 dpurdie 997
    my $release = 'RELEASE';
998
    my $debug = 'DEBUG';
227 dpurdie 999
 
1000
    #
1001
    #   Process options
1002
    #
1003
    foreach ( @$pArgs ) {
343 dpurdie 1004
        if ( m/^--TargetProd*=(.+)/ ) {
1005
            $release = $1;
1006
 
1007
        } elsif ( m/^--TargetDebug=(.+)/ ) {
1008
            $debug = $1;
1009
 
1010
        } else {
1011
            Message( "$toolset_name PROJECT: unknown option $_ -- ignored\n" );
1012
        }
227 dpurdie 1013
    }
1014
 
1015
    my ($io) = ToolsetPrinter::New();
1016
 
1017
    #
343 dpurdie 1018
    #   Setup toolset specific difinitions. Once
227 dpurdie 1019
    #
1020
    unless( $project_defines_done )
1021
    {
1022
        $project_defines_done = 1;
343 dpurdie 1023
        $io->PrtLn( 'project_target = $(if $(findstring 1,$(DEBUG)),$2,$1)' );
227 dpurdie 1024
        $io->Newline();
1025
    }
1026
 
1027
    #
1028
    #   Process the build and clean commands
1029
    #       Substitute arguments
1030
    #           =TYPE=
1031
    #           =LOG=
1032
    #           =DSW=
1033
    #
343 dpurdie 1034
    $buildcmd =~ s~=TYPE=~"\$(call project_target,$release,$debug)"~g;
227 dpurdie 1035
    $buildcmd =~ s~=LOG=~$name\$(GBE_TYPE).log~g;
1036
    $buildcmd =~ s~=DSW=~$solution~g;
1037
 
343 dpurdie 1038
    $cleancmd =~ s~=TYPE=~"\$(call project_target,$release,$debug)"~g;
227 dpurdie 1039
    $cleancmd =~ s~=LOG=~$name\$(GBE_TYPE).log~g;
1040
    $cleancmd =~ s~=DSW=~$solution~g;
1041
 
1042
    #
1043
    #   Generate the recipe to create the project
1044
    #   Use the set_<PLATFORM>.sh file to extend the DLL search path
1045
    #
1046
    $io->Label( "Build project", $name );
1047
    $io->PrtLn( "Project_$name: $solution \$(INTERFACEDIR)/set_$::ScmPlatform.sh" );
1048
 
1049
    $io->PrtLn( "\t\$(XX_PRE)( \$(rm) -f $name\$(GBE_TYPE).log; \\" );
1050
    $io->PrtLn( "\t. \$(INTERFACEDIR)/set_$::ScmPlatform.sh; \\" );
255 dpurdie 1051
    $io->PrtLn( "\t\$(show_environment); \\" );
227 dpurdie 1052
    $io->PrtLn( "\t$buildcmd; \\" );
1053
    $io->PrtLn( "\tret=\$\$?; \\" );
1054
    $io->PrtLn( "\t\$(GBE_BIN)/cat $name\$(GBE_TYPE).log; \\" );
1055
    $io->PrtLn( "\texit \$\$ret )" );
1056
    $io->Newline();
1057
 
1058
    #
1059
    #   Generate the recipe to clean the project
1060
    #
1061
    $io->Label( "Clean project", $name );
1062
    $io->PrtLn( "ProjectClean_$name: $solution" );
1063
    $io->PrtLn( "\t-\$(XX_PRE)$cleancmd" );
1064
    $io->PrtLn( "\t-\$(XX_PRE)\$(rm) -f $name\$(GBE_TYPE).log" );
1065
    $io->Newline();
1066
 
1067
}
1068
 
1069
#-------------------------------------------------------------------------------
1070
# Function        : ToolsetTESTFRAMEWORK_NUNIT
1071
#
1072
# Description     : Toolset specfic support for the NUNIT Test FrameWork
1073
#                   Accessed with RunTest ('*', --FrameWork=nunit, ... );
1074
#
1075
#                   Manipulates the pEntry structure to allow JATS to
1076
#                   construct a test entry to run Nunit tests
1077
#
1078
# Inputs          : $pEntry                 - Unit Test Hash
1079
#
1080
# Returns         : Modified Hash
1081
#
1082
sub ToolsetTESTFRAMEWORK_NUNIT
1083
{
1084
    my ($pEntry) = @_;
1085
    my $test_dll_name;
1086
    my @copy_dlls;
1087
    my %copy_dll_flags;
1088
 
1089
    #
1090
    #   Extract base name of DLL under test
1091
    #   Thsi will not have any extension.
1092
    #
1093
    $test_dll_name = $pEntry->{'prog'};
1094
    Error ("Nunit Framework. No TestDLL specified") unless $test_dll_name;
1095
 
1096
    #
1097
    #   Process the FrameWork Options
1098
    #
1099
    foreach  ( @{$pEntry->{'framework_opts'}} )
1100
    {
1101
        if ( m/^--Uses=(.+)/ ) {
1102
            my ($dll, @opts) = split (',', $1 );
1103
            push @copy_dlls, $dll;
1104
            foreach  ( @opts )
1105
            {
1106
                if ( m~^--NonJats~i ) {
1107
                    $copy_dll_flags{$dll}{'NonJats'} = 1;
1108
                } elsif ( m~--Jats~ ) {
1109
                    $copy_dll_flags{$dll}{'NonJats'} = 0;
1110
                } else {
1111
                    Error ("Nunit Framework. Unknown sub option to --Uses: $_");
1112
                }
1113
            }
1114
        } else {
1115
            Error ("Nunit Framework. Unknown option: $_");
1116
        }
1117
    }
1118
 
1119
    #
1120
    #   Locate the Nunit essentials
261 dpurdie 1121
    #       This list may change with each version of nunit
1122
    #       Look for a known file and use its contents
1123
    #       Format:
1124
    #           One file name per line
1125
    #           Line comments only
1126
    #           Comment marker is a #
1127
    #           First one MUST be the executable
227 dpurdie 1128
    #
261 dpurdie 1129
    my @nunit_files;
227 dpurdie 1130
 
261 dpurdie 1131
    my $mfile = 'nunit-jats-manifest.txt';
1132
    my $nunit_file = ToolExtensionProgram ( $mfile );
1133
    Error ("Cannot find Nunit Jats Manifest: $mfile") unless ( $nunit_file );
1134
    open (JM, $nunit_file ) || Error( "Cannot open file: $nunit_file", "Reason: $!" );
1135
    while ( <JM> )
1136
    {
1137
        s~\s+$~~;                   # Remove trailing white space
1138
        s~^\s+~~;                   # Remove Leading whitespace
1139
        next unless ( $_ );         # Skip block lines
1140
        next if ( m~^#~ );          # Skip comments
1141
        Verbose ("Nunit File: $_");
1142
        push @nunit_files, $_;
1143
    }
1144
    close JM;
1145
 
1146
    #
1147
    #   Locate all the required files
1148
    #   The first one will be the console executable
1149
    #
227 dpurdie 1150
    my @nunit_framework;
1151
    foreach my $file ( @nunit_files )
1152
    {
1153
        my $path = ToolExtensionProgram ($file );
1154
        Error ("Cannot locate nunit file: $file") unless ( $path );
1155
        push @nunit_framework, $path;
1156
    }
261 dpurdie 1157
    my $nunit_console = $nunit_framework[0];
1158
    Error ("Nunit console executable not specified") unless ( $nunit_console );
227 dpurdie 1159
 
1160
    #
1161
    #   Locate the test DLL.
1162
    #   This will be created locally within this makefile
1163
    #   It will be a known shared library
1164
    #
1165
    Errror( "TestDLL does not appear to be locally created: $test_dll_name" )
289 dpurdie 1166
        unless ( $::SHLIBS->Get($test_dll_name) );
227 dpurdie 1167
 
1168
    #
1169
    #   Hard bit. Determine the name/path of the DLL under test
1170
    #   It will have been created within this makefile
1171
    #   This is not a physical file.
1172
    #
1173
    $test_dll_name = $test_dll_name . '$(GBE_TYPE).' . $::so;
1174
    my $test_dll = '$(LIBDIR)/' . $test_dll_name;
1175
 
1176
    #
1177
    #   Other hard bit
1178
    #   Locate the other dll's needed by this test
1179
    #   Need to use P in production and D in Debug unless otherwise specified
1180
    #   These might be in:
1181
    #       an external package
1182
    #       within the local directory
1183
    #       the current makefile
1184
    #   ie: We can only determine the location of the files at run-time
1185
    #
1186
    #   The mechanism used is:
1187
    #       Create makefile recipe entries to
1188
    #           Use cmdfile to create a command file with copy command
1189
    #           Execute the command file
1190
    #
1191
    #   Complications include:
1192
    #       The windows shell used does not honour 'set -e', so we need to
1193
    #       detect error conditions ourselves
1194
    #
1195
    my $ofile = "\$(TESTDIR)/$pEntry->{test_name}.cmd";
1196
    push @{$pEntry->{'ShellRecipe'}}, "rm -f $ofile";
1197
 
1198
    my @cmds;
363 dpurdie 1199
    push @cmds, "\$(cmdfile) -wk1W1o$ofile";
227 dpurdie 1200
    foreach my $dll ( @copy_dlls )
1201
    {
1202
        #
1203
        #   Generate in-line commands to locate and copy in the required
1204
        #   DLL's. The 'cmdfile' utility can be used to do this at runtime
1205
        #
1206
        my $dll_name = $dll;
1207
        $dll_name .= '$(GBE_TYPE)' unless ( $copy_dll_flags{$dll}{'NonJats'} );
1208
 
363 dpurdie 1209
        push @cmds, '"' . "cp -f @(vglob2,$dll_name.$::so,PATH,/) \$(TESTDIR) || exit 98" . '\n"';
227 dpurdie 1210
    }
1211
    push @cmds, "|| exit 99";
1212
    push @{$pEntry->{'ShellRecipe'}}, \@cmds;
1213
    push @{$pEntry->{'ShellRecipe'}}, ". $ofile";
1214
 
1215
 
1216
    #
1217
    #   Add items to the Unit Test Hash
1218
    #       command     - command to execute to run the test program
1219
    #       prog        - test command/script that must be in the test dir
1220
    #       copyprog    - Prog must be copied in
1221
    #       args        - Arguments to the test
1222
    #       copyin      - Array of files to copy into the test directory
1223
    #       copyonce    - Array of files to copy only once
1224
    #       prereq      - Prerequiste conditions
1225
    #       testdir     - Symbolic name of the test directory
1226
    #       ShellRecipe - Recipe Bits to add
1227
    #
1228
    $pEntry->{'command'}  = $nunit_console . ' ' . $test_dll_name;
1229
    unshift @{$pEntry->{args}}, "/xml=$pEntry->{test_name}.xml";
1230
    $pEntry->{'prog'} = $test_dll_name;
1231
    $pEntry->{'copyprog'} = 0;
1232
    push @{$pEntry->{'copyin'}}, $test_dll;
261 dpurdie 1233
    push @{$pEntry->{'copyonce'}}, @nunit_framework;
227 dpurdie 1234
    $pEntry->{'testdir'}  = 'TESTDIR';
1235
 
1236
    #   
1237
    #   Create the Test Directory
1238
    #   Tests will be done in a .NUNIT subdir
1239
    #
1240
    MkdirRule( "\$(TESTDIR)", 'TESTDIR', '--Path=$(GBE_PLATFORM)$(GBE_TYPE).NUNIT', '--RemoveAll' );
1241
 
1242
    #
1243
    #   Files created by the Unit Test
1244
    #
1245
    ToolsetGenerate ( "\$(TESTDIR)/$pEntry->{test_name}.xml"  );
1246
    ToolsetGenerate ( $ofile  );
1247
 
1248
}
1249
 
1250
#.. Successful termination
1251
1;
1252