Page MenuHomec4science

nvcc.py
No OneTemporary

File Metadata

Created
Fri, May 3, 05:56
# -*- coding: utf-8 -*-
# @file
# @section LICENSE
#
# Copyright (©) 2016-19 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 <https://www.gnu.org/licenses/>.
"""
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 SCons
from SCons.Errors import StopError
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')
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')

Event Timeline