| #!/usr/bin/env python3 | |
| # | |
| # Wrapper around flex that: | |
| # - ensures lex.backup is created in a private directory | |
| # - can error out if lex.backup is created (--no-backup) | |
| # - can fix warnings (--fix-warnings) | |
| # - works around concurrency issues with win_flex.exe: | |
| # https://github.com/lexxmark/winflexbison/issues/86 | |
| import argparse | |
| import os | |
| import subprocess | |
| import sys | |
| from os.path import abspath | |
| parser = argparse.ArgumentParser() | |
| parser.add_argument('--flex', type=abspath, required=True) | |
| parser.add_argument('--perl', type=abspath, required=True) | |
| parser.add_argument('--builddir', type=abspath, required=True) | |
| parser.add_argument('--srcdir', type=abspath, required=True) | |
| parser.add_argument('--privatedir', type=abspath, required=True, | |
| help='private directory for target') | |
| parser.add_argument('-o', dest='output_file', type=abspath, required=True, | |
| help='output file') | |
| parser.add_argument('-i', dest='input_file', type=abspath, help='input file') | |
| parser.add_argument('--fix-warnings', action='store_true', | |
| help='whether to fix warnings in generated file') | |
| parser.add_argument('--no-backup', action='store_true', | |
| help='whether no_backup is enabled or not') | |
| parser.add_argument('flex_flags', nargs='*', help='flags passed on to flex') | |
| args = parser.parse_args() | |
| # Since 'lex.backup' is always named that and ninja uses the top level build | |
| # directory as current directory for all commands, change directory to | |
| # temporary directory to avoid conflicts between concurrent flex | |
| # invocations. Only unreleased versions of flex have an argument to change | |
| # lex.filename to be named differently. | |
| if not os.path.isdir(args.privatedir): | |
| os.mkdir(args.privatedir) | |
| os.chdir(args.privatedir) | |
| # win_flex.exe generates names in a racy way, sometimes leading to random | |
| # "error deleting file" failures and sometimes to intermingled file | |
| # contents. Set FLEX_TMP_DIR to the target private directory to avoid | |
| # that. That environment variable isn't consulted on other platforms, so we | |
| # don't even need to make this conditional. | |
| env = {'FLEX_TMP_DIR': args.privatedir} | |
| # build flex invocation | |
| command = [args.flex, '-o', args.output_file] | |
| if args.no_backup: | |
| command += ['-b'] | |
| command += args.flex_flags | |
| command += [args.input_file] | |
| # create .c file from .l file | |
| sp = subprocess.run(command, env=env) | |
| if sp.returncode != 0: | |
| sys.exit(sp.returncode) | |
| # check lex.backup | |
| if args.no_backup: | |
| with open('lex.backup') as lex: | |
| if len(lex.readlines()) != 1: | |
| sys.exit('Scanner requires backup; see lex.backup.') | |
| os.remove('lex.backup') | |
| # fix warnings | |
| if args.fix_warnings: | |
| fix_warning_script = os.path.join(args.srcdir, | |
| 'src/tools/fix-old-flex-code.pl') | |
| command = [args.perl, fix_warning_script, args.output_file] | |
| sp = subprocess.run(command) | |
| if sp.returncode != 0: | |
| sys.exit(sp.returncode) | |
| sys.exit(0) |