blob: e07fbc9ccdb5ad00e4e5c4c5b3121346334b7e52 [file] [log] [blame]
krollin@apple.comfb0d6a52018-12-04 17:05:10 +00001#!/usr/bin/env python
2# vim: set ft=python:
3# -*- coding: utf-8 -*-
4#
5# Copyright (C) 2018 Apple Inc. All rights reserved.
6#
7# Redistribution and use in source and binary forms, with or without
8# modification, are permitted provided that the following conditions
9# are met:
10#
11# 1. Redistributions of source code must retain the above copyright
12# notice, this list of conditions and the following disclaimer.
13# 2. Redistributions in binary form must reproduce the above copyright
14# notice, this list of conditions and the following disclaimer in the
15# documentation and/or other materials provided with the distribution.
16#
17# THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
18# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
21# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
25# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29
30# Extract dependency information from the output of `make -d`, generating a
31# list of top-level targets (which are assumed to be generated/output files)
32# and a list of leaf dependencies (which are assumed to be the base input
33# files). Read the make dependency information from stdin and write the results
34# to the specified files.
35
36
37from __future__ import print_function
38
39import argparse
40import re
41import sys
42
43
44class Parser(object):
45
46 fileNamePattern = r"`([^']+)'"
47 rePrerequisite = re.compile(r"Prerequisite {} is .* than target {}".format(fileNamePattern, fileNamePattern))
krollin@apple.com4b7e68c2019-01-25 21:51:03 +000048 reMustRemakeTarget = re.compile(r"Must remake target {}".format(fileNamePattern))
krollin@apple.comfb0d6a52018-12-04 17:05:10 +000049 reWasConsideredAlready = re.compile(r"{} was considered already.".format(fileNamePattern))
50 rePruningFile = re.compile(r"Pruning file {}.".format(fileNamePattern))
51
52 def __init__(self):
53 self.targets = {}
54 self.prereqs = {}
55
56 def nextLine(self, input):
57 while True:
58 line = input.readline()
59 if not line: break
60 line = line.strip()
61 if line: yield line
62
63 def addTarget(self, target):
krollin@apple.com4b7e68c2019-01-25 21:51:03 +000064 if target != 'all' and target != 'force':
65 self.targets[target] = 1
krollin@apple.comfb0d6a52018-12-04 17:05:10 +000066
67 def addPrereq(self, prereq):
krollin@apple.com4b7e68c2019-01-25 21:51:03 +000068 if prereq != 'all' and prereq != 'force':
69 self.prereqs[prereq] = 1
krollin@apple.comfb0d6a52018-12-04 17:05:10 +000070
71 def doParse(self, input):
72
73 # Pull out everything that looks like a target or prerequisite.
74
75 for line in self.nextLine(input):
76 m = Parser.rePrerequisite.search(line)
77 if m:
78 self.addTarget(m.group(2))
79 self.addPrereq(m.group(1))
80 continue
81
krollin@apple.com4b7e68c2019-01-25 21:51:03 +000082 m = Parser.reMustRemakeTarget.search(line)
83 if m:
84 self.addTarget(m.group(1))
85 continue
86
krollin@apple.comfb0d6a52018-12-04 17:05:10 +000087 m = Parser.reWasConsideredAlready.search(line)
88 if m:
89 self.addTarget(m.group(1))
90 continue
91
92 m = Parser.rePruningFile.search(line)
93 if m:
94 self.addPrereq(m.group(1))
95 continue
96
97 # Regarding prerequisites, we're interested in only those that aren't
98 # also targets. We only want ones that don't have build rules, and
99 # hence must already exist. Those are our inputs.
100
101 for key in self.targets.keys():
102 self.prereqs.pop(key, None)
103
104 def printInputs(self, inputsFile):
105 with open(inputsFile, 'w') as toFile:
106 [ print("{}".format(f), file = toFile) for f in sorted(self.prereqs.keys()) ]
107
108 def printOutputs(self, outputsFile):
109 with open(outputsFile, 'w') as toFile:
110 [ print("{}".format(f), file = toFile) for f in sorted(self.targets.keys()) ]
111
112
113def parseArgs():
114 parser = argparse.ArgumentParser()
115
116 parser.add_argument(
117 '--input',
118 metavar='<xcfilelist>',
119 type=str,
120 required = True,
121 help='path to the xcfilelist holding input files')
122
123 parser.add_argument(
124 '--output',
125 metavar='<xcfilelist>',
126 type=str,
127 required = True,
128 help='path to the xcfilelist holding output/generated files')
129
130 return parser.parse_args()
131
132
133def main():
134 args = parseArgs()
135 parser = Parser()
136
137 parser.doParse(sys.stdin)
138 parser.printInputs(args.input)
139 parser.printOutputs(args.output)
140
141
142if __name__ == '__main__':
143 main()