]>
Commit | Line | Data |
---|---|---|
259d87c3 MSO |
1 | #!/usr/bin/perl -w |
2 | ###################################################################### | |
3 | # Do not call this script directly! | |
4 | # | |
5 | # The generate script ensures that @INC is correct before the engine | |
6 | # is executed. | |
7 | # | |
8 | # Copyright (C) 2009 Marius Storm-Olsen <mstormo@gmail.com> | |
9 | ###################################################################### | |
10 | use strict; | |
11 | use File::Basename; | |
12 | use File::Spec; | |
13 | use Cwd; | |
14 | use Generators; | |
15 | ||
16 | my (%build_structure, %compile_options, @makedry); | |
17 | my $out_dir = getcwd(); | |
18 | my $git_dir = $out_dir; | |
19 | $git_dir =~ s=\\=/=g; | |
20 | $git_dir = dirname($git_dir) while (!-e "$git_dir/git.c" && "$git_dir" ne ""); | |
21 | die "Couldn't find Git repo" if ("$git_dir" eq ""); | |
22 | ||
23 | my @gens = Generators::available(); | |
24 | my $gen = "Vcproj"; | |
25 | ||
26 | sub showUsage | |
27 | { | |
28 | my $genlist = join(', ', @gens); | |
29 | print << "EOM"; | |
30 | generate usage: | |
31 | -g <GENERATOR> --gen <GENERATOR> Specify the buildsystem generator (default: $gen) | |
32 | Available: $genlist | |
33 | -o <PATH> --out <PATH> Specify output directory generation (default: .) | |
34 | -i <FILE> --in <FILE> Specify input file, instead of running GNU Make | |
35 | -h,-? --help This help | |
36 | EOM | |
37 | exit 0; | |
38 | } | |
39 | ||
40 | # Parse command-line options | |
41 | while (@ARGV) { | |
42 | my $arg = shift @ARGV; | |
43 | if ("$arg" eq "-h" || "$arg" eq "--help" || "$arg" eq "-?") { | |
44 | showUsage(); | |
45 | exit(0); | |
46 | } elsif("$arg" eq "--out" || "$arg" eq "-o") { | |
47 | $out_dir = shift @ARGV; | |
48 | } elsif("$arg" eq "--gen" || "$arg" eq "-g") { | |
49 | $gen = shift @ARGV; | |
50 | } elsif("$arg" eq "--in" || "$arg" eq "-i") { | |
51 | my $infile = shift @ARGV; | |
52 | open(F, "<$infile") || die "Couldn't open file $infile"; | |
53 | @makedry = <F>; | |
54 | close(F); | |
55 | } | |
56 | } | |
57 | ||
58 | # NOT using File::Spec->rel2abs($path, $base) here, as | |
59 | # it fails badly for me in the msysgit environment | |
60 | $git_dir = File::Spec->rel2abs($git_dir); | |
61 | $out_dir = File::Spec->rel2abs($out_dir); | |
62 | my $rel_dir = makeOutRel2Git($git_dir, $out_dir); | |
63 | ||
64 | # Print some information so the user feels informed | |
65 | print << "EOM"; | |
66 | ----- | |
67 | Generator: $gen | |
68 | Git dir: $git_dir | |
69 | Out dir: $out_dir | |
70 | ----- | |
71 | Running GNU Make to figure out build structure... | |
72 | EOM | |
73 | ||
74 | # Pipe a make --dry-run into a variable, if not already loaded from file | |
75 | @makedry = `cd $git_dir && make -n MSVC=1 V=1 2>/dev/null` if !@makedry; | |
76 | ||
77 | # Parse the make output into usable info | |
78 | parseMakeOutput(); | |
79 | ||
80 | # Finally, ask the generator to start generating.. | |
81 | Generators::generate($gen, $git_dir, $out_dir, $rel_dir, %build_structure); | |
82 | ||
83 | # main flow ends here | |
84 | # ------------------------------------------------------------------------------------------------- | |
85 | ||
86 | ||
87 | # 1) path: /foo/bar/baz 2) path: /foo/bar/baz 3) path: /foo/bar/baz | |
88 | # base: /foo/bar/baz/temp base: /foo/bar base: /tmp | |
89 | # rel: .. rel: baz rel: ../foo/bar/baz | |
90 | sub makeOutRel2Git | |
91 | { | |
92 | my ($path, $base) = @_; | |
93 | my $rel; | |
94 | if ("$path" eq "$base") { | |
95 | return "."; | |
96 | } elsif ($base =~ /^$path/) { | |
97 | # case 1 | |
98 | my $tmp = $base; | |
99 | $tmp =~ s/^$path//; | |
100 | foreach (split('/', $tmp)) { | |
101 | $rel .= "../" if ("$_" ne ""); | |
102 | } | |
103 | } elsif ($path =~ /^$base/) { | |
104 | # case 2 | |
105 | $rel = $path; | |
106 | $rel =~ s/^$base//; | |
107 | $rel = "./$rel"; | |
108 | } else { | |
109 | my $tmp = $base; | |
110 | foreach (split('/', $tmp)) { | |
111 | $rel .= "../" if ("$_" ne ""); | |
112 | } | |
113 | $rel .= $path; | |
114 | } | |
115 | $rel =~ s/\/\//\//g; # simplify | |
116 | $rel =~ s/\/$//; # don't end with / | |
117 | return $rel; | |
118 | } | |
119 | ||
120 | sub parseMakeOutput | |
121 | { | |
122 | print "Parsing GNU Make output to figure out build structure...\n"; | |
123 | my $line = 0; | |
124 | while (my $text = shift @makedry) { | |
125 | my $ate_next; | |
126 | do { | |
127 | $ate_next = 0; | |
128 | $line++; | |
129 | chomp $text; | |
130 | chop $text if ($text =~ /\r$/); | |
131 | if ($text =~ /\\$/) { | |
132 | $text =~ s/\\$//; | |
133 | $text .= shift @makedry; | |
134 | $ate_next = 1; | |
135 | } | |
136 | } while($ate_next); | |
137 | ||
74cf9bdd RJ |
138 | if ($text =~ /^test /) { |
139 | # options to test (eg -o) may be mistaken for linker options | |
140 | next; | |
141 | } | |
142 | ||
259d87c3 MSO |
143 | if($text =~ / -c /) { |
144 | # compilation | |
145 | handleCompileLine($text, $line); | |
146 | ||
147 | } elsif ($text =~ / -o /) { | |
148 | # linking executable | |
149 | handleLinkLine($text, $line); | |
150 | ||
151 | } elsif ($text =~ /\.o / && $text =~ /\.a /) { | |
152 | # libifying | |
153 | handleLibLine($text, $line); | |
154 | # | |
155 | # } elsif ($text =~ /^cp /) { | |
156 | # # copy file around | |
157 | # | |
158 | # } elsif ($text =~ /^rm -f /) { | |
159 | # # shell command | |
160 | # | |
161 | # } elsif ($text =~ /^make[ \[]/) { | |
162 | # # make output | |
163 | # | |
164 | # } elsif ($text =~ /^echo /) { | |
165 | # # echo to file | |
166 | # | |
167 | # } elsif ($text =~ /^if /) { | |
168 | # # shell conditional | |
169 | # | |
170 | # } elsif ($text =~ /^tclsh /) { | |
171 | # # translation stuff | |
172 | # | |
173 | # } elsif ($text =~ /^umask /) { | |
174 | # # handling boilerplates | |
175 | # | |
176 | # } elsif ($text =~ /\$\(\:\)/) { | |
177 | # # ignore | |
178 | # | |
179 | # } elsif ($text =~ /^FLAGS=/) { | |
180 | # # flags check for dependencies | |
181 | # | |
182 | # } elsif ($text =~ /^'\/usr\/bin\/perl' -MError -e/) { | |
183 | # # perl commands for copying files | |
184 | # | |
185 | # } elsif ($text =~ /generate-cmdlist\.sh/) { | |
186 | # # command for generating list of commands | |
187 | # | |
259d87c3 MSO |
188 | # } elsif ($text =~ /new locations or Tcl/) { |
189 | # # command for detecting Tcl/Tk changes | |
190 | # | |
191 | # } elsif ($text =~ /mkdir -p/) { | |
192 | # # command creating path | |
193 | # | |
194 | # } elsif ($text =~ /: no custom templates yet/) { | |
195 | # # whatever | |
196 | # | |
197 | # } else { | |
198 | # print "Unhandled (line: $line): $text\n"; | |
199 | } | |
200 | } | |
201 | ||
202 | # use Data::Dumper; | |
203 | # print "Parsed build structure:\n"; | |
204 | # print Dumper(%build_structure); | |
205 | } | |
206 | ||
207 | # variables for the compilation part of each step | |
208 | my (@defines, @incpaths, @cflags, @sources); | |
209 | ||
210 | sub clearCompileStep | |
211 | { | |
212 | @defines = (); | |
213 | @incpaths = (); | |
214 | @cflags = (); | |
215 | @sources = (); | |
216 | } | |
217 | ||
218 | sub removeDuplicates | |
219 | { | |
220 | my (%dupHash, $entry); | |
221 | %dupHash = map { $_, 1 } @defines; | |
222 | @defines = keys %dupHash; | |
223 | ||
224 | %dupHash = map { $_, 1 } @incpaths; | |
225 | @incpaths = keys %dupHash; | |
226 | ||
227 | %dupHash = map { $_, 1 } @cflags; | |
228 | @cflags = keys %dupHash; | |
229 | } | |
230 | ||
231 | sub handleCompileLine | |
232 | { | |
233 | my ($line, $lineno) = @_; | |
234 | my @parts = split(' ', $line); | |
235 | my $sourcefile; | |
236 | shift(@parts); # ignore cmd | |
237 | while (my $part = shift @parts) { | |
238 | if ("$part" eq "-o") { | |
239 | # ignore object file | |
240 | shift @parts; | |
241 | } elsif ("$part" eq "-c") { | |
242 | # ignore compile flag | |
243 | } elsif ("$part" eq "-c") { | |
244 | } elsif ($part =~ /^.?-I/) { | |
245 | push(@incpaths, $part); | |
246 | } elsif ($part =~ /^.?-D/) { | |
247 | push(@defines, $part); | |
248 | } elsif ($part =~ /^-/) { | |
249 | push(@cflags, $part); | |
250 | } elsif ($part =~ /\.(c|cc|cpp)$/) { | |
251 | $sourcefile = $part; | |
252 | } else { | |
253 | die "Unhandled compiler option @ line $lineno: $part"; | |
254 | } | |
255 | } | |
256 | @{$compile_options{"${sourcefile}_CFLAGS"}} = @cflags; | |
257 | @{$compile_options{"${sourcefile}_DEFINES"}} = @defines; | |
258 | @{$compile_options{"${sourcefile}_INCPATHS"}} = @incpaths; | |
259 | clearCompileStep(); | |
260 | } | |
261 | ||
262 | sub handleLibLine | |
263 | { | |
264 | my ($line, $lineno) = @_; | |
265 | my (@objfiles, @lflags, $libout, $part); | |
266 | # kill cmd and rm 'prefix' | |
267 | $line =~ s/^rm -f .* && .* rcs //; | |
268 | my @parts = split(' ', $line); | |
269 | while ($part = shift @parts) { | |
270 | if ($part =~ /^-/) { | |
271 | push(@lflags, $part); | |
272 | } elsif ($part =~ /\.(o|obj)$/) { | |
273 | push(@objfiles, $part); | |
274 | } elsif ($part =~ /\.(a|lib)$/) { | |
275 | $libout = $part; | |
276 | $libout =~ s/\.a$//; | |
277 | } else { | |
278 | die "Unhandled lib option @ line $lineno: $part"; | |
279 | } | |
280 | } | |
281 | # print "LibOut: '$libout'\nLFlags: @lflags\nOfiles: @objfiles\n"; | |
282 | # exit(1); | |
283 | foreach (@objfiles) { | |
284 | my $sourcefile = $_; | |
285 | $sourcefile =~ s/\.o/.c/; | |
286 | push(@sources, $sourcefile); | |
287 | push(@cflags, @{$compile_options{"${sourcefile}_CFLAGS"}}); | |
288 | push(@defines, @{$compile_options{"${sourcefile}_DEFINES"}}); | |
289 | push(@incpaths, @{$compile_options{"${sourcefile}_INCPATHS"}}); | |
290 | } | |
291 | removeDuplicates(); | |
292 | ||
293 | push(@{$build_structure{"LIBS"}}, $libout); | |
294 | @{$build_structure{"LIBS_${libout}"}} = ("_DEFINES", "_INCLUDES", "_CFLAGS", "_SOURCES", | |
295 | "_OBJECTS"); | |
296 | @{$build_structure{"LIBS_${libout}_DEFINES"}} = @defines; | |
297 | @{$build_structure{"LIBS_${libout}_INCLUDES"}} = @incpaths; | |
298 | @{$build_structure{"LIBS_${libout}_CFLAGS"}} = @cflags; | |
299 | @{$build_structure{"LIBS_${libout}_LFLAGS"}} = @lflags; | |
300 | @{$build_structure{"LIBS_${libout}_SOURCES"}} = @sources; | |
301 | @{$build_structure{"LIBS_${libout}_OBJECTS"}} = @objfiles; | |
302 | clearCompileStep(); | |
303 | } | |
304 | ||
305 | sub handleLinkLine | |
306 | { | |
307 | my ($line, $lineno) = @_; | |
308 | my (@objfiles, @lflags, @libs, $appout, $part); | |
309 | my @parts = split(' ', $line); | |
310 | shift(@parts); # ignore cmd | |
311 | while ($part = shift @parts) { | |
312 | if ($part =~ /^-IGNORE/) { | |
313 | push(@lflags, $part); | |
314 | } elsif ($part =~ /^-[GRIMDO]/) { | |
315 | # eat compiler flags | |
316 | } elsif ("$part" eq "-o") { | |
317 | $appout = shift @parts; | |
318 | } elsif ("$part" eq "-lz") { | |
319 | push(@libs, "zlib.lib"); | |
c36e1638 MSO |
320 | } elsif ("$part" eq "-lcrypto") { |
321 | push(@libs, "libeay32.lib"); | |
322 | push(@libs, "ssleay32.lib"); | |
259d87c3 MSO |
323 | } elsif ($part =~ /^-/) { |
324 | push(@lflags, $part); | |
325 | } elsif ($part =~ /\.(a|lib)$/) { | |
326 | $part =~ s/\.a$/.lib/; | |
327 | push(@libs, $part); | |
328 | } elsif ($part =~ /\.(o|obj)$/) { | |
329 | push(@objfiles, $part); | |
330 | } else { | |
331 | die "Unhandled lib option @ line $lineno: $part"; | |
332 | } | |
333 | } | |
334 | # print "AppOut: '$appout'\nLFlags: @lflags\nLibs : @libs\nOfiles: @objfiles\n"; | |
335 | # exit(1); | |
336 | foreach (@objfiles) { | |
337 | my $sourcefile = $_; | |
338 | $sourcefile =~ s/\.o/.c/; | |
339 | push(@sources, $sourcefile); | |
340 | push(@cflags, @{$compile_options{"${sourcefile}_CFLAGS"}}); | |
341 | push(@defines, @{$compile_options{"${sourcefile}_DEFINES"}}); | |
342 | push(@incpaths, @{$compile_options{"${sourcefile}_INCPATHS"}}); | |
343 | } | |
344 | removeDuplicates(); | |
345 | ||
346 | removeDuplicates(); | |
347 | push(@{$build_structure{"APPS"}}, $appout); | |
348 | @{$build_structure{"APPS_${appout}"}} = ("_DEFINES", "_INCLUDES", "_CFLAGS", "_LFLAGS", | |
349 | "_SOURCES", "_OBJECTS", "_LIBS"); | |
350 | @{$build_structure{"APPS_${appout}_DEFINES"}} = @defines; | |
351 | @{$build_structure{"APPS_${appout}_INCLUDES"}} = @incpaths; | |
352 | @{$build_structure{"APPS_${appout}_CFLAGS"}} = @cflags; | |
353 | @{$build_structure{"APPS_${appout}_LFLAGS"}} = @lflags; | |
354 | @{$build_structure{"APPS_${appout}_SOURCES"}} = @sources; | |
355 | @{$build_structure{"APPS_${appout}_OBJECTS"}} = @objfiles; | |
356 | @{$build_structure{"APPS_${appout}_LIBS"}} = @libs; | |
357 | clearCompileStep(); | |
358 | } |