blob: ebebe80f9f7670c297369427183617de684322c2 [file] [log] [blame]
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001#!/usr/bin/env python
Christopher Ferris08b60742014-06-05 11:17:06 -07002
3#------------------------------------------------------------------------------
4# Description of the header clean process
5#------------------------------------------------------------------------------
6# Here is the list of actions performed by this script to clean the original
7# kernel headers.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08008#
Christopher Ferris08b60742014-06-05 11:17:06 -07009# 1. Optimize well-known macros (e.g. __KERNEL__, __KERNEL_STRICT_NAMES)
10#
11# This pass gets rid of everything that is guarded by a well-known macro
12# definition. This means that a block like:
13#
14# #ifdef __KERNEL__
15# ....
16# #endif
17#
18# Will be totally omitted from the output. The optimizer is smart enough to
19# handle all complex C-preprocessor conditional expression appropriately.
20# This means that, for example:
21#
22# #if defined(__KERNEL__) || defined(FOO)
23# ...
24# #endif
25#
26# Will be transformed into:
27#
28# #ifdef FOO
29# ...
30# #endif
31#
32# See tools/defaults.py for the list of well-known macros used in this pass,
33# in case you need to update it in the future.
34#
35# Note that this also removes any reference to a kernel-specific
36# configuration macro like CONFIG_FOO from the clean headers.
37#
38#
39# 2. Remove variable and function declarations:
40#
41# This pass scans non-directive text and only keeps things that look like a
42# typedef/struct/union/enum declaration. This allows us to get rid of any
43# variables or function declarations that should only be used within the
44# kernel anyway (and which normally *should* be guarded by an #ifdef
45# __KERNEL__ ... #endif block, if the kernel writers were not so messy).
46#
47# There are, however, a few exceptions: it is seldom useful to keep the
48# definition of some static inline functions performing very simple
49# operations. A good example is the optimized 32-bit byte-swap function
50# found in:
51#
52# arch-arm/asm/byteorder.h
53#
54# The list of exceptions is in tools/defaults.py in case you need to update
55# it in the future.
56#
57# Note that we do *not* remove macro definitions, including these macro that
58# perform a call to one of these kernel-header functions, or even define other
59# functions. We consider it safe since userland applications have no business
60# using them anyway.
61#
62#
63# 3. Whitespace cleanup:
64#
65# The final pass removes any comments and empty lines from the final headers.
66#
67#
68# 4. Add a standard disclaimer:
69#
70# The message:
71#
72# /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
73#
74# Is prepended to each generated header.
75#------------------------------------------------------------------------------
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080076
77import sys, cpp, kernel, glob, os, re, getopt
78from defaults import *
79from utils import *
80
81noUpdate = 1
82
Elliott Hughesfddbafd2014-05-01 10:17:27 -070083def cleanupFile(path, original_path):
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080084 """reads an original header and perform the cleanup operation on it
85 this functions returns the destination path and the clean header
86 as a single string"""
87 # check the header path
David 'Digit' Turnerfc269312010-10-11 22:11:06 +020088 src_path = path
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080089
90 if not os.path.exists(src_path):
91 if noUpdate:
92 panic( "file does not exist: '%s'\n" % path )
93 sys.stderr.write( "warning: file does not exit: %s\n" % path )
94 return None, None
95
96 if not os.path.isfile(src_path):
97 if noUpdate:
98 panic( "path is not a file: '%s'\n" % path )
99 sys.stderr.write( "warning: not a file: %s\n" % path )
100 return None, None
101
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800102 if os.path.commonprefix( [ src_path, original_path ] ) != original_path:
103 if noUpdate:
104 panic( "file is not in 'original' directory: %s\n" % path );
105 sys.stderr.write( "warning: file not in 'original' ignored: %s\n" % path )
106 return None, None
107
108 src_path = src_path[len(original_path):]
109 if len(src_path) > 0 and src_path[0] == '/':
110 src_path = src_path[1:]
111
112 if len(src_path) == 0:
Glenn Kastenc61f9902011-12-19 11:27:50 -0800113 panic( "oops, internal error, can't extract correct relative path\n" )
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800114
115 # convert into destination path, extracting architecture if needed
116 # and the corresponding list of known static functions
117 #
118 arch = None
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800119 statics = kernel_known_generic_statics
Ben Cheng8bea2b62013-10-16 15:28:56 -0700120 m = re.match(r"asm-([\w\d_\+\.\-]+)(/.*)", src_path)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800121 if m and m.group(1) != 'generic':
122 dst_path = "arch-%s/asm/%s" % m.groups()
123 arch = m.group(1)
124 statics = statics.union( kernel_known_statics.get( arch, set() ) )
125 else:
Ben Cheng8bea2b62013-10-16 15:28:56 -0700126 # process headers under the uapi directory
127 # note the "asm" level has been explicitly added in the original
128 # kernel header tree for architectural-dependent uapi headers
129 m_uapi = re.match(r"(uapi)/([\w\d_\+\.\-]+)(/.*)", src_path)
130 if m_uapi:
131 dst_path = src_path
132 m_uapi_arch = re.match(r"asm-([\w\d_\+\.\-]+)", m_uapi.group(2))
133 if m_uapi_arch and m_uapi_arch.group(1) != 'generic':
134 arch = m_uapi_arch.group(1)
135 statics = statics.union( kernel_known_statics.get( arch, set() ) )
136 # common headers (ie non-asm and non-uapi)
137 else:
138 dst_path = "common/" + src_path
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800139
David 'Digit' Turnerfc269312010-10-11 22:11:06 +0200140 dst_path = os.path.normpath( kernel_cleaned_path + "/" + dst_path )
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800141
142 # now, let's parse the file
143 #
David 'Digit' Turnerfc269312010-10-11 22:11:06 +0200144 blocks = cpp.BlockParser().parseFile(path)
145 if not blocks:
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800146 sys.stderr.write( "error: can't parse '%s'" % path )
147 sys.exit(1)
148
Andrew Hsieh126601d2012-03-23 23:07:36 +0800149 macros = kernel_known_macros.copy()
150 if arch and arch in kernel_default_arch_macros:
151 macros.update(kernel_default_arch_macros[arch])
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800152
Raghu Gandhama864c2c2013-01-16 16:42:47 -0800153 if arch and arch in kernel_arch_token_replacements:
154 blocks.replaceTokens( kernel_arch_token_replacements[arch] )
155
Andrew Hsieh126601d2012-03-23 23:07:36 +0800156 blocks.optimizeMacros( macros )
David 'Digit' Turnerfc269312010-10-11 22:11:06 +0200157 blocks.optimizeIf01()
158 blocks.removeVarsAndFuncs( statics )
159 blocks.replaceTokens( kernel_token_replacements )
160 blocks.removeComments()
161 blocks.removeMacroDefines( kernel_ignored_macros )
162 blocks.removeWhiteSpace()
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800163
164 out = StringOutput()
David 'Digit' Turnerfc269312010-10-11 22:11:06 +0200165 out.write( kernel_disclaimer )
166 blocks.writeWithWarning(out, kernel_warning, 4)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800167 return dst_path, out.get()
168
169
170if __name__ == "__main__":
171
172 def usage():
173 print """\
174 usage: %s [options] <header_path>
175
176 options:
177 -v enable verbose mode
178
179 -u enabled update mode
180 this will try to update the corresponding 'clean header'
181 if the content has changed. with this, you can pass more
182 than one file on the command-line
183
David 'Digit' Turnerfc269312010-10-11 22:11:06 +0200184 -k<path> specify path of original kernel headers
185 -d<path> specify path of cleaned kernel headers
186
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800187 <header_path> must be in a subdirectory of 'original'
188 """ % os.path.basename(sys.argv[0])
189 sys.exit(1)
190
191 try:
David 'Digit' Turnerfc269312010-10-11 22:11:06 +0200192 optlist, args = getopt.getopt( sys.argv[1:], 'uvk:d:' )
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800193 except:
194 # unrecognized option
195 sys.stderr.write( "error: unrecognized option\n" )
196 usage()
197
198 for opt, arg in optlist:
199 if opt == '-u':
200 noUpdate = 0
201 elif opt == '-v':
Elliott Hughesdc1fb702014-08-20 11:16:11 -0700202 logging.basicConfig(level=logging.DEBUG)
Dima Zavin4c4a9632009-08-05 17:55:30 -0700203 elif opt == '-k':
204 kernel_original_path = arg
David 'Digit' Turnerfc269312010-10-11 22:11:06 +0200205 elif opt == '-d':
206 kernel_cleaned_path = arg
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800207
208 if len(args) == 0:
209 usage()
210
211 if noUpdate:
212 for path in args:
Frank Maker7b6795d2011-05-25 11:07:04 -0700213 dst_path, newdata = cleanupFile(path,kernel_original_path)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800214 print newdata
215
216 sys.exit(0)
217
218 # now let's update our files.
219
220 b = BatchFileUpdater()
221
222 for path in args:
Frank Maker7b6795d2011-05-25 11:07:04 -0700223 dst_path, newdata = cleanupFile(path,kernel_original_path)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800224 if not dst_path:
225 continue
226
227 b.readFile( dst_path )
228 r = b.editFile( dst_path, newdata )
229 if r == 0:
230 r = "unchanged"
231 elif r == 1:
232 r = "edited"
233 else:
234 r = "added"
235
236 print "cleaning: %-*s -> %-*s (%s)" % ( 35, path, 35, dst_path, r )
237
238
David 'Digit' Turnerfc269312010-10-11 22:11:06 +0200239 b.updateGitFiles()
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800240
241 sys.exit(0)