]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - android-sdk/platform-bionic.git/blob - libc/kernel/tools/kernel.py
Initial Contribution
[android-sdk/platform-bionic.git] / libc / kernel / tools / kernel.py
1 # this file contains definitions related to the Linux kernel itself
2 #
4 # list here the macros that you know are always defined/undefined when including
5 # the kernel headers
6 #
7 import sys, cpp, re, os.path, string, time
8 from defaults import *
10 verboseSearch = 0
11 verboseFind   = 0
13 ########################################################################
14 ########################################################################
15 #####                                                              #####
16 #####           H E A D E R   S C A N N E R                        #####
17 #####                                                              #####
18 ########################################################################
19 ########################################################################
22 class HeaderScanner:
23     """a class used to non-recursively detect which Linux kernel headers are
24        used by a given set of input source files"""
26     # to use the HeaderScanner, do the following:
27     #
28     #    scanner = HeaderScanner()
29     #    for path in <your list of files>:
30     #        scanner.parseFile(path)
31     #
32     #    # get the set of Linux headers included by your files
33     #    headers = scanner.getHeaders()
34     #
35     #    # get the set of of input files that do include Linux headers
36     #    files   = scanner.getFiles()
37     #
38     #    note that the result of getHeaders() is a set of strings, each one
39     #    corresponding to a non-bracketed path name, e.g.:
40     #
41     #        set("linux/types","asm/types.h")
42     #
44     # the default algorithm is pretty smart and will analyze the input
45     # files with a custom C pre-processor in order to optimize out macros,
46     # get rid of comments, empty lines, etc..
47     #
48     # this avoids many annoying false positives... !!
49     #
51     # this regular expression is used to detect include paths that relate to
52     # the kernel, by default, it selects one of:
53     #    <linux/*>
54     #    <asm/*>
55     #    <asm-generic/*>
56     #    <mtd/*>
57     #
58     re_combined =\
59        re.compile(r"^.*<((%s)/[\d\w_\+\.\-/]*)>.*$" % string.join(kernel_dirs,"|") )
61     def __init__(self,config={}):
62         """initialize a HeaderScanner"""
63         self.reset()
64         self.config = config
66     def reset(self,config={}):
67         self.files    = set()  # set of files being parsed for headers
68         self.headers  = {}     # maps headers to set of users
69         self.config   = config
71     def checkInclude(self,line,from_file):
72         m = HeaderScanner.re_combined.match(line)
73         if not m: return
75         header = m.group(1)
76         if from_file:
77             self.files.add(from_file)
79         if not header in self.headers:
80             self.headers[header] = set()
82         if from_file:
83             if verboseFind:
84                 print "=== %s uses %s" % (from_file, header)
85             self.headers[header].add(from_file)
87     def parseFile(self,path):
88         """parse a given file for Linux headers"""
89         if not os.path.exists(path):
90             return
92         # since tokenizing the file is very slow, we first try a quick grep
93         # to see if this returns any meaningful results. only if this is true
94         # do we do the tokenization"""
95         try:
96             f = open(path, "rt")
97         except:
98             print "!!! can't read '%s'" % path
99             return
101         hasIncludes = False
102         for line in f:
103             if HeaderScanner.re_combined.match(line):
104                 hasIncludes = True
105                 break
107         if not hasIncludes:
108             if verboseSearch: print "::: " + path
109             return
111         if verboseSearch: print "*** " + path
113         list = cpp.BlockParser().parseFile(path)
114         if list:
115             #list.removePrefixed("CONFIG_",self.config)
116             list.optimizeMacros(kernel_known_macros)
117             list.optimizeIf01()
118             includes = list.findIncludes()
119             for inc in includes:
120                 self.checkInclude(inc,path)
122     def getHeaders(self):
123         """return the set of all needed kernel headers"""
124         return set(self.headers.keys())
126     def getHeaderUsers(self,header):
127         """return the set of all users for a given header"""
128         return set(self.headers.get(header))
130     def getAllUsers(self):
131         """return a dictionary mapping heaaders to their user set"""
132         return self.headers.copy()
134     def getFiles(self):
135         """returns the set of files that do include kernel headers"""
136         return self.files.copy()
139 ##########################################################################
140 ##########################################################################
141 #####                                                                #####
142 #####           H E A D E R   F I N D E R                            #####
143 #####                                                                #####
144 ##########################################################################
145 ##########################################################################
148 class KernelHeaderFinder:
149     """a class used to scan the kernel headers themselves."""
151     # this is different
152     #  from a HeaderScanner because we need to translate the path returned by
153     #  HeaderScanner.getHeaders() into possibly architecture-specific ones.
154     #
155     # for example, <asm/XXXX.h> needs to be translated in <asm-ARCH/XXXX.h>
156     # where ARCH is appropriately chosen
158     # here's how to use this:
159     #
160     #    scanner = HeaderScanner()
161     #    for path in <your list of user sources>:
162     #        scanner.parseFile(path)
163     #
164     #    used_headers = scanner.getHeaders()
165     #    finder       = KernelHeaderFinder(used_headers, [ "arm", "x86" ],
166     #                                      "<kernel_include_path>")
167     #    all_headers  = finder.scanForAllArchs()
168     #
169     #   not that the result of scanForAllArchs() is a list of relative
170     #   header paths that are not bracketed
171     #
173     def __init__(self,headers,archs,kernel_root,kernel_config):
174         """init a KernelHeaderScanner,
176             'headers' is a list or set of headers,
177             'archs' is a list of architectures
178             'kernel_root' is the path to the 'include' directory
179              of your original kernel sources
180         """
182         if len(kernel_root) > 0 and kernel_root[-1] != "/":
183             kernel_root += "/"
184         #print "using kernel_root %s" % kernel_root
185         self.archs         = archs
186         self.searched      = set(headers)
187         self.kernel_root   = kernel_root
188         self.kernel_config = kernel_config
189         self.needed        = {}
191     def setArch(self,arch=None):
192         if arch:
193             self.prefix = "asm-%s/" % arch
194             self.arch_headers = set()
195         else:
196             self.prefix = None
197             self.arch_headers = set()
199     def pathFromHeader(self,header):
200         path = header
201         if self.prefix and path.startswith("asm/"):
202             path = "%s%s" % (self.prefix, path[4:])
203         return path
205     def pathToHeader(self,path):
206         if self.prefix and path.startswith(self.prefix):
207             path = "asm/%s" % path[len(self.prefix):]
208         return "%s" % path
210     def setSearchedHeaders(self,headers):
211         self.searched = set(headers)
213     def scanForArch(self):
214         fparser   = HeaderScanner(config=self.kernel_config)
215         workqueue = []
216         needed    = {}
217         for h in self.searched:
218             path = self.pathFromHeader(h)
219             if not path in needed:
220                 needed[path] = set()
221             workqueue.append(path)
223         i = 0
224         while i < len(workqueue):
225             path = workqueue[i]
226             i   += 1
227             fparser.parseFile(self.kernel_root + path)
228             for used in fparser.getHeaders():
229                 path  = self.pathFromHeader(used)
230                 if not path in needed:
231                     needed[path] = set()
232                     workqueue.append(path)
233                 for user in fparser.getHeaderUsers(used):
234                     needed[path].add(user)
236         # now copy the arch-specific headers into the global list
237         for header in needed.keys():
238             users = needed[header]
239             if not header in self.needed:
240                 self.needed[header] = set()
242             for user in users:
243                 self.needed[header].add(user)
245     def scanForAllArchs(self):
246         """scan for all architectures and return the set of all needed kernel headers"""
247         for arch in self.archs:
248             self.setArch(arch)
249             self.scanForArch()
251         return set(self.needed.keys())
253     def getHeaderUsers(self,header):
254         """return the set of all users for a given header"""
255         return set(self.needed[header])
257     def getArchHeaders(self,arch):
258         """return the set of all <asm/...> headers required by a given architecture"""
259         return set()  # XXX: TODO
261 #####################################################################################
262 #####################################################################################
263 #####                                                                           #####
264 #####           C O N F I G   P A R S E R                                       #####
265 #####                                                                           #####
266 #####################################################################################
267 #####################################################################################
269 class ConfigParser:
270     """a class used to parse the Linux kernel .config file"""
271     re_CONFIG_ = re.compile(r"^(CONFIG_\w+)=(.*)$")
273     def __init__(self):
274         self.items = {}
275         self.duplicates = False
277     def parseLine(self,line):
278         line = string.strip(line)
280         # skip empty and comment lines
281         if len(line) == 0 or line[0] == "#":
282             return
284         m = ConfigParser.re_CONFIG_.match(line)
285         if not m: return
287         name  = m.group(1)
288         value = m.group(2)
290         if name in self.items:  # aarg, duplicate value
291             self.duplicates = True
293         self.items[name] = value
295     def parseFile(self,path):
296         f = file(path, "r")
297         for line in f:
298             if len(line) > 0:
299                 if line[-1] == "\n":
300                     line = line[:-1]
301                     if len(line) > 0 and line[-1] == "\r":
302                         line = line[:-1]
303                 self.parseLine(line)
304         f.close()
306     def getDefinitions(self):
307         """retrieve a dictionary containing definitions for CONFIG_XXX"""
308         return self.items.copy()
310     def __repr__(self):
311         return repr(self.items)
313     def __str__(self):
314         return str(self.items)