diff --git a/.gitmodules b/.gitmodules index 00158b6..20f15f0 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,9 @@ [submodule "third-party/pybind11"] path = third-party/pybind11 url = https://github.com/pybind/pybind11.git [submodule "third-party/googletest"] path = third-party/googletest url = https://github.com/google/googletest.git +[submodule "third-party/expolit"] + path = third-party/expolit + url = ssh://git@c4science.ch/source/expolit.git diff --git a/SConstruct b/SConstruct index 4d94fc3..6ca4844 100644 --- a/SConstruct +++ b/SConstruct @@ -1,261 +1,262 @@ # ------------------------------------------------------------------------------ # Imports # ------------------------------------------------------------------------------ from __future__ import print_function import os from os.path import join, abspath from version import write_info_file -from detect import FindFFTW, FindBoost, FindThrust +from detect import FindFFTW, FindBoost, FindThrust, FindCuda, FindExpolit # ------------------------------------------------------------------------------ EnsurePythonVersion(2, 7) EnsureSConsVersion(2, 4) # ------------------------------------------------------------------------------ def detect_dependencies(env): """Detect all dependencies""" FindFFTW(env, ['omp']) 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) # ------------------------------------------------------------------------------ # Main compilation # ------------------------------------------------------------------------------ # Compilation colors colors = { 'cyan': '\033[96m', 'purple': '\033[95m', 'blue': '\033[94m', 'green': '\033[92m', 'yellow': '\033[93m', 'red': '\033[91m', 'end': '\033[0m' } # Inherit all environment variables (for CXX detection, etc.) main_env = Environment(ENV=os.environ) main_env['COLOR_DICT'] = colors # Compiler detection compiler_default = os.getenv('CXX', 'g++') # 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=('omp', 'cuda'), ignorecase=2), EnumVariable('sanitizer', 'Sanitizer type', 'none', allowed_values=('none', 'memory', 'leaks', 'address'), ignorecase=2), PathVariable('prefix', 'Prefix where to install', '/usr/local'), # Executables ('CXX', 'Compiler', compiler_default), ('py_exec', 'Python executable', 'python'), # 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', False), # Dependencies BoolVariable('use_googletest', 'Build tests using GTest', False) ) # Set variables of environment vars.Update(main_env) Help(vars.GenerateHelpText(main_env)) # Save all options, not just those that differ from default with open('build-setup.conf', 'w') as setup: for key in vars.keys(): setup.write("{} = '{}'\n".format(key, main_env[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'] if main_env['should_configure']: print("Building in " + build_dir) 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['SHCXXCOMSTR'] = \ u'{0}[Compiling ($SHCXX)] {1}$SOURCE'.format(colors['green'], colors['end']) main_env['SHLINKCOMSTR'] = \ u'{0}[Linking] {1}$TARGET'.format(colors['purple'], colors['end']) # Include paths main_env.AppendUnique(CPPPATH=['#/src', '#/src/core', '#/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": main_env['CXX'] = "g++" compiler_aliases = { "c++": "g++", "g++-7": "g++", "clang++-6.0": "clang++", } def cxx_alias(alias): return compiler_aliases.get(alias, alias) # OpenMP flags - compiler dependent omp_libs = { "g++": ["gomp"], "clang++": [], "icpc": [] } omp_flags = { "g++": ["-fopenmp"], "clang++": ["-fopenmp=libomp"], "icpc": ["-qopenmp"] } cxx = cxx_alias(main_env['CXX']) omp_lib = omp_libs[cxx] omp_flag = omp_flags[cxx] main_env.AppendUnique(LIBS=omp_lib) main_env.AppendUnique(LINKFLAGS=omp_flag) # Flags and options -main_env.AppendUnique(CXXFLAGS=['-std=c++14', +main_env.AppendUnique(CXXFLAGS=['-std=c++17', '-Wall', omp_flag]) if main_env['build_python']: main_env.AppendUnique(CPPDEFINES=['USE_PYTHON']) # Adding compile flags defined in evironment main_env.AppendUnique(CXXFLAGS=Split(os.getenv('CXXFLAGS', ""))) if build_type == 'debug': main_env.AppendUnique(CPPDEFINES=['TAMAAS_DEBUG']) # Compilation flags cxxflags_dict = { "debug": Split("-g -O0"), "profiling": Split("-g -O3 -fno-omit-frame-pointer"), "release": Split("-O3") } # Link flags for shared libs shlinkflags_dict = { "debug": Split(""), "profiling": Split("-g -O3 -fno-omit-frame-pointer"), "release": [] } if main_env['sanitizer'] != 'none': if main_env['backend'] == 'cuda': print("Sanitizers with cuda are not yet supported!") Exit(1) cxxflags_dict[build_type].append( '-fsanitize={}'.format(main_env['sanitizer'])) shlinkflags_dict[build_type].append( '-fsanitize={}'.format(main_env['sanitizer'])) main_env.AppendUnique(CXXFLAGS=cxxflags_dict[build_type]) main_env.AppendUnique(SHLINKFLAGS=shlinkflags_dict[build_type]) main_env.AppendUnique(LINKFLAGS=shlinkflags_dict[build_type]) main_env['LIBPATH'] = [abspath(join(build_dir, 'src'))] main_env['RPATH'] = "$LIBPATH" if main_env['should_configure']: detect_dependencies(main_env) # Writing information file write_info_file("src/tamaas_info.cpp") def write_env_file(target, source, env): """Builder to write content to file""" env_content = """ export PYTHONPATH=$PYTHONPATH:{0}/python export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:{0}/src """ with open(str(target[0]), 'w') as env_file: env_file.write(env_content.format(abspath(build_dir))) # Saving the env file main_env['gen_print'] = gen_print env_file_env = main_env.Clone( PRINT_CMD_LINE_FUNC=gen_print("Writing", "cyan", main_env) ) # Need to have a command and manage tamaas_environement.sh as target because # the build directory does not always exist env_file_env.Command(join(build_dir, 'tamaas_environement.sh'), None, write_env_file) # Building subdirs def subdir(dir): return SConscript(join(dir, 'SConscript'), variant_dir=join(build_dir, dir), duplicate=True) # Building Tamaas library Export('main_env') subdir('src') # Building Tamaas extra components for dir in ['python', 'tests', 'doc']: if main_env['build_{}'.format(dir)] and not main_env.GetOption('help'): subdir(dir) diff --git a/site_scons/detect.py b/site_scons/detect.py index e5bb7bf..751021e 100644 --- a/site_scons/detect.py +++ b/site_scons/detect.py @@ -1,170 +1,189 @@ import SCons from os.path import join, abspath, exists, isdir, basename from SCons.Script import Configure # ------------------------------------------------------------------------------ def _get_path(env, ext, module_var): path = "" if module_var in env['ENV']: root = abspath(env['ENV'][module_var]) if not exists(root) or not isdir(root): 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): raise RuntimeError("{} does not contain '{}' directory".format( module_var, ext)) return [path] # ------------------------------------------------------------------------------ def FindFFTW(env, components=[], module_var='FFTW_ROOT'): """Find FFTW3 and set relevant environment variables""" if not env.get('should_configure', True): return fftw_vars = {} fftw_vars['CPPPATH'] = _get_path(env, 'include', module_var) fftw_vars['LIBPATH'] = _get_path(env, 'lib', module_var) # Setting up FFTW wishes = ['main'] + components # Components lib_names = {'main': 'fftw3', 'thread': 'fftw3_threads', 'omp': 'fftw3_omp'} inc_names = ['fftw3.h'] # Checking list of wishes try: libs = [lib_names[i] for i in wishes] except KeyError: raise SCons.Errors.StopError( 'Incompatible FFTW wishlist {0}'.format(wishes)) fftw_vars['LIBS'] = libs conf_env = env.Clone(**fftw_vars) conf = Configure(conf_env) if not conf.CheckLibWithHeader(libs, inc_names, 'c++'): raise SCons.Errors.StopError( 'Failed to find libraries {0} or ' 'headers {1}.'.format(str(lib_names), str(inc_names))) conf_env = conf.Finish() # 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( '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 thrust_vars = {} thrust_vars['CPPPATH'] = _get_path(env, 'include', module_var) if basename(env['CXX']) == "clang++": thrust_vars['CXXFLAGS'] = ["-Wno-unused-local-typedef"] if backend == 'omp': thrust_vars['CPPDEFINES'] = [ "THRUST_DEVICE_SYSTEM=THRUST_DEVICE_SYSTEM_OMP" ] elif backend == 'cuda': thrust_vars['CPPDEFINES'] = [ "THRUST_DEVICE_SYSTEM=THRUST_DEVICE_SYSTEM_CUDA", "USE_CUDA" ] else: raise SCons.Errors.StopError( 'Unknown thrust backend "{}"'.format(backend)) conf_env = env.Clone(**thrust_vars) conf = Configure(conf_env) if not conf.CheckCXXHeader('thrust/version.h'): raise SCons.Errors.StopError( 'Failed to find Thrust') conf_env = conf.Finish() # Update modified variables env.AppendUnique(**thrust_vars) # ------------------------------------------------------------------------------ def FindCuda(env): """Detect cuda on clusters""" if not env.get('should_configure', True): return if 'CUDA_ROOT' in env['ENV']: env['CUDA_TOOLKIT_PATH'] = env['ENV']['CUDA_ROOT'] 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( '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( + '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/third-party/expolit b/third-party/expolit new file mode 160000 index 0000000..2d2697e --- /dev/null +++ b/third-party/expolit @@ -0,0 +1 @@ +Subproject commit 2d2697e75c4678458d5937abb3cea5e593d9a60e