| #!/usr/bin/env python |
| # vim: set ft=python: |
| # -*- coding: utf-8 -*- |
| # |
| # Copyright (C) 2018 Apple Inc. All rights reserved. |
| # |
| # Redistribution and use in source and binary forms, with or without |
| # modification, are permitted provided that the following conditions |
| # are met: |
| # |
| # 1. Redistributions of source code must retain the above copyright |
| # notice, this list of conditions and the following disclaimer. |
| # 2. Redistributions in binary form must reproduce the above copyright |
| # notice, this list of conditions and the following disclaimer in the |
| # documentation and/or other materials provided with the distribution. |
| # |
| # THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY |
| # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR |
| # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
| # OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| |
| # Extract dependency information from the output of `make -d`, generating a |
| # list of top-level targets (which are assumed to be generated/output files) |
| # and a list of leaf dependencies (which are assumed to be the base input |
| # files). Read the make dependency information from stdin and write the results |
| # to the specified files. |
| |
| |
| from __future__ import print_function |
| |
| import argparse |
| import re |
| import sys |
| |
| |
| class Parser(object): |
| |
| fileNamePattern = r"`([^']+)'" |
| rePrerequisite = re.compile(r"Prerequisite {} is .* than target {}".format(fileNamePattern, fileNamePattern)) |
| reMustRemakeTarget = re.compile(r"Must remake target {}".format(fileNamePattern)) |
| reWasConsideredAlready = re.compile(r"{} was considered already.".format(fileNamePattern)) |
| rePruningFile = re.compile(r"Pruning file {}.".format(fileNamePattern)) |
| |
| def __init__(self): |
| self.targets = {} |
| self.prereqs = {} |
| |
| def nextLine(self, input): |
| while True: |
| line = input.readline() |
| if not line: break |
| line = line.strip() |
| if line: yield line |
| |
| def addTarget(self, target): |
| if target != 'all' and target != 'force': |
| self.targets[target] = 1 |
| |
| def addPrereq(self, prereq): |
| if prereq != 'all' and prereq != 'force': |
| self.prereqs[prereq] = 1 |
| |
| def doParse(self, input): |
| |
| # Pull out everything that looks like a target or prerequisite. |
| |
| for line in self.nextLine(input): |
| m = Parser.rePrerequisite.search(line) |
| if m: |
| self.addTarget(m.group(2)) |
| self.addPrereq(m.group(1)) |
| continue |
| |
| m = Parser.reMustRemakeTarget.search(line) |
| if m: |
| self.addTarget(m.group(1)) |
| continue |
| |
| m = Parser.reWasConsideredAlready.search(line) |
| if m: |
| self.addTarget(m.group(1)) |
| continue |
| |
| m = Parser.rePruningFile.search(line) |
| if m: |
| self.addPrereq(m.group(1)) |
| continue |
| |
| # Regarding prerequisites, we're interested in only those that aren't |
| # also targets. We only want ones that don't have build rules, and |
| # hence must already exist. Those are our inputs. |
| |
| for key in self.targets.keys(): |
| self.prereqs.pop(key, None) |
| |
| def printInputs(self, inputsFile): |
| with open(inputsFile, 'w') as toFile: |
| [ print("{}".format(f), file = toFile) for f in sorted(self.prereqs.keys()) ] |
| |
| def printOutputs(self, outputsFile): |
| with open(outputsFile, 'w') as toFile: |
| [ print("{}".format(f), file = toFile) for f in sorted(self.targets.keys()) ] |
| |
| |
| def parseArgs(): |
| parser = argparse.ArgumentParser() |
| |
| parser.add_argument( |
| '--input', |
| metavar='<xcfilelist>', |
| type=str, |
| required = True, |
| help='path to the xcfilelist holding input files') |
| |
| parser.add_argument( |
| '--output', |
| metavar='<xcfilelist>', |
| type=str, |
| required = True, |
| help='path to the xcfilelist holding output/generated files') |
| |
| return parser.parse_args() |
| |
| |
| def main(): |
| args = parseArgs() |
| parser = Parser() |
| |
| parser.doParse(sys.stdin) |
| parser.printInputs(args.input) |
| parser.printOutputs(args.output) |
| |
| |
| if __name__ == '__main__': |
| main() |