1import getopt 2import os 3import re 4import sys 5from meson2python import * 6 7 8# Converts the given |file_name| from meson to python, and writes the python code 9# to the given |file|. Code is indented by |output_indent|. When a subdir command 10# is found, the meson.build build in that subdir is converted by recursively invoking 11# this function. 12def process_meson(file, file_name: str, output_indent: str): 13 print( 14 output_indent 15 + '########################################################################################################################', 16 file=file, 17 ) 18 print(output_indent + '### Begin conversion from: ' + file_name, file=file) 19 print( 20 output_indent 21 + '########################################################################################################################', 22 file=file, 23 ) 24 25 print('Processing: ' + file_name) 26 sys.stdout.flush() 27 28 content = meson2python(file_name) 29 30 inside_literal = False 31 32 for line in content.splitlines(): 33 # Remove line terminator 34 line = line.rstrip() 35 36 # Check for multiline literals. 37 # We ignore literals that start and end on one line, though that may cause 38 # problems for the line processing below. 39 matches = re.findall(r"'''", line) 40 41 literal_delimiter_count = len(matches) 42 43 line_prefix = '' 44 line_suffix = '' 45 if literal_delimiter_count == 1: 46 inside_literal = not inside_literal 47 literal_line_split = line.split(r"'''") 48 if inside_literal: 49 line = literal_line_split[0] 50 line_suffix = r"'''" + literal_line_split[1] 51 else: 52 line_prefix = literal_line_split[0] + r"'''" 53 line = literal_line_split[1] 54 elif literal_delimiter_count == 0 or literal_delimiter_count == 2: 55 if inside_literal: 56 # Don't match anything while inside literal 57 line_prefix = line 58 line = '' 59 else: 60 exit('Unhandled literal in line: ' + line) 61 62 # Recurse into subdirs 63 match = re.match("( *)subdir\('([a-zA-Z0-9_/]+)'\)", line) 64 if match != None: 65 subdir_output_indent = match.group(1) + output_indent 66 current_dir = os.path.dirname(file_name) 67 next_dir = os.path.join(current_dir, match.group(2)) 68 next_file = os.path.join(next_dir, 'meson.build') 69 # Ensure the build definitions are aware of the changing directory 70 print( 71 subdir_output_indent + "set_relative_dir('%s')" % next_dir, file=file 72 ) 73 process_meson(file, next_file, subdir_output_indent) 74 print( 75 subdir_output_indent + "set_relative_dir('%s')" % current_dir, 76 file=file, 77 ) 78 continue 79 80 print(output_indent + line_prefix + line + line_suffix, file=file) 81 82 print( 83 output_indent 84 + '########################################################################################################################', 85 file=file, 86 ) 87 print(output_indent + '### End conversion from: ' + file_name, file=file) 88 print( 89 output_indent 90 + '########################################################################################################################', 91 file=file, 92 ) 93 94 95def generate(target: str): 96 if not (target == 'android' or target == 'fuchsia'): 97 exit('Target must be android or fuchsia') 98 99 output_file_name = 'generate_%s_build.py' % target 100 print('Writing to: ' + output_file_name) 101 102 with open(output_file_name, 'w') as file: 103 print('import sys', file=file) 104 print('###', file=file) 105 print( 106 '########################################################################################################################', 107 file=file, 108 ) 109 print('###', file=file) 110 print('### Pull in the definitions meson is expecting', file=file) 111 print('###', file=file) 112 print('from meson_common import *', file=file) 113 print('from meson_%s import *' % target, file=file) 114 print('###', file=file) 115 print( 116 '########################################################################################################################', 117 file=file, 118 ) 119 print('', file=file) 120 121 print('### Open the build definition file', file=file) 122 print('open_output_file()', file=file) 123 124 process_meson(file, 'meson_options.txt', output_indent='') 125 126 print('###', file=file) 127 print('### Process command line arguments for setting options', file=file) 128 print('if __name__ == "__main__":', file=file) 129 print(' for arg in sys.argv[1:]:', file=file) 130 print( 131 ' match = re.match(r"-D([a-zA-Z0-9-]+)=([a-zA-Z0-9-]*)", arg)', 132 file=file, 133 ) 134 print(' if not match:', file=file) 135 print( 136 ' exit("Invalid arg: %s should be -Doption=value" % arg)', 137 file=file, 138 ) 139 print(' set_option(match.group(1), match.group(2))', file=file) 140 print('###', file=file) 141 142 print('### These definitions must be inside the module', file=file) 143 print('def get_variable(name: str):', file=file) 144 print(' return globals()[name]', file=file) 145 print('', file=file) 146 147 print('### Load config', file=file) 148 print('load_config_file()', file=file) 149 print('', file=file) 150 151 process_meson(file, 'meson.build', output_indent='') 152 153 print('### Close the build definition file', file=file) 154 print('close_output_file()', file=file) 155 156 file.close() 157 158 159def usage(): 160 print('Usage: -t [android|fuchsia]') 161 sys.exit() 162 163 164def main(argv): 165 target = 'android' 166 try: 167 opts, args = getopt.getopt( 168 argv, 169 'ht:', 170 [ 171 'help', 172 'target=', 173 ], 174 ) 175 for opt, arg in opts: 176 if opt in ('-h', '--help'): 177 usage() 178 elif opt in ('-t', '--target'): 179 target = arg 180 except getopt.GetoptError as err: 181 usage() 182 183 generate(target) 184 185 186if __name__ == '__main__': 187 main(sys.argv[1:]) 188