About
The following tool, cuda (cuda.py) is for using the CUDA toolkit/sdk by NVidia. See the end of the page for an example SConscript for building the simpleGL sample that comes with the SDK and some notes.
The tool code
Note: save this as cuda.py
1 """
2 SCons.Tool.cuda
3
4 CUDA Tool for SCons
5
6 """
7
8 import os
9 import sys
10 import SCons.Tool
11 import SCons.Scanner.C
12 import SCons.Defaults
13
14 CUDAScanner = SCons.Scanner.C.CScanner()
15
16 # this object emitters add '.linkinfo' suffixed files as extra targets
17 # these files are generated by nvcc. The reason to do this is to remove
18 # the extra .linkinfo files when calling scons -c
19 def CUDANVCCStaticObjectEmitter(target, source, env):
20 tgt, src = SCons.Defaults.StaticObjectEmitter(target, source, env)
21 for file in src:
22 lifile = os.path.splitext(src[0].rstr())[0] + '.linkinfo'
23 tgt.append(lifile)
24 return tgt, src
25 def CUDANVCCSharedObjectEmitter(target, source, env):
26 tgt, src = SCons.Defaults.SharedObjectEmitter(target, source, env)
27 for file in src:
28 lifile = os.path.splitext(src[0].rstr())[0] + '.linkinfo'
29 tgt.append(lifile)
30 return tgt, src
31
32 def generate(env):
33 staticObjBuilder, sharedObjBuilder = SCons.Tool.createObjBuilders(env);
34 staticObjBuilder.add_action('.cu', '$STATICNVCCCMD')
35 staticObjBuilder.add_emitter('.cu', CUDANVCCStaticObjectEmitter)
36 sharedObjBuilder.add_action('.cu', '$SHAREDNVCCCMD')
37 sharedObjBuilder.add_emitter('.cu', CUDANVCCSharedObjectEmitter)
38 SCons.Tool.SourceFileScanner.add_scanner('.cu', CUDAScanner)
39
40 # default compiler
41 env['NVCC'] = 'nvcc'
42
43 # default flags for the NVCC compiler
44 env['NVCCFLAGS'] = ''
45 env['STATICNVCCFLAGS'] = ''
46 env['SHAREDNVCCFLAGS'] = ''
47 env['ENABLESHAREDNVCCFLAG'] = '-shared'
48
49 # default NVCC commands
50 env['STATICNVCCCMD'] = '$NVCC -o $TARGET -c $NVCCFLAGS $STATICNVCCFLAGS $SOURCES'
51 env['SHAREDNVCCCMD'] = '$NVCC -o $TARGET -c $NVCCFLAGS $SHAREDNVCCFLAGS $ENABLESHAREDNVCCFLAG $SOURCES'
52
53 # helpers
54 home=os.environ.get('HOME', '')
55 programfiles=os.environ.get('PROGRAMFILES', '')
56 homedrive=os.environ.get('HOMEDRIVE', '')
57
58 # find CUDA Toolkit path and set CUDA_TOOLKIT_PATH
59 try:
60 cudaToolkitPath = env['CUDA_TOOLKIT_PATH']
61 except:
62 paths=[home + '/NVIDIA_CUDA_TOOLKIT',
63 home + '/Apps/NVIDIA_CUDA_TOOLKIT',
64 home + '/Apps/NVIDIA_CUDA_TOOLKIT',
65 home + '/Apps/CudaToolkit',
66 home + '/Apps/CudaTK',
67 '/usr/local/NVIDIA_CUDA_TOOLKIT',
68 '/usr/local/CUDA_TOOLKIT',
69 '/usr/local/cuda_toolkit',
70 '/usr/local/CUDA',
71 '/usr/local/cuda',
72 '/Developer/NVIDIA CUDA TOOLKIT',
73 '/Developer/CUDA TOOLKIT',
74 '/Developer/CUDA',
75 programfiles + 'NVIDIA Corporation/NVIDIA CUDA TOOLKIT',
76 programfiles + 'NVIDIA Corporation/NVIDIA CUDA',
77 programfiles + 'NVIDIA Corporation/CUDA TOOLKIT',
78 programfiles + 'NVIDIA Corporation/CUDA',
79 programfiles + 'NVIDIA/NVIDIA CUDA TOOLKIT',
80 programfiles + 'NVIDIA/NVIDIA CUDA',
81 programfiles + 'NVIDIA/CUDA TOOLKIT',
82 programfiles + 'NVIDIA/CUDA',
83 programfiles + 'CUDA TOOLKIT',
84 programfiles + 'CUDA',
85 homedrive + '/CUDA TOOLKIT',
86 homedrive + '/CUDA']
87 pathFound = False
88 for path in paths:
89 if os.path.isdir(path):
90 pathFound = True
91 print 'scons: CUDA Toolkit found in ' + path
92 cudaToolkitPath = path
93 break
94 if not pathFound:
95 sys.exit("Cannot find the CUDA Toolkit path. Please modify your SConscript or add the path in cudaenv.py")
96 env['CUDA_TOOLKIT_PATH'] = cudaToolkitPath
97
98 # find CUDA SDK path and set CUDA_SDK_PATH
99 try:
100 cudaSDKPath = env['CUDA_SDK_PATH']
101 except:
102 paths=[home + '/NVIDIA_CUDA_SDK', # i am just guessing here
103 home + '/Apps/NVIDIA_CUDA_SDK',
104 home + '/Apps/CudaSDK',
105 '/usr/local/NVIDIA_CUDA_SDK',
106 '/usr/local/CUDASDK',
107 '/usr/local/cuda_sdk',
108 '/Developer/NVIDIA CUDA SDK',
109 '/Developer/CUDA SDK',
110 '/Developer/CUDA',
111 '/Developer/GPU Computing/C',
112 programfiles + 'NVIDIA Corporation/NVIDIA CUDA SDK',
113 programfiles + 'NVIDIA/NVIDIA CUDA SDK',
114 programfiles + 'NVIDIA CUDA SDK',
115 programfiles + 'CudaSDK',
116 homedrive + '/NVIDIA CUDA SDK',
117 homedrive + '/CUDA SDK',
118 homedrive + '/CUDA/SDK']
119 pathFound = False
120 for path in paths:
121 if os.path.isdir(path):
122 pathFound = True
123 print 'scons: CUDA SDK found in ' + path
124 cudaSDKPath = path
125 break
126 if not pathFound:
127 sys.exit("Cannot find the CUDA SDK path. Please set env['CUDA_SDK_PATH'] to point to your SDK path")
128 env['CUDA_SDK_PATH'] = cudaSDKPath
129
130 # cuda libraries
131 if env['PLATFORM'] == 'posix':
132 cudaSDKSubLibDir = '/linux'
133 elif env['PLATFORM'] == 'darwin':
134 cudaSDKSubLibDir = '/darwin'
135 else:
136 cudaSDKSubLibDir = ''
137
138 # add nvcc to PATH
139 env.PrependENVPath('PATH', cudaToolkitPath + '/bin')
140
141 # add required libraries
142 env.Append(CPPPATH=[cudaSDKPath + '/common/inc', cudaToolkitPath + '/include'])
143 env.Append(LIBPATH=[cudaSDKPath + '/lib', cudaSDKPath + '/common/lib' + cudaSDKSubLibDir, cudaToolkitPath + '/lib'])
144 env.Append(LIBS=['cudart'])
145
146 def exists(env):
147 return env.Detect('nvcc')
Sample
The SConscript for building simpleGL:
Notes
The above tool has only been tested on Linux and Mac OS X. If your project doesn't use any of the above paths, you can specify
env['CUDA_TOOLKIT_PATH'] = path to the CUDA Toolkit env['CUDA_SDK_PATH'] = path to the CUDA SDK
If the tool finds the paths, it sets the above to the path it found. If you want to include CFLAGS for the nvcc, set the
env['NVCCFLAGS'] = flags common to static and shared objects env['STATICNVCCFLAGS'] = flags for static objects env['SHAREDNVCCFLAGS'] = flags for shared objects
variables. The tool will include automatically the 'cudart' library in LIBS but not cublas nor cufft because you might not need them. Call env.Append as shown in the sample above to add extra libraries after calling env.Tool('cuda').
Emitters
This is an implementation detail, but i'm posting this too here. I'm not sure if this was the best thing to do, but it seems to work. I added two emitters for .cu files which modify the results of the Scons.Defaults.Static/SharedObjectEmitter to also add .linkinfo suffixed files as a target because the nvcc compiler builds a .o/.obj and a .linkinfo from a .cu file and i needed to somehow tell to SCons to delete the .linkinfo files when scons -c is issued. If you think of a better method for this, please inform me.
