lh | 9ed821d | 2023-04-07 01:36:19 -0700 | [diff] [blame] | 1 | {- # -*- Mode: perl -*- |
| 2 | |
| 3 | use File::Basename; |
| 4 | |
| 5 | # A cache of objects for which a recipe has already been generated |
| 6 | my %cache; |
| 7 | |
| 8 | # resolvedepends and reducedepends work in tandem to make sure |
| 9 | # there are no duplicate dependencies and that they are in the |
| 10 | # right order. This is especially used to sort the list of |
| 11 | # libraries that a build depends on. |
| 12 | sub extensionlesslib { |
| 13 | my @result = map { $_ =~ /(\.a)?$/; $` } @_; |
| 14 | return @result if wantarray; |
| 15 | return $result[0]; |
| 16 | } |
| 17 | sub resolvedepends { |
| 18 | my $thing = shift; |
| 19 | my $extensionlessthing = extensionlesslib($thing); |
| 20 | my @listsofar = @_; # to check if we're looping |
| 21 | my @list = @{$unified_info{depends}->{$thing} // |
| 22 | $unified_info{depends}->{$extensionlessthing}}; |
| 23 | my @newlist = (); |
| 24 | if (scalar @list) { |
| 25 | foreach my $item (@list) { |
| 26 | my $extensionlessitem = extensionlesslib($item); |
| 27 | # It's time to break off when the dependency list starts looping |
| 28 | next if grep { extensionlesslib($_) eq $extensionlessitem } @listsofar; |
| 29 | push @newlist, $item, resolvedepends($item, @listsofar, $item); |
| 30 | } |
| 31 | } |
| 32 | @newlist; |
| 33 | } |
| 34 | sub reducedepends { |
| 35 | my @list = @_; |
| 36 | my @newlist = (); |
| 37 | my %replace = (); |
| 38 | while (@list) { |
| 39 | my $item = shift @list; |
| 40 | my $extensionlessitem = extensionlesslib($item); |
| 41 | if (grep { $extensionlessitem eq extensionlesslib($_) } @list) { |
| 42 | if ($item ne $extensionlessitem) { |
| 43 | # If this instance of the library is explicitly static, we |
| 44 | # prefer that to any shared library name, since it must have |
| 45 | # been done on purpose. |
| 46 | $replace{$extensionlessitem} = $item; |
| 47 | } |
| 48 | } else { |
| 49 | push @newlist, $item; |
| 50 | } |
| 51 | } |
| 52 | map { $replace{$_} // $_; } @newlist; |
| 53 | } |
| 54 | |
| 55 | # is_installed checks if a given file will be installed (i.e. they are |
| 56 | # not defined _NO_INST in build.info) |
| 57 | sub is_installed { |
| 58 | my $product = shift; |
| 59 | if (grep { $product eq $_ } |
| 60 | map { (@{$unified_info{install}->{$_}}) } |
| 61 | keys %{$unified_info{install}}) { |
| 62 | return 1; |
| 63 | } |
| 64 | return 0; |
| 65 | } |
| 66 | |
| 67 | # dogenerate is responsible for producing all the recipes that build |
| 68 | # generated source files. It recurses in case a dependency is also a |
| 69 | # generated source file. |
| 70 | sub dogenerate { |
| 71 | my $src = shift; |
| 72 | return "" if $cache{$src}; |
| 73 | my $obj = shift; |
| 74 | my $bin = shift; |
| 75 | my %opts = @_; |
| 76 | if ($unified_info{generate}->{$src}) { |
| 77 | die "$src is generated by Configure, should not appear in build file\n" |
| 78 | if ref $unified_info{generate}->{$src} eq ""; |
| 79 | my $script = $unified_info{generate}->{$src}->[0]; |
| 80 | $OUT .= generatesrc(src => $src, |
| 81 | generator => $unified_info{generate}->{$src}, |
| 82 | generator_incs => $unified_info{includes}->{$script}, |
| 83 | generator_deps => $unified_info{depends}->{$script}, |
| 84 | deps => $unified_info{depends}->{$src}, |
| 85 | incs => $unified_info{includes}->{$obj}, |
| 86 | %opts); |
| 87 | foreach (@{$unified_info{depends}->{$src}}) { |
| 88 | dogenerate($_, $obj, $bin, %opts); |
| 89 | } |
| 90 | } |
| 91 | $cache{$src} = 1; |
| 92 | } |
| 93 | |
| 94 | # doobj is responsible for producing all the recipes that build |
| 95 | # object files as well as dependency files. |
| 96 | sub doobj { |
| 97 | my $obj = shift; |
| 98 | return "" if $cache{$obj}; |
| 99 | my $bin = shift; |
| 100 | my %opts = @_; |
| 101 | if (@{$unified_info{sources}->{$obj}}) { |
| 102 | $OUT .= src2obj(obj => $obj, |
| 103 | product => $bin, |
| 104 | srcs => $unified_info{sources}->{$obj}, |
| 105 | deps => $unified_info{depends}->{$obj}, |
| 106 | incs => $unified_info{includes}->{$obj}, |
| 107 | %opts); |
| 108 | foreach ((@{$unified_info{sources}->{$obj}}, |
| 109 | @{$unified_info{depends}->{$obj}})) { |
| 110 | dogenerate($_, $obj, $bin, %opts); |
| 111 | } |
| 112 | } |
| 113 | $cache{$obj} = 1; |
| 114 | } |
| 115 | |
| 116 | # dolib is responsible for building libraries. It will call |
| 117 | # libobj2shlib is shared libraries are produced, and obj2lib in all |
| 118 | # cases. It also makes sure all object files for the library are |
| 119 | # built. |
| 120 | sub dolib { |
| 121 | my $lib = shift; |
| 122 | return "" if $cache{$lib}; |
| 123 | unless ($disabled{shared} || $lib =~ /\.a$/) { |
| 124 | $OUT .= libobj2shlib(shlib => $unified_info{sharednames}->{$lib}, |
| 125 | lib => $lib, |
| 126 | objs => [ @{$unified_info{shared_sources}->{$lib}}, |
| 127 | @{$unified_info{sources}->{$lib}} ], |
| 128 | deps => [ reducedepends(resolvedepends($lib)) ], |
| 129 | installed => is_installed($lib)); |
| 130 | foreach ((@{$unified_info{shared_sources}->{$lib}}, |
| 131 | @{$unified_info{sources}->{$lib}})) { |
| 132 | # If this is somehow a compiled object, take care of it that way |
| 133 | # Otherwise, it might simply be generated |
| 134 | if (defined $unified_info{sources}->{$_}) { |
| 135 | doobj($_, $lib, intent => "lib", installed => is_installed($lib)); |
| 136 | } else { |
| 137 | dogenerate($_, undef, undef, intent => "lib"); |
| 138 | } |
| 139 | } |
| 140 | } |
| 141 | $OUT .= obj2lib(lib => $lib, |
| 142 | objs => [ @{$unified_info{sources}->{$lib}} ]); |
| 143 | foreach (@{$unified_info{sources}->{$lib}}) { |
| 144 | doobj($_, $lib, intent => "lib", installed => is_installed($lib)); |
| 145 | } |
| 146 | $cache{$lib} = 1; |
| 147 | } |
| 148 | |
| 149 | # doengine is responsible for building engines. It will call |
| 150 | # obj2dso, and also makes sure all object files for the library |
| 151 | # are built. |
| 152 | sub doengine { |
| 153 | my $lib = shift; |
| 154 | return "" if $cache{$lib}; |
| 155 | $OUT .= obj2dso(lib => $lib, |
| 156 | objs => [ @{$unified_info{sources}->{$lib}}, |
| 157 | @{$unified_info{shared_sources}->{$lib}} ], |
| 158 | deps => [ resolvedepends($lib) ], |
| 159 | installed => is_installed($lib)); |
| 160 | foreach ((@{$unified_info{sources}->{$lib}}, |
| 161 | @{$unified_info{shared_sources}->{$lib}})) { |
| 162 | doobj($_, $lib, intent => "dso", installed => is_installed($lib)); |
| 163 | } |
| 164 | $cache{$lib} = 1; |
| 165 | } |
| 166 | |
| 167 | # dobin is responsible for building programs. It will call obj2bin, |
| 168 | # and also makes sure all object files for the library are built. |
| 169 | sub dobin { |
| 170 | my $bin = shift; |
| 171 | return "" if $cache{$bin}; |
| 172 | my $deps = [ reducedepends(resolvedepends($bin)) ]; |
| 173 | $OUT .= obj2bin(bin => $bin, |
| 174 | objs => [ @{$unified_info{sources}->{$bin}} ], |
| 175 | deps => $deps, |
| 176 | installed => is_installed($bin)); |
| 177 | foreach (@{$unified_info{sources}->{$bin}}) { |
| 178 | doobj($_, $bin, intent => "bin", installed => is_installed($bin)); |
| 179 | } |
| 180 | $cache{$bin} = 1; |
| 181 | } |
| 182 | |
| 183 | # dobin is responsible for building scripts from templates. It will |
| 184 | # call in2script. |
| 185 | sub doscript { |
| 186 | my $script = shift; |
| 187 | return "" if $cache{$script}; |
| 188 | $OUT .= in2script(script => $script, |
| 189 | sources => $unified_info{sources}->{$script}, |
| 190 | installed => is_installed($script)); |
| 191 | $cache{$script} = 1; |
| 192 | } |
| 193 | |
| 194 | sub dodir { |
| 195 | my $dir = shift; |
| 196 | return "" if !exists(&generatedir) or $cache{$dir}; |
| 197 | $OUT .= generatedir(dir => $dir, |
| 198 | deps => $unified_info{dirinfo}->{$dir}->{deps}, |
| 199 | %{$unified_info{dirinfo}->{$_}->{products}}); |
| 200 | $cache{$dir} = 1; |
| 201 | } |
| 202 | |
| 203 | # Start with populating the cache with all the overrides |
| 204 | %cache = map { $_ => 1 } @{$unified_info{overrides}}; |
| 205 | |
| 206 | # Build mandatory generated headers |
| 207 | foreach (@{$unified_info{depends}->{""}}) { dogenerate($_); } |
| 208 | |
| 209 | # Build all known libraries, engines, programs and scripts. |
| 210 | # Everything else will be handled as a consequence. |
| 211 | foreach (@{$unified_info{libraries}}) { dolib($_); } |
| 212 | foreach (@{$unified_info{engines}}) { doengine($_); } |
| 213 | foreach (@{$unified_info{programs}}) { dobin($_); } |
| 214 | foreach (@{$unified_info{scripts}}) { doscript($_); } |
| 215 | |
| 216 | foreach (sort keys %{$unified_info{dirinfo}}) { dodir($_); } |
| 217 | |
| 218 | # Finally, should there be any applicable BEGINRAW/ENDRAW sections, |
| 219 | # they are added here. |
| 220 | $OUT .= $_."\n" foreach @{$unified_info{rawlines}}; |
| 221 | -} |