|
| 1 | +# Adding new C++ Dependencies |
| 2 | + |
| 3 | +## Step 1: Make the package available to the build |
| 4 | + |
| 5 | +First, decide if you must install the package in the container or if you |
| 6 | +may defer fetching until the build phase. In general, *prefer to fetch |
| 7 | +packages during the build phase*. You may be required to install |
| 8 | +packages into the container, however, if there is a runtime component |
| 9 | +(e.g. shared objects) that cannot be reasonably distributed with the |
| 10 | +wheel. |
| 11 | + |
| 12 | +### Install in the container |
| 13 | + |
| 14 | +#### Debian Packages via os package manager (e.g. apt, dnf) |
| 15 | + |
| 16 | +Add your package to one of the existing shell scripts used by the docker build |
| 17 | +under [docker/common/][1] Find the location where the package manager is |
| 18 | +invoked, and add the name of your package there. |
| 19 | + |
| 20 | +NOTE: Internal compliance tooling will automatically detect the |
| 21 | +installation of this package and fetch sources using the source-fetching |
| 22 | +facilities of the OS package manager. |
| 23 | + |
| 24 | +[1]: https://github.com/NVIDIA/TensorRT-LLM/tree/main/docker/common. |
| 25 | + |
| 26 | +#### Python Packages via pip |
| 27 | + |
| 28 | +If it makes sense, add your package to one of the existing shell scripts used by |
| 29 | +the docker build under [docker/common/][2]. Grep for "pip3 install" to see |
| 30 | +existing invocations. If none of the existing shell scripts make sense, add a |
| 31 | +new shell script to install your package and then invoke that script in |
| 32 | +Dockerfile.multi. |
| 33 | + |
| 34 | +NOTE: If the new python package you are adding has a compiled component (e.g. a |
| 35 | +python extension module), you must coordinate with the [Security Team][20] to |
| 36 | +ensure that the source for this component is managed correctly. |
| 37 | + |
| 38 | +[2]: https://github.com/NVIDIA/TensorRT-LLM/tree/main/docker/common |
| 39 | + |
| 40 | +#### Tarball packages via HTTP/FTP |
| 41 | + |
| 42 | +Invoke `wget` in a shell script which is called from the docker build file. |
| 43 | +When it makes sense, please prefer to extend an existing script in |
| 44 | +[docker/common/][3] rather than creating a new one. If you are downloading a |
| 45 | +binary package, you must also download the source package that produced that |
| 46 | +binary. |
| 47 | + |
| 48 | +Ensure that the source package is copied to /third-party-source and retained |
| 49 | +after all cleanup within the docker image layer. |
| 50 | + |
| 51 | +[3]: https://github.com/NVIDIA/TensorRT-LLM/tree/main/docker/common |
| 52 | + |
| 53 | +### Fetch during the build |
| 54 | + |
| 55 | +#### Python Packages via pip |
| 56 | + |
| 57 | +Add an entry to [requirements-dev.txt][4]. |
| 58 | +The package will be installed by build\_wheel.py during virtual |
| 59 | +environment initialization prior to configuring the build with cmake. |
| 60 | +Include a comment indicating the intended usage of the package. |
| 61 | + |
| 62 | +[4]: https://github.com/NVIDIA/TensorRT-LLM/blob/main/requirements-dev.txt |
| 63 | + |
| 64 | +**Example:** |
| 65 | + |
| 66 | +`requirements-dev.txt`: |
| 67 | + |
| 68 | +``` requirements.txt |
| 69 | +# my-package is needed by <feature> where it is used for <reason> |
| 70 | +my-package==1.2.24 |
| 71 | +``` |
| 72 | + |
| 73 | +#### C/C++ Packages via conan |
| 74 | + |
| 75 | +Add a new entry to [conandata.yml][6] indicating the package version for the |
| 76 | +dependency you are adding. Include a yaml comment indicating the intended usage |
| 77 | +of the package. Then add a new invocation of `self.require()` within the `def |
| 78 | +requirements(self)` method of [conanfile.py], referencing the version you added |
| 79 | +to conandata. |
| 80 | + |
| 81 | +[6]: https://github.com/NVIDIA/TensorRT-LLM/blob/main/cpp/conandata.yml |
| 82 | +[7]: https://github.com/NVIDIA/TensorRT-LLM/blob/main/cpp/conanfile.py |
| 83 | + |
| 84 | +**Example:** |
| 85 | + |
| 86 | +`conandata.yml`: |
| 87 | + |
| 88 | +```.yml |
| 89 | +# my_dependency is needed by <feature> where it is used for <reason> |
| 90 | +my_dependency: 1.2.24+1 |
| 91 | +``` |
| 92 | + |
| 93 | +`conanfile.py`: |
| 94 | + |
| 95 | +```.py |
| 96 | +def requirements(self): |
| 97 | + ... |
| 98 | + my_dependency_version = self.conandata["my_dependency"] |
| 99 | + self.requires(f"my_dependency/{my_dependency_version}") |
| 100 | +``` |
| 101 | + |
| 102 | +#### Source integration via CMake |
| 103 | + |
| 104 | +If you have a package you need to build from source then use CMake |
| 105 | +[FetchContent][8] of [ExternalProject][9] to fetch the package sources and |
| 106 | +integrate it with the build. See the details in the next section. |
| 107 | + |
| 108 | +[8]: https://cmake.org/cmake/help/latest/module/FetchContent.html |
| 109 | +[9]: https://cmake.org/cmake/help/latest/module/ExternalProject.html#id1 |
| 110 | + |
| 111 | +#### git Submodule - Don't Use |
| 112 | + |
| 113 | +Please *avoid use of git-submodule*. If, for some reason, the CMake integrations |
| 114 | +described below don't work and git-submodule is absolutely required, please add |
| 115 | +the submodule under the 3rdparty directory. |
| 116 | + |
| 117 | +**Rationale:** |
| 118 | + |
| 119 | +For a source-code dependency distributed via git, |
| 120 | +FetchContent/ExternalProject and git submodules both ultimately contain |
| 121 | +the same referential information (repository URL, commit sha) and, at |
| 122 | +the end of the day, do the same things. However |
| 123 | +FetchContent/ExternalProject have the following advantages: |
| 124 | + |
| 125 | +1. The git operations happen during the build and are interleaved with the rest |
| 126 | + of the build processing, rather than requiring an additional step managed |
| 127 | + outside of CMake. |
| 128 | + |
| 129 | +2. The fetch, patch, and build steps for the sub project are individually named |
| 130 | + in the build, so any failures are more clearly identified |
| 131 | + |
| 132 | +3. The build state is better contained within the build tree where it is less |
| 133 | + prone to interference by development actions. |
| 134 | + |
| 135 | +4. For source code that is modified, FetchContent/ExternalProject can manage |
| 136 | + application of the patches making it clear what modifications are present. |
| 137 | + |
| 138 | +5. The build does not have to make assumptions about the version control |
| 139 | + configuration of the source tree, which may be incorrect due to the fact |
| 140 | + that it is bind-mounted in a container. For example, `git submodule --init` |
| 141 | + inside a container will corrupt the git configuration outside the container |
| 142 | + if the source tree is a git worktree. |
| 143 | + |
| 144 | +6. External project references and their patches are collected under a more |
| 145 | + narrow surface, rather than being spread across different tools. This makes |
| 146 | + it easier to track third part dependencies as well as to recognize them |
| 147 | + during code review. |
| 148 | + |
| 149 | +**Example:** |
| 150 | + |
| 151 | +``` bash |
| 152 | +git submodule add https://github.com/some-organization/some-project.git 3rdparty/some-project |
| 153 | +``` |
| 154 | + |
| 155 | + |
| 156 | +## Step 2: Integrate the package |
| 157 | + |
| 158 | +There are many ways to integrate a package with the build through cmake. |
| 159 | + |
| 160 | +### find\_package for binary packages |
| 161 | + |
| 162 | +For binary packages (os-provided via apt-get or yum, or conan-provided), prefer |
| 163 | +the use of [find\_package][10] to integrate the package into the build. Conan |
| 164 | +will generate a find-script for packages that don't already come with a Cmake |
| 165 | +configuration file and the conan-specific logic is provided through the |
| 166 | +conan-generated toolchain already used in our build. |
| 167 | + |
| 168 | +For any packages which do not have provided find modules (either built-in, or |
| 169 | +available from conan), please implement one in [cpp/cmake/modules][11]. Please |
| 170 | +do not add "direct" invocations of `find_library` / `add_library` / `find_file` |
| 171 | +/ `find_path` outside of a find module the package. |
| 172 | + |
| 173 | +Please add invocations of `find_package` directly in the root Cmake file. |
| 174 | + |
| 175 | +[10]: https://cmake.org/cmake/help/latest/command/find_package.html |
| 176 | +[11]: https://github.com/NVIDIA/TensorRT-LLM/tree/main//cpp/cmake/modules?ref_type=heads |
| 177 | + |
| 178 | +**Example:** |
| 179 | + |
| 180 | +cpp/CMakeLists.txt |
| 181 | + |
| 182 | +```.cmake |
| 183 | +find_package(NIXL) |
| 184 | +``` |
| 185 | + |
| 186 | +cpp/cmake/modules/FindNIXL.cmake |
| 187 | +```.cmake |
| 188 | +... |
| 189 | + find_library( |
| 190 | +NIXL_LIBRARY nixl |
| 191 | +HINTS |
| 192 | + ${NIXL_ROOT}/lib/${NIXL_TARGET_ARCH} |
| 193 | + ${NIXL_ROOT}/lib64) |
| 194 | +... |
| 195 | + add_library(NIXL::nixl SHARED IMPORTED) |
| 196 | + set_target_properties( |
| 197 | + NIXL::nixl |
| 198 | + PROPERTIES |
| 199 | + INTERFACE_INCLUDE_DIRECTORIES ${NIXL_INCLUDE_DIR} |
| 200 | + IMPORTED_LOCATION ${NIXL_LIBRARY} |
| 201 | + ${NIXL_BUILD_LIBRARY} |
| 202 | +${SERDES_LIBRARY} |
| 203 | +) |
| 204 | +``` |
| 205 | + |
| 206 | +### FetchContent for source packages with compatible cmake builds |
| 207 | + |
| 208 | +For source packages that have a compatible cmake (e.g. where add\_subdirectory |
| 209 | +will work correctly), please use [FetchContent][12] to download the sources and |
| 210 | +integrate them into the build. Please add new invocations of |
| 211 | +FetchContent\_Declare in [3rdparty/CMakeLists.txt][13]. Add new invocations for |
| 212 | +FetchContent\_MakeAvailable wherever it makes sense in the build where you are |
| 213 | +integrating it, but prefer the root listfile for that build |
| 214 | +([cpp/CMakeLists.txt][14] for the primary build). |
| 215 | + |
| 216 | +CODEOWNERS for this file will consist of PLC reviewers who verify that |
| 217 | +third-party license compliance strategies are being followed. |
| 218 | + |
| 219 | +If the dependency you are adding has modified sources, please do the |
| 220 | +following: |
| 221 | + |
| 222 | +1. Create a repository on gitlab to mirror the upstream source files. If the |
| 223 | + upstream is also in git, please use the gitlab "mirror" repository option. |
| 224 | + Otherwise, please use branches/tags to help identify the upstream source |
| 225 | + versions. |
| 226 | + |
| 227 | +2. Track nvidia changes in a branch. Use a linear sequence (trunk-based) |
| 228 | + development strategy. Use meaningful, concise commit message subjects and |
| 229 | + comprehensive commit messages for the changes applied. |
| 230 | + |
| 231 | +3. Use `git format-patch \<upstream-commit\>\...HEAD` to create a list of |
| 232 | + patches, one file per commit, |
| 233 | + |
| 234 | +4. Add your patches under 3rdparty/patches/\<package-name\> |
| 235 | + |
| 236 | +5. Use CMake's [PATCH\_COMMAND][15] option to apply the patches during the |
| 237 | + build process. |
| 238 | + |
| 239 | +[12]: https://cmake.org/cmake/help/latest/module/FetchContent.html |
| 240 | +[13]: https://github.com/NVIDIA/TensorRT-LLM/tree/main//3rdparty/CMakeLists.txt?ref_type=heads |
| 241 | +[14]: https://github.com/NVIDIA/TensorRT-LLM/blob/main/cpp/CMakeLists.txt |
| 242 | +[15]: https://cmake.org/cmake/help/latest/module/ExternalProject.html#patch-step-options |
| 243 | + |
| 244 | +**Example:** |
| 245 | + |
| 246 | +3rdparty/CMakeLists.txt |
| 247 | + |
| 248 | +```.cmake |
| 249 | +FetchContent_Declare( |
| 250 | + pybind11 |
| 251 | + GIT_REPOSITORY https://github.com/pybind/pybind11.git |
| 252 | + GIT_TAG f99ffd7e03001810a3e722bf48ad1a9e08415d7d |
| 253 | +) |
| 254 | +``` |
| 255 | + |
| 256 | +cpp/CmakeLists.txt |
| 257 | + |
| 258 | +```.cmake |
| 259 | +FetchContent_MakeAvailable(pybind11) |
| 260 | +``` |
| 261 | + |
| 262 | +### ExternalProject |
| 263 | + |
| 264 | +If the package you are adding doesn't support FetchContent (e.g. if it's not |
| 265 | +built by CMake or if its CMake configuration doesn't nest well), then please use |
| 266 | +[ExternalProject][16]. In this case that project's build system will be invoked |
| 267 | +as a build step of the primary build system. Note that, unless both the primary |
| 268 | +and child build systems are GNU Make, they will not share a job server and will |
| 269 | +independently schedule parallelism (e.g. -j flags). |
| 270 | + |
| 271 | +[16]: https://cmake.org/cmake/help/latest/module/ExternalProject.html#id1 |
| 272 | + |
| 273 | +**Example:** |
| 274 | + |
| 275 | +```.cmake |
| 276 | +ExternalProject_Add( |
| 277 | + nvshmem_project |
| 278 | + URL https://developer.download.nvidia.com/compute/nvshmem/redist/libnvshmem/linux-x86_64/libnvshmem-linux-x86_64-3.2.5_cuda12-archive.tar.xz |
| 279 | + URL_HASH ${NVSHMEM_URL_HASH} |
| 280 | + PATCH_COMMAND patch -p1 --forward --batch -i |
| 281 | + ${DEEP_EP_SOURCE_DIR}/third-party/nvshmem.patch |
| 282 | + ... |
| 283 | + CMAKE_CACHE_ARGS |
| 284 | + -DCMAKE_C_COMPILER:STRING=${CMAKE_C_COMPILER} |
| 285 | + -DCMAKE_C_COMPILER_LAUNCHER:STRING=${CMAKE_C_COMPILER_LAUNCHER} |
| 286 | + ... |
| 287 | + BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/nvshmem-build |
| 288 | + BUILD_BYPRODUCTS |
| 289 | + ${CMAKE_CURRENT_BINARY_DIR}/nvshmem-build/src/lib/libnvshmem.a |
| 290 | +) |
| 291 | +add_library(nvshmem_project::nvshmem STATIC IMPORTED) |
| 292 | +add_dependencies(nvshmem_project::nvshmem nvshmem_project) |
| 293 | +... |
| 294 | +set_target_properties( |
| 295 | + nvshmem_project::nvshmem |
| 296 | + PROPERTIES IMPORTED_LOCATION |
| 297 | + ${CMAKE_CURRENT_BINARY_DIR}/nvshmem-build/src/lib/libnvshmem.a |
| 298 | + INTERFACE_INCLUDE_DIRECTORIES |
| 299 | + ${CMAKE_CURRENT_BINARY_DIR}/nvshmem-build/src/include) |
| 300 | +``` |
| 301 | + |
| 302 | +## Step 3: Update third-party attributions and license tracking |
| 303 | + |
| 304 | +1. Clone the dependency source code to an NVIDIA-controlled repository. The |
| 305 | + consumed commit must be stored as-received (ensure the consumed commit-sha |
| 306 | + is present in the clone). For sources available via git (or git-adaptable) |
| 307 | + SCM, mirror the repository in the [oss-components][18] gitlab project. |
| 308 | + |
| 309 | +2. Collect the license text of the consumed commit |
| 310 | + |
| 311 | +3. If the license does not include a copyright notice, collect any copyright |
| 312 | + notices that were originally published with the dependency (these may be on |
| 313 | + individual file levels, in metadata files, or in packaging control files). |
| 314 | + |
| 315 | +4. Add the license and copyright notices to the ATTRIBUTIONS-CPP-x86\_64.md and |
| 316 | + ATTRIBUTIONS-CPP-aarch64.md files |
| 317 | + |
| 318 | +CODEOWNERS for ATTRIBUTIONS-CPP-\*.md are members of the PLC team and modifying |
| 319 | +this file will signal to reviewers that they are verifying that your change |
| 320 | +follows the process in this document. |
| 321 | + |
| 322 | +[18]: https://gitlab.com/nvidia/tensorrt-llm/oss-components |
| 323 | + |
| 324 | +## Step 4: File a JIRA ticket if you need help from the Security team |
| 325 | + |
| 326 | +This step is optional, if you need assistance from the Security team. |
| 327 | + |
| 328 | +File a Jira ticket using the issue template [TRTLLM-8383][19] to request |
| 329 | +inclusion of this new dependency and initiate license and/or security review. |
| 330 | +The Security Team will triage and assign the ticket. |
| 331 | + |
| 332 | +If you don’t have access to the JIRA project, please email the [Security |
| 333 | +Team][20]. |
| 334 | + |
| 335 | + |
| 336 | +[19]: https://jirasw.nvidia.com/browse/TRTLLM-8383 |
| 337 | + |
0 commit comments