You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
208 lines
7.1 KiB
208 lines
7.1 KiB
4 months ago
|
#
|
||
|
# Copyright 2016 - The Android Open Source Project
|
||
|
#
|
||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
# you may not use this file except in compliance with the License.
|
||
|
# You may obtain a copy of the License at
|
||
|
#
|
||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||
|
#
|
||
|
# Unless required by applicable law or agreed to in writing, software
|
||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
# See the License for the specific language governing permissions and
|
||
|
# limitations under the License.
|
||
|
#
|
||
|
|
||
|
import argparse
|
||
|
import os
|
||
|
import os.path
|
||
|
import sys
|
||
|
import re
|
||
|
import fileinput
|
||
|
import pprint
|
||
|
|
||
|
AR = 'ar'
|
||
|
CC = 'gcc'
|
||
|
|
||
|
class MakeParser(object):
|
||
|
'''Parses the output of make --dry-run.
|
||
|
|
||
|
Attributes:
|
||
|
ltp_root: string, LTP root directory
|
||
|
ar_parser: archive (ar) command argument parser
|
||
|
cc_parser: gcc command argument parser
|
||
|
result: list of string, result string buffer
|
||
|
dir_stack: list of string, directory stack for parsing make commands
|
||
|
'''
|
||
|
|
||
|
def __init__(self, ltp_root):
|
||
|
self.ltp_root = ltp_root
|
||
|
ar_parser = argparse.ArgumentParser()
|
||
|
ar_parser.add_argument('-r', dest='r', action='store_true')
|
||
|
ar_parser.add_argument('-c', dest='c', action='store')
|
||
|
self.ar_parser = ar_parser
|
||
|
|
||
|
cc_parser = argparse.ArgumentParser()
|
||
|
cc_parser.add_argument('-D', dest='defines', action='append')
|
||
|
cc_parser.add_argument('-I', dest='includes', action='append')
|
||
|
cc_parser.add_argument('-l', dest='libraries', action='append')
|
||
|
cc_parser.add_argument('-c', dest='compile', action='store_true')
|
||
|
cc_parser.add_argument('-o', dest='target', action='store')
|
||
|
self.cc_parser = cc_parser
|
||
|
|
||
|
self.result = []
|
||
|
self.dir_stack = []
|
||
|
|
||
|
def GetRelativePath(self, path):
|
||
|
'''Get relative path toward LTP directory.
|
||
|
|
||
|
Args:
|
||
|
path: string, a path to convert to relative path
|
||
|
'''
|
||
|
if path[0] == '/':
|
||
|
path = os.path.realpath(path)
|
||
|
else:
|
||
|
path = os.path.realpath(self.ltp_root + os.sep + self.dir_stack[-1]
|
||
|
+ os.sep + path)
|
||
|
return os.path.realpath(path).replace(self.ltp_root + os.sep, '')
|
||
|
|
||
|
def GetRelativePathForExtensions(self, paths, extensions):
|
||
|
'''Get relative path toward LTP directory of paths with given extension.
|
||
|
|
||
|
Args:
|
||
|
paths: list of string, paths to convert to relative path
|
||
|
extensions: list of string, extension include filter
|
||
|
'''
|
||
|
return [self.GetRelativePath(i) for i in paths if i[-1] in extensions]
|
||
|
|
||
|
def ParseAr(self, line):
|
||
|
'''Parse a archive command line.
|
||
|
|
||
|
Args:
|
||
|
line: string, a line of ar command to parse
|
||
|
'''
|
||
|
args, unparsed = self.ar_parser.parse_known_args(line.split()[1:])
|
||
|
|
||
|
sources = self.GetRelativePathForExtensions(unparsed, ['o'])
|
||
|
|
||
|
# Support 'ar' command line with or without hyphens (-)
|
||
|
# e.g.:
|
||
|
# 1. ar rcs libfoo.a foo1.o foo2.o
|
||
|
# 2. ar -rc "libfoo.a" foo1.o foo2.o; ranlib "libfoo.a"
|
||
|
target = None
|
||
|
if not args.c and not args.r:
|
||
|
for path in unparsed:
|
||
|
if path.endswith('.a'):
|
||
|
target = self.GetRelativePath(path)
|
||
|
break
|
||
|
else:
|
||
|
target = self.GetRelativePath(args.c.replace('"', ""))
|
||
|
|
||
|
assert len(sources) > 0
|
||
|
assert target != None
|
||
|
|
||
|
self.result.append("ar['%s'] = %s" % (target, sources))
|
||
|
|
||
|
def ParseCc(self, line):
|
||
|
'''Parse a gcc command line.
|
||
|
|
||
|
Args:
|
||
|
line: string, a line of gcc command to parse
|
||
|
'''
|
||
|
args, unparsed = self.cc_parser.parse_known_args(line.split()[1:])
|
||
|
|
||
|
sources = self.GetRelativePathForExtensions(unparsed, ['c', 'o'])
|
||
|
includes = [self.GetRelativePath(i)
|
||
|
for i in args.includes] if args.includes else []
|
||
|
flags = []
|
||
|
defines = args.defines if args.defines else []
|
||
|
target = self.GetRelativePath(args.target)
|
||
|
|
||
|
if args.defines:
|
||
|
for define in args.defines:
|
||
|
flags.append('-D%s' % define)
|
||
|
|
||
|
flags.extend(i for i in unparsed if i.startswith('-Wno'))
|
||
|
|
||
|
assert len(sources) > 0
|
||
|
|
||
|
if args.compile:
|
||
|
self.result.append("cc_compile['%s'] = %s" % (target, sources))
|
||
|
else:
|
||
|
libraries = args.libraries if args.libraries else []
|
||
|
if sources[0].endswith('.o'):
|
||
|
self.result.append("cc_link['%s'] = %s" % (target, sources))
|
||
|
else:
|
||
|
self.result.append("cc_compilelink['%s'] = %s" %
|
||
|
(target, sources))
|
||
|
self.result.append("cc_libraries['%s'] = %s" % (target, libraries))
|
||
|
|
||
|
self.result.append("cc_flags['%s'] = %s" % (target, flags))
|
||
|
self.result.append("cc_includes['%s'] = %s" % (target, includes))
|
||
|
|
||
|
def ParseFile(self, input_path):
|
||
|
'''Parses the output of make --dry-run.
|
||
|
|
||
|
Args:
|
||
|
input_text: string, output of make --dry-run
|
||
|
|
||
|
Returns:
|
||
|
string, generated directives in the form
|
||
|
ar['target.a'] = [ 'srcfile1.o, 'srcfile2.o', ... ]
|
||
|
cc_link['target'] = [ 'srcfile1.o', 'srcfile2.o', ... ]
|
||
|
cc_compile['target.o'] = [ 'srcfile1.c' ]
|
||
|
cc_compilelink['target'] = [ 'srcfile1.c' ]
|
||
|
along with optional flags for the above directives in the form
|
||
|
cc_flags['target'] = [ '-flag1', '-flag2', ...]
|
||
|
cc_includes['target'] = [ 'includepath1', 'includepath2', ...]
|
||
|
cc_libraries['target'] = [ 'library1', 'library2', ...]
|
||
|
'''
|
||
|
self.result = []
|
||
|
self.dir_stack = []
|
||
|
|
||
|
entering_directory = re.compile(r"make.*: Entering directory [`,'](.*)'")
|
||
|
leaving_directory = re.compile(r"make.*: Leaving directory [`,'](.*)'")
|
||
|
|
||
|
with open(input_path, 'r') as f:
|
||
|
for line in f:
|
||
|
line = line.strip()
|
||
|
|
||
|
m = entering_directory.match(line)
|
||
|
if m:
|
||
|
self.dir_stack.append(self.GetRelativePath(m.group(1)))
|
||
|
continue
|
||
|
|
||
|
m = leaving_directory.match(line)
|
||
|
if m:
|
||
|
self.dir_stack.pop()
|
||
|
elif line.startswith(AR):
|
||
|
self.ParseAr(line)
|
||
|
elif line.startswith(CC):
|
||
|
self.ParseCc(line)
|
||
|
|
||
|
return self.result
|
||
|
|
||
|
def main():
|
||
|
arg_parser = argparse.ArgumentParser(
|
||
|
description='Parse the LTP make --dry-run output into a list')
|
||
|
arg_parser.add_argument(
|
||
|
'--ltp-root',
|
||
|
dest='ltp_root',
|
||
|
required=True,
|
||
|
help='LTP Root dir')
|
||
|
arg_parser.add_argument(
|
||
|
'--dry-run-file',
|
||
|
dest='input_path',
|
||
|
required=True,
|
||
|
help='Path to LTP make --dry-run output file')
|
||
|
args = arg_parser.parse_args()
|
||
|
|
||
|
make_parser = MakeParser(args.ltp_root)
|
||
|
result = make_parser.ParseFile(args.input_path)
|
||
|
|
||
|
print pprint.pprint(result)
|
||
|
|
||
|
if __name__ == '__main__':
|
||
|
main()
|