| 1 | include(FetchContent) |
| 2 | |
| 3 | # If DEEPGEMM_SRC_DIR is set, DeepGEMM is built from that directory |
| 4 | # instead of downloading. |
| 5 | # It can be set as an environment variable or passed as a cmake argument. |
| 6 | # The environment variable takes precedence. |
| 7 | if (DEFINED ENV{DEEPGEMM_SRC_DIR}) |
| 8 | set(DEEPGEMM_SRC_DIR $ENV{DEEPGEMM_SRC_DIR}) |
| 9 | endif() |
| 10 | |
| 11 | # Local tree: set deepgemm_SOURCE_DIR directly (no FetchContent download). |
| 12 | # Upstream git: use FetchContent_Populate with explicit options (CMP0169 NEW |
| 13 | # disallows one-argument Populate(dep) after Declare; MakeAvailable would run |
| 14 | # DeepGEMM's top-level CMakeLists.txt, which vLLM must not load). |
| 15 | if(DEEPGEMM_SRC_DIR) |
| 16 | # cmake_path(ABSOLUTE_PATH <var> ...) reads the path from <var>; NORMALIZE is a |
| 17 | # flag (no trailing path argument). Resolve relative paths against vLLM root. |
| 18 | set(_deepgemm_user_src "${DEEPGEMM_SRC_DIR}") |
| 19 | cmake_path(ABSOLUTE_PATH _deepgemm_user_src |
| 20 | BASE_DIRECTORY "${CMAKE_SOURCE_DIR}" |
| 21 | NORMALIZE) |
| 22 | set(DEEPGEMM_SRC_DIR "${_deepgemm_user_src}") |
| 23 | if(NOT IS_DIRECTORY "${DEEPGEMM_SRC_DIR}") |
| 24 | message(FATAL_ERROR |
| 25 | "DEEPGEMM_SRC_DIR is not an existing directory: '${DEEPGEMM_SRC_DIR}'") |
| 26 | endif() |
| 27 | set(deepgemm_SOURCE_DIR "${DEEPGEMM_SRC_DIR}") |
| 28 | message(STATUS "DeepGEMM using local DEEPGEMM_SRC_DIR: ${deepgemm_SOURCE_DIR}") |
| 29 | else() |
| 30 | # Keep in sync with tools/install_deepgemm.sh |
| 31 | set(_DEEPGEMM_UPSTREAM_REPO "https://github.com/vllm-project/DeepGEMM.git") |
| 32 | # Pinned to the fork's dev branch: upstream 2.8.0 plus the SM120 |
| 33 | # port, the SM90 paged-MQA kv_block=32/next_n=4 port, configurable SwiGLU |
| 34 | # alpha/beta, and SiTU for FP8/FP4 Mega MoE. Also includes the CUDA 12.x |
| 35 | # layout header fix from vllm-project/DeepGEMM#12. |
| 36 | set(_DEEPGEMM_UPSTREAM_TAG "e1f418c2a4f20818221f6b0e578b4c2f634d4c3f") |
| 37 | |
| 38 | set(_deepgemm_fc_root "${FETCHCONTENT_BASE_DIR}") |
| 39 | if(NOT _deepgemm_fc_root) |
| 40 | set(_deepgemm_fc_root "${CMAKE_BINARY_DIR}/_deps") |
| 41 | endif() |
| 42 | set(_deepgemm_src "${_deepgemm_fc_root}/deepgemm-src") |
| 43 | set(_deepgemm_bin "${_deepgemm_fc_root}/deepgemm-build") |
| 44 | set(_deepgemm_sub "${_deepgemm_fc_root}/deepgemm-subbuild") |
| 45 | |
| 46 | if(EXISTS "${_deepgemm_src}/csrc/python_api.cpp") |
| 47 | set(deepgemm_SOURCE_DIR "${_deepgemm_src}") |
| 48 | set(deepgemm_BINARY_DIR "${_deepgemm_bin}") |
| 49 | else() |
| 50 | FetchContent_Populate( |
| 51 | deepgemm |
| 52 | SUBBUILD_DIR "${_deepgemm_sub}" |
| 53 | SOURCE_DIR "${_deepgemm_src}" |
| 54 | BINARY_DIR "${_deepgemm_bin}" |
| 55 | GIT_REPOSITORY "${_DEEPGEMM_UPSTREAM_REPO}" |
| 56 | GIT_TAG "${_DEEPGEMM_UPSTREAM_TAG}" |
| 57 | GIT_SUBMODULES "third-party/cutlass" "third-party/deep_jit" |
| 58 | GIT_PROGRESS TRUE |
| 59 | ) |
| 60 | endif() |
| 61 | message(STATUS "DeepGEMM is available at ${deepgemm_SOURCE_DIR}") |
| 62 | endif() |
| 63 | |
| 64 | # DeepGEMM requires CUDA 12.3+ for SM90, 12.9+ for SM100 (official upstream), |
| 65 | # and 12.8+ for SM120 / SM12x. CUDA 13+ can use the family-specific SM12x |
| 66 | # arch; CUDA 12.x builds the arch-specific SM120/SM121 variants. |
| 67 | set(DEEPGEMM_SUPPORT_ARCHS) |
| 68 | if(${CMAKE_CUDA_COMPILER_VERSION} VERSION_GREATER_EQUAL 12.3) |
| 69 | list(APPEND DEEPGEMM_SUPPORT_ARCHS "9.0a") |
| 70 | endif() |
| 71 | if(${CMAKE_CUDA_COMPILER_VERSION} VERSION_GREATER_EQUAL 12.8) |
| 72 | if(${CMAKE_CUDA_COMPILER_VERSION} VERSION_GREATER_EQUAL 12.9) |
| 73 | list(APPEND DEEPGEMM_SUPPORT_ARCHS "10.0f") |
| 74 | if(${CMAKE_CUDA_COMPILER_VERSION} VERSION_GREATER_EQUAL 13.4) |
| 75 | list(APPEND DEEPGEMM_SUPPORT_ARCHS "10.7f") |
| 76 | endif() |
| 77 | else() |
| 78 | list(APPEND DEEPGEMM_SUPPORT_ARCHS "10.0a") |
| 79 | endif() |
| 80 | if(${CMAKE_CUDA_COMPILER_VERSION} VERSION_GREATER_EQUAL 13.0) |
| 81 | list(APPEND DEEPGEMM_SUPPORT_ARCHS "12.0f") |
| 82 | else() |
| 83 | list(APPEND DEEPGEMM_SUPPORT_ARCHS "12.0a" "12.1a") |
| 84 | endif() |
| 85 | endif() |
| 86 | |
| 87 | cuda_archs_loose_intersection(DEEPGEMM_ARCHS |
| 88 | "${DEEPGEMM_SUPPORT_ARCHS}" "${CUDA_ARCHS}") |
| 89 | |
| 90 | if(DEEPGEMM_ARCHS) |
| 91 | message(STATUS "DeepGEMM CUDA architectures: ${DEEPGEMM_ARCHS}") |
| 92 | |
| 93 | # |
| 94 | # DeepGEMM integration notes |
| 95 | # -------------------------- |
| 96 | # We vendor DeepGEMM into vllm/third_party/deep_gemm/ and bundle a |
| 97 | # `_C.cpython-X.Y-*.so` for every CPython in `requires-python`. The |
| 98 | # per-Python build is delegated to tools/build_deepgemm_C.py. |
| 99 | # |
| 100 | # Why per-Python: DeepGEMM's binding uses PYBIND11_MODULE, which links |
| 101 | # private CPython symbols — a single `_C.abi3.so` is not viable today |
| 102 | # (see #41476 / #41512 for the failed attempt). |
| 103 | # |
| 104 | # TODOs (tracked in vllm-project/vllm#42431): |
| 105 | # - Replace DeepGEMM's pybind11 binding with a TORCH_LIBRARY + shim |
| 106 | # binding (cf. vllm-flash-attention/csrc/common/pytorch_shim.h) to |
| 107 | # collapse to one `_C.abi3.so`. Needs either an upstream change or |
| 108 | # a maintained binding fork in vLLM. |
| 109 | # - AOT-compile DeepGEMM's CUDA kernels instead of runtime JIT to drop |
| 110 | # the vendored CUTLASS/CCCL headers and the CUDA-toolkit-at-runtime |
| 111 | # requirement. |
| 112 | # |
| 113 | |
| 114 | # DEEPGEMM_PYTHON_INTERPRETERS: ":"-separated target Python paths. |
| 115 | # Empty/unset → fall back to the build interpreter (editable installs). |
| 116 | # (Empty-but-set env vars test as DEFINED in cmake — treat as unset.) |
| 117 | if(NOT "$ENV{DEEPGEMM_PYTHON_INTERPRETERS}" STREQUAL "") |
| 118 | string(REPLACE ":" ";" _dg_pythons "$ENV{DEEPGEMM_PYTHON_INTERPRETERS}") |
| 119 | else() |
| 120 | set(_dg_pythons "${Python_EXECUTABLE}") |
| 121 | endif() |
| 122 | message(STATUS "DeepGEMM _C will be built for: ${_dg_pythons}") |
| 123 | |
| 124 | # add_custom_command does no implicit header scanning; glob explicitly so |
| 125 | # header-only edits in DeepGEMM/cutlass/deep_jit re-trigger the rebuild. |
| 126 | file(GLOB_RECURSE _dg_headers |
| 127 | "${deepgemm_SOURCE_DIR}/csrc/*.h" |
| 128 | "${deepgemm_SOURCE_DIR}/csrc/*.hpp" |
| 129 | "${deepgemm_SOURCE_DIR}/deep_gemm/include/*.h" |
| 130 | "${deepgemm_SOURCE_DIR}/deep_gemm/include/*.hpp" |
| 131 | "${deepgemm_SOURCE_DIR}/deep_gemm/include/*.cuh" |
| 132 | "${deepgemm_SOURCE_DIR}/third-party/deep_jit/include/*.h" |
| 133 | "${deepgemm_SOURCE_DIR}/third-party/deep_jit/include/*.hpp") |
| 134 | |
| 135 | set(_dg_markers) |
| 136 | set(_dg_seen_soabis) |
| 137 | foreach(_pybin IN LISTS _dg_pythons) |
| 138 | execute_process( |
| 139 | COMMAND "${_pybin}" -c |
| 140 | "import sysconfig; print(sysconfig.get_config_var('SOABI'))" |
| 141 | OUTPUT_VARIABLE _dg_soabi |
| 142 | OUTPUT_STRIP_TRAILING_WHITESPACE |
| 143 | COMMAND_ERROR_IS_FATAL ANY) |
| 144 | # Dedup interpreters that resolve to the same CPython. |
| 145 | if(_dg_soabi IN_LIST _dg_seen_soabis) |
| 146 | continue() |
| 147 | endif() |
| 148 | list(APPEND _dg_seen_soabis "${_dg_soabi}") |
| 149 | set(_dg_dir "${CMAKE_CURRENT_BINARY_DIR}/deepgemm_C_${_dg_soabi}") |
| 150 | set(_dg_marker "${_dg_dir}/.built") |
| 151 | add_custom_command( |
| 152 | OUTPUT "${_dg_marker}" |
| 153 | COMMAND "${Python_EXECUTABLE}" |
| 154 | "${CMAKE_SOURCE_DIR}/tools/build_deepgemm_C.py" |
| 155 | "${deepgemm_SOURCE_DIR}" "${_dg_dir}" "${_pybin}" |
| 156 | COMMAND "${CMAKE_COMMAND}" -E touch "${_dg_marker}" |
| 157 | DEPENDS "${CMAKE_SOURCE_DIR}/tools/build_deepgemm_C.py" |
| 158 | "${deepgemm_SOURCE_DIR}/csrc/python_api.cpp" |
| 159 | ${_dg_headers} |
| 160 | COMMENT "Building DeepGEMM _C for ${_pybin}" |
| 161 | VERBATIM) |
| 162 | list(APPEND _dg_markers "${_dg_marker}") |
| 163 | install(DIRECTORY "${_dg_dir}/" |
| 164 | DESTINATION vllm/third_party/deep_gemm |
| 165 | COMPONENT _deep_gemm_C |
| 166 | FILES_MATCHING PATTERN "_C.cpython-*.so") |
| 167 | endforeach() |
| 168 | add_custom_target(_deep_gemm_C ALL DEPENDS ${_dg_markers}) |
| 169 | |
| 170 | # |
| 171 | # Vendor DeepGEMM Python package files |
| 172 | # |
| 173 | install(FILES |
| 174 | "${deepgemm_SOURCE_DIR}/deep_gemm/__init__.py" |
| 175 | DESTINATION vllm/third_party/deep_gemm |
| 176 | COMPONENT _deep_gemm_C) |
| 177 | |
| 178 | install(DIRECTORY "${deepgemm_SOURCE_DIR}/deep_gemm/utils/" |
| 179 | DESTINATION vllm/third_party/deep_gemm/utils |
| 180 | COMPONENT _deep_gemm_C |
| 181 | FILES_MATCHING PATTERN "*.py") |
| 182 | |
| 183 | install(DIRECTORY "${deepgemm_SOURCE_DIR}/deep_gemm/testing/" |
| 184 | DESTINATION vllm/third_party/deep_gemm/testing |
| 185 | COMPONENT _deep_gemm_C |
| 186 | FILES_MATCHING PATTERN "*.py") |
| 187 | |
| 188 | install(DIRECTORY "${deepgemm_SOURCE_DIR}/deep_gemm/legacy/" |
| 189 | DESTINATION vllm/third_party/deep_gemm/legacy |
| 190 | COMPONENT _deep_gemm_C |
| 191 | FILES_MATCHING PATTERN "*.py") |
| 192 | |
| 193 | install(DIRECTORY "${deepgemm_SOURCE_DIR}/deep_gemm/mega/" |
| 194 | DESTINATION vllm/third_party/deep_gemm/mega |
| 195 | COMPONENT _deep_gemm_C |
| 196 | FILES_MATCHING PATTERN "*.py") |
| 197 | |
| 198 | # Generate envs.py (normally generated by DeepGEMM's setup.py build step) |
| 199 | file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/deep_gemm_envs.py" |
| 200 | "# Pre-installed environment variables\npersistent_envs = dict()\n") |
| 201 | install(FILES "${CMAKE_CURRENT_BINARY_DIR}/deep_gemm_envs.py" |
| 202 | DESTINATION vllm/third_party/deep_gemm |
| 203 | RENAME envs.py |
| 204 | COMPONENT _deep_gemm_C) |
| 205 | |
| 206 | # |
| 207 | # Install include files needed for JIT compilation at runtime. |
| 208 | # The JIT compiler finds these relative to the package directory. |
| 209 | # |
| 210 | |
| 211 | # DeepGEMM's own CUDA headers |
| 212 | install(DIRECTORY "${deepgemm_SOURCE_DIR}/deep_gemm/include/" |
| 213 | DESTINATION vllm/third_party/deep_gemm/include |
| 214 | COMPONENT _deep_gemm_C) |
| 215 | |
| 216 | # CUTLASS and CuTe headers (vendored for JIT, separate from vLLM's CUTLASS) |
| 217 | install(DIRECTORY "${deepgemm_SOURCE_DIR}/third-party/cutlass/include/" |
| 218 | DESTINATION vllm/third_party/deep_gemm/include |
| 219 | COMPONENT _deep_gemm_C) |
| 220 | |
| 221 | else() |
| 222 | message(STATUS "DeepGEMM will not compile: " |
| 223 | "unsupported CUDA architecture ${CUDA_ARCHS}") |
| 224 | # Create empty target so setup.py doesn't fail on unsupported systems |
| 225 | add_custom_target(_deep_gemm_C) |
| 226 | endif() |