blob: 6b4e53439a1c47099c5daa0076b2e6c9ffc2792b [file] [log] [blame]
#!/usr/bin/env python3
# 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()