| #!/usr/bin/env python3 | 
 |  | 
 | """Generate the compilation target feature printing source code. | 
 |  | 
 | The source code for detecting target features is heavily redundant and | 
 | copy-pasted, and is easier to maintain using a generative script. | 
 |  | 
 | This script creates the source and the include files in its current | 
 | directory. | 
 | """ | 
 |  | 
 | import argparse | 
 | from pathlib import Path | 
 | from typing import Dict, List, Iterable | 
 |  | 
 | _CPP_BOILERPLATE: str = """\ | 
 | #include <stdio.h> | 
 |  | 
 | #define TO_STRING_EXP(DEF) #DEF | 
 | #define TO_STRING(DEF) TO_STRING_EXP(DEF) | 
 | """ | 
 |  | 
 | _FEATURES = { | 
 |     "Aarch64": [ | 
 |         "__ARM_FEATURE_AES", | 
 |         "__ARM_FEATURE_BTI", | 
 |         "__ARM_FEATURE_CRC32", | 
 |         "__ARM_FEATURE_CRYPTO", | 
 |         "__ARM_FEATURE_PAC_DEFAULT", | 
 |         "__ARM_FEATURE_SHA2", | 
 |         "__ARM_FEATURE_SHA3", | 
 |         "__ARM_FEATURE_SHA512", | 
 |     ], | 
 |     "Arm32": [ | 
 |         "__ARM_ARCH_ISA_THUMB", | 
 |         "__ARM_FEATURE_AES", | 
 |         "__ARM_FEATURE_BTI", | 
 |         "__ARM_FEATURE_CRC32", | 
 |         "__ARM_FEATURE_CRYPTO", | 
 |         "__ARM_FEATURE_PAC_DEFAULT", | 
 |         "__ARM_FEATURE_SHA2", | 
 |     ], | 
 |     "X86": [ | 
 |         "__AES__", | 
 |         "__AVX__", | 
 |         "__CRC32__", | 
 |         "__POPCNT__", | 
 |         "__SHA512__", | 
 |         "__SHA__", | 
 |     ], | 
 |     "Riscv": [ | 
 |         "__riscv_vector", | 
 |     ], | 
 | } | 
 |  | 
 |  | 
 | def _make_function_sig(name: str) -> str: | 
 |     return f"void print{name}TargetFeatures()" | 
 |  | 
 |  | 
 | def check_template(define: str) -> List[str]: | 
 |     return [ | 
 |         f"#if defined({define})", | 
 |         f'  printf("%s=%s\\n", TO_STRING_EXP({define}), TO_STRING({define}));', | 
 |         "#else", | 
 |         f'  printf("%s not defined\\n", TO_STRING_EXP({define}));', | 
 |         "#endif", | 
 |     ] | 
 |  | 
 |  | 
 | def generate_cpp_file(define_mapping: Dict[str, List[str]]) -> List[str]: | 
 |     out: List[str] = _CPP_BOILERPLATE.split("\n") | 
 |     for target, defines in define_mapping.items(): | 
 |         out.append("") | 
 |         out.extend(generate_print_function(target, defines)) | 
 |     return out | 
 |  | 
 |  | 
 | def generate_print_function(name: str, defines: List[str]) -> List[str]: | 
 |     """Generate a print<DEFINE>TargetFeatures function.""" | 
 |     function_body = [_make_function_sig(name) + " {"] | 
 |     for d in defines: | 
 |         function_body.extend(check_template(d)) | 
 |     function_body.append("}") | 
 |     return function_body | 
 |  | 
 |  | 
 | def parse_args() -> argparse.Namespace: | 
 |     parser = argparse.ArgumentParser(description=__doc__) | 
 |     parser.add_argument( | 
 |         "cpp_in", | 
 |         type=Path, | 
 |         help="Output path to generate the cpp file.", | 
 |     ) | 
 |     return parser.parse_args() | 
 |  | 
 |  | 
 | def main() -> None: | 
 |     args = parse_args() | 
 |     printer_cpp_filepath = args.cpp_in | 
 |     printer_cpp_filepath.write_text( | 
 |         "\n".join(generate_cpp_file(_FEATURES)), encoding="utf-8" | 
 |     ) | 
 |  | 
 |  | 
 | if __name__ == "__main__": | 
 |     main() |