#!/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='', type=str, required = True, help='path to the xcfilelist holding input files') parser.add_argument( '--output', metavar='', 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()