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-} 222