Merge pull request #224 from DOCGroup/jwillemsen-patch-1
[MPC.git] / modules / Depgen / Driver.pm
blob491d37b1bfa5be045e62b2ee435712bb9a7bf197
1 package Driver;
3 # ************************************************************
4 # Description : Generate dependencies for Make and NMake.
5 # Author : Chad Elliott
6 # Create Date : 3/21/2007
7 # ************************************************************
9 # ************************************************************
10 # Pragma Section
11 # ************************************************************
13 use strict;
14 use File::Basename;
16 use DependencyEditor;
18 # ************************************************************
19 # Data Section
20 # ************************************************************
22 my $version = '1.2';
23 my $os = ($^O eq 'MSWin32' ? 'Windows' : 'UNIX');
24 my %types;
25 my %defaults = ('UNIX' => 'make',
26 'Windows' => 'nmake',
29 # ************************************************************
30 # Subroutine Section
31 # ************************************************************
33 sub BEGIN {
34 my $fh = new FileHandle();
35 my(%writers, %generators);
37 ## Find all the dependency writers and object generators
38 foreach my $dir (@INC) {
39 if (opendir($fh, $dir)) {
40 foreach my $module (readdir($fh)) {
41 if ($module =~ /(.+)DependencyWriter\.pm$/) {
42 my $type = lc($1);
43 my $class = $module;
44 $class =~ s/\.pm$//;
45 require $module;
46 $writers{$type} = $class;
47 $types{$type} = 1;
49 elsif ($module =~ /(.+)ObjectGenerator\.pm$/) {
50 my $type = lc($1);
51 my $class = $module;
52 $class =~ s/\.pm$//;
53 require $module;
54 $generators{$type} = $class;
57 closedir($fh);
61 ## Register them with the right factory
62 DependencyWriterFactory::register(\%writers);
63 ObjectGeneratorFactory::register(\%generators);
67 sub new {
68 my $class = shift;
69 my $self = bless {'automatic' => [],
70 }, $class;
72 foreach my $add (@_) {
73 if ($add =~ /(UNIX|Windows)=(.*)/) {
74 $defaults{$1} = $2;
76 elsif ($add =~ /automatic=(.*)/) {
77 my @auto = split(/,/, $1);
78 $self->{'automatic'} = \@auto;
80 else {
81 print "WARNING: Unknown parameter: $add\n";
85 return $self;
89 sub usageAndExit {
90 my($self, $opt) = @_;
91 my $base = basename($0);
93 if (defined $opt) {
94 print "$opt.\n";
97 print "$base v$version\n" .
98 "Usage: $base [-D<MACRO>[=VALUE]] [-I<include dir>] ",
99 (defined $self->{'automatic'}->[0] ? "[-A] " : ''),
100 "[-R <VARNAME>]\n" .
101 " " . (" " x length($base)) .
102 " [-e <file>] [-f <output file>] [-g] [-i] [-t <type>] [-n]\n" .
103 " " . (" " x length($base)) . " <files...>\n" .
104 "\n";
105 if (defined $self->{'automatic'}->[0]) {
106 print "-A Replace paths equal to the following variables with ",
107 "the corresponding \$()\n value: ",
108 join(', ', @{$self->{'automatic'}}), ".\n";
110 print "-D This option sets a macro to an optional value.\n" .
111 "-I The -I option adds an include directory.\n" .
112 "-R Replace \$VARNAME paths with \$(VARNAME).\n" .
113 "-a Append to existing dependencies." .
114 (exists $types{'gnuidl'} ? ' Useful with -t gnuidl.' : '') . "\n" .
115 "-e Exclude dependencies generated by <file>, but not <file> " .
116 "itself.\n" .
117 "-f Specifies the output file. This file will be edited if it " .
118 "already\n exists.\n" .
119 "-g Do not create Cygwin paths when on Windows.\n" .
120 "-i Do not print an error if no source files are provided.\n" .
121 "-n Do not include inline files (ending in .i or .inl) in the " .
122 "dependencies.\n" .
123 "-t Use specified type (";
124 my @keys = sort keys %types;
125 for(my $i = 0; $i <= $#keys; ++$i) {
126 print "$keys[$i]" .
127 ($i != $#keys ? $i == $#keys - 1 ? ' or ' : ', ' : '');;
129 print ") instead of the default.\n" .
130 " The default is ";
131 @keys = sort keys %defaults;
132 for(my $i = 0; $i <= $#keys; ++$i) {
133 my $def = $keys[$i];
134 print $defaults{$def} . " on $def" .
135 ($i != $#keys ? $i == $#keys - 1 ? ' and ' : ', ' : '');
137 print ".\n";
138 exit(0);
142 sub setReplace {
143 my($self, $replace, $name, $value) = @_;
145 if (defined $name) {
146 ## The key will be used in a regular expression.
147 ## So, we need to escape some special characters.
148 $name = File::Spec->canonpath($name);
149 $name =~ s/([\+\-\\\$\[\]\(\)\.])/\\$1/g;
151 $$replace{$name} = $value;
156 sub run {
157 my($self, $args) = @_;
158 my $argc = scalar(@$args);
159 my $type = $defaults{$os};
160 my $output = '-';
161 my $needsrc = 1;
162 my($noinline, @files, %macros, @ipaths, %replace, %exclude, $append);
164 for(my $i = 0; $i < $argc; ++$i) {
165 my $arg = $$args[$i];
166 if ($arg =~ /^\-D(\w+)(=(.*))?/) {
167 $macros{$1} = $3;
169 elsif ($arg =~ /^\-(I|isystem)(.*)/) {
170 # support '-Idir' and '-I dir'
171 my $opt = $1;
172 if ('' ne $2) {
173 push(@ipaths, File::Spec->canonpath($2));
175 else {
176 # get next arg
177 if (++$i < $argc) {
178 $arg = $$args[$i];
179 if ($arg =~ /^\-/) {
180 $self->usageAndExit('Invalid use of -' . $opt);
183 push(@ipaths, File::Spec->canonpath($arg));
185 else {
186 $self->usageAndExit('Invalid use of -' . $opt);
190 elsif ($arg eq '-A') {
191 foreach my $auto (@{$self->{'automatic'}}) {
192 $self->setReplace(\%replace, $ENV{$auto}, '$(' . $auto . ')');
195 elsif ($arg eq '-R') {
196 ++$i;
197 $arg = $$args[$i];
198 if (defined $arg) {
199 my $val = $ENV{$arg};
200 if (defined $val) {
201 $self->setReplace(\%replace, $val, "\$($arg)");
204 else {
205 $self->usageAndExit('Invalid use of -R');
208 elsif ($arg eq '-e') {
209 ++$i;
210 $arg = $$args[$i];
211 if (defined $arg) {
212 $exclude{$arg} = 1;
214 else {
215 $self->usageAndExit('Invalid use of -e');
218 elsif ($arg eq '-f') {
219 ++$i;
220 $arg = $$args[$i];
221 if (defined $arg) {
222 $output = $arg;
224 else {
225 $self->usageAndExit('Invalid use of -f');
228 elsif ($arg eq '-g') {
229 ## By default, on Windows, we assume Cygwin and create paths with
230 ## /cygdrive. Some users have a non-Cygwin make and need paths with
231 ## drive letters.
232 delete $ENV{OS};
234 elsif ($arg eq '-a') {
235 $append = 1;
237 elsif ($arg eq '-i') {
238 $needsrc = undef;
240 elsif ($arg eq '-n') {
241 $noinline = 1;
243 elsif ($arg eq '-h') {
244 $self->usageAndExit();
246 elsif ($arg eq '-t') {
247 ++$i;
248 $arg = $$args[$i];
249 if (defined $arg && defined $types{$arg}) {
250 $type = $arg;
252 else {
253 $self->usageAndExit('Invalid use of -t');
256 elsif ($arg =~ /^[\-+]/) {
257 ## We will ignore unknown options
258 ## Some options for aCC start with +
260 else {
261 push(@files, $arg);
265 if (!defined $files[0]) {
266 if ($needsrc) {
267 $self->usageAndExit('No files specified');
271 my $editor = new DependencyEditor();
272 return $editor->process($output, $type, $noinline, \%macros, \@ipaths,
273 \%replace, \%exclude, \@files, $append);