1*49cdfc7eSAndroid Build Coastguard Worker#!/usr/bin/env python 2*49cdfc7eSAndroid Build Coastguard Worker# 3*49cdfc7eSAndroid Build Coastguard Worker# Copyright 2016 - The Android Open Source Project 4*49cdfc7eSAndroid Build Coastguard Worker# 5*49cdfc7eSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); 6*49cdfc7eSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License. 7*49cdfc7eSAndroid Build Coastguard Worker# You may obtain a copy of the License at 8*49cdfc7eSAndroid Build Coastguard Worker# 9*49cdfc7eSAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 10*49cdfc7eSAndroid Build Coastguard Worker# 11*49cdfc7eSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 12*49cdfc7eSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, 13*49cdfc7eSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14*49cdfc7eSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and 15*49cdfc7eSAndroid Build Coastguard Worker# limitations under the License. 16*49cdfc7eSAndroid Build Coastguard Worker# 17*49cdfc7eSAndroid Build Coastguard Worker 18*49cdfc7eSAndroid Build Coastguard Workerimport argparse 19*49cdfc7eSAndroid Build Coastguard Workerimport os 20*49cdfc7eSAndroid Build Coastguard Workerimport os.path 21*49cdfc7eSAndroid Build Coastguard Workerimport sys 22*49cdfc7eSAndroid Build Coastguard Workerimport re 23*49cdfc7eSAndroid Build Coastguard Workerimport fileinput 24*49cdfc7eSAndroid Build Coastguard Workerimport pprint 25*49cdfc7eSAndroid Build Coastguard Worker 26*49cdfc7eSAndroid Build Coastguard WorkerAR = 'ar' 27*49cdfc7eSAndroid Build Coastguard WorkerAS = 'as' 28*49cdfc7eSAndroid Build Coastguard WorkerCC = 'gcc' 29*49cdfc7eSAndroid Build Coastguard Worker 30*49cdfc7eSAndroid Build Coastguard Workerclass MakeParser(object): 31*49cdfc7eSAndroid Build Coastguard Worker '''Parses the output of make --dry-run. 32*49cdfc7eSAndroid Build Coastguard Worker 33*49cdfc7eSAndroid Build Coastguard Worker Attributes: 34*49cdfc7eSAndroid Build Coastguard Worker ltp_root: string, LTP root directory 35*49cdfc7eSAndroid Build Coastguard Worker ar_parser: archive (ar) command argument parser 36*49cdfc7eSAndroid Build Coastguard Worker as_parser: assembly (as) command argument parser 37*49cdfc7eSAndroid Build Coastguard Worker cc_parser: gcc command argument parser 38*49cdfc7eSAndroid Build Coastguard Worker result: list of string, result string buffer 39*49cdfc7eSAndroid Build Coastguard Worker dir_stack: list of string, directory stack for parsing make commands 40*49cdfc7eSAndroid Build Coastguard Worker ''' 41*49cdfc7eSAndroid Build Coastguard Worker 42*49cdfc7eSAndroid Build Coastguard Worker def __init__(self, ltp_root): 43*49cdfc7eSAndroid Build Coastguard Worker self.ltp_root = ltp_root 44*49cdfc7eSAndroid Build Coastguard Worker ar_parser = argparse.ArgumentParser() 45*49cdfc7eSAndroid Build Coastguard Worker ar_parser.add_argument('-r', dest='r', action='store_true') 46*49cdfc7eSAndroid Build Coastguard Worker ar_parser.add_argument('-c', dest='c', action='store') 47*49cdfc7eSAndroid Build Coastguard Worker self.ar_parser = ar_parser 48*49cdfc7eSAndroid Build Coastguard Worker 49*49cdfc7eSAndroid Build Coastguard Worker as_parser = argparse.ArgumentParser() 50*49cdfc7eSAndroid Build Coastguard Worker as_parser.add_argument('-c', dest='compile', action='store_true') 51*49cdfc7eSAndroid Build Coastguard Worker as_parser.add_argument('-o', dest='target', action='store') 52*49cdfc7eSAndroid Build Coastguard Worker self.as_parser = as_parser 53*49cdfc7eSAndroid Build Coastguard Worker 54*49cdfc7eSAndroid Build Coastguard Worker cc_parser = argparse.ArgumentParser() 55*49cdfc7eSAndroid Build Coastguard Worker cc_parser.add_argument('-D', dest='defines', action='append') 56*49cdfc7eSAndroid Build Coastguard Worker cc_parser.add_argument('-I', dest='includes', action='append') 57*49cdfc7eSAndroid Build Coastguard Worker cc_parser.add_argument('-l', dest='libraries', action='append') 58*49cdfc7eSAndroid Build Coastguard Worker cc_parser.add_argument('-L', dest='libraries_path', action='append') 59*49cdfc7eSAndroid Build Coastguard Worker cc_parser.add_argument('-c', dest='compile', action='store_true') 60*49cdfc7eSAndroid Build Coastguard Worker cc_parser.add_argument('-o', dest='target', action='store') 61*49cdfc7eSAndroid Build Coastguard Worker self.cc_parser = cc_parser 62*49cdfc7eSAndroid Build Coastguard Worker 63*49cdfc7eSAndroid Build Coastguard Worker self.result = [] 64*49cdfc7eSAndroid Build Coastguard Worker self.dir_stack = [] 65*49cdfc7eSAndroid Build Coastguard Worker 66*49cdfc7eSAndroid Build Coastguard Worker def GetRelativePath(self, path): 67*49cdfc7eSAndroid Build Coastguard Worker '''Get relative path toward LTP directory. 68*49cdfc7eSAndroid Build Coastguard Worker 69*49cdfc7eSAndroid Build Coastguard Worker Args: 70*49cdfc7eSAndroid Build Coastguard Worker path: string, a path to convert to relative path 71*49cdfc7eSAndroid Build Coastguard Worker ''' 72*49cdfc7eSAndroid Build Coastguard Worker if path[0] == '/': 73*49cdfc7eSAndroid Build Coastguard Worker path = os.path.realpath(path) 74*49cdfc7eSAndroid Build Coastguard Worker else: 75*49cdfc7eSAndroid Build Coastguard Worker path = os.path.realpath(self.ltp_root + os.sep + self.dir_stack[-1] 76*49cdfc7eSAndroid Build Coastguard Worker + os.sep + path) 77*49cdfc7eSAndroid Build Coastguard Worker return os.path.realpath(path).replace(self.ltp_root + os.sep, '') 78*49cdfc7eSAndroid Build Coastguard Worker 79*49cdfc7eSAndroid Build Coastguard Worker def GetRelativePathForExtensions(self, paths, extensions): 80*49cdfc7eSAndroid Build Coastguard Worker '''Get relative path toward LTP directory of paths with given extension. 81*49cdfc7eSAndroid Build Coastguard Worker 82*49cdfc7eSAndroid Build Coastguard Worker Args: 83*49cdfc7eSAndroid Build Coastguard Worker paths: list of string, paths to convert to relative path 84*49cdfc7eSAndroid Build Coastguard Worker extensions: list of string, extension include filter 85*49cdfc7eSAndroid Build Coastguard Worker ''' 86*49cdfc7eSAndroid Build Coastguard Worker return [self.GetRelativePath(i) for i in paths if i[-1] in extensions] 87*49cdfc7eSAndroid Build Coastguard Worker 88*49cdfc7eSAndroid Build Coastguard Worker def ParseAr(self, line): 89*49cdfc7eSAndroid Build Coastguard Worker '''Parse an archive command line. 90*49cdfc7eSAndroid Build Coastguard Worker 91*49cdfc7eSAndroid Build Coastguard Worker Args: 92*49cdfc7eSAndroid Build Coastguard Worker line: string, a line of as command to parse 93*49cdfc7eSAndroid Build Coastguard Worker ''' 94*49cdfc7eSAndroid Build Coastguard Worker args, unparsed = self.ar_parser.parse_known_args(line.split()[1:]) 95*49cdfc7eSAndroid Build Coastguard Worker 96*49cdfc7eSAndroid Build Coastguard Worker sources = self.GetRelativePathForExtensions(unparsed, ['o']) 97*49cdfc7eSAndroid Build Coastguard Worker 98*49cdfc7eSAndroid Build Coastguard Worker # Support 'ar' command line with or without hyphens (-) 99*49cdfc7eSAndroid Build Coastguard Worker # e.g.: 100*49cdfc7eSAndroid Build Coastguard Worker # 1. ar rcs libfoo.a foo1.o foo2.o 101*49cdfc7eSAndroid Build Coastguard Worker # 2. ar -rc "libfoo.a" foo1.o foo2.o; ranlib "libfoo.a" 102*49cdfc7eSAndroid Build Coastguard Worker target = None 103*49cdfc7eSAndroid Build Coastguard Worker if not args.c and not args.r: 104*49cdfc7eSAndroid Build Coastguard Worker for path in unparsed: 105*49cdfc7eSAndroid Build Coastguard Worker if path.endswith('.a'): 106*49cdfc7eSAndroid Build Coastguard Worker target = self.GetRelativePath(path) 107*49cdfc7eSAndroid Build Coastguard Worker break 108*49cdfc7eSAndroid Build Coastguard Worker else: 109*49cdfc7eSAndroid Build Coastguard Worker target = self.GetRelativePath(args.c.replace('"', "")) 110*49cdfc7eSAndroid Build Coastguard Worker 111*49cdfc7eSAndroid Build Coastguard Worker assert len(sources) > 0 112*49cdfc7eSAndroid Build Coastguard Worker assert target != None 113*49cdfc7eSAndroid Build Coastguard Worker 114*49cdfc7eSAndroid Build Coastguard Worker self.result.append("ar['%s'] = %s" % (target, sources)) 115*49cdfc7eSAndroid Build Coastguard Worker 116*49cdfc7eSAndroid Build Coastguard Worker def ParseAs(self, line): 117*49cdfc7eSAndroid Build Coastguard Worker '''Parse an assembly command line. 118*49cdfc7eSAndroid Build Coastguard Worker 119*49cdfc7eSAndroid Build Coastguard Worker Args: 120*49cdfc7eSAndroid Build Coastguard Worker line: string, a line of as command to parse 121*49cdfc7eSAndroid Build Coastguard Worker ''' 122*49cdfc7eSAndroid Build Coastguard Worker args, unparsed = self.as_parser.parse_known_args(line.split()[1:]) 123*49cdfc7eSAndroid Build Coastguard Worker 124*49cdfc7eSAndroid Build Coastguard Worker sources = self.GetRelativePathForExtensions(unparsed, ['S']) 125*49cdfc7eSAndroid Build Coastguard Worker 126*49cdfc7eSAndroid Build Coastguard Worker assert len(sources) > 0 127*49cdfc7eSAndroid Build Coastguard Worker target = self.GetRelativePath(args.target) 128*49cdfc7eSAndroid Build Coastguard Worker 129*49cdfc7eSAndroid Build Coastguard Worker if args.compile: 130*49cdfc7eSAndroid Build Coastguard Worker self.result.append("cc_compile['%s'] = %s" % (target, sources)) 131*49cdfc7eSAndroid Build Coastguard Worker else: 132*49cdfc7eSAndroid Build Coastguard Worker raise Exception("Unparsed assembly line: %s" % line) 133*49cdfc7eSAndroid Build Coastguard Worker 134*49cdfc7eSAndroid Build Coastguard Worker def ParseCc(self, line): 135*49cdfc7eSAndroid Build Coastguard Worker '''Parse a gcc command line. 136*49cdfc7eSAndroid Build Coastguard Worker 137*49cdfc7eSAndroid Build Coastguard Worker Args: 138*49cdfc7eSAndroid Build Coastguard Worker line: string, a line of gcc command to parse 139*49cdfc7eSAndroid Build Coastguard Worker ''' 140*49cdfc7eSAndroid Build Coastguard Worker args, unparsed = self.cc_parser.parse_known_args(line.split()[1:]) 141*49cdfc7eSAndroid Build Coastguard Worker 142*49cdfc7eSAndroid Build Coastguard Worker sources = self.GetRelativePathForExtensions(unparsed, ['c', 'o']) 143*49cdfc7eSAndroid Build Coastguard Worker includes = [self.GetRelativePath(i) 144*49cdfc7eSAndroid Build Coastguard Worker for i in args.includes] if args.includes else [] 145*49cdfc7eSAndroid Build Coastguard Worker flags = [] 146*49cdfc7eSAndroid Build Coastguard Worker defines = args.defines if args.defines else [] 147*49cdfc7eSAndroid Build Coastguard Worker target = self.GetRelativePath(args.target) 148*49cdfc7eSAndroid Build Coastguard Worker 149*49cdfc7eSAndroid Build Coastguard Worker if args.defines: 150*49cdfc7eSAndroid Build Coastguard Worker for define in args.defines: 151*49cdfc7eSAndroid Build Coastguard Worker flags.append('-D%s' % define) 152*49cdfc7eSAndroid Build Coastguard Worker 153*49cdfc7eSAndroid Build Coastguard Worker flags.extend(i for i in unparsed if i.startswith('-Wno')) 154*49cdfc7eSAndroid Build Coastguard Worker 155*49cdfc7eSAndroid Build Coastguard Worker assert len(sources) > 0 156*49cdfc7eSAndroid Build Coastguard Worker 157*49cdfc7eSAndroid Build Coastguard Worker if args.compile: 158*49cdfc7eSAndroid Build Coastguard Worker self.result.append("cc_compile['%s'] = %s" % (target, sources)) 159*49cdfc7eSAndroid Build Coastguard Worker else: 160*49cdfc7eSAndroid Build Coastguard Worker libraries = args.libraries if args.libraries else [] 161*49cdfc7eSAndroid Build Coastguard Worker if sources[0].endswith('.o'): 162*49cdfc7eSAndroid Build Coastguard Worker self.result.append("cc_link['%s'] = %s" % (target, sources)) 163*49cdfc7eSAndroid Build Coastguard Worker else: 164*49cdfc7eSAndroid Build Coastguard Worker self.result.append("cc_compilelink['%s'] = %s" % 165*49cdfc7eSAndroid Build Coastguard Worker (target, sources)) 166*49cdfc7eSAndroid Build Coastguard Worker self.result.append("cc_libraries['%s'] = %s" % (target, libraries)) 167*49cdfc7eSAndroid Build Coastguard Worker 168*49cdfc7eSAndroid Build Coastguard Worker self.result.append("cc_flags['%s'] = %s" % (target, flags)) 169*49cdfc7eSAndroid Build Coastguard Worker self.result.append("cc_includes['%s'] = %s" % (target, includes)) 170*49cdfc7eSAndroid Build Coastguard Worker 171*49cdfc7eSAndroid Build Coastguard Worker def ParseFile(self, input_path): 172*49cdfc7eSAndroid Build Coastguard Worker '''Parses the output of make --dry-run. 173*49cdfc7eSAndroid Build Coastguard Worker 174*49cdfc7eSAndroid Build Coastguard Worker Args: 175*49cdfc7eSAndroid Build Coastguard Worker input_text: string, output of make --dry-run 176*49cdfc7eSAndroid Build Coastguard Worker 177*49cdfc7eSAndroid Build Coastguard Worker Returns: 178*49cdfc7eSAndroid Build Coastguard Worker string, generated directives in the form 179*49cdfc7eSAndroid Build Coastguard Worker ar['target.a'] = [ 'srcfile1.o, 'srcfile2.o', ... ] 180*49cdfc7eSAndroid Build Coastguard Worker cc_link['target'] = [ 'srcfile1.o', 'srcfile2.o', ... ] 181*49cdfc7eSAndroid Build Coastguard Worker cc_compile['target.o'] = [ 'srcfile1.c' ] 182*49cdfc7eSAndroid Build Coastguard Worker cc_compilelink['target'] = [ 'srcfile1.c' ] 183*49cdfc7eSAndroid Build Coastguard Worker along with optional flags for the above directives in the form 184*49cdfc7eSAndroid Build Coastguard Worker cc_flags['target'] = [ '-flag1', '-flag2', ...] 185*49cdfc7eSAndroid Build Coastguard Worker cc_includes['target'] = [ 'includepath1', 'includepath2', ...] 186*49cdfc7eSAndroid Build Coastguard Worker cc_libraries['target'] = [ 'library1', 'library2', ...] 187*49cdfc7eSAndroid Build Coastguard Worker ''' 188*49cdfc7eSAndroid Build Coastguard Worker self.result = [] 189*49cdfc7eSAndroid Build Coastguard Worker self.dir_stack = [] 190*49cdfc7eSAndroid Build Coastguard Worker 191*49cdfc7eSAndroid Build Coastguard Worker entering_directory = re.compile(r"make.*: Entering directory [`,'](.*)'") 192*49cdfc7eSAndroid Build Coastguard Worker leaving_directory = re.compile(r"make.*: Leaving directory [`,'](.*)'") 193*49cdfc7eSAndroid Build Coastguard Worker 194*49cdfc7eSAndroid Build Coastguard Worker with open(input_path, 'r') as f: 195*49cdfc7eSAndroid Build Coastguard Worker for line in f: 196*49cdfc7eSAndroid Build Coastguard Worker line = line.strip() 197*49cdfc7eSAndroid Build Coastguard Worker 198*49cdfc7eSAndroid Build Coastguard Worker m = entering_directory.match(line) 199*49cdfc7eSAndroid Build Coastguard Worker if m: 200*49cdfc7eSAndroid Build Coastguard Worker self.dir_stack.append(self.GetRelativePath(m.group(1))) 201*49cdfc7eSAndroid Build Coastguard Worker continue 202*49cdfc7eSAndroid Build Coastguard Worker 203*49cdfc7eSAndroid Build Coastguard Worker m = leaving_directory.match(line) 204*49cdfc7eSAndroid Build Coastguard Worker if m: 205*49cdfc7eSAndroid Build Coastguard Worker self.dir_stack.pop() 206*49cdfc7eSAndroid Build Coastguard Worker elif line.startswith(AR): 207*49cdfc7eSAndroid Build Coastguard Worker self.ParseAr(line) 208*49cdfc7eSAndroid Build Coastguard Worker elif line.startswith(AS): 209*49cdfc7eSAndroid Build Coastguard Worker self.ParseAs(line) 210*49cdfc7eSAndroid Build Coastguard Worker elif line.startswith(CC): 211*49cdfc7eSAndroid Build Coastguard Worker self.ParseCc(line) 212*49cdfc7eSAndroid Build Coastguard Worker 213*49cdfc7eSAndroid Build Coastguard Worker return self.result 214*49cdfc7eSAndroid Build Coastguard Worker 215*49cdfc7eSAndroid Build Coastguard Workerdef main(): 216*49cdfc7eSAndroid Build Coastguard Worker arg_parser = argparse.ArgumentParser( 217*49cdfc7eSAndroid Build Coastguard Worker description='Parse the LTP make --dry-run output into a list') 218*49cdfc7eSAndroid Build Coastguard Worker arg_parser.add_argument( 219*49cdfc7eSAndroid Build Coastguard Worker '--ltp-root', 220*49cdfc7eSAndroid Build Coastguard Worker dest='ltp_root', 221*49cdfc7eSAndroid Build Coastguard Worker required=True, 222*49cdfc7eSAndroid Build Coastguard Worker help='LTP Root dir') 223*49cdfc7eSAndroid Build Coastguard Worker arg_parser.add_argument( 224*49cdfc7eSAndroid Build Coastguard Worker '--dry-run-file', 225*49cdfc7eSAndroid Build Coastguard Worker dest='input_path', 226*49cdfc7eSAndroid Build Coastguard Worker required=True, 227*49cdfc7eSAndroid Build Coastguard Worker help='Path to LTP make --dry-run output file') 228*49cdfc7eSAndroid Build Coastguard Worker args = arg_parser.parse_args() 229*49cdfc7eSAndroid Build Coastguard Worker 230*49cdfc7eSAndroid Build Coastguard Worker make_parser = MakeParser(args.ltp_root) 231*49cdfc7eSAndroid Build Coastguard Worker result = make_parser.ParseFile(args.input_path) 232*49cdfc7eSAndroid Build Coastguard Worker 233*49cdfc7eSAndroid Build Coastguard Worker print(pprint.pprint(result)) 234*49cdfc7eSAndroid Build Coastguard Worker 235*49cdfc7eSAndroid Build Coastguard Workerif __name__ == '__main__': 236*49cdfc7eSAndroid Build Coastguard Worker main() 237