Commit e5dd87c4 authored by Chris Mumford's avatar Chris Mumford Committed by Commit Bot

sqlite: Corrected formatting of Python scripts.

Corrected indent to be four spaces IAW the style guide. Doing this
makes all Python scripts uniformaly formatted in //third_party/sqlite/scripts.

Bug: None
Change-Id: I476654c330bf957e0ad65d46c44df53e1eacdf2d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2150236Reviewed-by: default avatarDarwin Huang <huangdarwin@chromium.org>
Commit-Queue: Chris Mumford <cmumford@google.com>
Cr-Commit-Position: refs/heads/master@{#759702}
parent e13e0b1b
# TODO(cmumford): Format older files in a future CL.
extract_sqlite_api.py
extract_sqlite_api_unittest.py
...@@ -3,7 +3,6 @@ ...@@ -3,7 +3,6 @@
# Copyright 2018 The Chromium Authors. All rights reserved. # Copyright 2018 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be # Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file. # found in the LICENSE file.
''' '''
Parses SQLite source code and produces renaming macros for its exported symbols. Parses SQLite source code and produces renaming macros for its exported symbols.
...@@ -18,136 +17,144 @@ For example, the following renaming macro is produced for sqlite3_initialize(). ...@@ -18,136 +17,144 @@ For example, the following renaming macro is produced for sqlite3_initialize().
import re import re
import sys import sys
class ExtractError(ValueError): class ExtractError(ValueError):
def __init__(self, message): def __init__(self, message):
self.message = message self.message = message
def ExtractLineTuples(string): def ExtractLineTuples(string):
'''Returns a list of lines, with start/end whitespace stripped. '''Returns a list of lines, with start/end whitespace stripped.
Each line is a tuple of (line number, string). Each line is a tuple of (line number, string).
''' '''
raw_lines = string.split('\n') raw_lines = string.split('\n')
stripped_lines = [line.strip() for line in raw_lines] stripped_lines = [line.strip() for line in raw_lines]
return list(enumerate(stripped_lines, start=1)) return list(enumerate(stripped_lines, start=1))
def ExtractPreprocessorDirectives(lines):
'''Extracts preprocessor directives from lines of C code.
Each input line should be a tuple of (line number, string).
Returns a list of preprocessor directives, and a list of C code lines with the
preprocessor directives removed. The returned code lines are a subset of the
input tuples.
'''
code_lines = []
directives = []
in_directive = False
last_directive = []
for line_tuple in lines:
line = line_tuple[1]
# Preprocessor directives start with #.
if not in_directive:
if len(line) > 0 and line[0] == '#':
in_directive = True
last_directive = []
# Preprocessor directives use \ as a line continuation character.
if in_directive:
if line[-1] == '\\':
line = line[:-1]
else:
in_directive = False
last_directive.append(line)
if not in_directive:
directives.append('\n'.join(last_directive))
else:
code_lines.append(line_tuple)
return directives, code_lines def ExtractPreprocessorDirectives(lines):
'''Extracts preprocessor directives from lines of C code.
Each input line should be a tuple of (line number, string).
Returns a list of preprocessor directives, and a list of C code lines with
the preprocessor directives removed. The returned code lines are a subset
of the input tuples.
'''
code_lines = []
directives = []
in_directive = False
last_directive = []
for line_tuple in lines:
line = line_tuple[1]
# Preprocessor directives start with #.
if not in_directive:
if len(line) > 0 and line[0] == '#':
in_directive = True
last_directive = []
# Preprocessor directives use \ as a line continuation character.
if in_directive:
if line[-1] == '\\':
line = line[:-1]
else:
in_directive = False
last_directive.append(line)
if not in_directive:
directives.append('\n'.join(last_directive))
else:
code_lines.append(line_tuple)
return directives, code_lines
# Regular expression used to parse a macro definition. # Regular expression used to parse a macro definition.
DEFINITION_RE = re.compile(r'^\#\s*define\s+(\w+)(\s|$)') DEFINITION_RE = re.compile(r'^\#\s*define\s+(\w+)(\s|$)')
def ExtractDefineMacroName(line): def ExtractDefineMacroName(line):
'''Extracts the macro name from a non-function preprocessor definition. '''Extracts the macro name from a non-function preprocessor definition.
Returns None if the preprocessor line is not a preprocessor macro definition. Returns None if the preprocessor line is not a preprocessor macro
Macro functions are not considered preprocessor definitions. definition. Macro functions are not considered preprocessor definitions.
''' '''
match = DEFINITION_RE.match(line) match = DEFINITION_RE.match(line)
if match is None: if match is None:
return None return None
return match.group(1) return match.group(1)
# Matches C++-style // single-line comments. # Matches C++-style // single-line comments.
SINGLE_LINE_COMMENT_RE = re.compile(r'//.*$') SINGLE_LINE_COMMENT_RE = re.compile(r'//.*$')
# Matches C-style /* multi-line comments */. # Matches C-style /* multi-line comments */.
MULTI_LINE_COMMENT_RE = re.compile(r'/\*.*?\*/', flags=re.MULTILINE|re.DOTALL) MULTI_LINE_COMMENT_RE = re.compile(
r'/\*.*?\*/', flags=re.MULTILINE | re.DOTALL)
def RemoveLineComments(line): def RemoveLineComments(line):
'''Returns the given C code line with comments removed. '''Returns the given C code line with comments removed.
This handles both C-style /* comments */ and C++-style // comments, but cannot This handles both C-style /* comments */ and C++-style // comments, but
tackle C-style comments that extend over multiple lines. cannot tackle C-style comments that extend over multiple lines.
''' '''
return SINGLE_LINE_COMMENT_RE.sub('', MULTI_LINE_COMMENT_RE.sub('', line)) return SINGLE_LINE_COMMENT_RE.sub('', MULTI_LINE_COMMENT_RE.sub('', line))
def RemoveComments(code_tuples): def RemoveComments(code_tuples):
'Returns the given C code tuples with all comments removed.' 'Returns the given C code tuples with all comments removed.'
output_tuples = [] output_tuples = []
in_comment = False in_comment = False
for line_number, line in code_tuples: for line_number, line in code_tuples:
if in_comment: if in_comment:
if '*/' in line: if '*/' in line:
_, line = line.split('*/', 1) _, line = line.split('*/', 1)
in_comment = False in_comment = False
if not in_comment: if not in_comment:
line = RemoveLineComments(line) line = RemoveLineComments(line)
if '/*' in line: if '/*' in line:
line, _ = line.split('/*', 1) line, _ = line.split('/*', 1)
in_comment = True in_comment = True
output_tuples.append((line_number, line)) output_tuples.append((line_number, line))
return output_tuples return output_tuples
# Splits a line of C code into statement pieces. # Splits a line of C code into statement pieces.
STATEMENT_BREAK_RE = re.compile(r'[;{}]') STATEMENT_BREAK_RE = re.compile(r'[;{}]')
def ToStatementTuples(code_tuples): def ToStatementTuples(code_tuples):
'''Converts C code lines into statements. '''Converts C code lines into statements.
The input is tuples of (line number, line code string). The output is The input is tuples of (line number, line code string). The output is
tuples of (min line, max line, statement). tuples of (min line, max line, statement).
The function considers ; { and } to be statement separators. This is The function considers ; { and } to be statement separators. This is
sufficiently correct, given our goal. sufficiently correct, given our goal.
''' '''
statements = [] statements = []
current_statement = '' current_statement = ''
current_start = 0 current_start = 0
for line_number, line in code_tuples: for line_number, line in code_tuples:
pieces = STATEMENT_BREAK_RE.split(line) pieces = STATEMENT_BREAK_RE.split(line)
for piece in pieces[:-1]: # The last piece is an unfinished statement. for piece in pieces[:-1]: # The last piece is an unfinished statement.
if current_statement != '': if current_statement != '':
current_statement = current_statement + '\n' + piece current_statement = current_statement + '\n' + piece
statements.append( statements.append((current_start, line_number,
(current_start, line_number, current_statement.strip())) current_statement.strip()))
current_statement = '' current_statement = ''
else: else:
statements.append((line_number, line_number, piece.strip())) statements.append((line_number, line_number, piece.strip()))
if current_statement == '': if current_statement == '':
current_start = line_number current_start = line_number
if pieces[-1] != '': if pieces[-1] != '':
current_statement = current_statement + '\n' + pieces[-1] current_statement = current_statement + '\n' + pieces[-1]
return statements return statements
# Used to break down a line into words. # Used to break down a line into words.
...@@ -159,12 +166,7 @@ WHITESPACE_RE = re.compile(r'\s+') ...@@ -159,12 +166,7 @@ WHITESPACE_RE = re.compile(r'\s+')
# them before incorporating them into exported symbols. We can avoid matching # them before incorporating them into exported symbols. We can avoid matching
# curly braces because we do not support enum, struct, or union, and we only # curly braces because we do not support enum, struct, or union, and we only
# need to consider declarations involving typedef names and primitive types. # need to consider declarations involving typedef names and primitive types.
UNSUPPORTED_KEYWORDS = set([ UNSUPPORTED_KEYWORDS = set(['enum', 'struct', 'union', 'typedef'])
'enum',
'struct',
'union',
'typedef'
])
# Type qualifiers that we can skip over. # Type qualifiers that we can skip over.
# #
...@@ -172,12 +174,12 @@ UNSUPPORTED_KEYWORDS = set([ ...@@ -172,12 +174,12 @@ UNSUPPORTED_KEYWORDS = set([
# finding the end of declaration specifiers, they are not needed. This # finding the end of declaration specifiers, they are not needed. This
# additionally discards any pointer type qualifiers. # additionally discards any pointer type qualifiers.
QUALIFIER_KEYWORDS = set([ QUALIFIER_KEYWORDS = set([
'extern', 'extern',
'static', 'static',
'auto', 'auto',
'register', 'register',
'const', 'const',
'volatile', 'volatile',
]) ])
# Keywords used in composite primitive types. # Keywords used in composite primitive types.
...@@ -185,156 +187,161 @@ QUALIFIER_KEYWORDS = set([ ...@@ -185,156 +187,161 @@ QUALIFIER_KEYWORDS = set([
# Types using these keywords may have more than one keyword, e.g. # Types using these keywords may have more than one keyword, e.g.
# "long long int". # "long long int".
COMPOSITE_TYPE_SPECIFIERS = set([ COMPOSITE_TYPE_SPECIFIERS = set([
'char', 'char',
'short', 'short',
'int', 'int',
'long', 'long',
'float', 'float',
'double', 'double',
'signed', 'signed',
'unsigned', 'unsigned',
]) ])
# Matches an identifier. # Matches an identifier.
IDENTIFIER_RE = re.compile(r'^[a-zA-Z_0-9]+$') IDENTIFIER_RE = re.compile(r'^[a-zA-Z_0-9]+$')
def ExtractApiExport(macro_names, api_export_macro, statement): def ExtractApiExport(macro_names, api_export_macro, statement):
'''Extracts the symbol name from a statement exporting a function. '''Extracts the symbol name from a statement exporting a function.
Returns None if the statement does not export a symbol. Throws ExtractError if Returns None if the statement does not export a symbol. Throws ExtractError
the parser cannot understand the statement. if the parser cannot understand the statement.
''' '''
# See http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf, section 6.7 # See http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf, section 6.7
# for how to parse C declarations. Note that a declaration is a number of # for how to parse C declarations. Note that a declaration is a number of
# declaration-specifiers, followed by a list of declarators with optional # declaration-specifiers, followed by a list of declarators with optional
# initializer. Multiple declarators would be a declaration like: # initializer. Multiple declarators would be a declaration like:
# #
# int a, b; # int a, b;
# #
# While, in principle, one could declare a pair of C functions like this, no # While, in principle, one could declare a pair of C functions like this, no
# one does it. We assume there is only one declarator. # one does it. We assume there is only one declarator.
# #
# int foo(int), bar(int, int); # int foo(int), bar(int, int);
# #
# Jumping to section 6.7.5, a declarator includes some optional pointer # Jumping to section 6.7.5, a declarator includes some optional pointer
# specifiers (which may have type qualifiers like 'const' embedded, e.g. 'int # specifiers (which may have type qualifiers like 'const' embedded, e.g. 'int
# * const * const foo') and some grouping. Note, however, that in all cases, # * const * const foo') and some grouping. Note, however, that in all cases,
# the declaration name is the first non-type-qualifier identifier. # the declaration name is the first non-type-qualifier identifier.
# #
# Thus our goal is to skip the declaration specifiers and get to the # Thus our goal is to skip the declaration specifiers and get to the
# declarators. # declarators.
# Simplification: get rid of pointer characters. # Simplification: get rid of pointer characters.
statement = statement.replace('*', ' ') statement = statement.replace('*', ' ')
# Simplification: make sure each open parenthesis is each own word. # Simplification: make sure each open parenthesis is each own word.
statement = statement.replace('(', ' ( ') statement = statement.replace('(', ' ( ')
statement = statement.replace('[', ' [ ') statement = statement.replace('[', ' [ ')
words = WHITESPACE_RE.split(statement) words = WHITESPACE_RE.split(statement)
# Ignore statements that don't deal with exporting symbols. # Ignore statements that don't deal with exporting symbols.
if api_export_macro not in words: if api_export_macro not in words:
return None return None
seen_composite_type = False seen_composite_type = False
seen_simple_type = False seen_simple_type = False
for word in words: for word in words:
if word in UNSUPPORTED_KEYWORDS: if word in UNSUPPORTED_KEYWORDS:
raise ExtractError("Unsupported keyword %s" % word) raise ExtractError("Unsupported keyword %s" % word)
if word in QUALIFIER_KEYWORDS: if word in QUALIFIER_KEYWORDS:
continue continue
# Per section 6.7.2, we must have at least one type specifier (so the first # Per section 6.7.2, we must have at least one type specifier (so the first
# token is one). Moreover, clause 2 implies that if we have a typedef name, # token is one). Moreover, clause 2 implies that if we have a typedef name,
# enum, struct, or union, it is the only type specifier. If we have a # enum, struct, or union, it is the only type specifier. If we have a
# keyword such as 'int', we may have one or more of such keywords. # keyword such as 'int', we may have one or more of such keywords.
if word in COMPOSITE_TYPE_SPECIFIERS: if word in COMPOSITE_TYPE_SPECIFIERS:
if seen_simple_type: if seen_simple_type:
raise ExtractError('Mixed simple (struct_name) and composite (int) types') raise ExtractError(
seen_composite_type = True 'Mixed simple (struct_name) and composite (int) types')
continue seen_composite_type = True
continue
# We assume that macros are only used for qualifiers, which can be skipped.
if word in macro_names or word == api_export_macro: # We assume that macros are only used for qualifiers, which can be skipped.
continue if word in macro_names or word == api_export_macro:
continue
if not seen_composite_type and not seen_simple_type:
seen_simple_type = True if not seen_composite_type and not seen_simple_type:
if IDENTIFIER_RE.match(word) is None: seen_simple_type = True
raise ExtractError( if IDENTIFIER_RE.match(word) is None:
"%s parsed as type name, which doesn't make sense" % word) raise ExtractError(
continue "%s parsed as type name, which doesn't make sense" % word)
continue
if IDENTIFIER_RE.match(word) is None:
raise ExtractError( if IDENTIFIER_RE.match(word) is None:
"%s parsed as symbol name, which doesn't make sense" % word) raise ExtractError(
return word "%s parsed as symbol name, which doesn't make sense" % word)
return word
raise ExtractError('Failed to find symbol name')
raise ExtractError('Failed to find symbol name')
def ExportedSymbolLine(symbol_prefix, symbol, statement_tuple): def ExportedSymbolLine(symbol_prefix, symbol, statement_tuple):
'Returns an output line for an exported symbol.' 'Returns an output line for an exported symbol.'
if statement_tuple[0] == statement_tuple[1]: if statement_tuple[0] == statement_tuple[1]:
lines = 'Line %d' % statement_tuple[0] lines = 'Line %d' % statement_tuple[0]
else: else:
lines = 'Lines %d-%d' % (statement_tuple[0], statement_tuple[1]) lines = 'Lines %d-%d' % (statement_tuple[0], statement_tuple[1])
return '#define %s %s%s // %s' % (symbol, symbol_prefix, symbol, lines) return '#define %s %s%s // %s' % (symbol, symbol_prefix, symbol, lines)
def ExportedExceptionLine(exception, statement_tuple): def ExportedExceptionLine(exception, statement_tuple):
'Returns an output line for a parsing failure.' 'Returns an output line for a parsing failure.'
# Output a TODO without a name so the broken parsing result doesn't # Output a TODO without a name so the broken parsing result doesn't
# accidentally get checked in. # accidentally get checked in.
return '// TODO: Lines %d-%d -- %s' % ( return '// TODO: Lines %d-%d -- %s' % (
statement_tuple[0], statement_tuple[1], exception.message) statement_tuple[0], statement_tuple[1], exception.message)
def ProcessSource(api_export_macro, symbol_prefix, header_line, footer_line, def ProcessSource(api_export_macro, symbol_prefix, header_line, footer_line,
file_content): file_content):
'Returns a list of lines that rename exported symbols in an C program file.' 'Returns a list of lines that rename exported symbols in an C program file.'
line_tuples = ExtractLineTuples(file_content) line_tuples = ExtractLineTuples(file_content)
line_tuples = RemoveComments(line_tuples) line_tuples = RemoveComments(line_tuples)
directives, code_tuples = ExtractPreprocessorDirectives(line_tuples) directives, code_tuples = ExtractPreprocessorDirectives(line_tuples)
macro_names = set( macro_names = set(
name for name in name for name in
[ExtractDefineMacroName(directive) for directive in directives] [ExtractDefineMacroName(directive) for directive in directives]
if name is not None) if name is not None)
statement_tuples = ToStatementTuples(code_tuples) statement_tuples = ToStatementTuples(code_tuples)
output_lines = [] output_lines = []
for statement_tuple in statement_tuples: for statement_tuple in statement_tuples:
line = statement_tuple[2] line = statement_tuple[2]
try: try:
symbol_name = ExtractApiExport(macro_names, api_export_macro, line) symbol_name = ExtractApiExport(macro_names, api_export_macro, line)
if symbol_name: if symbol_name:
output_lines.append( output_lines.append(
ExportedSymbolLine(symbol_prefix, symbol_name, statement_tuple)) ExportedSymbolLine(symbol_prefix, symbol_name,
except ExtractError as exception: statement_tuple))
output_lines.append(ExportedExceptionLine(exception, statement_tuple)) except ExtractError as exception:
output_lines.append(
output_lines.sort() ExportedExceptionLine(exception, statement_tuple))
return [header_line] + output_lines + [footer_line]
output_lines.sort()
return [header_line] + output_lines + [footer_line]
def ProcessSourceFile(api_export_macro, symbol_prefix, header_line, def ProcessSourceFile(api_export_macro, symbol_prefix, header_line,
footer_line, input_file, output_file): footer_line, input_file, output_file):
'Reads in a C program file and outputs macros renaming exported symbols.' 'Reads in a C program file and outputs macros renaming exported symbols.'
with open(input_file, 'r') as f:
file_content = f.read()
output_lines = ProcessSource(api_export_macro, symbol_prefix, header_line,
footer_line, file_content)
output_lines.append('')
with open(output_file, 'w') as f:
f.write('\n'.join(output_lines))
with open(input_file, 'r') as f:
file_content = f.read()
output_lines = ProcessSource(api_export_macro, symbol_prefix, header_line,
footer_line, file_content)
output_lines.append('')
with open(output_file, 'w') as f:
f.write('\n'.join(output_lines))
header_line='''// Copyright 2018 The Chromium Authors. All rights reserved. header_line = '''// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
...@@ -344,11 +351,15 @@ header_line='''// Copyright 2018 The Chromium Authors. All rights reserved. ...@@ -344,11 +351,15 @@ header_line='''// Copyright 2018 The Chromium Authors. All rights reserved.
#define THIRD_PARTY_SQLITE_AMALGAMATION_RENAME_EXPORTS_H_ #define THIRD_PARTY_SQLITE_AMALGAMATION_RENAME_EXPORTS_H_
''' '''
footer_line =''' footer_line = '''
#endif // THIRD_PARTY_SQLITE_AMALGAMATION_RENAME_EXPORTS_H_ #endif // THIRD_PARTY_SQLITE_AMALGAMATION_RENAME_EXPORTS_H_
''' '''
if __name__ == '__main__': if __name__ == '__main__':
ProcessSourceFile(api_export_macro='SQLITE_API', symbol_prefix='chrome_', ProcessSourceFile(
header_line=header_line, footer_line=footer_line, api_export_macro='SQLITE_API',
input_file=sys.argv[1], output_file=sys.argv[2]) symbol_prefix='chrome_',
header_line=header_line,
footer_line=footer_line,
input_file=sys.argv[1],
output_file=sys.argv[2])
...@@ -15,276 +15,281 @@ import sys ...@@ -15,276 +15,281 @@ import sys
import tempfile import tempfile
import unittest import unittest
class ExtractSqliteApiUnittest(unittest.TestCase): class ExtractSqliteApiUnittest(unittest.TestCase):
def setUp(self): def setUp(self):
self.test_root = tempfile.mkdtemp() self.test_root = tempfile.mkdtemp()
source_path = os.path.join( source_path = os.path.join(
os.path.dirname(os.path.realpath(__file__)), 'extract_sqlite_api.py') os.path.dirname(os.path.realpath(__file__)),
self.extractor = SourceFileLoader('extract_api', source_path).load_module() 'extract_sqlite_api.py')
self.extractor = SourceFileLoader('extract_api',
source_path).load_module()
def tearDown(self):
if self.test_root:
shutil.rmtree(self.test_root)
def tearDown(self): def testExtractLineTuples(self):
if self.test_root: golden = [(1, 'Line1'), (2, ''), (3, 'Line 2'), (4, 'Line3'), (5, '')]
shutil.rmtree(self.test_root) text_with_newline = "Line1\n\nLine 2 \nLine3\n"
self.assertEqual(
self.extractor.ExtractLineTuples(text_with_newline), golden)
def testExtractLineTuples(self): golden = [(1, 'Line1'), (2, ''), (3, 'Line 2'), (4, 'Line3')]
golden = [(1, 'Line1'), (2, ''), (3, 'Line 2'), (4, 'Line3'), (5, '')] text_without_newline = "Line1\n\nLine 2 \nLine3"
text_with_newline = "Line1\n\nLine 2 \nLine3\n" self.assertEqual(
self.assertEqual(self.extractor.ExtractLineTuples(text_with_newline), self.extractor.ExtractLineTuples(text_without_newline), golden)
golden)
golden = [(1, 'Line1'), (2, ''), (3, 'Line 2'), (4, 'Line3')] def testExtractPreprocessorDirectives(self):
text_without_newline = "Line1\n\nLine 2 \nLine3" lines = [
self.assertEqual(self.extractor.ExtractLineTuples(text_without_newline), (1, '// Header comment'),
golden) (2, '#define DIRECTIVE 1'),
(3, 'int main() { // \\'),
(4, '}'),
(5, ''),
(6, '#define MULTILINE \\'),
(7, 'MORE_MULTILINE_DIRECTIVE\\'),
(8, 'END_MULTILINE_DIRECTIVE'),
(9, 'void code() { }'),
]
def testExtractPreprocessorDirectives(self): directives, code_lines = self.extractor.ExtractPreprocessorDirectives(
lines = [ lines)
(1, '// Header comment'), self.assertEqual(directives, [
(2, '#define DIRECTIVE 1'), '#define DIRECTIVE 1',
(3, 'int main() { // \\'), '#define MULTILINE \nMORE_MULTILINE_DIRECTIVE\nEND_MULTILINE_DIRECTIVE',
(4, '}'), ])
(5, ''), self.assertEqual(code_lines, [
(6, '#define MULTILINE \\'), (1, '// Header comment'),
(7, 'MORE_MULTILINE_DIRECTIVE\\'), (3, 'int main() { // \\'),
(8, 'END_MULTILINE_DIRECTIVE'), (4, '}'),
(9, 'void code() { }'), (5, ''),
] (9, 'void code() { }'),
])
directives, code_lines = self.extractor.ExtractPreprocessorDirectives(lines) def testExtractDefineMacroName(self):
self.assertEqual(directives, [ self.assertEqual(
'#define DIRECTIVE 1', 'SQLITE_API',
'#define MULTILINE \nMORE_MULTILINE_DIRECTIVE\nEND_MULTILINE_DIRECTIVE', self.extractor.ExtractDefineMacroName('#define SQLITE_API 1'))
]) self.assertEqual(
self.assertEqual(code_lines, [ 'SQLITE_API',
(1, '// Header comment'), self.extractor.ExtractDefineMacroName('#define SQLITE_API'))
(3, 'int main() { // \\'), self.assertEqual(
(4, '}'), 'SQLITE_API',
(5, ''), self.extractor.ExtractDefineMacroName('#define SQLITE_API\n1'))
(9, 'void code() { }'), self.assertEqual(
]) 'SQLITE_API',
self.extractor.ExtractDefineMacroName(
'# define SQLITE_API 1'))
self.assertEqual(
'SQLITE_API',
self.extractor.ExtractDefineMacroName('#\tdefine\tSQLITE_API\t1'))
self.assertEqual(
None,
self.extractor.ExtractDefineMacroName(' #define SQLITE_API 1'))
self.assertEqual(
None,
self.extractor.ExtractDefineMacroName(' #define SQLITE_API() 1'))
self.assertEqual(None, self.extractor.ExtractDefineMacroName(''))
def testExtractDefineMacroName(self): def testRemoveLineComments(self):
self.assertEqual( self.assertEqual('word;', self.extractor.RemoveLineComments('word;'))
'SQLITE_API', self.extractor.ExtractDefineMacroName( self.assertEqual('', self.extractor.RemoveLineComments(''))
'#define SQLITE_API 1')) self.assertEqual('', self.extractor.RemoveLineComments('// comment'))
self.assertEqual( self.assertEqual('',
'SQLITE_API', self.extractor.ExtractDefineMacroName( self.extractor.RemoveLineComments('/* comment */'))
'#define SQLITE_API')) self.assertEqual('word;',
self.assertEqual( self.extractor.RemoveLineComments('wo/*comment*/rd;'))
'SQLITE_API', self.extractor.ExtractDefineMacroName( self.assertEqual(
'#define SQLITE_API\n1')) 'word;*/', self.extractor.RemoveLineComments('wo/*comment*/rd;*/'))
self.assertEqual( self.assertEqual(
'SQLITE_API', self.extractor.ExtractDefineMacroName( 'word;*/',
'# define SQLITE_API 1')) self.extractor.RemoveLineComments('wo/*/*comment*/rd;*/'))
self.assertEqual( self.assertEqual(
'SQLITE_API', self.extractor.ExtractDefineMacroName( 'word;', self.extractor.RemoveLineComments('wo/*comm//ent*/rd;'))
'#\tdefine\tSQLITE_API\t1'))
self.assertEqual(
None, self.extractor.ExtractDefineMacroName(
' #define SQLITE_API 1'))
self.assertEqual(
None, self.extractor.ExtractDefineMacroName(
' #define SQLITE_API() 1'))
self.assertEqual(None, self.extractor.ExtractDefineMacroName(''))
def testRemoveLineComments(self): def testRemoveComments(self):
self.assertEqual( lines = [
'word;', self.extractor.RemoveLineComments('word;')) (1, 'code();'),
self.assertEqual( (2, 'more_code(); /* with comment */ more_code();'),
'', self.extractor.RemoveLineComments('')) (3, '/**'),
self.assertEqual( (4, 'Spec text'),
'', self.extractor.RemoveLineComments('// comment')) (5, '**/ spec_code();'),
self.assertEqual( (6,
'', self.extractor.RemoveLineComments('/* comment */')) 'late_code(); /* with comment */ more_late_code(); /* late comment'
self.assertEqual( ),
'word;', self.extractor.RemoveLineComments('wo/*comment*/rd;')) (7, 'ends here // C++ trap */ code(); // /* C trap'),
self.assertEqual( (8, 'last_code();'),
'word;*/', self.extractor.RemoveLineComments('wo/*comment*/rd;*/')) ]
self.assertEqual(
'word;*/', self.extractor.RemoveLineComments('wo/*/*comment*/rd;*/'))
self.assertEqual(
'word;', self.extractor.RemoveLineComments('wo/*comm//ent*/rd;'))
def testRemoveComments(self): self.assertEqual(
lines = [ self.extractor.RemoveComments(lines), [
(1, 'code();'), (1, 'code();'),
(2, 'more_code(); /* with comment */ more_code();'), (2, 'more_code(); more_code();'),
(3, '/**'), (3, ''),
(4, 'Spec text'), (5, ' spec_code();'),
(5, '**/ spec_code();'), (6, 'late_code(); more_late_code(); '),
(6, 'late_code(); /* with comment */ more_late_code(); /* late comment'), (7, ' code(); '),
(7, 'ends here // C++ trap */ code(); // /* C trap'), (8, 'last_code();'),
(8, 'last_code();'), ])
]
self.assertEqual(self.extractor.RemoveComments(lines), [ def testToStatementTuples(self):
(1, 'code();'), lines = [(1, 'void function();'), (2, 'int main('),
(2, 'more_code(); more_code();'), (3, ' int argc, char* argv) {'),
(3, ''), (4, ' statement1; statement2;'), (5, '}'), (6, 'stat'),
(5, ' spec_code();'), (7, 'ement4; statement5; sta'), (8, 'tem'),
(6, 'late_code(); more_late_code(); '), (9, 'ent6; statement7;')]
(7, ' code(); '),
(8, 'last_code();'),
])
def testToStatementTuples(self): self.assertEqual(
lines = [ self.extractor.ToStatementTuples(lines), [
(1, 'void function();'), (1, 1, 'void function()'),
(2, 'int main('), (2, 3, 'int main(\n int argc, char* argv)'),
(3, ' int argc, char* argv) {'), (4, 4, 'statement1'),
(4, ' statement1; statement2;'), (4, 4, 'statement2'),
(5, '}'), (5, 5, ''),
(6, 'stat'), (6, 7, 'stat\nement4'),
(7, 'ement4; statement5; sta'), (7, 7, 'statement5'),
(8, 'tem'), (7, 9, 'sta\ntem\nent6'),
(9, 'ent6; statement7;') (9, 9, 'statement7'),
] ])
self.assertEqual(self.extractor.ToStatementTuples(lines), [ def testExtractApiExport(self):
(1, 1, 'void function()'), self.assertEqual(
(2, 3, 'int main(\n int argc, char* argv)'), 'sqlite3_init',
(4, 4, 'statement1'), self.extractor.ExtractApiExport(set(), 'SQLITE_API',
(4, 4, 'statement2'), 'SQLITE_API void sqlite3_init()'))
(5, 5, ''), self.assertEqual(
(6, 7, 'stat\nement4'), 'sqlite3_sleep',
(7, 7, 'statement5'), self.extractor.ExtractApiExport(
(7, 9, 'sta\ntem\nent6'), set(), 'SQLITE_API', 'SQLITE_API int sqlite3_sleep(int ms)'))
(9, 9, 'statement7'), self.assertEqual(
]) 'sqlite3_sleep',
self.extractor.ExtractApiExport(
set(), 'SQLITE_API',
'SQLITE_API long long sqlite3_sleep(int ms)'))
self.assertEqual(
'sqlite3rbu_temp_size',
self.extractor.ExtractApiExport(
set(), 'SQLITE_API',
'SQLITE_API sqlite3_int64 sqlite3rbu_temp_size(sqlite3rbu *pRbu)'
))
self.assertEqual(
'sqlite3_expired',
self.extractor.ExtractApiExport(
set(['SQLITE_DEPRECATED']), 'SQLITE_API',
'SQLITE_API SQLITE_DEPRECATED int sqlite3_expired(sqlite3_stmt*)'
))
# SQLite's header actually #defines double (in some cases).
self.assertEqual(
'sqlite3_column_double',
self.extractor.ExtractApiExport(
set(['double']), 'SQLITE_API',
'SQLITE_API double sqlite3_column_double(sqlite3_stmt*, int iCol)'
))
self.assertEqual(
'sqlite3_temp_directory',
self.extractor.ExtractApiExport(
set(['SQLITE_EXTERN']), 'SQLITE_API',
'SQLITE_API SQLITE_EXTERN char *sqlite3_temp_directory'))
self.assertEqual(
'sqlite3_version',
self.extractor.ExtractApiExport(
set(['SQLITE_EXTERN']), 'SQLITE_API',
'SQLITE_API SQLITE_EXTERN const char sqlite3_version[]'))
self.assertEqual(
None,
self.extractor.ExtractApiExport(
set(['SQLITE_DEPRECATED']), 'SQLITE_API',
'NOT_SQLITE_API struct sqlite_type sqlite3_sleep(int ms)'))
def testExtractApiExport(self): with self.assertRaisesRegex(self.extractor.ExtractError,
self.assertEqual( 'Mixed simple .* and composite'):
'sqlite3_init', self.extractor.ExtractApiExport(
self.extractor.ExtractApiExport( set(), 'SQLITE_API',
set(), 'SQLITE_API', 'SQLITE_API void sqlite3_init()')) 'SQLITE_API void int sqlite3_sleep(int ms)')
self.assertEqual( with self.assertRaisesRegex(self.extractor.ExtractError,
'sqlite3_sleep', 'Unsupported keyword struct'):
self.extractor.ExtractApiExport( self.extractor.ExtractApiExport(
set(), 'SQLITE_API', 'SQLITE_API int sqlite3_sleep(int ms)')) set(), 'SQLITE_API',
self.assertEqual( 'SQLITE_API struct sqlite_type sqlite3_sleep(int ms)')
'sqlite3_sleep', with self.assertRaisesRegex(self.extractor.ExtractError,
self.extractor.ExtractApiExport( 'int\+\+ parsed as type name'):
set(), 'SQLITE_API', self.extractor.ExtractApiExport(
'SQLITE_API long long sqlite3_sleep(int ms)')) set(), 'SQLITE_API', 'SQLITE_API int++ sqlite3_sleep(int ms)')
self.assertEqual( with self.assertRaisesRegex(self.extractor.ExtractError,
'sqlite3rbu_temp_size', 'sqlite3\+sleep parsed as symbol'):
self.extractor.ExtractApiExport( self.extractor.ExtractApiExport(
set(), 'SQLITE_API', set(), 'SQLITE_API', 'SQLITE_API int sqlite3+sleep(int ms)')
'SQLITE_API sqlite3_int64 sqlite3rbu_temp_size(sqlite3rbu *pRbu)'))
self.assertEqual(
'sqlite3_expired',
self.extractor.ExtractApiExport(
set(['SQLITE_DEPRECATED']), 'SQLITE_API',
'SQLITE_API SQLITE_DEPRECATED int sqlite3_expired(sqlite3_stmt*)'))
# SQLite's header actually #defines double (in some cases).
self.assertEqual(
'sqlite3_column_double',
self.extractor.ExtractApiExport(
set(['double']), 'SQLITE_API',
'SQLITE_API double sqlite3_column_double(sqlite3_stmt*, int iCol)'))
self.assertEqual(
'sqlite3_temp_directory',
self.extractor.ExtractApiExport(
set(['SQLITE_EXTERN']), 'SQLITE_API',
'SQLITE_API SQLITE_EXTERN char *sqlite3_temp_directory'))
self.assertEqual(
'sqlite3_version',
self.extractor.ExtractApiExport(
set(['SQLITE_EXTERN']), 'SQLITE_API',
'SQLITE_API SQLITE_EXTERN const char sqlite3_version[]'))
self.assertEqual(
None,
self.extractor.ExtractApiExport(
set(['SQLITE_DEPRECATED']), 'SQLITE_API',
'NOT_SQLITE_API struct sqlite_type sqlite3_sleep(int ms)'))
with self.assertRaisesRegex(self.extractor.ExtractError, def testExportedSymbolLine(self):
'Mixed simple .* and composite'): self.assertEqual(
self.extractor.ExtractApiExport( '#define sqlite3_sleep chrome_sqlite3_sleep // Line 42',
set(), 'SQLITE_API', 'SQLITE_API void int sqlite3_sleep(int ms)') self.extractor.ExportedSymbolLine(
with self.assertRaisesRegex(self.extractor.ExtractError, 'chrome_', 'sqlite3_sleep',
'Unsupported keyword struct'): (42, 42, 'SQLITE_API int chrome_sqlite3_sleep(int ms)')))
self.extractor.ExtractApiExport( self.assertEqual(
set(), 'SQLITE_API', '#define sqlite3_sleep chrome_sqlite3_sleep // Lines 42-44',
'SQLITE_API struct sqlite_type sqlite3_sleep(int ms)') self.extractor.ExportedSymbolLine(
with self.assertRaisesRegex(self.extractor.ExtractError, 'chrome_', 'sqlite3_sleep',
'int\+\+ parsed as type name'): (42, 44, 'SQLITE_API int chrome_sqlite3_sleep(int ms)')))
self.extractor.ExtractApiExport(
set(), 'SQLITE_API', 'SQLITE_API int++ sqlite3_sleep(int ms)')
with self.assertRaisesRegex(self.extractor.ExtractError,
'sqlite3\+sleep parsed as symbol'):
self.extractor.ExtractApiExport(
set(), 'SQLITE_API', 'SQLITE_API int sqlite3+sleep(int ms)')
def testExportedSymbolLine(self): def testExportedExceptionLine(self):
self.assertEqual( self.assertEqual(
'#define sqlite3_sleep chrome_sqlite3_sleep // Line 42', '// TODO: Lines 42-44 -- Something went wrong',
self.extractor.ExportedSymbolLine( self.extractor.ExportedExceptionLine(
'chrome_', 'sqlite3_sleep', self.extractor.ExtractError('Something went wrong'),
(42, 42, 'SQLITE_API int chrome_sqlite3_sleep(int ms)'))) (42, 44, 'SQLITE_API int chrome_sqlite3_sleep(int ms)')))
self.assertEqual(
'#define sqlite3_sleep chrome_sqlite3_sleep // Lines 42-44',
self.extractor.ExportedSymbolLine(
'chrome_', 'sqlite3_sleep',
(42, 44, 'SQLITE_API int chrome_sqlite3_sleep(int ms)')))
def testExportedExceptionLine(self): def testProcessSource(self):
self.assertEqual( file_content = '\n'.join([
'// TODO: Lines 42-44 -- Something went wrong', '/*',
self.extractor.ExportedExceptionLine( 'struct sqlite_type sqlite3_sleep; // Remove comments',
self.extractor.ExtractError('Something went wrong'), '*/',
(42, 44, 'SQLITE_API int chrome_sqlite3_sleep(int ms)'))) '#define SQLITE_DEPRECATED',
'SQLITE_API int sqlite3_sleep(int ms);',
'SQLITE_API struct sqlite_type sqlite3_sleep(int ms);',
'SQLITE_API SQLITE_DEPRECATED int sqlite3_expired(sqlite3_stmt*);',
])
golden_output = [
'// Header',
'#define sqlite3_expired chrome_sqlite3_expired // Line 7',
'#define sqlite3_sleep chrome_sqlite3_sleep // Line 5',
'// TODO: Lines 6-6 -- Unsupported keyword struct',
'// Footer',
]
self.assertEqual(
golden_output,
self.extractor.ProcessSource('SQLITE_API', 'chrome_', '// Header',
'// Footer', file_content))
def testProcessSource(self): def testProcessSourceFile(self):
file_content = '\n'.join([ file_content = '\n'.join([
'/*', '/*',
'struct sqlite_type sqlite3_sleep; // Remove comments', 'struct sqlite_type sqlite3_sleep; // Remove comments',
'*/', '*/',
'#define SQLITE_DEPRECATED', '#define SQLITE_DEPRECATED',
'SQLITE_API int sqlite3_sleep(int ms);', 'SQLITE_API int sqlite3_sleep(int ms);',
'SQLITE_API struct sqlite_type sqlite3_sleep(int ms);', 'SQLITE_API struct sqlite_type sqlite3_sleep(int ms);',
'SQLITE_API SQLITE_DEPRECATED int sqlite3_expired(sqlite3_stmt*);', 'SQLITE_API SQLITE_DEPRECATED int sqlite3_expired(sqlite3_stmt*);',
]) ])
golden_output = [ golden_output = '\n'.join([
'// Header', '// Header',
'#define sqlite3_expired chrome_sqlite3_expired // Line 7', '#define sqlite3_expired chrome_sqlite3_expired // Line 7',
'#define sqlite3_sleep chrome_sqlite3_sleep // Line 5', '#define sqlite3_sleep chrome_sqlite3_sleep // Line 5',
'// TODO: Lines 6-6 -- Unsupported keyword struct', '// TODO: Lines 6-6 -- Unsupported keyword struct',
'// Footer', '// Footer',
] '',
self.assertEqual( ])
golden_output,
self.extractor.ProcessSource('SQLITE_API', 'chrome_', '// Header',
'// Footer', file_content))
def testProcessSourceFile(self): input_file = os.path.join(self.test_root, 'input.h')
file_content = '\n'.join([ output_file = os.path.join(self.test_root, 'macros.h')
'/*', with open(input_file, 'w') as f:
'struct sqlite_type sqlite3_sleep; // Remove comments', f.write(file_content)
'*/', self.extractor.ProcessSourceFile('SQLITE_API', 'chrome_', '// Header',
'#define SQLITE_DEPRECATED', '// Footer', input_file, output_file)
'SQLITE_API int sqlite3_sleep(int ms);', with open(output_file, 'r') as f:
'SQLITE_API struct sqlite_type sqlite3_sleep(int ms);', self.assertEqual(f.read(), golden_output)
'SQLITE_API SQLITE_DEPRECATED int sqlite3_expired(sqlite3_stmt*);',
])
golden_output = '\n'.join([
'// Header',
'#define sqlite3_expired chrome_sqlite3_expired // Line 7',
'#define sqlite3_sleep chrome_sqlite3_sleep // Line 5',
'// TODO: Lines 6-6 -- Unsupported keyword struct',
'// Footer',
'',
])
input_file = os.path.join(self.test_root, 'input.h')
output_file = os.path.join(self.test_root, 'macros.h')
with open(input_file, 'w') as f:
f.write(file_content)
self.extractor.ProcessSourceFile(
'SQLITE_API', 'chrome_', '// Header', '// Footer', input_file,
output_file)
with open(output_file, 'r') as f:
self.assertEqual(f.read(), golden_output)
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()
...@@ -44,212 +44,212 @@ _CONFIGURE_FOR_TESTING = False ...@@ -44,212 +44,212 @@ _CONFIGURE_FOR_TESTING = False
def get_amalgamation_dir(config_name): def get_amalgamation_dir(config_name):
if config_name == 'chromium': if config_name == 'chromium':
return os.path.join(_SQLITE_SRC_DIR, 'amalgamation') return os.path.join(_SQLITE_SRC_DIR, 'amalgamation')
elif config_name == 'dev': elif config_name == 'dev':
return os.path.join(_SQLITE_SRC_DIR, 'amalgamation_dev') return os.path.join(_SQLITE_SRC_DIR, 'amalgamation_dev')
else: else:
assert False assert False
def _icu_cpp_flags(): def _icu_cpp_flags():
"""Return the libicu C++ flags.""" """Return the libicu C++ flags."""
cmd = ['icu-config', '--cppflags'] cmd = ['icu-config', '--cppflags']
try: try:
return subprocess.check_output(cmd) return subprocess.check_output(cmd)
except Exception: except Exception:
return '' return ''
def _icu_ld_flags(): def _icu_ld_flags():
"""Return the libicu linker flags.""" """Return the libicu linker flags."""
cmd = ['icu-config', '--ldflags'] cmd = ['icu-config', '--ldflags']
try: try:
return subprocess.check_output(cmd) return subprocess.check_output(cmd)
except Exception: except Exception:
return '' return ''
def _strip_flags_for_testing(flags): def _strip_flags_for_testing(flags):
"""Accepts the default configure/build flags and strips out those """Accepts the default configure/build flags and strips out those
incompatible with the SQLite tests. incompatible with the SQLite tests.
When configuring SQLite to run tests this script uses a configuration When configuring SQLite to run tests this script uses a configuration
as close to what Chromium ships as possible. Some flags need to be as close to what Chromium ships as possible. Some flags need to be
omitted for the tests to link and run correct. See comments below. omitted for the tests to link and run correct. See comments below.
""" """
test_flags = [] test_flags = []
for flag in flags: for flag in flags:
# Omitting features can cause tests to hang/crash/fail because the # Omitting features can cause tests to hang/crash/fail because the
# SQLite tests don't seem to detect feature omission. Keep them enabled. # SQLite tests don't seem to detect feature omission. Keep them enabled.
if flag.startswith('SQLITE_OMIT_'): if flag.startswith('SQLITE_OMIT_'):
continue continue
# Some tests compile with specific SQLITE_DEFAULT_PAGE_SIZE so do # Some tests compile with specific SQLITE_DEFAULT_PAGE_SIZE so do
# not hard-code. # not hard-code.
if flag.startswith('SQLITE_DEFAULT_PAGE_SIZE='): if flag.startswith('SQLITE_DEFAULT_PAGE_SIZE='):
continue continue
# Some tests compile with specific SQLITE_DEFAULT_MEMSTATUS so do # Some tests compile with specific SQLITE_DEFAULT_MEMSTATUS so do
# not hard-code. # not hard-code.
if flag.startswith('SQLITE_DEFAULT_MEMSTATUS='): if flag.startswith('SQLITE_DEFAULT_MEMSTATUS='):
continue continue
# If enabled then get undefined reference to `uregex_open_63' and # If enabled then get undefined reference to `uregex_open_63' and
# other *_64 functions. # other *_64 functions.
if flag == 'SQLITE_ENABLE_ICU': if flag == 'SQLITE_ENABLE_ICU':
continue continue
# If defined then the fts4umlaut tests fail with the following error: # If defined then the fts4umlaut tests fail with the following error:
# #
# Error: unknown tokenizer: unicode61 # Error: unknown tokenizer: unicode61
if flag == 'SQLITE_DISABLE_FTS3_UNICODE': if flag == 'SQLITE_DISABLE_FTS3_UNICODE':
continue continue
test_flags.append(flag) test_flags.append(flag)
return test_flags return test_flags
def _read_flags(file_name, param_name): def _read_flags(file_name, param_name):
config_globals = dict() config_globals = dict()
with open(file_name) as input_file: with open(file_name) as input_file:
code = compile(input_file.read(), file_name, 'exec') code = compile(input_file.read(), file_name, 'exec')
exec(code, config_globals) exec (code, config_globals)
return config_globals[param_name] return config_globals[param_name]
def _read_configuration_values(config_name): def _read_configuration_values(config_name):
"""Read the configuration flags and return them in an array. """Read the configuration flags and return them in an array.
|config_name| is one of "chromium" or "dev". |config_name| is one of "chromium" or "dev".
""" """
common_flags = _read_flags(_COMMON_CONFIGURATION_FLAGS_GNI_FILE, common_flags = _read_flags(_COMMON_CONFIGURATION_FLAGS_GNI_FILE,
'sqlite_common_configuration_flags') 'sqlite_common_configuration_flags')
chromium_flags = _read_flags(_CHROMIUM_CONFIGURATION_FLAGS_GNI_FILE, chromium_flags = _read_flags(_CHROMIUM_CONFIGURATION_FLAGS_GNI_FILE,
'sqlite_chromium_configuration_flags') 'sqlite_chromium_configuration_flags')
dev_flags = _read_flags(_DEV_CONFIGURATION_FLAGS_GNI_FILE, dev_flags = _read_flags(_DEV_CONFIGURATION_FLAGS_GNI_FILE,
'sqlite_dev_configuration_flags') 'sqlite_dev_configuration_flags')
if config_name == 'chromium': if config_name == 'chromium':
flags = common_flags + chromium_flags flags = common_flags + chromium_flags
elif config_name == 'dev': elif config_name == 'dev':
flags = common_flags + dev_flags flags = common_flags + dev_flags
else: else:
print('Incorrect config "%s"' % config_name, file=sys.stderr) print('Incorrect config "%s"' % config_name, file=sys.stderr)
sys.exit(1) sys.exit(1)
if _CONFIGURE_FOR_TESTING: if _CONFIGURE_FOR_TESTING:
flags = _strip_flags_for_testing(flags) flags = _strip_flags_for_testing(flags)
return flags return flags
def _do_configure(config_name): def _do_configure(config_name):
"""Run the configure script for the SQLite source.""" """Run the configure script for the SQLite source."""
configure = os.path.join(_SQLITE_SRC_DIR, 'configure') configure = os.path.join(_SQLITE_SRC_DIR, 'configure')
build_flags = ' '.join( build_flags = ' '.join(
['-D' + f for f in _read_configuration_values(config_name)]) ['-D' + f for f in _read_configuration_values(config_name)])
cflags = '-Os {} {}'.format(build_flags, _icu_cpp_flags()) cflags = '-Os {} {}'.format(build_flags, _icu_cpp_flags())
ldflags = _icu_ld_flags() ldflags = _icu_ld_flags()
cmd = [ cmd = [
configure, configure,
'CFLAGS={}'.format(cflags), 'CFLAGS={}'.format(cflags),
'LDFLAGS={}'.format(ldflags), 'LDFLAGS={}'.format(ldflags),
'--disable-load-extension', '--disable-load-extension',
'--enable-amalgamation', '--enable-amalgamation',
'--enable-threadsafe', '--enable-threadsafe',
] ]
subprocess.check_call(cmd) subprocess.check_call(cmd)
if _CONFIGURE_FOR_TESTING:
# Copy the files necessary for building/running tests back
#into the source directory.
files = ['Makefile', 'config.h', 'libtool']
for file_name in files:
copyfile(
os.path.join(_TEMP_CONFIG_DIR, file_name),
os.path.join(_SQLITE_SRC_DIR, file_name))
file_name = os.path.join(_SQLITE_SRC_DIR, 'libtool')
st = os.stat(file_name)
os.chmod(file_name, st.st_mode | stat.S_IEXEC)
if _CONFIGURE_FOR_TESTING:
# Copy the files necessary for building/running tests back
#into the source directory.
files = ['Makefile', 'config.h', 'libtool']
for file_name in files:
copyfile(
os.path.join(_TEMP_CONFIG_DIR, file_name),
os.path.join(_SQLITE_SRC_DIR, file_name))
file_name = os.path.join(_SQLITE_SRC_DIR, 'libtool')
st = os.stat(file_name)
os.chmod(file_name, st.st_mode | stat.S_IEXEC)
def make_aggregate(config_name):
"""Generate the aggregate source files."""
if not os.path.exists(_TEMP_CONFIG_DIR):
os.mkdir(_TEMP_CONFIG_DIR)
try:
os.chdir(_TEMP_CONFIG_DIR)
_do_configure(config_name)
cmd = ['make', 'shell.c', 'sqlite3.h', 'sqlite3.c']
subprocess.check_call(cmd)
amalgamation_dir = get_amalgamation_dir(config_name) def make_aggregate(config_name):
if not os.path.exists(amalgamation_dir): """Generate the aggregate source files."""
os.mkdir(amalgamation_dir) if not os.path.exists(_TEMP_CONFIG_DIR):
os.mkdir(_TEMP_CONFIG_DIR)
readme_dst = os.path.join(amalgamation_dir, 'README.md') try:
if not os.path.exists(readme_dst): os.chdir(_TEMP_CONFIG_DIR)
readme_src = os.path.join(_SQLITE_ROOT_DIR, 'scripts', _do_configure(config_name)
'README_amalgamation.md')
copyfile(readme_src, readme_dst) cmd = ['make', 'shell.c', 'sqlite3.h', 'sqlite3.c']
subprocess.check_call(cmd)
copyfile(
os.path.join(_TEMP_CONFIG_DIR, 'sqlite3.c'), amalgamation_dir = get_amalgamation_dir(config_name)
os.path.join(amalgamation_dir, 'sqlite3.c')) if not os.path.exists(amalgamation_dir):
copyfile( os.mkdir(amalgamation_dir)
os.path.join(_TEMP_CONFIG_DIR, 'sqlite3.h'),
os.path.join(amalgamation_dir, 'sqlite3.h')) readme_dst = os.path.join(amalgamation_dir, 'README.md')
if not os.path.exists(readme_dst):
# shell.c must be placed in a different directory from sqlite3.h, readme_src = os.path.join(_SQLITE_ROOT_DIR, 'scripts',
# because it contains an '#include "sqlite3.h"' that we want to resolve 'README_amalgamation.md')
# to our custom //third_party/sqlite/sqlite3.h, not to the sqlite3.h copyfile(readme_src, readme_dst)
# produced here.
shell_dir = os.path.join(amalgamation_dir, 'shell') copyfile(
if not os.path.exists(shell_dir): os.path.join(_TEMP_CONFIG_DIR, 'sqlite3.c'),
os.mkdir(shell_dir) os.path.join(amalgamation_dir, 'sqlite3.c'))
copyfile( copyfile(
os.path.join(_TEMP_CONFIG_DIR, 'shell.c'), os.path.join(_TEMP_CONFIG_DIR, 'sqlite3.h'),
os.path.join(shell_dir, 'shell.c')) os.path.join(amalgamation_dir, 'sqlite3.h'))
finally:
rmtree(_TEMP_CONFIG_DIR) # shell.c must be placed in a different directory from sqlite3.h,
# because it contains an '#include "sqlite3.h"' that we want to resolve
# to our custom //third_party/sqlite/sqlite3.h, not to the sqlite3.h
# produced here.
shell_dir = os.path.join(amalgamation_dir, 'shell')
if not os.path.exists(shell_dir):
os.mkdir(shell_dir)
copyfile(
os.path.join(_TEMP_CONFIG_DIR, 'shell.c'),
os.path.join(shell_dir, 'shell.c'))
finally:
rmtree(_TEMP_CONFIG_DIR)
def extract_sqlite_api(config_name): def extract_sqlite_api(config_name):
amalgamation_dir = get_amalgamation_dir(config_name) amalgamation_dir = get_amalgamation_dir(config_name)
input_file = os.path.join(amalgamation_dir, 'sqlite3.h') input_file = os.path.join(amalgamation_dir, 'sqlite3.h')
output_file = os.path.join(amalgamation_dir, 'rename_exports.h') output_file = os.path.join(amalgamation_dir, 'rename_exports.h')
ProcessSourceFile( ProcessSourceFile(
api_export_macro='SQLITE_API', api_export_macro='SQLITE_API',
symbol_prefix='chrome_', symbol_prefix='chrome_',
header_line=header_line, header_line=header_line,
footer_line=footer_line, footer_line=footer_line,
input_file=input_file, input_file=input_file,
output_file=output_file) output_file=output_file)
if __name__ == '__main__': if __name__ == '__main__':
desc = \ desc = \
('Create the SQLite amalgamation. The SQLite amalgamation is documented at ' ('Create the SQLite amalgamation. The SQLite amalgamation is documented at '
'https://www.sqlite.org/amalgamation.html and is a single large file ' 'https://www.sqlite.org/amalgamation.html and is a single large file '
'containing the SQLite source code. Chromium generates the amalgamation with' 'containing the SQLite source code. Chromium generates the amalgamation with'
' this script to ensure that the configuration parameters are identical to ' ' this script to ensure that the configuration parameters are identical to '
'those in the Ninja build file.') 'those in the Ninja build file.')
parser = argparse.ArgumentParser(description=desc) parser = argparse.ArgumentParser(description=desc)
parser.add_argument( parser.add_argument(
'-t', '-t',
'--testing', '--testing',
action='store_true', action='store_true',
help='Generate an amalgamation for testing (default: false)') help='Generate an amalgamation for testing (default: false)')
namespace = parser.parse_args() namespace = parser.parse_args()
if namespace.testing: if namespace.testing:
_CONFIGURE_FOR_TESTING = True _CONFIGURE_FOR_TESTING = True
print('Running configure for testing.') print('Running configure for testing.')
for config_name in ['chromium', 'dev']: for config_name in ['chromium', 'dev']:
make_aggregate(config_name) make_aggregate(config_name)
extract_sqlite_api(config_name) extract_sqlite_api(config_name)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment