Subversion Repositories gelsvn

Rev

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

Rev Author Line No. Line
107 bj 1
package Options;
2
 
3
# ************************************************************
4
# Description   : Process mpc command line options
5
# Author        : Chad Elliott
6
# Create Date   : 3/20/2003
7
# ************************************************************
8
 
9
# ************************************************************
10
# Pragmas
11
# ************************************************************
12
 
13
use strict;
14
 
15
use DirectoryManager;
16
 
17
# ************************************************************
18
# Data Section
19
# ************************************************************
20
 
217 bj 21
my($deflang)   = 'cplusplus';
107 bj 22
my(%languages) = ('cplusplus' => 1,
23
                  'csharp'    => 1,
24
                  'java'      => 1,
25
                  'vb'        => 1,
26
                 );
27
 
28
# ************************************************************
29
# Subroutine Section
30
# ************************************************************
31
 
32
sub printUsage {
33
  my($self)    = shift;
34
  my($msg)     = shift;
35
  my($base)    = shift;
36
  my($version) = shift;
37
  my($default) = shift;
38
  my(@types)   = @_;
39
 
40
  if (defined $msg) {
41
    print STDERR "ERROR: $msg\n";
42
  }
43
  my($spaces) = (' ' x (length($base) + 8));
44
  print STDERR "$base v$version\n" .
45
               "Usage: $base [-global <file>] [-include <directory>] [-recurse]\n" .
46
               $spaces . "[-ti <dll | lib | dll_exe | lib_exe>:<file>] [-hierarchy]\n" .
47
               $spaces . "[-template <file>] [-relative NAME=VAR] [-base <project>]\n" .
48
               $spaces . "[-noreldefs] [-notoplevel] [-static] [-genins] [-use_env]\n" .
49
               $spaces . "[-value_template <NAME+=VAL | NAME=VAL | NAME-=VAL>]\n" .
50
               $spaces . "[-value_project <NAME+=VAL | NAME=VAL | NAME-=VAL>]\n" .
51
               $spaces . "[-make_coexistence] [-feature_file <file name>]\n" .
52
               $spaces . "[-expand_vars] [-features <feature definitions>]\n" .
53
               $spaces . "[-exclude <directories>] [-name_modifier <pattern>]\n" .
54
               $spaces . "[-apply_project] [-version] [-into <directory>]\n" .
217 bj 55
               $spaces . "[-gfeature_file <file name>]\n" .
107 bj 56
               $spaces . "[-language <";
57
 
58
  my(@keys) = sort keys %languages;
59
  for(my $i = 0; $i <= $#keys; $i++) {
60
    print STDERR $keys[$i];
61
    if ($i != $#keys) {
62
      print STDERR ' | ';
63
    }
64
    if ($i != $#keys && (($i + 1) % 4) == 0) {
65
      print STDERR "\n$spaces        ";
66
    }
67
  }
68
  print STDERR ">]\n",
69
               $spaces, "[-type <";
70
 
71
  @keys = sort @types;
72
  for(my $i = 0; $i <= $#keys; $i++) {
73
    print STDERR $keys[$i];
74
    if ($i != $#keys) {
75
      print STDERR ' | ';
76
    }
77
    if ($i != $#keys && (($i + 1) % 6) == 0) {
78
      print STDERR "\n$spaces        ";
79
    }
80
  }
81
  print STDERR ">]\n" .
82
               $spaces . "[files]\n\n";
83
 
84
  print STDERR
85
"       -base           Add <project> as a base project to each generated\n" .
86
"                       project file.  Do not provide a file extension, the\n" .
87
"                       .mpb extension will be tried first; if that fails the\n" .
88
"                       .mpc extension will be tried.\n" .
89
"       -exclude        Use this option to exclude directories when searching\n" .
90
"                       for input files.\n" .
91
"       -expand_vars    Perform direct expansion, instead of performing relative\n" .
92
"                       replacement with either -use_env or -relative options.\n" .
93
"       -feature_file   Specifies the feature file to read before processing.\n" .
94
"                       The default feature file is default.features under the\n" .
95
"                       config directory.\n" .
96
"       -features       Specifies the feature list to set before processing.\n" .
97
"       -genins         Generate .ins files for use with prj_install.pl.\n" .
217 bj 98
"       -gfeature_file  Specifies the global feature file.  The\n" .
99
"                       default value is global.features under the\n" .
100
"                       config directory.\n" .
107 bj 101
"       -global         Specifies the global input file.  Values stored\n" .
102
"                       within this file are applied to all projects.\n" .
103
"       -hierarchy      Generate a workspace in a hierarchical fashion.\n" .
104
"       -include        Specifies a directory to search when looking for base\n" .
105
"                       projects, template input files and templates.  This\n" .
106
"                       option can be used multiple times to add directories.\n" .
107
"       -into           Place all output files in a mirrored directory\n" .
108
"                       structure starting at <directory>.\n" .
217 bj 109
"       -language       Specify the language preference; possible values are\n",
110
"                       [", join(' ', sort keys %languages), "].  The default is\n".
111
"                       $deflang.\n",
107 bj 112
"       -make_coexistence If multiple 'make' based project types are\n" .
113
"                       generated, they will be named such that they can coexist.\n" .
114
"       -name_modifier  Modify output names.  The pattern passed to this\n" .
115
"                       parameter will have the '*' portion replaced with the\n" .
116
"                       actual output name.  Ex. *_Static\n" .
117
"       -apply_project  When used in conjunction with -name_modifier, it applies\n" .
118
"                       the name modifier to the project name also.\n" .
119
"       -noreldefs      Do not try to generate default relative definitions.\n" .
120
"       -notoplevel     Do not generate the top level target file.  Files\n" .
121
"                       are still process, but no top level file is created.\n" .
122
"       -recurse        Recurse from the current directory and generate from\n" .
123
"                       all found input files.\n" .
124
"       -relative       Any \$() variable in an mpc file that is matched to NAME\n" .
125
"                       is replaced by VAR only if VAR can be made into a\n" .
126
"                       relative path based on the current working directory.\n" .
127
"       -static         Specifies that only static projects will be generated.\n" .
128
"                       By default, only dynamic projects are generated.\n" .
129
"       -ti             Specifies the template input file (with no extension)\n" .
130
"                       for the specific type (ex. -ti dll_exe:vc8exe).\n" .
131
"       -template       Specifies the template name (with no extension).\n" .
132
"       -type           Specifies the type of project file to generate.  This\n" .
133
"                       option can be used multiple times to generate multiple\n" .
134
"                       types.  If -type is not used, it defaults to '$default'.\n" .
135
"       -use_env        Use environment variables for all uses of \$() instead\n" .
136
"                       of the relative replacement values.\n" .
137
"       -value_project  This option allows modification of a project variable\n" .
138
"                       assignment .  Use += to add VAL to the NAME's value.\n" .
139
"                       Use -= to subtract and = to override the value.\n" .
140
"                       This can be used to introduce new name value pairs to\n" .
141
"                       a project.  However, it must be a valid project\n" .
142
"                       assignment.\n" .
143
"       -value_template This option allows modification of a template input\n" .
144
"                       name value pair.  Use += to add VAL to the NAME's\n" .
145
"                       value.  Use -= to subtract and = to override the value.\n" .
146
"       -version        Print the MPC version and exit.\n";
147
 
148
  exit(0);
149
}
150
 
151
 
152
sub optionError {
153
  #my($self) = shift;
154
  #my($str)  = shift;
155
}
156
 
157
 
158
sub completion_command {
159
  my($self)  = shift;
160
  my($name)  = shift;
161
  my($types) = shift;
162
  my($str)   = "complete $name " .
163
               "'c/-/(genins global include type template relative " .
164
               "ti static noreldefs notoplevel feature_file use_env " .
165
               "value_template value_project make_coexistence language " .
166
               "hierarchy exclude name_modifier apply_project version " .
217 bj 167
               "expand_vars gfeature_file)/' " .
107 bj 168
               "'c/dll:/f/' 'c/dll_exe:/f/' 'c/lib_exe:/f/' 'c/lib:/f/' " .
169
               "'n/-ti/(dll lib dll_exe lib_exe)/:' ";
170
 
171
  $str .= "'n/-language/(";
172
  my(@keys) = sort keys %languages;
173
  for(my $i = 0; $i <= $#keys; $i++) {
174
    $str .= $keys[$i];
175
    if ($i != $#keys) {
176
      $str .= " ";
177
    }
178
  }
179
  $str .= ")/' 'n/-type/(";
180
 
181
  @keys = sort keys %$types;
182
  for(my $i = 0; $i <= $#keys; $i++) {
183
    $str .= $keys[$i];
184
    if ($i != $#keys) {
185
      $str .= " ";
186
    }
187
  }
188
  $str .= ")/'";
189
  return $str;
190
}
191
 
192
 
193
sub options {
194
  my($self)       = shift;
195
  my($name)       = shift;
196
  my($types)      = shift;
197
  my($defaults)   = shift;
198
  my(@args)       = @_;
199
  my(@include)    = ();
200
  my(@input)      = ();
201
  my(@creators)   = ();
202
  my(@baseprojs)  = ();
203
  my(%ti)         = ();
204
  my(%relative)   = ();
205
  my(%addtemp)    = ();
206
  my(%addproj)    = ();
207
  my(@exclude)    = ();
208
  my($global)     = undef;
209
  my($template)   = undef;
210
  my($feature_f)  = undef;
217 bj 211
  my($gfeature_f) = undef;
107 bj 212
  my(@features)   = ();
213
  my($nmodifier)  = undef;
214
  my($into)       = undef;
215
  my($hierarchy)  = 0;
217 bj 216
  my($language)   = ($defaults ? $deflang : undef);
107 bj 217
  my($dynamic)    = ($defaults ? 1 : undef);
218
  my($reldefs)    = ($defaults ? 1 : undef);
219
  my($toplevel)   = ($defaults ? 1 : undef);
220
  my($use_env)    = ($defaults ? 0 : undef);
221
  my($expandvars) = ($defaults ? 0 : undef);
222
  my($static)     = ($defaults ? 0 : undef);
223
  my($recurse)    = ($defaults ? 0 : undef);
224
  my($makeco)     = ($defaults ? 0 : undef);
225
  my($applypj)    = ($defaults ? 0 : undef);
226
  my($genins)     = ($defaults ? 0 : undef);
227
 
228
  ## Process the command line arguments
229
  for(my $i = 0; $i <= $#args; $i++) {
230
    my($arg) = $args[$i];
231
    $arg =~ s/^--/-/;
232
 
233
    if ($arg eq '-apply_project') {
234
      $applypj = 1;
235
    }
236
    elsif ($arg eq '-complete') {
237
      print $self->completion_command($name, $types) . "\n";
238
      return undef;
239
    }
240
    elsif ($arg eq '-base') {
241
      $i++;
242
      if (!defined $args[$i]) {
243
        $self->optionError('-base requires an argument');
244
      }
245
      else {
246
        push(@baseprojs, $args[$i]);
247
      }
248
    }
249
    elsif ($arg eq '-type') {
250
      $i++;
251
      if (!defined $args[$i]) {
252
        $self->optionError('-type requires an argument');
253
      }
254
      else {
255
        my($type) = lc($args[$i]);
256
        if (defined $types->{$type}) {
257
          my($call)  = $types->{$type};
258
          my($found) = 0;
259
          foreach my $creator (@creators) {
260
            if ($creator eq $call) {
261
              $found = 1;
262
              last;
263
            }
264
          }
265
          if (!$found) {
266
            push(@creators, $call);
267
          }
268
        }
269
        else {
270
          $self->optionError("Invalid type: $args[$i]");
271
        }
272
      }
273
    }
274
    elsif ($arg eq '-exclude') {
275
      $i++;
276
      if (defined $args[$i]) {
217 bj 277
        foreach my $exclude (split(',', $args[$i])) {
278
          push(@exclude, DirectoryManager::mpc_glob(undef, $exclude));
279
        }
107 bj 280
      }
281
      else {
282
        $self->optionError('-exclude requires a ' .
283
                           'comma separated list argument');
284
      }
285
    }
286
    elsif ($arg eq '-expand_vars') {
287
      $expandvars = 1;
288
    }
289
    elsif ($arg eq '-feature_file') {
290
      $i++;
291
      $feature_f = $args[$i];
292
      if (!defined $feature_f) {
293
        $self->optionError('-feature_file requires a file name argument');
294
      }
295
    }
296
    elsif ($arg eq '-features') {
297
      $i++;
298
      if (defined $args[$i]) {
299
        @features = split(',', $args[$i]);
300
      }
301
      else {
302
        $self->optionError('-features requires a comma separated list argument');
303
      }
304
    }
217 bj 305
    elsif ($arg eq '-gfeature_file') {
306
      $i++;
307
      $gfeature_f = $args[$i];
308
      if (!defined $gfeature_f) {
309
        $self->optionError('-gfeature_file ' .
310
                           'requires a file name argument');
311
      }
312
    }
107 bj 313
    elsif ($arg eq '-genins') {
314
      $genins = 1;
315
    }
316
    elsif ($arg eq '-global') {
317
      $i++;
318
      $global = $args[$i];
319
      if (!defined $global) {
320
        $self->optionError('-global requires a file name argument');
321
      }
322
    }
323
    elsif ($arg eq '-hierarchy') {
324
      $hierarchy = 1;
325
    }
326
    elsif ($arg eq '-include') {
327
      $i++;
328
      my($include) = $args[$i];
329
      if (!defined $include) {
330
        $self->optionError('-include requires a directory argument');
331
      }
332
      else {
333
        ## If the specified include path is relative, expand it based on
334
        ## the current working directory.
335
        if ($include !~ /^[\/\\]/ &&
336
            $include !~ /^[A-Za-z]:[\/\\]?/) {
337
          $include = DirectoryManager::getcwd() . '/' . $include;
338
        }
339
 
340
        push(@include, $include);
341
      }
342
    }
343
    elsif ($arg eq '-into') {
344
      $i++;
345
      $into = $args[$i];
346
      if (!defined $into) {
347
        $self->optionError('-into requires a directory argument');
348
      }
349
    }
350
    elsif ($arg eq '-language') {
351
      $i++;
352
      $language = $args[$i];
353
      if (!defined $language) {
354
        $self->optionError('-language requires a language argument');
355
      }
356
      elsif (!defined $languages{$language}) {
357
        $self->optionError("$language is not a valid language");
358
      }
359
    }
360
    elsif ($arg eq '-make_coexistence') {
361
      $makeco = 1;
362
    }
363
    elsif ($arg eq '-name_modifier') {
364
      $i++;
365
      my($nmod) = $args[$i];
366
      if (!defined $nmod) {
367
        $self->optionError('-name_modifier requires a modifier argument');
368
      }
369
      else {
370
        $nmodifier = $nmod;
371
      }
372
    }
373
    elsif ($arg eq '-noreldefs') {
374
      $reldefs = 0;
375
    }
376
    elsif ($arg eq '-notoplevel') {
377
      $toplevel = 0;
378
    }
379
    elsif ($arg eq '-recurse') {
380
      $recurse = 1;
381
    }
382
    elsif ($arg eq '-template') {
383
      $i++;
384
      $template = $args[$i];
385
      if (!defined $template) {
386
        $self->optionError('-template requires a file name argument');
387
      }
388
    }
389
    elsif ($arg eq '-relative') {
390
      $i++;
391
      my($rel) = $args[$i];
392
      if (!defined $rel) {
393
        $self->optionError('-relative requires a variable assignment argument');
394
      }
395
      else {
396
        if ($rel =~ /(\w+)\s*=\s*(.*)/) {
397
          my($name) = $1;
398
          my($val)  = $2;
399
          $val =~ s/^\s+//;
400
          $val =~ s/\s+$//;
401
 
402
          ## If the specified path is relative, expand it based on
403
          ## the current working directory.
404
          if ($val !~ /^[\/\\]/ &&
405
              $val !~ /^[A-Za-z]:[\/\\]?/) {
406
            $val = DirectoryManager::getcwd() . '/' . $val;
407
          }
408
 
409
          ## Clean up the path as much as possible
410
          $relative{$name} = File::Spec->canonpath($val);
411
          $relative{$name} =~ s/\\/\//g;
412
        }
413
        else {
414
          $self->optionError('Invalid argument to -relative');
415
        }
416
      }
417
    }
418
    elsif ($arg eq '-ti') {
419
      $i++;
420
      my($tmpi) = $args[$i];
421
      if (!defined $tmpi) {
422
        $self->optionError('-ti requires a template input argument');
423
      }
424
      else {
425
        if ($tmpi =~ /((dll|lib|dll_exe|lib_exe):)?(.*)/) {
426
          my($key)  = $2;
427
          my($name) = $3;
428
          if (defined $key) {
429
            $ti{$key} = $name;
430
          }
431
          else {
432
            foreach my $type ('dll', 'lib', 'dll_exe', 'lib_exe') {
433
              $ti{$type} = $name;
434
            }
435
          }
436
        }
437
        else {
438
          $self->optionError("Invalid -ti argument: $tmpi");
439
        }
440
      }
441
    }
442
    elsif ($arg eq '-use_env') {
443
      $use_env = 1;
444
    }
445
    elsif ($arg eq '-value_template') {
446
      $i++;
447
      my($value) = $args[$i];
448
      if (!defined $value) {
449
        $self->optionError('-value_template requires a variable assignment argument');
450
      }
451
      else {
452
        if ($value =~ /(\w+)\s*([\-+]?=)\s*(.*)/) {
453
          my($name) = lc($1);
454
          my($op)   = $2;
455
          my($val)  = $3;
456
          $val =~ s/^\s+//;
457
          $val =~ s/\s+$//;
458
          if ($op eq '+=') {
459
            $op = 1;
460
          }
461
          elsif ($op eq '-=') {
462
            $op = -1;
463
          }
464
          else {
465
            $op = 0;
466
          }
467
          if (!defined $addtemp{$name}) {
468
            $addtemp{$name} = [];
469
          }
470
          push(@{$addtemp{$name}}, [$op, $val]);
471
        }
472
        else {
473
          $self->optionError('Invalid argument to -value_template');
474
        }
475
      }
476
    }
477
    elsif ($arg eq '-value_project') {
478
      $i++;
479
      my($value) = $args[$i];
480
      if (!defined $value) {
481
        $self->optionError('-value_project requires a variable assignment argument');
482
      }
483
      else {
484
        if ($value =~ /(\w+)\s*([\-+]?=)\s*(.*)/) {
485
          my($name) = lc($1);
486
          my($op)   = $2;
487
          my($val)  = $3;
488
          $val =~ s/^\s+//;
489
          $val =~ s/\s+$//;
490
          if ($op eq '+=') {
491
            $op = 1;
492
          }
493
          elsif ($op eq '-=') {
494
            $op = -1;
495
          }
496
          else {
497
            $op = 0;
498
          }
499
          $addproj{$name} = [$op, $val];
500
        }
501
        else {
502
          $self->optionError('Invalid argument to -value_project');
503
        }
504
      }
505
    }
506
    elsif ($arg eq '-version') {
507
      print 'MPC v', Version::get(), "\n";
508
      return undef;
509
    }
510
    elsif ($arg eq '-static') {
511
      $static  = 1;
512
      $dynamic = 0;
513
    }
514
    elsif ($arg =~ /^-/) {
515
      $self->optionError("Unknown option: $arg");
516
    }
517
    else {
518
      push(@input, $arg);
519
    }
520
  }
521
 
217 bj 522
  return {'global'        => $global,
523
          'feature_file'  => $feature_f,
524
          'gfeature_file' => $gfeature_f,
525
          'features'      => \@features,
526
          'include'       => \@include,
527
          'input'         => \@input,
528
          'creators'      => \@creators,
529
          'baseprojs'     => \@baseprojs,
530
          'template'      => $template,
531
          'ti'            => \%ti,
532
          'dynamic'       => $dynamic,
533
          'static'        => $static,
534
          'relative'      => \%relative,
535
          'reldefs'       => $reldefs,
536
          'toplevel'      => $toplevel,
537
          'recurse'       => $recurse,
538
          'addtemp'       => \%addtemp,
539
          'addproj'       => \%addproj,
540
          'coexistence'   => $makeco,
541
          'hierarchy'     => $hierarchy,
542
          'exclude'       => \@exclude,
543
          'name_modifier' => $nmodifier,
544
          'apply_project' => $applypj,
545
          'genins'        => $genins,
546
          'into'          => $into,
547
          'language'      => $language,
548
          'use_env'       => $use_env,
549
          'expand_vars'   => $expandvars,
550
         };
107 bj 551
}
552
 
553
 
554
sub is_set {
555
  my($self)    = shift;
556
  my($key)     = shift;
557
  my($options) = shift;
558
 
559
  if (defined $options->{$key}) {
560
    if (UNIVERSAL::isa($options->{$key}, 'ARRAY')) {
561
      if (defined $options->{$key}->[0]) {
562
        return 'ARRAY';
563
      }
564
    }
565
    elsif (UNIVERSAL::isa($options->{$key}, 'HASH')) {
566
      my(@keys) = keys %{$options->{$key}};
567
      if (defined $keys[0]) {
568
        return 'HASH';
569
      }
570
    }
571
    else {
572
      return 'SCALAR';
573
    }
574
  }
575
 
576
  return undef;
577
}
578
 
579
1;