| {- # -*- Mode: perl -*- |
| |
| # A cache of objects for which a recipe has already been generated |
| my %cache; |
| |
| # resolvedepends and reducedepends work in tandem to make sure |
| # there are no duplicate dependencies and that they are in the |
| # right order. This is especially used to sort the list of |
| # libraries that a build depends on. |
| sub resolvedepends { |
| my $thing = shift; |
| my @listsofar = @_; # to check if we're looping |
| my @list = @{$unified_info{depends}->{$thing}}; |
| my @newlist = (); |
| if (scalar @list) { |
| foreach my $item (@list) { |
| # It's time to break off when the dependency list starts looping |
| next if grep { $_ eq $item } @listsofar; |
| push @newlist, $item, resolvedepends($item, @listsofar, $item); |
| } |
| } |
| @newlist; |
| } |
| sub reducedepends { |
| my @list = @_; |
| my @newlist = (); |
| while (@list) { |
| my $item = shift @list; |
| push @newlist, $item |
| unless grep { $item eq $_ } @list; |
| } |
| @newlist; |
| } |
| |
| # dogenerate is responsible for producing all the recipes that build |
| # generated source files. It recurses in case a dependency is also a |
| # generated source file. |
| sub dogenerate { |
| my $src = shift; |
| return "" if $cache{$src}; |
| my $obj = shift; |
| my $bin = shift; |
| my %opts = @_; |
| if ($unified_info{generate}->{$src}) { |
| $OUT .= generatesrc(src => $src, |
| generator => $unified_info{generate}->{$src}, |
| deps => $unified_info{depends}->{$src}, |
| incs => [ @{$unified_info{includes}->{$bin}}, |
| @{$unified_info{includes}->{$obj}} ], |
| %opts); |
| foreach (@{$unified_info{depends}->{$src}}) { |
| dogenerate($_, $obj, $bin, %opts); |
| } |
| } |
| $cache{$src} = 1; |
| } |
| |
| # doobj is responsible for producing all the recipes that build |
| # object files as well as dependency files. |
| sub doobj { |
| my $obj = shift; |
| return "" if $cache{$obj}; |
| (my $obj_no_o = $obj) =~ s|\.o$||; |
| my $bin = shift; |
| my %opts = @_; |
| if (@{$unified_info{sources}->{$obj}}) { |
| $OUT .= src2obj(obj => $obj_no_o, |
| srcs => $unified_info{sources}->{$obj}, |
| deps => $unified_info{depends}->{$obj}, |
| incs => [ @{$unified_info{includes}->{$bin}}, |
| @{$unified_info{includes}->{$obj}} ], |
| %opts); |
| foreach ((@{$unified_info{sources}->{$obj}}, |
| @{$unified_info{depends}->{$obj}})) { |
| dogenerate($_, $obj, $bin, %opts); |
| } |
| } |
| $cache{$obj} = 1; |
| } |
| |
| # dolib is responsible for building libraries. It will call |
| # libobj2shlib is shared libraries are produced, and obj2lib in all |
| # cases. It also makes sure all object files for the library are |
| # built. |
| sub dolib { |
| my $lib = shift; |
| return "" if $cache{$lib}; |
| unless ($disabled{shared}) { |
| my %ordinals = |
| $unified_info{ordinals}->{$lib} |
| ? (ordinals => $unified_info{ordinals}->{$lib}) : (); |
| $OUT .= libobj2shlib(shlib => $unified_info{sharednames}->{$lib}, |
| lib => $lib, |
| objs => [ map { (my $x = $_) =~ s|\.o$||; $x } |
| @{$unified_info{sources}->{$lib}} ], |
| deps => [ reducedepends(resolvedepends($lib)) ], |
| %ordinals); |
| } |
| $OUT .= obj2lib(lib => $lib, |
| objs => [ map { (my $x = $_) =~ s|\.o$||; $x } |
| @{$unified_info{sources}->{$lib}} ]); |
| map { doobj($_, $lib, intent => "lib") } @{$unified_info{sources}->{$lib}}; |
| $cache{$lib} = 1; |
| } |
| |
| # doengine is responsible for building engines. It will call |
| # obj2dso, and also makes sure all object files for the library |
| # are built. |
| sub doengine { |
| my $lib = shift; |
| return "" if $cache{$lib}; |
| $OUT .= obj2dso(lib => $lib, |
| objs => [ map { (my $x = $_) =~ s|\.o$||; $x } |
| @{$unified_info{sources}->{$lib}} ], |
| deps => [ resolvedepends($lib) ]); |
| map { doobj($_, $lib, intent => "dso") } @{$unified_info{sources}->{$lib}}; |
| $cache{$lib} = 1; |
| } |
| |
| # dobin is responsible for building programs. It will call obj2bin, |
| # and also makes sure all object files for the library are built. |
| sub dobin { |
| my $bin = shift; |
| return "" if $cache{$bin}; |
| my $deps = [ reducedepends(resolvedepends($bin)) ]; |
| $OUT .= obj2bin(bin => $bin, |
| objs => [ map { (my $x = $_) =~ s|\.o$||; $x } |
| @{$unified_info{sources}->{$bin}} ], |
| deps => $deps); |
| map { doobj($_, $bin, intent => "bin") } @{$unified_info{sources}->{$bin}}; |
| $cache{$bin} = 1; |
| } |
| |
| # dobin is responsible for building scripts from templates. It will |
| # call in2script. |
| sub doscript { |
| my $script = shift; |
| return "" if $cache{$script}; |
| $OUT .= in2script(script => $script, |
| sources => $unified_info{sources}->{$script}); |
| $cache{$script} = 1; |
| } |
| |
| # Start with populating the cache with all the overrides |
| %cache = map { $_ => 1 } @{$unified_info{overrides}}; |
| |
| # Build all known libraries, engines, programs and scripts. |
| # Everything else will be handled as a consequence. |
| map { dolib($_) } @{$unified_info{libraries}}; |
| map { doengine($_) } @{$unified_info{engines}}; |
| map { dobin($_) } @{$unified_info{programs}}; |
| map { doscript($_) } @{$unified_info{scripts}}; |
| |
| # Finally, should there be any applicable BEGINRAW/ENDRAW sections, |
| # they are added here. |
| $OUT .= $_."\n" foreach(@{$unified_info{rawlines}}); |
| -} |