def main(): parser = argparse.ArgumentParser(conflict_handler='resolve') parser.add_argument("-V", "--version", dest="show_version", help="show version and exit", action="store_true", default=False) parser.add_argument("-v", "--debug", dest="debug", help="verbose", action="store_true", default=False) parser.add_argument("-###", "--test-only", dest="dry_run", help="print (but do not run) the commands", action="store_true", default=False) parser.add_argument("-Xpreprocessor", dest="preprocessor_options", metavar="<arg>", help="Pass <arg> to the preprocessor", action="append", default=[]) parser.add_argument("-Xp4c", dest="compiler_options", metavar="<arg>", help="Pass <arg> to the compiler", action="append", default=[]) parser.add_argument("-Xassembler", dest="assembler_options", metavar="<arg>", help="Pass <arg> to the assembler", action="append", default=[]) parser.add_argument("-Xlinker", dest="linker_options", metavar="<arg>", help="Pass <arg> to the linker", action="append", default=[]) parser.add_argument("-b", "--target", dest="target", help="specify target device", action="store", default="bmv2") parser.add_argument("-a", "--arch", dest="arch", help="specify target architecture", action="store", default="v1model") parser.add_argument("-c", "--compile", dest="run_all", help="Only run the preprocess, compile, and assemble" " steps", action="store_true", default=True) parser.add_argument("-D", dest="preprocessor_defines", help="define a macro to be used by the preprocessor", action="append", default=[]) parser.add_argument("-E", dest="run_preprocessor_only", help="Only run the preprocessor", action="store_true", default=False) parser.add_argument("-e", dest="skip_preprocessor", help="Skip the preprocessor", action="store_true", default=False) parser.add_argument("-g", dest="debug_info", help="Generate debug information", action="store_true", default=False) parser.add_argument("-I", dest="search_path", help="Add directory to include search path", action="append", default=[]) parser.add_argument("-o", "--output", dest="output_directory", help="Write output to the provided path", action="store", metavar="PATH", default=".") parser.add_argument("--p4runtime-file", help="Write a P4Runtime control plane API description " "to the specified file. " "[Deprecated; use '--p4runtime-files' instead]", action="store", default=None) parser.add_argument("--p4runtime-files", help="Write the P4Runtime control plane API " "description (P4Info) to the specified files " "(comma-separated list); the format is detected based" " on the filename suffix. " ' Legal suffixes are ".txt", ".json", and ".bin".', action="store", default=None) parser.add_argument("--p4runtime-format", choices=["binary", "json", "text"], help="Choose output format for the P4Runtime API " "description (default is binary). " "[Deprecated; use '--p4runtime-files' instead]", action="store", default="binary") parser.add_argument("--help-pragmas", "--pragma-help", "--pragmas-help", "--help-annotations", "--annotation-help", "--annotations-help", dest="help_pragmas", action="store_true", default=False, help="Print the documentation about supported" " annotations/pragmas and exit.") parser.add_argument("--help-targets", "--target-help", "--targets-help", dest="show_target_help", help="Display target specific command line options.", action="store_true", default=False) parser.add_argument("--disable-annotations", "--disable-annotation", "--disable-pragmas", "--disable-pragma", dest="disabled_annos", action="store", help="List of (comma-separated) annotations that" " should be ignored by the compiler.") parser.add_argument("-S", dest="run_till_assembler", help="Only run the preprocess and compilation steps", action="store_true", default=False) parser.add_argument( "--std", "-x", dest="language", choices=[ "p4-14", "p4-16", ### dash separator "p4_14", "p4_16", ### underscore separator "P4₁₄", "P4₁₆" ], ### Unicode, for fun help="Treat subsequent input files as having contents " "of the type indicated by " "the parameter to this argument.", action="store", default="p4-16") parser.add_argument("--ndebug", dest="ndebug_mode", help="Compile program in non-debug mode.\n", action="store_true", default=False) parser.add_argument("--parser-inline-opt", dest="optimizeParserInlining", help="Enable optimization of inlining of callee " "parsers (subparsers). " "The optimization is disabled by default. " "When the optimization is disabled, " "for each invocation of the subparser " "all states of the subparser are inlined, " "which means that the subparser " "might be inlined multiple times even if " "it is the same instance " "which is invoked multiple times. " "When the optimization is enabled, the compiler " "tries to identify the cases where it can inline" " the subparser's states only once for multiple " "invocations of the same subparser instance.", action="store_true", default=False) ### DRYified “env_indicates_developer_build” env_indicates_developer_build = os.environ['P4C_BUILD_TYPE'] == "DEVELOPER" if env_indicates_developer_build: add_developer_options(parser) parser.add_argument("P4_source_files", nargs='*', help="P4 source files to compile.", default=None) # load supported configuration. # We load these before we parse options, so that backends can register # proprietary options cfg_files = glob.glob("{}/*.cfg".format(os.environ['P4C_CFG_PATH'])) cfg = config.Config(config_prefix="p4c") for cf in cfg_files: cfg.load_from_config(cf, parser) ### ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ### ### Abe`s note: I hope my {“source_file” → “P4_source_files”} change ### (to the “parser” object) at this point in time can`t cause any ### ill effects in the callee “config.Config.load_from_config”. ### ### WIP To Do: check with somebody more experienced with this codebase ### before even _thinking_ about merging ### this changeset into “main”. # parse the arguments opts = parser.parse_args() user_defined_version = os.environ.get('P4C_DEFAULT_VERSION') ### Note: the next line of real code _was_τhe clear and easy-to-understand ### “if user_defined_version != None:”, but “pycodestyle” ### complained about that idiom so I rewrote it to something ### semantically-equivalent but with different syntax. if not (user_defined_version is None): opts.language = user_defined_version ### Accept multiple ways of specifying which language, ### and ensure that it is a consistent string from now on. ### ### Abe`s note: before I started working on reformatting this file for ### style-guidelines compliance, the code for this part was basically: ### # if opts.language == "p4_14": # opts.language = "p4-14" # if opts.language == "p4_16": # opts.language = "p4-16" ### ### The following should be more general, i.e. it should handle e.g. ### “p4_22” ⇒ “p4-22” just fine. ### ### Note: Abe dislikes the ASCII dash/minus in ### “p4-”<some decimal integer>, but is keeping it here so as to not ### break/change this part of the contract/interface between the driver ### and the rest of the compiler. One of these days/years, ### Abe suggests switching to e.g. “P4₁₄” and “P4₁₆” instead... ;-) ### ... or, probably even better, providing that Python≥3.4 ### is an acceptable requirement: ### <https://docs.python.org/3/library/enum.html> if (len(opts.language) > 2) and ('_' == opts.language[2]): opts.language = opts.language[:2] + '-' + opts.language[3:] ### Support for specifying the P4 version using Unicode: map to what the ### rest of the compiler expects/understands. Unicode_to_internal = {"P4₁₄": "p4-14", "P4₁₆": "p4-16"} ### On the next real code line, ### “.keys()” is implied [by Python] after “Unicode_to_internal”. if opts.language in Unicode_to_internal: opts.language = Unicode_to_internal[opts.language] user_defined_target = os.environ.get('P4C_DEFAULT_TARGET') ### Re the next line of real code: please see the 4-line comment, above, ### about “pycodestyle”. if not (user_defined_target is None): opts.target = user_defined_target user_defined_arch = os.environ.get('P4C_DEFAULT_ARCH') ### Re the next line of real code: please see the 4-line comment, above, ### about “pycodestyle”. if not (user_defined_arch is None): opts.arch = user_defined_arch # deal with early exits if opts.show_version: print("p4c", get_version()) sys.exit(0) if opts.show_target_help: print(display_supported_targets(cfg)) sys.exit(0) # check that the tuple value is correct backend = (opts.target, opts.arch) if (len(backend) != 2): parser.error("Invalid target and arch tuple: {}\n{}".format( backend, display_supported_targets(cfg))) # find the backend backend = None for target in cfg.target: regex = target._backend.replace('*', '[a-zA-Z0-9*]*') pattern = re.compile(regex) if (pattern.match(opts.target + '-' + opts.arch)): backend = target break if backend is None: parser.error("Unknown backend: {}-{}".format(str(opts.target), str(opts.arch))) error_count = 0 JSON_input_specified = env_indicates_developer_build and opts.json_source ### ^^^^^^^^^^^^^^^^^^^^: DRY, i.e. Don`t Repeat Yourself P4_input_or_inputs_specified = len(opts.P4_source_files) > 0 any_input_specified = JSON_input_specified or P4_input_or_inputs_specified ### ^^^^^^^^^^^^^^^^^^^: for readability if JSON_input_specified and P4_input_or_inputs_specified: ### Note: this restriction was added by Abe, so if there is a test case ### which tries to feed the driver both a JSON input pathname ### via the relevant flag _and_ another input pathname, ### that will now fail whereas before the JSON input pathname ### would silently override the other input pathname[s]. print( "\n" "ERROR: it seems that both (firstly) a JSON input pathname " 'was specified via "' + JSON_input_flag + '"' " _and_ (secondly) " + str(len(opts.P4_source_files)) + "" ### ^^ ### The above nonsense is to get rid of a W504 in “pycodestyle” ### [“W504 line break after binary operator”] ### The same goes for “"" +” two lines down. " other input pathname" "" + s_and_were_or_just_was(len(opts.P4_source_files)) + "" " specified. A JSON input at the same time as a P4 input is" " currently unsupported.") error_count = 1 ### Replace ↑ ‘=’ with “+=” if/when ever moving this line of code ### to somewhere it might not be the first error detection. ### When using “--help-”<*> options, we don`t necessarily need to pass ### an input-file pathname. However, by default the driver checks the ### input pathname and fails if the respective file does not exist. ### In that case we set source to “dummy.p4” so sanity checking works. ### The backend can force this behavior for its own help options by ### overriding the “should_not_check_input” method. checkInput = not (opts.help_pragmas or backend.should_not_check_input(opts)) use_a_dummy_P4_pseudoPathname = False ### a note from Abe: do we really still need the dummy pathname? ### Maybe we can take all the dummy-related code out once ### my work to improve the pathname handling in the ### driver is good enough for merging to “main”. if checkInput: if not any_input_specified: parser.error("no input pathname was specified.") ### reminder: at this point, the program is dead if len(opts.P4_source_files) > 1: print("\n" "ERROR: sorry, but as of this writing, the P4 compiler " "driver does _not_ support multiple top-level P4 source " "files in a single invocation. Multiple P4 source files at " 'a time are currently only supported via "#include"' "(i.e. additional non-top-level P4 source files). " "Number of top-level P4 source-file pathnames detected: " "" + str(len(opts.P4_source_files)), file=sys.stderr) ### ^^ this nonsense is to get rid of a W504 in “pycodestyle” ### [“W504 line break after binary operator”] error_count += 1 ### We need to do the next 3 lines of code this way (instead of ### iterating over a concise “list if list else []” expression) ### because “opts.json_source” might be invalid ### [i.e. we are _not_ in a developer build]. pathnames_to_check = opts.P4_source_files.copy() ### Abe`s reminder to self re the preceding line: ### a plain “pathnames_to_check = opts.P4_source_files” ### creates an _alias_!!! if JSON_input_specified: pathnames_to_check.append(opts.json_source) for pathname in pathnames_to_check: if not os.path.isfile(pathname): print('\nERROR: the input file "{}" does not exist.'.format( pathname), file=sys.stderr) error_count += 1 elif not any_input_specified: use_a_dummy_P4_pseudoPathname = True if error_count != 0: print("\nSorry; {} error{} found while analyzing the command inputs." " Aborting the P4 compiler driver.\n".format( error_count, s_and_were_or_just_was(error_count)), file=sys.stderr) sys.exit(min(255, error_count)) ### maximum of 255: being extra-careful here, ### just in case “error_count” is ### a positive integer multiple of 256 ### A reminder: by this point, “error_count” _must_ equal zero, ### due to the “sys.exit” call immediately above. assert 0 == error_count ### _Intentionally_ not “assert error_count < 1” or “assert error_count <= 0”, ### so that it will crash —— again, _intentionally_ —— if/when “error_count” is negative. ### Now we can make sanity-checking assertions in the following ### code without double-checking “error_count” first. ### Figure out what we need to pass to the backend as “opts.source_file”, ### since that is the interface contract between the driver and backends ### as of this writing. ### ### Do some sanity checking along the way (e.g. assertions). string_to_pass_as___source_file = "" ### the preceding line: _intentionally_ initializing with a value that ### Python considers false if JSON_input_specified: assert 0 == len(opts.P4_source_files) assert not use_a_dummy_P4_pseudoPathname string_to_pass_as___source_file = opts.json_source if P4_input_or_inputs_specified: assert 1 == len(opts.P4_source_files) assert not JSON_input_specified string_to_pass_as___source_file = opts.P4_source_files[0] if use_a_dummy_P4_pseudoPathname: assert 0 == len(opts.P4_source_files) assert not any_input_specified assert not JSON_input_specified assert not P4_input_or_inputs_specified string_to_pass_as___source_file = "dummy.p4" ### The following is admittedly somewhat hackish, but was the only way ### Abe could figure out how to set the appropriate attribute for the ### interface contract with the back end while maintaining the ### established norm that “opts” is of type “argparse.Namespace”, ### as it was before Abe touched this file. opts.__setattr__("source_file", string_to_pass_as___source_file) # set all configuration and command line options for backend backend.process_command_line_options(opts) # run all commands rc = backend.run() sys.exit(rc)
def main(): parser = argparse.ArgumentParser() parser.add_argument("-V", "--version", dest="show_version", help="show version and exit", action="store_true", default=False) parser.add_argument("-v", "--debug", dest="debug", help="verbose", action="store_true", default=False) parser.add_argument("-###", "--test-only", dest="dry_run", help="print (but do not run) the commands", action="store_true", default=False) parser.add_argument("-Xpreprocessor", dest="preprocessor_options", metavar="<arg>", help="Pass <arg> to the preprocessor", action="append", default=[]) parser.add_argument("-Xp4c", dest="compiler_options", metavar="<arg>", help="Pass <arg> to the compiler", action="append", default=[]) parser.add_argument("-Xassembler", dest="assembler_options", metavar="<arg>", help="Pass <arg> to the assembler", action="append", default=[]) parser.add_argument("-Xlinker", dest="linker_options", metavar="<arg>", help="Pass <arg> to the linker", action="append", default=[]) parser.add_argument("-b", "--target", dest="backend", help="specify target backend", action="store", default="bmv2-ss-p4org") parser.add_argument("-E", dest="run_preprocessor_only", help="Only run the preprocessor", action="store_true", default=False) parser.add_argument("-e", dest="skip_preprocessor", help="Skip the preprocessor", action="store_true", default=False) parser.add_argument("-S", dest="run_till_assembler", help="Only run the preprocess and compilation steps", action="store_true", default=False) parser.add_argument("-c", dest="run_all", help="Only run preprocess, compile, and assemble steps", action="store_true", default=True) parser.add_argument("-x", dest="language", choices = ["p4-14", "p4-16"], help="Treat subsequent input files as having type language.", action="store", default="p4-16") parser.add_argument("-I", dest="search_path", help="Add directory to include search path", action="append", default=[]) parser.add_argument("-o", dest="output_directory", help="Write output to the provided path", action="store", metavar="PATH", default=".") parser.add_argument("--target-help", dest="show_target_help", help="Display target specific command line options.", action="store_true", default=False) parser.add_argument("--p4runtime-file", help="Write a P4Runtime control plane API description " "to the specified file.", action="store", default=None) parser.add_argument("--p4runtime-format", choices=["binary", "json", "text"], help="Choose output format for the P4Runtime API " "description (default is binary).", action="store", default="binary") if (os.environ['P4C_BUILD_TYPE'] == "DEVELOPER"): add_developer_options(parser) parser.add_argument("source_file", nargs='?', help="Files to compile", default=None) # many more options opts = parser.parse_args() source = opts.source_file if opts.show_version: print("p4c %s" % (p4c_src.__version__)) sys.exit(0) # load supported configuration cfg_files = glob.glob("{}/*.cfg".format(os.environ['P4C_CFG_PATH'])) cfg = config.Config(config_prefix = "p4c") for cf in cfg_files: if opts.debug: print 'loading config {}'.format(cf) cfg.load_from_config(cf, opts.output_directory, opts.source_file) if opts.show_target_help: display_supported_targets(cfg) sys.exit(0) # target-arch-vendor, e.g. # bmv2-ss-p4org # ebpf-psa-p4org triplet = opts.backend.split('-') if (len(triplet) != 3): print "Invalid target-arch-vendor triplet." display_supported_targets(cfg) sys.exit(1) if not source: parser.error('No input specified.') backend = None for triplet, _ in cfg.steps.iteritems(): regex = triplet.replace('*', '[a-zA-Z0-9*]*') pattern = re.compile(regex) if (pattern.match(opts.backend)): backend = triplet break if backend == None: print "Unknown backend:", opts.backend sys.exit(1) commands['preprocessor'] = [] commands['compiler'] = [] commands['assembler'] = [] commands['linker'] = [] for option in opts.preprocessor_options: commands["preprocessor"] += shlex.split(option) for option in opts.compiler_options: commands["compiler"] += shlex.split(option) if (os.environ['P4C_BUILD_TYPE'] == "DEVELOPER"): for option in opts.log_levels: commands["compiler"].append("-T{}".format(option)) if opts.passes: commands["compiler"].append("--top4 {}".format(",".join(opts.passes))) if opts.debug: commands["compiler"].append("-vvv") if opts.dump_dir: commands["compiler"].append("--dump {}".format(opts.dump_dir)) if opts.json: commands["compiler"].append("--toJSON {}".format(opts.json)) if opts.pretty_print: commands["compiler"].append("--pp {}".format(opts.pretty_print)) for option in opts.assembler_options: commands["assembler"] += shlex.split(option) for option in opts.linker_options: commands["linker"] += shlex.split(option) # set output directory if not os.path.exists(opts.output_directory): os.makedirs(opts.output_directory) commands['preprocessor'].insert(0, cfg.get_preprocessor(backend)) commands['compiler'].insert(0, cfg.get_compiler(backend)) commands['assembler'].insert(0, cfg.get_assembler(backend)) commands['linker'].insert(0, cfg.get_linker(backend)) # handle mode flags step_enable = [False, False, False, False] if opts.run_preprocessor_only: step_enable = [True, False, False, False] elif opts.skip_preprocessor: step_enable = [False, True, True, True] elif opts.run_till_assembler: step_enable = [True, True, False, False] elif opts.run_all: step_enable = [True, True, True, True] # default search path if opts.language == 'p4-16': commands['preprocessor'].append("-I {}".format(os.environ['P4C_16_INCLUDE_PATH'])) commands['compiler'].append("-I {}".format(os.environ['P4C_16_INCLUDE_PATH'])) else: commands['preprocessor'].append("-I {}".format(os.environ['P4C_14_INCLUDE_PATH'])) commands['compiler'].append("-I {}".format(os.environ['P4C_14_INCLUDE_PATH'])) # append search path for path in opts.search_path: commands['preprocessor'].append("-I") commands['preprocessor'].append(path) commands['compiler'].append("-I") commands['compiler'].append(path) # set p4 version if opts.language == 'p4-16': commands['compiler'].append("--p4v=16") else: commands['compiler'].append("--p4v=14") # P4Runtime options if opts.p4runtime_file: commands['compiler'].append("--p4runtime-file {}".format(opts.p4runtime_file)) commands['compiler'].append("--p4runtime-format {}".format(opts.p4runtime_format)) for idx, step in enumerate(cfg.steps[backend]): cmd = [] for c in commands[step]: cmd = cmd + shlex.split(c) options = cfg.options[backend][step] for option in options: cmd = cmd + shlex.split(option) # check if cmd in PATH unless absolute path if cmd[0].find('/') != 0 and (util.find_bin(cmd[0]) == None): print "{}: command not found".format(cmd[0]) sys.exit(1) # only dry-run if opts.dry_run: print "{}: {}".format(step, " ".join(cmd)) continue # skip if not required if not step_enable[idx]: continue # run command try: p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) except: import traceback print "error invoking {}".format(" ".join(cmd)) print traceback.format_exc() sys.exit(1) if opts.debug: print 'running {}'.format(' '.join(cmd)) out, err = p.communicate() # now wait if len(out) > 0: print out if p.returncode != 0: sys.exit(p.returncode)
def main(): parser = argparse.ArgumentParser(conflict_handler='resolve') parser.add_argument("-V", "--version", dest="show_version", help="show version and exit", action="store_true", default=False) parser.add_argument("-v", "--debug", dest="debug", help="verbose", action="store_true", default=False) parser.add_argument("-###", "--test-only", dest="dry_run", help="print (but do not run) the commands", action="store_true", default=False) parser.add_argument("-Xpreprocessor", dest="preprocessor_options", metavar="<arg>", help="Pass <arg> to the preprocessor", action="append", default=[]) parser.add_argument("-Xp4c", dest="compiler_options", metavar="<arg>", help="Pass <arg> to the compiler", action="append", default=[]) parser.add_argument("-Xassembler", dest="assembler_options", metavar="<arg>", help="Pass <arg> to the assembler", action="append", default=[]) parser.add_argument("-Xlinker", dest="linker_options", metavar="<arg>", help="Pass <arg> to the linker", action="append", default=[]) parser.add_argument("-b", "--target", dest="target", help="specify target device", action="store", default="bmv2") parser.add_argument("-a", "--arch", dest="arch", help="specify target architecture", action="store", default="v1model") parser.add_argument( "-c", "--compile", dest="run_all", help="Only run preprocess, compile, and assemble steps", action="store_true", default=True) parser.add_argument("-D", dest="preprocessor_defines", help="define a macro to be used by the preprocessor", action="append", default=[]) parser.add_argument("-E", dest="run_preprocessor_only", help="Only run the preprocessor", action="store_true", default=False) parser.add_argument("-e", dest="skip_preprocessor", help="Skip the preprocessor", action="store_true", default=False) parser.add_argument("-g", dest="debug_info", help="Generate debug information", action="store_true", default=False) parser.add_argument("-I", dest="search_path", help="Add directory to include search path", action="append", default=[]) parser.add_argument("-o", "--output", dest="output_directory", help="Write output to the provided path", action="store", metavar="PATH", default=".") parser.add_argument("--p4runtime-file", help="Write a P4Runtime control plane API description " "to the specified file. " "[Deprecated; use '--p4runtime-files' instead]", action="store", default=None) parser.add_argument( "--p4runtime-files", help="Write the P4Runtime control plane API description (P4Info) " "to the specified files (comma-separated list); " "format is detected based on file suffix. " "Legal suffixes are .txt, .json, .bin.", action="store", default=None) parser.add_argument("--p4runtime-format", choices=["binary", "json", "text"], help="Choose output format for the P4Runtime API " "description (default is binary). " "[Deprecated; use '--p4runtime-files' instead]", action="store", default="binary") parser.add_argument( "--help-pragmas", "--pragma-help", "--pragmas-help", "--help-annotations", "--annotation-help", "--annotations-help", dest="help_pragmas", action="store_true", default=False, help= "Print the documentation about supported annotations/pragmas and exit." ) parser.add_argument("--help-targets", "--target-help", "--targets-help", dest="show_target_help", help="Display target specific command line options.", action="store_true", default=False) parser.add_argument( "--disable-annotations", "--disable-annotation", "--disable-pragmas", "--disable-pragma", dest="disabled_annos", action="store", help= "List of annotations (comma separated) that should be ignored by the compiler." ) parser.add_argument("-S", dest="run_till_assembler", help="Only run the preprocess and compilation steps", action="store_true", default=False) parser.add_argument( "--std", "-x", dest="language", choices=["p4-14", "p4_14", "p4-16", "p4_16"], help="Treat subsequent input files as having type language.", action="store", default="p4-16") parser.add_argument("--ndebug", dest="ndebug_mode", help="Compile program in non-debug mode.\n", action="store_true", default=False) if (os.environ['P4C_BUILD_TYPE'] == "DEVELOPER"): add_developer_options(parser) parser.add_argument("source_file", nargs='?', help="Files to compile", default=None) # load supported configuration. # We load these before we parse options, so that backends can register # proprietary options cfg_files = glob.glob("{}/*.cfg".format(os.environ['P4C_CFG_PATH'])) cfg = config.Config(config_prefix="p4c") for cf in cfg_files: cfg.load_from_config(cf, parser) # parse the arguments opts = parser.parse_args() user_defined_version = os.environ.get('P4C_DEFAULT_VERSION') if user_defined_version != None: opts.language = user_defined_version # accept multiple ways of specifying which language, and ensure that it is a consistent # string from now on. if opts.language == "p4_14": opts.language = "p4-14" if opts.language == "p4_16": opts.language = "p4-16" user_defined_target = os.environ.get('P4C_DEFAULT_TARGET') if user_defined_target != None: opts.target = user_defined_target user_defined_arch = os.environ.get('P4C_DEFAULT_ARCH') if user_defined_arch != None: opts.arch = user_defined_arch # deal with early exits if opts.show_version: print "p4c", get_version() sys.exit(0) if opts.show_target_help: print display_supported_targets(cfg) sys.exit(0) # When using --help-* options, we don't necessarily need to pass an input file # However, by default the driver checks the input and fails if it does not exist. # Also, loading the backend configuration files requires a source file to be set, # so in that case, we set the input to dummy.p4 and expect that the backend itself # will do its printing and ignore the input file. # If not, the compiler will error out anyway. checkInput = not opts.help_pragmas input_specified = False if opts.source_file: input_specified = True if (os.environ['P4C_BUILD_TYPE'] == "DEVELOPER"): if opts.json_source: input_specified = True if checkInput and not input_specified: parser.error('No input specified.') elif not checkInput: opts.source_file = "dummy.p4" if (os.environ['P4C_BUILD_TYPE'] == "DEVELOPER"): if opts.json_source: opts.source_file = opts.json_source if checkInput and not os.path.isfile(opts.source_file): print >> sys.stderr, 'Input file ' + opts.source_file + ' does not exist' sys.exit(1) # check that the tuple value is correct backend = (opts.target, opts.arch) if (len(backend) != 2): parser.error("Invalid target and arch tuple: {}\n{}".\ format(backend, display_supported_targets(cfg))) # find the backend backend = None for target in cfg.target: regex = target._backend.replace('*', '[a-zA-Z0-9*]*') pattern = re.compile(regex) if (pattern.match(opts.target + '-' + opts.arch)): backend = target break if backend == None: parser.error("Unknown backend: {}-{}".format(str(opts.target), str(opts.arch))) # set all configuration and command line options for backend backend.process_command_line_options(opts) # run all commands rc = backend.run() sys.exit(rc)
def main(): parser = argparse.ArgumentParser(conflict_handler='resolve') parser.add_argument("-V", "--version", dest="show_version", help="show version and exit", action="store_true", default=False) parser.add_argument("-v", "--debug", dest="debug", help="verbose", action="store_true", default=False) parser.add_argument("-###", "--test-only", dest="dry_run", help="print (but do not run) the commands", action="store_true", default=False) parser.add_argument("-Xpreprocessor", dest="preprocessor_options", metavar="<arg>", help="Pass <arg> to the preprocessor", action="append", default=[]) parser.add_argument("-Xp4c", dest="compiler_options", metavar="<arg>", help="Pass <arg> to the compiler", action="append", default=[]) parser.add_argument("-Xassembler", dest="assembler_options", metavar="<arg>", help="Pass <arg> to the assembler", action="append", default=[]) parser.add_argument("-Xlinker", dest="linker_options", metavar="<arg>", help="Pass <arg> to the linker", action="append", default=[]) parser.add_argument("-b", "--target", dest="backend", help="specify target backend", action="store", default="bmv2-ss-p4org") parser.add_argument( "-c", dest="run_all", help="Only run preprocess, compile, and assemble steps", action="store_true", default=True) parser.add_argument("-D", dest="preprocessor_defines", help="define a macro to be used by the preprocessor", action="append", default=[]) parser.add_argument("-E", dest="run_preprocessor_only", help="Only run the preprocessor", action="store_true", default=False) parser.add_argument("-e", dest="skip_preprocessor", help="Skip the preprocessor", action="store_true", default=False) parser.add_argument("-g", dest="debug_info", help="Generate debug information", action="store_true", default=False) parser.add_argument("-I", dest="search_path", help="Add directory to include search path", action="append", default=[]) parser.add_argument("-o", dest="output_directory", help="Write output to the provided path", action="store", metavar="PATH", default=".") parser.add_argument("--p4runtime-file", help="Write a P4Runtime control plane API description " "to the specified file.", action="store", default=None) parser.add_argument("--p4runtime-format", choices=["binary", "json", "text"], help="Choose output format for the P4Runtime API " "description (default is binary).", action="store", default="binary") parser.add_argument("--target-help", dest="show_target_help", help="Display target specific command line options.", action="store_true", default=False) parser.add_argument("-S", dest="run_till_assembler", help="Only run the preprocess and compilation steps", action="store_true", default=False) parser.add_argument( "--std", "-x", dest="language", choices=["p4-14", "p4-16"], help="Treat subsequent input files as having type language.", action="store", default="p4-16") if (os.environ['P4C_BUILD_TYPE'] == "DEVELOPER"): add_developer_options(parser) parser.add_argument("source_file", nargs='?', help="Files to compile", default=None) # load supported configuration. # We load these before we parse options, so that backends can register # proprietary options cfg_files = glob.glob("{}/*.cfg".format(os.environ['P4C_CFG_PATH'])) cfg = config.Config(config_prefix="p4c") for cf in cfg_files: cfg.load_from_config(cf, parser) # parse the arguments opts = parser.parse_args() # deal with early exits if opts.show_version: print "p4c", get_version() sys.exit(0) if opts.show_target_help: print display_supported_targets(cfg) sys.exit(0) if not opts.source_file: parser.error('No input specified.') # check that the triplet value is correct triplet = opts.backend.split('-') if (len(triplet) != 3): parser.error("Invalid target-arch-vendor triplet: {}\n{}".\ format(triplet, display_supported_targets(cfg))) # find the backend backend = None for target in cfg.target: regex = target._backend.replace('*', '[a-zA-Z0-9*]*') pattern = re.compile(regex) if (pattern.match(opts.backend)): backend = target break if backend == None: parser.error("Unknown backend: {}".format(str(opts.backend))) # set all configuration and command line options for backend backend.process_command_line_options(opts) # run all commands backend.run()