xref: /aosp_15_r20/bionic/libc/kernel/tools/clean_header.py (revision 8d67ca893c1523eb926b9080dbe4e2ffd2a27ba1)
1*8d67ca89SAndroid Build Coastguard Worker#!/usr/bin/env python3
2*8d67ca89SAndroid Build Coastguard Worker
3*8d67ca89SAndroid Build Coastguard Worker#------------------------------------------------------------------------------
4*8d67ca89SAndroid Build Coastguard Worker# Description of the header clean process
5*8d67ca89SAndroid Build Coastguard Worker#------------------------------------------------------------------------------
6*8d67ca89SAndroid Build Coastguard Worker# Here is the list of actions performed by this script to clean the original
7*8d67ca89SAndroid Build Coastguard Worker# kernel headers.
8*8d67ca89SAndroid Build Coastguard Worker#
9*8d67ca89SAndroid Build Coastguard Worker# 1. Optimize well-known macros (e.g. __KERNEL__, __KERNEL_STRICT_NAMES)
10*8d67ca89SAndroid Build Coastguard Worker#
11*8d67ca89SAndroid Build Coastguard Worker#     This pass gets rid of everything that is guarded by a well-known macro
12*8d67ca89SAndroid Build Coastguard Worker#     definition. This means that a block like:
13*8d67ca89SAndroid Build Coastguard Worker#
14*8d67ca89SAndroid Build Coastguard Worker#        #ifdef __KERNEL__
15*8d67ca89SAndroid Build Coastguard Worker#        ....
16*8d67ca89SAndroid Build Coastguard Worker#        #endif
17*8d67ca89SAndroid Build Coastguard Worker#
18*8d67ca89SAndroid Build Coastguard Worker#     Will be totally omitted from the output. The optimizer is smart enough to
19*8d67ca89SAndroid Build Coastguard Worker#     handle all complex C-preprocessor conditional expression appropriately.
20*8d67ca89SAndroid Build Coastguard Worker#     This means that, for example:
21*8d67ca89SAndroid Build Coastguard Worker#
22*8d67ca89SAndroid Build Coastguard Worker#        #if defined(__KERNEL__) || defined(FOO)
23*8d67ca89SAndroid Build Coastguard Worker#        ...
24*8d67ca89SAndroid Build Coastguard Worker#        #endif
25*8d67ca89SAndroid Build Coastguard Worker#
26*8d67ca89SAndroid Build Coastguard Worker#     Will be transformed into:
27*8d67ca89SAndroid Build Coastguard Worker#
28*8d67ca89SAndroid Build Coastguard Worker#        #ifdef FOO
29*8d67ca89SAndroid Build Coastguard Worker#        ...
30*8d67ca89SAndroid Build Coastguard Worker#        #endif
31*8d67ca89SAndroid Build Coastguard Worker#
32*8d67ca89SAndroid Build Coastguard Worker#     See tools/defaults.py for the list of well-known macros used in this pass,
33*8d67ca89SAndroid Build Coastguard Worker#     in case you need to update it in the future.
34*8d67ca89SAndroid Build Coastguard Worker#
35*8d67ca89SAndroid Build Coastguard Worker#     Note that this also removes any reference to a kernel-specific
36*8d67ca89SAndroid Build Coastguard Worker#     configuration macro like CONFIG_FOO from the clean headers.
37*8d67ca89SAndroid Build Coastguard Worker#
38*8d67ca89SAndroid Build Coastguard Worker#
39*8d67ca89SAndroid Build Coastguard Worker# 2. Remove variable and function declarations:
40*8d67ca89SAndroid Build Coastguard Worker#
41*8d67ca89SAndroid Build Coastguard Worker#   This pass scans non-directive text and only keeps things that look like a
42*8d67ca89SAndroid Build Coastguard Worker#   typedef/struct/union/enum declaration. This allows us to get rid of any
43*8d67ca89SAndroid Build Coastguard Worker#   variables or function declarations that should only be used within the
44*8d67ca89SAndroid Build Coastguard Worker#   kernel anyway (and which normally *should* be guarded by an #ifdef
45*8d67ca89SAndroid Build Coastguard Worker#   __KERNEL__ ...  #endif block, if the kernel writers were not so messy).
46*8d67ca89SAndroid Build Coastguard Worker#
47*8d67ca89SAndroid Build Coastguard Worker#   There are, however, a few exceptions: it is seldom useful to keep the
48*8d67ca89SAndroid Build Coastguard Worker#   definition of some static inline functions performing very simple
49*8d67ca89SAndroid Build Coastguard Worker#   operations. A good example is the optimized 32-bit byte-swap function
50*8d67ca89SAndroid Build Coastguard Worker#   found in:
51*8d67ca89SAndroid Build Coastguard Worker#
52*8d67ca89SAndroid Build Coastguard Worker#     arch-arm/asm/byteorder.h
53*8d67ca89SAndroid Build Coastguard Worker#
54*8d67ca89SAndroid Build Coastguard Worker#   The list of exceptions is in tools/defaults.py in case you need to update
55*8d67ca89SAndroid Build Coastguard Worker#   it in the future.
56*8d67ca89SAndroid Build Coastguard Worker#
57*8d67ca89SAndroid Build Coastguard Worker#   Note that we do *not* remove macro definitions, including these macro that
58*8d67ca89SAndroid Build Coastguard Worker#   perform a call to one of these kernel-header functions, or even define other
59*8d67ca89SAndroid Build Coastguard Worker#   functions. We consider it safe since userland applications have no business
60*8d67ca89SAndroid Build Coastguard Worker#   using them anyway.
61*8d67ca89SAndroid Build Coastguard Worker#
62*8d67ca89SAndroid Build Coastguard Worker#
63*8d67ca89SAndroid Build Coastguard Worker# 3. Add a standard disclaimer:
64*8d67ca89SAndroid Build Coastguard Worker#
65*8d67ca89SAndroid Build Coastguard Worker#   The message:
66*8d67ca89SAndroid Build Coastguard Worker#
67*8d67ca89SAndroid Build Coastguard Worker#   /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
68*8d67ca89SAndroid Build Coastguard Worker#
69*8d67ca89SAndroid Build Coastguard Worker#   Is prepended to each generated header.
70*8d67ca89SAndroid Build Coastguard Worker#------------------------------------------------------------------------------
71*8d67ca89SAndroid Build Coastguard Worker
72*8d67ca89SAndroid Build Coastguard Workerimport sys, cpp, kernel, glob, os, re, getopt, textwrap
73*8d67ca89SAndroid Build Coastguard Workerfrom defaults import *
74*8d67ca89SAndroid Build Coastguard Workerfrom utils import *
75*8d67ca89SAndroid Build Coastguard Worker
76*8d67ca89SAndroid Build Coastguard Workerdef print_error(no_update, msg):
77*8d67ca89SAndroid Build Coastguard Worker    if no_update:
78*8d67ca89SAndroid Build Coastguard Worker        panic(msg)
79*8d67ca89SAndroid Build Coastguard Worker    sys.stderr.write("warning: " + msg)
80*8d67ca89SAndroid Build Coastguard Worker
81*8d67ca89SAndroid Build Coastguard Worker
82*8d67ca89SAndroid Build Coastguard Workerdef cleanupFile(dst_file, src_file, rel_path, no_update = True):
83*8d67ca89SAndroid Build Coastguard Worker    """reads an original header and perform the cleanup operation on it
84*8d67ca89SAndroid Build Coastguard Worker       this functions returns the destination path and the clean header
85*8d67ca89SAndroid Build Coastguard Worker       as a single string"""
86*8d67ca89SAndroid Build Coastguard Worker    # Check the header path
87*8d67ca89SAndroid Build Coastguard Worker    if not os.path.exists(src_file):
88*8d67ca89SAndroid Build Coastguard Worker        print_error(no_update, "'%s' does not exist\n" % src_file)
89*8d67ca89SAndroid Build Coastguard Worker        return None
90*8d67ca89SAndroid Build Coastguard Worker
91*8d67ca89SAndroid Build Coastguard Worker    if not os.path.isfile(src_file):
92*8d67ca89SAndroid Build Coastguard Worker        print_error(no_update, "'%s' is not a file\n" % src_file)
93*8d67ca89SAndroid Build Coastguard Worker        return None
94*8d67ca89SAndroid Build Coastguard Worker
95*8d67ca89SAndroid Build Coastguard Worker    # Extract the architecture if found.
96*8d67ca89SAndroid Build Coastguard Worker    arch = None
97*8d67ca89SAndroid Build Coastguard Worker    m = re.search(r"(^|/)asm-([\w\d_\+\.\-]+)/.*", rel_path)
98*8d67ca89SAndroid Build Coastguard Worker    if m and m.group(2) != 'generic':
99*8d67ca89SAndroid Build Coastguard Worker        arch = m.group(2)
100*8d67ca89SAndroid Build Coastguard Worker
101*8d67ca89SAndroid Build Coastguard Worker    # Now, let's parse the file.
102*8d67ca89SAndroid Build Coastguard Worker    parser = cpp.BlockParser()
103*8d67ca89SAndroid Build Coastguard Worker    blocks = parser.parseFile(src_file)
104*8d67ca89SAndroid Build Coastguard Worker    if not parser.parsed:
105*8d67ca89SAndroid Build Coastguard Worker        print_error(no_update, "Can't parse '%s'" % src_file)
106*8d67ca89SAndroid Build Coastguard Worker        return None
107*8d67ca89SAndroid Build Coastguard Worker
108*8d67ca89SAndroid Build Coastguard Worker    macros = kernel_known_macros.copy()
109*8d67ca89SAndroid Build Coastguard Worker    if arch and arch in kernel_default_arch_macros:
110*8d67ca89SAndroid Build Coastguard Worker        macros.update(kernel_default_arch_macros[arch])
111*8d67ca89SAndroid Build Coastguard Worker
112*8d67ca89SAndroid Build Coastguard Worker    blocks.removeStructs(kernel_structs_to_remove)
113*8d67ca89SAndroid Build Coastguard Worker    blocks.optimizeMacros(macros)
114*8d67ca89SAndroid Build Coastguard Worker    blocks.optimizeIf01()
115*8d67ca89SAndroid Build Coastguard Worker    blocks.removeVarsAndFuncs(kernel_known_generic_statics)
116*8d67ca89SAndroid Build Coastguard Worker    blocks.replaceTokens(kernel_token_replacements)
117*8d67ca89SAndroid Build Coastguard Worker
118*8d67ca89SAndroid Build Coastguard Worker    out = StringOutput()
119*8d67ca89SAndroid Build Coastguard Worker    out.write(textwrap.dedent("""\
120*8d67ca89SAndroid Build Coastguard Worker        /*
121*8d67ca89SAndroid Build Coastguard Worker         * This file is auto-generated. Modifications will be lost.
122*8d67ca89SAndroid Build Coastguard Worker         *
123*8d67ca89SAndroid Build Coastguard Worker         * See https://android.googlesource.com/platform/bionic/+/master/libc/kernel/
124*8d67ca89SAndroid Build Coastguard Worker         * for more information.
125*8d67ca89SAndroid Build Coastguard Worker         */
126*8d67ca89SAndroid Build Coastguard Worker        """))
127*8d67ca89SAndroid Build Coastguard Worker    blocks.write(out)
128*8d67ca89SAndroid Build Coastguard Worker    return out.get()
129*8d67ca89SAndroid Build Coastguard Worker
130*8d67ca89SAndroid Build Coastguard Worker
131*8d67ca89SAndroid Build Coastguard Workerif __name__ == "__main__":
132*8d67ca89SAndroid Build Coastguard Worker
133*8d67ca89SAndroid Build Coastguard Worker    def usage():
134*8d67ca89SAndroid Build Coastguard Worker        print("""\
135*8d67ca89SAndroid Build Coastguard Worker    usage:  %s [options] <header_path>
136*8d67ca89SAndroid Build Coastguard Worker
137*8d67ca89SAndroid Build Coastguard Worker        options:
138*8d67ca89SAndroid Build Coastguard Worker            -v    enable verbose mode
139*8d67ca89SAndroid Build Coastguard Worker
140*8d67ca89SAndroid Build Coastguard Worker            -u    enabled update mode
141*8d67ca89SAndroid Build Coastguard Worker                this will try to update the corresponding 'clean header'
142*8d67ca89SAndroid Build Coastguard Worker                if the content has changed. with this, you can pass more
143*8d67ca89SAndroid Build Coastguard Worker                than one file on the command-line
144*8d67ca89SAndroid Build Coastguard Worker
145*8d67ca89SAndroid Build Coastguard Worker            -k<path>  specify path of original kernel headers
146*8d67ca89SAndroid Build Coastguard Worker            -d<path>  specify path of cleaned kernel headers
147*8d67ca89SAndroid Build Coastguard Worker
148*8d67ca89SAndroid Build Coastguard Worker        <header_path> must be in a subdirectory of 'original'
149*8d67ca89SAndroid Build Coastguard Worker    """ % os.path.basename(sys.argv[0]))
150*8d67ca89SAndroid Build Coastguard Worker        sys.exit(1)
151*8d67ca89SAndroid Build Coastguard Worker
152*8d67ca89SAndroid Build Coastguard Worker    try:
153*8d67ca89SAndroid Build Coastguard Worker        optlist, args = getopt.getopt(sys.argv[1:], 'uvk:d:')
154*8d67ca89SAndroid Build Coastguard Worker    except:
155*8d67ca89SAndroid Build Coastguard Worker        # unrecognized option
156*8d67ca89SAndroid Build Coastguard Worker        sys.stderr.write("error: unrecognized option\n")
157*8d67ca89SAndroid Build Coastguard Worker        usage()
158*8d67ca89SAndroid Build Coastguard Worker
159*8d67ca89SAndroid Build Coastguard Worker    no_update = True
160*8d67ca89SAndroid Build Coastguard Worker    dst_dir = None
161*8d67ca89SAndroid Build Coastguard Worker    src_dir = None
162*8d67ca89SAndroid Build Coastguard Worker    for opt, arg in optlist:
163*8d67ca89SAndroid Build Coastguard Worker        if opt == '-u':
164*8d67ca89SAndroid Build Coastguard Worker            no_update = False
165*8d67ca89SAndroid Build Coastguard Worker        elif opt == '-v':
166*8d67ca89SAndroid Build Coastguard Worker            logging.basicConfig(level=logging.DEBUG)
167*8d67ca89SAndroid Build Coastguard Worker        elif opt == '-k':
168*8d67ca89SAndroid Build Coastguard Worker            src_dir = arg
169*8d67ca89SAndroid Build Coastguard Worker        elif opt == '-d':
170*8d67ca89SAndroid Build Coastguard Worker            dst_dir = arg
171*8d67ca89SAndroid Build Coastguard Worker    # get_kernel_dir() and get_kernel_headers_original_dir() require the current
172*8d67ca89SAndroid Build Coastguard Worker    # working directory to be a direct or indirect subdirectory of
173*8d67ca89SAndroid Build Coastguard Worker    # ANDROID_BUILD_TOP.  Otherwise, these functions print an error message and
174*8d67ca89SAndroid Build Coastguard Worker    # exit.  Let's allow the user to run this program from an unrelated
175*8d67ca89SAndroid Build Coastguard Worker    # directory, if they specify src_dir and dst_dir on the command line.
176*8d67ca89SAndroid Build Coastguard Worker    if dst_dir is None:
177*8d67ca89SAndroid Build Coastguard Worker      dst_dir = get_kernel_dir()
178*8d67ca89SAndroid Build Coastguard Worker    if src_dir is None:
179*8d67ca89SAndroid Build Coastguard Worker      src_dir = get_kernel_headers_original_dir()
180*8d67ca89SAndroid Build Coastguard Worker
181*8d67ca89SAndroid Build Coastguard Worker    if len(args) == 0:
182*8d67ca89SAndroid Build Coastguard Worker        usage()
183*8d67ca89SAndroid Build Coastguard Worker
184*8d67ca89SAndroid Build Coastguard Worker    if no_update:
185*8d67ca89SAndroid Build Coastguard Worker        for path in args:
186*8d67ca89SAndroid Build Coastguard Worker            dst_file = os.path.join(dst_dir, path)
187*8d67ca89SAndroid Build Coastguard Worker            src_file = os.path.join(src_dir, path)
188*8d67ca89SAndroid Build Coastguard Worker            new_data = cleanupFile(dst_file, src_file, path)
189*8d67ca89SAndroid Build Coastguard Worker            # Use sys.stdout.write instead of a simple print statement to avoid
190*8d67ca89SAndroid Build Coastguard Worker            # sending an extra new line character to stdout.  Running this
191*8d67ca89SAndroid Build Coastguard Worker            # program in non-update mode and redirecting stdout to a file should
192*8d67ca89SAndroid Build Coastguard Worker            # yield the same result as using update mode, where new_data is
193*8d67ca89SAndroid Build Coastguard Worker            # written directly to a file.
194*8d67ca89SAndroid Build Coastguard Worker            sys.stdout.write(new_data)
195*8d67ca89SAndroid Build Coastguard Worker
196*8d67ca89SAndroid Build Coastguard Worker        sys.exit(0)
197*8d67ca89SAndroid Build Coastguard Worker
198*8d67ca89SAndroid Build Coastguard Worker    # Now let's update our files.
199*8d67ca89SAndroid Build Coastguard Worker
200*8d67ca89SAndroid Build Coastguard Worker    b = BatchFileUpdater()
201*8d67ca89SAndroid Build Coastguard Worker
202*8d67ca89SAndroid Build Coastguard Worker    for path in args:
203*8d67ca89SAndroid Build Coastguard Worker        dst_file = os.path.join(dst_dir, path)
204*8d67ca89SAndroid Build Coastguard Worker        src_file = os.path.join(src_dir, path)
205*8d67ca89SAndroid Build Coastguard Worker        new_data = cleanupFile(dst_file, src_file, path, no_update)
206*8d67ca89SAndroid Build Coastguard Worker        if not new_data:
207*8d67ca89SAndroid Build Coastguard Worker            continue
208*8d67ca89SAndroid Build Coastguard Worker
209*8d67ca89SAndroid Build Coastguard Worker        b.readFile(dst_file)
210*8d67ca89SAndroid Build Coastguard Worker        r = b.editFile(dst_file, new_data)
211*8d67ca89SAndroid Build Coastguard Worker        if r == 0:
212*8d67ca89SAndroid Build Coastguard Worker            r = "unchanged"
213*8d67ca89SAndroid Build Coastguard Worker        elif r == 1:
214*8d67ca89SAndroid Build Coastguard Worker            r = "edited"
215*8d67ca89SAndroid Build Coastguard Worker        else:
216*8d67ca89SAndroid Build Coastguard Worker            r = "added"
217*8d67ca89SAndroid Build Coastguard Worker
218*8d67ca89SAndroid Build Coastguard Worker        print("cleaning: %-*s -> %-*s (%s)" % (35, path, 35, path, r))
219*8d67ca89SAndroid Build Coastguard Worker
220*8d67ca89SAndroid Build Coastguard Worker    b.updateFiles()
221*8d67ca89SAndroid Build Coastguard Worker
222*8d67ca89SAndroid Build Coastguard Worker    sys.exit(0)
223