| #!/usr/bin/env python3 |
| import re |
| import sys |
| |
| from argparse import ArgumentParser |
| |
| # This is a very dumb regex based method of translating from |
| # gn variable declarations and simple if statements to the |
| # equivalent cmake code. It only supports a few constructs and |
| # assumes the code is formatted a certain way. ANGLE gn files |
| # are auto-formatted so this should work most of the time. |
| |
| # The output may need a bit of manual fixup, but it beats |
| # translating the whole thing by hand. If new constructs |
| # are added to the ANGLE gn files, hopefully we can just add |
| # a few extra regexes here. |
| |
| parser = ArgumentParser( |
| prog='gni-to-cmake', description='converts a .gni file to .cmake', usage='%(prog)s [options]') |
| parser.add_argument('gni', help='the .gni file to parse') |
| parser.add_argument('cmake', help='the .cmake file to output') |
| parser.add_argument('--prepend', default='', help='the path to prepend to each file name') |
| |
| args = parser.parse_args() |
| |
| with open(args.gni, 'r', encoding="utf-8") as gni: |
| file = gni.read() |
| |
| # Prepend path to every string. |
| file = re.sub(r'"((\\\"|[^"])+)"', '"' + args.prepend + r'\1"', file) |
| |
| # Remove import, assert, config, and angle_source_set statements. |
| file = re.sub( |
| r'^\s*(import|assert|config|angle_source_set)\([^)]+\)( {.*})?$', |
| r'', |
| file, |
| flags=re.MULTILINE | re.DOTALL) |
| |
| # Remove pkg_config and declare_args statements after removing import statements. |
| # Import statements can refer to pkg_config, necessating handling this separately, |
| # and the regexps are slightly different. |
| file = re.sub( |
| r'(^\s*(pkg_config|declare_args)\([^)]*\)\s+{.*?}$)*', |
| r'', |
| file, |
| flags=re.MULTILINE | re.DOTALL) |
| |
| # Translate gn single line list declaration: |
| file = re.sub(r'\[ ((?:"[^"]*",? )*)\]$', r' \1)', file, flags=re.MULTILINE) |
| |
| # Translate gn single line list append: |
| file = re.sub( |
| r'^(\s*)(\w+) \+= (\w+)$', r'\1 set(\2, "${\2};${\3}")', file, flags=re.MULTILINE) |
| |
| # Translate gn list declaration: |
| # variable_name = [ |
| # "file/name/foo.cpp", |
| # ] |
| # to cmake list declaration: |
| # set(variable_name |
| # "file/name/foo.cpp" |
| # ) |
| file = re.sub(r'^(\s*)(\w+) = ?\[?', r'\1\1set(\2', file, flags=re.MULTILINE) |
| file = re.sub(r'^(\s*)("[^"]+"),$', r'\1\1\2', file, flags=re.MULTILINE) |
| file = re.sub(r'^(\s*)]$', r'\1\1)', file, flags=re.MULTILINE) |
| |
| # Translate list append fom gn to cmake |
| file = re.sub(r'^(\s*)(\w+) \+= ?\[?', r'\1\1list(APPEND \2', file, flags=re.MULTILINE) |
| |
| # Translate if statements from gn to cmake |
| file = re.sub(r'^(\s*)((?:} else )?)if \((.+)\) {$', r'\1\1\2if(\3)', file, flags=re.MULTILINE) |
| file = re.sub(r'^} else if$', r'elseif', file, flags=re.MULTILINE) |
| file = re.sub(r'^(\s*)} else {$', r'\1\1else()', file, flags=re.MULTILINE) |
| file = re.sub(r'^(\s*)}$', r'\1\1endif()', file, flags=re.MULTILINE) |
| |
| # Translate logic ops from gn to cmake |
| file = re.sub(r' \|\| ', r' OR ', file, flags=re.MULTILINE) |
| file = re.sub(r' \&\& ', r' AND ', file, flags=re.MULTILINE) |
| file = re.sub(r' == ', r' STREQUAL ', file, flags=re.MULTILINE) |
| file = re.sub(r'!', r' NOT ', file, flags=re.MULTILINE) |
| |
| with open(args.cmake, 'w', encoding="utf-8") as cmake: |
| cmake.write('# This file was generated with the command:\n') |
| cmake.write('# ' + ' '.join(['"' + arg.replace('"', '\\"') + '"' for arg in sys.argv])) |
| cmake.write('\n\n') |
| cmake.write(file) |