-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcuda_build.py
199 lines (170 loc) · 7.1 KB
/
cuda_build.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
import os
from distutils.errors import DistutilsExecError, CompileError
from distutils.msvccompiler import MSVCCompiler
from distutils.unixccompiler import UnixCCompiler
from os.path import join
import types
from typing import List, Optional, Union
from setuptools.command.build_ext import build_ext
def find_in_path(names: List[str], path: str) -> Optional[str]:
for dir in path.split(os.pathsep):
print(f"Looking for NVCC in: {dir}")
for name in names:
binpath = join(dir, name)
if os.path.exists(binpath):
return os.path.abspath(binpath)
return None
def locate_CUDA() -> dict:
if 'CUDAHOME' in os.environ:
home = os.environ['CUDAHOME']
nvcc = join(home, 'bin', 'nvcc')
else:
nvcc = find_in_path(['nvcc', 'nvcc.exe'], os.environ['PATH'])
if not nvcc:
raise EnvironmentError(
'The nvcc binary could not be located in your $PATH. Either add it to your path, or set $CUDAHOME'
)
home = os.path.dirname(os.path.dirname(nvcc))
cuda_config = {
'home': home, 'nvcc': nvcc,
'include': join(home, 'include'),
'lib64': join(home, 'lib64'), 'lib': join(home, 'lib')
}
for k, v in cuda_config.items():
if not os.path.exists(v):
print('Warning: The CUDA %s path could not be located in %s' % (k, v))
return cuda_config
def customize_compiler_for_nvcc(
compiler: Union[UnixCCompiler, MSVCCompiler], CUDA: dict, cuda_compile_args: List[str],
cuda_include_dirs_generated: List[str], cuda_macros_generated: List[str]
) -> None:
def setup_unix_compiler():
default_compiler_so = compiler.compiler_so
_super = compiler._compile
def _compile(obj, src, ext, cc_args, extra_postargs, pp_opts):
# Set compiler to NVCC for .cu files
if os.path.splitext(src)[1] == '.cu':
compiler.set_executable('compiler_so', CUDA['nvcc'])
extra_postargs = cuda_compile_args + ["--compiler-options=-fpic"]
_super(obj, src, ext, cc_args, extra_postargs, pp_opts)
# Reset compiler to default
compiler.compiler_so = default_compiler_so
compiler._compile = _compile
def setup_msvc_compiler():
compiler.nvcc = CUDA['nvcc']
compiler.cuda_compile_args = cuda_compile_args
compiler.cuda_include_dirs = cuda_include_dirs_generated
compiler.cuda_macros = cuda_macros_generated
compiler.compile = types.MethodType(_MSVC_CUDA_compile, compiler)
# Determine the compiler type and set it up
compiler.src_extensions.append('.cu')
if compiler.compiler_type == "unix":
print("Setting up Unix compiler for CUDA building.")
setup_unix_compiler()
elif compiler.compiler_type == "msvc":
print("Setting up MSVC compiler for CUDA building.")
setup_msvc_compiler()
else:
raise Exception("Trying to build CUDA code with an unsupported compiler.")
def _MSVC_CUDA_compile(
compiler: MSVCCompiler,
sources: List[str], output_dir: Optional[str] = None,
macros: Optional[List[tuple]] = None, include_dirs: Optional[List[str]] = None,
debug: bool = False,
extra_preargs: Optional[List[str]] = None, extra_postargs: Optional[List[str]] = None,
depends: Optional[List[str]] = None,
):
if not compiler.initialized:
compiler.initialize()
compile_info = compiler._setup_compile(
output_dir, macros, include_dirs, sources, depends, extra_postargs
)
macros, objects, extra_postargs, pp_opts, build = compile_info
compile_opts = extra_preargs or []
compile_opts.append('/c')
if debug:
compile_opts.extend(compiler.compile_options_debug)
else:
compile_opts.extend(compiler.compile_options)
for obj in objects:
try:
src, ext = build[obj]
except KeyError:
continue
if debug:
# pass the full pathname to MSVC in debug mode,
# this allows the debugger to find the source file
# without asking the user to browse for it
src = os.path.abspath(src)
if ext in compiler._c_extensions:
input_opt = "/Tc" + src
elif ext in compiler._cpp_extensions:
input_opt = "/Tp" + src
elif ext in compiler._rc_extensions:
# compile .RC to .RES file
input_opt = src
output_opt = "/fo" + obj
try:
compiler.spawn([compiler.rc] + pp_opts + [output_opt] + [input_opt])
except DistutilsExecError as msg:
raise CompileError(msg)
continue
elif ext in compiler._mc_extensions:
# Compile .MC to .RC file to .RES file.
h_dir = os.path.dirname(src)
rc_dir = os.path.dirname(obj)
try:
# first compile .MC to .RC and .H file
compiler.spawn([compiler.mc] + ['-h', h_dir, '-r', rc_dir] + [src])
base, _ = os.path.splitext(os.path.basename(src))
rc_file = os.path.join(rc_dir, base + '.rc')
# then compile .RC to .RES file
compiler.spawn([compiler.rc] + ["/fo" + obj] + [rc_file])
except DistutilsExecError as msg:
raise CompileError(msg)
continue
elif ext == '.cu':
# Compile CUDA file
input_opt = src
output_opt = f'-o={obj}'
try:
compiler.spawn(
[compiler.nvcc] + ["-c"] + compiler.cuda_compile_args
+ compiler.cuda_include_dirs + compiler.cuda_macros
+ [output_opt] + [input_opt])
except DistutilsExecError as msg:
raise CompileError(msg)
continue
else:
raise CompileError(
"Don't know how to compile {} to {}".format(src, obj)
)
output_opt = "/Fo" + obj
try:
compiler.spawn(
[compiler.cc]
+ compile_opts
+ pp_opts
+ [input_opt, output_opt]
+ extra_postargs
)
except DistutilsExecError as msg:
raise CompileError(msg)
return objects
class CudaBuildExt(build_ext):
CUDA: dict
cuda_compile_args: List[str]
cuda_include_dirs_generated: List[str]
cuda_macros_generated: List[str]
def build_extensions(self):
customize_compiler_for_nvcc(
self.compiler, CudaBuildExt.CUDA, CudaBuildExt.cuda_compile_args,
CudaBuildExt.cuda_include_dirs_generated, CudaBuildExt.cuda_macros_generated
)
build_ext.build_extensions(self)
@staticmethod
def setup(CUDA: dict, cuda_compile_args: List[str], cuda_include_dirs: List[str], cuda_macros: List[tuple]):
CudaBuildExt.CUDA = CUDA
CudaBuildExt.cuda_compile_args = cuda_compile_args
CudaBuildExt.cuda_include_dirs_generated = [f"-I{inc_dir}" for inc_dir in cuda_include_dirs]
CudaBuildExt.cuda_macros_generated = [f"-D{key}={value}" for key, value in cuda_macros]