]>
Commit | Line | Data |
---|---|---|
ddf1847d RL |
1 | {- # -*- Mode: perl -*- |
2 | ||
0ad1d94d RL |
3 | use File::Basename; |
4 | ||
5 | # A cache of objects for which a recipe has already been generated | |
6 | my %cache; | |
ddf1847d RL |
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. | |
186a31e5 RL |
12 | sub extensionlesslib { |
13 | my @result = map { $_ =~ /(\.a)?$/; $` } @_; | |
14 | return @result if wantarray; | |
15 | return $result[0]; | |
16 | } | |
ddf1847d RL |
17 | sub resolvedepends { |
18 | my $thing = shift; | |
186a31e5 | 19 | my $extensionlessthing = extensionlesslib($thing); |
ddf1847d | 20 | my @listsofar = @_; # to check if we're looping |
33105818 RL |
21 | my @list = @{$unified_info{depends}->{$thing} // |
22 | $unified_info{depends}->{$extensionlessthing}}; | |
ddf1847d RL |
23 | my @newlist = (); |
24 | if (scalar @list) { | |
25 | foreach my $item (@list) { | |
186a31e5 | 26 | my $extensionlessitem = extensionlesslib($item); |
ddf1847d | 27 | # It's time to break off when the dependency list starts looping |
186a31e5 | 28 | next if grep { extensionlesslib($_) eq $extensionlessitem } @listsofar; |
ddf1847d RL |
29 | push @newlist, $item, resolvedepends($item, @listsofar, $item); |
30 | } | |
31 | } | |
32 | @newlist; | |
33 | } | |
34 | sub reducedepends { | |
35 | my @list = @_; | |
36 | my @newlist = (); | |
33105818 | 37 | my %replace = (); |
ddf1847d RL |
38 | while (@list) { |
39 | my $item = shift @list; | |
186a31e5 | 40 | my $extensionlessitem = extensionlesslib($item); |
33105818 RL |
41 | if (grep { $extensionlessitem eq extensionlesslib($_) } @list) { |
42 | if ($item ne $extensionlessitem) { | |
43 | # If this instance of the library is explicitely 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 | } | |
ddf1847d | 51 | } |
33105818 | 52 | map { $replace{$_} // $_; } @newlist; |
ddf1847d RL |
53 | } |
54 | ||
84f38675 RL |
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 | ||
d4605727 RL |
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. | |
ae4c7450 RL |
70 | sub dogenerate { |
71 | my $src = shift; | |
72 | return "" if $cache{$src}; | |
d4605727 RL |
73 | my $obj = shift; |
74 | my $bin = shift; | |
ae4c7450 RL |
75 | my %opts = @_; |
76 | if ($unified_info{generate}->{$src}) { | |
05a7aee0 RL |
77 | die "$src is generated by Configure, should not appear in build file\n" |
78 | if ref $unified_info{generate}->{$src} eq ""; | |
8d34daf0 | 79 | my $script = $unified_info{generate}->{$src}->[0]; |
ae4c7450 RL |
80 | $OUT .= generatesrc(src => $src, |
81 | generator => $unified_info{generate}->{$src}, | |
8d34daf0 RL |
82 | generator_incs => $unified_info{includes}->{$script}, |
83 | generator_deps => $unified_info{depends}->{$script}, | |
ae4c7450 | 84 | deps => $unified_info{depends}->{$src}, |
d4605727 RL |
85 | incs => [ @{$unified_info{includes}->{$bin}}, |
86 | @{$unified_info{includes}->{$obj}} ], | |
ae4c7450 RL |
87 | %opts); |
88 | foreach (@{$unified_info{depends}->{$src}}) { | |
d4605727 | 89 | dogenerate($_, $obj, $bin, %opts); |
ae4c7450 RL |
90 | } |
91 | } | |
92 | $cache{$src} = 1; | |
93 | } | |
94 | ||
ddf1847d RL |
95 | # doobj is responsible for producing all the recipes that build |
96 | # object files as well as dependency files. | |
97 | sub doobj { | |
98 | my $obj = shift; | |
b23238f9 | 99 | return "" if $cache{$obj}; |
ddf1847d RL |
100 | (my $obj_no_o = $obj) =~ s|\.o$||; |
101 | my $bin = shift; | |
45502bfe | 102 | my %opts = @_; |
ddf1847d RL |
103 | if (@{$unified_info{sources}->{$obj}}) { |
104 | $OUT .= src2obj(obj => $obj_no_o, | |
84f38675 | 105 | product => $bin, |
ddf1847d | 106 | srcs => $unified_info{sources}->{$obj}, |
ae4c7450 | 107 | deps => $unified_info{depends}->{$obj}, |
ddf1847d | 108 | incs => [ @{$unified_info{includes}->{$bin}}, |
45502bfe RL |
109 | @{$unified_info{includes}->{$obj}} ], |
110 | %opts); | |
ae4c7450 RL |
111 | foreach ((@{$unified_info{sources}->{$obj}}, |
112 | @{$unified_info{depends}->{$obj}})) { | |
d4605727 | 113 | dogenerate($_, $obj, $bin, %opts); |
ae4c7450 | 114 | } |
ddf1847d | 115 | } |
b23238f9 | 116 | $cache{$obj} = 1; |
ddf1847d RL |
117 | } |
118 | ||
119 | # dolib is responsible for building libraries. It will call | |
120 | # libobj2shlib is shared libraries are produced, and obj2lib in all | |
121 | # cases. It also makes sure all object files for the library are | |
122 | # built. | |
123 | sub dolib { | |
124 | my $lib = shift; | |
b23238f9 | 125 | return "" if $cache{$lib}; |
33105818 | 126 | unless ($disabled{shared} || $lib =~ /\.a$/) { |
ddf1847d RL |
127 | my %ordinals = |
128 | $unified_info{ordinals}->{$lib} | |
129 | ? (ordinals => $unified_info{ordinals}->{$lib}) : (); | |
130 | $OUT .= libobj2shlib(shlib => $unified_info{sharednames}->{$lib}, | |
131 | lib => $lib, | |
132 | objs => [ map { (my $x = $_) =~ s|\.o$||; $x } | |
2a08d1a0 RL |
133 | (@{$unified_info{sources}->{$lib}}, |
134 | @{$unified_info{shared_sources}->{$lib}}) ], | |
ddf1847d | 135 | deps => [ reducedepends(resolvedepends($lib)) ], |
84f38675 | 136 | installed => is_installed($lib), |
ddf1847d | 137 | %ordinals); |
2110febb | 138 | foreach (@{$unified_info{shared_sources}->{$lib}}) { |
84f38675 | 139 | doobj($_, $lib, intent => "lib", installed => is_installed($lib)); |
2110febb | 140 | } |
ddf1847d RL |
141 | } |
142 | $OUT .= obj2lib(lib => $lib, | |
143 | objs => [ map { (my $x = $_) =~ s|\.o$||; $x } | |
144 | @{$unified_info{sources}->{$lib}} ]); | |
2110febb | 145 | foreach (@{$unified_info{sources}->{$lib}}) { |
19eaee74 | 146 | doobj($_, $lib, intent => "lib", installed => is_installed($lib)); |
2110febb | 147 | } |
b23238f9 | 148 | $cache{$lib} = 1; |
ddf1847d RL |
149 | } |
150 | ||
151 | # doengine is responsible for building engines. It will call | |
5386287c | 152 | # obj2dso, and also makes sure all object files for the library |
ddf1847d RL |
153 | # are built. |
154 | sub doengine { | |
155 | my $lib = shift; | |
b23238f9 | 156 | return "" if $cache{$lib}; |
5386287c RL |
157 | $OUT .= obj2dso(lib => $lib, |
158 | objs => [ map { (my $x = $_) =~ s|\.o$||; $x } | |
2a08d1a0 RL |
159 | (@{$unified_info{sources}->{$lib}}, |
160 | @{$unified_info{shared_sources}->{$lib}}) ], | |
84f38675 RL |
161 | deps => [ resolvedepends($lib) ], |
162 | installed => is_installed($lib)); | |
2110febb RL |
163 | foreach ((@{$unified_info{sources}->{$lib}}, |
164 | @{$unified_info{shared_sources}->{$lib}})) { | |
84f38675 | 165 | doobj($_, $lib, intent => "dso", installed => is_installed($lib)); |
2110febb | 166 | } |
b23238f9 | 167 | $cache{$lib} = 1; |
ddf1847d RL |
168 | } |
169 | ||
170 | # dobin is responsible for building programs. It will call obj2bin, | |
171 | # and also makes sure all object files for the library are built. | |
172 | sub dobin { | |
173 | my $bin = shift; | |
b23238f9 | 174 | return "" if $cache{$bin}; |
ddf1847d RL |
175 | my $deps = [ reducedepends(resolvedepends($bin)) ]; |
176 | $OUT .= obj2bin(bin => $bin, | |
177 | objs => [ map { (my $x = $_) =~ s|\.o$||; $x } | |
178 | @{$unified_info{sources}->{$bin}} ], | |
84f38675 RL |
179 | deps => $deps, |
180 | installed => is_installed($bin)); | |
2110febb | 181 | foreach (@{$unified_info{sources}->{$bin}}) { |
84f38675 | 182 | doobj($_, $bin, intent => "bin", installed => is_installed($bin)); |
2110febb | 183 | } |
b23238f9 | 184 | $cache{$bin} = 1; |
ddf1847d RL |
185 | } |
186 | ||
187 | # dobin is responsible for building scripts from templates. It will | |
188 | # call in2script. | |
189 | sub doscript { | |
190 | my $script = shift; | |
b23238f9 | 191 | return "" if $cache{$script}; |
ddf1847d | 192 | $OUT .= in2script(script => $script, |
84f38675 RL |
193 | sources => $unified_info{sources}->{$script}, |
194 | installed => is_installed($script)); | |
b23238f9 | 195 | $cache{$script} = 1; |
ddf1847d RL |
196 | } |
197 | ||
0ad1d94d RL |
198 | sub dodir { |
199 | my $dir = shift; | |
200 | return "" if !exists(&generatedir) or $cache{$dir}; | |
201 | $OUT .= generatedir(dir => $dir, | |
202 | deps => $unified_info{dirinfo}->{$dir}->{deps}, | |
203 | %{$unified_info{dirinfo}->{$_}->{products}}); | |
204 | $cache{$dir} = 1; | |
205 | } | |
206 | ||
8a67946e RL |
207 | # Start with populating the cache with all the overrides |
208 | %cache = map { $_ => 1 } @{$unified_info{overrides}}; | |
209 | ||
0ad1d94d RL |
210 | # For convenience collect information regarding directories where |
211 | # files are generated, those generated files and the end product | |
212 | # they end up in where applicable. Then, add build rules for those | |
213 | # directories | |
214 | if (exists &generatedir) { | |
215 | my %loopinfo = ( "dso" => [ @{$unified_info{engines}} ], | |
216 | "lib" => [ @{$unified_info{libraries}} ], | |
217 | "bin" => [ @{$unified_info{programs}} ], | |
218 | "script" => [ @{$unified_info{scripts}} ] ); | |
219 | foreach my $type (keys %loopinfo) { | |
220 | foreach my $product (@{$loopinfo{$type}}) { | |
221 | my %dirs = (); | |
222 | my $pd = dirname($product); | |
ec772a81 RL |
223 | |
224 | # We already have a "test" target, and the current directory | |
225 | # is just silly to make a target for | |
226 | $dirs{$pd} = 1 unless $pd eq "test" || $pd eq "."; | |
227 | ||
0ad1d94d RL |
228 | foreach (@{$unified_info{sources}->{$product}}) { |
229 | my $d = dirname($_); | |
ec772a81 RL |
230 | |
231 | # We don't want to create targets for source directories | |
232 | # when building out of source | |
233 | next if ($config{sourcedir} ne $config{builddir} | |
234 | && $d =~ m|^\Q$config{sourcedir}\E|); | |
235 | # We already have a "test" target, and the current directory | |
236 | # is just silly to make a target for | |
237 | next if $d eq "test" || $d eq "."; | |
238 | ||
0ad1d94d RL |
239 | $dirs{$d} = 1; |
240 | push @{$unified_info{dirinfo}->{$d}->{deps}}, $_ | |
241 | if $d ne $pd; | |
242 | } | |
243 | foreach (keys %dirs) { | |
244 | push @{$unified_info{dirinfo}->{$_}->{products}->{$type}}, | |
245 | $product; | |
246 | } | |
247 | } | |
248 | } | |
249 | } | |
250 | ||
4f858293 RL |
251 | # Build mandatory generated headers |
252 | foreach (@{$unified_info{depends}->{""}}) { dogenerate($_); } | |
253 | ||
ddf1847d RL |
254 | # Build all known libraries, engines, programs and scripts. |
255 | # Everything else will be handled as a consequence. | |
f246f90e RL |
256 | foreach (@{$unified_info{libraries}}) { dolib($_); } |
257 | foreach (@{$unified_info{engines}}) { doengine($_); } | |
258 | foreach (@{$unified_info{programs}}) { dobin($_); } | |
259 | foreach (@{$unified_info{scripts}}) { doscript($_); } | |
ddf1847d | 260 | |
0ad1d94d RL |
261 | foreach (sort keys %{$unified_info{dirinfo}}) { dodir($_); } |
262 | ||
ddf1847d RL |
263 | # Finally, should there be any applicable BEGINRAW/ENDRAW sections, |
264 | # they are added here. | |
2110febb | 265 | $OUT .= $_."\n" foreach @{$unified_info{rawlines}}; |
ddf1847d | 266 | -} |