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