Streamline dependency generation
[openssl.git] / util / postprocess-makedepend.pl
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
9 use strict;
10 use warnings;
11
12 my $producer = shift @ARGV;
13
14 die "Producer not given\n" unless $producer;
15
16 my $procedure = {
17     'makedepend' =>
18         sub {
19             my $line = shift;
20
21             # makedepend, in its infinite wisdom, wants to have the object file
22             # in the same directory as the source file.  This doesn't work too
23             # well with out-of-source-tree builds, so we must resort to tricks
24             # to get things right.  The trick is to call makedepend with an
25             # extra suffix that contains the desired object file path, like
26             # this:
27             #
28             #   makedepend -f- -o"|dir/foo.o" -- $(CFLAGS) -- ../some/foo.c
29             #
30             # The result will look something like this:
31             #
32             #   ../somewhere/foo|dir/foo.o: deps...
33             #
34             # Which is easy to massage by removing everything up to the first |
35
36             # Remove everything up to the first |
37             $line =~ s/^.*\|//;
38             # Also, remove any dependency that starts with a /, because those
39             # are typically system headers
40             $line =~ s/\s+\/(\\.|\S)*//g;
41             # Finally, discard all empty lines or comment lines
42             return undef if $line =~ /:\s*$/ || $line =~ /^(#.*|\s*)$/;
43
44             $line.="\n" unless $line =~ /\R$/g;
45
46             return $line;
47         },
48     'VMS C' =>
49         sub {
50             my $line = shift;
51
52             # current versions of DEC / Compaq / HP / VSI C strips away all
53             # directory information from the object file, so we must insert it
54             # back. Just to be safe against future changes, we check that there
55             # really is no directory information.
56             my $directory = shift;
57
58             # The pattern for target and dependencies will always take this
59             # form:
60             #
61             #   target SPACE : SPACE deps
62             #
63             # This is so a volume delimiter (a : without any spaces around it)
64             # won't get mixed up with the target / deps delimiter.  We use this
65             # fact in the regexp below to make sure we do look at the target.
66             $line =~ s/^/$directory/ unless /^\S+[:>\]]\S+\s+:/;
67
68             # We know that VMS has system header files in text libraries,
69             # extension .TLB.  We also know that our header files aren't stored
70             # in text libraries.  Finally, we know that VMS C produces exactly
71             # one dependency per line, so we simply discard any line ending with
72             # .TLB.
73             return undef if /\.TLB\s*$/;
74
75             return $line;
76         },
77     'VC' =>
78         sub {
79             my $line = shift;
80             my $object = shift;
81
82             # For the moment, we only support Visual C on native Windows, or
83             # compatible compilers.  With those, the flags /Zs /showIncludes
84             # give us the necessary output to be able to create dependencies
85             # that nmake (or any 'make' implementation) should be able to read,
86             # with a bit of help.  The output we're interested in looks like
87             # this (it always starts the same)
88             #
89             #   Note: including file: {whatever header file}
90             #
91             # So all we really have to do is to is to replace the start of the
92             # line with an object file specification, given to us as an extra
93             # argument (passed from $ARGV[1]);
94             #
95             # There are also other lines mixed in, for example compiler
96             # warnings, so we simply discard anything that doesn't start with
97             # the Note:
98
99             if (/^Note: including file: */) {
100                 (my $tail = $') =~ s/\s*\R$//;
101                 return "${object}: \"$tail\"\n";
102             }
103
104             return undef;
105         },
106 } -> {$producer};
107
108 die "Producer unrecognised: $producer\n" unless defined $procedure;
109
110 while (<STDIN>) {
111     if ($_ = $procedure->($_, @ARGV)) {
112         print or die "$!\n";
113     }
114 }