"""Build a separate configurable CPU backend; original KNP files/libs stay intact.""" from pathlib import Path import shlex import subprocess root = Path('/home/int/run/cats-dogs/acceleration') root.mkdir(exist_ok=True) header_original = Path('/mnt/c/KNP/examples/knp/backends/cpu/cpu-multi-threaded-backend/include/knp/backends/cpu-multi-threaded/backend.h') header = header_original.read_text() old_types = 'knp::neuron_traits::LIFNeuron>;' assert header.count(old_types) == 1 header = header.replace(old_types, '''knp::neuron_traits::LIFNeuron, knp::neuron_traits::AltAILIF, knp::neuron_traits::SynapticResourceSTDPAltAILIFNeuron>;''') header_path = root / 'include/knp/backends/cpu-multi-threaded/backend.h' header_path.parent.mkdir(parents=True, exist_ok=True) header_path.write_text(header) original = Path('/mnt/c/KNP/examples/knp/backends/cpu/cpu-multi-threaded-backend/impl/backend.cpp') source = original.read_text() helper = ''' // Experiment-local factory configuration; the original backend is unchanged. static size_t configured_size(const char* name, size_t fallback, size_t maximum) { const char* value = std::getenv(name); if (!value || !*value) return fallback; if (*value < '0' || *value > '9') throw std::invalid_argument(name); char* end = nullptr; errno = 0; const auto parsed = std::strtoull(value, &end, 10); if (errno || *end || !parsed || parsed > maximum) throw std::invalid_argument(name); return static_cast(parsed); } ''' source = source.replace('#include ', '#include \n#include \n#include \n#include ') marker = 'std::shared_ptr MultiThreadedCPUBackend::create()' assert marker in source source = source.replace(marker, helper + marker) old = 'return std::make_shared();' assert source.count(old) == 1 source = source.replace(old, '''return std::make_shared( configured_size("KNP_CPU_THREADS", 2, 256), configured_size("KNP_CPU_POPULATION_PART", 64, 1000000), configured_size("KNP_CPU_PROJECTION_PART", 8192, 10000000));''') (root / 'cpu_backend.cpp').write_text(source) build = Path('/home/int/knp-build/knp/backends/cpu/cpu-multi-threaded-backend') folder = build / 'CMakeFiles/knp-cpu-multi-threaded-backend.dir' flags = {} for line in (folder / 'flags.make').read_text().splitlines(): if ' = ' in line: key, value = line.split(' = ', 1) flags[key] = shlex.split(value) obj = root / 'cpu_backend.o' subprocess.run(['/usr/bin/c++', *flags['CXX_DEFINES'], '-I' + str(root / 'include'), *flags['CXX_INCLUDES'], *flags['CXX_FLAGS'], '-c', str(root / 'cpu_backend.cpp'), '-o', str(obj)], check=True) network_obj = root / 'get_network.o' subprocess.run(['/usr/bin/c++', *flags['CXX_DEFINES'], '-I' + str(root / 'include'), *flags['CXX_INCLUDES'], *flags['CXX_FLAGS'], '-c', str(original.with_name('get_network.cpp')), '-o', str(network_obj)], check=True) link = shlex.split((folder / 'link.txt').read_text()) rebuilt = [] for item in link: if item.startswith('-Wl,--dependency-file='): continue if item.endswith('/impl/backend.cpp.o'): item = str(obj) elif item.endswith('/impl/get_network.cpp.o'): item = str(network_obj) elif item.startswith('-Wl,-soname,'): item = '-Wl,-soname,libknp-cpu-tuned-backend.so' rebuilt.append(item) rebuilt[rebuilt.index('-o') + 1] = str(root / 'libknp-cpu-tuned-backend.so') subprocess.run(rebuilt, cwd=build, check=True) print(root / 'libknp-cpu-tuned-backend.so', flush=True)