]>
Commit | Line | Data |
---|---|---|
249b4e28 RL |
1 | #! /usr/bin/env perl |
2 | # Copyright 2018 The OpenSSL Project Authors. All Rights Reserved. | |
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 RL |
25 | my $build_mtime = (stat($buildfile))[9]; |
26 | my $rebuild = 0; | |
249b4e28 | 27 | my $depext = $target{dep_extension} || ".d"; |
c39785d4 | 28 | my @depfiles = |
d35b2c72 | 29 | sort |
c39785d4 RL |
30 | grep { |
31 | # This grep has side effects. Not only does if check the existence | |
32 | # of the dependency file given in $_, but it also checks if it's | |
33 | # newer than the build file, and if it is, sets $rebuild. | |
34 | my @st = stat($_); | |
35 | $rebuild = 1 if @st && $st[9] > $build_mtime; | |
36 | scalar @st > 0; # Determines the grep result | |
37 | } | |
249b4e28 | 38 | map { (my $x = $_) =~ s|\.o$|$depext|; $x; } |
3866b224 RL |
39 | ( ( grep { $unified_info{sources}->{$_}->[0] =~ /\.cc?$/ } |
40 | keys %{$unified_info{sources}} ), | |
41 | ( grep { $unified_info{shared_sources}->{$_}->[0] =~ /\.cc?$/ } | |
42 | keys %{$unified_info{shared_sources}} ) ); | |
249b4e28 | 43 | |
c39785d4 RL |
44 | exit 0 unless $rebuild; |
45 | ||
46 | # Ok, primary checks are done, time to do some real work | |
47 | ||
433e8572 RL |
48 | my $producer = shift @ARGV; |
49 | die "Producer not given\n" unless $producer; | |
50 | ||
8ed5f094 RL |
51 | my $srcdir = $config{sourcedir}; |
52 | my $blddir = $config{builddir}; | |
53 | my $abs_srcdir = rel2abs($srcdir); | |
54 | my $abs_blddir = rel2abs($blddir); | |
c39785d4 | 55 | |
433e8572 RL |
56 | # Convenient cache of absolute to relative map. We start with filling it |
57 | # with mappings for the known generated header files. They are relative to | |
58 | # the current working directory, so that's an easy task. | |
59 | # NOTE: there's more than C header files that are generated. They will also | |
60 | # generate entries in this map. We could of course deal with C header files | |
61 | # only, but in case we decide to handle more than just C files in the future, | |
62 | # we already have the mechanism in place here. | |
63 | # NOTE2: we lower case the index to make it searchable without regard for | |
64 | # character case. That could seem dangerous, but as long as we don't have | |
65 | # files we depend on in the same directory that only differ by character case, | |
66 | # we're fine. | |
67 | my %depconv_cache = | |
d3c72e39 | 68 | map { catfile($abs_blddir, $_) => $_ } |
433e8572 | 69 | keys %{$unified_info{generate}}; |
c39785d4 RL |
70 | |
71 | my %procedures = ( | |
72 | 'gcc' => undef, # gcc style dependency files needs no mods | |
73 | 'makedepend' => | |
74 | sub { | |
75 | # makedepend, in its infinite wisdom, wants to have the object file | |
76 | # in the same directory as the source file. This doesn't work too | |
77 | # well with out-of-source-tree builds, so we must resort to tricks | |
78 | # to get things right. Fortunately, the .d files are always placed | |
79 | # parallel with the object files, so all we need to do is construct | |
80 | # the object file name from the dep file name. | |
81 | (my $objfile = shift) =~ s|\.d$|.o|i; | |
82 | my $line = shift; | |
83 | ||
84 | # Discard comments | |
85 | return undef if $line =~ /^(#.*|\s*)$/; | |
86 | ||
87 | # Remove the original object file | |
88 | $line =~ s|^.*\.o: | |; | |
89 | # Also, remove any dependency that starts with a /, because those | |
90 | # are typically system headers | |
91 | $line =~ s/\s+\/(\\.|\S)*//g; | |
92 | # Finally, discard all empty lines | |
93 | return undef if $line =~ /^\s*$/; | |
94 | ||
95 | # All we got now is a dependency, just shave off surrounding spaces | |
96 | $line =~ s/^\s+//; | |
97 | $line =~ s/\s+$//; | |
98 | return ($objfile, $line); | |
99 | }, | |
100 | 'VMS C' => | |
101 | sub { | |
8ed5f094 RL |
102 | state $abs_srcdir_shaved = undef; |
103 | state $srcdir_shaved = undef; | |
104 | ||
105 | unless (defined $abs_srcdir_shaved) { | |
106 | ($abs_srcdir_shaved = $abs_srcdir) =~ s|[>\]]$||; | |
107 | ($srcdir_shaved = $srcdir) =~ s|[>\]]$||; | |
108 | } | |
109 | ||
c39785d4 RL |
110 | # current versions of DEC / Compaq / HP / VSI C strips away all |
111 | # directory information from the object file, so we must insert it | |
112 | # back. To make life simpler, we simply replace it with the | |
113 | # corresponding .D file that's had its extension changed. Since | |
114 | # .D files are always written parallel to the object files, we | |
115 | # thereby get the directory information for free. | |
116 | (my $objfile = shift) =~ s|\.D$|.OBJ|i; | |
117 | my $line = shift; | |
118 | ||
119 | # Shave off the target. | |
120 | # | |
121 | # The pattern for target and dependencies will always take this | |
122 | # form: | |
123 | # | |
124 | # target SPACE : SPACE deps | |
125 | # | |
126 | # This is so a volume delimiter (a : without any spaces around it) | |
127 | # won't get mixed up with the target / deps delimiter. We use this | |
128 | # to easily identify what needs to be removed. | |
129 | m|\s:\s|; $line = $'; | |
130 | ||
131 | # We know that VMS has system header files in text libraries, | |
132 | # extension .TLB. We also know that our header files aren't stored | |
133 | # in text libraries. Finally, we know that VMS C produces exactly | |
134 | # one dependency per line, so we simply discard any line ending with | |
135 | # .TLB. | |
136 | return undef if /\.TLB\s*$/; | |
137 | ||
138 | # All we got now is a dependency, just shave off surrounding spaces | |
139 | $line =~ s/^\s+//; | |
140 | $line =~ s/\s+$//; | |
8ed5f094 RL |
141 | |
142 | # VMS C gives us absolute paths, always. Let's see if we can | |
143 | # make them relative instead. | |
d3c72e39 | 144 | $line = canonpath($line); |
8ed5f094 RL |
145 | |
146 | unless (defined $depconv_cache{$line}) { | |
147 | my $dep = $line; | |
148 | # Since we have already pre-populated the cache with | |
149 | # mappings for generated headers, we only need to deal | |
150 | # with the source tree. | |
151 | if ($dep =~ s|^\Q$abs_srcdir_shaved\E([\.>\]])?|$srcdir_shaved$1|i) { | |
152 | $depconv_cache{$line} = $dep; | |
153 | } | |
154 | } | |
155 | return ($objfile, $depconv_cache{$line}) | |
156 | if defined $depconv_cache{$line}; | |
157 | print STDERR "DEBUG[VMS C]: ignoring $objfile <- $line\n" | |
158 | if $debug; | |
159 | ||
160 | return undef; | |
c39785d4 RL |
161 | }, |
162 | 'VC' => | |
163 | sub { | |
164 | # For the moment, we only support Visual C on native Windows, or | |
165 | # compatible compilers. With those, the flags /Zs /showIncludes | |
166 | # give us the necessary output to be able to create dependencies | |
167 | # that nmake (or any 'make' implementation) should be able to read, | |
168 | # with a bit of help. The output we're interested in looks like | |
169 | # this (it always starts the same) | |
170 | # | |
171 | # Note: including file: {whatever header file} | |
172 | # | |
173 | # Since there's no object file name at all in that information, | |
174 | # we must construct it ourselves. | |
175 | ||
176 | (my $objfile = shift) =~ s|\.d$|.obj|i; | |
177 | my $line = shift; | |
178 | ||
179 | # There are also other lines mixed in, for example compiler | |
180 | # warnings, so we simply discard anything that doesn't start with | |
181 | # the Note: | |
182 | ||
183 | if (/^Note: including file: */) { | |
184 | (my $tail = $') =~ s/\s*\R$//; | |
185 | ||
186 | # VC gives us absolute paths for all include files, so to | |
187 | # remove system header dependencies, we need to check that | |
433e8572 | 188 | # they don't match $abs_srcdir or $abs_blddir. |
d3c72e39 | 189 | $tail = canonpath($tail); |
433e8572 RL |
190 | |
191 | unless (defined $depconv_cache{$tail}) { | |
192 | my $dep = $tail; | |
193 | # Since we have already pre-populated the cache with | |
194 | # mappings for generated headers, we only need to deal | |
195 | # with the source tree. | |
196 | if ($dep =~ s|^\Q$abs_srcdir\E\\|\$(SRCDIR)\\|i) { | |
197 | $depconv_cache{$tail} = $dep; | |
198 | } | |
c39785d4 | 199 | } |
433e8572 RL |
200 | return ($objfile, '"'.$depconv_cache{$tail}.'"') |
201 | if defined $depconv_cache{$tail}; | |
202 | print STDERR "DEBUG[VC]: ignoring $objfile <- $tail\n" | |
203 | if $debug; | |
c39785d4 RL |
204 | } |
205 | ||
206 | return undef; | |
207 | }, | |
208 | ); | |
209 | my %continuations = ( | |
210 | 'gcc' => undef, | |
211 | 'makedepend' => "\\", | |
212 | 'VMS C' => "-", | |
213 | 'VC' => "\\", | |
214 | ); | |
215 | ||
216 | die "Producer unrecognised: $producer\n" | |
217 | unless exists $procedures{$producer} && exists $continuations{$producer}; | |
218 | ||
219 | my $procedure = $procedures{$producer}; | |
220 | my $continuation = $continuations{$producer}; | |
221 | ||
222 | my $buildfile_new = "$buildfile-$$"; | |
223 | ||
224 | my %collect = (); | |
225 | if (defined $procedure) { | |
226 | foreach my $depfile (@depfiles) { | |
227 | open IDEP,$depfile or die "Trying to read $depfile: $!\n"; | |
228 | while (<IDEP>) { | |
229 | s|\R$||; # The better chomp | |
230 | my ($target, $deps) = $procedure->($depfile, $_); | |
231 | $collect{$target}->{$deps} = 1 if defined $target; | |
232 | } | |
233 | close IDEP; | |
234 | } | |
235 | } | |
236 | ||
249b4e28 RL |
237 | open IBF, $buildfile or die "Trying to read $buildfile: $!\n"; |
238 | open OBF, '>', $buildfile_new or die "Trying to write $buildfile_new: $!\n"; | |
239 | while (<IBF>) { | |
249b4e28 RL |
240 | last if /^# DO NOT DELETE THIS LINE/; |
241 | print OBF or die "$!\n"; | |
249b4e28 RL |
242 | } |
243 | close IBF; | |
244 | ||
245 | print OBF "# DO NOT DELETE THIS LINE -- make depend depends on it.\n"; | |
246 | ||
c39785d4 RL |
247 | if (defined $procedure) { |
248 | foreach my $target (sort keys %collect) { | |
249 | my $prefix = $target . ' :'; | |
250 | my @deps = sort keys %{$collect{$target}}; | |
251 | ||
252 | while (@deps) { | |
253 | my $buf = $prefix; | |
254 | $prefix = ''; | |
255 | ||
256 | while (@deps && ($buf eq '' | |
257 | || length($buf) + length($deps[0]) <= 77)) { | |
258 | $buf .= ' ' . shift @deps; | |
259 | } | |
260 | $buf .= ' '.$continuation if @deps; | |
261 | ||
262 | print OBF $buf,"\n" or die "Trying to print: $!\n" | |
263 | } | |
264 | } | |
265 | } else { | |
266 | foreach my $depfile (@depfiles) { | |
267 | open IDEP,$depfile or die "Trying to read $depfile: $!\n"; | |
268 | while (<IDEP>) { | |
269 | print OBF or die "Trying to print: $!\n"; | |
270 | } | |
271 | close IDEP; | |
249b4e28 | 272 | } |
249b4e28 | 273 | } |
c39785d4 | 274 | |
249b4e28 RL |
275 | close OBF; |
276 | ||
277 | if (compare_text($buildfile_new, $buildfile) != 0) { | |
278 | rename $buildfile_new, $buildfile | |
279 | or die "Trying to rename $buildfile_new -> $buildfile: $!\n"; | |
280 | } | |
c39785d4 RL |
281 | |
282 | END { | |
283 | # On VMS, we want to remove all generations of this file, in case there | |
284 | # are more than one, so we loop. | |
285 | if (defined $buildfile_new) { | |
286 | while (unlink $buildfile_new) {} | |
287 | } | |
288 | } |