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