Skip to content

Commit 1e0e7c3

Browse files
authored
Merge pull request #514 from vzhurba01/283-specify-headers
Check for required headers before compilation
2 parents b500268 + 439681e commit 1e0e7c3

File tree

4 files changed

+111
-72
lines changed

4 files changed

+111
-72
lines changed

cuda_bindings/cuda/bindings/_lib/cyruntime/cyruntime.pxd.in

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -108,9 +108,9 @@ from libcpp cimport bool
108108
{{if 'cudaCreateSurfaceObject' in found_functions}}cdef cudaError_t _cudaCreateSurfaceObject(cudaSurfaceObject_t* pSurfObject, const cudaResourceDesc* pResDesc) except ?cudaErrorCallRequiresNewerDriver nogil{{endif}}
109109
{{if 'cudaGetTextureObjectResourceDesc' in found_functions}}cdef cudaError_t _cudaGetTextureObjectResourceDesc(cudaResourceDesc* pResDesc, cudaTextureObject_t texObject) except ?cudaErrorCallRequiresNewerDriver nogil{{endif}}
110110
{{if 'cudaGraphicsEGLRegisterImage' in found_functions}}cdef cudaError_t _cudaGraphicsEGLRegisterImage(cudaGraphicsResource_t* pCudaResource, EGLImageKHR image, unsigned int flags) except ?cudaErrorCallRequiresNewerDriver nogil{{endif}}
111-
{{if 'cudaEGLStreamProducerPresentFrame' in found_functions}}cdef cudaError_t _cudaEGLStreamProducerPresentFrame(cudaEglStreamConnection* conn, cudaEglFrame eglframe, cudaStream_t* pStream) except ?cudaErrorCallRequiresNewerDriver nogil{{endif}}
112-
{{if 'cudaEGLStreamProducerReturnFrame' in found_functions}}cdef cudaError_t _cudaEGLStreamProducerReturnFrame(cudaEglStreamConnection* conn, cudaEglFrame* eglframe, cudaStream_t* pStream) except ?cudaErrorCallRequiresNewerDriver nogil{{endif}}
113-
{{if 'cudaGraphicsResourceGetMappedEglFrame' in found_functions}}cdef cudaError_t _cudaGraphicsResourceGetMappedEglFrame(cudaEglFrame* eglFrame, cudaGraphicsResource_t resource, unsigned int index, unsigned int mipLevel) except ?cudaErrorCallRequiresNewerDriver nogil{{endif}}
111+
{{if True}}cdef cudaError_t _cudaEGLStreamProducerPresentFrame(cudaEglStreamConnection* conn, cudaEglFrame eglframe, cudaStream_t* pStream) except ?cudaErrorCallRequiresNewerDriver nogil{{endif}}
112+
{{if True}}cdef cudaError_t _cudaEGLStreamProducerReturnFrame(cudaEglStreamConnection* conn, cudaEglFrame* eglframe, cudaStream_t* pStream) except ?cudaErrorCallRequiresNewerDriver nogil{{endif}}
113+
{{if True}}cdef cudaError_t _cudaGraphicsResourceGetMappedEglFrame(cudaEglFrame* eglFrame, cudaGraphicsResource_t resource, unsigned int index, unsigned int mipLevel) except ?cudaErrorCallRequiresNewerDriver nogil{{endif}}
114114
{{if True}}cdef cudaError_t _cudaVDPAUSetVDPAUDevice(int device, VdpDevice vdpDevice, VdpGetProcAddress* vdpGetProcAddress) except ?cudaErrorCallRequiresNewerDriver nogil{{endif}}
115115
{{if 'cudaArrayGetMemoryRequirements' in found_functions}}cdef cudaError_t _cudaArrayGetMemoryRequirements(cudaArrayMemoryRequirements* memoryRequirements, cudaArray_t array, int device) except ?cudaErrorCallRequiresNewerDriver nogil{{endif}}
116116
{{if 'cudaMipmappedArrayGetMemoryRequirements' in found_functions}}cdef cudaError_t _cudaMipmappedArrayGetMemoryRequirements(cudaArrayMemoryRequirements* memoryRequirements, cudaMipmappedArray_t mipmap, int device) except ?cudaErrorCallRequiresNewerDriver nogil{{endif}}

cuda_bindings/cuda/bindings/_lib/cyruntime/cyruntime.pyx.in

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2206,6 +2206,7 @@ cdef cudaError_t _cudaGetTextureObjectResourceDesc(cudaResourceDesc* pResDesc, c
22062206
return err
22072207

22082208
{{endif}}
2209+
{{if True}}
22092210

22102211
cdef cudaError_t _cudaEGLStreamProducerPresentFrame(cudaEglStreamConnection* conn, cudaEglFrame eglframe, cudaStream_t* pStream) except ?cudaErrorCallRequiresNewerDriver nogil:
22112212
cdef cudaError_t err = cudaSuccess
@@ -2222,6 +2223,9 @@ cdef cudaError_t _cudaEGLStreamProducerPresentFrame(cudaEglStreamConnection* con
22222223
_setLastError(err)
22232224
return err
22242225

2226+
{{endif}}
2227+
{{if True}}
2228+
22252229
cdef cudaError_t _cudaEGLStreamProducerReturnFrame(cudaEglStreamConnection* conn, cudaEglFrame* eglframe, cudaStream_t* pStream) except ?cudaErrorCallRequiresNewerDriver nogil:
22262230
cdef cudaError_t err = cudaSuccess
22272231
err = m_global.lazyInitContextState()
@@ -2242,6 +2246,9 @@ cdef cudaError_t _cudaEGLStreamProducerReturnFrame(cudaEglStreamConnection* conn
22422246
return err
22432247
return err
22442248

2249+
{{endif}}
2250+
{{if True}}
2251+
22452252
cdef cudaError_t _cudaGraphicsResourceGetMappedEglFrame(cudaEglFrame* eglFrame, cudaGraphicsResource_t resource, unsigned int index, unsigned int mipLevel) except ?cudaErrorCallRequiresNewerDriver nogil:
22462253
cdef cudaError_t err = cudaSuccess
22472254
err = m_global.lazyInitContextState()
@@ -2259,9 +2266,13 @@ cdef cudaError_t _cudaGraphicsResourceGetMappedEglFrame(cudaEglFrame* eglFrame,
22592266
return err
22602267
return err
22612268

2269+
{{endif}}
2270+
{{if True}}
2271+
22622272
cdef cudaError_t _cudaVDPAUSetVDPAUDevice(int device, VdpDevice vdpDevice, VdpGetProcAddress* vdpGetProcAddress) except ?cudaErrorCallRequiresNewerDriver nogil:
22632273
return cudaErrorNotSupported
22642274

2275+
{{endif}}
22652276
{{if 'cudaArrayGetMemoryRequirements' in found_functions}}
22662277

22672278
cdef cudaError_t _cudaArrayGetMemoryRequirements(cudaArrayMemoryRequirements* memoryRequirements, cudaArray_t array, int device) except ?cudaErrorCallRequiresNewerDriver nogil:

cuda_bindings/docs/source/release/12.X.Y-notes.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ Highlights
99

1010
* The ``cuda.bindings.nvvm`` Python module was added, wrapping the
1111
`libNVVM C API <https://docs.nvidia.com/cuda/libnvvm-api/>`_.
12+
* Source build error checking added for missing required headers

cuda_bindings/setup.py

Lines changed: 96 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,11 @@
4848
# ----------------------------------------------------------------------
4949
# Parse user-provided CUDA headers
5050

51-
header_dict = {
52-
"driver": ["cuda.h", "cudaProfiler.h", "cudaEGL.h", "cudaGL.h", "cudaVDPAU.h"],
51+
required_headers = {
52+
"driver": [
53+
"cuda.h",
54+
"cudaProfiler.h",
55+
],
5356
"runtime": [
5457
"driver_types.h",
5558
"vector_types.h",
@@ -61,32 +64,42 @@
6164
"device_types.h",
6265
"driver_functions.h",
6366
"cuda_profiler_api.h",
64-
"cuda_egl_interop.h",
65-
"cuda_gl_interop.h",
66-
"cuda_vdpau_interop.h",
6767
],
68-
"nvrtc": ["nvrtc.h"],
68+
"nvrtc": [
69+
"nvrtc.h",
70+
],
71+
# During compilation, Cython will reference C headers that are not
72+
# explicitly parsed above. These are the known dependencies:
73+
#
74+
# - crt/host_defines.h
75+
# - builtin_types.h
76+
# - cuda_device_runtime_api.h
6977
}
7078

71-
replace = {
72-
" __device_builtin__ ": " ",
73-
"CUDARTAPI ": " ",
74-
"typedef __device_builtin__ enum cudaError cudaError_t;": "typedef cudaError cudaError_t;",
75-
"typedef __device_builtin__ enum cudaOutputMode cudaOutputMode_t;": "typedef cudaOutputMode cudaOutputMode_t;",
76-
"typedef enum cudaError cudaError_t;": "typedef cudaError cudaError_t;",
77-
"typedef enum cudaOutputMode cudaOutputMode_t;": "typedef cudaOutputMode cudaOutputMode_t;",
78-
"typedef enum cudaDataType_t cudaDataType_t;": "",
79-
"typedef enum libraryPropertyType_t libraryPropertyType_t;": "",
80-
" enum ": " ",
81-
", enum ": ", ",
82-
"\\(enum ": "(",
83-
}
8479

85-
found_types = []
86-
found_functions = []
87-
found_values = []
88-
found_struct = []
89-
struct_list = {}
80+
def fetch_header_paths(required_headers, include_path_list):
81+
header_dict = {}
82+
missing_headers = []
83+
for library, header_list in required_headers.items():
84+
header_paths = []
85+
for header in header_list:
86+
path_candidate = [os.path.join(path, header) for path in include_path_list]
87+
for path in path_candidate:
88+
if os.path.exists(path):
89+
header_paths += [path]
90+
break
91+
else:
92+
missing_headers += [header]
93+
94+
# Update dictionary with validated paths to headers
95+
header_dict[library] = header_paths
96+
97+
if missing_headers:
98+
error_message = "Couldn't find required headers: "
99+
error_message += ", ".join([header for header in missing_headers])
100+
raise RuntimeError(f'{error_message}\nIs CUDA_HOME setup correctly? (CUDA_HOME="{CUDA_HOME}")')
101+
102+
return header_dict
90103

91104

92105
class Struct:
@@ -117,52 +130,66 @@ def __repr__(self):
117130
return f"{self._name}: {self._member_names} with types {self._member_types}"
118131

119132

120-
include_path_list = [os.path.join(path, "include") for path in CUDA_HOME]
121-
print(f'Parsing headers in "{include_path_list}" (Caching = {PARSER_CACHING})')
122-
for library, header_list in header_dict.items():
123-
header_paths = []
124-
for header in header_list:
125-
path_candidate = [os.path.join(path, header) for path in include_path_list]
126-
for path in path_candidate:
127-
if os.path.exists(path):
128-
header_paths += [path]
129-
break
130-
if not os.path.exists(path):
131-
print(f"Missing header {header}")
132-
133-
print(f"Parsing {library} headers")
134-
parser = CParser(
135-
header_paths, cache="./cache_{}".format(library.split(".")[0]) if PARSER_CACHING else None, replace=replace
136-
)
133+
def parse_headers(header_dict):
134+
found_types = []
135+
found_functions = []
136+
found_values = []
137+
found_struct = []
138+
struct_list = {}
139+
140+
replace = {
141+
" __device_builtin__ ": " ",
142+
"CUDARTAPI ": " ",
143+
"typedef __device_builtin__ enum cudaError cudaError_t;": "typedef cudaError cudaError_t;",
144+
"typedef __device_builtin__ enum cudaOutputMode cudaOutputMode_t;": "typedef cudaOutputMode cudaOutputMode_t;",
145+
"typedef enum cudaError cudaError_t;": "typedef cudaError cudaError_t;",
146+
"typedef enum cudaOutputMode cudaOutputMode_t;": "typedef cudaOutputMode cudaOutputMode_t;",
147+
"typedef enum cudaDataType_t cudaDataType_t;": "",
148+
"typedef enum libraryPropertyType_t libraryPropertyType_t;": "",
149+
" enum ": " ",
150+
", enum ": ", ",
151+
"\\(enum ": "(",
152+
}
153+
154+
print(f'Parsing headers in "{include_path_list}" (Caching = {PARSER_CACHING})')
155+
for library, header_paths in header_dict.items():
156+
print(f"Parsing {library} headers")
157+
parser = CParser(
158+
header_paths, cache="./cache_{}".format(library.split(".")[0]) if PARSER_CACHING else None, replace=replace
159+
)
160+
161+
if library == "driver":
162+
CUDA_VERSION = parser.defs["macros"].get("CUDA_VERSION", "Unknown")
163+
print(f"Found CUDA_VERSION: {CUDA_VERSION}")
164+
165+
# Combine types with others since they sometimes get tangled
166+
found_types += {key for key in parser.defs["types"]}
167+
found_types += {key for key in parser.defs["structs"]}
168+
found_types += {key for key in parser.defs["unions"]}
169+
found_types += {key for key in parser.defs["enums"]}
170+
found_functions += {key for key in parser.defs["functions"]}
171+
found_values += {key for key in parser.defs["values"]}
172+
173+
for key, value in parser.defs["structs"].items():
174+
struct_list[key] = Struct(key, value["members"])
175+
for key, value in parser.defs["unions"].items():
176+
struct_list[key] = Struct(key, value["members"])
177+
178+
for key, value in struct_list.items():
179+
if key.startswith("anon_union") or key.startswith("anon_struct"):
180+
continue
137181

138-
if library == "driver":
139-
CUDA_VERSION = parser.defs["macros"].get("CUDA_VERSION", "Unknown")
140-
print(f"Found CUDA_VERSION: {CUDA_VERSION}")
141-
142-
# Combine types with others since they sometimes get tangled
143-
found_types += {key for key in parser.defs["types"]}
144-
found_types += {key for key in parser.defs["structs"]}
145-
found_types += {key for key in parser.defs["unions"]}
146-
found_types += {key for key in parser.defs["enums"]}
147-
found_functions += {key for key in parser.defs["functions"]}
148-
found_values += {key for key in parser.defs["values"]}
149-
150-
for key, value in parser.defs["structs"].items():
151-
struct_list[key] = Struct(key, value["members"])
152-
for key, value in parser.defs["unions"].items():
153-
struct_list[key] = Struct(key, value["members"])
154-
155-
for key, value in struct_list.items():
156-
if key.startswith("anon_union") or key.startswith("anon_struct"):
157-
continue
158-
159-
found_struct += [key]
160-
discovered = value.discoverMembers(struct_list, key)
161-
if discovered:
162-
found_struct += discovered
163-
164-
if len(found_functions) == 0:
165-
raise RuntimeError(f'Parser found no functions. Is CUDA_HOME setup correctly? (CUDA_HOME="{CUDA_HOME}")')
182+
found_struct += [key]
183+
discovered = value.discoverMembers(struct_list, key)
184+
if discovered:
185+
found_struct += discovered
186+
187+
return found_types, found_functions, found_values, found_struct, struct_list
188+
189+
190+
include_path_list = [os.path.join(path, "include") for path in CUDA_HOME]
191+
header_dict = fetch_header_paths(required_headers, include_path_list)
192+
found_types, found_functions, found_values, found_struct, struct_list = parse_headers(header_dict)
166193

167194
# ----------------------------------------------------------------------
168195
# Generate

0 commit comments

Comments
 (0)