xref: /aosp_15_r20/external/ltp/android/tools/make_parser.py (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
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