1#!/usr/bin/env python 2 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. 8# 9# 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. Add a standard disclaimer: 64# 65# The message: 66# 67# /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ 68# 69# Is prepended to each generated header. 70#------------------------------------------------------------------------------ 71 72import sys, cpp, kernel, glob, os, re, getopt 73from defaults import * 74from utils import * 75 76def print_error(no_update, msg): 77 if no_update: 78 panic(msg) 79 sys.stderr.write("warning: " + msg) 80 81 82def cleanupFile(dst_file, src_file, rel_path, no_update = True): 83 """reads an original header and perform the cleanup operation on it 84 this functions returns the destination path and the clean header 85 as a single string""" 86 # Check the header path 87 if not os.path.exists(src_file): 88 print_error(no_update, "'%s' does not exist\n" % src_file) 89 return None, None 90 91 if not os.path.isfile(src_file): 92 print_error(no_update, "'%s' is not a file\n" % src_file) 93 return None, None 94 95 # Extract the architecture if found. 96 arch = None 97 statics = kernel_known_generic_statics 98 m = re.search(r"(^|/)asm-([\w\d_\+\.\-]+)/.*", rel_path) 99 if m and m.group(2) != 'generic': 100 arch = m.group(2) 101 statics = statics.union(kernel_known_statics.get(arch, set())) 102 103 # Now, let's parse the file. 104 parser = cpp.BlockParser() 105 blocks = parser.parseFile(src_file) 106 if not parser.parsed: 107 print_error(no_update, "Can't parse '%s'" % src_file) 108 return None 109 110 macros = kernel_known_macros.copy() 111 if arch and arch in kernel_default_arch_macros: 112 macros.update(kernel_default_arch_macros[arch]) 113 114 if arch and arch in kernel_arch_token_replacements: 115 blocks.replaceTokens(kernel_arch_token_replacements[arch]) 116 117 blocks.optimizeMacros(macros) 118 blocks.optimizeIf01() 119 blocks.removeVarsAndFuncs(statics) 120 blocks.replaceTokens(kernel_token_replacements) 121 blocks.removeMacroDefines(kernel_ignored_macros) 122 123 out = StringOutput() 124 out.write(kernel_disclaimer) 125 blocks.writeWithWarning(out, kernel_warning, 4) 126 return out.get() 127 128 129if __name__ == "__main__": 130 131 def usage(): 132 print """\ 133 usage: %s [options] <header_path> 134 135 options: 136 -v enable verbose mode 137 138 -u enabled update mode 139 this will try to update the corresponding 'clean header' 140 if the content has changed. with this, you can pass more 141 than one file on the command-line 142 143 -k<path> specify path of original kernel headers 144 -d<path> specify path of cleaned kernel headers 145 146 <header_path> must be in a subdirectory of 'original' 147 """ % os.path.basename(sys.argv[0]) 148 sys.exit(1) 149 150 try: 151 optlist, args = getopt.getopt(sys.argv[1:], 'uvk:d:') 152 except: 153 # unrecognized option 154 sys.stderr.write("error: unrecognized option\n") 155 usage() 156 157 no_update = True 158 dst_dir = get_kernel_dir() 159 src_dir = get_kernel_headers_original_dir() 160 for opt, arg in optlist: 161 if opt == '-u': 162 no_update = False 163 elif opt == '-v': 164 logging.basicConfig(level=logging.DEBUG) 165 elif opt == '-k': 166 src_dir = arg 167 elif opt == '-d': 168 dst_dir = arg 169 170 if len(args) == 0: 171 usage() 172 173 if no_update: 174 for path in args: 175 dst_file = os.path.join(dst_dir, path) 176 src_file = os.path.join(src_dir, path) 177 new_data = cleanupFile(dst_file, src_file, path) 178 print new_data 179 180 sys.exit(0) 181 182 # Now let's update our files. 183 184 b = BatchFileUpdater() 185 186 for path in args: 187 dst_file = os.path.join(dst_dir, path) 188 src_file = os.path.join(src_dir, path) 189 new_data = cleanupFile(dst_file, src_file, path, no_update) 190 if not new_data: 191 continue 192 193 b.readFile(path) 194 r = b.editFile(path, new_data) 195 if r == 0: 196 r = "unchanged" 197 elif r == 1: 198 r = "edited" 199 else: 200 r = "added" 201 202 print "cleaning: %-*s -> %-*s (%s)" % (35, path, 35, path, r) 203 204 205 b.updateGitFiles() 206 207 sys.exit(0) 208