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