Skip to content
Bitcoin Roots

v31.1-roots.1 · Commit 1: [PATCH 01/17] build(roots): establish v31 portability foundation

test/cmake/test_leveldb.py

Before: /dev/null · After: test/cmake/test_leveldb.py

File metadata
new file mode 100644
index 0000000000000000000000000000000000000000..b1614ac9b297a083bebff5398b6cb4484f655520

Download original patch · Release notes

Diff rows 1–122 of 122. Line numbers refer to the original before/after files.

+ Added− RemovedUnmarked lines are context.

Scroll the code area horizontally to read long lines. Before is on the left; after is on the right. Unified view fits narrow screens more easily.

test/cmake/test_leveldb.py ADDED
@@ -0,0 +1,122 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ # Copyright (c) 2026-present The Bitcoin Roots developers
3
+ # Distributed under the MIT software license, see the accompanying
4
+ # file COPYING or https://opensource.org/license/mit/.
5
+
6
+ """Exercise MemEnv discovery and consumer linkage with isolated fixture libraries.
7
+
8
+ These are finder regressions, not evidence of compatibility with a real system
9
+ LevelDB release. No package is installed and no host search paths are changed.
10
+ """
11
+
12
+ import argparse
13
+ from pathlib import Path
14
+ import shutil
15
+ import subprocess
16
+ import tempfile
17
+
18
+
19
+ def run(command, *, succeeds=True):
20
+ result = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)
21
+ if (result.returncode == 0) != succeeds:
22
+ raise AssertionError(f"Unexpected result for {command}:\n{result.stdout}")
23
+
24
+
25
+ def main():
26
+ parser = argparse.ArgumentParser(description=__doc__)
27
+ parser.add_argument("--cmake", required=True)
28
+ parser.add_argument("--compiler", required=True)
29
+ parser.add_argument("--generator", required=True)
30
+ parser.add_argument("--modules", required=True)
31
+ args = parser.parse_args()
32
+ with tempfile.TemporaryDirectory(prefix="roots-leveldb-") as directory:
33
+ root = Path(directory)
34
+ headers = root / "include"
35
+ (headers / "leveldb").mkdir(parents=True)
36
+ (headers / "leveldb/filter_policy.h").write_text("// Finder fixture.\n", encoding="utf8")
37
+ (headers / "leveldb/env.h").write_text(
38
+ "#pragma once\nnamespace leveldb { struct Env { virtual ~Env() = default; static Env* Default(); }; }\n",
39
+ encoding="utf8",
40
+ )
41
+ (headers / "memenv.h").write_text(
42
+ '#include <leveldb/env.h>\nnamespace leveldb { Env* NewMemEnv(Env*); }\n', encoding="utf8"
43
+ )
44
+ (root / "env.cpp").write_text(
45
+ '#include <leveldb/env.h>\nleveldb::Env* leveldb::Env::Default() { static Env env; return &env; }\n',
46
+ encoding="utf8",
47
+ )
48
+ (root / "memenv.cpp").write_text(
49
+ '#include <memenv.h>\nleveldb::Env* leveldb::NewMemEnv(Env*) { return new Env; }\n', encoding="utf8"
50
+ )
51
+ (root / "CMakeLists.txt").write_text(
52
+ "cmake_minimum_required(VERSION 3.22)\nproject(Fixture LANGUAGES CXX)\n"
53
+ "include_directories(include)\n"
54
+ "add_library(integrated STATIC env.cpp memenv.cpp)\n"
55
+ "add_library(base STATIC env.cpp)\nadd_library(helper STATIC memenv.cpp)\n", encoding="utf8"
56
+ )
57
+ fixture = root / "fixture"
58
+ run([args.cmake, "-S", str(root), "-B", str(fixture), "-G", args.generator,
59
+ f"-DCMAKE_CXX_COMPILER={args.compiler}"])
60
+ run([args.cmake, "--build", str(fixture), "--config", "Release", "-j2"])
61
+ # CMake controls the filename and multi-config output directory.
62
+ def library(name):
63
+ matches = [p for p in fixture.rglob(f"*{name}*") if p.suffix in (".a", ".lib")]
64
+ assert len(matches) == 1, matches
65
+ return matches[0]
66
+
67
+ consumer = root / "consumer"
68
+ consumer.mkdir()
69
+ (consumer / "main.cpp").write_text(
70
+ '#include <memenv.h>\nint main() { delete leveldb::NewMemEnv(leveldb::Env::Default()); }\n',
71
+ encoding="utf8",
72
+ )
73
+ (consumer / "CMakeLists.txt").write_text(
74
+ "cmake_minimum_required(VERSION 3.22)\nproject(Consumer LANGUAGES CXX)\n"
75
+ "list(APPEND CMAKE_MODULE_PATH \"${MODULES}\")\nfind_package(LevelDB REQUIRED)\n"
76
+ "add_executable(consumer main.cpp)\ntarget_link_libraries(consumer PRIVATE leveldb)\n", encoding="utf8"
77
+ )
78
+ for name, base, helper, succeeds in [
79
+ ("integrated", library("integrated"), "", True),
80
+ ("split", library("base"), library("helper"), True),
81
+ ("missing-helper", library("base"), "LevelDB_MemEnv_LIBRARY_RELEASE-NOTFOUND", False),
82
+ ("broken-debug-helper", library("integrated"), "", False),
83
+ ]:
84
+ build = root / name
85
+ command = [args.cmake, "-S", str(consumer), "-B", str(build), "-DCMAKE_BUILD_TYPE=Release",
86
+ "-G", args.generator,
87
+ f"-DCMAKE_CXX_COMPILER={args.compiler}", f"-DMODULES={args.modules}",
88
+ f"-DCMAKE_FIND_ROOT_PATH={fixture}", "-DCMAKE_FIND_ROOT_PATH_MODE_LIBRARY=ONLY",
89
+ f"-DLevelDB_INCLUDE_DIR={headers}", f"-DLevelDB_MemEnv_INCLUDE_DIR={headers}",
90
+ f"-DLevelDB_LIBRARY_RELEASE={base}",
91
+ f"-DLevelDB_LIBRARY_DEBUG={library('base') if name == 'broken-debug-helper' else 'LevelDB_LIBRARY_DEBUG-NOTFOUND'}",
92
+ f"-DLevelDB_MemEnv_LIBRARY_RELEASE={helper}",
93
+ "-DLevelDB_MemEnv_LIBRARY_DEBUG=LevelDB_MemEnv_LIBRARY_DEBUG-NOTFOUND"]
94
+ run(command, succeeds=succeeds)
95
+ if succeeds:
96
+ run([args.cmake, "--build", str(build), "--config", "Release", "-j2"])
97
+ print(f"PASS: {name} discovery and {'consumer linkage' if succeeds else 'rejection'}")
98
+
99
+ # Reuse one cache while switching between integrated and split packages.
100
+ # A cached empty helper from an integrated package must not suppress
101
+ # discovery of the separate helper after selecting another library.
102
+ helper_library = library("helper")
103
+ shutil.copyfile(helper_library, fixture / helper_library.name.replace("helper", "memenv"))
104
+ build = root / "reconfigured"
105
+ command = [args.cmake, "-S", str(consumer), "-B", str(build),
106
+ "-DCMAKE_BUILD_TYPE=Release", "-G", args.generator,
107
+ f"-DCMAKE_CXX_COMPILER={args.compiler}", f"-DMODULES={args.modules}",
108
+ f"-DCMAKE_LIBRARY_PATH={fixture}",
109
+ f"-DCMAKE_FIND_ROOT_PATH={fixture}", "-DCMAKE_FIND_ROOT_PATH_MODE_LIBRARY=ONLY",
110
+ f"-DLevelDB_INCLUDE_DIR={headers}", f"-DLevelDB_MemEnv_INCLUDE_DIR={headers}",
111
+ "-DLevelDB_LIBRARY_DEBUG=LevelDB_LIBRARY_DEBUG-NOTFOUND",
112
+ "-DLevelDB_MemEnv_LIBRARY_DEBUG=LevelDB_MemEnv_LIBRARY_DEBUG-NOTFOUND"]
113
+ for index, name in enumerate(("integrated", "base", "integrated", "base")):
114
+ # Reproduce the cache entry written by the old finder as well.
115
+ legacy_cache = ["-DLevelDB_MemEnv_LIBRARY_RELEASE="] if index == 0 else []
116
+ run(command + [f"-DLevelDB_LIBRARY_RELEASE={library(name)}"] + legacy_cache)
117
+ run([args.cmake, "--build", str(build), "--config", "Release", "-j2"])
118
+ print("PASS: cache reconfiguration integrated/split discovery and consumer linkage")
119
+
120
+
121
+ if __name__ == "__main__":
122
+ main()