main
cmake 226 lines 8.94 KB
Raw
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()