Files
2026-07-13 12:47:05 +08:00

850 lines
36 KiB
CMake
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
################################################################################
# CUDA Configuration Functions
# Functions for CUDA-specific build configuration and optimization
################################################################################
# Enhanced CUDA toolkit detection with proper include path setup
function(setup_cuda_toolkit_paths)
message(STATUS "🔍 Setting up CUDA toolkit paths...")
# Find CUDA toolkit first
find_package(CUDAToolkit REQUIRED)
if(NOT CUDAToolkit_FOUND)
message(FATAL_ERROR "CUDA toolkit not found. Please install CUDA toolkit or set CUDA_PATH environment variable.")
endif()
# Get CUDA include directories
get_target_property(CUDA_INCLUDE_DIRS CUDA::toolkit INTERFACE_INCLUDE_DIRECTORIES)
# If the above doesn't work, try alternative methods
if(NOT CUDA_INCLUDE_DIRS)
set(CUDA_INCLUDE_DIRS "${CUDAToolkit_INCLUDE_DIRS}")
endif()
# Still not found? Try environment variables and common paths
if(NOT CUDA_INCLUDE_DIRS)
set(CUDA_SEARCH_PATHS
$ENV{CUDA_PATH}
$ENV{CUDA_HOME}
$ENV{CUDA_ROOT}
${CUDAToolkit_ROOT}
)
if(WIN32)
list(APPEND CUDA_SEARCH_PATHS
"$ENV{ProgramFiles}/NVIDIA GPU Computing Toolkit/CUDA/v12.6"
"$ENV{ProgramFiles}/NVIDIA GPU Computing Toolkit/CUDA/v12.5"
"$ENV{ProgramFiles}/NVIDIA GPU Computing Toolkit/CUDA/v12.4"
"$ENV{ProgramFiles}/NVIDIA GPU Computing Toolkit/CUDA/v12.3"
"$ENV{ProgramFiles}/NVIDIA GPU Computing Toolkit/CUDA/v12.2"
"$ENV{ProgramFiles}/NVIDIA GPU Computing Toolkit/CUDA/v12.1"
"$ENV{ProgramFiles}/NVIDIA GPU Computing Toolkit/CUDA/v12.0"
"$ENV{ProgramFiles}/NVIDIA GPU Computing Toolkit/CUDA/v11.8"
"C:/tools/cuda"
)
else()
list(APPEND CUDA_SEARCH_PATHS
/usr/local/cuda
/opt/cuda
/usr/cuda
)
endif()
foreach(search_path ${CUDA_SEARCH_PATHS})
if(EXISTS "${search_path}/include/cuda.h")
set(CUDA_INCLUDE_DIRS "${search_path}/include")
message(STATUS "✅ Found CUDA include directory: ${CUDA_INCLUDE_DIRS}")
break()
endif()
endforeach()
endif()
# Verify we found CUDA headers
if(NOT CUDA_INCLUDE_DIRS)
message(FATAL_ERROR "❌ CUDA include directories not found. Please ensure CUDA toolkit is properly installed.")
endif()
# Verify cuda.h exists
set(CUDA_H_FOUND FALSE)
foreach(include_dir ${CUDA_INCLUDE_DIRS})
if(EXISTS "${include_dir}/cuda.h")
set(CUDA_H_FOUND TRUE)
message(STATUS "✅ Found cuda.h in: ${include_dir}")
break()
endif()
endforeach()
if(NOT CUDA_H_FOUND)
message(FATAL_ERROR "❌ cuda.h not found in CUDA include directories: ${CUDA_INCLUDE_DIRS}")
endif()
# Set variables for parent scope
set(CUDA_INCLUDE_DIRS "${CUDA_INCLUDE_DIRS}" PARENT_SCOPE)
set(CUDA_TOOLKIT_ROOT_DIR "${CUDAToolkit_ROOT}" PARENT_SCOPE)
message(STATUS "✅ CUDA toolkit paths configured:")
message(STATUS " Root: ${CUDAToolkit_ROOT}")
message(STATUS " Include: ${CUDA_INCLUDE_DIRS}")
message(STATUS " Version: ${CUDAToolkit_VERSION}")
endfunction()
# Modern cuDNN detection using updated FindCUDNN.cmake practices
function(setup_modern_cudnn)
set(HAVE_CUDNN FALSE PARENT_SCOPE)
if(NOT (HELPERS_cudnn AND SD_CUDA))
message(STATUS "🔍 cuDNN: Skipped (HELPERS_cudnn=${HELPERS_cudnn}, SD_CUDA=${SD_CUDA})")
return()
endif()
message(STATUS "🔍 Searching for cuDNN...")
# Find the CUDA toolkit first to get the proper paths
find_package(CUDAToolkit REQUIRED)
# Enhanced search paths for CI environments and common installations
set(CUDNN_SEARCH_PATHS
# Environment variables
$ENV{CUDNN_ROOT_DIR}
$ENV{CUDNN_ROOT}
$ENV{CUDA_PATH}
$ENV{CUDA_HOME}
# CMake variables
${CUDNN_ROOT_DIR}
${CUDAToolkit_ROOT}
)
# Add platform-specific paths
if(WIN32)
# Windows-specific paths
list(APPEND CUDNN_SEARCH_PATHS
"$ENV{ProgramFiles}/NVIDIA GPU Computing Toolkit/CUDA/v12.6"
"$ENV{ProgramFiles}/NVIDIA GPU Computing Toolkit/CUDA/v12.5"
"$ENV{ProgramFiles}/NVIDIA GPU Computing Toolkit/CUDA/v12.4"
"$ENV{ProgramFiles}/NVIDIA GPU Computing Toolkit/CUDA/v12.3"
"$ENV{ProgramFiles}/NVIDIA GPU Computing Toolkit/CUDA/v12.2"
"$ENV{ProgramFiles}/NVIDIA GPU Computing Toolkit/CUDA/v12.1"
"$ENV{ProgramFiles}/NVIDIA GPU Computing Toolkit/CUDA/v12.0"
"$ENV{ProgramFiles}/NVIDIA GPU Computing Toolkit/CUDA/v11.8"
"$ENV{ProgramFiles}/NVIDIA GPU Computing Toolkit/CUDA/v11.7"
"$ENV{ProgramFiles}/NVIDIA GPU Computing Toolkit/CUDA/v11.6"
"$ENV{ProgramFiles}/NVIDIA GPU Computing Toolkit/CUDA/v11.5"
"$ENV{ProgramFiles}/NVIDIA GPU Computing Toolkit/CUDA/v11.4"
"$ENV{ProgramFiles}/NVIDIA GPU Computing Toolkit/CUDA/v11.3"
"$ENV{ProgramFiles}/NVIDIA GPU Computing Toolkit/CUDA/v11.2"
"$ENV{ProgramFiles}/NVIDIA GPU Computing Toolkit/CUDA/v11.1"
"$ENV{ProgramFiles}/NVIDIA GPU Computing Toolkit/CUDA/v11.0"
"$ENV{ProgramFiles}/NVIDIA GPU Computing Toolkit/CUDA"
"C:/tools/cuda" # Common CI path on Windows
)
else()
# Linux/Unix-specific paths
list(APPEND CUDNN_SEARCH_PATHS
# CI-specific paths (GitHub Actions, etc.)
/usr/local/cuda-12.6
/usr/local/cuda-12.5
/usr/local/cuda-12.4
/usr/local/cuda-12.3
/usr/local/cuda-12.2
/usr/local/cuda-12.1
/usr/local/cuda-12.0
/usr/local/cuda-11.8
/usr/local/cuda-11.7
/usr/local/cuda-11.6
/usr/local/cuda-11.5
/usr/local/cuda-11.4
/usr/local/cuda-11.3
/usr/local/cuda-11.2
/usr/local/cuda-11.1
/usr/local/cuda-11.0
/usr/local/cuda
# Package manager paths
/usr/include/cudnn
/usr/local/include/cudnn
/opt/cuda
/opt/cudnn
# System paths
/usr
/usr/local
)
endif()
message(STATUS "🔍 Searching for cuDNN headers...")
# Search for cuDNN headers with comprehensive path coverage
find_path(CUDNN_INCLUDE_DIR
NAMES cudnn.h
HINTS ${CUDNN_SEARCH_PATHS}
PATHS ${CUDNN_SEARCH_PATHS}
PATH_SUFFIXES
include
targets/x86_64-linux/include
targets/aarch64-linux/include
include/cudnn
cudnn/include
x86_64-linux/include
aarch64-linux/include
NO_DEFAULT_PATH
)
# If not found, try system paths
if(NOT CUDNN_INCLUDE_DIR)
find_path(CUDNN_INCLUDE_DIR
NAMES cudnn.h
PATHS /usr/include /usr/local/include /opt/include
PATH_SUFFIXES cudnn
)
endif()
message(STATUS "🔍 Searching for cuDNN libraries...")
# Search for cuDNN libraries
find_library(CUDNN_LIBRARY
NAMES cudnn libcudnn cudnn8 libcudnn8
HINTS ${CUDNN_SEARCH_PATHS}
PATHS ${CUDNN_SEARCH_PATHS}
PATH_SUFFIXES
lib64
lib
lib/x64
targets/x86_64-linux/lib
targets/aarch64-linux/lib
lib64/cudnn
lib/cudnn
cudnn/lib64
cudnn/lib
x86_64-linux/lib
aarch64-linux/lib
NO_DEFAULT_PATH
)
# If not found, try system paths
if(NOT CUDNN_LIBRARY)
find_library(CUDNN_LIBRARY
NAMES cudnn libcudnn cudnn8 libcudnn8
PATHS /usr/lib64 /usr/lib /usr/local/lib64 /usr/local/lib /opt/lib64 /opt/lib
PATH_SUFFIXES cudnn
)
endif()
message(STATUS "🔍 cuDNN search results:")
message(STATUS " CUDNN_INCLUDE_DIR: ${CUDNN_INCLUDE_DIR}")
message(STATUS " CUDNN_LIBRARY: ${CUDNN_LIBRARY}")
# Check if we found both header and library
if(CUDNN_INCLUDE_DIR AND CUDNN_LIBRARY)
message(STATUS "✅ cuDNN found!")
# Extract version information from cudnn.h
if(EXISTS "${CUDNN_INCLUDE_DIR}/cudnn.h")
file(READ "${CUDNN_INCLUDE_DIR}/cudnn.h" CUDNN_HEADER_CONTENTS)
# Try different version detection methods
string(REGEX MATCH "define CUDNN_MAJOR[ \t]+([0-9]+)" CUDNN_VERSION_MAJOR_MATCH "${CUDNN_HEADER_CONTENTS}")
string(REGEX MATCH "define CUDNN_MINOR[ \t]+([0-9]+)" CUDNN_VERSION_MINOR_MATCH "${CUDNN_HEADER_CONTENTS}")
string(REGEX MATCH "define CUDNN_PATCHLEVEL[ \t]+([0-9]+)" CUDNN_VERSION_PATCH_MATCH "${CUDNN_HEADER_CONTENTS}")
if(CUDNN_VERSION_MAJOR_MATCH)
string(REGEX REPLACE "define CUDNN_MAJOR[ \t]+([0-9]+)" "\\1" CUDNN_VERSION_MAJOR "${CUDNN_VERSION_MAJOR_MATCH}")
string(REGEX REPLACE "define CUDNN_MINOR[ \t]+([0-9]+)" "\\1" CUDNN_VERSION_MINOR "${CUDNN_VERSION_MINOR_MATCH}")
string(REGEX REPLACE "define CUDNN_PATCHLEVEL[ \t]+([0-9]+)" "\\1" CUDNN_VERSION_PATCH "${CUDNN_VERSION_PATCH_MATCH}")
set(CUDNN_VERSION_STRING "${CUDNN_VERSION_MAJOR}.${CUDNN_VERSION_MINOR}.${CUDNN_VERSION_PATCH}")
else()
# Try alternative version detection
string(REGEX MATCH "#define CUDNN_MAJOR ([0-9]+)" CUDNN_VERSION_MAJOR_MATCH2 "${CUDNN_HEADER_CONTENTS}")
if(CUDNN_VERSION_MAJOR_MATCH2)
string(REGEX REPLACE "#define CUDNN_MAJOR ([0-9]+)" "\\1" CUDNN_VERSION_MAJOR "${CUDNN_VERSION_MAJOR_MATCH2}")
string(REGEX MATCH "#define CUDNN_MINOR ([0-9]+)" CUDNN_VERSION_MINOR_MATCH2 "${CUDNN_HEADER_CONTENTS}")
string(REGEX MATCH "#define CUDNN_PATCHLEVEL ([0-9]+)" CUDNN_VERSION_PATCH_MATCH2 "${CUDNN_HEADER_CONTENTS}")
string(REGEX REPLACE "#define CUDNN_MINOR ([0-9]+)" "\\1" CUDNN_VERSION_MINOR "${CUDNN_VERSION_MINOR_MATCH2}")
string(REGEX REPLACE "#define CUDNN_PATCHLEVEL ([0-9]+)" "\\1" CUDNN_VERSION_PATCH "${CUDNN_VERSION_PATCH_MATCH2}")
set(CUDNN_VERSION_STRING "${CUDNN_VERSION_MAJOR}.${CUDNN_VERSION_MINOR}.${CUDNN_VERSION_PATCH}")
else()
set(CUDNN_VERSION_STRING "Unknown")
endif()
endif()
else()
message(WARNING "⚠️ cuDNN header found but cannot read version")
set(CUDNN_VERSION_STRING "Unknown")
endif()
# Create imported target if it doesn't exist
if(NOT TARGET CUDNN::cudnn)
add_library(CUDNN::cudnn UNKNOWN IMPORTED)
set_target_properties(CUDNN::cudnn PROPERTIES
IMPORTED_LOCATION "${CUDNN_LIBRARY}"
INTERFACE_INCLUDE_DIRECTORIES "${CUDNN_INCLUDE_DIR}"
)
endif()
message(STATUS "✅ cuDNN configuration:")
message(STATUS " Include: ${CUDNN_INCLUDE_DIR}")
message(STATUS " Library: ${CUDNN_LIBRARY}")
message(STATUS " Version: ${CUDNN_VERSION_STRING}")
# Set all the variables that might be needed
set(HAVE_CUDNN TRUE PARENT_SCOPE)
set(CUDNN_FOUND TRUE PARENT_SCOPE)
set(CUDNN_INCLUDE_DIR "${CUDNN_INCLUDE_DIR}" PARENT_SCOPE)
set(CUDNN_LIBRARIES "${CUDNN_LIBRARY}" PARENT_SCOPE)
set(CUDNN_LIBRARY "${CUDNN_LIBRARY}" PARENT_SCOPE)
set(CUDNN_VERSION_STRING "${CUDNN_VERSION_STRING}" PARENT_SCOPE)
return()
endif()
# Try package manager detection as fallback
find_package(PkgConfig QUIET)
if(PkgConfig_FOUND)
pkg_check_modules(PC_CUDNN QUIET cudnn)
if(PC_CUDNN_FOUND)
message(STATUS "✅ Found cuDNN via pkg-config")
set(HAVE_CUDNN TRUE PARENT_SCOPE)
set(CUDNN_INCLUDE_DIR "${PC_CUDNN_INCLUDE_DIRS}" PARENT_SCOPE)
set(CUDNN_LIBRARIES "${PC_CUDNN_LIBRARIES}" PARENT_SCOPE)
set(CUDNN_VERSION_STRING "${PC_CUDNN_VERSION}" PARENT_SCOPE)
return()
endif()
endif()
# Final attempt: check if cuDNN is embedded in CUDA installation
if(CUDAToolkit_FOUND AND CUDAToolkit_INCLUDE_DIRS)
foreach(cuda_include_dir ${CUDAToolkit_INCLUDE_DIRS})
if(EXISTS "${cuda_include_dir}/cudnn.h")
message(STATUS "✅ Found cuDNN embedded in CUDA installation")
set(HAVE_CUDNN TRUE PARENT_SCOPE)
set(CUDNN_INCLUDE_DIR "${cuda_include_dir}" PARENT_SCOPE)
set(CUDNN_LIBRARIES "" PARENT_SCOPE) # May be linked with CUDA
set(CUDNN_VERSION_STRING "Embedded" PARENT_SCOPE)
return()
endif()
endforeach()
endif()
message(STATUS "❌ cuDNN not found. Searched extensively in:")
message(STATUS " Environment variables: CUDNN_ROOT_DIR, CUDNN_ROOT, CUDA_PATH, CUDA_HOME")
message(STATUS " CUDA installation: ${CUDAToolkit_ROOT}")
if(WIN32)
message(STATUS " System paths: $ENV{ProgramFiles}/NVIDIA GPU Computing Toolkit")
else()
message(STATUS " System paths: /usr, /usr/local, /opt")
endif()
message(STATUS " Package manager: pkg-config")
message(STATUS "")
message(STATUS "💡 To fix this issue:")
message(STATUS " 1. Install cuDNN development libraries")
message(STATUS " 2. Set CUDNN_ROOT_DIR to your cuDNN installation")
message(STATUS " 3. Ensure cuDNN headers are in CUDA_PATH/include")
message(STATUS " 4. Or disable cuDNN with -DHELPERS_cudnn=OFF")
# Debug information
message(STATUS "")
message(STATUS "🔍 Debug information:")
message(STATUS " CUDAToolkit_ROOT: ${CUDAToolkit_ROOT}")
message(STATUS " CUDAToolkit_INCLUDE_DIRS: ${CUDAToolkit_INCLUDE_DIRS}")
message(STATUS " ENV CUDNN_ROOT_DIR: $ENV{CUDNN_ROOT_DIR}")
message(STATUS " ENV CUDA_PATH: $ENV{CUDA_PATH}")
message(STATUS " ENV CUDA_HOME: $ENV{CUDA_HOME}")
endfunction()
function(configure_cuda_linking main_target_name)
# Setup CUDA toolkit paths first
setup_cuda_toolkit_paths()
# Find the CUDAToolkit to define the CUDA::toolkit target
find_package(CUDAToolkit REQUIRED)
# Setup modern cuDNN detection
setup_modern_cudnn()
# This ensures cuda.h and other CUDA headers are found
if(CUDA_INCLUDE_DIRS)
target_include_directories(${main_target_name} PUBLIC ${CUDA_INCLUDE_DIRS})
message(STATUS "✅ Added CUDA include directories to ${main_target_name}: ${CUDA_INCLUDE_DIRS}")
endif()
# Apply GNU-specific CUDA compiler flags for duplicate instantiation handling
# ONLY for non-Windows builds
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND NOT WIN32)
message(STATUS "🔧 Applying GNU-specific CUDA flags for duplicate instantiation handling")
target_compile_options(${main_target_name} PRIVATE
$<$<COMPILE_LANGUAGE:CUDA>:-Xcompiler=-fno-implicit-templates>
)
endif()
# Modern CMake uses imported targets which handle all necessary dependencies.
# Linking against CUDA::toolkit automatically adds include directories,
# runtime libraries, and all other required flags.
target_link_libraries(${main_target_name} PUBLIC CUDA::toolkit)
# If cuDNN was found, link against its imported target
if(HAVE_CUDNN AND TARGET CUDNN::cudnn)
message(STATUS "✅ Linking with modern CUDNN::cudnn target")
target_link_libraries(${main_target_name} PUBLIC CUDNN::cudnn)
target_compile_definitions(${main_target_name} PUBLIC HAVE_CUDNN=1)
elseif(HAVE_CUDNN AND CUDNN_LIBRARIES)
message(STATUS "✅ Linking with cuDNN libraries: ${CUDNN_LIBRARIES}")
target_link_libraries(${main_target_name} PUBLIC ${CUDNN_LIBRARIES})
target_include_directories(${main_target_name} PUBLIC ${CUDNN_INCLUDE_DIR})
target_compile_definitions(${main_target_name} PUBLIC HAVE_CUDNN=1)
elseif(HAVE_CUDNN AND CUDNN_INCLUDE_DIR)
message(STATUS "✅ Linking with cuDNN include-only (embedded in CUDA)")
target_include_directories(${main_target_name} PUBLIC ${CUDNN_INCLUDE_DIR})
target_compile_definitions(${main_target_name} PUBLIC HAVE_CUDNN=1)
else()
message(STATUS "️ Building without cuDNN support")
target_compile_definitions(${main_target_name} PUBLIC HAVE_CUDNN=0)
endif()
target_link_libraries(${main_target_name} PUBLIC flatbuffers_interface)
install(TARGETS ${main_target_name} DESTINATION .)
endfunction()
function(setup_cuda_architectures_early)
if(NOT SD_CUDA)
return()
endif()
# Fix missing _CMAKE_CUDA_WHOLE_FLAG (note the underscore prefix)
if(NOT DEFINED _CMAKE_CUDA_WHOLE_FLAG)
message(STATUS "Setting _CMAKE_CUDA_WHOLE_FLAG (was missing)")
if(WIN32)
set(_CMAKE_CUDA_WHOLE_FLAG "/WHOLEARCHIVE:" CACHE INTERNAL "CUDA whole archive flag")
else()
set(_CMAKE_CUDA_WHOLE_FLAG "-Wl,--whole-archive" CACHE INTERNAL "CUDA whole archive flag")
endif()
endif()
if(NOT DEFINED CMAKE_CUDA_WHOLE_FLAG)
if(WIN32)
set(CMAKE_CUDA_WHOLE_FLAG "/WHOLEARCHIVE:" CACHE STRING "CUDA whole archive flag")
else()
set(CMAKE_CUDA_WHOLE_FLAG "-Wl,--whole-archive" CACHE STRING "CUDA whole archive flag")
endif()
endif()
message(STATUS "🔧 Early CUDA: Configuring architectures before project() call")
if(DEFINED COMPUTE)
string(TOLOWER "${COMPUTE}" COMPUTE_CMP)
if(COMPUTE_CMP STREQUAL "all")
set(CUDA_ARCHITECTURES "75;80;86;89" PARENT_SCOPE)
message(STATUS " CUDA architectures (all): 75;80;86;89")
elseif(COMPUTE_CMP STREQUAL "auto")
set(CMAKE_CUDA_ARCHITECTURES "86" PARENT_SCOPE)
message(STATUS " CUDA architectures (auto): 86")
else()
string(REPLACE "," ";" ARCH_LIST "${COMPUTE}")
set(PARSED_ARCHS "")
foreach(ARCH ${ARCH_LIST})
string(REPLACE "." "" ARCH_CLEAN "${ARCH}")
if(ARCH_CLEAN MATCHES "^[0-9][0-9]$")
list(APPEND PARSED_ARCHS "${ARCH_CLEAN}")
endif()
endforeach()
if(PARSED_ARCHS)
set(CUDA_ARCHITECTURES "${PARSED_ARCHS}" PARENT_SCOPE)
message(STATUS " CUDA architectures (custom): ${PARSED_ARCHS}")
else()
set(CUDA_ARCHITECTURES "86" PARENT_SCOPE)
message(STATUS " CUDA architectures (default): 86")
endif()
endif()
else()
set(CUDA_ARCHITECTURES "86" PARENT_SCOPE)
message(STATUS " CUDA architectures (no COMPUTE): 86")
endif()
endfunction()
function(setup_cuda_language)
if(NOT DEFINED _CMAKE_CUDA_WHOLE_FLAG)
message(STATUS "Setting _CMAKE_CUDA_WHOLE_FLAG (was missing)")
if(WIN32)
set(_CMAKE_CUDA_WHOLE_FLAG "/WHOLEARCHIVE:" CACHE INTERNAL "CUDA whole archive flag")
else()
set(_CMAKE_CUDA_WHOLE_FLAG "-Wl,--whole-archive" CACHE INTERNAL "CUDA whole archive flag")
endif()
endif()
include(CheckLanguage)
check_language(CUDA)
if(NOT CMAKE_CUDA_COMPILER)
find_program(NVCC_EXECUTABLE nvcc)
if(NVCC_EXECUTABLE)
set(CMAKE_CUDA_COMPILER ${NVCC_EXECUTABLE} PARENT_SCOPE)
message(STATUS "CUDA compiler found: ${CMAKE_CUDA_COMPILER}")
else()
message(FATAL_ERROR "CUDA compiler not found. Please ensure CUDA toolkit is installed and nvcc is in PATH.")
endif()
endif()
message(STATUS "CUDA language enabled successfully with compiler: ${CMAKE_CUDA_COMPILER}")
endfunction()
function(configure_windows_cuda_build)
if(NOT WIN32)
return()
endif()
message(STATUS "Configuring Windows CUDA build with verbose mode...")
# Enable verbose output for the build system
set(CMAKE_VERBOSE_MAKEFILE ON PARENT_SCOPE)
set(CMAKE_CUDA_VERBOSE_FLAG ON PARENT_SCOPE)
# Completely disable response files to prevent command line issues
set(CMAKE_CUDA_USE_RESPONSE_FILE_FOR_OBJECTS OFF PARENT_SCOPE)
set(CMAKE_CUDA_USE_RESPONSE_FILE_FOR_INCLUDES OFF PARENT_SCOPE)
set(CMAKE_CUDA_USE_RESPONSE_FILE_FOR_LIBRARIES OFF PARENT_SCOPE)
set(CMAKE_CUDA_USE_RESPONSE_FILE_FOR_LINK_OBJECTS OFF PARENT_SCOPE)
# Remove problematic dependency generation that causes NVCC failures
set(CMAKE_CUDA_DEPFILE_FORMAT "" PARENT_SCOPE)
set(CMAKE_CUDA_DEPENDS_USE_COMPILER OFF PARENT_SCOPE)
# Clean MSVC runtime library settings
set(CMAKE_CUDA_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreaded "" PARENT_SCOPE)
set(CMAKE_CUDA_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDLL "" PARENT_SCOPE)
set(CMAKE_CUDA_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebug "" PARENT_SCOPE)
set(CMAKE_CUDA_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebugDLL "" PARENT_SCOPE)
# Force clean CXX flags to prevent contamination
set(CMAKE_CXX_FLAGS "" PARENT_SCOPE)
# Enable verbose rule and target messages
set_property(GLOBAL PROPERTY RULE_MESSAGES ON)
set_property(GLOBAL PROPERTY TARGET_MESSAGES ON)
message(STATUS "Windows CUDA: Verbose mode enabled with clean flags")
endfunction()
function(configure_cuda_architecture_flags COMPUTE)
string(TOLOWER "${COMPUTE}" COMPUTE_CMP)
if(COMPUTE_CMP STREQUAL "all")
set(CUDA_ARCH_FLAGS "-gencode arch=compute_75,code=sm_75 -gencode arch=compute_80,code=sm_80 -gencode arch=compute_86,code=sm_86 -gencode arch=compute_89,code=sm_89" PARENT_SCOPE)
message(STATUS "Building for all CUDA architectures (gencode flags)")
elseif(COMPUTE_CMP STREQUAL "auto")
set(CUDA_ARCH_FLAGS "-gencode arch=compute_86,code=sm_86" PARENT_SCOPE)
message(STATUS "Auto-detecting CUDA architectures (gencode flags)")
else()
string(REPLACE "," ";" ARCH_LIST "${COMPUTE}")
set(ARCH_FLAGS "")
foreach(ARCH ${ARCH_LIST})
string(REPLACE "." "" ARCH_CLEAN "${ARCH}")
if(ARCH_CLEAN MATCHES "^[0-9][0-9]$")
set(ARCH_FLAGS "${ARCH_FLAGS} -gencode arch=compute_${ARCH_CLEAN},code=sm_${ARCH_CLEAN}")
endif()
endforeach()
string(STRIP "${ARCH_FLAGS}" ARCH_FLAGS)
if(ARCH_FLAGS)
set(CUDA_ARCH_FLAGS "${ARCH_FLAGS}" PARENT_SCOPE)
message(STATUS "Using custom CUDA architectures (gencode flags): ${ARCH_FLAGS}")
else()
set(CUDA_ARCH_FLAGS "-gencode arch=compute_86,code=sm_86" PARENT_SCOPE)
message(STATUS "Using default CUDA architecture (gencode flags)")
endif()
endif()
endfunction()
function(build_cuda_compiler_flags CUDA_ARCH_FLAGS)
set(LOCAL_CUDA_FLAGS "")
if(WIN32 AND MSVC)
message(STATUS "Configuring CUDA for Windows MSVC with verbose mode...")
set(CMAKE_CUDA_HOST_COMPILER ${CMAKE_CXX_COMPILER} PARENT_SCOPE)
set(LOCAL_CUDA_FLAGS "-maxrregcount=128")
# Enable verbose mode for Windows CUDA compilation
set(LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS} --verbose")
set(LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS} --ptxas-options=-v")
set(LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS} --resource-usage")
# Host compiler verbose flags
set(LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS} -Xcompiler=/showIncludes")
set(LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS} -Xcompiler=/verbose")
set(LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS} -Xcompiler=/diagnostics:caret")
# Linker verbose flags
set(LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS} -Xlinker=/VERBOSE")
set(LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS} -Xlinker=/TIME")
# Explicitly enable C++17 for the host compiler
set(LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS} -Xcompiler=/std:c++17")
if(WIN32 AND NOT CMAKE_CUDA_HOST_COMPILER)
find_program(CL_IN_PATH cl.exe)
if(CL_IN_PATH)
# Check if this cl.exe is 64-bit by examining its path
get_filename_component(CL_DIR ${CL_IN_PATH} DIRECTORY)
if(CL_DIR MATCHES "x64")
set(CMAKE_CUDA_HOST_COMPILER ${CL_IN_PATH})
message(STATUS "Found x64 cl.exe in PATH: ${CMAKE_CUDA_HOST_COMPILER}")
else()
# Try to find x64 version relative to this cl.exe
get_filename_component(CL_PARENT ${CL_DIR} DIRECTORY)
if(EXISTS "${CL_PARENT}/x64/cl.exe")
set(CMAKE_CUDA_HOST_COMPILER "${CL_PARENT}/x64/cl.exe")
message(STATUS "Found x64 cl.exe relative to PATH cl.exe: ${CMAKE_CUDA_HOST_COMPILER}")
endif()
endif()
endif()
endif()
if(WIN32 AND NOT CMAKE_CUDA_HOST_COMPILER)
# Only check the most common paths that exist in barebones installs
set(COMMON_PATHS
"C:/Program Files (x86)/Microsoft Visual Studio/2022/BuildTools/VC/Tools/MSVC"
"C:/Program Files (x86)/Microsoft Visual Studio/2019/BuildTools/VC/Tools/MSVC"
"C:/Program Files/Microsoft Visual Studio/2022/BuildTools/VC/Tools/MSVC"
)
foreach(BASE_PATH ${COMMON_PATHS})
if(EXISTS ${BASE_PATH})
file(GLOB MSVC_VERSIONS "${BASE_PATH}/*")
if(MSVC_VERSIONS)
# Get the lexicographically last version (should be newest)
list(SORT MSVC_VERSIONS)
list(REVERSE MSVC_VERSIONS)
list(GET MSVC_VERSIONS 0 LATEST_MSVC)
set(CANDIDATE_COMPILER "${LATEST_MSVC}/bin/Hostx64/x64/cl.exe")
if(EXISTS ${CANDIDATE_COMPILER})
set(CMAKE_CUDA_HOST_COMPILER ${CANDIDATE_COMPILER})
message(STATUS "Found CUDA host compiler in standard path: ${CMAKE_CUDA_HOST_COMPILER}")
break()
endif()
endif()
endif()
endforeach()
endif()
# Validation and warning
if(WIN32)
if(CMAKE_CUDA_HOST_COMPILER)
if(NOT EXISTS ${CMAKE_CUDA_HOST_COMPILER})
message(WARNING "CUDA host compiler path does not exist: ${CMAKE_CUDA_HOST_COMPILER}")
unset(CMAKE_CUDA_HOST_COMPILER)
else()
message(STATUS "Final CUDA host compiler: ${CMAKE_CUDA_HOST_COMPILER}")
endif()
else()
message(WARNING "Could not auto-detect x64 CUDA host compiler.")
message(STATUS "Manual options:")
message(STATUS " 1. Use x64 Native Tools Command Prompt")
message(STATUS " 2. Set manually: -DCMAKE_CUDA_HOST_COMPILER=\"path/to/x64/cl.exe\"")
message(STATUS " 3. Ensure x64 cl.exe is in your PATH")
endif()
endif()
# Windows/MSVC flags: bigobj, EHsc, *and* disable the new preprocessor
set(LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS}
-Xcompiler=/std:c++17
-Xcompiler=/bigobj
-Xcompiler=/EHsc
-Xcompiler=/Zc:preprocessor-")
# Force clean host compiler flags
set(CMAKE_CXX_FLAGS "" PARENT_SCOPE)
message(STATUS "CUDA Windows verbose flags configured")
else()
message(STATUS "Configuring CUDA for Unix/Linux with verbose mode...")
set(LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS} -maxrregcount=128")
# Enable verbose mode for Unix/Linux CUDA compilation
set(LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS} --verbose")
set(LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS} --ptxas-options=-v")
set(LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS} --resource-usage")
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
# Host compiler verbose flags for GCC
set(LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS} -Xcompiler=-v")
set(LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS} -Xcompiler=-H")
# Linker verbose flags
set(LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS} -Xlinker=-v")
set(LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS} -Xlinker=--verbose")
if(SD_GCC_FUNCTRACE)
set(LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS} -Xcompiler=-fPIC --device-debug -lineinfo -G")
else()
set(LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS} -Xcompiler=-fPIC -Xcompiler=-fpermissive")
# Add flags to handle duplicate instantiations for GNU compiler
set(LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS} -Xcompiler=-fno-implicit-templates")
endif()
endif()
message(STATUS "CUDA Unix/Linux verbose flags configured")
endif()
if("${SD_PTXAS}" STREQUAL "ON")
set(LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS} --ptxas-options=-v")
endif()
if(SD_KEEP_NVCC_OUTPUT)
set(LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS} --keep")
endif()
if(DEFINED CUDA_ARCH_FLAGS)
set(LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS} ${CUDA_ARCH_FLAGS}")
endif()
set(LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS} -w --cudart=shared --expt-extended-lambda -Xfatbin -compress-all")
if(CMAKE_CUDA_COMPILER_VERSION)
string(REGEX MATCH "^([0-9]+)" CUDA_VERSION_MAJOR "${CMAKE_CUDA_COMPILER_VERSION}")
set(LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS} -DCUDA_VERSION_MAJOR=${CUDA_VERSION_MAJOR}")
endif()
# Clean up any problematic flags for Windows
if(WIN32)
# Remove any GCC-style flags that might have been added
string(REGEX REPLACE "-MD[^a-zA-Z]" "" LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS}")
string(REGEX REPLACE "-MT[^a-zA-Z]" "" LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS}")
string(REGEX REPLACE "-MF[^a-zA-Z]" "" LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS}")
string(REGEX REPLACE "-x cu" "" LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS}")
string(REGEX REPLACE "-fpermissive" "" LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS}")
string(REGEX REPLACE "-Wno-error" "" LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS}")
string(REGEX REPLACE "/FS[ ]*" "" LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS}")
string(REGEX REPLACE "-Xcompiler=-Fd[^,]*,?" "" LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS}")
string(REGEX REPLACE "-Xcompiler=," "-Xcompiler=" LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS}")
string(REGEX REPLACE "-Xcompiler=$" "" LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS}")
endif()
string(REGEX REPLACE " +" " " LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS}")
string(STRIP "${LOCAL_CUDA_FLAGS}" LOCAL_CUDA_FLAGS)
set(CMAKE_CUDA_SEPARABLE_COMPILATION ON PARENT_SCOPE)
set(CMAKE_CUDA_FLAGS "${LOCAL_CUDA_FLAGS}" PARENT_SCOPE)
message(STATUS "Final CMAKE_CUDA_FLAGS (with verbose): ${LOCAL_CUDA_FLAGS}")
endfunction()
# Debug configuration function
function(debug_cuda_configuration)
message(STATUS "=== CUDA Configuration Debug Info ===")
message(STATUS "CMAKE_CUDA_COMPILER: ${CMAKE_CUDA_COMPILER}")
message(STATUS "CMAKE_CUDA_COMPILER_VERSION: ${CMAKE_CUDA_COMPILER_VERSION}")
message(STATUS "CMAKE_CUDA_ARCHITECTURES: ${CMAKE_CUDA_ARCHITECTURES}")
message(STATUS "CMAKE_CUDA_FLAGS: ${CMAKE_CUDA_FLAGS}")
message(STATUS "CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES: ${CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES}")
message(STATUS "CMAKE_CUDA_COMPILE_OBJECT: ${CMAKE_CUDA_COMPILE_OBJECT}")
message(STATUS "CUDA_INCLUDE_DIRS: ${CUDA_INCLUDE_DIRS}")
message(STATUS "CUDAToolkit_ROOT: ${CUDAToolkit_ROOT}")
message(STATUS "CUDAToolkit_INCLUDE_DIRS: ${CUDAToolkit_INCLUDE_DIRS}")
if(HAVE_CUDNN)
message(STATUS "CUDNN_INCLUDE_DIR: ${CUDNN_INCLUDE_DIR}")
message(STATUS "CUDNN_LIBRARIES: ${CUDNN_LIBRARIES}")
message(STATUS "CUDNN_VERSION: ${CUDNN_VERSION_STRING}")
endif()
message(STATUS "=== End CUDA Debug Info ===")
endfunction()
# Enhanced CUDA include directory setup for global configuration
function(setup_cuda_include_directories)
setup_cuda_toolkit_paths()
# Set global include directories that will be inherited by all targets
if(CUDA_INCLUDE_DIRS)
include_directories(${CUDA_INCLUDE_DIRS})
message(STATUS "✅ Added global CUDA include directories: ${CUDA_INCLUDE_DIRS}")
endif()
# Also set the CMAKE variable for compatibility
if(CUDAToolkit_INCLUDE_DIRS)
set(CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES ${CUDAToolkit_INCLUDE_DIRS} PARENT_SCOPE)
endif()
endfunction()
function(setup_cuda_build)
message(STATUS "=== CUDA BUILD CONFIGURATION (VERBOSE MODE) ===")
# Enable verbose output for the build system
set(CMAKE_VERBOSE_MAKEFILE ON PARENT_SCOPE)
set(CMAKE_CUDA_VERBOSE_FLAG ON PARENT_SCOPE)
if(NOT DEFINED _CMAKE_CUDA_WHOLE_FLAG)
message(STATUS "Setting _CMAKE_CUDA_WHOLE_FLAG (was missing)")
if(WIN32)
set(_CMAKE_CUDA_WHOLE_FLAG "/WHOLEARCHIVE:" CACHE INTERNAL "CUDA whole archive flag")
else()
set(_CMAKE_CUDA_WHOLE_FLAG "-Wl,--whole-archive" CACHE INTERNAL "CUDA whole archive flag")
endif()
endif()
# Setup CUDA toolkit paths and include directories early
setup_cuda_include_directories()
if(NOT DEFINED COMPUTE)
set(COMPUTE "auto")
endif()
configure_cuda_architecture_flags("${COMPUTE}")
set_property(GLOBAL PROPERTY CUDA_ARCHITECTURES "${CMAKE_CUDA_ARCHITECTURES}")
setup_cuda_language()
if(NOT CMAKE_CUDA_COMPILER)
message(FATAL_ERROR "CUDA compiler not found after enabling CUDA language")
endif()
message(STATUS "CUDA Compiler: ${CMAKE_CUDA_COMPILER}")
message(STATUS "CUDA Include Dirs: ${CUDA_INCLUDE_DIRS}")
message(STATUS "CUDAToolkit Include Dirs: ${CUDAToolkit_INCLUDE_DIRS}")
message(STATUS "Host CXX Compiler: ${CMAKE_CXX_COMPILER_ID}")
configure_windows_cuda_build()
build_cuda_compiler_flags("${CUDA_ARCH_FLAGS}")
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS}" PARENT_SCOPE)
# Also set the toolkit include directories for global access
set(CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES "${CUDA_INCLUDE_DIRS}" PARENT_SCOPE)
# Enable verbose rule and target messages
set_property(GLOBAL PROPERTY RULE_MESSAGES ON)
set_property(GLOBAL PROPERTY TARGET_MESSAGES ON)
debug_cuda_configuration()
add_compile_definitions(SD_CUDA=true)
set(DEFAULT_ENGINE "samediff::ENGINE_CUDA" PARENT_SCOPE)
message(STATUS "=== CUDA BUILD CONFIGURATION (VERBOSE MODE) COMPLETE ===")
endfunction()
# Enhanced function to ensure CUDA paths are available at configure time
function(ensure_cuda_paths_available)
if(NOT SD_CUDA)
return()
endif()
message(STATUS "🔍 Ensuring CUDA paths are available...")
# Find CUDA early
find_package(CUDAToolkit REQUIRED)
# Set up paths immediately
setup_cuda_toolkit_paths()
# Export to parent scope for immediate use
set(CUDA_INCLUDE_DIRS "${CUDA_INCLUDE_DIRS}" PARENT_SCOPE)
set(CUDA_TOOLKIT_ROOT_DIR "${CUDAToolkit_ROOT}" PARENT_SCOPE)
message(STATUS "✅ CUDA paths configured and available")
endfunction()
# Legacy function for backward compatibility - now calls modern version
function(setup_cudnn)
setup_modern_cudnn()
# Set legacy variables for backward compatibility
set(HAVE_CUDNN ${HAVE_CUDNN} PARENT_SCOPE)
if(HAVE_CUDNN)
set(CUDNN_INCLUDE_DIR ${CUDNN_INCLUDE_DIR} PARENT_SCOPE)
set(CUDNN ${CUDNN_LIBRARIES} PARENT_SCOPE)
endif()
endfunction()