diff --git a/cuda_bindings/cuda/bindings/_lib/cyruntime/cyruntime.pxd.in b/cuda_bindings/cuda/bindings/_lib/cyruntime/cyruntime.pxd.in index 743dac01a..c760f0220 100644 --- a/cuda_bindings/cuda/bindings/_lib/cyruntime/cyruntime.pxd.in +++ b/cuda_bindings/cuda/bindings/_lib/cyruntime/cyruntime.pxd.in @@ -108,9 +108,9 @@ from libcpp cimport bool {{if 'cudaCreateSurfaceObject' in found_functions}}cdef cudaError_t _cudaCreateSurfaceObject(cudaSurfaceObject_t* pSurfObject, const cudaResourceDesc* pResDesc) except ?cudaErrorCallRequiresNewerDriver nogil{{endif}} {{if 'cudaGetTextureObjectResourceDesc' in found_functions}}cdef cudaError_t _cudaGetTextureObjectResourceDesc(cudaResourceDesc* pResDesc, cudaTextureObject_t texObject) except ?cudaErrorCallRequiresNewerDriver nogil{{endif}} {{if 'cudaGraphicsEGLRegisterImage' in found_functions}}cdef cudaError_t _cudaGraphicsEGLRegisterImage(cudaGraphicsResource_t* pCudaResource, EGLImageKHR image, unsigned int flags) except ?cudaErrorCallRequiresNewerDriver nogil{{endif}} -{{if 'cudaEGLStreamProducerPresentFrame' in found_functions}}cdef cudaError_t _cudaEGLStreamProducerPresentFrame(cudaEglStreamConnection* conn, cudaEglFrame eglframe, cudaStream_t* pStream) except ?cudaErrorCallRequiresNewerDriver nogil{{endif}} -{{if 'cudaEGLStreamProducerReturnFrame' in found_functions}}cdef cudaError_t _cudaEGLStreamProducerReturnFrame(cudaEglStreamConnection* conn, cudaEglFrame* eglframe, cudaStream_t* pStream) except ?cudaErrorCallRequiresNewerDriver nogil{{endif}} -{{if 'cudaGraphicsResourceGetMappedEglFrame' in found_functions}}cdef cudaError_t _cudaGraphicsResourceGetMappedEglFrame(cudaEglFrame* eglFrame, cudaGraphicsResource_t resource, unsigned int index, unsigned int mipLevel) except ?cudaErrorCallRequiresNewerDriver nogil{{endif}} +{{if True}}cdef cudaError_t _cudaEGLStreamProducerPresentFrame(cudaEglStreamConnection* conn, cudaEglFrame eglframe, cudaStream_t* pStream) except ?cudaErrorCallRequiresNewerDriver nogil{{endif}} +{{if True}}cdef cudaError_t _cudaEGLStreamProducerReturnFrame(cudaEglStreamConnection* conn, cudaEglFrame* eglframe, cudaStream_t* pStream) except ?cudaErrorCallRequiresNewerDriver nogil{{endif}} +{{if True}}cdef cudaError_t _cudaGraphicsResourceGetMappedEglFrame(cudaEglFrame* eglFrame, cudaGraphicsResource_t resource, unsigned int index, unsigned int mipLevel) except ?cudaErrorCallRequiresNewerDriver nogil{{endif}} {{if True}}cdef cudaError_t _cudaVDPAUSetVDPAUDevice(int device, VdpDevice vdpDevice, VdpGetProcAddress* vdpGetProcAddress) except ?cudaErrorCallRequiresNewerDriver nogil{{endif}} {{if 'cudaArrayGetMemoryRequirements' in found_functions}}cdef cudaError_t _cudaArrayGetMemoryRequirements(cudaArrayMemoryRequirements* memoryRequirements, cudaArray_t array, int device) except ?cudaErrorCallRequiresNewerDriver nogil{{endif}} {{if 'cudaMipmappedArrayGetMemoryRequirements' in found_functions}}cdef cudaError_t _cudaMipmappedArrayGetMemoryRequirements(cudaArrayMemoryRequirements* memoryRequirements, cudaMipmappedArray_t mipmap, int device) except ?cudaErrorCallRequiresNewerDriver nogil{{endif}} diff --git a/cuda_bindings/cuda/bindings/_lib/cyruntime/cyruntime.pyx.in b/cuda_bindings/cuda/bindings/_lib/cyruntime/cyruntime.pyx.in index 3210f173c..b66f0c0c8 100644 --- a/cuda_bindings/cuda/bindings/_lib/cyruntime/cyruntime.pyx.in +++ b/cuda_bindings/cuda/bindings/_lib/cyruntime/cyruntime.pyx.in @@ -2206,6 +2206,7 @@ cdef cudaError_t _cudaGetTextureObjectResourceDesc(cudaResourceDesc* pResDesc, c return err {{endif}} +{{if True}} cdef cudaError_t _cudaEGLStreamProducerPresentFrame(cudaEglStreamConnection* conn, cudaEglFrame eglframe, cudaStream_t* pStream) except ?cudaErrorCallRequiresNewerDriver nogil: cdef cudaError_t err = cudaSuccess @@ -2222,6 +2223,9 @@ cdef cudaError_t _cudaEGLStreamProducerPresentFrame(cudaEglStreamConnection* con _setLastError(err) return err +{{endif}} +{{if True}} + cdef cudaError_t _cudaEGLStreamProducerReturnFrame(cudaEglStreamConnection* conn, cudaEglFrame* eglframe, cudaStream_t* pStream) except ?cudaErrorCallRequiresNewerDriver nogil: cdef cudaError_t err = cudaSuccess err = m_global.lazyInitContextState() @@ -2242,6 +2246,9 @@ cdef cudaError_t _cudaEGLStreamProducerReturnFrame(cudaEglStreamConnection* conn return err return err +{{endif}} +{{if True}} + cdef cudaError_t _cudaGraphicsResourceGetMappedEglFrame(cudaEglFrame* eglFrame, cudaGraphicsResource_t resource, unsigned int index, unsigned int mipLevel) except ?cudaErrorCallRequiresNewerDriver nogil: cdef cudaError_t err = cudaSuccess err = m_global.lazyInitContextState() @@ -2259,9 +2266,13 @@ cdef cudaError_t _cudaGraphicsResourceGetMappedEglFrame(cudaEglFrame* eglFrame, return err return err +{{endif}} +{{if True}} + cdef cudaError_t _cudaVDPAUSetVDPAUDevice(int device, VdpDevice vdpDevice, VdpGetProcAddress* vdpGetProcAddress) except ?cudaErrorCallRequiresNewerDriver nogil: return cudaErrorNotSupported +{{endif}} {{if 'cudaArrayGetMemoryRequirements' in found_functions}} cdef cudaError_t _cudaArrayGetMemoryRequirements(cudaArrayMemoryRequirements* memoryRequirements, cudaArray_t array, int device) except ?cudaErrorCallRequiresNewerDriver nogil: diff --git a/cuda_bindings/docs/source/release/12.X.Y-notes.rst b/cuda_bindings/docs/source/release/12.X.Y-notes.rst index 708bb77e3..6536d3aea 100644 --- a/cuda_bindings/docs/source/release/12.X.Y-notes.rst +++ b/cuda_bindings/docs/source/release/12.X.Y-notes.rst @@ -9,3 +9,4 @@ Highlights * The ``cuda.bindings.nvvm`` Python module was added, wrapping the `libNVVM C API `_. +* Source build error checking added for missing required headers diff --git a/cuda_bindings/setup.py b/cuda_bindings/setup.py index 887f30ac2..3409766bf 100644 --- a/cuda_bindings/setup.py +++ b/cuda_bindings/setup.py @@ -48,8 +48,11 @@ # ---------------------------------------------------------------------- # Parse user-provided CUDA headers -header_dict = { - "driver": ["cuda.h", "cudaProfiler.h", "cudaEGL.h", "cudaGL.h", "cudaVDPAU.h"], +required_headers = { + "driver": [ + "cuda.h", + "cudaProfiler.h", + ], "runtime": [ "driver_types.h", "vector_types.h", @@ -61,32 +64,42 @@ "device_types.h", "driver_functions.h", "cuda_profiler_api.h", - "cuda_egl_interop.h", - "cuda_gl_interop.h", - "cuda_vdpau_interop.h", ], - "nvrtc": ["nvrtc.h"], + "nvrtc": [ + "nvrtc.h", + ], + # During compilation, Cython will reference C headers that are not + # explicitly parsed above. These are the known dependencies: + # + # - crt/host_defines.h + # - builtin_types.h + # - cuda_device_runtime_api.h } -replace = { - " __device_builtin__ ": " ", - "CUDARTAPI ": " ", - "typedef __device_builtin__ enum cudaError cudaError_t;": "typedef cudaError cudaError_t;", - "typedef __device_builtin__ enum cudaOutputMode cudaOutputMode_t;": "typedef cudaOutputMode cudaOutputMode_t;", - "typedef enum cudaError cudaError_t;": "typedef cudaError cudaError_t;", - "typedef enum cudaOutputMode cudaOutputMode_t;": "typedef cudaOutputMode cudaOutputMode_t;", - "typedef enum cudaDataType_t cudaDataType_t;": "", - "typedef enum libraryPropertyType_t libraryPropertyType_t;": "", - " enum ": " ", - ", enum ": ", ", - "\\(enum ": "(", -} -found_types = [] -found_functions = [] -found_values = [] -found_struct = [] -struct_list = {} +def fetch_header_paths(required_headers, include_path_list): + header_dict = {} + missing_headers = [] + for library, header_list in required_headers.items(): + header_paths = [] + for header in header_list: + path_candidate = [os.path.join(path, header) for path in include_path_list] + for path in path_candidate: + if os.path.exists(path): + header_paths += [path] + break + else: + missing_headers += [header] + + # Update dictionary with validated paths to headers + header_dict[library] = header_paths + + if missing_headers: + error_message = "Couldn't find required headers: " + error_message += ", ".join([header for header in missing_headers]) + raise RuntimeError(f'{error_message}\nIs CUDA_HOME setup correctly? (CUDA_HOME="{CUDA_HOME}")') + + return header_dict class Struct: @@ -117,52 +130,66 @@ def __repr__(self): return f"{self._name}: {self._member_names} with types {self._member_types}" -include_path_list = [os.path.join(path, "include") for path in CUDA_HOME] -print(f'Parsing headers in "{include_path_list}" (Caching = {PARSER_CACHING})') -for library, header_list in header_dict.items(): - header_paths = [] - for header in header_list: - path_candidate = [os.path.join(path, header) for path in include_path_list] - for path in path_candidate: - if os.path.exists(path): - header_paths += [path] - break - if not os.path.exists(path): - print(f"Missing header {header}") - - print(f"Parsing {library} headers") - parser = CParser( - header_paths, cache="./cache_{}".format(library.split(".")[0]) if PARSER_CACHING else None, replace=replace - ) +def parse_headers(header_dict): + found_types = [] + found_functions = [] + found_values = [] + found_struct = [] + struct_list = {} + + replace = { + " __device_builtin__ ": " ", + "CUDARTAPI ": " ", + "typedef __device_builtin__ enum cudaError cudaError_t;": "typedef cudaError cudaError_t;", + "typedef __device_builtin__ enum cudaOutputMode cudaOutputMode_t;": "typedef cudaOutputMode cudaOutputMode_t;", + "typedef enum cudaError cudaError_t;": "typedef cudaError cudaError_t;", + "typedef enum cudaOutputMode cudaOutputMode_t;": "typedef cudaOutputMode cudaOutputMode_t;", + "typedef enum cudaDataType_t cudaDataType_t;": "", + "typedef enum libraryPropertyType_t libraryPropertyType_t;": "", + " enum ": " ", + ", enum ": ", ", + "\\(enum ": "(", + } + + print(f'Parsing headers in "{include_path_list}" (Caching = {PARSER_CACHING})') + for library, header_paths in header_dict.items(): + print(f"Parsing {library} headers") + parser = CParser( + header_paths, cache="./cache_{}".format(library.split(".")[0]) if PARSER_CACHING else None, replace=replace + ) + + if library == "driver": + CUDA_VERSION = parser.defs["macros"].get("CUDA_VERSION", "Unknown") + print(f"Found CUDA_VERSION: {CUDA_VERSION}") + + # Combine types with others since they sometimes get tangled + found_types += {key for key in parser.defs["types"]} + found_types += {key for key in parser.defs["structs"]} + found_types += {key for key in parser.defs["unions"]} + found_types += {key for key in parser.defs["enums"]} + found_functions += {key for key in parser.defs["functions"]} + found_values += {key for key in parser.defs["values"]} + + for key, value in parser.defs["structs"].items(): + struct_list[key] = Struct(key, value["members"]) + for key, value in parser.defs["unions"].items(): + struct_list[key] = Struct(key, value["members"]) + + for key, value in struct_list.items(): + if key.startswith("anon_union") or key.startswith("anon_struct"): + continue - if library == "driver": - CUDA_VERSION = parser.defs["macros"].get("CUDA_VERSION", "Unknown") - print(f"Found CUDA_VERSION: {CUDA_VERSION}") - - # Combine types with others since they sometimes get tangled - found_types += {key for key in parser.defs["types"]} - found_types += {key for key in parser.defs["structs"]} - found_types += {key for key in parser.defs["unions"]} - found_types += {key for key in parser.defs["enums"]} - found_functions += {key for key in parser.defs["functions"]} - found_values += {key for key in parser.defs["values"]} - - for key, value in parser.defs["structs"].items(): - struct_list[key] = Struct(key, value["members"]) - for key, value in parser.defs["unions"].items(): - struct_list[key] = Struct(key, value["members"]) - - for key, value in struct_list.items(): - if key.startswith("anon_union") or key.startswith("anon_struct"): - continue - - found_struct += [key] - discovered = value.discoverMembers(struct_list, key) - if discovered: - found_struct += discovered - -if len(found_functions) == 0: - raise RuntimeError(f'Parser found no functions. Is CUDA_HOME setup correctly? (CUDA_HOME="{CUDA_HOME}")') + found_struct += [key] + discovered = value.discoverMembers(struct_list, key) + if discovered: + found_struct += discovered + + return found_types, found_functions, found_values, found_struct, struct_list + + +include_path_list = [os.path.join(path, "include") for path in CUDA_HOME] +header_dict = fetch_header_paths(required_headers, include_path_list) +found_types, found_functions, found_values, found_struct, struct_list = parse_headers(header_dict) # ---------------------------------------------------------------------- # Generate