diff --git a/site_scons/site_init.py b/site_scons/site_init.py index 99b39e1..afe753c 100644 --- a/site_scons/site_init.py +++ b/site_scons/site_init.py @@ -1,191 +1,195 @@ # -*- coding: utf-8 -*- # @file # 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 subprocess from detect import FindPybind11 from SCons.Script import Configure from SCons.Errors import StopError # ------------------------------------------------------------------------------ def pybind11(env): """A tool to configure pybind11""" def execute(command): return [line for line in subprocess.check_output( command, universal_newlines=True).split('\n') if line != ""] # Create a clone so we do not modify env clone = env.Clone() # Set variables for clone FindPybind11(clone) includes = clone['CPPPATH'] # Extension of shared library for python try: extension = execute( env.subst('${py_exec}-config --extension-suffix').split())[0] except subprocess.CalledProcessError: extension = ".so" def pybind11_builder(env, target, source, **kwargs): """Create a pybind11 module""" clone = env.Clone() clone.AppendUnique(CPPPATH=includes) clone['SHLIBSUFFIX'] = extension clone.AppendUnique(SHLINKFLAGS=['-fvisibility=hidden']) return clone.SharedLibrary(target, source, **kwargs) # Add pseudo-builder to master environment env.AddMethod(pybind11_builder, 'Pybind11Module') # ------------------------------------------------------------------------------ def pretty_cmd_print(command, target, source, env): colors = env['COLOR_DICT'] if 'Copy' in command: color = colors['gray'] action = 'Copying' elif 'Creating' in command: color = colors['yellow'] action = 'Generating' elif 'database' in command: color = colors['yellow'] action = 'Generating' elif 'pytest' in command: color = colors['green'] action = 'Running tests' target[0] = target[0].dir elif 'pip' in command: color = colors['blue'] if 'user' in command: action = 'Symlinking' target[0] = target[0].dir elif 'prefix' in command: action = 'Installing' target[0] = env.subst(target[0].dir.path + ' to ${prefix}') + elif 'tar' in command: + color = colors['blue'] + action = 'Archiving' + target[0] = '../' + target[0].path else: print(command) return print("{color}[{action}] {end}{target}".format( color=color, end=colors['end'], target=target[0], action=action )) # ------------------------------------------------------------------------------ def CheckPythonModule(context, module): """Checks the existence of a python module""" context.Message('Checking for Python module {}... '.format(module)) env = context.sconf.env command = [env.subst('${py_exec}'), '-c', 'import {}'.format(module)] context.Log('Executing external command: {}\n'.format(command)) try: subprocess.check_output(command, stderr=subprocess.STDOUT) result = True except subprocess.CalledProcessError as e: result = False output = bytes(e.output) context.Log(output.decode() + '\n') context.Result(result) return result # ------------------------------------------------------------------------------ def CheckCompilerFlag(context, flag): "Check compiler provides flag" context.Message('Checking compiler flag {}... '.format( context.sconf.env.subst(flag))) test_file = """ int main() { return 0; } """ env = context.sconf.env.Clone(CXXFLAGS=[flag], LINKFLAGS=[flag]) context.sconf.env = env result = context.TryLink(test_file, '.cpp') context.Result(result) return result # ------------------------------------------------------------------------------ def dummy_command(env, command, error_msg): """Creates a dummy scons command""" def print_error(*args, **kwargs): print(error_msg) def print_cmd(*args, **kwargs): pass comm = env.Command('#.phony_{}'.format(command), '', print_error, PRINT_CMD_LINE_FUNC=print_cmd) env.Alias(command, comm) # ------------------------------------------------------------------------------ def get_python_version(env): versions_script = """ from __future__ import print_function from sysconfig import get_python_version print(get_python_version())""" version = subprocess.check_output([env['py_exec'], "-c", versions_script], universal_newlines=True).replace('\n', '') print(version) return version # ------------------------------------------------------------------------------ def basic_checks(env): custom_tests = { 'CheckCompilerFlag': CheckCompilerFlag, } conf = Configure(env, custom_tests=custom_tests) if not conf.CheckCXX(): StopError('Could not find working C++ compiler') for flag in env['CXXFLAGS']: if not conf.CheckCompilerFlag(flag): StopError('Compiler does not support flag {}'.format(flag)) def check_type(cpp_type, stl_header): if not conf.CheckType(cpp_type, '#include <{}>'.format(stl_header), 'cpp'): StopError('Standard type {} is not available'.format(cpp_type)) check_type('std::multiplies', 'functional') check_type('std::unique_ptr', 'memory') conf.Finish()