diff --git a/.github/workflows/package_c.yml b/.github/workflows/package_c.yml index fc360b53f4..18ff281372 100644 --- a/.github/workflows/package_c.yml +++ b/.github/workflows/package_c.yml @@ -21,8 +21,8 @@ jobs: strategy: matrix: include: - - tensorflow_build_version: "2.20" - tensorflow_version: "==2.20.*" + - package_c_runtime_dependency_pre_exclude_regexes: 'libtorch.*\.so.*;libc10.*\.so.*;libshm\.so.*;libkineto\.so.*;libbackend_with_compiler\.so.*;libcaffe2.*\.so.*;libcuda.*\.so.*;libcudart.*\.so.*;libcublas.*\.so.*;libcufft.*\.so.*;libcufile.*\.so.*;libcupti.*\.so.*;libcurand.*\.so.*;libcusolver.*\.so.*;libcusparse.*\.so.*;libnv.*\.so.*;libcudnn.*\.so.*;libnccl.*\.so.*' + package_c_runtime_dependency_post_exclude_regexes: '.*/libtorch.*\.so.*;.*/libc10.*\.so.*;.*/libshm\.so.*;.*/libkineto\.so.*;.*/libbackend_with_compiler\.so.*;.*/libcaffe2.*\.so.*;.*/libcuda.*\.so.*;.*/libcudart.*\.so.*;.*/libcublas.*\.so.*;.*/libcufft.*\.so.*;.*/libcufile.*\.so.*;.*/libcupti.*\.so.*;.*/libcurand.*\.so.*;.*/libcusolver.*\.so.*;.*/libcusparse.*\.so.*;.*/libnv.*\.so.*;.*/libcudnn.*\.so.*;.*/libnccl.*\.so.*' filename: libdeepmd_c.tar.gz steps: - name: Free Disk Space (Ubuntu) @@ -41,8 +41,30 @@ jobs: - name: Package C library run: ./source/install/docker_package_c.sh env: - TENSORFLOW_VERSION: ${{ matrix.tensorflow_version }} - TENSORFLOW_BUILD_VERSION: ${{ matrix.tensorflow_build_version }} + ENABLE_PYTORCH: "TRUE" + PACKAGE_C_RUNTIME_DEPENDENCY_PRE_EXCLUDE_REGEXES: ${{ matrix.package_c_runtime_dependency_pre_exclude_regexes }} + PACKAGE_C_RUNTIME_DEPENDENCY_POST_EXCLUDE_REGEXES: ${{ matrix.package_c_runtime_dependency_post_exclude_regexes }} + - name: Check C library package contents + run: | + tar -tzf libdeepmd_c.tar.gz | tee libdeepmd_c.contents + grep -q 'libdeepmd_c/lib/libdeepmd_backend_tf.so' libdeepmd_c.contents + grep -q 'libdeepmd_c/lib/libdeepmd_backend_pt.so' libdeepmd_c.contents + grep -q 'libdeepmd_c/lib/libdeepmd_backend_ptexpt.so' libdeepmd_c.contents + grep -q 'libdeepmd_c/lib/libdeepmd_op_pt.so' libdeepmd_c.contents + grep -q 'libdeepmd_c/download_libtorch.sh' libdeepmd_c.contents + if grep -E 'libdeepmd_c/lib/(libtorch|libc10|libshm|libkineto|libbackend_with_compiler|libcaffe2|libcuda|libcudart|libcublas|libcufft|libcufile|libcupti|libcurand|libcusolver|libcusparse|libnv|libcudnn|libnccl)' libdeepmd_c.contents; then + echo "PyTorch/CUDA runtime libraries must not be bundled in libdeepmd_c.tar.gz" + exit 1 + fi + - name: Note external PyTorch runtime + run: | + libtorch_url=$(tar -xOf libdeepmd_c.tar.gz libdeepmd_c/download_libtorch.sh | sed -n 's/^LIBTORCH_DOWNLOAD_URL="\(.*\)"$/\1/p') + { + echo "PyTorch support was built into the C package, but PyTorch runtime libraries are not bundled." + echo "Download matching libtorch from: ${libtorch_url}" + echo "Or run ./download_libtorch.sh after extracting libdeepmd_c.tar.gz." + echo "The PyTorch version must match the build version exactly; the CUDA variant may be omitted only when compatible." + } >> "$GITHUB_STEP_SUMMARY" - run: cp libdeepmd_c.tar.gz ${{ matrix.filename }} if: matrix.filename != 'libdeepmd_c.tar.gz' # for download and debug @@ -53,6 +75,8 @@ jobs: path: ${{ matrix.filename }} - name: Test C library run: ./source/install/docker_test_package_c.sh + env: + CHECK_PYTORCH_RUNTIME: "1" - name: Release uses: softprops/action-gh-release@v3 if: startsWith(github.ref, 'refs/tags/') diff --git a/doc/install/install-from-c-library.md b/doc/install/install-from-c-library.md index 13498fc886..836ee1a712 100644 --- a/doc/install/install-from-c-library.md +++ b/doc/install/install-from-c-library.md @@ -1,7 +1,7 @@ -# Install from pre-compiled C library {{ tensorflow_icon }} {{ jax_icon }} +# Install from pre-compiled C library {{ tensorflow_icon }} {{ pytorch_icon }} {{ jax_icon }} :::{note} -**Supported backends**: TensorFlow {{ tensorflow_icon }}, JAX {{ jax_icon }} +**Supported backends**: TensorFlow {{ tensorflow_icon }}, PyTorch {{ pytorch_icon }}, JAX {{ jax_icon }} ::: DeePMD-kit provides pre-compiled C library package (`libdeepmd_c.tar.gz`) in each [release](https://github.com/deepmodeling/deepmd-kit/releases). It can be used to build the [LAMMPS plugin](./install-lammps.md) and the [i-PI driver](./install-ipi.md), as well as many [third-party software packages](../third-party/out-of-deepmd-kit.md), without building TensorFlow and DeePMD-kit on one's own. @@ -12,7 +12,17 @@ wget https://github.com/deepmodeling/deepmd-kit/releases/latest/download/libdeep tar xzf libdeepmd_c.tar.gz ``` -The library is built in Linux (GLIBC 2.17) with CUDA 12.2 (`libdeepmd_c.tar.gz`). It's noted that this package does not contain CUDA Toolkit and cuDNN, so one needs to download them from the NVIDIA website. +The library is built in Linux (GLIBC 2.28) with CUDA 12.9 (`libdeepmd_c.tar.gz`). It's noted that this package does not contain CUDA Toolkit, cuDNN, or PyTorch runtime libraries. +To use the PyTorch C/C++ backend on Linux, install a libtorch runtime that exactly matches the PyTorch version used to build the package. +The PyTorch version must match exactly, while the CUDA variant may be omitted only when the target runtime is compatible. +Make the libtorch `lib` directory discoverable by the dynamic linker, for example by adding it to `LD_LIBRARY_PATH`. +The C library package includes `download_libtorch.sh`, which downloads and unpacks the matching libtorch runtime and writes `libtorch_env.sh`: + +```sh +cd libdeepmd_c +./download_libtorch.sh +. ./libtorch_env.sh +``` ## Use Pre-compiled C Library to build the LAMMPS plugin and i-PI driver diff --git a/source/api_c/CMakeLists.txt b/source/api_c/CMakeLists.txt index 03ca851c73..b11eee41a9 100644 --- a/source/api_c/CMakeLists.txt +++ b/source/api_c/CMakeLists.txt @@ -31,10 +31,38 @@ endif(BUILD_PY_IF) if(PACKAGE_C) message(STATUS "Packaging C API library") + set(PACKAGE_C_RUNTIME_DEPENDENCY_PRE_EXCLUDE_REGEXES + "" + CACHE STRING + "Additional file(GET_RUNTIME_DEPENDENCIES) pre-exclude regexes") + set(PACKAGE_C_RUNTIME_DEPENDENCY_POST_EXCLUDE_REGEXES + "" + CACHE STRING + "Additional file(GET_RUNTIME_DEPENDENCIES) post-exclude regexes") + set(PACKAGE_C_RUNTIME_DEPENDENCY_PRE_EXCLUDE_REGEXES_DEFAULT + "libgcc_s\\.so.*" + "libstdc\\+\\+\\.so.*" + "libm\\.so.*" + "libdl\\.so.*" + "librt\\.so.*" + "libc\\.so.*" + "libpthread\\.so.*" + "ld-.*\\.so.*" + "libgomp\\.so.*") + set(PACKAGE_C_RUNTIME_DEPENDENCY_PRE_EXCLUDE_REGEXES_ALL + ${PACKAGE_C_RUNTIME_DEPENDENCY_PRE_EXCLUDE_REGEXES_DEFAULT} + ${PACKAGE_C_RUNTIME_DEPENDENCY_PRE_EXCLUDE_REGEXES}) get_property(DEEPMD_BACKEND_PLUGIN_TARGETS GLOBAL PROPERTY DEEPMD_BACKEND_PLUGIN_TARGETS) - set(PACKAGE_C_RUNTIME_LIBRARIES "$" - "$") + set(PACKAGE_C_RUNTIME_LIBRARIES "$") + if(TARGET ${LIB_DEEPMD_OP}) + list(APPEND PACKAGE_C_RUNTIME_LIBRARIES "$") + endif() + foreach(_target deepmd_op_pt deepmd_op_pd) + if(TARGET ${_target}) + list(APPEND PACKAGE_C_RUNTIME_LIBRARIES "$") + endif() + endforeach() foreach(_target ${DEEPMD_BACKEND_PLUGIN_TARGETS}) list(APPEND PACKAGE_C_RUNTIME_LIBRARIES "$") endforeach() @@ -42,24 +70,22 @@ if(PACKAGE_C) "${PACKAGE_C_RUNTIME_LIBRARIES}") # follow pypa/auditwheel convention install(CODE "set(_dp_runtime_libraries ${PACKAGE_C_RUNTIME_LIBRARIES_CODE})") + install( + CODE "set(_dp_package_c_lib_dir [==[${CMAKE_BINARY_DIR}/libdeepmd_c/lib]==]) +set(_dp_runtime_pre_exclude_regexes [==[${PACKAGE_C_RUNTIME_DEPENDENCY_PRE_EXCLUDE_REGEXES_ALL}]==]) +set(_dp_runtime_post_exclude_regexes [==[${PACKAGE_C_RUNTIME_DEPENDENCY_POST_EXCLUDE_REGEXES}]==])" + ) install( CODE [[ file(GET_RUNTIME_DEPENDENCIES LIBRARIES ${_dp_runtime_libraries} RESOLVED_DEPENDENCIES_VAR _r_deps - PRE_EXCLUDE_REGEXES "libgcc_s\\.so.*" - "libstdc\\+\\+\\.so.*" - "libm\\.so.*" - "libdl\\.so.*" - "librt\\.so.*" - "libc\\.so.*" - "libpthread\\.so.*" - "ld-.*\\.so.*" - "libgomp\\.so.*" + PRE_EXCLUDE_REGEXES ${_dp_runtime_pre_exclude_regexes} + POST_EXCLUDE_REGEXES ${_dp_runtime_post_exclude_regexes} ) message(STATUS "Runtime dependencies: ${_r_deps}") foreach(_file ${_r_deps}) - file(INSTALL ${_file} DESTINATION libdeepmd_c/lib + file(INSTALL ${_file} DESTINATION "${_dp_package_c_lib_dir}" FOLLOW_SYMLINK_CHAIN ) endforeach() @@ -67,8 +93,16 @@ if(PACKAGE_C) install(FILES ${INC_SRC} DESTINATION ${CMAKE_BINARY_DIR}/libdeepmd_c/include/deepmd) install(TARGETS ${libname} DESTINATION ${CMAKE_BINARY_DIR}/libdeepmd_c/lib) - install(TARGETS ${LIB_DEEPMD_OP} - DESTINATION ${CMAKE_BINARY_DIR}/libdeepmd_c/lib) + if(TARGET ${LIB_DEEPMD_OP}) + install(TARGETS ${LIB_DEEPMD_OP} + DESTINATION ${CMAKE_BINARY_DIR}/libdeepmd_c/lib) + endif() + foreach(_target deepmd_op_pt deepmd_op_pd) + if(TARGET ${_target}) + install(TARGETS ${_target} + DESTINATION ${CMAKE_BINARY_DIR}/libdeepmd_c/lib) + endif() + endforeach() foreach(_target ${DEEPMD_BACKEND_PLUGIN_TARGETS}) install(TARGETS ${_target} DESTINATION ${CMAKE_BINARY_DIR}/libdeepmd_c/lib) endforeach() diff --git a/source/install/docker_package_c.sh b/source/install/docker_package_c.sh index 3846daf93b..a13fe15a19 100755 --- a/source/install/docker_package_c.sh +++ b/source/install/docker_package_c.sh @@ -1,12 +1,39 @@ set -e -SCRIPT_PATH=$(dirname $(realpath -s $0)) +SCRIPT_PATH=$(dirname "$(realpath -s "$0")") +MANYLINUX_CUDA_IMAGE=${MANYLINUX_CUDA_IMAGE:-quay.io/manylinux_cuda/manylinux_2_28_x86_64_cuda12_9:latest} +PYTHON_BIN=${PYTHON_BIN:-/opt/python/cp311-cp311/bin/python} +PYTORCH_DEPENDENCY_GROUP=${PYTORCH_DEPENDENCY_GROUP:-pin_pytorch_cpu} +PYTORCH_TORCH_BACKEND=${PYTORCH_TORCH_BACKEND:-cpu} +TENSORFLOW_DEPENDENCY_GROUP=${TENSORFLOW_DEPENDENCY_GROUP:-pin_tensorflow_cpu} -docker run --rm -v ${SCRIPT_PATH}/../..:/root/deepmd-kit -w /root/deepmd-kit \ - tensorflow/build:${TENSORFLOW_BUILD_VERSION:-2.15}-python3.11 \ - /bin/sh -c "pip install \"tensorflow${TENSORFLOW_VERSION}\" cmake \ - && git config --global --add safe.directory /root/deepmd-kit \ - && cd /root/deepmd-kit/source/install \ - && CC=/dt9/usr/bin/gcc \ - CXX=/dt9/usr/bin/g++ \ - /bin/sh package_c.sh" +docker run --rm -v "${SCRIPT_PATH}/../..":/root/deepmd-kit -w /root/deepmd-kit \ + -e CIBUILDWHEEL="${CIBUILDWHEEL:-1}" \ + -e ENABLE_PYTORCH="${ENABLE_PYTORCH:-FALSE}" \ + -e MANYLINUX_CUDA_IMAGE="${MANYLINUX_CUDA_IMAGE}" \ + -e PACKAGE_C_RUNTIME_DEPENDENCY_PRE_EXCLUDE_REGEXES="${PACKAGE_C_RUNTIME_DEPENDENCY_PRE_EXCLUDE_REGEXES:-}" \ + -e PACKAGE_C_RUNTIME_DEPENDENCY_POST_EXCLUDE_REGEXES="${PACKAGE_C_RUNTIME_DEPENDENCY_POST_EXCLUDE_REGEXES:-}" \ + -e PYTORCH_DEPENDENCY_GROUP="${PYTORCH_DEPENDENCY_GROUP}" \ + -e PYTHON_BIN="${PYTHON_BIN}" \ + -e PYTORCH_RUNTIME_DOWNLOAD_URL="${PYTORCH_RUNTIME_DOWNLOAD_URL:-}" \ + -e PYTORCH_TORCH_BACKEND="${PYTORCH_TORCH_BACKEND}" \ + -e TENSORFLOW_DEPENDENCY_GROUP="${TENSORFLOW_DEPENDENCY_GROUP}" \ + "${MANYLINUX_CUDA_IMAGE}" \ + /bin/bash -lc 'set -euo pipefail + export PATH="$(dirname "${PYTHON_BIN}"):${PATH}" + "${PYTHON_BIN}" -m pip install uv + UV_INSTALL_ARGS=( + pip install + --python "${PYTHON_BIN}" + cmake + ninja + patchelf + --group "${TENSORFLOW_DEPENDENCY_GROUP}" + ) + if [ "${ENABLE_PYTORCH}" = "TRUE" ]; then + UV_INSTALL_ARGS+=(--group "${PYTORCH_DEPENDENCY_GROUP}" --torch-backend "${PYTORCH_TORCH_BACKEND}") + fi + source/install/uv_with_retry.sh "${UV_INSTALL_ARGS[@]}" + git config --global --add safe.directory /root/deepmd-kit + cd /root/deepmd-kit/source/install + /bin/sh package_c.sh' diff --git a/source/install/docker_test_package_c.sh b/source/install/docker_test_package_c.sh index ed3b265821..38f94f555f 100755 --- a/source/install/docker_test_package_c.sh +++ b/source/install/docker_test_package_c.sh @@ -1,15 +1,94 @@ -# test libdeepmd_c.tar.gz works with gcc 4.9.0, glibc 2.19 +# test libdeepmd_c.tar.gz works on a manylinux 2.28 runtime set -e -SCRIPT_PATH=$(dirname $(realpath -s $0)) +SCRIPT_PATH=$(dirname "$(realpath -s "$0")") +MANYLINUX_IMAGE=${MANYLINUX_IMAGE:-quay.io/pypa/manylinux_2_28_x86_64:latest} +PYTHON_BIN=${PYTHON_BIN:-/opt/python/cp311-cp311/bin/python} +PYTORCH_DEPENDENCY_GROUP=${PYTORCH_DEPENDENCY_GROUP:-pin_pytorch_cpu} +PYTORCH_TORCH_BACKEND=${PYTORCH_TORCH_BACKEND:-cpu} # assume libdeepmd_c.tar.gz has been created -docker run --rm -v ${SCRIPT_PATH}/../..:/root/deepmd-kit -w /root/deepmd-kit \ - gcc:4.9 \ - /bin/sh -c "tar vxzf libdeepmd_c.tar.gz \ - && cd examples/infer_water \ - && gcc convert_model.c -std=c99 -L ../../libdeepmd_c/lib -I ../../libdeepmd_c/include -Wl,--no-as-needed -ldeepmd_c -Wl,-rpath=../../libdeepmd_c/lib -o convert_model \ - && gcc infer_water.c -std=c99 -L ../../libdeepmd_c/lib -I ../../libdeepmd_c/include -Wl,--no-as-needed -ldeepmd_c -Wl,-rpath=../../libdeepmd_c/lib -o infer_water \ - && ./convert_model \ - && ./infer_water" +docker run --rm -v "${SCRIPT_PATH}/../..":/root/deepmd-kit -w /root/deepmd-kit \ + -e CHECK_PYTORCH_RUNTIME="${CHECK_PYTORCH_RUNTIME:-0}" \ + -e PYTHON_BIN="${PYTHON_BIN}" \ + -e PYTORCH_DEPENDENCY_GROUP="${PYTORCH_DEPENDENCY_GROUP}" \ + -e PYTORCH_TORCH_BACKEND="${PYTORCH_TORCH_BACKEND}" \ + "${MANYLINUX_IMAGE}" \ + /bin/bash -lc 'set -euo pipefail + export PATH="$(dirname "${PYTHON_BIN}"):${PATH}" + tar vxzf libdeepmd_c.tar.gz + if [ -f libdeepmd_c/download_libtorch.sh ]; then + sh -n libdeepmd_c/download_libtorch.sh + fi + cd examples/infer_water + gcc convert_model.c -std=c99 -L ../../libdeepmd_c/lib -I ../../libdeepmd_c/include -Wl,--no-as-needed -ldeepmd_c -Wl,-rpath=../../libdeepmd_c/lib -o convert_model + gcc infer_water.c -std=c99 -L ../../libdeepmd_c/lib -I ../../libdeepmd_c/include -Wl,--no-as-needed -ldeepmd_c -Wl,-rpath=../../libdeepmd_c/lib -o infer_water + ./convert_model + ./infer_water + cd /root/deepmd-kit + if [ "${CHECK_PYTORCH_RUNTIME}" = "1" ]; then + "${PYTHON_BIN}" -m pip install uv + source/install/uv_with_retry.sh pip install --python "${PYTHON_BIN}" --group "${PYTORCH_DEPENDENCY_GROUP}" --torch-backend "${PYTORCH_TORCH_BACKEND}" + TORCH_RUNTIME_LIB_DIRS=$("${PYTHON_BIN}" - <<'"'"'PY'"'"' +import pathlib +import site +import sys + +import torch + +dirs = [pathlib.Path(torch.__file__).resolve().parent / "lib"] +roots = [] +try: + roots.extend(site.getsitepackages()) +except AttributeError: + pass +try: + roots.append(site.getusersitepackages()) +except AttributeError: + pass +roots.extend(sys.path) +for root in roots: + if not root: + continue + nvidia_dir = pathlib.Path(root) / "nvidia" + if nvidia_dir.is_dir(): + dirs.extend(sorted(path for path in nvidia_dir.glob("*/lib") if path.is_dir())) +seen = set() +unique_dirs = [] +for path in dirs: + path = path.resolve() + if path in seen: + continue + seen.add(path) + unique_dirs.append(str(path)) +print(":".join(unique_dirs)) +PY +) + RUNTIME_LIBRARY_PATH="${PWD}/libdeepmd_c/lib:${TORCH_RUNTIME_LIB_DIRS}" + if [ -n "${LD_LIBRARY_PATH:-}" ]; then + RUNTIME_LIBRARY_PATH="${RUNTIME_LIBRARY_PATH}:${LD_LIBRARY_PATH}" + fi + LD_LIBRARY_PATH="${RUNTIME_LIBRARY_PATH}" ldd libdeepmd_c/lib/libdeepmd_backend_pt.so > /tmp/deepmd_pt_ldd.txt + LD_LIBRARY_PATH="${RUNTIME_LIBRARY_PATH}" ldd libdeepmd_c/lib/libdeepmd_backend_ptexpt.so >> /tmp/deepmd_pt_ldd.txt + LD_LIBRARY_PATH="${RUNTIME_LIBRARY_PATH}" ldd libdeepmd_c/lib/libdeepmd_op_pt.so >> /tmp/deepmd_pt_ldd.txt + cat /tmp/deepmd_pt_ldd.txt + if grep -q "not found" /tmp/deepmd_pt_ldd.txt; then + exit 1 + fi + LD_LIBRARY_PATH="${RUNTIME_LIBRARY_PATH}" "${PYTHON_BIN}" - <<'"'"'PY'"'"' +import ctypes +import os +import pathlib + +import torch # noqa: F401 + +libdir = pathlib.Path("libdeepmd_c/lib").resolve() +for name in [ + "libdeepmd_op_pt.so", + "libdeepmd_backend_pt.so", + "libdeepmd_backend_ptexpt.so", +]: + ctypes.CDLL(str(libdir / name), mode=os.RTLD_NOW | os.RTLD_LOCAL) +PY + fi' diff --git a/source/install/package_c.sh b/source/install/package_c.sh index 0c145b22af..7c957fcba0 100755 --- a/source/install/package_c.sh +++ b/source/install/package_c.sh @@ -2,32 +2,216 @@ set -e -SCRIPT_PATH=$(dirname $(realpath -s $0)) -if [ -z "$INSTALL_PREFIX" ]; then - INSTALL_PREFIX=$(realpath -s ${SCRIPT_PATH}/../../dp_c) +SCRIPT_PATH=$(dirname "$(realpath -s "$0")") +if [ -z "${INSTALL_PREFIX}" ]; then + INSTALL_PREFIX=$(realpath -s "${SCRIPT_PATH}/../../dp_c") fi -mkdir -p ${INSTALL_PREFIX} +mkdir -p "${INSTALL_PREFIX}" echo "Installing DeePMD-kit to ${INSTALL_PREFIX}" NPROC=$(nproc --all) #------------------ BUILD_TMP_DIR=${SCRIPT_PATH}/../build_c -mkdir -p ${BUILD_TMP_DIR} -cd ${BUILD_TMP_DIR} -cmake -DCMAKE_INSTALL_PREFIX=${INSTALL_PREFIX} \ - -DUSE_CUDA_TOOLKIT=TRUE \ +mkdir -p "${BUILD_TMP_DIR}" +cd "${BUILD_TMP_DIR}" +CMAKE_EXTRA_ARGS=${CMAKE_EXTRA_ARGS:-} +if [ -n "${PYTHON_BIN:-}" ]; then + PYTHON_INCLUDE_DIR=$( + "${PYTHON_BIN}" - <<'PY' +import sysconfig + +print(sysconfig.get_path("include") or "") +PY + ) + PYTHON_LIBRARY=$( + "${PYTHON_BIN}" - <<'PY' +import pathlib +import sysconfig + +lib_names = ( + sysconfig.get_config_var("LDLIBRARY"), + sysconfig.get_config_var("INSTSONAME"), + sysconfig.get_config_var("LIBRARY"), +) +lib_dirs = ( + sysconfig.get_config_var("LIBDIR"), + sysconfig.get_config_var("LIBPL"), +) +for lib_dir in filter(None, lib_dirs): + for lib_name in filter(None, lib_names): + candidate = pathlib.Path(lib_dir) / lib_name + if candidate.exists(): + print(candidate) + raise SystemExit +print("") +PY + ) + PYTHON_CMAKE_ARGS="-DPython_EXECUTABLE=${PYTHON_BIN}" + if [ -n "${PYTHON_INCLUDE_DIR}" ]; then + PYTHON_CMAKE_ARGS="${PYTHON_CMAKE_ARGS} -DPython_INCLUDE_DIR=${PYTHON_INCLUDE_DIR} -DPYTHON_INCLUDE_DIR=${PYTHON_INCLUDE_DIR}" + fi + if [ -n "${PYTHON_LIBRARY}" ]; then + PYTHON_CMAKE_ARGS="${PYTHON_CMAKE_ARGS} -DPython_LIBRARY=${PYTHON_LIBRARY} -DPYTHON_LIBRARY=${PYTHON_LIBRARY}" + fi + if [ -z "${CUDA_NVRTC_LIBRARY:-}" ]; then + CUDA_NVRTC_LIBRARY=$( + "${PYTHON_BIN}" - <<'PY' +import pathlib +import site +import sys + +roots = [] +try: + roots.extend(site.getsitepackages()) +except AttributeError: + pass +try: + roots.append(site.getusersitepackages()) +except AttributeError: + pass +roots.extend(sys.path) +seen = set() +for root in roots: + if not root: + continue + root_path = pathlib.Path(root) + if root_path in seen: + continue + seen.add(root_path) + for pattern in ( + "nvidia/cuda_nvrtc/lib/libnvrtc.so", + "nvidia/cuda_nvrtc/lib/libnvrtc.so.*", + ): + for candidate in sorted(root_path.glob(pattern)): + if candidate.exists(): + print(candidate) + raise SystemExit +print("") +PY + ) + fi +fi +if [ -n "${CUDA_NVRTC_LIBRARY:-}" ]; then + CMAKE_EXTRA_ARGS="${CMAKE_EXTRA_ARGS} -DCUDA_nvrtc_LIBRARY=${CUDA_NVRTC_LIBRARY}" +fi +cmake -DCMAKE_INSTALL_PREFIX="${INSTALL_PREFIX}" \ + -DUSE_CUDA_TOOLKIT="${USE_CUDA_TOOLKIT:-TRUE}" \ -DPACKAGE_C=TRUE \ - -DUSE_TF_PYTHON_LIBS=TRUE \ + -DUSE_TF_PYTHON_LIBS="${USE_TF_PYTHON_LIBS:-TRUE}" \ + -DENABLE_PYTORCH="${ENABLE_PYTORCH:-FALSE}" \ + -DUSE_PT_PYTHON_LIBS="${USE_PT_PYTHON_LIBS:-${ENABLE_PYTORCH:-FALSE}}" \ + -DPACKAGE_C_RUNTIME_DEPENDENCY_PRE_EXCLUDE_REGEXES="${PACKAGE_C_RUNTIME_DEPENDENCY_PRE_EXCLUDE_REGEXES:-}" \ + -DPACKAGE_C_RUNTIME_DEPENDENCY_POST_EXCLUDE_REGEXES="${PACKAGE_C_RUNTIME_DEPENDENCY_POST_EXCLUDE_REGEXES:-}" \ + ${PYTHON_CMAKE_ARGS:-} \ + ${CMAKE_EXTRA_ARGS:-} \ .. -cmake --build . -j${NPROC} +cmake --build . -j"${NPROC}" cmake --install . #------------------ # fix runpath -for ii in ${BUILD_TMP_DIR}/libdeepmd_c/lib/*.so*; do - patchelf --set-rpath \$ORIGIN $ii +for ii in "${BUILD_TMP_DIR}"/libdeepmd_c/lib/*.so*; do + patchelf --set-rpath \$ORIGIN "$ii" done -tar vczf ${SCRIPT_PATH}/../../libdeepmd_c.tar.gz -C ${BUILD_TMP_DIR} libdeepmd_c +if [ -z "${PYTORCH_RUNTIME_DOWNLOAD_URL:-}" ] && [ "${ENABLE_PYTORCH:-FALSE}" = "TRUE" ] && [ -n "${PYTHON_BIN:-}" ]; then + PYTORCH_RUNTIME_DOWNLOAD_URL=$( + "${PYTHON_BIN}" - <<'PY' +from urllib.parse import quote + +import torch + +version = torch.__version__.split(".dev", 1)[0] +if "+" in version: + variant = version.split("+", 1)[1] +else: + cuda_version = torch.version.cuda + variant = "cu" + cuda_version.replace(".", "") if cuda_version else "cpu" + version = f"{version}+{variant}" + +if variant == "cpu" or variant.startswith("cu"): + print( + f"https://download.pytorch.org/libtorch/{variant}/" + f"libtorch-shared-with-deps-{quote(version, safe='')}.zip" + ) +PY + ) +fi + +if [ -n "${PYTORCH_RUNTIME_DOWNLOAD_URL:-}" ]; then + cat >"${BUILD_TMP_DIR}/libdeepmd_c/README.md" <"${BUILD_TMP_DIR}/libdeepmd_c/download_libtorch.sh" <<'EOF' +#!/bin/sh + +set -eu + +LIBTORCH_DOWNLOAD_URL="__PYTORCH_RUNTIME_DOWNLOAD_URL__" +SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd -P) +DEST_DIR=${1:-"${SCRIPT_DIR}"} +ARCHIVE_PATH=${LIBTORCH_ARCHIVE:-"${SCRIPT_DIR}/libtorch.zip"} + +mkdir -p "${DEST_DIR}" + +if [ -d "${DEST_DIR}/libtorch" ]; then + echo "libtorch already exists at ${DEST_DIR}/libtorch" +else + echo "Downloading ${LIBTORCH_DOWNLOAD_URL}" + if command -v curl >/dev/null 2>&1; then + curl -L --fail --retry 3 -o "${ARCHIVE_PATH}" "${LIBTORCH_DOWNLOAD_URL}" + elif command -v wget >/dev/null 2>&1; then + wget -O "${ARCHIVE_PATH}" "${LIBTORCH_DOWNLOAD_URL}" + else + echo "curl or wget is required to download libtorch." >&2 + exit 1 + fi + + echo "Extracting ${ARCHIVE_PATH} to ${DEST_DIR}" + if command -v unzip >/dev/null 2>&1; then + unzip -q -o "${ARCHIVE_PATH}" -d "${DEST_DIR}" + elif command -v python3 >/dev/null 2>&1; then + ZIP_ARCHIVE="${ARCHIVE_PATH}" ZIP_DEST_DIR="${DEST_DIR}" python3 - <<'PY' +import os +import zipfile + +with zipfile.ZipFile(os.environ["ZIP_ARCHIVE"]) as zip_file: + zip_file.extractall(os.environ["ZIP_DEST_DIR"]) +PY + elif command -v python >/dev/null 2>&1; then + ZIP_ARCHIVE="${ARCHIVE_PATH}" ZIP_DEST_DIR="${DEST_DIR}" python - <<'PY' +import os +import zipfile + +with zipfile.ZipFile(os.environ["ZIP_ARCHIVE"]) as zip_file: + zip_file.extractall(os.environ["ZIP_DEST_DIR"]) +PY + else + echo "unzip or python is required to extract libtorch." >&2 + exit 1 + fi +fi + +cat >"${SCRIPT_DIR}/libtorch_env.sh" <