|  | #!/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() |