line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package App::AutoBuild; |
2
|
1
|
|
|
1
|
|
27039
|
use strict; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
33
|
|
3
|
1
|
|
|
1
|
|
5
|
use warnings; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
91
|
|
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
=head1 NAME |
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
App::AutoBuild - A perl tool to make it quick and easy to compile a C/C++ project with automatic compilation of dependencies |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
=head1 VERSION |
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
Version 0.04 |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
=cut |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
our $VERSION = '0.04'; |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
=head1 SYNOPSIS |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
Example project layout: |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
build.pl |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
#!/usr/bin/perl |
24
|
|
|
|
|
|
|
use App::AutoBuild qw(build shell_config); |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
build({ |
27
|
|
|
|
|
|
|
'cflags'=>[qw(-O2 -Isrc/ -Wall -Wextra), shell_config('sdl-config', '--cflags')], |
28
|
|
|
|
|
|
|
'ldflags'=>[qw(-lSDL_image -lm), shell_config('sdl-config', '--libs')], |
29
|
|
|
|
|
|
|
'programs'=>{ |
30
|
|
|
|
|
|
|
# each output executable goes here. you can list several. |
31
|
|
|
|
|
|
|
'main'=>'src/main.c', |
32
|
|
|
|
|
|
|
}, |
33
|
|
|
|
|
|
|
}); |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
src/main.c |
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
#include "stuff.h" |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
int main(int argc, char** argv) |
40
|
|
|
|
|
|
|
{ |
41
|
|
|
|
|
|
|
stuff_function(); |
42
|
|
|
|
|
|
|
return 0; |
43
|
|
|
|
|
|
|
} |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
src/stuff.c |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
#include "stuff.h" |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
void stuff_function() |
50
|
|
|
|
|
|
|
{ |
51
|
|
|
|
|
|
|
// hai |
52
|
|
|
|
|
|
|
} |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
src/stuff.h |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
#pragma once |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
void stuff_function(); |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
Note you don't need to put stuff.c into your build.pl-- it Just Works(tm). |
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
An even shorter example-- instead of a build.pl: |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
build.sh |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
#!/bin/sh |
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
export CC="clang" |
69
|
|
|
|
|
|
|
export CFLAGS="-std=c99 -pedantic -Wall -Wextra -O3" |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
perl -MApp::AutoBuild -e 'build("main.c");' -- $@ |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
=head1 COMMAND LINE |
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
usage: ./build.pl [-h|--help] [-v] [clean] |
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
-h, --help: dump help |
78
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
-v: increase verbosity (-vv or more -v's) |
80
|
|
|
|
|
|
|
0 (default) only show compile/link actions, in shortened form |
81
|
|
|
|
|
|
|
1 show compile/link actions with full command lines, and at the end a time summary (also shows App::AutoBuild overhead) |
82
|
|
|
|
|
|
|
2 shows debugging for job numbers (not useful really yet) |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
-d: increase debugosity (-dd or more -d's) |
85
|
|
|
|
|
|
|
0 (default) nothing! |
86
|
|
|
|
|
|
|
1 show which dependencies caused a recompile |
87
|
|
|
|
|
|
|
2 show stat() calls |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
-q: be more quiet |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
--cc=(compiler path): pick a compiler other than gcc |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
--program=(program): don't compile all targets, just this one |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
clean: unlink output files/meta file (.autobuild_meta) |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
=head1 DESCRIPTION |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
After writing a makefile for my 30th C project, I decided this was dumb and it (the computer) should figure out which object files should be linked in or recompiled. The idea behind this module is you create a build.pl that uses App::AutoBuild and calls build() with cflags and ldflags, an output binary filename, and a C file to start with (usually the C file with main()). |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
App::AutoBuild will figure out all the object files your C file depends on. A list of included header files (.h) will be computed by GCC and remembered in a cache. At build time, stat() is called on each header file included by your .c file. If any have a different mtime, the .c file will be recompiled. If you include a .h file that has a corresponding .c file, this process repeats and the output object code will be linked into your final binary automatically. |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
This tool isn't supposed to be a make replacement-- there are plenty of those, and at least one great one already in Perl. The idea is that the build system should know enough about the source code to do what you want for you. This replaces all the functionality of a makefile for a standard C project with the added bonus of having it only link in the objects that are actually used in each output target. |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
=head1 CAVEATS |
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
For this to work properly, you must have a scheme and follow it. Every .c/.cpp file must have an .h/.hpp file that matches (with the exception of the .c/.cpp file with main()). For now, the .c and .h files must be in the same directory (but this may be fixed in the future). |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
If you have a .h file and an unrelated .c file with the same name (as in, headers.h and headers.c) in the same folder, the .c file will be compiled and linked in automatically. If this doesn't work well for you, put the .h files without .c files into a different folder (i.e. "include/") or something. |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
A .autobuild_meta file is created in the current directory so it can remember modification times and dependency lists of files. This will definitely be configurable in a future version! |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
=head1 SUBROUTINES/METHODS |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
These are exported by default. |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
=head2 build() |
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
Pass this function a hashref of parameters for how to build your project. Keys are as follows: |
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
=head3 cflags |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
An arrayref of cflags |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
=head3 ldflags |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
An arrayref of ldflags |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
=head3 programs |
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
A hashref with binaries as keys, and start-point C files as values. |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
=head3 rules |
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
An arrayref of rule hashrefs. See L. |
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
=head2 shell_config() |
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
This is a helper function that takes a shell command + args (as an array) to pass to system() and splits the STDOUT into an array by whitespace. |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
I do all this as arrays because the CFLAGS/LDFLAGS can be added or removed per-file with rules. |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
=head1 RULES |
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
Rules let you have custom build options per-file. For now it only supports adding/removing cflags for a given .c file, or adding/removing ldflags for a given output binary. |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
{'file'=>'contrib/GLee/GLee.c', 'del_cflags'=>['-pedantic']}, |
148
|
|
|
|
|
|
|
{'file'=>'configtest', 'add_ldflags'=>['-lyaml'], 'del_ldflags'=>['-lGL', '-lGLU', shell_config('sdl-config', '--libs')]}, |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
These definitely need some more work! |
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
=head1 AUTHOR |
153
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
Joel Jensen, C<< >> |
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
=head1 BUGS/TODO |
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
Please email me if it doesn't work! I've only tested with GCC and clang. |
159
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
Job paralellizing would be sweet. Patches welcome. |
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
=head1 LICENSE AND COPYRIGHT |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
Copyright 2010 Joel Jensen. |
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify it |
167
|
|
|
|
|
|
|
under the terms of either: the GNU General Public License as published |
168
|
|
|
|
|
|
|
by the Free Software Foundation; or the Artistic License. |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
See http://dev.perl.org/licenses/ for more information. |
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
=cut |
173
|
|
|
|
|
|
|
|
174
|
1
|
|
|
1
|
|
822
|
use Time::HiRes qw(time); |
|
1
|
|
|
|
|
1743
|
|
|
1
|
|
|
|
|
4
|
|
175
|
1
|
|
|
1
|
|
1249
|
use Storable qw(store retrieve); |
|
1
|
|
|
|
|
3486
|
|
|
1
|
|
|
|
|
102
|
|
176
|
1
|
|
|
1
|
|
10
|
use Digest::MD5(); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
21
|
|
177
|
1
|
|
|
1
|
|
1648
|
use autodie qw(system); |
|
1
|
|
|
|
|
20419
|
|
|
1
|
|
|
|
|
7
|
|
178
|
|
|
|
|
|
|
|
179
|
1
|
|
|
1
|
|
20380
|
use Exporter qw(import); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
4502
|
|
180
|
|
|
|
|
|
|
our @EXPORT = qw(build shell_config); |
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
my $meta_file = '.autobuild_meta'; |
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
my $next_jid = 0; |
185
|
|
|
|
|
|
|
my $system_runtime = 0; |
186
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
sub build |
188
|
|
|
|
|
|
|
{ |
189
|
0
|
|
|
0
|
1
|
|
my $opts = shift; |
190
|
|
|
|
|
|
|
|
191
|
0
|
0
|
|
|
|
|
if(ref($opts) eq '') |
192
|
|
|
|
|
|
|
{ |
193
|
0
|
|
|
|
|
|
my $bin = $opts; |
194
|
0
|
|
|
|
|
|
$bin =~ s/\.cp?p?$//; |
195
|
0
|
|
|
|
|
|
$opts = {'programs'=>{$bin=>$opts}}; |
196
|
|
|
|
|
|
|
} |
197
|
|
|
|
|
|
|
|
198
|
0
|
|
|
|
|
|
my $start = time; |
199
|
|
|
|
|
|
|
|
200
|
0
|
|
|
|
|
|
my $ab = App::AutoBuild->new(); |
201
|
0
|
|
|
|
|
|
$ab->args(\@ARGV); |
202
|
|
|
|
|
|
|
|
203
|
0
|
|
|
|
|
|
my @cflags; |
204
|
|
|
|
|
|
|
my @ldflags; |
205
|
|
|
|
|
|
|
|
206
|
0
|
0
|
|
|
|
|
push @cflags, split(/\s+/, $ENV{'CFLAGS'}) if($ENV{'CFLAGS'}); |
207
|
0
|
0
|
|
|
|
|
push @ldflags, split(/\s+/, $ENV{'LDFLAGS'}) if($ENV{'LDFLAGS'}); |
208
|
|
|
|
|
|
|
|
209
|
0
|
0
|
|
|
|
|
push @cflags, @{$opts->{'cflags'}} if($opts->{'cflags'}); |
|
0
|
|
|
|
|
|
|
210
|
0
|
0
|
|
|
|
|
push @ldflags, @{$opts->{'ldflags'}} if($opts->{'ldflags'}); |
|
0
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
|
212
|
0
|
|
|
|
|
|
$ab->cflags(\@cflags); |
213
|
0
|
|
|
|
|
|
$ab->ldflags(\@ldflags); |
214
|
|
|
|
|
|
|
|
215
|
0
|
0
|
|
|
|
|
if($ENV{'CC'}) |
216
|
|
|
|
|
|
|
{ |
217
|
0
|
|
|
|
|
|
$ab->{'cc'} = $ENV{'CC'}; |
218
|
|
|
|
|
|
|
} |
219
|
|
|
|
|
|
|
|
220
|
0
|
|
|
|
|
|
for(qw(cc osuffix)) |
221
|
|
|
|
|
|
|
{ |
222
|
0
|
0
|
|
|
|
|
$ab->{$_} = $opts->{$_} if($opts->{$_}); |
223
|
|
|
|
|
|
|
} |
224
|
|
|
|
|
|
|
|
225
|
0
|
|
0
|
|
|
|
$ab->{'rules'} = $opts->{'rules'} || []; # HACK for now until I decide the right way to do this |
226
|
|
|
|
|
|
|
|
227
|
0
|
|
|
|
|
|
for my $bin (keys %{ $opts->{'programs'} }) |
|
0
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
{ |
229
|
0
|
0
|
0
|
|
|
|
if($ab->{'clean'} || !$ab->{'default'} || $ab->{'default'}{$bin}) |
|
|
|
0
|
|
|
|
|
230
|
|
|
|
|
|
|
{ |
231
|
0
|
|
|
|
|
|
$ab->program($opts->{'programs'}{$bin}, $bin); |
232
|
|
|
|
|
|
|
} |
233
|
|
|
|
|
|
|
} |
234
|
|
|
|
|
|
|
|
235
|
0
|
|
|
|
|
|
my $moar = 1; |
236
|
|
|
|
|
|
|
|
237
|
0
|
|
|
|
|
|
while($moar) |
238
|
|
|
|
|
|
|
{ |
239
|
|
|
|
|
|
|
#$ab->debug_jobs(); |
240
|
|
|
|
|
|
|
#; |
241
|
0
|
|
|
|
|
|
$moar = $ab->run(); |
242
|
|
|
|
|
|
|
}; |
243
|
|
|
|
|
|
|
|
244
|
0
|
|
|
|
|
|
my $end = time; |
245
|
|
|
|
|
|
|
|
246
|
0
|
0
|
|
|
|
|
if($ab->{'verbose'} > 0) |
247
|
|
|
|
|
|
|
{ |
248
|
0
|
|
|
|
|
|
printf( |
249
|
|
|
|
|
|
|
"AutoBuild.pm runtime: %.3fs\n". |
250
|
|
|
|
|
|
|
" system() runtime: %.3fs\n". |
251
|
|
|
|
|
|
|
" overhead: %.3fs\n", |
252
|
|
|
|
|
|
|
$end - $start, |
253
|
|
|
|
|
|
|
$system_runtime, |
254
|
|
|
|
|
|
|
($end - $start) - $system_runtime); |
255
|
|
|
|
|
|
|
} |
256
|
|
|
|
|
|
|
|
257
|
0
|
|
|
|
|
|
return; |
258
|
|
|
|
|
|
|
} |
259
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
sub shell_config |
261
|
|
|
|
|
|
|
{ |
262
|
0
|
|
|
0
|
1
|
|
my @cmdline = @_; |
263
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
# TODO use system() for this |
265
|
|
|
|
|
|
|
|
266
|
0
|
|
|
|
|
|
my $run = join(' ', @cmdline); |
267
|
0
|
|
|
|
|
|
my $txt = `$run`; |
268
|
0
|
|
|
|
|
|
chomp($txt); |
269
|
|
|
|
|
|
|
|
270
|
0
|
|
|
|
|
|
return split(/\s+/, $txt); |
271
|
|
|
|
|
|
|
} |
272
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
sub new |
274
|
|
|
|
|
|
|
{ |
275
|
0
|
|
|
0
|
0
|
|
my($class) = @_; |
276
|
0
|
|
0
|
|
|
|
$class = ref($class) || $class; |
277
|
0
|
|
|
|
|
|
my $self = bless({}, $class); |
278
|
|
|
|
|
|
|
|
279
|
0
|
0
|
|
|
|
|
if(-e $meta_file) |
280
|
|
|
|
|
|
|
{ |
281
|
0
|
|
|
|
|
|
$self->{'meta'} = retrieve($meta_file); |
282
|
|
|
|
|
|
|
}else |
283
|
|
|
|
|
|
|
{ |
284
|
0
|
|
|
|
|
|
$self->{'meta'} = {}; |
285
|
|
|
|
|
|
|
} |
286
|
|
|
|
|
|
|
|
287
|
|
|
|
|
|
|
# some defaults |
288
|
0
|
|
|
|
|
|
$self->{'verbose'} = 0; |
289
|
0
|
|
|
|
|
|
$self->{'debug'} = 0; |
290
|
0
|
|
|
|
|
|
$self->{'cc'} = 'gcc'; |
291
|
0
|
|
|
|
|
|
$self->{'cpp'} = 'g++'; |
292
|
0
|
|
|
|
|
|
$self->{'osuffix'} = 'o'; |
293
|
|
|
|
|
|
|
|
294
|
0
|
|
|
|
|
|
$self->{'jobs'} = []; |
295
|
0
|
|
|
|
|
|
$self->{'job_index'} = {}; |
296
|
|
|
|
|
|
|
|
297
|
0
|
|
|
|
|
|
return($self); |
298
|
|
|
|
|
|
|
} |
299
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
sub DESTROY |
301
|
|
|
|
|
|
|
{ |
302
|
0
|
|
|
0
|
|
|
my($self) = @_; |
303
|
0
|
0
|
|
|
|
|
if($self->{'clean'}) |
304
|
|
|
|
|
|
|
{ |
305
|
0
|
|
|
|
|
|
$self->unlink_file($meta_file); |
306
|
|
|
|
|
|
|
}else |
307
|
|
|
|
|
|
|
{ |
308
|
0
|
|
|
|
|
|
store($self->{'meta'}, $meta_file); |
309
|
|
|
|
|
|
|
} |
310
|
0
|
|
|
|
|
|
return; |
311
|
|
|
|
|
|
|
} |
312
|
|
|
|
|
|
|
|
313
|
|
|
|
|
|
|
sub args |
314
|
|
|
|
|
|
|
{ |
315
|
0
|
|
|
0
|
0
|
|
my($self, $argv) = @_; |
316
|
|
|
|
|
|
|
|
317
|
0
|
|
|
|
|
|
for(@$argv) |
318
|
|
|
|
|
|
|
{ |
319
|
0
|
0
|
0
|
|
|
|
if($_ =~ m/^-(v+)$/) |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
320
|
|
|
|
|
|
|
{ |
321
|
0
|
|
|
|
|
|
$self->{'verbose'} += length($1); |
322
|
|
|
|
|
|
|
} |
323
|
|
|
|
|
|
|
elsif($_ =~ m/^-(d+)$/) |
324
|
|
|
|
|
|
|
{ |
325
|
0
|
|
|
|
|
|
$self->{'debug'} += length($1); |
326
|
|
|
|
|
|
|
} |
327
|
|
|
|
|
|
|
elsif($_ eq '-q') |
328
|
|
|
|
|
|
|
{ |
329
|
0
|
|
|
|
|
|
$self->{'quiet'} = 1; |
330
|
|
|
|
|
|
|
} |
331
|
|
|
|
|
|
|
elsif($_ eq 'clean') |
332
|
|
|
|
|
|
|
{ |
333
|
0
|
|
|
|
|
|
$self->{'clean'} = 1; |
334
|
|
|
|
|
|
|
} |
335
|
|
|
|
|
|
|
elsif($_ =~ m/^--cc=(.+)$/) |
336
|
|
|
|
|
|
|
{ |
337
|
0
|
|
|
|
|
|
$self->{'cc'} = $1; |
338
|
|
|
|
|
|
|
} |
339
|
|
|
|
|
|
|
elsif($_ =~ m/^--program=(.+)$/) |
340
|
|
|
|
|
|
|
{ |
341
|
0
|
|
|
|
|
|
$self->{'default'}{$1} = 1; |
342
|
|
|
|
|
|
|
} |
343
|
|
|
|
|
|
|
elsif($_ eq '-h' || $_ eq '--help') |
344
|
|
|
|
|
|
|
{ |
345
|
0
|
|
|
|
|
|
print <<"zap"; |
346
|
|
|
|
|
|
|
usage: $0 [-h|--help] [-v] [clean] |
347
|
|
|
|
|
|
|
|
348
|
|
|
|
|
|
|
-h, --help: dump help |
349
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
-v: increase verbosity (-vv or more -v's) |
351
|
|
|
|
|
|
|
0 (default) only show compile/link actions, in shortened form |
352
|
|
|
|
|
|
|
1 show compile/link actions with full command lines, and at the end a time summary (also shows App::AutoBuild overhead) |
353
|
|
|
|
|
|
|
2 shows debugging for job numbers (not useful really yet) |
354
|
|
|
|
|
|
|
|
355
|
|
|
|
|
|
|
-d: increase debugosity (-dd or more -d's) |
356
|
|
|
|
|
|
|
0 (default) nothing! |
357
|
|
|
|
|
|
|
1 show which dependencies caused a recompile |
358
|
|
|
|
|
|
|
2 show stat() calls |
359
|
|
|
|
|
|
|
|
360
|
|
|
|
|
|
|
clean: unlink output files/meta file ($meta_file) |
361
|
|
|
|
|
|
|
zap |
362
|
0
|
|
|
|
|
|
exit(1); |
363
|
|
|
|
|
|
|
} |
364
|
|
|
|
|
|
|
else |
365
|
|
|
|
|
|
|
{ |
366
|
0
|
|
|
|
|
|
warn "ignoring unknown commandline option $_"; |
367
|
|
|
|
|
|
|
} |
368
|
|
|
|
|
|
|
} |
369
|
|
|
|
|
|
|
} |
370
|
|
|
|
|
|
|
|
371
|
|
|
|
|
|
|
sub cflags |
372
|
|
|
|
|
|
|
{ |
373
|
0
|
|
|
0
|
1
|
|
my($self, $v) = @_; |
374
|
0
|
0
|
|
|
|
|
if($v) |
375
|
|
|
|
|
|
|
{ |
376
|
0
|
|
|
|
|
|
$self->{'cflags'} = $v; |
377
|
|
|
|
|
|
|
} |
378
|
0
|
|
|
|
|
|
return $self->{'cflags'}; |
379
|
|
|
|
|
|
|
} |
380
|
|
|
|
|
|
|
sub ldflags |
381
|
|
|
|
|
|
|
{ |
382
|
0
|
|
|
0
|
1
|
|
my($self, $v) = @_; |
383
|
0
|
0
|
|
|
|
|
if($v) |
384
|
|
|
|
|
|
|
{ |
385
|
0
|
|
|
|
|
|
$self->{'ldflags'} = $v; |
386
|
|
|
|
|
|
|
} |
387
|
0
|
|
|
|
|
|
return $self->{'ldflags'}; |
388
|
|
|
|
|
|
|
} |
389
|
|
|
|
|
|
|
|
390
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
sub program |
392
|
|
|
|
|
|
|
{ |
393
|
0
|
|
|
0
|
0
|
|
my($self, $cfile, $out) = @_; |
394
|
|
|
|
|
|
|
|
395
|
0
|
|
|
|
|
|
my %job = ( |
396
|
|
|
|
|
|
|
'out'=>$out, |
397
|
|
|
|
|
|
|
'task'=>'ld', |
398
|
|
|
|
|
|
|
); |
399
|
|
|
|
|
|
|
|
400
|
0
|
|
|
|
|
|
my $jid = $self->add_job(\%job); |
401
|
|
|
|
|
|
|
|
402
|
0
|
|
|
|
|
|
$job{'needs'} = [$self->add_build_job($cfile, $jid)]; |
403
|
|
|
|
|
|
|
} |
404
|
|
|
|
|
|
|
|
405
|
|
|
|
|
|
|
sub add_build_job |
406
|
|
|
|
|
|
|
{ |
407
|
0
|
|
|
0
|
0
|
|
my($self, $cfile) = @_; |
408
|
|
|
|
|
|
|
|
409
|
0
|
|
|
|
|
|
my $cpp = 0; |
410
|
0
|
0
|
|
|
|
|
if(substr($cfile, -4, 4) eq '.cpp') |
411
|
|
|
|
|
|
|
{ |
412
|
0
|
|
|
|
|
|
$self->{'cpp_ld'} = 1; |
413
|
0
|
|
|
|
|
|
$cpp = 1; |
414
|
|
|
|
|
|
|
} |
415
|
|
|
|
|
|
|
# otherwise assume C instead of C++ |
416
|
|
|
|
|
|
|
|
417
|
0
|
|
|
|
|
|
my $ofile = replace_ext($cfile, $self->{'osuffix'}); |
418
|
0
|
|
|
|
|
|
$ofile =~ s/([^\/]+)$/\.$1/; |
419
|
|
|
|
|
|
|
|
420
|
0
|
|
|
|
|
|
my $job_key = $ofile; # add CFLAGS to this when that's customizable per binary |
421
|
0
|
0
|
|
|
|
|
if(my $existing_jid = $self->{'job_index'}{$job_key}) |
422
|
|
|
|
|
|
|
{ |
423
|
0
|
|
|
|
|
|
return $existing_jid; # dont add a job |
424
|
|
|
|
|
|
|
} |
425
|
|
|
|
|
|
|
|
426
|
0
|
|
|
|
|
|
my %job = ( |
427
|
|
|
|
|
|
|
'cfile'=>$cfile, |
428
|
|
|
|
|
|
|
'out'=>$ofile, |
429
|
|
|
|
|
|
|
'task'=>'cc', |
430
|
|
|
|
|
|
|
'cpp'=>$cpp, |
431
|
|
|
|
|
|
|
); |
432
|
|
|
|
|
|
|
|
433
|
0
|
|
|
|
|
|
my $jid = $self->add_job(\%job); |
434
|
0
|
|
|
|
|
|
$self->{'job_index'}{$job_key} = $jid; |
435
|
0
|
|
|
|
|
|
return $jid; |
436
|
|
|
|
|
|
|
} |
437
|
|
|
|
|
|
|
|
438
|
|
|
|
|
|
|
sub add_job |
439
|
|
|
|
|
|
|
{ |
440
|
0
|
|
|
0
|
0
|
|
my($self, $job) = @_; |
441
|
0
|
|
|
|
|
|
$self->{'jobs'}[$next_jid] = $job; |
442
|
0
|
|
|
|
|
|
return $next_jid++; |
443
|
|
|
|
|
|
|
} |
444
|
|
|
|
|
|
|
|
445
|
|
|
|
|
|
|
sub needs_recurse |
446
|
|
|
|
|
|
|
{ |
447
|
0
|
|
|
0
|
0
|
|
my($self, $jid) = @_; |
448
|
|
|
|
|
|
|
|
449
|
0
|
|
|
|
|
|
my @r = ($jid); |
450
|
0
|
|
|
|
|
|
my %dups = ($jid=>1); |
451
|
0
|
|
|
|
|
|
my %recursed; |
452
|
|
|
|
|
|
|
|
453
|
0
|
|
|
|
|
|
my $more = 1; |
454
|
|
|
|
|
|
|
|
455
|
0
|
|
|
|
|
|
while($more) |
456
|
|
|
|
|
|
|
{ |
457
|
0
|
|
|
|
|
|
$more = 0; |
458
|
0
|
|
|
|
|
|
for my $i (@r) |
459
|
|
|
|
|
|
|
{ |
460
|
0
|
0
|
|
|
|
|
next if($recursed{$i}); |
461
|
0
|
|
|
|
|
|
$recursed{$i} = 1; |
462
|
0
|
|
|
|
|
|
my $n = $self->{'jobs'}[$i]{'needs'}; |
463
|
0
|
0
|
|
|
|
|
next unless($n); |
464
|
0
|
|
|
|
|
|
for my $id (@$n) |
465
|
|
|
|
|
|
|
{ |
466
|
0
|
0
|
|
|
|
|
if(!$dups{$id}) |
467
|
|
|
|
|
|
|
{ |
468
|
0
|
|
|
|
|
|
push @r, $id; |
469
|
0
|
|
|
|
|
|
$dups{$id} = 1; |
470
|
0
|
|
|
|
|
|
$more = 1; |
471
|
|
|
|
|
|
|
} |
472
|
|
|
|
|
|
|
} |
473
|
|
|
|
|
|
|
} |
474
|
|
|
|
|
|
|
} |
475
|
|
|
|
|
|
|
|
476
|
0
|
|
|
|
|
|
shift @r; # take off our initial job id |
477
|
|
|
|
|
|
|
|
478
|
0
|
|
|
|
|
|
return \@r; |
479
|
|
|
|
|
|
|
} |
480
|
|
|
|
|
|
|
|
481
|
|
|
|
|
|
|
sub debug_jobs |
482
|
|
|
|
|
|
|
{ |
483
|
0
|
|
|
0
|
0
|
|
my($self) = @_; |
484
|
|
|
|
|
|
|
|
485
|
0
|
|
|
|
|
|
print "\n"; |
486
|
0
|
|
|
|
|
|
for(my $i = 0; $i < $next_jid; $i++) |
487
|
|
|
|
|
|
|
{ |
488
|
0
|
|
|
|
|
|
my $job = $self->{'jobs'}[$i]; |
489
|
0
|
|
|
|
|
|
print " job $i: ".$job->{'task'}.' '.$job->{'out'}; |
490
|
|
|
|
|
|
|
|
491
|
0
|
0
|
0
|
|
|
|
if($job->{'needs'} && scalar @{ $job->{'needs'} }) |
|
0
|
|
|
|
|
|
|
492
|
|
|
|
|
|
|
{ |
493
|
0
|
|
|
|
|
|
print " (needs ".join(', ', @{ $job->{'needs'} }).")"; |
|
0
|
|
|
|
|
|
|
494
|
|
|
|
|
|
|
} |
495
|
|
|
|
|
|
|
|
496
|
0
|
0
|
|
|
|
|
if($job->{'done'}) |
497
|
|
|
|
|
|
|
{ |
498
|
0
|
|
|
|
|
|
print " DONE"; |
499
|
|
|
|
|
|
|
} |
500
|
|
|
|
|
|
|
|
501
|
0
|
|
|
|
|
|
print "\n"; |
502
|
|
|
|
|
|
|
} |
503
|
|
|
|
|
|
|
} |
504
|
|
|
|
|
|
|
|
505
|
|
|
|
|
|
|
sub run |
506
|
|
|
|
|
|
|
{ |
507
|
0
|
|
|
0
|
0
|
|
my($self) = @_; |
508
|
|
|
|
|
|
|
|
509
|
0
|
|
|
|
|
|
my @can; |
510
|
|
|
|
|
|
|
|
511
|
0
|
|
|
|
|
|
for(my $i = 0; $i < $next_jid; $i++) |
512
|
|
|
|
|
|
|
{ |
513
|
0
|
|
|
|
|
|
my $job = $self->{'jobs'}[$i]; |
514
|
0
|
0
|
|
|
|
|
if($job->{'done'}) |
515
|
|
|
|
|
|
|
{ |
516
|
0
|
|
|
|
|
|
next; |
517
|
|
|
|
|
|
|
} |
518
|
|
|
|
|
|
|
|
519
|
0
|
|
|
|
|
|
my $met = 1; |
520
|
|
|
|
|
|
|
|
521
|
0
|
|
|
|
|
|
for my $ni (@{ $self->needs_recurse($i) }) |
|
0
|
|
|
|
|
|
|
522
|
|
|
|
|
|
|
{ |
523
|
0
|
0
|
|
|
|
|
if(!$self->{'jobs'}[$ni]{'done'}) |
524
|
|
|
|
|
|
|
{ |
525
|
0
|
|
|
|
|
|
$met = 0; |
526
|
|
|
|
|
|
|
} |
527
|
|
|
|
|
|
|
} |
528
|
|
|
|
|
|
|
|
529
|
0
|
0
|
|
|
|
|
if($met) |
530
|
|
|
|
|
|
|
{ |
531
|
0
|
|
|
|
|
|
push @can, $i; |
532
|
|
|
|
|
|
|
} |
533
|
|
|
|
|
|
|
} |
534
|
|
|
|
|
|
|
|
535
|
0
|
|
|
|
|
|
my $r = 0; |
536
|
|
|
|
|
|
|
|
537
|
0
|
|
|
|
|
|
for my $i (@can) |
538
|
|
|
|
|
|
|
{ |
539
|
0
|
0
|
|
|
|
|
if($self->{'verbose'} > 1) |
540
|
|
|
|
|
|
|
{ |
541
|
0
|
|
|
|
|
|
print "executing job $i\n"; |
542
|
|
|
|
|
|
|
} |
543
|
|
|
|
|
|
|
|
544
|
0
|
0
|
|
|
|
|
if($self->exec_job($i)) |
545
|
|
|
|
|
|
|
{ |
546
|
0
|
|
|
|
|
|
$r = 1; |
547
|
|
|
|
|
|
|
} |
548
|
|
|
|
|
|
|
} |
549
|
|
|
|
|
|
|
|
550
|
0
|
|
|
|
|
|
return $r; |
551
|
|
|
|
|
|
|
} |
552
|
|
|
|
|
|
|
|
553
|
|
|
|
|
|
|
sub exec_job |
554
|
|
|
|
|
|
|
{ |
555
|
0
|
|
|
0
|
0
|
|
my($self, $jid) = @_; |
556
|
0
|
|
|
|
|
|
my $job = $self->{'jobs'}[$jid]; |
557
|
|
|
|
|
|
|
|
558
|
0
|
0
|
|
|
|
|
if($job->{'task'} eq 'cc') |
559
|
|
|
|
|
|
|
{ |
560
|
0
|
|
|
|
|
|
my $ofile = $job->{'out'}; |
561
|
0
|
|
|
|
|
|
my $cfile = $job->{'cfile'}; |
562
|
0
|
|
|
|
|
|
my $depfile = $cfile.'.deps'; |
563
|
|
|
|
|
|
|
|
564
|
0
|
|
|
|
|
|
my $headers = $self->{'meta'}{$cfile}{'headers'}; |
565
|
|
|
|
|
|
|
|
566
|
0
|
|
|
|
|
|
my @cflags = @{ $self->{'cflags'} }; |
|
0
|
|
|
|
|
|
|
567
|
0
|
|
|
|
|
|
for my $rule (@{ $self->{'rules'} }) |
|
0
|
|
|
|
|
|
|
568
|
|
|
|
|
|
|
{ |
569
|
0
|
|
|
|
|
|
my $fm = $rule->{'filematch'}; |
570
|
0
|
0
|
0
|
|
|
|
if(($rule->{'file'} && ($rule->{'file'} eq $cfile || $rule->{'file'} eq $ofile)) || |
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
571
|
|
|
|
|
|
|
($fm && ($cfile =~ m/$fm/ || $ofile =~ m/$fm/))) |
572
|
|
|
|
|
|
|
{ |
573
|
0
|
|
|
|
|
|
my $add = $rule->{'add_cflags'}; |
574
|
0
|
|
|
|
|
|
my $del = $rule->{'del_cflags'}; |
575
|
0
|
0
|
|
|
|
|
if($add) |
576
|
|
|
|
|
|
|
{ |
577
|
0
|
|
|
|
|
|
for my $f (@$add) |
578
|
|
|
|
|
|
|
{ |
579
|
0
|
0
|
|
|
|
|
if(!grep { $_ eq $f } @cflags) |
|
0
|
|
|
|
|
|
|
580
|
|
|
|
|
|
|
{ |
581
|
0
|
|
|
|
|
|
push @cflags, $f; |
582
|
|
|
|
|
|
|
} |
583
|
|
|
|
|
|
|
} |
584
|
|
|
|
|
|
|
} |
585
|
0
|
0
|
|
|
|
|
if($del) |
586
|
|
|
|
|
|
|
{ |
587
|
0
|
|
|
|
|
|
@cflags = grep { my $f = $_; ! grep { $f eq $_ } @$del } @cflags; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
588
|
|
|
|
|
|
|
} |
589
|
|
|
|
|
|
|
} |
590
|
|
|
|
|
|
|
} |
591
|
|
|
|
|
|
|
|
592
|
0
|
0
|
|
|
|
|
my $exec = $job->{'cpp'} ? $self->{'cpp'} : $self->{'cc'}; |
593
|
|
|
|
|
|
|
|
594
|
0
|
|
|
|
|
|
my @gcc = grep { $_ } ( |
|
0
|
|
|
|
|
|
|
595
|
|
|
|
|
|
|
$exec, |
596
|
|
|
|
|
|
|
@cflags, |
597
|
|
|
|
|
|
|
'-MF', $depfile, '-MMD', |
598
|
|
|
|
|
|
|
'-c', $cfile, |
599
|
|
|
|
|
|
|
'-o', $ofile, |
600
|
|
|
|
|
|
|
); |
601
|
0
|
|
|
|
|
|
my $exec_str = join(' ', @gcc); |
602
|
|
|
|
|
|
|
|
603
|
0
|
|
|
|
|
|
my @check = ($ofile); |
604
|
0
|
|
|
|
|
|
for(@$headers) |
605
|
|
|
|
|
|
|
{ |
606
|
0
|
0
|
|
|
|
|
next if(substr($_, 0, 1) eq '/'); |
607
|
0
|
|
|
|
|
|
push @check, $_; |
608
|
|
|
|
|
|
|
} |
609
|
|
|
|
|
|
|
|
610
|
0
|
|
|
|
|
|
my $changed = 1; |
611
|
|
|
|
|
|
|
|
612
|
0
|
0
|
|
|
|
|
if($self->{'meta'}{$ofile}) |
613
|
|
|
|
|
|
|
{ |
614
|
0
|
0
|
0
|
|
|
|
if($self->{'meta'}{$ofile}{'exec'} && $self->{'meta'}{$ofile}{'exec'} eq $exec_str) |
|
|
0
|
|
|
|
|
|
615
|
|
|
|
|
|
|
{ |
616
|
0
|
|
|
|
|
|
$changed = 0; |
617
|
0
|
0
|
|
|
|
|
if($self->{'debug'} > 2) |
618
|
|
|
|
|
|
|
{ |
619
|
0
|
|
|
|
|
|
print "cc $ofile has the same GCC options\n"; |
620
|
|
|
|
|
|
|
} |
621
|
|
|
|
|
|
|
}elsif($self->{'debug'}) |
622
|
|
|
|
|
|
|
{ |
623
|
0
|
|
|
|
|
|
print "cc $ofile has changed GCC options\n"; |
624
|
|
|
|
|
|
|
} |
625
|
|
|
|
|
|
|
} |
626
|
|
|
|
|
|
|
|
627
|
0
|
|
|
|
|
|
for my $f (@check) |
628
|
|
|
|
|
|
|
{ |
629
|
0
|
0
|
|
|
|
|
if($self->file_changed($f)) |
630
|
|
|
|
|
|
|
{ |
631
|
0
|
|
|
|
|
|
$changed = 1; |
632
|
0
|
0
|
|
|
|
|
if($self->{'debug'}) |
633
|
|
|
|
|
|
|
{ |
634
|
0
|
|
|
|
|
|
print "cc $cfile has changed dep $f\n"; |
635
|
|
|
|
|
|
|
} |
636
|
|
|
|
|
|
|
}else |
637
|
|
|
|
|
|
|
{ |
638
|
0
|
0
|
|
|
|
|
if($self->{'debug'} > 2) |
639
|
|
|
|
|
|
|
{ |
640
|
0
|
|
|
|
|
|
print "cc $cfile no changed dep $f\n"; |
641
|
|
|
|
|
|
|
} |
642
|
|
|
|
|
|
|
} |
643
|
|
|
|
|
|
|
} |
644
|
|
|
|
|
|
|
|
645
|
0
|
0
|
|
|
|
|
if($self->{'clean'}) |
|
|
0
|
|
|
|
|
|
646
|
|
|
|
|
|
|
{ |
647
|
0
|
|
|
|
|
|
$self->unlink_file($ofile); |
648
|
|
|
|
|
|
|
} |
649
|
|
|
|
|
|
|
elsif($changed) |
650
|
|
|
|
|
|
|
{ |
651
|
|
|
|
|
|
|
|
652
|
0
|
0
|
|
|
|
|
if($self->{'verbose'}) |
|
|
0
|
|
|
|
|
|
653
|
|
|
|
|
|
|
{ |
654
|
0
|
|
|
|
|
|
print $exec_str."\n"; |
655
|
|
|
|
|
|
|
}elsif(!$self->{'quiet'}) |
656
|
|
|
|
|
|
|
{ |
657
|
0
|
0
|
|
|
|
|
print $job->{'cpp'} ? 'cc++ ' : 'cc '; |
658
|
0
|
|
|
|
|
|
print "$cfile..\n"; |
659
|
|
|
|
|
|
|
} |
660
|
|
|
|
|
|
|
|
661
|
0
|
|
|
|
|
|
my $start = time; |
662
|
0
|
|
|
|
|
|
system(@gcc); |
663
|
0
|
|
|
|
|
|
$system_runtime += (time - $start); |
664
|
|
|
|
|
|
|
|
665
|
0
|
|
|
|
|
|
$headers = slurp_depfile($depfile); |
666
|
0
|
|
|
|
|
|
$self->{'meta'}{$cfile}{'headers'} = $headers; |
667
|
|
|
|
|
|
|
|
668
|
|
|
|
|
|
|
# remember the new md5sum/mtime |
669
|
0
|
0
|
|
|
|
|
if($self->file_update($ofile)) |
670
|
|
|
|
|
|
|
{ |
671
|
0
|
|
|
|
|
|
$job->{'updated'} = 1; |
672
|
|
|
|
|
|
|
} |
673
|
0
|
|
|
|
|
|
$self->{'meta'}{$ofile}{'exec'} = $exec_str; |
674
|
|
|
|
|
|
|
|
675
|
0
|
|
|
|
|
|
for(@$headers) |
676
|
|
|
|
|
|
|
{ |
677
|
0
|
0
|
|
|
|
|
next if(substr($_, 0, 1) eq '/'); |
678
|
0
|
|
|
|
|
|
$self->file_changed($_); |
679
|
|
|
|
|
|
|
} |
680
|
|
|
|
|
|
|
|
681
|
|
|
|
|
|
|
} |
682
|
|
|
|
|
|
|
|
683
|
0
|
|
|
|
|
|
my @needs; |
684
|
|
|
|
|
|
|
|
685
|
0
|
|
|
|
|
|
for my $hfile (@$headers) |
686
|
|
|
|
|
|
|
{ |
687
|
0
|
0
|
|
|
|
|
next if(substr($hfile, 0, 1) eq '/'); |
688
|
|
|
|
|
|
|
# look for a matching c file |
689
|
0
|
|
|
|
|
|
my $c = replace_ext($hfile, 'c'); |
690
|
|
|
|
|
|
|
# look for a matching cpp file |
691
|
0
|
0
|
|
|
|
|
$c = replace_ext($hfile, 'cpp') if(!-e $c); |
692
|
0
|
0
|
|
|
|
|
next unless(-e $c); |
693
|
|
|
|
|
|
|
|
694
|
0
|
|
|
|
|
|
push @needs, $self->add_build_job($c); |
695
|
|
|
|
|
|
|
} |
696
|
|
|
|
|
|
|
|
697
|
0
|
|
|
|
|
|
$job->{'needs'} = \@needs; |
698
|
0
|
|
|
|
|
|
$job->{'done'} = 1; |
699
|
|
|
|
|
|
|
|
700
|
0
|
|
|
|
|
|
return 1; |
701
|
|
|
|
|
|
|
} |
702
|
|
|
|
|
|
|
|
703
|
0
|
0
|
|
|
|
|
if($job->{'task'} eq 'ld') |
704
|
|
|
|
|
|
|
{ |
705
|
0
|
|
|
|
|
|
my $out = $job->{'out'}; |
706
|
|
|
|
|
|
|
|
707
|
0
|
|
|
|
|
|
my $any_changed = $self->file_changed($out); |
708
|
|
|
|
|
|
|
|
709
|
0
|
|
|
|
|
|
my $needs = $self->needs_recurse($jid); |
710
|
0
|
|
|
|
|
|
my @ofiles; |
711
|
0
|
|
|
|
|
|
for my $n (@{ $self->needs_recurse($jid) }) |
|
0
|
|
|
|
|
|
|
712
|
|
|
|
|
|
|
{ |
713
|
0
|
|
|
|
|
|
my $oj = $self->{'jobs'}[$n]; |
714
|
0
|
|
|
|
|
|
push @ofiles, $oj->{'out'}; |
715
|
0
|
0
|
|
|
|
|
if($oj->{'updated'}) |
716
|
|
|
|
|
|
|
{ |
717
|
0
|
|
|
|
|
|
$any_changed = 1; |
718
|
0
|
0
|
|
|
|
|
if($self->{'debug'}) |
719
|
|
|
|
|
|
|
{ |
720
|
0
|
|
|
|
|
|
print "ld $out has changed dep ".$oj->{'out'}."\n"; |
721
|
|
|
|
|
|
|
} |
722
|
|
|
|
|
|
|
} |
723
|
|
|
|
|
|
|
} |
724
|
|
|
|
|
|
|
|
725
|
0
|
|
|
|
|
|
my @ldflags = @{ $self->{'ldflags'} }; |
|
0
|
|
|
|
|
|
|
726
|
0
|
|
|
|
|
|
for my $rule (@{ $self->{'rules'} }) |
|
0
|
|
|
|
|
|
|
727
|
|
|
|
|
|
|
{ |
728
|
0
|
0
|
0
|
|
|
|
if($rule->{'file'} && $rule->{'file'} eq $out) |
729
|
|
|
|
|
|
|
{ |
730
|
0
|
|
|
|
|
|
my $add = $rule->{'add_ldflags'}; |
731
|
0
|
|
|
|
|
|
my $del = $rule->{'del_ldflags'}; |
732
|
0
|
0
|
|
|
|
|
if($add) |
733
|
|
|
|
|
|
|
{ |
734
|
0
|
|
|
|
|
|
for my $f (@$add) |
735
|
|
|
|
|
|
|
{ |
736
|
0
|
0
|
|
|
|
|
if(!grep { $_ eq $f } @ldflags) |
|
0
|
|
|
|
|
|
|
737
|
|
|
|
|
|
|
{ |
738
|
0
|
|
|
|
|
|
push @ldflags, $f; |
739
|
|
|
|
|
|
|
} |
740
|
|
|
|
|
|
|
} |
741
|
|
|
|
|
|
|
} |
742
|
0
|
0
|
|
|
|
|
if($del) |
743
|
|
|
|
|
|
|
{ |
744
|
0
|
|
|
|
|
|
@ldflags = grep { my $f = $_; ! grep { $f eq $_ } @$del } @ldflags; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
745
|
|
|
|
|
|
|
} |
746
|
|
|
|
|
|
|
} |
747
|
|
|
|
|
|
|
} |
748
|
|
|
|
|
|
|
|
749
|
0
|
0
|
|
|
|
|
my $exec = $self->{'cpp_ld'} ? $self->{'cpp'} : $self->{'cc'}; |
750
|
0
|
|
|
|
|
|
my @gcc = grep { $_ } ( |
|
0
|
|
|
|
|
|
|
751
|
|
|
|
|
|
|
$exec, |
752
|
|
|
|
|
|
|
@ldflags, |
753
|
|
|
|
|
|
|
@ofiles, |
754
|
|
|
|
|
|
|
'-o', $out, |
755
|
|
|
|
|
|
|
); |
756
|
0
|
|
|
|
|
|
my $exec_str = join(' ', @gcc); |
757
|
|
|
|
|
|
|
|
758
|
0
|
0
|
0
|
|
|
|
if(!$self->{'meta'}{$out} || !$self->{'meta'}{$out}{'exec'} || $self->{'meta'}{$out}{'exec'} ne $exec_str) |
|
|
|
0
|
|
|
|
|
759
|
|
|
|
|
|
|
{ |
760
|
0
|
|
|
|
|
|
$any_changed = 1; |
761
|
0
|
0
|
|
|
|
|
if($self->{'debug'}) |
762
|
|
|
|
|
|
|
{ |
763
|
0
|
|
|
|
|
|
print "cc $out has changed GCC options\n"; |
764
|
|
|
|
|
|
|
} |
765
|
|
|
|
|
|
|
}else |
766
|
|
|
|
|
|
|
{ |
767
|
0
|
0
|
|
|
|
|
if($self->{'debug'} > 2) |
768
|
|
|
|
|
|
|
{ |
769
|
0
|
|
|
|
|
|
print "cc $out has the same GCC options\n"; |
770
|
|
|
|
|
|
|
} |
771
|
|
|
|
|
|
|
} |
772
|
|
|
|
|
|
|
|
773
|
0
|
0
|
|
|
|
|
if($self->{'clean'}) |
|
|
0
|
|
|
|
|
|
774
|
|
|
|
|
|
|
{ |
775
|
0
|
|
|
|
|
|
$self->unlink_file($out); |
776
|
|
|
|
|
|
|
} |
777
|
|
|
|
|
|
|
elsif($any_changed) |
778
|
|
|
|
|
|
|
{ |
779
|
0
|
0
|
|
|
|
|
if($self->{'verbose'}) |
|
|
0
|
|
|
|
|
|
780
|
|
|
|
|
|
|
{ |
781
|
0
|
|
|
|
|
|
print $exec_str."\n"; |
782
|
|
|
|
|
|
|
}elsif(!$self->{'quiet'}) |
783
|
|
|
|
|
|
|
{ |
784
|
0
|
0
|
|
|
|
|
print $self->{'cpp_ld'} ? "ld++ " : "ld "; |
785
|
0
|
|
|
|
|
|
print "$out..\n"; |
786
|
|
|
|
|
|
|
} |
787
|
|
|
|
|
|
|
|
788
|
0
|
|
|
|
|
|
my $start = time; |
789
|
0
|
|
|
|
|
|
system(@gcc); |
790
|
0
|
|
|
|
|
|
$system_runtime += (time - $start); |
791
|
|
|
|
|
|
|
|
792
|
0
|
|
|
|
|
|
$self->file_update($out); |
793
|
0
|
|
|
|
|
|
$self->{'meta'}{$out}{'exec'} = $exec_str; |
794
|
|
|
|
|
|
|
}else |
795
|
|
|
|
|
|
|
{ |
796
|
0
|
0
|
|
|
|
|
if($self->{'verbose'}) |
797
|
|
|
|
|
|
|
{ |
798
|
0
|
|
|
|
|
|
print "Already up to date: $out\n"; |
799
|
|
|
|
|
|
|
} |
800
|
|
|
|
|
|
|
} |
801
|
|
|
|
|
|
|
|
802
|
0
|
|
|
|
|
|
$job->{'done'} = 1; |
803
|
0
|
|
|
|
|
|
return 1; |
804
|
|
|
|
|
|
|
} |
805
|
|
|
|
|
|
|
|
806
|
0
|
|
0
|
|
|
|
die "bad task type: ".($job->{'task'} // 'undef'); |
807
|
|
|
|
|
|
|
} |
808
|
|
|
|
|
|
|
|
809
|
|
|
|
|
|
|
sub slurp_depfile |
810
|
|
|
|
|
|
|
{ |
811
|
0
|
|
|
0
|
0
|
|
my($depfile) = @_; |
812
|
|
|
|
|
|
|
|
813
|
0
|
0
|
|
|
|
|
open(my $dat, '<', $depfile) || die $!; |
814
|
0
|
|
|
|
|
|
my $slurp = do { local $/ = undef; <$dat> }; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
815
|
0
|
0
|
|
|
|
|
close($dat) || die $!; |
816
|
|
|
|
|
|
|
|
817
|
0
|
|
|
|
|
|
unlink($depfile); |
818
|
|
|
|
|
|
|
|
819
|
0
|
|
|
|
|
|
$slurp =~ s/^.+:\s+//; |
820
|
0
|
|
|
|
|
|
$slurp =~ s/\\\n/ /gsm; |
821
|
|
|
|
|
|
|
|
822
|
0
|
|
|
|
|
|
my @incs = grep { length } split(/\s+/, $slurp); |
|
0
|
|
|
|
|
|
|
823
|
|
|
|
|
|
|
|
824
|
0
|
|
|
|
|
|
return \@incs; |
825
|
|
|
|
|
|
|
} |
826
|
|
|
|
|
|
|
|
827
|
|
|
|
|
|
|
sub replace_ext |
828
|
|
|
|
|
|
|
{ |
829
|
0
|
|
|
0
|
0
|
|
my($in, $ext) = @_; |
830
|
0
|
|
|
|
|
|
$in =~ s/\.[^.]{1,3}$//; |
831
|
0
|
|
|
|
|
|
$in .= '.'.$ext; |
832
|
0
|
|
|
|
|
|
return $in; |
833
|
|
|
|
|
|
|
} |
834
|
|
|
|
|
|
|
|
835
|
|
|
|
|
|
|
sub file_changed |
836
|
|
|
|
|
|
|
{ |
837
|
0
|
|
|
0
|
0
|
|
my($self, $file) = @_; |
838
|
|
|
|
|
|
|
|
839
|
0
|
0
|
|
|
|
|
if(defined $self->{'changed_this_run'}{$file}) |
840
|
|
|
|
|
|
|
{ |
841
|
0
|
|
|
|
|
|
return $self->{'changed_this_run'}{$file}; |
842
|
|
|
|
|
|
|
} |
843
|
|
|
|
|
|
|
|
844
|
0
|
0
|
|
|
|
|
if(-e $file) |
845
|
|
|
|
|
|
|
{ |
846
|
0
|
|
|
|
|
|
my $mtime = $self->mtime($file); |
847
|
|
|
|
|
|
|
#my $md5 = $self->md5($file); |
848
|
|
|
|
|
|
|
|
849
|
0
|
0
|
0
|
|
|
|
if($self->{'meta'}{$file} && $self->{'meta'}{$file}{'mtime'} && $self->{'meta'}{$file}{'mtime'} == $mtime) |
|
|
|
0
|
|
|
|
|
850
|
|
|
|
|
|
|
{ |
851
|
0
|
|
|
|
|
|
$self->{'changed_this_run'}{$file} = 0; |
852
|
0
|
|
|
|
|
|
return 0; |
853
|
|
|
|
|
|
|
} |
854
|
|
|
|
|
|
|
|
855
|
|
|
|
|
|
|
#if($self->{'meta'}{$file} && $self->{'meta'}{$file}{'md5'} && $self->{'meta'}{$file}{'md5'} eq $md5) |
856
|
|
|
|
|
|
|
#{ |
857
|
|
|
|
|
|
|
# $self->{'changed_this_run'}{$file} = 0; |
858
|
|
|
|
|
|
|
# return 0; |
859
|
|
|
|
|
|
|
#} |
860
|
|
|
|
|
|
|
|
861
|
0
|
|
|
|
|
|
$self->{'meta'}{$file}{'mtime'} = $mtime; |
862
|
|
|
|
|
|
|
#$self->{'meta'}{$file}{'md5'} = $md5; |
863
|
|
|
|
|
|
|
} |
864
|
|
|
|
|
|
|
|
865
|
0
|
|
|
|
|
|
$self->{'changed_this_run'}{$file} = 1; |
866
|
0
|
|
|
|
|
|
return 1; |
867
|
|
|
|
|
|
|
} |
868
|
|
|
|
|
|
|
sub file_update |
869
|
|
|
|
|
|
|
{ |
870
|
0
|
|
|
0
|
0
|
|
my($self, $file) = @_; |
871
|
|
|
|
|
|
|
|
872
|
0
|
|
|
|
|
|
delete $self->{'mtime_this_run'}{$file}; |
873
|
0
|
|
|
|
|
|
delete $self->{'md5_this_run'}{$file}; |
874
|
0
|
|
|
|
|
|
delete $self->{'changed_this_run'}{$file}; |
875
|
0
|
|
|
|
|
|
return $self->file_changed($file); |
876
|
|
|
|
|
|
|
} |
877
|
|
|
|
|
|
|
|
878
|
|
|
|
|
|
|
sub mtime |
879
|
|
|
|
|
|
|
{ |
880
|
0
|
|
|
0
|
0
|
|
my($self, $file) = @_; |
881
|
0
|
0
|
|
|
|
|
if($self->{'mtime_this_run'}{$file}) |
882
|
|
|
|
|
|
|
{ |
883
|
0
|
|
|
|
|
|
return $self->{'mtime_this_run'}{$file}; |
884
|
|
|
|
|
|
|
} |
885
|
0
|
0
|
|
|
|
|
if($self->{'debug'} > 1) |
886
|
|
|
|
|
|
|
{ |
887
|
0
|
|
|
|
|
|
print "stat('$file');\n"; |
888
|
|
|
|
|
|
|
} |
889
|
0
|
|
|
|
|
|
my @s = stat($file); |
890
|
0
|
|
|
|
|
|
$self->{'mtime_this_run'}{$file} = $s[9]; |
891
|
0
|
|
|
|
|
|
return $s[9]; |
892
|
|
|
|
|
|
|
} |
893
|
|
|
|
|
|
|
|
894
|
|
|
|
|
|
|
sub md5 |
895
|
|
|
|
|
|
|
{ |
896
|
0
|
|
|
0
|
0
|
|
my($self, $file) = @_; |
897
|
0
|
0
|
|
|
|
|
if($self->{'md5_this_run'}{$file}) |
898
|
|
|
|
|
|
|
{ |
899
|
0
|
|
|
|
|
|
return $self->{'md5_this_run'}{$file}; |
900
|
|
|
|
|
|
|
} |
901
|
0
|
0
|
|
|
|
|
if($self->{'debug'} > 1) |
902
|
|
|
|
|
|
|
{ |
903
|
0
|
|
|
|
|
|
print " md5('$file');\n"; |
904
|
|
|
|
|
|
|
} |
905
|
0
|
0
|
|
|
|
|
open(my $dat, '<', $file) || die "cannot open file for md5: $!"; |
906
|
0
|
|
|
|
|
|
my $md5 = Digest::MD5->new(); |
907
|
0
|
|
|
|
|
|
$md5->addfile($dat); |
908
|
0
|
|
|
|
|
|
close($dat); |
909
|
0
|
|
|
|
|
|
my $sum = $md5->hexdigest(); |
910
|
0
|
|
|
|
|
|
$self->{'md5_this_run'}{$file} = $sum; |
911
|
0
|
|
|
|
|
|
return $sum; |
912
|
|
|
|
|
|
|
} |
913
|
|
|
|
|
|
|
|
914
|
|
|
|
|
|
|
sub unlink_file |
915
|
|
|
|
|
|
|
{ |
916
|
0
|
|
|
0
|
0
|
|
my($self, $file) = @_; |
917
|
|
|
|
|
|
|
|
918
|
0
|
0
|
|
|
|
|
if(-e $file) |
919
|
|
|
|
|
|
|
{ |
920
|
0
|
0
|
|
|
|
|
if($self->{'verbose'}) |
921
|
|
|
|
|
|
|
{ |
922
|
0
|
|
|
|
|
|
print "unlink('$file');\n"; |
923
|
|
|
|
|
|
|
} |
924
|
0
|
0
|
|
|
|
|
unlink($file) || die "could not unlink $file: $!"; |
925
|
|
|
|
|
|
|
} |
926
|
|
|
|
|
|
|
} |
927
|
|
|
|
|
|
|
|
928
|
|
|
|
|
|
|
1; |