[DYNACACHE] Added auto-generated DynaCache versions (#3858)

* [DYNACACHE] Added auto-generated DynaCache versions

* Guarded dynacache_hashes.h with DYNAREC
This commit is contained in:
Yang Liu authored and GitHub committed 2026-05-13 10:44:58 +02:00
1 parent 75721e4f97
commit 6ccba477de
5 files changed
+132 -21

No files matched your search

+1
View File
@@ -58,6 +58,7 @@ build*/
.cache
.gdb_history
src/git_head.h
src/dynacache_hashes.h
backup/
# Wrapper helper
+12 -1
View File
@@ -393,9 +393,19 @@ if(BOX32)
)
endif()
# git_head.h is a generated file
set(DYNACACHE_HASH_HEADER "${BOX64_ROOT}/src/dynacache_hashes.h")
add_custom_target(generate_dynacache_hashes
COMMAND "${PYTHON_EXECUTABLE}" "${BOX64_ROOT}/tools/gen_dynacache_hashes.py"
--root "${BOX64_ROOT}"
--output "${DYNACACHE_HASH_HEADER}"
BYPRODUCTS "${DYNACACHE_HASH_HEADER}"
VERBATIM
)
# generated files
set_source_files_properties(
"${BOX64_ROOT}/src/git_head.h"
"${BOX64_ROOT}/src/dynacache_hashes.h"
PROPERTIES GENERATED TRUE
HEADER_FILE_ONLY TRUE)
@@ -1299,6 +1309,7 @@ add_library(interpreter OBJECT ${INTERPRETER})
add_library(mainobj OBJECT ${OS_LINUX_SRC} ${ELFLOADER_SRC} ${WRAPPEDS} ${WRAPPEDS32})
add_dependencies(mainobj generate_git_head_target)
add_dependencies(mainobj generate_dynacache_hashes)
add_executable(${BOX64})
target_link_libraries(${BOX64} mainobj)
+9 -20
View File
@@ -21,6 +21,9 @@
#include "rbtree.h"
#include "wine_tools.h"
#include "pe_tools.h"
#ifdef DYNAREC
#include "dynacache_hashes.h"
#endif
box64env_t box64env = { 0 };
@@ -916,31 +919,17 @@ done:
}
/*
There is 3 version to change when evoling things, depending on what is changed:
1. FILE_VERSION for the DynaCache infrastructure
2. DYNAREC_VERSION for dynablock_t changes and other global dynarec change
3. ARCH_VERSION for the architecture specific changes (and there is one per arch)
There are 3 compatibility values for DynaCache:
1. FILE_VERSION for the DynaCache infrastructure and file format
2. DYNAREC_VERSION as the generated hash of common dynarec sources
3. ARCH_VERSION as the generated hash of the active backend sources
An ARCH_VERSION of 0 means Unsupported and disable DynaCache.
Dynacache will ignore any DynaCache file not exactly matching those 3 version.
`box64 --dynacache-clean` can be used from command line to purge obsolete DyaCache files
*/
#define FILE_VERSION 2
#define HEADER_SIGN "DynaCache"
#define SET_VERSION(MAJ, MIN, REV) (((MAJ)<<24)|((MIN)<<16)|(REV))
#ifdef ARM64
#define ARCH_VERSION SET_VERSION(0, 0, 14)
#elif defined(RV64)
#define ARCH_VERSION SET_VERSION(0, 0, 5)
#elif defined(LA64)
#define ARCH_VERSION SET_VERSION(0, 0, 8)
#elif defined(PPC64LE)
#define ARCH_VERSION SET_VERSION(0, 0, 1)
#else
#error meh!
#endif
#define DYNAREC_VERSION SET_VERSION(0, 1, 1)
#define FILE_VERSION 2
#define HEADER_SIGN "DynaCache"
typedef struct DynaCacheHeader_s {
char sign[10]; //"DynaCache\0"
+100
View File
@@ -0,0 +1,100 @@
#!/usr/bin/env python3
import argparse
import hashlib
import os
from pathlib import Path
from typing import List, Set, Tuple
ARCH_DIRS = ("arm64", "la64", "rv64", "ppc64le")
GROUPS = (
("COMMON", Path("src/dynarec"), set(ARCH_DIRS)),
("ARM64", Path("src/dynarec/arm64"), set()),
("LOONGARCH64", Path("src/dynarec/la64"), set()),
("RISCV64", Path("src/dynarec/rv64"), set()),
("PPC64LE", Path("src/dynarec/ppc64le"), set()),
)
def iter_files(base: Path, excluded_dirs: Set[str]) -> List[Path]:
files: List[Path] = []
for path in sorted(base.rglob("*")):
if not path.is_file():
continue
rel_parts = path.relative_to(base).parts
if excluded_dirs and rel_parts and rel_parts[0] in excluded_dirs:
continue
files.append(path)
return files
def hash_files(root: Path, files: List[Path]) -> int:
digest = hashlib.sha256()
for path in files:
rel_path = path.relative_to(root).as_posix().encode("utf-8")
digest.update(rel_path)
digest.update(b"\0")
digest.update(path.read_bytes())
digest.update(b"\0")
value = int.from_bytes(digest.digest()[:3], "big")
return value or 1
def render_header(root: Path) -> str:
values: List[Tuple[str, int]] = []
for name, rel_base, excluded_dirs in GROUPS:
base = root / rel_base
files = iter_files(base, excluded_dirs)
if not files:
raise RuntimeError(f"no files found for {name.lower()} hash in {base}")
values.append((name, hash_files(root, files)))
hashes = dict(values)
lines = [
"/* Auto-generated by tools/gen_dynacache_hashes.py. Do not edit. */",
"#ifndef __DYNACACHE_HASHES_H__",
"#define __DYNACACHE_HASHES_H__",
"",
f"#define DYNAREC_VERSION 0x{hashes['COMMON']:06X}u",
"",
"#if defined(ARM64)",
f"#define ARCH_VERSION 0x{hashes['ARM64']:06X}u",
"#elif defined(RV64)",
f"#define ARCH_VERSION 0x{hashes['RISCV64']:06X}u",
"#elif defined(LA64)",
f"#define ARCH_VERSION 0x{hashes['LOONGARCH64']:06X}u",
"#elif defined(PPC64LE)",
f"#define ARCH_VERSION 0x{hashes['PPC64LE']:06X}u",
"#else",
"#error Unsupported architecture",
"#endif",
"",
"#endif",
]
return "\n".join(lines) + "\n"
def write_if_changed(path: Path, content: str) -> None:
path.parent.mkdir(parents=True, exist_ok=True)
if path.exists() and path.read_text(encoding="utf-8") == content:
return
tmp_path = path.with_suffix(f"{path.suffix}.{os.getpid()}.tmp")
tmp_path.write_text(content, encoding="utf-8")
tmp_path.replace(path)
def main() -> int:
parser = argparse.ArgumentParser()
parser.add_argument("--root", required=True)
parser.add_argument("--output", required=True)
args = parser.parse_args()
root = Path(args.root).resolve()
output = Path(args.output).resolve()
write_if_changed(output, render_header(root))
return 0
if __name__ == "__main__":
raise SystemExit(main())
+10
View File
@@ -119,6 +119,16 @@ include_directories(
"${BOX64_ROOT}/external/musl/internal"
)
set(DYNACACHE_HASH_HEADER "${BOX64_ROOT}/src/dynacache_hashes.h")
add_custom_target(generate_dynacache_hashes
COMMAND "${PYTHON_EXECUTABLE}" "${BOX64_ROOT}/tools/gen_dynacache_hashes.py"
--root "${BOX64_ROOT}"
--output "${DYNACACHE_HASH_HEADER}"
BYPRODUCTS "${DYNACACHE_HASH_HEADER}"
VERBATIM
)
add_dependencies(wowbox64 generate_dynacache_hashes)
set(DLLTOOL aarch64-w64-mingw32-dlltool)
function(import_dll name)