]>
Commit | Line | Data |
---|---|---|
2660b7cf RL |
1 | package gentemplate; |
2 | ||
3 | use strict; | |
4 | use warnings; | |
5 | use Carp; | |
6 | ||
7 | use Exporter; | |
8 | use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS); | |
9 | @ISA = qw(Exporter); | |
10 | @EXPORT = qw(gentemplate); | |
11 | ||
12 | use File::Basename; | |
13 | ||
14 | sub gentemplate { | |
15 | my %opts = @_; | |
16 | ||
17 | my $generator = OpenSSL::GenTemplate->new(%opts); | |
18 | ||
19 | # Build mandatory header file generators | |
20 | foreach (@{$generator->{info}->{depends}->{""}}) { $generator->dogenerate($_); } | |
21 | ||
22 | # Build all known targets, libraries, modules, programs and scripts. | |
23 | # Everything else will be handled as a consequence. | |
24 | foreach (@{$generator->{info}->{targets}}) { $generator->dotarget($_); } | |
25 | foreach (@{$generator->{info}->{libraries}}) { $generator->dolib($_); } | |
26 | foreach (@{$generator->{info}->{modules}}) { $generator->domodule($_); } | |
27 | foreach (@{$generator->{info}->{programs}}) { $generator->dobin($_); } | |
28 | foreach (@{$generator->{info}->{scripts}}) { $generator->doscript($_); } | |
29 | foreach (sort keys %{$generator->{info}->{htmldocs}}) { $generator->dodocs('html', $_); } | |
30 | foreach (sort keys %{$generator->{info}->{mandocs}}) { $generator->dodocs('man', $_); } | |
31 | foreach (sort keys %{$generator->{info}->{dirinfo}}) { $generator->dodir($_); } | |
32 | } | |
33 | ||
34 | package OpenSSL::GenTemplate; | |
35 | ||
36 | use OpenSSL::Util; | |
37 | ||
38 | sub new { | |
39 | my $class = shift; | |
40 | my %opts = @_; | |
41 | ||
42 | my $data = { | |
43 | output => $opts{output}, | |
44 | config => $opts{config} // {}, | |
45 | disabled => $opts{disabled} // {}, | |
46 | info => $opts{unified_info} // {}, | |
47 | }; | |
48 | ||
49 | return bless $data, $class; | |
50 | }; | |
51 | ||
52 | sub emit { | |
53 | my $self = shift; | |
54 | my $name = shift; | |
55 | my %opts = @_; | |
56 | my $fh = $self->{output}; | |
57 | ||
58 | die "No name?" unless $name; | |
4d02d500 RL |
59 | print $fh "{-\n ", $name, '(', dump_data(\%opts), ');', " \n-}" |
60 | unless defined $opts{attrs}->{skip}; | |
2660b7cf RL |
61 | } |
62 | ||
63 | my $debug_resolvedepends = $ENV{BUILDFILE_DEBUG_DEPENDS}; | |
64 | my $debug_rules = $ENV{BUILDFILE_DEBUG_RULES}; | |
65 | ||
66 | # A cache of objects for which a recipe has already been generated | |
67 | our %cache; | |
68 | ||
69 | # collectdepends, expanddepends and reducedepends work together to make | |
70 | # sure there are no duplicate or weak dependencies and that they are in | |
71 | # the right order. This is used to sort the list of libraries that a | |
72 | # build depends on. | |
73 | sub extensionlesslib { | |
74 | my @result = map { $_ =~ /(\.a)?$/; $` } @_; | |
75 | return @result if wantarray; | |
76 | return $result[0]; | |
77 | } | |
78 | ||
79 | # collectdepends dives into the tree of dependencies and returns | |
80 | # a list of all the non-weak ones. | |
81 | sub collectdepends { | |
82 | my $self = shift; | |
83 | return () unless @_; | |
84 | ||
85 | my $thing = shift; | |
86 | my $extensionlessthing = extensionlesslib($thing); | |
87 | my @listsofar = @_; # to check if we're looping | |
88 | my @list = @{ $self->{info}->{depends}->{$thing} // | |
89 | $self->{info}->{depends}->{$extensionlessthing} | |
90 | // [] }; | |
91 | my @newlist = (); | |
92 | ||
93 | print STDERR "DEBUG[collectdepends] $thing > ", join(' ', @listsofar), "\n" | |
94 | if $debug_resolvedepends; | |
95 | foreach my $item (@list) { | |
96 | my $extensionlessitem = extensionlesslib($item); | |
97 | # It's time to break off when the dependency list starts looping | |
98 | next if grep { extensionlesslib($_) eq $extensionlessitem } @listsofar; | |
99 | # Don't add anything here if the dependency is weak | |
100 | next if defined $self->{info}->{attributes}->{depends}->{$thing}->{$item}->{'weak'}; | |
101 | my @resolved = $self->collectdepends($item, @listsofar, $item); | |
102 | push @newlist, $item, @resolved; | |
103 | } | |
104 | print STDERR "DEBUG[collectdepends] $thing < ", join(' ', @newlist), "\n" | |
105 | if $debug_resolvedepends; | |
106 | @newlist; | |
107 | } | |
108 | ||
109 | # expanddepends goes through a list of stuff, checks if they have any | |
110 | # dependencies, and adds them at the end of the current position if | |
111 | # they aren't already present later on. | |
112 | sub expanddepends { | |
113 | my $self = shift; | |
114 | my @after = ( @_ ); | |
115 | print STDERR "DEBUG[expanddepends]> ", join(' ', @after), "\n" | |
116 | if $debug_resolvedepends; | |
117 | my @before = (); | |
118 | while (@after) { | |
119 | my $item = shift @after; | |
120 | print STDERR "DEBUG[expanddepends]\\ ", join(' ', @before), "\n" | |
121 | if $debug_resolvedepends; | |
122 | print STDERR "DEBUG[expanddepends] - ", $item, "\n" | |
123 | if $debug_resolvedepends; | |
124 | my @middle = ( | |
125 | $item, | |
126 | map { | |
127 | my $x = $_; | |
128 | my $extlessx = extensionlesslib($x); | |
129 | if (grep { $extlessx eq extensionlesslib($_) } @before | |
130 | and | |
131 | !grep { $extlessx eq extensionlesslib($_) } @after) { | |
132 | print STDERR "DEBUG[expanddepends] + ", $x, "\n" | |
133 | if $debug_resolvedepends; | |
134 | ( $x ) | |
135 | } else { | |
136 | print STDERR "DEBUG[expanddepends] ! ", $x, "\n" | |
137 | if $debug_resolvedepends; | |
138 | () | |
139 | } | |
140 | } @{$self->{info}->{depends}->{$item} // []} | |
141 | ); | |
142 | print STDERR "DEBUG[expanddepends] = ", join(' ', @middle), "\n" | |
143 | if $debug_resolvedepends; | |
144 | print STDERR "DEBUG[expanddepends]/ ", join(' ', @after), "\n" | |
145 | if $debug_resolvedepends; | |
146 | push @before, @middle; | |
147 | } | |
148 | print STDERR "DEBUG[expanddepends]< ", join(' ', @before), "\n" | |
149 | if $debug_resolvedepends; | |
150 | @before; | |
151 | } | |
152 | ||
153 | # reducedepends looks through a list, and checks if each item is | |
154 | # repeated later on. If it is, the earlier copy is dropped. | |
155 | sub reducedepends { | |
156 | my @list = @_; | |
157 | print STDERR "DEBUG[reducedepends]> ", join(' ', @list), "\n" | |
158 | if $debug_resolvedepends; | |
159 | my @newlist = (); | |
160 | my %replace = (); | |
161 | while (@list) { | |
162 | my $item = shift @list; | |
163 | my $extensionlessitem = extensionlesslib($item); | |
164 | if (grep { $extensionlessitem eq extensionlesslib($_) } @list) { | |
165 | if ($item ne $extensionlessitem) { | |
166 | # If this instance of the library is explicitly static, we | |
167 | # prefer that to any shared library name, since it must have | |
168 | # been done on purpose. | |
169 | $replace{$extensionlessitem} = $item; | |
170 | } | |
171 | } else { | |
172 | push @newlist, $item; | |
173 | } | |
174 | } | |
175 | @newlist = map { $replace{$_} // $_; } @newlist; | |
176 | print STDERR "DEBUG[reducedepends]< ", join(' ', @newlist), "\n" | |
177 | if $debug_resolvedepends; | |
178 | @newlist; | |
179 | } | |
180 | ||
181 | # Do it all | |
182 | # This takes multiple inputs and combine them into a single list of | |
183 | # interdependent things. The returned value will include all the input. | |
184 | # Callers are responsible for taking away the things they are building. | |
185 | sub resolvedepends { | |
186 | my $self = shift; | |
187 | print STDERR "DEBUG[resolvedepends] START (", join(', ', @_), ")\n" | |
188 | if $debug_resolvedepends; | |
189 | my @all = | |
190 | reducedepends($self->expanddepends(map { ( $_, $self->collectdepends($_) ) } @_)); | |
191 | print STDERR "DEBUG[resolvedepends] END (", join(', ', @_), ") : ", | |
192 | join(',', map { "\n $_" } @all), "\n" | |
193 | if $debug_resolvedepends; | |
194 | @all; | |
195 | } | |
196 | ||
197 | # dogenerate is responsible for producing all the recipes that build | |
198 | # generated source files. It recurses in case a dependency is also a | |
199 | # generated source file. | |
200 | sub dogenerate { | |
201 | my $self = shift; | |
202 | my $src = shift; | |
203 | # Safety measure | |
4d02d500 | 204 | return "" unless defined $self->{info}->{generate}->{$src}; |
2660b7cf RL |
205 | return "" if $cache{$src}; |
206 | my $obj = shift; | |
207 | my $bin = shift; | |
208 | my %opts = @_; | |
209 | if ($self->{info}->{generate}->{$src}) { | |
210 | die "$src is generated by Configure, should not appear in build file\n" | |
211 | if ref $self->{info}->{generate}->{$src} eq ""; | |
212 | my $script = $self->{info}->{generate}->{$src}->[0]; | |
4d02d500 | 213 | my %attrs = %{$self->{info}->{attributes}->{generate}->{$src} // {}}; |
2660b7cf RL |
214 | $self->emit('generatesrc', |
215 | src => $src, | |
216 | product => $bin, | |
217 | generator => $self->{info}->{generate}->{$src}, | |
218 | generator_incs => $self->{info}->{includes}->{$script} // [], | |
219 | generator_deps => $self->{info}->{depends}->{$script} // [], | |
220 | deps => $self->{info}->{depends}->{$src} // [], | |
221 | incs => [ defined $obj ? @{$self->{info}->{includes}->{$obj} // []} : (), | |
222 | defined $bin ? @{$self->{info}->{includes}->{$bin} // []} : () ], | |
223 | defs => [ defined $obj ? @{$self->{info}->{defines}->{$obj} // []} : (), | |
224 | defined $bin ? @{$self->{info}->{defines}->{$bin} // []} : () ], | |
4d02d500 | 225 | attrs => { %attrs }, |
2660b7cf RL |
226 | %opts); |
227 | foreach (@{$self->{info}->{depends}->{$src} // []}) { | |
228 | $self->dogenerate($_, $obj, $bin, %opts); | |
229 | } | |
230 | } | |
231 | $cache{$src} = 1; | |
232 | } | |
233 | ||
234 | sub dotarget { | |
235 | my $self = shift; | |
236 | my $target = shift; | |
237 | return "" if $cache{$target}; | |
238 | $self->emit('generatetarget', | |
239 | target => $target, | |
240 | deps => $self->{info}->{depends}->{$target} // []); | |
241 | foreach (@{$self->{info}->{depends}->{$target} // []}) { | |
242 | $self->dogenerate($_); | |
243 | } | |
244 | $cache{$target} = 1; | |
245 | } | |
246 | ||
247 | # doobj is responsible for producing all the recipes that build | |
248 | # object files as well as dependency files. | |
249 | sub doobj { | |
250 | my $self = shift; | |
251 | my $obj = shift; | |
252 | return "" if $cache{$obj}; | |
253 | my $bin = shift; | |
254 | my %opts = @_; | |
255 | if (@{$self->{info}->{sources}->{$obj} // []}) { | |
256 | my @srcs = @{$self->{info}->{sources}->{$obj}}; | |
257 | my @deps = @{$self->{info}->{depends}->{$obj} // []}; | |
258 | my @incs = ( @{$self->{info}->{includes}->{$obj} // []}, | |
259 | @{$self->{info}->{includes}->{$bin} // []} ); | |
260 | my @defs = ( @{$self->{info}->{defines}->{$obj} // []}, | |
261 | @{$self->{info}->{defines}->{$bin} // []} ); | |
262 | print STDERR "DEBUG[doobj] \@srcs for $obj ($bin) : ", | |
263 | join(",", map { "\n $_" } @srcs), "\n" | |
264 | if $debug_rules; | |
265 | print STDERR "DEBUG[doobj] \@deps for $obj ($bin) : ", | |
266 | join(",", map { "\n $_" } @deps), "\n" | |
267 | if $debug_rules; | |
268 | print STDERR "DEBUG[doobj] \@incs for $obj ($bin) : ", | |
269 | join(",", map { "\n $_" } @incs), "\n" | |
270 | if $debug_rules; | |
271 | print STDERR "DEBUG[doobj] \@defs for $obj ($bin) : ", | |
272 | join(",", map { "\n $_" } @defs), "\n" | |
273 | if $debug_rules; | |
274 | print STDERR "DEBUG[doobj] \%opts for $obj ($bin) : ", , | |
275 | join(",", map { "\n $_ = $opts{$_}" } sort keys %opts), "\n" | |
276 | if $debug_rules; | |
277 | $self->emit('src2obj', | |
278 | obj => $obj, product => $bin, | |
279 | srcs => [ @srcs ], deps => [ @deps ], | |
280 | incs => [ @incs ], defs => [ @defs ], | |
281 | %opts); | |
282 | foreach ((@{$self->{info}->{sources}->{$obj}}, | |
283 | @{$self->{info}->{depends}->{$obj} // []})) { | |
284 | $self->dogenerate($_, $obj, $bin, %opts); | |
285 | } | |
286 | } | |
287 | $cache{$obj} = 1; | |
288 | } | |
289 | ||
290 | # Helper functions to grab all applicable intermediary files. | |
291 | # This is particularly useful when a library is given as source | |
292 | # rather than a dependency. In that case, we consider it to be a | |
293 | # container with object file references, or possibly references | |
294 | # to further libraries to pilfer in the same way. | |
295 | sub getsrclibs { | |
296 | my $self = shift; | |
297 | my $section = shift; | |
298 | ||
299 | # For all input, see if it sources static libraries. If it does, | |
300 | # return them together with the result of a recursive call. | |
301 | map { ( $_, getsrclibs($section, $_) ) } | |
302 | grep { $_ =~ m|\.a$| } | |
303 | map { @{$self->{info}->{$section}->{$_} // []} } | |
304 | @_; | |
305 | } | |
306 | ||
307 | sub getlibobjs { | |
308 | my $self = shift; | |
309 | my $section = shift; | |
310 | ||
311 | # For all input, see if it's an intermediary file (library or object). | |
312 | # If it is, collect the result of a recursive call, or if that returns | |
313 | # an empty list, the element itself. Return the result. | |
314 | map { | |
315 | my @x = $self->getlibobjs($section, @{$self->{info}->{$section}->{$_}}); | |
316 | @x ? @x : ( $_ ); | |
317 | } | |
318 | grep { defined $self->{info}->{$section}->{$_} } | |
319 | @_; | |
320 | } | |
321 | ||
322 | # dolib is responsible for building libraries. It will call | |
323 | # obj2shlib if shared libraries are produced, and obj2lib in all | |
324 | # cases. It also makes sure all object files for the library are | |
325 | # built. | |
326 | sub dolib { | |
327 | my $self = shift; | |
328 | my $lib = shift; | |
329 | return "" if $cache{$lib}; | |
330 | ||
331 | my %attrs = %{$self->{info}->{attributes}->{libraries}->{$lib} // {}}; | |
332 | ||
333 | my @deps = ( $self->resolvedepends(getsrclibs('sources', $lib)) ); | |
334 | ||
335 | # We support two types of objs, those who are specific to this library | |
336 | # (they end up in @objs) and those that we get indirectly, via other | |
337 | # libraries (they end up in @foreign_objs). We get the latter any time | |
338 | # someone has done something like this in build.info: | |
339 | # SOURCE[libfoo.a]=libbar.a | |
340 | # The indirect object files must be kept in a separate array so they | |
341 | # don't get rebuilt unnecessarily (and with incorrect auxiliary | |
342 | # information). | |
343 | # | |
344 | # Object files can't be collected commonly for shared and static | |
345 | # libraries, because we contain their respective object files in | |
346 | # {shared_sources} and {sources}, and because the implications are | |
347 | # slightly different for each library form. | |
348 | # | |
349 | # We grab all these "foreign" object files recursively with getlibobjs(). | |
350 | ||
351 | unless ($self->{disabled}->{shared} || $lib =~ /\.a$/) { | |
352 | # If this library sources other static libraries and those | |
353 | # libraries are marked {noinst}, there's no need to include | |
354 | # all of their object files. Instead, we treat those static | |
355 | # libraries as dependents alongside any other library this | |
356 | # one depends on, and let symbol resolution do its job. | |
357 | my @sourced_libs = (); | |
358 | my @objs = (); | |
359 | my @foreign_objs = (); | |
360 | my @deps = (); | |
361 | foreach (@{$self->{info}->{shared_sources}->{$lib} // []}) { | |
362 | if ($_ !~ m|\.a$|) { | |
363 | push @objs, $_; | |
364 | } elsif ($self->{info}->{attributes}->{libraries}->{$_}->{noinst}) { | |
365 | push @deps, $_; | |
366 | } else { | |
367 | push @deps, $self->getsrclibs('sources', $_); | |
368 | push @foreign_objs, $self->getlibobjs('sources', $_); | |
369 | } | |
370 | } | |
371 | @deps = ( grep { $_ ne $lib } $self->resolvedepends($lib, @deps) ); | |
372 | print STDERR "DEBUG[dolib:shlib] \%attrs for $lib : ", , | |
373 | join(",", map { "\n $_ = $attrs{$_}" } sort keys %attrs), "\n" | |
374 | if %attrs && $debug_rules; | |
375 | print STDERR "DEBUG[dolib:shlib] \@deps for $lib : ", | |
376 | join(",", map { "\n $_" } @deps), "\n" | |
377 | if @deps && $debug_rules; | |
378 | print STDERR "DEBUG[dolib:shlib] \@objs for $lib : ", | |
379 | join(",", map { "\n $_" } @objs), "\n" | |
380 | if @objs && $debug_rules; | |
381 | print STDERR "DEBUG[dolib:shlib] \@foreign_objs for $lib : ", | |
382 | join(",", map { "\n $_" } @foreign_objs), "\n" | |
383 | if @foreign_objs && $debug_rules; | |
384 | $self->emit('obj2shlib', | |
385 | lib => $lib, | |
386 | attrs => { %attrs }, | |
387 | objs => [ @objs, @foreign_objs ], | |
388 | deps => [ @deps ]); | |
389 | foreach (@objs) { | |
390 | # If this is somehow a compiled object, take care of it that way | |
391 | # Otherwise, it might simply be generated | |
392 | if (defined $self->{info}->{sources}->{$_}) { | |
393 | if($_ =~ /\.a$/) { | |
394 | $self->dolib($_); | |
395 | } else { | |
396 | $self->doobj($_, $lib, intent => "shlib", attrs => { %attrs }); | |
397 | } | |
398 | } else { | |
399 | $self->dogenerate($_, undef, undef, intent => "lib"); | |
400 | } | |
401 | } | |
402 | } | |
403 | { | |
404 | # When putting static libraries together, we cannot rely on any | |
405 | # symbol resolution, so for all static libraries used as source for | |
406 | # this one, as well as other libraries they depend on, we simply | |
407 | # grab all their object files unconditionally, | |
408 | # Symbol resolution will happen when any program, module or shared | |
409 | # library is linked with this one. | |
410 | my @objs = (); | |
411 | my @sourcedeps = (); | |
412 | my @foreign_objs = (); | |
413 | foreach (@{$self->{info}->{sources}->{$lib}}) { | |
414 | if ($_ !~ m|\.a$|) { | |
415 | push @objs, $_; | |
416 | } else { | |
417 | push @sourcedeps, $_; | |
418 | } | |
419 | } | |
420 | @sourcedeps = ( grep { $_ ne $lib } $self->resolvedepends(@sourcedeps) ); | |
421 | print STDERR "DEBUG[dolib:lib] : \@sourcedeps for $_ : ", | |
422 | join(",", map { "\n $_" } @sourcedeps), "\n" | |
423 | if @sourcedeps && $debug_rules; | |
424 | @foreign_objs = $self->getlibobjs('sources', @sourcedeps); | |
425 | print STDERR "DEBUG[dolib:lib] \%attrs for $lib : ", , | |
426 | join(",", map { "\n $_ = $attrs{$_}" } sort keys %attrs), "\n" | |
427 | if %attrs && $debug_rules; | |
428 | print STDERR "DEBUG[dolib:lib] \@objs for $lib : ", | |
429 | join(",", map { "\n $_" } @objs), "\n" | |
430 | if @objs && $debug_rules; | |
431 | print STDERR "DEBUG[dolib:lib] \@foreign_objs for $lib : ", | |
432 | join(",", map { "\n $_" } @foreign_objs), "\n" | |
433 | if @foreign_objs && $debug_rules; | |
434 | $self->emit('obj2lib', | |
435 | lib => $lib, attrs => { %attrs }, | |
436 | objs => [ @objs, @foreign_objs ]); | |
437 | foreach (@objs) { | |
438 | $self->doobj($_, $lib, intent => "lib", attrs => { %attrs }); | |
439 | } | |
440 | } | |
441 | $cache{$lib} = 1; | |
442 | } | |
443 | ||
444 | # domodule is responsible for building modules. It will call | |
445 | # obj2dso, and also makes sure all object files for the library | |
446 | # are built. | |
447 | sub domodule { | |
448 | my $self = shift; | |
449 | my $module = shift; | |
450 | return "" if $cache{$module}; | |
451 | my %attrs = %{$self->{info}->{attributes}->{modules}->{$module} // {}}; | |
452 | my @objs = @{$self->{info}->{sources}->{$module}}; | |
453 | my @deps = ( grep { $_ ne $module } | |
454 | $self->resolvedepends($module) ); | |
455 | print STDERR "DEBUG[domodule] \%attrs for $module :", | |
456 | join(",", map { "\n $_ = $attrs{$_}" } sort keys %attrs), "\n" | |
457 | if $debug_rules; | |
458 | print STDERR "DEBUG[domodule] \@objs for $module : ", | |
459 | join(",", map { "\n $_" } @objs), "\n" | |
460 | if $debug_rules; | |
461 | print STDERR "DEBUG[domodule] \@deps for $module : ", | |
462 | join(",", map { "\n $_" } @deps), "\n" | |
463 | if $debug_rules; | |
464 | $self->emit('obj2dso', | |
465 | module => $module, | |
466 | attrs => { %attrs }, | |
467 | objs => [ @objs ], | |
468 | deps => [ @deps ]); | |
469 | foreach (@{$self->{info}->{sources}->{$module}}) { | |
470 | # If this is somehow a compiled object, take care of it that way | |
471 | # Otherwise, it might simply be generated | |
472 | if (defined $self->{info}->{sources}->{$_}) { | |
473 | $self->doobj($_, $module, intent => "dso", attrs => { %attrs }); | |
474 | } else { | |
475 | $self->dogenerate($_, undef, $module, intent => "dso"); | |
476 | } | |
477 | } | |
478 | $cache{$module} = 1; | |
479 | } | |
480 | ||
481 | # dobin is responsible for building programs. It will call obj2bin, | |
482 | # and also makes sure all object files for the library are built. | |
483 | sub dobin { | |
484 | my $self = shift; | |
485 | my $bin = shift; | |
486 | return "" if $cache{$bin}; | |
487 | my %attrs = %{$self->{info}->{attributes}->{programs}->{$bin} // {}}; | |
488 | my @objs = @{$self->{info}->{sources}->{$bin}}; | |
489 | my @deps = ( grep { $_ ne $bin } $self->resolvedepends($bin) ); | |
490 | print STDERR "DEBUG[dobin] \%attrs for $bin : ", | |
491 | join(",", map { "\n $_ = $attrs{$_}" } sort keys %attrs), "\n" | |
492 | if %attrs && $debug_rules; | |
493 | print STDERR "DEBUG[dobin] \@objs for $bin : ", | |
494 | join(",", map { "\n $_" } @objs), "\n" | |
495 | if @objs && $debug_rules; | |
496 | print STDERR "DEBUG[dobin] \@deps for $bin : ", | |
497 | join(",", map { "\n $_" } @deps), "\n" | |
498 | if @deps && $debug_rules; | |
499 | $self->emit('obj2bin', | |
500 | bin => $bin, | |
501 | attrs => { %attrs }, | |
502 | objs => [ @objs ], | |
503 | deps => [ @deps ]); | |
504 | foreach (@objs) { | |
505 | $self->doobj($_, $bin, intent => "bin", attrs => { %attrs }); | |
506 | } | |
507 | $cache{$bin} = 1; | |
508 | } | |
509 | ||
510 | # doscript is responsible for building scripts from templates. It will | |
511 | # call in2script. | |
512 | sub doscript { | |
513 | my $self = shift; | |
514 | my $script = shift; | |
515 | return "" if $cache{$script}; | |
516 | $self->emit('in2script', | |
517 | script => $script, | |
3c121b98 | 518 | attrs => $self->{info}->{attributes}->{scripts}->{$script} // {}, |
2660b7cf RL |
519 | sources => $self->{info}->{sources}->{$script}); |
520 | $cache{$script} = 1; | |
521 | } | |
522 | ||
523 | sub dodir { | |
524 | my $self = shift; | |
525 | my $dir = shift; | |
526 | return "" if !exists(&generatedir) or $cache{$dir}; | |
527 | $self->emit('generatedir', | |
528 | dir => $dir, | |
529 | deps => $self->{info}->{dirinfo}->{$dir}->{deps} // [], | |
530 | %{$self->{info}->{dirinfo}->{$_}->{products}}); | |
531 | $cache{$dir} = 1; | |
532 | } | |
533 | ||
534 | # dodocs is responsible for building documentation from .pods. | |
535 | # It will call generatesrc. | |
536 | sub dodocs { | |
537 | my $self = shift; | |
538 | my $type = shift; | |
539 | my $section = shift; | |
540 | foreach my $doc (@{$self->{info}->{"${type}docs"}->{$section}}) { | |
541 | next if $cache{$doc}; | |
542 | $self->emit('generatesrc', | |
543 | src => $doc, | |
544 | generator => $self->{info}->{generate}->{$doc}); | |
545 | foreach ((@{$self->{info}->{depends}->{$doc} // []})) { | |
546 | $self->dogenerate($_, undef, undef); | |
547 | } | |
548 | $cache{$doc} = 1; | |
549 | } | |
550 | } | |
551 | ||
552 | 1; |