blob: dc56eb5fb9f0e2b0e0cc6c9209f09690ca20be04 [file] [log] [blame] [edit]
#!/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()