]>
Commit | Line | Data |
---|---|---|
249b4e28 | 1 | #! /usr/bin/env perl |
fecb3aae | 2 | # Copyright 2018-2022 The OpenSSL Project Authors. All Rights Reserved. |
249b4e28 | 3 | # |
9059ab42 | 4 | # Licensed under the Apache License 2.0 (the "License"). You may not use |
249b4e28 RL |
5 | # this file except in compliance with the License. You can obtain a copy |
6 | # in the file LICENSE in the source distribution or at | |
7 | # https://www.openssl.org/source/license.html | |
8 | ||
c39785d4 RL |
9 | use strict; |
10 | use warnings; | |
11 | ||
249b4e28 RL |
12 | use lib '.'; |
13 | use configdata; | |
14 | ||
433e8572 | 15 | use File::Spec::Functions qw(:DEFAULT rel2abs); |
249b4e28 | 16 | use File::Compare qw(compare_text); |
8ed5f094 | 17 | use feature 'state'; |
249b4e28 | 18 | |
c39785d4 RL |
19 | # When using stat() on Windows, we can get it to perform better by avoid some |
20 | # data. This doesn't affect the mtime field, so we're not losing anything... | |
21 | ${^WIN32_SLOPPY_STAT} = 1; | |
22 | ||
17928cf9 | 23 | my $debug = $ENV{ADD_DEPENDS_DEBUG}; |
249b4e28 | 24 | my $buildfile = $config{build_file}; |
c39785d4 | 25 | my $build_mtime = (stat($buildfile))[9]; |
023cb594 | 26 | my $configdata_mtime = (stat('configdata.pm'))[9]; |
c39785d4 | 27 | my $rebuild = 0; |
249b4e28 | 28 | my $depext = $target{dep_extension} || ".d"; |
c39785d4 | 29 | my @depfiles = |
d35b2c72 | 30 | sort |
c39785d4 RL |
31 | grep { |
32 | # This grep has side effects. Not only does if check the existence | |
33 | # of the dependency file given in $_, but it also checks if it's | |
023cb594 RL |
34 | # newer than the build file or older than configdata.pm, and if it |
35 | # is, sets $rebuild. | |
c39785d4 | 36 | my @st = stat($_); |
023cb594 RL |
37 | $rebuild = 1 |
38 | if @st && ($st[9] > $build_mtime || $st[9] < $configdata_mtime); | |
c39785d4 RL |
39 | scalar @st > 0; # Determines the grep result |
40 | } | |
249b4e28 | 41 | map { (my $x = $_) =~ s|\.o$|$depext|; $x; } |
3866b224 RL |
42 | ( ( grep { $unified_info{sources}->{$_}->[0] =~ /\.cc?$/ } |
43 | keys %{$unified_info{sources}} ), | |
44 | ( grep { $unified_info{shared_sources}->{$_}->[0] =~ /\.cc?$/ } | |
45 | keys %{$unified_info{shared_sources}} ) ); | |
249b4e28 | 46 | |
c39785d4 RL |
47 | exit 0 unless $rebuild; |
48 | ||
49 | # Ok, primary checks are done, time to do some real work | |
50 | ||
433e8572 RL |
51 | my $producer = shift @ARGV; |
52 | die "Producer not given\n" unless $producer; | |
53 | ||
8ed5f094 RL |
54 | my $srcdir = $config{sourcedir}; |
55 | my $blddir = $config{builddir}; | |
56 | my $abs_srcdir = rel2abs($srcdir); | |
57 | my $abs_blddir = rel2abs($blddir); | |
c39785d4 | 58 | |
433e8572 RL |
59 | # Convenient cache of absolute to relative map. We start with filling it |
60 | # with mappings for the known generated header files. They are relative to | |
61 | # the current working directory, so that's an easy task. | |
62 | # NOTE: there's more than C header files that are generated. They will also | |
63 | # generate entries in this map. We could of course deal with C header files | |
64 | # only, but in case we decide to handle more than just C files in the future, | |
65 | # we already have the mechanism in place here. | |
66 | # NOTE2: we lower case the index to make it searchable without regard for | |
67 | # character case. That could seem dangerous, but as long as we don't have | |
68 | # files we depend on in the same directory that only differ by character case, | |
69 | # we're fine. | |
70 | my %depconv_cache = | |
d3c72e39 | 71 | map { catfile($abs_blddir, $_) => $_ } |
433e8572 | 72 | keys %{$unified_info{generate}}; |
c39785d4 RL |
73 | |
74 | my %procedures = ( | |
3bb2046a RL |
75 | 'gcc' => |
76 | sub { | |
77 | (my $objfile = shift) =~ s|\.d$|.o|i; | |
78 | my $line = shift; | |
79 | ||
80 | # Remove the original object file | |
81 | $line =~ s|^.*\.o: | |; | |
82 | # All we got now is a dependency, shave off surrounding spaces | |
83 | $line =~ s/^\s+//; | |
84 | $line =~ s/\s+$//; | |
85 | # Also, shave off any continuation | |
86 | $line =~ s/\s*\\$//; | |
87 | ||
88 | # Split the line into individual header files, and keep those | |
89 | # that exist in some form | |
90 | my @headers; | |
91 | for (split(/\s+/, $line)) { | |
92 | my $x = rel2abs($_); | |
93 | ||
94 | if (!$depconv_cache{$x}) { | |
95 | if (-f $x) { | |
96 | $depconv_cache{$x} = $_; | |
97 | } | |
98 | } | |
99 | ||
100 | if ($depconv_cache{$x}) { | |
101 | push @headers, $_; | |
102 | } else { | |
103 | print STDERR "DEBUG[$producer]: ignoring $objfile <- $line\n" | |
104 | if $debug; | |
105 | } | |
106 | } | |
107 | return ($objfile, join(' ', @headers)) if @headers; | |
108 | return undef; | |
109 | }, | |
c39785d4 RL |
110 | 'makedepend' => |
111 | sub { | |
112 | # makedepend, in its infinite wisdom, wants to have the object file | |
113 | # in the same directory as the source file. This doesn't work too | |
114 | # well with out-of-source-tree builds, so we must resort to tricks | |
115 | # to get things right. Fortunately, the .d files are always placed | |
116 | # parallel with the object files, so all we need to do is construct | |
117 | # the object file name from the dep file name. | |
118 | (my $objfile = shift) =~ s|\.d$|.o|i; | |
119 | my $line = shift; | |
120 | ||
121 | # Discard comments | |
122 | return undef if $line =~ /^(#.*|\s*)$/; | |
123 | ||
124 | # Remove the original object file | |
125 | $line =~ s|^.*\.o: | |; | |
126 | # Also, remove any dependency that starts with a /, because those | |
127 | # are typically system headers | |
128 | $line =~ s/\s+\/(\\.|\S)*//g; | |
129 | # Finally, discard all empty lines | |
130 | return undef if $line =~ /^\s*$/; | |
131 | ||
132 | # All we got now is a dependency, just shave off surrounding spaces | |
133 | $line =~ s/^\s+//; | |
134 | $line =~ s/\s+$//; | |
135 | return ($objfile, $line); | |
136 | }, | |
137 | 'VMS C' => | |
138 | sub { | |
8ed5f094 RL |
139 | state $abs_srcdir_shaved = undef; |
140 | state $srcdir_shaved = undef; | |
141 | ||
142 | unless (defined $abs_srcdir_shaved) { | |
143 | ($abs_srcdir_shaved = $abs_srcdir) =~ s|[>\]]$||; | |
144 | ($srcdir_shaved = $srcdir) =~ s|[>\]]$||; | |
145 | } | |
146 | ||
c39785d4 RL |
147 | # current versions of DEC / Compaq / HP / VSI C strips away all |
148 | # directory information from the object file, so we must insert it | |
149 | # back. To make life simpler, we simply replace it with the | |
150 | # corresponding .D file that's had its extension changed. Since | |
151 | # .D files are always written parallel to the object files, we | |
152 | # thereby get the directory information for free. | |
153 | (my $objfile = shift) =~ s|\.D$|.OBJ|i; | |
154 | my $line = shift; | |
155 | ||
156 | # Shave off the target. | |
157 | # | |
158 | # The pattern for target and dependencies will always take this | |
159 | # form: | |
160 | # | |
161 | # target SPACE : SPACE deps | |
162 | # | |
163 | # This is so a volume delimiter (a : without any spaces around it) | |
164 | # won't get mixed up with the target / deps delimiter. We use this | |
165 | # to easily identify what needs to be removed. | |
166 | m|\s:\s|; $line = $'; | |
167 | ||
168 | # We know that VMS has system header files in text libraries, | |
169 | # extension .TLB. We also know that our header files aren't stored | |
170 | # in text libraries. Finally, we know that VMS C produces exactly | |
171 | # one dependency per line, so we simply discard any line ending with | |
172 | # .TLB. | |
173 | return undef if /\.TLB\s*$/; | |
174 | ||
175 | # All we got now is a dependency, just shave off surrounding spaces | |
176 | $line =~ s/^\s+//; | |
177 | $line =~ s/\s+$//; | |
8ed5f094 RL |
178 | |
179 | # VMS C gives us absolute paths, always. Let's see if we can | |
180 | # make them relative instead. | |
d3c72e39 | 181 | $line = canonpath($line); |
8ed5f094 RL |
182 | |
183 | unless (defined $depconv_cache{$line}) { | |
184 | my $dep = $line; | |
185 | # Since we have already pre-populated the cache with | |
186 | # mappings for generated headers, we only need to deal | |
187 | # with the source tree. | |
188 | if ($dep =~ s|^\Q$abs_srcdir_shaved\E([\.>\]])?|$srcdir_shaved$1|i) { | |
3bb2046a RL |
189 | # Also check that the header actually exists |
190 | if (-f $line) { | |
191 | $depconv_cache{$line} = $dep; | |
192 | } | |
8ed5f094 RL |
193 | } |
194 | } | |
195 | return ($objfile, $depconv_cache{$line}) | |
196 | if defined $depconv_cache{$line}; | |
2e535eb5 | 197 | print STDERR "DEBUG[$producer]: ignoring $objfile <- $line\n" |
8ed5f094 RL |
198 | if $debug; |
199 | ||
200 | return undef; | |
c39785d4 RL |
201 | }, |
202 | 'VC' => | |
203 | sub { | |
2e535eb5 RL |
204 | # With Microsoft Visual C the flags /Zs /showIncludes give us the |
205 | # necessary output to be able to create dependencies that nmake | |
206 | # (or any 'make' implementation) should be able to read, with a | |
207 | # bit of help. The output we're interested in looks something | |
208 | # like this (it always starts the same) | |
c39785d4 RL |
209 | # |
210 | # Note: including file: {whatever header file} | |
211 | # | |
3babc1e4 RL |
212 | # This output is localized, so for example, the German pack gives |
213 | # us this: | |
214 | # | |
215 | # Hinweis: Einlesen der Datei: {whatever header file} | |
216 | # | |
e304aa87 | 217 | # To accommodate, we need to use a very general regular expression |
3babc1e4 RL |
218 | # to parse those lines. |
219 | # | |
2e535eb5 RL |
220 | # Since there's no object file name at all in that information, |
221 | # we must construct it ourselves. | |
222 | ||
223 | (my $objfile = shift) =~ s|\.d$|.obj|i; | |
224 | my $line = shift; | |
225 | ||
226 | # There are also other lines mixed in, for example compiler | |
227 | # warnings, so we simply discard anything that doesn't start with | |
228 | # the Note: | |
229 | ||
3babc1e4 | 230 | if (/^[^:]*: [^:]*: */) { |
2e535eb5 RL |
231 | (my $tail = $') =~ s/\s*\R$//; |
232 | ||
233 | # VC gives us absolute paths for all include files, so to | |
234 | # remove system header dependencies, we need to check that | |
235 | # they don't match $abs_srcdir or $abs_blddir. | |
236 | $tail = canonpath($tail); | |
237 | ||
238 | unless (defined $depconv_cache{$tail}) { | |
239 | my $dep = $tail; | |
240 | # Since we have already pre-populated the cache with | |
241 | # mappings for generated headers, we only need to deal | |
242 | # with the source tree. | |
243 | if ($dep =~ s|^\Q$abs_srcdir\E\\|\$(SRCDIR)\\|i) { | |
3bb2046a RL |
244 | # Also check that the header actually exists |
245 | if (-f $line) { | |
246 | $depconv_cache{$tail} = $dep; | |
247 | } | |
2e535eb5 RL |
248 | } |
249 | } | |
250 | return ($objfile, '"'.$depconv_cache{$tail}.'"') | |
251 | if defined $depconv_cache{$tail}; | |
252 | print STDERR "DEBUG[$producer]: ignoring $objfile <- $tail\n" | |
253 | if $debug; | |
254 | } | |
255 | ||
256 | return undef; | |
257 | }, | |
258 | 'embarcadero' => | |
259 | sub { | |
3babc1e4 RL |
260 | # With Embarcadero C++Builder's preprocessor (cpp32.exe) the -Sx -Hp |
261 | # flags give us the list of #include files read, like the following: | |
16f2a444 | 262 | # |
3babc1e4 | 263 | # Including ->->{whatever header file} |
16f2a444 TI |
264 | # |
265 | # where each "->" indicates the nesting level of the #include. The | |
2e535eb5 | 266 | # logic here is otherwise the same as the 'VC' scheme. |
16f2a444 | 267 | # |
c39785d4 RL |
268 | # Since there's no object file name at all in that information, |
269 | # we must construct it ourselves. | |
270 | ||
271 | (my $objfile = shift) =~ s|\.d$|.obj|i; | |
272 | my $line = shift; | |
273 | ||
274 | # There are also other lines mixed in, for example compiler | |
275 | # warnings, so we simply discard anything that doesn't start with | |
276 | # the Note: | |
277 | ||
2e535eb5 | 278 | if (/^Including (->)*/) { |
c39785d4 RL |
279 | (my $tail = $') =~ s/\s*\R$//; |
280 | ||
2e535eb5 RL |
281 | # C++Builder gives us relative paths when possible, so to |
282 | # remove system header dependencies, we convert them to | |
283 | # absolute paths and check that they don't match $abs_srcdir | |
284 | # or $abs_blddir, just as the 'VC' scheme. | |
16f2a444 | 285 | $tail = rel2abs($tail); |
433e8572 RL |
286 | |
287 | unless (defined $depconv_cache{$tail}) { | |
288 | my $dep = $tail; | |
289 | # Since we have already pre-populated the cache with | |
290 | # mappings for generated headers, we only need to deal | |
291 | # with the source tree. | |
292 | if ($dep =~ s|^\Q$abs_srcdir\E\\|\$(SRCDIR)\\|i) { | |
3bb2046a RL |
293 | # Also check that the header actually exists |
294 | if (-f $line) { | |
295 | $depconv_cache{$tail} = $dep; | |
296 | } | |
433e8572 | 297 | } |
c39785d4 | 298 | } |
433e8572 RL |
299 | return ($objfile, '"'.$depconv_cache{$tail}.'"') |
300 | if defined $depconv_cache{$tail}; | |
2e535eb5 | 301 | print STDERR "DEBUG[$producer]: ignoring $objfile <- $tail\n" |
433e8572 | 302 | if $debug; |
c39785d4 RL |
303 | } |
304 | ||
305 | return undef; | |
306 | }, | |
307 | ); | |
308 | my %continuations = ( | |
3bb2046a | 309 | 'gcc' => "\\", |
c39785d4 RL |
310 | 'makedepend' => "\\", |
311 | 'VMS C' => "-", | |
312 | 'VC' => "\\", | |
2e535eb5 | 313 | 'embarcadero' => "\\", |
c39785d4 RL |
314 | ); |
315 | ||
316 | die "Producer unrecognised: $producer\n" | |
317 | unless exists $procedures{$producer} && exists $continuations{$producer}; | |
318 | ||
319 | my $procedure = $procedures{$producer}; | |
320 | my $continuation = $continuations{$producer}; | |
321 | ||
322 | my $buildfile_new = "$buildfile-$$"; | |
323 | ||
324 | my %collect = (); | |
3bb2046a RL |
325 | foreach my $depfile (@depfiles) { |
326 | open IDEP,$depfile or die "Trying to read $depfile: $!\n"; | |
327 | while (<IDEP>) { | |
328 | s|\R$||; # The better chomp | |
329 | my ($target, $deps) = $procedure->($depfile, $_); | |
330 | $collect{$target}->{$deps} = 1 if defined $target; | |
c39785d4 | 331 | } |
3bb2046a | 332 | close IDEP; |
c39785d4 RL |
333 | } |
334 | ||
249b4e28 RL |
335 | open IBF, $buildfile or die "Trying to read $buildfile: $!\n"; |
336 | open OBF, '>', $buildfile_new or die "Trying to write $buildfile_new: $!\n"; | |
337 | while (<IBF>) { | |
249b4e28 RL |
338 | last if /^# DO NOT DELETE THIS LINE/; |
339 | print OBF or die "$!\n"; | |
249b4e28 RL |
340 | } |
341 | close IBF; | |
342 | ||
343 | print OBF "# DO NOT DELETE THIS LINE -- make depend depends on it.\n"; | |
344 | ||
3bb2046a RL |
345 | foreach my $target (sort keys %collect) { |
346 | my $prefix = $target . ' :'; | |
347 | my @deps = sort keys %{$collect{$target}}; | |
c39785d4 | 348 | |
3bb2046a RL |
349 | while (@deps) { |
350 | my $buf = $prefix; | |
351 | $prefix = ''; | |
c39785d4 | 352 | |
3bb2046a RL |
353 | while (@deps && ($buf eq '' |
354 | || length($buf) + length($deps[0]) <= 77)) { | |
355 | $buf .= ' ' . shift @deps; | |
c39785d4 | 356 | } |
3bb2046a RL |
357 | $buf .= ' '.$continuation if @deps; |
358 | ||
359 | print OBF $buf,"\n" or die "Trying to print: $!\n" | |
249b4e28 | 360 | } |
249b4e28 | 361 | } |
c39785d4 | 362 | |
249b4e28 RL |
363 | close OBF; |
364 | ||
365 | if (compare_text($buildfile_new, $buildfile) != 0) { | |
366 | rename $buildfile_new, $buildfile | |
367 | or die "Trying to rename $buildfile_new -> $buildfile: $!\n"; | |
368 | } | |
c39785d4 RL |
369 | |
370 | END { | |
371 | # On VMS, we want to remove all generations of this file, in case there | |
372 | # are more than one, so we loop. | |
373 | if (defined $buildfile_new) { | |
374 | while (unlink $buildfile_new) {} | |
375 | } | |
376 | } |