diff --git a/SConstruct b/SConstruct
index a8d197d..8e168ca 100644
--- a/SConstruct
+++ b/SConstruct
@@ -1,463 +1,464 @@
# -*- mode:python; coding: utf-8 -*-
# vim: set ft=python:
# @file
# @section LICENSE
#
# Copyright (©) 2016-2021 EPFL (École Polytechnique Fédérale de Lausanne),
# Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
#
# 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 .
# ------------------------------------------------------------------------------
# Imports
# ------------------------------------------------------------------------------
from __future__ import print_function
import os
from subprocess import check_output
-from os.path import join, abspath, basename
# Import below not strictly necessary, but good for pep8
from SCons.Script import (
EnsurePythonVersion,
EnsureSConsVersion,
Help,
Environment,
Variables,
EnumVariable,
PathVariable,
BoolVariable,
Split,
- SConscript,
Export,
+ Dir,
)
from SCons.Errors import StopError
from SCons import __version__ as scons_version
from version import get_git_subst
from detect import (
FindFFTW,
FindBoost,
FindThrust,
FindCuda,
FindExpolit,
FindPybind11
)
from INFOS import TAMAAS_INFOS
# ------------------------------------------------------------------------------
EnsurePythonVersion(2, 7)
EnsureSConsVersion(2, 4)
# ------------------------------------------------------------------------------
def detect_dependencies(env):
"Detect all dependencies"
fftw_comp = {
'omp': ['omp'],
'threads': ['threads'],
'none': [],
}
fftw_components = fftw_comp[env['fftw_threads']]
if main_env['use_mpi']:
fftw_components.append('mpi')
FindFFTW(env, fftw_components, precision=env['real_type'])
FindBoost(env, ['boost/preprocessor/seq.hpp'])
FindExpolit(env)
thrust_var = 'THRUST_ROOT'
# Take cuda version of thrust if available
if 'CUDA_ROOT' in env['ENV']:
thrust_var = 'CUDA_ROOT'
FindThrust(env, env['backend'], thrust_var)
# Activate cuda if needed
if env['backend'] == 'cuda':
FindCuda(env)
if env['build_python']:
FindPybind11(env)
-def subdir(dir):
+def subdir(env, dir):
"Building a sub-directory"
- return SConscript(join(dir, 'SConscript'),
- variant_dir=join(build_dir, dir),
- duplicate=True)
+ return env.SConscript(env.File('SConscript', dir),
+ variant_dir=env.Dir(dir, env['build_dir']),
+ duplicate=True)
# ------------------------------------------------------------------------------
# Main compilation
# ------------------------------------------------------------------------------
# Compilation colors
colors = {
'cyan': '\033[96m',
'purple': '\033[95m',
'blue': '\033[94m',
'green': '\033[92m',
'yellow': '\033[93m',
'gray': '\033[38;5;8m',
'orange': '\033[38;5;208m',
'red': '\033[91m',
'end': '\033[0m'
}
# Inherit all environment variables (for CXX detection, etc.)
main_env = Environment(
ENV=os.environ,
)
# Set tamaas information
for k, v in TAMAAS_INFOS.items():
main_env[k] = v
main_env['COLOR_DICT'] = colors
+main_env.AddMethod(subdir, 'SubDirectory')
# Build variables
vars = Variables('build-setup.conf')
vars.AddVariables(
EnumVariable('build_type', 'Build type', 'release',
allowed_values=('release', 'profiling', 'debug'),
ignorecase=2),
EnumVariable('backend', 'Thrust backend', 'omp',
allowed_values=('cpp', 'omp', 'tbb'),
ignorecase=2),
EnumVariable('fftw_threads', 'Threads FFTW library preference', 'omp',
allowed_values=('omp', 'threads', 'none'),
ignorecase=2),
EnumVariable('sanitizer', 'Sanitizer type', 'none',
allowed_values=('none', 'memory', 'leaks', 'address'),
ignorecase=2),
PathVariable('prefix',
'Prefix where to install', '/usr/local'),
# Dependencies paths
PathVariable('FFTW_ROOT',
'FFTW custom path', os.getenv('FFTW_ROOT', ''),
PathVariable.PathAccept),
PathVariable('THRUST_ROOT',
'Thrust custom path', os.getenv('THRUST_ROOT', ''),
PathVariable.PathAccept),
PathVariable('BOOST_ROOT',
'Boost custom path', os.getenv('BOOST_ROOT', ''),
PathVariable.PathAccept),
PathVariable('CUDA_ROOT',
'Cuda custom path', os.getenv('CUDA_ROOT', ''),
PathVariable.PathAccept),
# Dependencies provided as submodule get different default
PathVariable('GTEST_ROOT',
'Googletest custom path',
os.getenv('GTEST_ROOT', '#third-party/googletest/googletest'),
PathVariable.PathAccept),
PathVariable('PYBIND11_ROOT',
'Pybind11 custom path',
os.getenv('PYBIND11_ROOT', '#third-party/pybind11/include'),
PathVariable.PathAccept),
PathVariable('EXPOLIT_ROOT',
'Expolit custom path',
os.getenv('EXPOLIT_ROOT', '#third-party/expolit/include'),
PathVariable.PathAccept),
# Executables
('CXX', 'Compiler', os.getenv('CXX', 'g++')),
('MPICXX', 'MPI Compiler wrapper', os.getenv('MPICXX', 'mpicxx')),
('py_exec', 'Python executable', 'python3'),
# Compiler flags
('CXXFLAGS', 'C++ compiler flags', os.getenv('CXXFLAGS', "")),
# Cosmetic
BoolVariable('verbose', 'Activate verbosity', False),
BoolVariable('color', 'Color the non-verbose compilation output', False),
# Tamaas components
BoolVariable('build_doc', 'Build documentation', False),
BoolVariable('build_tests', 'Build test suite', False),
BoolVariable('build_python', 'Build python wrapper', True),
# Dependencies
BoolVariable('use_googletest', 'Build tests using GTest', False),
BoolVariable('use_mpi', 'Builds multi-process parallelism', False),
# Distribution options
BoolVariable('strip_info', 'Strip binary of added information', False),
BoolVariable('build_static_lib', "Build a static libTamaas", False),
# Type variables
EnumVariable('real_type', 'Type for real precision variables', 'double',
allowed_values=('double', 'long double')),
EnumVariable('integer_type', 'Type for integer variables', 'int',
allowed_values=('int', 'long')),
)
# Set variables of environment
vars.Update(main_env)
help_text = vars.GenerateHelpText(main_env)
help_text += """
Commands:
scons [build] [options]... Compile Tamaas (and additional modules/tests)
scons install [prefix=/your/prefix] [options]... Install Tamaas to prefix
scons dev Install symlink to Tamaas python module (useful to development purposes)
scons test Run tests with pytest
scons doc Compile documentation with Doxygen and Sphinx+Breathe
scons archive Create a gzipped archive from source
""" # noqa
Help(help_text)
# Save all options, not just those that differ from default
with open('build-setup.conf', 'w') as setup:
for option in vars.options:
setup.write("# " + option.help + "\n")
setup.write("{} = '{}'\n".format(option.key, main_env[option.key]))
main_env['should_configure'] = \
not main_env.GetOption('clean') and not main_env.GetOption('help')
build_type = main_env['build_type']
-build_dir = 'build-' + main_env['build_type']
-main_env['build_dir'] = build_dir
+build_dir = 'build-${build_type}'
+main_env['build_dir'] = main_env.Dir(build_dir)
# Printing some build infos
if main_env['should_configure']:
print('-- SCons {}'.format(scons_version))
print(main_env.subst("-- Build type: ${build_type}\n"
"-- Thrust backend: ${backend}\n"
"-- FFTW threads: ${fftw_threads}\n"
- "-- MPI: ${use_mpi}"))
- print("-- Build directory: " + build_dir)
+ "-- MPI: ${use_mpi}\n"
+ "-- Build directory: ${build_dir}"))
# Setting up the python name with version
if main_env['build_python']:
args = (main_env.subst("${py_exec} -c").split()
+ ["from distutils.sysconfig import get_python_version;"
"print(get_python_version())"])
main_env['py_version'] = bytes(check_output(args)).decode()
print(main_env.subst('-- Python version: $py_version'))
verbose = main_env['verbose']
# Remove colors if not set
if not main_env['color']:
for key in colors:
colors[key] = ''
if not verbose:
main_env['CXXCOMSTR'] = main_env['SHCXXCOMSTR'] = \
u'{0}[Compiling ($SHCXX)] {1}$SOURCE'.format(colors['green'],
colors['end'])
main_env['LINKCOMSTR'] = main_env['SHLINKCOMSTR'] = \
u'{0}[Linking] {1}$TARGET'.format(colors['purple'],
colors['end'])
main_env['ARCOMSTR'] = u'{}[Ar]{} $TARGET'.format(colors['purple'],
colors['end'])
main_env['RANLIBCOMSTR'] = \
u'{}[Randlib]{} $TARGET'.format(colors['purple'],
colors['end'])
main_env['PRINT_CMD_LINE_FUNC'] = pretty_cmd_print
# Include paths
main_env.AppendUnique(CPPPATH=['#/src',
'#/src/core',
'#/src/mpi',
'#/src/bem',
'#/src/surface',
'#/src/python',
'#/src/percolation',
'#/src/model',
'#/src/model/elasto_plastic',
'#/src/solvers',
'#/src/gpu',
'#/python'])
# Changing the shared object extension
main_env['SHOBJSUFFIX'] = '.o'
# Back to gcc if cuda is activated
if main_env['backend'] == "cuda" and "g++" not in main_env['CXX']:
raise StopError('GCC should be used when compiling with CUDA')
# OpenMP flags - compiler dependent
omp_flags = {
"g++": ["-fopenmp"],
"clang++": ["-fopenmp"],
"icpc": ["-qopenmp"]
}
def cxx_alias(cxx):
for k in omp_flags.keys():
if k in cxx:
return k
raise StopError('Unsupported compiler: ' + cxx)
cxx = cxx_alias(main_env['CXX'])
# Setting main compilation flags
main_env['CXXFLAGS'] = Split(main_env['CXXFLAGS'])
main_env['LINKFLAGS'] = main_env['CXXFLAGS']
main_env.AppendUnique(
CXXFLAGS=Split('-std=c++14 -Wall -Wextra -pedantic'),
CPPDEFINES=['TAMAAS_BACKEND=TAMAAS_BACKEND_{}'.format(
main_env['backend'].upper()
)],
)
# Adding OpenMP flags
if main_env['backend'] == 'omp':
main_env.AppendUnique(CXXFLAGS=omp_flags[cxx])
main_env.AppendUnique(LINKFLAGS=omp_flags[cxx])
else:
main_env.AppendUnique(CXXFLAGS=['-Wno-unknown-pragmas'])
# Correct bug in clang?
if main_env['backend'] == 'omp' and cxx == "clang++":
main_env.AppendUnique(LIBS=["atomic"])
elif main_env['backend'] == 'tbb':
main_env.AppendUnique(LIBS=['tbb'])
# Manage MPI compiler
if main_env['use_mpi']:
main_env['CXX'] = '$MPICXX'
main_env.AppendUnique(CPPDEFINES=['TAMAAS_USE_MPI'])
main_env.AppendUnique(CXXFLAGS=['-Wno-cast-function-type'])
# Flags and options
if main_env['build_type'] == 'debug':
main_env.AppendUnique(CPPDEFINES=['TAMAAS_DEBUG'])
# Define the scalar types
main_env.AppendUnique(CPPDEFINES={'TAMAAS_REAL_TYPE': '${real_type}',
'TAMAAS_INT_TYPE': '${integer_type}'})
# Compilation flags
cxxflags_dict = {
"debug": Split("-g -O0"),
"profiling": Split("-g -O3 -fno-omit-frame-pointer"),
"release": Split("-O3")
}
if main_env['sanitizer'] != 'none':
if main_env['backend'] == 'cuda':
raise StopError(
"Sanitizers with cuda are not yet supported!")
cxxflags_dict[build_type].append('-fsanitize=${sanitizer}')
main_env.AppendUnique(CXXFLAGS=cxxflags_dict[build_type])
main_env.AppendUnique(SHLINKFLAGS=cxxflags_dict[build_type])
main_env.AppendUnique(LINKFLAGS=cxxflags_dict[build_type])
if main_env['should_configure']:
basic_checks(main_env)
detect_dependencies(main_env)
# Writing information file
main_env.Tool('textfile')
main_env['SUBST_DICT'] = get_git_subst()
# Empty values if requested
if main_env['strip_info']:
for k in main_env['SUBST_DICT']:
main_env['SUBST_DICT'][k] = ""
# Substitution of environment file
main_env['SUBST_DICT'].update({
'@build_type@': '$build_type',
- '@build_dir@': abspath(build_dir),
+ '@build_dir@': '${build_dir.abspath}',
'@build_version@': '$version',
})
# Environment file content
env_content = """export PYTHONPATH=@build_dir@/python:$$PYTHONPATH
export LD_LIBRARY_PATH=@build_dir@/src:$$LD_LIBRARY_PATH
"""
# Writing environment file
-env_file = main_env.Textfile(join(build_dir, 'tamaas_environment.sh'),
- env_content)
+env_file = main_env.Textfile(
+ main_env.File('tamaas_environment.sh', main_env['build_dir']),
+ env_content)
# Default targets
build_targets = ['build-cpp', env_file]
install_targets = ['install-lib']
if main_env._get_major_minor_revision(scons_version)[0] >= 4:
main_env.Tool('compilation_db')
main_env.CompilationDatabase(PRINT_CMD_LINE_FUNC=pretty_cmd_print)
# Building Tamaas library
Export('main_env')
-subdir('src')
+main_env.SubDirectory('src')
# Building Tamaas extra components
for dir in ['python', 'tests']:
if main_env['build_{}'.format(dir)] and not main_env.GetOption('help'):
- subdir(dir)
+ main_env.SubDirectory(dir)
build_targets.append('build-{}'.format(dir))
# Building API + Sphinx documentation if requested
if main_env['build_doc']:
- subdir('doc')
+ main_env.SubDirectory('doc')
main_env.Alias('doc', 'build-doc')
install_targets.append('install-doc')
else:
dummy_command(main_env, 'doc', 'Command "doc" does not do anything'
' without documentation activated ("build_doc=True")')
# Define dummy dev command when python is deactivated
if not main_env['build_python']:
dummy_command(main_env, 'dev', 'Command "dev" does not do anything'
+ ' without python activated ("build_python=True")')
else:
install_targets.append('install-python')
# Define dummy test command when tests are deactivated
if not main_env['build_tests']:
dummy_command(main_env, 'test', 'Command "test" does not do anything'
+ ' without tests activated ("build_tests=True")')
# Definition of target aliases, a.k.a. sub-commands
main_env.Alias('build', build_targets)
# Define proper install targets
main_env.Alias('install', install_targets)
# Default target is to build stuff
main_env.Default('build')
# Building a tar archive
archive = main_env.Command(
'tamaas-{}.tar.gz'.format(main_env['version']),
'',
('tar --exclude-vcs --exclude-vcs-ignores '
'--exclude=third-party/googletest '
'--exclude=third-party/pybind11 '
'--exclude=joss '
'--exclude=".*" '
- '-czf $TARGET {}'.format(basename(os.getcwd()))),
+ '-czf $TARGET {}'.format(Dir('.').name)),
chdir='..',
)
main_env.Alias('archive', archive)
diff --git a/doc/SConscript b/doc/SConscript
index a3ee390..5ad7226 100644
--- a/doc/SConscript
+++ b/doc/SConscript
@@ -1,79 +1,80 @@
# -*- mode:python; coding: utf-8 -*-
# vim: set ft=python:
# @file
# @section LICENSE
#
# Copyright (©) 2016-2021 EPFL (École Polytechnique Fédérale de Lausanne),
# Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
#
# 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 .
from __future__ import print_function
-import os
-
-from os.path import join
from SCons.Script import Import, Glob, Dir, File
+def add_sources(source_list, dirname, fnames):
+ source_list += Dir(dirname).glob('*.hh')
+ source_list += Dir(dirname).glob('*.cpp')
+
+
Import('main_env')
Import('libTamaas')
doc_env = main_env.Clone()
# Generating Doxyfile
doxyfile_target = doc_env.Substfile('doxygen/Doxyfile', 'doxygen/Doxyfile.in',
SUBST_DICT={
'@version@': '$version',
'@build_dir@': Dir('doxygen').path,
'@logo@': File('icon.svg').path,
'@src_dir@': Dir('#src').abspath,
})
# Generate Doxygen API documentation
doc_env.Tool('doxygen')
doxygen_target = doc_env.Doxygen('doxygen/xml/index.xml',
[doxyfile_target, 'icon.svg'])
# Adding all source files as dependencies
sources = []
-for root, _, files in os.walk(Dir('#src').abspath):
- sources += Glob(join(root, '*.hh'))
- sources += Glob(join(root, '*.cpp'))
+Dir('#src').walk(add_sources, sources)
doc_env.Depends(doxygen_target, sources)
# Generate Sphinx User documentation
doc_env.Tool('sphinx')
sphinx_sources = [Glob('sphinx/source/*'), Glob('sphinx/source/figures/*')]
sphinx_targets = []
sphinx_targets.append(doc_env.Sphinx('sphinx/html/index.html', sphinx_sources))
sphinx_targets.append(doc_env.Sphinx('sphinx/tamaas.1', sphinx_sources))
doc_env.Depends(sphinx_targets, doxygen_target)
# Alias for both docs
doc_targets = [doxygen_target] + sphinx_targets
main_env.Alias('build-doc', doc_targets)
# Install target for documentation
-doc_prefix = join(doc_env['prefix'], 'share', 'doc', 'tamaas')
-man_prefix = join(doc_env['prefix'], 'share', 'man', 'man1')
+share = Dir('share', doc_env['prefix'])
+doc_prefix = share.Dir('doc').Dir('tamaas')
+man_prefix = share.Dir('man').Dir('man1')
doc_install = []
doc_install.append(doc_env.Install(target=doc_prefix,
source=sphinx_targets[0][0].dir))
doc_install.append(doc_env.Install(target=man_prefix,
source=sphinx_targets[1]))
main_env.Alias('install-doc', doc_install)
diff --git a/python/SConscript b/python/SConscript
index f2d4f7b..1ba61c3 100644
--- a/python/SConscript
+++ b/python/SConscript
@@ -1,160 +1,159 @@
# -*- mode:python; coding: utf-8 -*-
# vim: set ft=python:
# @file
# @section LICENSE
#
# Copyright (©) 2016-2021 EPFL (École Polytechnique Fédérale de Lausanne),
# Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
#
# 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 .
from __future__ import print_function
-from os.path import abspath, join
from SCons.Script import Import, Split, Copy, Dir
Import('main_env')
# Pybind11 wrapper
env_pybind = main_env.Clone(SHLIBPREFIX='')
# Remove pedantic warnings
cxx_flags = env_pybind['CXXFLAGS']
try:
del cxx_flags[cxx_flags.index('-pedantic')]
except ValueError:
pass
env_pybind.Tool(pybind11)
pybind_sources = Split("""
tamaas_module.cpp
wrap/core.cpp
wrap/percolation.cpp
wrap/surface.cpp
wrap/model.cpp
wrap/solvers.cpp
wrap/compute.cpp
wrap/mpi.cpp
wrap/test_features.cpp
""")
# Setting paths to find libTamaas
-env_pybind.AppendUnique(LIBPATH=[Dir(join('#${build_dir}', 'src'))])
+env_pybind.AppendUnique(LIBPATH=['../src'])
# Link against a static libTamaas
if env_pybind['build_static_lib']:
env_pybind.PrependUnique(LIBS=['Tamaas']) # keep other libs for link
env_pybind['RPATH'] = "" # no need for rpath w/ static lib
# Link against a dynamic libTamaas
else:
env_pybind.AppendUnique(RPATH=[
"'$$$$ORIGIN/../../src'", # path to lib in build_dir
"'$$$$ORIGIN/../../..'", # path to lib in install prefix
])
env_pybind['LIBS'] = ['Tamaas'] # discard other libs for link
# Building the pybind library
tamaas_wrap = env_pybind.Pybind11Module(
target='tamaas/_tamaas',
source=pybind_sources,
)
# For some reason link happens too early
Import('libTamaas')
env_pybind.Depends(tamaas_wrap, libTamaas)
# Copying the __init__.py file with extra python classes
copy_env = env_pybind.Clone()
# Copying additional python files
python_files = """
compute.py
dumpers/__init__.py
dumpers/_helper.py
nonlinear_solvers/__init__.py
""".split()
targets = [tamaas_wrap]
targets += [
- copy_env.Command(join('tamaas', f),
- join(abspath(str(Dir('#python/tamaas'))), f),
+ copy_env.Command(copy_env.File(f, 'tamaas'),
+ copy_env.File(f, '#python/tamaas'),
Copy("$TARGET", "$SOURCE"))
for f in python_files
]
targets.append(copy_env.Command('MANIFEST.in', '#python/MANIFEST.in',
Copy("$TARGET", "$SOURCE")))
subst_env = env_pybind.Clone(
SUBST_DICT={
'@version@': '$version',
'@authors@': str(copy_env['authors']),
'@email@': '$email',
# TODO change when issue with unicode fixed
# '@copyright@': '$copyright',
# '@maintainer@': '$maintainer',
}
)
subst_env.Tool('textfile')
targets.append(subst_env.Substfile('setup.py.in'))
targets.append(subst_env.Substfile('tamaas/__init__.py.in'))
# Defining alias for python builds
main_env.Alias('build-python', targets)
# Checking if we can use pip to install (more convenient for end-user)
install_env = main_env.Clone()
conf = Configure(install_env,
custom_tests={'CheckPythonModule': CheckPythonModule})
has_pip = conf.CheckPythonModule('pip')
install_env = conf.Finish()
# Current build directory
install_env['PYDIR'] = Dir('.')
# Setting command line for installation
if has_pip:
install_env['PYINSTALLCOM'] = '${py_exec} -m pip install -U $PYOPTIONS .'
install_env['PYDEVELOPCOM'] = \
'${py_exec} -m pip install $PYOPTIONS -e .[all]'
else:
install_env['PYINSTALLCOM'] = '${py_exec} setup.py install $PYOPTIONS'
install_env['PYDEVELOPCOM'] = '${py_exec} setup.py develop $PYOPTIONS'
install_env['py_version'] = get_python_version(install_env)
install_env.PrependENVPath(
'PYTHONPATH',
install_env.subst('${prefix}/lib/python${py_version}/site-packages'))
# Specify install target
python_install = install_env.Command(
- join('$prefix', 'dummy_target'),
+ '.python_install_phony',
targets, install_env['PYINSTALLCOM'], PYOPTIONS='--prefix ${prefix}',
chdir=install_env['PYDIR'])
python_install_dev = install_env.Command(
- join('$prefix', 'dummy_target_local'),
+ '.python_install_local_phony',
targets, install_env['PYDEVELOPCOM'], PYOPTIONS='--user',
chdir=install_env['PYDIR'])
# Defining aliases
main_env.Alias('install-python', python_install)
main_env.Alias('dev', python_install_dev)
diff --git a/site_scons/detect.py b/site_scons/detect.py
index 86fb5b8..c41a831 100644
--- a/site_scons/detect.py
+++ b/site_scons/detect.py
@@ -1,264 +1,262 @@
# -*- coding: utf-8 -*-
# @file
# @section LICENSE
#
# Copyright (©) 2016-2021 EPFL (École Polytechnique Fédérale de Lausanne),
# Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
#
# 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 .
from __future__ import print_function
-import SCons
-
-from os.path import join, abspath, exists, isdir
-from SCons.Script import Configure
+from SCons.Script import Configure, Dir
+from SCons.Errors import StopError
# ------------------------------------------------------------------------------
def _get_path(env, ext, module_var):
path = ""
if module_var in env and env[module_var] != "":
- root = abspath(env[module_var])
- if not exists(root) or not isdir(root):
+ 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 = join(root, ext)
- if not exists(path) or not isdir(path):
+ path = Dir(ext, root)
+ 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 SCons.Errors.StopError(
+ 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]
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 SCons.Errors.StopError(
+ 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 SCons.Errors.StopError(
+ 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 SCons.Errors.StopError(
+ 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")
conf_env = env.Clone(**thrust_vars)
conf = Configure(conf_env)
if not conf.CheckCXXHeader('thrust/version.h'):
- raise SCons.Errors.StopError(
+ raise StopError(
'Failed to find Thrust')
conf_env = conf.Finish()
# Update modified variables
env.AppendUnique(**thrust_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=['$PYBIND11_ROOT'])
pybind11_vars['CPPPATH'] = clone['CPPPATH']
conf = Configure(clone)
if not conf.CheckCXXHeader('pybind11/pybind11.h'):
- raise SCons.Errors.StopError(
+ raise StopError(
'Failed to find pybind11 header\n' +
"Run 'git submodule update --init --recursive " +
"third-party/pybind11'")
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)
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['NVCCCOMSTR'] = env['SHCXXCOMSTR']
env['SHLINKCOMSTR'] = \
u'{0}[Linking (cuda)] {1}$TARGET{2}'.format(colors['purple'],
colors['blue'],
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)
if not conf.CheckCXXHeader('gtest/gtest.h'):
- raise SCons.Errors.StopError(
+ raise StopError(
'Failed to find GoogleTest header\n' +
"Run 'git submodule update --init --recursive " +
"third-party/googletest'")
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(**expolit_vars)
conf = Configure(conf_env)
if not conf.CheckCXXHeader('expolit/expolit'):
- raise SCons.Errors.StopError(
+ raise StopError(
'Failed to find Expolit header\n' +
"Run 'git submodule update --init " +
"third-party/expolit'")
conf_env = conf.Finish()
env.AppendUnique(**expolit_vars)
diff --git a/site_scons/site_tools/nvcc.py b/site_scons/site_tools/nvcc.py
index e9316fd..e3b02b7 100644
--- a/site_scons/site_tools/nvcc.py
+++ b/site_scons/site_tools/nvcc.py
@@ -1,223 +1,223 @@
# -*- coding: utf-8 -*-
# @file
# @section LICENSE
#
# Copyright (©) 2016-2021 EPFL (École Polytechnique Fédérale de Lausanne),
# Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
#
# 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 .
"""
SCons tool to setup compilation environment for NVidia's NVCC
Based on version
https://github.com/thrust/thrust/blob/master/site_scons/site_tools/nvcc.py
"""
from __future__ import print_function
+import platform
import SCons
from SCons.Errors import StopError
+from SCons.Script import Dir
-import platform
-from os.path import join
known_components = {
'cufft': 'cufft.h',
'cufftw': 'cufftw.h'
}
def _find_cuda_paths(env):
"""Finding cuda paths"""
if 'CUDA_TOOLKIT_PATH' not in env:
raise StopError("CUDA_TOOLKIT_PATH variable not found in environment")
cuda_path = env['CUDA_TOOLKIT_PATH']
- inc_path = join(cuda_path, 'include')
- lib_path = join(cuda_path, 'lib')
- bin_path = join(cuda_path, 'bin')
+ inc_path = Dir('include', cuda_path)
+ lib_path = Dir('lib', cuda_path)
+ bin_path = Dir('bin', cuda_path)
if platform.machine()[-2:] == '64':
lib_path += '64'
# add nvcc's location to PATH
env.PrependENVPath('PATH', bin_path)
# add the location of the cudart shared library to LD_LIBRARY_PATH as well
# this allows us to execute CUDA programs during the build
env.PrependENVPath('LD_LIBRARY_PATH', lib_path)
# add to include paths
env.AppendUnique(CPPPATH=[inc_path])
# add to library paths
env.AppendUnique(LIBPATH=[lib_path])
def _configure_cuda_components(env):
"""Finding required components in cuda"""
if env.GetOption('clean'):
return
if 'CUDA_COMPONENTS' in env:
for component in env['CUDA_COMPONENTS']:
if component not in known_components:
raise StopError("Unknown cuda component '{}'".format(component))
conf = SCons.Script.Configure(env)
if not conf.CheckLibWithHeader(component,
known_components[component],
'c++'):
raise StopError("Failed to find library {} or header {}".format(
component, known_components[component]))
env = conf.Finish()
def _define_compile_cuda(env):
"""Define the compile string for files that need nvcc"""
env['NVCC'] = env.Detect('nvcc')
# Setting compilation command
env['NVCCCOM'] = \
'$NVCC $CUDA_ARCH_FLAG -o $TARGET -c $NVCC_CXXFLAGS $NVCC_CCFLAGS ' \
+ '$_CCCOMCOM -x cu $SOURCES'
env['SHNVCCCOM'] = \
'$NVCC $CUDA_ARCH_FLAG -o $TARGET -dc -Xcompiler -fPIC ' \
+ '$NVCC_CXXFLAGS $NVCC_CCFLAGS $_CCCOMCOM -x cu $SOURCES'
# Constructing proper cc flags
env['_NVCC_BARE_CCFLAGS'] = \
'${_concat("", CCFLAGS, "", __env__, _NVCC_BARE_FILTER)}'
env['_NVCC_PASSED_CCFLAGS'] = \
'${_concat("-Xcompiler ", CCFLAGS, "", __env__, ' \
+ '_NVCC_COMPILER_PASSED_FILTER)}'
# Constructing proper cxx flags
env['_NVCC_BARE_CXXFLAGS'] = \
'${_concat("", CXXFLAGS, "", __env__, _NVCC_BARE_FILTER)}'
env['_NVCC_PASSED_CXXFLAGS'] = \
'${_concat("-Xcompiler ", CXXFLAGS, "", __env__, ' \
+ '_NVCC_COMPILER_PASSED_FILTER)}'
# Putting all together
env['NVCC_CCFLAGS'] = '$_NVCC_BARE_CCFLAGS $_NVCC_PASSED_CCFLAGS'
env['NVCC_CXXFLAGS'] = '$_NVCC_BARE_CXXFLAGS $_NVCC_PASSED_CXXFLAGS'
def _define_link_cuda(env):
"""Define the link string"""
# Fixing rpaths
env['RPATHPREFIX'] = '-rpath='
env['__RPATH'] = '${_concat("-Xlinker ", _RPATH, "", __env__)}'
env['LINK'] = env['NVCC']
env['SHLINK'] = env['NVCC']
# Replacing old link command strings
env['LINKCOM'] = \
'$LINK $CUDA_ARCH_FLAG -o $TARGET $NVCC_LINKFLAGS $__RPATH ' \
+ '$SOURCES $_LIBDIRFLAGS $_LIBFLAGS'
env['SHLINKCOM'] = \
'$SHLINK -shared $CUDA_ARCH_FLAG -o $TARGET $NVCC_SHLINKFLAGS ' \
+ '$__SHLIBVERSIONFLAGS $__RPATH $SOURCES $_LIBDIRFLAGS $_LIBFLAGS'
# Constructing proper static linker flags
env['_NVCC_BARE_LINKFLAGS'] = \
'${_concat("", LINKFLAGS, "", __env__, _NVCC_BARE_FILTER)}'
env['_NVCC_COMPILER_LINKFLAGS'] = \
'${_concat("-Xcompiler ", LINKFLAGS, "", __env__, ' \
+ '_NVCC_COMPILER_FILTER)}'
env['_NVCC_PASSED_LINKFLAGS'] = \
'${_concat("-Xlinker ", LINKFLAGS, "", __env__, ' \
+ '_NVCC_LINK_PASSED_FILTER)}'
# Constructing proper shared linker flags
env['_NVCC_BARE_SHLINKFLAGS'] = \
'${_concat("", SHLINKFLAGS, "", __env__, _NVCC_BARE_FILTER)}'
env['_NVCC_COMPILER_SHLINKFLAGS'] = \
'${_concat("-Xcompiler ", LINKFLAGS, "", __env__, ' \
+ '_NVCC_COMPILER_FILTER)}'
env['_NVCC_PASSED_SHLINKFLAGS'] = \
'${_concat("-Xlinker ", SHLINKFLAGS, "", __env__, ' \
+ '_NVCC_LINK_PASSED_FILTER)}'
# Putting all together
env['NVCC_LINKFLAGS'] = \
'$_NVCC_BARE_LINKFLAGS $_NVCC_COMPILER_LINKFLAGS ' \
+ '$_NVCC_PASSED_LINKFLAGS'
env['NVCC_SHLINKFLAGS'] = env['NVCC_LINKFLAGS']
env['NVCC_SHLINKFLAGS'] += \
' $_NVCC_BARE_SHLINKFLAGS $_NVCC_COMPILER_SHLINKFLAGS ' \
+ '$_NVCC_PASSED_SHLINKFLAGS'
def _define_commands(env):
"""Defining the command strings"""
# Flags allowed by nvcc
bare_flags = """-std=c++11 -O0 -O1 -O2 -O3 -g -pg -G -w""".split()
# Experimental flags
bare_flags += """-expt-extended-lambda -expt-relaxed-constexpr""".split()
# Flags that must be passed to compiler at link time
compiler_flags = """-fopenmp -qopenmp""".split()
# Pass flags bare to nvcc
env['_NVCC_BARE_FILTER'] = lambda flags: list(filter(
lambda flag: flag in bare_flags, flags))
# Must prepend -Xcompiler, even at link time
env['_NVCC_COMPILER_FILTER'] = lambda flags: list(filter(
lambda flag: flag in compiler_flags, flags))
# Prepend -Xcompiler
env['_NVCC_COMPILER_PASSED_FILTER'] = lambda flags: list(filter(
lambda flag: flag not in set(bare_flags), flags))
# Prepend -Xlinker
env['_NVCC_LINKED_PASSED_FILTER'] = lambda flags: list(filter(
lambda flag: flag not in set(bare_flags) | set(compiler_flags), flags))
_define_compile_cuda(env)
_define_link_cuda(env)
def _add_actions_cuda(env):
"""
Adding actions to .cu files to compile with nvcc.
Other files are not affected.
"""
nvcc_action = SCons.Action.Action('$NVCCCOM', '$NVCCCOMSTR')
shnvcc_action = SCons.Action.Action('$SHNVCCCOM', '$NVCCCOMSTR')
static, shared = SCons.Tool.createObjBuilders(env)
# Compiling with nvcc action added to detected .cu files
static.add_action('.cu', nvcc_action)
shared.add_action('.cu', shnvcc_action)
# Emitter to qualify correctly object code type
static.add_emitter('.cu', SCons.Defaults.StaticObjectEmitter)
shared.add_emitter('.cu', SCons.Defaults.SharedObjectEmitter)
env['CXXCOM'] = '$NVCCCOM'
env['SHCXXCOM'] = '$SHNVCCCOM'
# Scanner for dependency calculations
SCons.Tool.SourceFileScanner.add_scanner('.cu', SCons.Scanner.C.CScanner())
def generate(env):
"""Setup environment for compiling .cu files with nvcc"""
_find_cuda_paths(env)
_add_actions_cuda(env)
_define_commands(env)
_configure_cuda_components(env)
def exists(env):
return env.Detect('nvcc')
diff --git a/site_scons/site_tools/tamaas.py b/site_scons/site_tools/tamaas.py
index 822a716..2ba3ab3 100644
--- a/site_scons/site_tools/tamaas.py
+++ b/site_scons/site_tools/tamaas.py
@@ -1,63 +1,61 @@
# -*- coding: utf-8 -*-
# @file
# @section LICENSE
#
# Copyright (©) 2016-2021 EPFL (École Polytechnique Fédérale de Lausanne),
# Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
#
# 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 .
-import os
from SCons.Errors import StopError
-from SCons.Script import Configure
+from SCons.Script import Configure, Dir
def generate(env):
"""Sets correct environement variables for Tamaas.
- 'TAMAAS_PATH' is the path to the build directory of Tamaas"""
if env.GetOption("clean"):
return
if 'TAMAAS_PATH' not in env:
raise StopError("Please set the 'TAMAAS_PATH' variable in your " +
"scons environment")
- tm_path = env['TAMAAS_PATH']
- include_dir = tm_path + '/src'
+ tm_path = Dir(env['TAMAAS_PATH'])
+ include_dir = Dir('src', tm_path)
subdirs = "core model solvers bem surface percolation".split(" ")
- include_dirs = [os.path.abspath(os.path.join(include_dir, x))
- for x in subdirs]
+ include_dirs = [Dir(x, include_dir).abspath for x in subdirs]
lib_dir = include_dir
env.AppendUnique(CPPPATH=include_dirs)
- env.AppendUnique(LIBPATH=[os.path.abspath(lib_dir)])
- env.AppendUnique(RPATH=[os.path.abspath(lib_dir)])
+ env.AppendUnique(LIBPATH=[lib_dir.abspath])
+ env.AppendUnique(RPATH=[lib_dir.abspath])
env.AppendUnique(CXXFLAGS=["-std=c++14"])
env.AppendUnique(
CPPDEFINES=["THRUST_DEVICE_SYSTEM=THRUST_DEVICE_SYSTEM_OMP"])
env.AppendUnique(LIBS=['fftw3', 'fftw3_omp'])
conf = Configure(env)
if not conf.CheckLibWithHeader("Tamaas", "tamaas.hh", language="CXX"):
raise StopError(
- "Tamaas not found in {}".format(os.path.abspath(tm_path)))
- env['TAMAAS_PATH'] = os.path.abspath(tm_path)
+ "Tamaas not found in {}".format(tm_path.abspath))
+ env['TAMAAS_PATH'] = tm_path.abspath
env = conf.Finish()
def exists(env):
if 'TAMAAS_PATH' in env:
return True
return False
diff --git a/src/SConscript b/src/SConscript
index fc34057..0488e9d 100644
--- a/src/SConscript
+++ b/src/SConscript
@@ -1,158 +1,158 @@
# -*- mode:python; coding: utf-8 -*-
# vim: set ft=python:
# @file
# @section LICENSE
#
# Copyright (©) 2016-2021 EPFL (École Polytechnique Fédérale de Lausanne),
# Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
#
# 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 .
-import os
from SCons.Script import Import, Export
-def prepend(path, list):
- return [os.path.join(path, x) for x in list]
+def prepend(env, path, list):
+ return [env.File(x, path) for x in list]
Import('main_env')
env = main_env.Clone()
+env.AddMethod(prepend, 'PrependDir')
# Core
core_list = """
fft_engine.cpp
fftw_engine.cpp
grid.cpp
grid_hermitian.cpp
statistics.cpp
tamaas.cpp
loop.cpp
computes.cpp
logger.cpp
""".split()
-core_list = prepend('core', core_list)
+core_list = env.PrependDir('core', core_list)
info_file = env.Substfile('tamaas_info.cpp', 'tamaas_info.cpp.in')
core_list.append(info_file)
# Lib roughcontact
generator_list = """
surface_generator.cpp
surface_generator_filter.cpp
surface_generator_random_phase.cpp
isopowerlaw.cpp
regularized_powerlaw.cpp
""".split()
-generator_list = prepend('surface', generator_list)
+generator_list = env.PrependDir('surface', generator_list)
# Lib PERCOLATION
percolation_list = """
flood_fill.cpp
""".split()
-percolation_list = prepend('percolation', percolation_list)
+percolation_list = env.PrependDir('percolation', percolation_list)
# Model
model_list = """
model.cpp
model_factory.cpp
model_type.cpp
model_template.cpp
integral_operator.cpp
be_engine.cpp
westergaard.cpp
elastic_functional.cpp
meta_functional.cpp
adhesion_functional.cpp
volume_potential.cpp
kelvin.cpp
mindlin.cpp
boussinesq.cpp
hooke.cpp
elasto_plastic/isotropic_hardening.cpp
elasto_plastic/residual.cpp
integration/element.cpp
""".split()
-model_list = prepend('model', model_list)
+model_list = env.PrependDir('model', model_list)
# Solvers
solvers_list = """
contact_solver.cpp
polonsky_keer_rey.cpp
kato_saturated.cpp
kato.cpp
beck_teboulle.cpp
condat.cpp
polonsky_keer_tan.cpp
ep_solver.cpp
dfsane_solver.cpp
epic.cpp
""".split()
-solvers_list = prepend('solvers', solvers_list)
+solvers_list = env.PrependDir('solvers', solvers_list)
# GPU API
gpu_list = """
fftransform_cufft.cpp
""".split()
-gpu_list = prepend('gpu', gpu_list)
+gpu_list = env.PrependDir('gpu', gpu_list)
# MPI API
mpi_list = """
fftw_mpi_engine.cpp
mpi_interface.cpp
""".split()
-mpi_list = prepend('mpi', mpi_list)
+mpi_list = env.PrependDir('mpi', mpi_list)
# Assembling total list
rough_contact_list = \
core_list + generator_list + percolation_list + model_list + solvers_list
# Adding GPU if needed
if env['backend'] == 'cuda':
rough_contact_list += gpu_list
# Adding MPI if needed
if env['use_mpi']:
rough_contact_list += mpi_list
# Adding extra warnings for Tamaas base lib
env.AppendUnique(CXXFLAGS=['-Wextra'])
# Allowing libTamaas.so to find libs in the same directory
env.AppendUnique(RPATH=["'$$$$ORIGIN'"])
# Build static library for packaging
if env['build_static_lib']:
env.AppendUnique(CXXFLAGS='-fPIC')
libTamaas = env.StaticLibrary('Tamaas', rough_contact_list)
# Build shared library (default)
else:
libTamaas = env.SharedLibrary('Tamaas', rough_contact_list,
SHLIBVERSION=env['version'])
# Specify install target to install lib
-lib_prefix = os.path.join(env['prefix'], 'lib')
+lib_prefix = env.Dir('lib', env['prefix'])
lib_install = env.InstallVersionedLib(target=lib_prefix,
source=libTamaas)
# Defining alias targets
main_env.Alias('build-cpp', libTamaas)
main_env.Alias('install-lib', lib_install)
# Export target for use in python builds
Export('libTamaas')
diff --git a/tests/SConscript b/tests/SConscript
index 5fe3156..d567952 100644
--- a/tests/SConscript
+++ b/tests/SConscript
@@ -1,215 +1,214 @@
# -*- mode:python; coding: utf-8 -*-
# vim: set ft=python:
# @file
# @section LICENSE
#
# Copyright (©) 2016-2021 EPFL (École Polytechnique Fédérale de Lausanne),
# Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
#
# 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 .
from __future__ import print_function
-from os.path import join, abspath
-
from SCons.Script import Split, Copy, Dir, Import
from detect import FindGTest, FindPybind11
# ------------------------------------------------------------------------------
def copyComStr(env, main):
if 'SHCXXCOMSTR' in main:
env['CXXCOMSTR'] = main['SHCXXCOMSTR']
if 'SHLINKCOMSTR' in main:
env['LINKCOMSTR'] = main['SHLINKCOMSTR']
# ------------------------------------------------------------------------------
def make_python_tests(env):
"""Copy python tests to build directory"""
test_env = env.Clone()
test_files = Split("""
test_autocorrelation.py
test_hertz.py
test_westergaard.py
test_patch_westergaard.py
test_patch_plasticity.py
test_surface.py
test_hertz_disp.py
test_hertz_kato.py
test_saturated_pressure.py
test_flood_fill.py
test_integral_operators.py
test_dumper.py
test_tangential.py
test_boussinesq_surface.py
test_voigt.py
test_memory.py
test_epic.py
fftfreq.py
conftest.py
pytest.ini
""")
if env['use_mpi']:
test_files += ['test_mpi_routines.py', 'mpi_routines.py']
src_dir = "#/tests"
targets = [
- test_env.Command(file, join(src_dir, file),
+ test_env.Command(file, test_env.File(file, src_dir),
Copy("$TARGET", "$SOURCE"))
for file in test_files
]
test_env = env.Clone(tools=[pybind11])
# Helper module for integral operators
test_env['SHLIBPREFIX'] = ''
test_env.PrependUnique(LIBS=['Tamaas'])
register = test_env.Pybind11Module(
target="register_integral_operators",
source=["register_integral_operators.cpp"])
Import('libTamaas')
test_env.Depends(register, libTamaas)
targets.append(register)
return targets
# ------------------------------------------------------------------------------
def compile_google_test(env, gtest_path):
- gtest_obj = env.Object('gtest.o', [join(gtest_path, "src/gtest-all.cc")])
+ gtest_obj = env.Object('gtest.o',
+ [env.File("src/gtest-all.cc", gtest_path)])
return env.StaticLibrary('gtest', gtest_obj)
# ------------------------------------------------------------------------------
def make_google_tests(env):
gtest_dir = Dir(env['GTEST_ROOT'])
gtest_env = env.Clone(CPPPATH=[gtest_dir],
CXXFLAGS=['-pthread', '-isystem',
- join(str(gtest_dir), "include")])
+ env.Dir('include', gtest_dir).path])
FindGTest(gtest_env)
libgtest = None
# Hugly hack to detect if we need to compile gtest submodule
if env['GTEST_ROOT'] == '#third-party/googletest/googletest':
gtest_path = str(gtest_dir)
libgtest = compile_google_test(gtest_env, gtest_path)
env.AppendUnique(CXXFLAGS=gtest_env['CXXFLAGS'])
env.PrependUnique(LIBS=['Tamaas', env.subst('python${py_version}')])
google_test_files = Split("""
test_fft.cpp
test_grid.cpp
test_loop.cpp
test_model.cpp
test_static_types.cpp
test_integration.cpp
""")
# Necessary for the tests that use pybind11 calls to python
uses = []
if env['build_python']:
google_test_files.append('test_fftfreq.cpp')
uses = ['TAMAAS_USE_PYTHON']
if env['use_mpi']:
google_test_files.append('test_mpi.cpp')
defines = env['CPPDEFINES']
if type(defines) is not list:
defines = [defines]
gtest_main = env.Object("tamaas_gtest_main.o", 'tamaas_gtest_main.cc',
CPPDEFINES=defines + uses)
gtest_all = env.Program('test_gtest_all', google_test_files + [gtest_main],
LIBS=(env['LIBS'] + ['gtest']))
Import('libTamaas')
env.Depends(gtest_all, libTamaas)
env.Depends(gtest_all, libgtest)
return [gtest_all]
# ------------------------------------------------------------------------------
def make_bare_tests(env):
rough = env.Program("test_rough_surface.cpp")
Import('libTamaas')
env.Depends(rough, libTamaas)
return [rough]
# ------------------------------------------------------------------------------
Import('main_env')
# Setup of test environment
test_env = main_env.Clone()
test_env.AppendUnique(
- LIBPATH=['.', Dir(join('#${build_dir}', 'src'))],
+ LIBPATH=['.', '../src'],
RPATH=["'$$$$ORIGIN/../src'"]
)
test_env.PrependUnique(LIBS=['Tamaas'])
# Building tests that do not require any third party
targets = make_bare_tests(test_env)
# Build tests that required python bindings
if test_env['build_python']:
FindPybind11(test_env)
test_env.Tool(pybind11)
test_env.ParseConfig("${py_exec}-config --ldflags")
test_env['CCFLAGS'] = []
targets += make_python_tests(test_env)
# Building google tests
if test_env['use_googletest']:
targets += make_google_tests(test_env)
targets.append(test_env.Command('test_gtest.py', '#tests/test_gtest.py',
Copy('$TARGET', '$SOURCE')))
# Target alias to build tests
main_env.Alias('build-tests', targets)
# Check if pytest is installed
conf = Configure(test_env,
custom_tests={'CheckPythonModule': CheckPythonModule})
has_pytest = conf.CheckPythonModule('pytest')
conf.Finish()
# Define a command to execute tests
if has_pytest:
pytest_env = test_env.Clone()
- pytest_env.PrependENVPath('PYTHONPATH',
- abspath(pytest_env.subst('${build_dir}/python')))
- pytest_env.PrependENVPath('LD_LIBRARY_PATH',
- abspath(pytest_env.subst('${build_dir}/src')))
+ test_env['pythonpath'] = '${build_dir}/python'
+ test_env['ld_library_path'] = '${build_dir}/src'
+ pytest_env.PrependENVPath('PYTHONPATH', '${pythonpath.abspath}')
+ pytest_env.PrependENVPath('LD_LIBRARY_PATH', '${ld_library_path.abspath}')
# Setting a moderate thread number
pytest_env['ENV']['OMP_NUM_THREADS'] = "1"
- test_target = pytest_env.Command('#/.phony_test', targets,
+ test_target = pytest_env.Command('.phony_test', targets,
'${py_exec} -m pytest ${build_dir}/tests')
main_env.Alias('test', test_target)
else:
# We still define a target here so that `scons test` still works
dummy_command(main_env, 'test',
'Cannot run tests: pytest is not installed')