# Copyright 2013-2022 Lawrence Livermore National Security, LLC and other # Spack Project Developers. See the top-level COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) import os from spack import * class PynnBrainscales(WafPackage): """PyNN toplevel for the BrainScaleS-2 neuromorphic hardware systems""" homepage = "https://github.com/electronicvisions/pynn-brainscales" git = "https://github.com/electronicvisions/pynn-brainscales.git" version('4.0-rc2', branch='waf') # PPU compiler dependencies depends_on('oppulance@4.0-rc2') # host software dependencies depends_on('bitsery', type=('build', 'link', 'run')) depends_on('binutils+gold+ld+plugins', type=('build', 'link', 'run')) # specialize depends_on('boost@1.69.0: +graph+icu+mpi+numpy+coroutine+context+filesystem+python+serialization+system+thread+program_options cxxstd=17', type=('build', 'link', 'run')) # specialize boost (non-clingo, type=('build', 'link', 'run')) depends_on('cereal', type=('build', 'link', 'run')) depends_on('cppcheck', type=('build', 'link', 'run')) depends_on('doxygen+graphviz', type=('build', 'link', 'run')) depends_on('genpybind@ebrains', type=('build', 'link', 'run')) depends_on('gflags', type=('build', 'link', 'run')) depends_on('googletest@1.11.0:+gmock', type=('build', 'link', 'run')) # variadic templates needed depends_on('intel-tbb', type=('build', 'link', 'run')) # ppu gdbserver depends_on('libelf', type=('build', 'link', 'run')) depends_on('liblockfile', type=('build', 'link', 'run')) depends_on('llvm', type=('build', 'link', 'run')) depends_on('log4cxx@0.12.1:', type=('build', 'link', 'run')) depends_on('pkgconfig', type=('build', 'link', 'run')) depends_on('psmisc', type=('run', 'test')) depends_on('python@3.7.0:', type=('build', 'link', 'run')) # BrainScaleS(-2, type=('build', 'link', 'run')) only supports Python >= 3.7 depends_on('py-deap@1.3.1:', type=('build', 'link', 'run')) depends_on('py-h5py', type=('build', 'link', 'run')) # PyNN tests need it depends_on('py-matplotlib', type=('build', 'link', 'run')) depends_on('py-nose', type=('build', 'link', 'run')) depends_on('py-numpy', type=('build', 'link', 'run')) depends_on('py-pybind11', type=('build', 'link', 'run')) depends_on('py-pybind11-stubgen', type=('build', 'link', 'run')) depends_on('py-pycodestyle', type=('build', 'link', 'run')) depends_on('py-pyelftools', type=('build', 'link', 'run')) depends_on('py-pylint', type=('build', 'link', 'run')) depends_on('py-pynn@0.9.4:', type=('build', 'link', 'run')) depends_on('py-pyyaml', type=('build', 'link', 'run')) depends_on('py-scipy', type=('build', 'link', 'run')) depends_on('py-sqlalchemy', type=('build', 'link', 'run')) depends_on('util-linux', type=('build', 'link', 'run')) depends_on('yaml-cpp+shared', type=('build', 'link', 'run')) extends('python') def setup_build_environment(self, env): """waf needs to find headers and libraries by itself (mostly `boost` tool, but also `gtest`); it also needs to run executables during configuration.""" include = [] include_exclude_dirs = set(['/usr/include']) for dep in self.spec.traverse(deptype='build', root=False): query = self.spec[dep.name] try: include_dirs = set(query.headers.directories) include_dirs -= include_exclude_dirs print('headers (', dep.name, '):', include_dirs, "\n") include.extend(list(include_dirs)) except spack.error.NoHeadersError: # we don't care if no header directories are found pass library = [] library_exclude_dirs = set(['/lib', '/lib64', '/usr/lib', '/usr/lib64']) for dep in self.spec.traverse(deptype=('link', 'run'), root=False): query = self.spec[dep.name] try: library_dirs = set(query.libs.directories) library_dirs -= library_exclude_dirs print('libs (', dep.name, '):', library_dirs, "\n") library.extend(list(library_dirs)) except spack.error.NoLibrariesError: # we don't care if no library directories are found pass path = [] for dep in self.spec.traverse(deptype=('build', 'link', 'run'), root=False): query = self.spec[dep.name] if os.path.exists(self.prefix.bin): path.append(query.prefix.bin) print('bin (', dep.name, '):', query.prefix.bin, "\n") # llvm might be built with ~shared_libs but still builds shared libs if not any('llvm' in lib for lib in library): print("libs: manually adding ", self.spec['llvm'].prefix.lib) library.append(self.spec['llvm'].prefix.lib) env.set('CPATH', ':'.join(include)) env.set('C_INCLUDE_PATH', ':'.join(include)) env.set('CPLUS_INCLUDE_PATH', ':'.join(include)) env.set('LIBRARY_PATH', ':'.join(library)) env.set('WAF_CONFIGURE_LD_LIBRARY_PATH', ':'.join(library)) env.prepend_path('PATH', ':'.join(path)) def setup_run_environment(self, env): env.prepend_path('PYTHONPATH', self.prefix.lib) # override configure step as we perform a project setup first def configure(self, spec, prefix): """Setup and configure the project.""" self.waf('setup', '--repo-db-url=https://github.com/electronicvisions/projects', '--without-munge', '--project=pynn-brainscales@ebrains-' + str(spec.version), '--project=haldls@ebrains-' + str(spec.version), '--project=grenade@ebrains-' + str(spec.version), '--project=code-format@ebrains-' + str(spec.version), '--project=logger@ebrains-' + str(spec.version), '--project=halco@ebrains-' + str(spec.version), '--project=hate@ebrains-' + str(spec.version), '--project=fisch@ebrains-' + str(spec.version), '--project=ztl@ebrains-' + str(spec.version), '--project=hxcomm@ebrains-' + str(spec.version), '--project=rant@ebrains-' + str(spec.version), '--project=pywrap@ebrains-' + str(spec.version), '--project=lib-boost-patches@ebrains-' + str(spec.version), '--project=sctrltp@ebrains-' + str(spec.version), '--project=hwdb@ebrains-' + str(spec.version), '--project=visions-slurm@ebrains-' + str(spec.version), '--project=flange@ebrains-' + str(spec.version), '--project=lib-rcf@ebrains-' + str(spec.version), '--project=bss-hw-params@ebrains-' + str(spec.version), '--project=nhtl-extoll@ebrains-' + str(spec.version), '--project=librma@ebrains-' + str(spec.version), '--project=libnux@ebrains-' + str(spec.version) ) args = ['--prefix={0}'.format(self.prefix)] args += self.configure_args() env = os.environ env['LD_LIBRARY_PATH'] = env.get('WAF_CONFIGURE_LD_LIBRARY_PATH') self.waf('configure', '--build-profile=release', *args) def build_args(self): args = ['--keep', '--test-execnone', '-v'] return args def build_test(self): self.waf('build', '--test-execall') def install_args(self): args = ['--test-execnone'] return args # def install_test(self): # with working_dir('spack-test', create=True): # old_pythonpath = os.environ.get('PYTHONPATH', '') # os.environ['PYTHONPATH'] = ':'.join([str(self.prefix.lib), old_pythonpath]) # python('-c', 'import pynn_brainscales; print(pynn_brainscales.__file__)')