summaryrefslogtreecommitdiff
path: root/libc/kernel/tools/cpp.py
diff options
context:
space:
mode:
Diffstat (limited to 'libc/kernel/tools/cpp.py')
-rwxr-xr-xlibc/kernel/tools/cpp.py263
1 files changed, 240 insertions, 23 deletions
diff --git a/libc/kernel/tools/cpp.py b/libc/kernel/tools/cpp.py
index 1ada59e09..54886413e 100755
--- a/libc/kernel/tools/cpp.py
+++ b/libc/kernel/tools/cpp.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
"""A glorified C pre-processor parser."""
import ctypes
@@ -14,7 +14,7 @@ if top is None:
utils.panic('ANDROID_BUILD_TOP not set.\n')
# Set up the env vars for libclang.
-site.addsitedir(os.path.join(top, 'external/clang/bindings/python'))
+site.addsitedir(os.path.join(top, 'prebuilts/clang/host/linux-x86/clang-stable/lib64/python3/site-packages/'))
import clang.cindex
from clang.cindex import conf
@@ -28,12 +28,9 @@ from clang.cindex import TranslationUnit
# Set up LD_LIBRARY_PATH to include libclang.so, libLLVM.so, and etc.
# Note that setting LD_LIBRARY_PATH with os.putenv() sometimes doesn't help.
-clang.cindex.Config.set_library_file(os.path.join(top, 'prebuilts/sdk/tools/linux/lib64/libclang_android.so'))
+clang.cindex.Config.set_library_file(os.path.join(top, 'prebuilts/clang/host/linux-x86/clang-stable/lib64/libclang.so'))
-from defaults import kCppUndefinedMacro
-from defaults import kernel_remove_config_macros
-from defaults import kernel_struct_replacements
-from defaults import kernel_token_replacements
+from defaults import *
debugBlockParser = False
@@ -257,7 +254,7 @@ class CppTokenizer(object):
token_group = TokenGroup(self._tu, tokens_memory, tokens_count)
tokens = []
- for i in xrange(0, count):
+ for i in range(0, count):
token = Token(self._tu, token_group,
int_data=tokens_array[i].int_data,
ptr_data=tokens_array[i].ptr_data,
@@ -270,7 +267,7 @@ class CppTokenizer(object):
def parseString(self, lines):
"""Parse a list of text lines into a BlockList object."""
- file_ = 'dummy.c'
+ file_ = 'no-filename-available.c'
self._tu = self._indexer.parse(file_, self.clang_flags,
unsaved_files=[(file_, lines)],
options=self.options)
@@ -397,10 +394,10 @@ class CppExpr(object):
self._index = 0
if debugCppExpr:
- print "CppExpr: trying to parse %s" % repr(tokens)
+ print("CppExpr: trying to parse %s" % repr(tokens))
self.expr = self.parseExpression(0)
if debugCppExpr:
- print "CppExpr: got " + repr(self.expr)
+ print("CppExpr: got " + repr(self.expr))
if self._index != self._num_tokens:
self.throw(BadExpectedToken, "crap at end of input (%d != %d): %s"
% (self._index, self._num_tokens, repr(tokens)))
@@ -408,9 +405,9 @@ class CppExpr(object):
def throw(self, exception, msg):
if self._index < self._num_tokens:
tok = self.tokens[self._index]
- print "%d:%d: %s" % (tok.location.line, tok.location.column, msg)
+ print("%d:%d: %s" % (tok.location.line, tok.location.column, msg))
else:
- print "EOF: %s" % msg
+ print("EOF: %s" % msg)
raise exception(msg)
def expectId(self, id):
@@ -725,7 +722,7 @@ class CppExpr(object):
if op == "defined":
op, name = e
- if macros.has_key(name):
+ if name in macros:
if macros[name] == kCppUndefinedMacro:
return ("int", 0)
else:
@@ -742,7 +739,7 @@ class CppExpr(object):
elif op == "ident":
op, name = e
- if macros.has_key(name):
+ if name in macros:
try:
value = int(macros[name])
expanded = ("int", value)
@@ -1182,11 +1179,11 @@ class BlockList(object):
def dump(self):
"""Dump all the blocks in current BlockList."""
- print '##### BEGIN #####'
+ print('##### BEGIN #####')
for i, b in enumerate(self.blocks):
- print '### BLOCK %d ###' % i
- print b
- print '##### END #####'
+ print('### BLOCK %d ###' % i)
+ print(b)
+ print('##### END #####')
def optimizeIf01(self):
"""Remove the code between #if 0 .. #endif in a BlockList."""
@@ -1198,6 +1195,52 @@ class BlockList(object):
if b.isIf():
b.expr.optimize(macros)
+ def removeStructs(self, structs):
+ """Remove structs."""
+ for b in self.blocks:
+ # Have to look in each block for a top-level struct definition.
+ if b.directive:
+ continue
+ num_tokens = len(b.tokens)
+ # A struct definition has at least 5 tokens:
+ # struct
+ # ident
+ # {
+ # }
+ # ;
+ if num_tokens < 5:
+ continue
+ # This is a simple struct finder, it might fail if a top-level
+ # structure has an #if type directives that confuses the algorithm
+ # for finding th end of the structure. Or if there is another
+ # structure definition embedded in the structure.
+ i = 0
+ while i < num_tokens - 2:
+ if (b.tokens[i].kind != TokenKind.KEYWORD or
+ b.tokens[i].id != "struct"):
+ i += 1
+ continue
+ if (b.tokens[i + 1].kind == TokenKind.IDENTIFIER and
+ b.tokens[i + 2].kind == TokenKind.PUNCTUATION and
+ b.tokens[i + 2].id == "{" and b.tokens[i + 1].id in structs):
+ # Search forward for the end of the structure.
+ # Very simple search, look for } and ; tokens. If something
+ # more complicated is needed we can add it later.
+ j = i + 3
+ while j < num_tokens - 1:
+ if (b.tokens[j].kind == TokenKind.PUNCTUATION and
+ b.tokens[j].id == "}" and
+ b.tokens[j + 1].kind == TokenKind.PUNCTUATION and
+ b.tokens[j + 1].id == ";"):
+ b.tokens = b.tokens[0:i] + b.tokens[j + 2:num_tokens]
+ num_tokens = len(b.tokens)
+ j = i
+ break
+ j += 1
+ i = j
+ continue
+ i += 1
+
def optimizeAll(self, macros):
self.optimizeMacros(macros)
self.optimizeIf01()
@@ -1467,7 +1510,7 @@ class BlockParser(object):
while i < len(tokens) and tokens[i].location in extent:
t = tokens[i]
if debugBlockParser:
- print ' ' * 2, t.id, t.kind, t.cursor.kind
+ print(' ' * 2, t.id, t.kind, t.cursor.kind)
if (detect_change and t.cursor.extent != extent and
t.cursor.kind == CursorKind.PREPROCESSING_DIRECTIVE):
break
@@ -1755,7 +1798,6 @@ class OptimizerTests(unittest.TestCase):
def parse(self, text, macros=None):
out = utils.StringOutput()
blocks = BlockParser().parse(CppStringTokenizer(text))
- blocks.replaceTokens(kernel_token_replacements)
blocks.optimizeAll(macros)
blocks.write(out)
return out.get()
@@ -1931,8 +1973,8 @@ class OptimizerTests(unittest.TestCase):
#endif /* SIGRTMAX */
"""
expected = """\
-#ifndef __SIGRTMAX
-#define __SIGRTMAX 123
+#ifndef SIGRTMAX
+#define SIGRTMAX 123
#endif
"""
self.assertEqual(self.parse(text), expected)
@@ -1948,6 +1990,146 @@ class OptimizerTests(unittest.TestCase):
expected = ""
self.assertEqual(self.parse(text), expected)
+class RemoveStructsTests(unittest.TestCase):
+ def parse(self, text, structs):
+ out = utils.StringOutput()
+ blocks = BlockParser().parse(CppStringTokenizer(text))
+ blocks.removeStructs(structs)
+ blocks.write(out)
+ return out.get()
+
+ def test_remove_struct_from_start(self):
+ text = """\
+struct remove {
+ int val1;
+ int val2;
+};
+struct something {
+ struct timeval val1;
+ struct timeval val2;
+};
+"""
+ expected = """\
+struct something {
+ struct timeval val1;
+ struct timeval val2;
+};
+"""
+ self.assertEqual(self.parse(text, set(["remove"])), expected)
+
+ def test_remove_struct_from_end(self):
+ text = """\
+struct something {
+ struct timeval val1;
+ struct timeval val2;
+};
+struct remove {
+ int val1;
+ int val2;
+};
+"""
+ expected = """\
+struct something {
+ struct timeval val1;
+ struct timeval val2;
+};
+"""
+ self.assertEqual(self.parse(text, set(["remove"])), expected)
+
+ def test_remove_minimal_struct(self):
+ text = """\
+struct remove {
+};
+"""
+ expected = "";
+ self.assertEqual(self.parse(text, set(["remove"])), expected)
+
+ def test_remove_struct_with_struct_fields(self):
+ text = """\
+struct something {
+ struct remove val1;
+ struct remove val2;
+};
+struct remove {
+ int val1;
+ struct something val3;
+ int val2;
+};
+"""
+ expected = """\
+struct something {
+ struct remove val1;
+ struct remove val2;
+};
+"""
+ self.assertEqual(self.parse(text, set(["remove"])), expected)
+
+ def test_remove_consecutive_structs(self):
+ text = """\
+struct keep1 {
+ struct timeval val1;
+ struct timeval val2;
+};
+struct remove1 {
+ int val1;
+ int val2;
+};
+struct remove2 {
+ int val1;
+ int val2;
+ int val3;
+};
+struct keep2 {
+ struct timeval val1;
+ struct timeval val2;
+};
+"""
+ expected = """\
+struct keep1 {
+ struct timeval val1;
+ struct timeval val2;
+};
+struct keep2 {
+ struct timeval val1;
+ struct timeval val2;
+};
+"""
+ self.assertEqual(self.parse(text, set(["remove1", "remove2"])), expected)
+
+ def test_remove_multiple_structs(self):
+ text = """\
+struct keep1 {
+ int val;
+};
+struct remove1 {
+ int val1;
+ int val2;
+};
+struct keep2 {
+ int val;
+};
+struct remove2 {
+ struct timeval val1;
+ struct timeval val2;
+};
+struct keep3 {
+ int val;
+};
+"""
+ expected = """\
+struct keep1 {
+ int val;
+};
+struct keep2 {
+ int val;
+};
+struct keep3 {
+ int val;
+};
+"""
+ self.assertEqual(self.parse(text, set(["remove1", "remove2"])), expected)
+
+
class FullPathTest(unittest.TestCase):
"""Test of the full path parsing."""
@@ -1956,9 +2138,12 @@ class FullPathTest(unittest.TestCase):
keep = set()
out = utils.StringOutput()
blocks = BlockParser().parse(CppStringTokenizer(text))
+
+ blocks.removeStructs(kernel_structs_to_remove)
blocks.removeVarsAndFuncs(keep)
blocks.replaceTokens(kernel_token_replacements)
blocks.optimizeAll(None)
+
blocks.write(out)
return out.get()
@@ -2241,6 +2426,38 @@ something that should still be kept
"""
self.assertEqual(self.parse(text), expected)
+ def test_verify_timeval_itemerval(self):
+ text = """\
+struct __kernel_old_timeval {
+ struct something val;
+};
+struct __kernel_old_itimerval {
+ struct __kernel_old_timeval val;
+};
+struct fields {
+ struct __kernel_old_timeval timeval;
+ struct __kernel_old_itimerval itimerval;
+};
+"""
+ expected = """\
+struct fields {
+ struct timeval timeval;
+ struct itimerval itimerval;
+};
+"""
+ self.assertEqual(self.parse(text), expected)
+
+ def test_token_replacement(self):
+ text = """\
+#define SIGRTMIN 32
+#define SIGRTMAX _NSIG
+"""
+ expected = """\
+#define __SIGRTMIN 32
+#define __SIGRTMAX _KERNEL__NSIG
+"""
+ self.assertEqual(self.parse(text), expected)
+
if __name__ == '__main__':
unittest.main()