123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749 |
- #!/usr/bin/env python3
- # ################################################################
- # Copyright (c) 2021-2021, Facebook, Inc.
- # All rights reserved.
- #
- # This source code is licensed under both the BSD-style license (found in the
- # LICENSE file in the root directory of this source tree) and the GPLv2 (found
- # in the COPYING file in the root directory of this source tree).
- # You may select, at your option, one of the above-listed licenses.
- # ##########################################################################
- import argparse
- import contextlib
- import os
- import re
- import shutil
- import sys
- from typing import Optional
- INCLUDED_SUBDIRS = ["common", "compress", "decompress"]
- SKIPPED_FILES = [
- "common/mem.h",
- "common/zstd_deps.h",
- "common/pool.c",
- "common/pool.h",
- "common/threading.c",
- "common/threading.h",
- "common/zstd_trace.h",
- "compress/zstdmt_compress.h",
- "compress/zstdmt_compress.c",
- ]
- XXHASH_FILES = [
- "common/xxhash.c",
- "common/xxhash.h",
- ]
- class FileLines(object):
- def __init__(self, filename):
- self.filename = filename
- with open(self.filename, "r") as f:
- self.lines = f.readlines()
- def write(self):
- with open(self.filename, "w") as f:
- f.write("".join(self.lines))
- class PartialPreprocessor(object):
- """
- Looks for simple ifdefs and ifndefs and replaces them.
- Handles && and ||.
- Has fancy logic to handle translating elifs to ifs.
- Only looks for macros in the first part of the expression with no
- parens.
- Does not handle multi-line macros (only looks in first line).
- """
- def __init__(self, defs: [(str, Optional[str])], replaces: [(str, str)], undefs: [str]):
- MACRO_GROUP = r"(?P<macro>[a-zA-Z_][a-zA-Z_0-9]*)"
- ELIF_GROUP = r"(?P<elif>el)?"
- OP_GROUP = r"(?P<op>&&|\|\|)?"
- self._defs = {macro:value for macro, value in defs}
- self._replaces = {macro:value for macro, value in replaces}
- self._defs.update(self._replaces)
- self._undefs = set(undefs)
- self._define = re.compile(r"\s*#\s*define")
- self._if = re.compile(r"\s*#\s*if")
- self._elif = re.compile(r"\s*#\s*(?P<elif>el)if")
- self._else = re.compile(r"\s*#\s*(?P<else>else)")
- self._endif = re.compile(r"\s*#\s*endif")
- self._ifdef = re.compile(fr"\s*#\s*if(?P<not>n)?def {MACRO_GROUP}\s*")
- self._if_defined = re.compile(
- fr"\s*#\s*{ELIF_GROUP}if\s+(?P<not>!)?\s*defined\s*\(\s*{MACRO_GROUP}\s*\)\s*{OP_GROUP}"
- )
- self._if_defined_value = re.compile(
- fr"\s*#\s*{ELIF_GROUP}if\s+defined\s*\(\s*{MACRO_GROUP}\s*\)\s*"
- fr"(?P<op>&&)\s*"
- fr"(?P<openp>\()?\s*"
- fr"(?P<macro2>[a-zA-Z_][a-zA-Z_0-9]*)\s*"
- fr"(?P<cmp>[=><!]+)\s*"
- fr"(?P<value>[0-9]*)\s*"
- fr"(?P<closep>\))?\s*"
- )
- self._if_true = re.compile(
- fr"\s*#\s*{ELIF_GROUP}if\s+{MACRO_GROUP}\s*{OP_GROUP}"
- )
- self._c_comment = re.compile(r"/\*.*?\*/")
- self._cpp_comment = re.compile(r"//")
- def _log(self, *args, **kwargs):
- print(*args, **kwargs)
- def _strip_comments(self, line):
- # First strip c-style comments (may include //)
- while True:
- m = self._c_comment.search(line)
- if m is None:
- break
- line = line[:m.start()] + line[m.end():]
- # Then strip cpp-style comments
- m = self._cpp_comment.search(line)
- if m is not None:
- line = line[:m.start()]
- return line
- def _fixup_indentation(self, macro, replace: [str]):
- if len(replace) == 0:
- return replace
- if len(replace) == 1 and self._define.match(replace[0]) is None:
- # If there is only one line, only replace defines
- return replace
- all_pound = True
- for line in replace:
- if not line.startswith('#'):
- all_pound = False
- if all_pound:
- replace = [line[1:] for line in replace]
- min_spaces = len(replace[0])
- for line in replace:
- spaces = 0
- for i, c in enumerate(line):
- if c != ' ':
- # Non-preprocessor line ==> skip the fixup
- if not all_pound and c != '#':
- return replace
- spaces = i
- break
- min_spaces = min(min_spaces, spaces)
- replace = [line[min_spaces:] for line in replace]
- if all_pound:
- replace = ["#" + line for line in replace]
- return replace
- def _handle_if_block(self, macro, idx, is_true, prepend):
- """
- Remove the #if or #elif block starting on this line.
- """
- REMOVE_ONE = 0
- KEEP_ONE = 1
- REMOVE_REST = 2
- if is_true:
- state = KEEP_ONE
- else:
- state = REMOVE_ONE
- line = self._inlines[idx]
- is_if = self._if.match(line) is not None
- assert is_if or self._elif.match(line) is not None
- depth = 0
- start_idx = idx
- idx += 1
- replace = prepend
- finished = False
- while idx < len(self._inlines):
- line = self._inlines[idx]
- # Nested if statement
- if self._if.match(line):
- depth += 1
- idx += 1
- continue
- # We're inside a nested statement
- if depth > 0:
- if self._endif.match(line):
- depth -= 1
- idx += 1
- continue
- # We're at the original depth
- # Looking only for an endif.
- # We've found a true statement, but haven't
- # completely elided the if block, so we just
- # remove the remainder.
- if state == REMOVE_REST:
- if self._endif.match(line):
- if is_if:
- # Remove the endif because we took the first if
- idx += 1
- finished = True
- break
- idx += 1
- continue
- if state == KEEP_ONE:
- m = self._elif.match(line)
- if self._endif.match(line):
- replace += self._inlines[start_idx + 1:idx]
- idx += 1
- finished = True
- break
- if self._elif.match(line) or self._else.match(line):
- replace += self._inlines[start_idx + 1:idx]
- state = REMOVE_REST
- idx += 1
- continue
- if state == REMOVE_ONE:
- m = self._elif.match(line)
- if m is not None:
- if is_if:
- idx += 1
- b = m.start('elif')
- e = m.end('elif')
- assert e - b == 2
- replace.append(line[:b] + line[e:])
- finished = True
- break
- m = self._else.match(line)
- if m is not None:
- if is_if:
- idx += 1
- while self._endif.match(self._inlines[idx]) is None:
- replace.append(self._inlines[idx])
- idx += 1
- idx += 1
- finished = True
- break
- if self._endif.match(line):
- if is_if:
- # Remove the endif because no other elifs
- idx += 1
- finished = True
- break
- idx += 1
- continue
- if not finished:
- raise RuntimeError("Unterminated if block!")
- replace = self._fixup_indentation(macro, replace)
- self._log(f"\tHardwiring {macro}")
- if start_idx > 0:
- self._log(f"\t\t {self._inlines[start_idx - 1][:-1]}")
- for x in range(start_idx, idx):
- self._log(f"\t\t- {self._inlines[x][:-1]}")
- for line in replace:
- self._log(f"\t\t+ {line[:-1]}")
- if idx < len(self._inlines):
- self._log(f"\t\t {self._inlines[idx][:-1]}")
- return idx, replace
- def _preprocess_once(self):
- outlines = []
- idx = 0
- changed = False
- while idx < len(self._inlines):
- line = self._inlines[idx]
- sline = self._strip_comments(line)
- m = self._ifdef.fullmatch(sline)
- if_true = False
- if m is None:
- m = self._if_defined_value.fullmatch(sline)
- if m is None:
- m = self._if_defined.match(sline)
- if m is None:
- m = self._if_true.match(sline)
- if_true = (m is not None)
- if m is None:
- outlines.append(line)
- idx += 1
- continue
- groups = m.groupdict()
- macro = groups['macro']
- op = groups.get('op')
- if not (macro in self._defs or macro in self._undefs):
- outlines.append(line)
- idx += 1
- continue
- defined = macro in self._defs
- # Needed variables set:
- # resolved: Is the statement fully resolved?
- # is_true: If resolved, is the statement true?
- ifdef = False
- if if_true:
- if not defined:
- outlines.append(line)
- idx += 1
- continue
- defined_value = self._defs[macro]
- is_int = True
- try:
- defined_value = int(defined_value)
- except TypeError:
- is_int = False
- except ValueError:
- is_int = False
- resolved = is_int
- is_true = (defined_value != 0)
- if resolved and op is not None:
- if op == '&&':
- resolved = not is_true
- else:
- assert op == '||'
- resolved = is_true
- else:
- ifdef = groups.get('not') is None
- elseif = groups.get('elif') is not None
- macro2 = groups.get('macro2')
- cmp = groups.get('cmp')
- value = groups.get('value')
- openp = groups.get('openp')
- closep = groups.get('closep')
- is_true = (ifdef == defined)
- resolved = True
- if op is not None:
- if op == '&&':
- resolved = not is_true
- else:
- assert op == '||'
- resolved = is_true
- if macro2 is not None and not resolved:
- assert ifdef and defined and op == '&&' and cmp is not None
- # If the statment is true, but we have a single value check, then
- # check the value.
- defined_value = self._defs[macro]
- are_ints = True
- try:
- defined_value = int(defined_value)
- value = int(value)
- except TypeError:
- are_ints = False
- except ValueError:
- are_ints = False
- if (
- macro == macro2 and
- ((openp is None) == (closep is None)) and
- are_ints
- ):
- resolved = True
- if cmp == '<':
- is_true = defined_value < value
- elif cmp == '<=':
- is_true = defined_value <= value
- elif cmp == '==':
- is_true = defined_value == value
- elif cmp == '!=':
- is_true = defined_value != value
- elif cmp == '>=':
- is_true = defined_value >= value
- elif cmp == '>':
- is_true = defined_value > value
- else:
- resolved = False
- if op is not None and not resolved:
- # Remove the first op in the line + spaces
- if op == '&&':
- opre = op
- else:
- assert op == '||'
- opre = r'\|\|'
- needle = re.compile(fr"(?P<if>\s*#\s*(el)?if\s+).*?(?P<op>{opre}\s*)")
- match = needle.match(line)
- assert match is not None
- newline = line[:match.end('if')] + line[match.end('op'):]
- self._log(f"\tHardwiring partially resolved {macro}")
- self._log(f"\t\t- {line[:-1]}")
- self._log(f"\t\t+ {newline[:-1]}")
- outlines.append(newline)
- idx += 1
- continue
- # Skip any statements we cannot fully compute
- if not resolved:
- outlines.append(line)
- idx += 1
- continue
- prepend = []
- if macro in self._replaces:
- assert not ifdef
- assert op is None
- value = self._replaces.pop(macro)
- prepend = [f"#define {macro} {value}\n"]
- idx, replace = self._handle_if_block(macro, idx, is_true, prepend)
- outlines += replace
- changed = True
- return changed, outlines
- def preprocess(self, filename):
- with open(filename, 'r') as f:
- self._inlines = f.readlines()
- changed = True
- iters = 0
- while changed:
- iters += 1
- changed, outlines = self._preprocess_once()
- self._inlines = outlines
- with open(filename, 'w') as f:
- f.write(''.join(self._inlines))
- class Freestanding(object):
- def __init__(
- self, zstd_deps: str, mem: str, source_lib: str, output_lib: str,
- external_xxhash: bool, xxh64_state: Optional[str],
- xxh64_prefix: Optional[str], rewritten_includes: [(str, str)],
- defs: [(str, Optional[str])], replaces: [(str, str)],
- undefs: [str], excludes: [str], seds: [str],
- ):
- self._zstd_deps = zstd_deps
- self._mem = mem
- self._src_lib = source_lib
- self._dst_lib = output_lib
- self._external_xxhash = external_xxhash
- self._xxh64_state = xxh64_state
- self._xxh64_prefix = xxh64_prefix
- self._rewritten_includes = rewritten_includes
- self._defs = defs
- self._replaces = replaces
- self._undefs = undefs
- self._excludes = excludes
- self._seds = seds
- def _dst_lib_file_paths(self):
- """
- Yields all the file paths in the dst_lib.
- """
- for root, dirname, filenames in os.walk(self._dst_lib):
- for filename in filenames:
- filepath = os.path.join(root, filename)
- yield filepath
- def _log(self, *args, **kwargs):
- print(*args, **kwargs)
- def _copy_file(self, lib_path):
- suffixes = [".c", ".h", ".S"]
- if not any((lib_path.endswith(suffix) for suffix in suffixes)):
- return
- if lib_path in SKIPPED_FILES:
- self._log(f"\tSkipping file: {lib_path}")
- return
- if self._external_xxhash and lib_path in XXHASH_FILES:
- self._log(f"\tSkipping xxhash file: {lib_path}")
- return
- src_path = os.path.join(self._src_lib, lib_path)
- dst_path = os.path.join(self._dst_lib, lib_path)
- self._log(f"\tCopying: {src_path} -> {dst_path}")
- shutil.copyfile(src_path, dst_path)
- def _copy_source_lib(self):
- self._log("Copying source library into output library")
- assert os.path.exists(self._src_lib)
- os.makedirs(self._dst_lib, exist_ok=True)
- self._copy_file("zstd.h")
- self._copy_file("zstd_errors.h")
- for subdir in INCLUDED_SUBDIRS:
- src_dir = os.path.join(self._src_lib, subdir)
- dst_dir = os.path.join(self._dst_lib, subdir)
- assert os.path.exists(src_dir)
- os.makedirs(dst_dir, exist_ok=True)
- for filename in os.listdir(src_dir):
- lib_path = os.path.join(subdir, filename)
- self._copy_file(lib_path)
- def _copy_zstd_deps(self):
- dst_zstd_deps = os.path.join(self._dst_lib, "common", "zstd_deps.h")
- self._log(f"Copying zstd_deps: {self._zstd_deps} -> {dst_zstd_deps}")
- shutil.copyfile(self._zstd_deps, dst_zstd_deps)
- def _copy_mem(self):
- dst_mem = os.path.join(self._dst_lib, "common", "mem.h")
- self._log(f"Copying mem: {self._mem} -> {dst_mem}")
- shutil.copyfile(self._mem, dst_mem)
- def _hardwire_preprocessor(self, name: str, value: Optional[str] = None, undef=False):
- """
- If value=None then hardwire that it is defined, but not what the value is.
- If undef=True then value must be None.
- If value='' then the macro is defined to '' exactly.
- """
- assert not (undef and value is not None)
- for filepath in self._dst_lib_file_paths():
- file = FileLines(filepath)
- def _hardwire_defines(self):
- self._log("Hardwiring macros")
- partial_preprocessor = PartialPreprocessor(self._defs, self._replaces, self._undefs)
- for filepath in self._dst_lib_file_paths():
- partial_preprocessor.preprocess(filepath)
- def _remove_excludes(self):
- self._log("Removing excluded sections")
- for exclude in self._excludes:
- self._log(f"\tRemoving excluded sections for: {exclude}")
- begin_re = re.compile(f"BEGIN {exclude}")
- end_re = re.compile(f"END {exclude}")
- for filepath in self._dst_lib_file_paths():
- file = FileLines(filepath)
- outlines = []
- skipped = []
- emit = True
- for line in file.lines:
- if emit and begin_re.search(line) is not None:
- assert end_re.search(line) is None
- emit = False
- if emit:
- outlines.append(line)
- else:
- skipped.append(line)
- if end_re.search(line) is not None:
- assert begin_re.search(line) is None
- self._log(f"\t\tRemoving excluded section: {exclude}")
- for s in skipped:
- self._log(f"\t\t\t- {s}")
- emit = True
- skipped = []
- if not emit:
- raise RuntimeError("Excluded section unfinished!")
- file.lines = outlines
- file.write()
- def _rewrite_include(self, original, rewritten):
- self._log(f"\tRewriting include: {original} -> {rewritten}")
- regex = re.compile(f"\\s*#\\s*include\\s*(?P<include>{original})")
- for filepath in self._dst_lib_file_paths():
- file = FileLines(filepath)
- for i, line in enumerate(file.lines):
- match = regex.match(line)
- if match is None:
- continue
- s = match.start('include')
- e = match.end('include')
- file.lines[i] = line[:s] + rewritten + line[e:]
- file.write()
- def _rewrite_includes(self):
- self._log("Rewriting includes")
- for original, rewritten in self._rewritten_includes:
- self._rewrite_include(original, rewritten)
- def _replace_xxh64_prefix(self):
- if self._xxh64_prefix is None:
- return
- self._log(f"Replacing XXH64 prefix with {self._xxh64_prefix}")
- replacements = []
- if self._xxh64_state is not None:
- replacements.append(
- (re.compile(r"([^\w]|^)(?P<orig>XXH64_state_t)([^\w]|$)"), self._xxh64_state)
- )
- if self._xxh64_prefix is not None:
- replacements.append(
- (re.compile(r"([^\w]|^)(?P<orig>XXH64)[\(_]"), self._xxh64_prefix)
- )
- for filepath in self._dst_lib_file_paths():
- file = FileLines(filepath)
- for i, line in enumerate(file.lines):
- modified = False
- for regex, replacement in replacements:
- match = regex.search(line)
- while match is not None:
- modified = True
- b = match.start('orig')
- e = match.end('orig')
- line = line[:b] + replacement + line[e:]
- match = regex.search(line)
- if modified:
- self._log(f"\t- {file.lines[i][:-1]}")
- self._log(f"\t+ {line[:-1]}")
- file.lines[i] = line
- file.write()
- def _parse_sed(self, sed):
- assert sed[0] == 's'
- delim = sed[1]
- match = re.fullmatch(f's{delim}(.+){delim}(.*){delim}(.*)', sed)
- assert match is not None
- regex = re.compile(match.group(1))
- format_str = match.group(2)
- is_global = match.group(3) == 'g'
- return regex, format_str, is_global
- def _process_sed(self, sed):
- self._log(f"Processing sed: {sed}")
- regex, format_str, is_global = self._parse_sed(sed)
- for filepath in self._dst_lib_file_paths():
- file = FileLines(filepath)
- for i, line in enumerate(file.lines):
- modified = False
- while True:
- match = regex.search(line)
- if match is None:
- break
- replacement = format_str.format(match.groups(''), match.groupdict(''))
- b = match.start()
- e = match.end()
- line = line[:b] + replacement + line[e:]
- modified = True
- if not is_global:
- break
- if modified:
- self._log(f"\t- {file.lines[i][:-1]}")
- self._log(f"\t+ {line[:-1]}")
- file.lines[i] = line
- file.write()
- def _process_seds(self):
- self._log("Processing seds")
- for sed in self._seds:
- self._process_sed(sed)
- def go(self):
- self._copy_source_lib()
- self._copy_zstd_deps()
- self._copy_mem()
- self._hardwire_defines()
- self._remove_excludes()
- self._rewrite_includes()
- self._replace_xxh64_prefix()
- self._process_seds()
- def parse_optional_pair(defines: [str]) -> [(str, Optional[str])]:
- output = []
- for define in defines:
- parsed = define.split('=')
- if len(parsed) == 1:
- output.append((parsed[0], None))
- elif len(parsed) == 2:
- output.append((parsed[0], parsed[1]))
- else:
- raise RuntimeError(f"Bad define: {define}")
- return output
- def parse_pair(rewritten_includes: [str]) -> [(str, str)]:
- output = []
- for rewritten_include in rewritten_includes:
- parsed = rewritten_include.split('=')
- if len(parsed) == 2:
- output.append((parsed[0], parsed[1]))
- else:
- raise RuntimeError(f"Bad rewritten include: {rewritten_include}")
- return output
- def main(name, args):
- parser = argparse.ArgumentParser(prog=name)
- parser.add_argument("--zstd-deps", default="zstd_deps.h", help="Zstd dependencies file")
- parser.add_argument("--mem", default="mem.h", help="Memory module")
- parser.add_argument("--source-lib", default="../../lib", help="Location of the zstd library")
- parser.add_argument("--output-lib", default="./freestanding_lib", help="Where to output the freestanding zstd library")
- parser.add_argument("--xxhash", default=None, help="Alternate external xxhash include e.g. --xxhash='<xxhash.h>'. If set xxhash is not included.")
- parser.add_argument("--xxh64-state", default=None, help="Alternate XXH64 state type (excluding _) e.g. --xxh64-state='struct xxh64_state'")
- parser.add_argument("--xxh64-prefix", default=None, help="Alternate XXH64 function prefix (excluding _) e.g. --xxh64-prefix=xxh64")
- parser.add_argument("--rewrite-include", default=[], dest="rewritten_includes", action="append", help="Rewrite an include REGEX=NEW (e.g. '<stddef\\.h>=<linux/types.h>')")
- parser.add_argument("--sed", default=[], dest="seds", action="append", help="Apply a sed replacement. Format: `s/REGEX/FORMAT/[g]`. REGEX is a Python regex. FORMAT is a Python format string formatted by the regex dict.")
- parser.add_argument("-D", "--define", default=[], dest="defs", action="append", help="Pre-define this macro (can be passed multiple times)")
- parser.add_argument("-U", "--undefine", default=[], dest="undefs", action="append", help="Pre-undefine this macro (can be passed mutliple times)")
- parser.add_argument("-R", "--replace", default=[], dest="replaces", action="append", help="Pre-define this macro and replace the first ifndef block with its definition")
- parser.add_argument("-E", "--exclude", default=[], dest="excludes", action="append", help="Exclude all lines between 'BEGIN <EXCLUDE>' and 'END <EXCLUDE>'")
- args = parser.parse_args(args)
- # Always remove threading
- if "ZSTD_MULTITHREAD" not in args.undefs:
- args.undefs.append("ZSTD_MULTITHREAD")
- args.defs = parse_optional_pair(args.defs)
- for name, _ in args.defs:
- if name in args.undefs:
- raise RuntimeError(f"{name} is both defined and undefined!")
- # Always set tracing to 0
- if "ZSTD_NO_TRACE" not in (arg[0] for arg in args.defs):
- args.defs.append(("ZSTD_NO_TRACE", None))
- args.defs.append(("ZSTD_TRACE", "0"))
- args.replaces = parse_pair(args.replaces)
- for name, _ in args.replaces:
- if name in args.undefs or name in args.defs:
- raise RuntimeError(f"{name} is both replaced and (un)defined!")
- args.rewritten_includes = parse_pair(args.rewritten_includes)
- external_xxhash = False
- if args.xxhash is not None:
- external_xxhash = True
- args.rewritten_includes.append(('"(\\.\\./common/)?xxhash.h"', args.xxhash))
- if args.xxh64_prefix is not None:
- if not external_xxhash:
- raise RuntimeError("--xxh64-prefix may only be used with --xxhash provided")
- if args.xxh64_state is not None:
- if not external_xxhash:
- raise RuntimeError("--xxh64-state may only be used with --xxhash provided")
- Freestanding(
- args.zstd_deps,
- args.mem,
- args.source_lib,
- args.output_lib,
- external_xxhash,
- args.xxh64_state,
- args.xxh64_prefix,
- args.rewritten_includes,
- args.defs,
- args.replaces,
- args.undefs,
- args.excludes,
- args.seds,
- ).go()
- if __name__ == "__main__":
- main(sys.argv[0], sys.argv[1:])
|