Page MenuHomec4science

detect.py
No OneTemporary

File Metadata

Created
Fri, Apr 19, 07:23

detect.py

# -*- coding: utf-8 -*-
#
# Copyright (©) 2016-2024 EPFL (École Polytechnique Fédérale de Lausanne),
# Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
# Copyright (©) 2020-2024 Lucas Frérot
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
from SCons.Script import Configure, Dir
from SCons.Errors import StopError
# ------------------------------------------------------------------------------
def _get_path(env, ext: str, module_var: str):
path = ""
if module_var in env and env[module_var] != "":
root = Dir(env[module_var])
if not root.exists() or not root.isdir():
raise RuntimeError("{} is set to a non-existing path '{}'".format(
module_var, root))
path = root.Dir(ext)
if not path.exists() or not path.isdir():
raise RuntimeError("{} does not contain '{}' directory".format(
module_var, ext))
return [path]
# ------------------------------------------------------------------------------
def FindFFTW(env, components=None, precision='double', module_var='FFTW_ROOT'):
"""Find FFTW3 and set relevant environment variables"""
if not env.get('should_configure', True):
return
if components is None:
components = []
fftw_vars = {}
fftw_vars['CPPPATH'] = _get_path(env, 'include', module_var)
fftw_vars['LIBPATH'] = _get_path(env, 'lib', module_var)
try:
fftw_vars['LIBPATH'] += _get_path(env, 'lib64', module_var)
except RuntimeError:
pass
fftw_vars['RPATH'] = fftw_vars['LIBPATH']
if 'threads' in components:
fftw_vars['LIBS'] = ['pthread']
# Setting up FFTW
wishes = ['main'] + components
fftw_name = "fftw3{}"
# Components
lib_names = {'main': fftw_name,
'threads': fftw_name + '_threads',
'omp': fftw_name + '_omp',
'mpi': fftw_name + '_mpi'}
# Checking list of wishes
try:
libs = [lib_names[i].format("") for i in wishes]
except KeyError:
raise StopError(
'Incompatible FFTW wishlist {0}'.format(wishes))
# Add long precision libraries
if precision == 'long double':
libs += [lib_names[i].format("l") for i in wishes]
elif precision == 'float':
libs += [lib_names[i].format("f") for i in wishes]
conf_env = env.Clone(**fftw_vars)
conf = Configure(conf_env)
for lib in libs:
inc_names = ['fftw3.h']
if 'mpi' in lib:
inc_names.append('fftw3-mpi.h')
if not conf.CheckLibWithHeader(lib, inc_names, 'c++'):
raise StopError(
('Failed to find library {0} or '
'headers {1}. Check the build options "fftw_threads"'
' and "FFTW_ROOT".').format(lib, str(inc_names)))
conf_env = conf.Finish()
fftw_vars['LIBS'] = fftw_vars.get('LIBS', []) + libs
# Update modified variables
env.AppendUnique(**fftw_vars)
# ------------------------------------------------------------------------------
def FindBoost(env, headers=['boost/version.hpp'], module_var='BOOST_ROOT'):
"""Find Boost and set relevant environment variables"""
if not env.get('should_configure', True):
return
boost_vars = {}
boost_vars['CPPPATH'] = _get_path(env, 'include', module_var)
conf_env = env.Clone(**boost_vars)
conf = Configure(conf_env)
if not conf.CheckCXXHeader(headers):
raise StopError(
'Failed to find Boost headers {}'.format(headers))
conf_env = conf.Finish()
# Update modified variables
env.AppendUnique(**boost_vars)
# ------------------------------------------------------------------------------
def FindThrust(env, backend='omp', module_var='THRUST_ROOT'):
"""Find Thrust and set relevant environment variables"""
if not env.get('should_configure', True):
return
if backend not in ('cpp', 'omp', 'cuda', 'tbb'):
raise StopError(
'Unknown thrust backend "{}"'.format(backend))
thrust_vars = {}
try:
thrust_vars['CPPPATH'] = _get_path(env, 'include', module_var)
except RuntimeError:
thrust_vars['CPPPATH'] = _get_path(env, '', module_var)
if "clang++" in env['CXX']:
thrust_vars['CXXFLAGS'] = ["-Wno-unused-local-typedef"]
thrust_vars['CPPDEFINES'] = [
"THRUST_DEVICE_SYSTEM=THRUST_DEVICE_SYSTEM_{}".format(backend.upper())
]
if backend == 'cuda':
thrust_vars['CPPDEFINES'].append("TAMAAS_USE_CUDA")
# Detect thrust
conf_env = env.Clone(**thrust_vars)
conf = Configure(conf_env)
if not conf.CheckCXXHeader('thrust/version.h'):
raise StopError(
'Failed to find Thrust')
conf_env = conf.Finish()
# Update modified variables
env.AppendUnique(**thrust_vars)
def FindLibCUDACXX(env, module_var='LIBCUDACXX_ROOT'):
# Recent versions of thrust need libcudacxx
libcuda_vars = {}
# If root of Thrust is specified but not libcudacxx, look in the thrust repo
if env["THRUST_ROOT"] != "" and env["LIBCUDACXX_ROOT"] == "":
try:
default_path = "dependencies/libcudacxx/include"
path = _get_path(env, default_path, "THRUST_ROOT")
libcuda_vars["CPPPATH"] = path
except RuntimeError as e:
print(e)
print("You may want to clone Thrust with its submodules")
else:
libcuda_vars["CPPPATH"] = \
_get_path(env, "include", module_var)
existing_cpppath = env["CPPPATH"]
conf_env = env.Clone(**libcuda_vars)
conf_env.AppendUnique(CPPPATH=existing_cpppath)
conf = Configure(conf_env)
# Check for a header in libcudacxx, fail is ok for backward compatibility
conf.CheckCXXHeader("cuda/std/type_traits")
# We only have an error if this include does not work
if not conf.CheckCXXHeader("thrust/pair.h"):
raise StopError("Thrust versions >= 2.x need libcudacxx "
"(use LIBCUDACXX_ROOT to specify path)")
conf_env = conf.Finish()
env.AppendUnique(**libcuda_vars)
# ------------------------------------------------------------------------------
def FindPybind11(env, module_var='PYBIND11_ROOT'):
"""Detech Pybind11 and set appropriate build variables"""
if not env.get('should_configure', True) \
or env.get("PYBIND11_FOUND", False):
return
pybind11_vars = {}
clone = env.Clone(CPPPATH=[])
clone.ParseConfig('${py_exec}-config --includes')
clone.AppendUnique(CPPPATH=_get_path(env, 'include', module_var))
pybind11_vars['CPPPATH'] = clone['CPPPATH']
conf = Configure(clone)
if not conf.CheckCXXHeader('pybind11/pybind11.h'):
raise StopError(
"Failed to find pybind11 header.\n"
"Install pybind11 headers or "
"set PYBIND11_ROOT='#third-party/pybind11' "
"to use vendored dependency."
)
conf.Finish()
pybind11_vars['PYBIND11_FOUND'] = True
# Update variables
env.AppendUnique(**pybind11_vars)
# ------------------------------------------------------------------------------
def FindCuda(env, module_var="CUDA_ROOT"):
"""Detect cuda on clusters"""
if not env.get('should_configure', True):
return
if 'CUDA_ROOT' in env:
env['CUDA_TOOLKIT_PATH'] = _get_path(env, '', module_var)[0]
else:
env['CUDA_TOOLKIT_PATH'] = '/opt/cuda'
env['CUDA_COMPONENTS'] = ['cufft']
env['CUDA_ARCH_FLAG'] = '-arch=sm_60'
colors = env['COLOR_DICT']
if not env['verbose']:
env['SHCXX'] = 'nvcc'
env['NVCCCOMSTR'] = env['SHCXXCOMSTR']
env['SHLINKCOMSTR'] = \
u'{0}[Linking (cuda)] {1}$TARGET'.format(colors['purple'],
colors['end'])
env.AppendUnique(CXXFLAGS=[
"-expt-extended-lambda", # experimental lambda support
"-expt-relaxed-constexpr", # experimental constexpr
])
if env['build_type'] == 'debug':
env.AppendUnique(CXXFLAGS="-G")
env.Tool('nvcc')
# ------------------------------------------------------------------------------
def FindGTest(env):
"""A tool to configure GoogleTest"""
if not env.get('should_configure', True):
return
conf = Configure(env)
env['has_gtest'] = conf.CheckCXXHeader('gtest/gtest.h')
env = conf.Finish()
# ------------------------------------------------------------------------------
def FindExpolit(env):
"""A tool to configure Expolit"""
if not env.get('should_configure', True):
return
expolit_vars = {"CPPPATH": "#/third-party/expolit/include"}
conf_env = env.Clone()
conf_env.AppendUnique(**expolit_vars)
conf = Configure(conf_env)
if not conf.CheckCXXHeader('expolit/expolit'):
raise StopError(
'Failed to find Expolit header\n' +
"Run 'git submodule update --init " +
"third-party/expolit'")
conf_env = conf.Finish()
env.AppendUnique(**expolit_vars)
# ------------------------------------------------------------------------------
def FindPETSc(env, module_var='PETSC_ROOT'):
"""A tool to configure PETSc"""
petsc_vars = {}
conf_env = env.Clone()
petsc_vars['CPPPATH'] = _get_path(env, 'include', module_var)
petsc_vars['LIBPATH'] = _get_path(env, 'lib', module_var)
try:
petsc_vars['LIBPATH'] += _get_path(env, 'lib64', module_var)
except RuntimeError:
pass
petsc_vars['LIBS'] = 'petsc'
petsc_vars['RPATH'] = petsc_vars['LIBPATH']
conf_env = env.Clone()
conf_env.AppendUnique(**petsc_vars)
conf = Configure(conf_env)
if not conf.CheckLibWithHeader('petsc', 'petscmat.h', language='c++'):
raise StopError('Failed to find PETSc, or PETSc with MPI')
conf_env = conf.Finish()
env.AppendUnique(**petsc_vars)

Event Timeline