Skip to content
Merged
8 changes: 8 additions & 0 deletions doc/env.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,14 @@ These environment variables also apply to third-party programs using the C++ int
List of customized OP plugin libraries to load, such as `/path/to/plugin1.so:/path/to/plugin2.so` on Linux and `/path/to/plugin1.dll;/path/to/plugin2.dll` on Windows.
:::

:::{envvar} DP_BACKEND_PLUGIN_PATH

**Type**: List of directories, split by `:` on Unix and `;` on Windows

List of directories used to search for C/C++ backend plugin libraries before the directory that contains `libdeepmd_cc`.
This controls backend implementation plugins, such as `libdeepmd_backend_tf.so` and `libdeepmd_backend_pt.so`, and is separate from {envvar}`DP_PLUGIN_PATH`, which loads customized OP plugins.
:::

:::{envvar} DP_PROFILER

{{ pytorch_icon }} Enable the built-in PyTorch Kineto profiler for the PyTorch C++ (inference) backend.
Expand Down
37 changes: 34 additions & 3 deletions doc/inference/cxx.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ See {cpp:class}`deepmd::DeepPot` for details.
You can compile `infer_water.cpp` using `gcc`:

```sh
gcc infer_water.cpp -L $deepmd_root/lib -L $tensorflow_root/lib -I $deepmd_root/include -Wl,--no-as-needed -ldeepmd_cc -lstdc++ -ltensorflow_cc -Wl,-rpath=$deepmd_root/lib -Wl,-rpath=$tensorflow_root/lib -o infer_water
gcc infer_water.cpp -L $deepmd_root/lib -I $deepmd_root/include -Wl,--no-as-needed -ldeepmd_cc -lstdc++ -Wl,-rpath=$deepmd_root/lib -o infer_water
```

and then run the program:
Expand All @@ -37,6 +37,37 @@ and then run the program:
./infer_water
```

## Backend plugins

The C and C++ libraries load backend implementations as runtime plugins.
An application links to `libdeepmd_cc` or `libdeepmd_c`; it does not need to link directly to TensorFlow, PyTorch, JAX, or Paddle.
When a model is opened, DeePMD-kit detects the backend from the model format and loads only the corresponding backend plugin.

The plugin library names are:

- TensorFlow: `libdeepmd_backend_tf.so`
- PyTorch: `libdeepmd_backend_pt.so`
- PyTorch exportable: `libdeepmd_backend_ptexpt.so`
- JAX: `libdeepmd_backend_jax.so`
- Paddle: `libdeepmd_backend_pd.so`

On macOS the suffix is `.dylib`; on Windows the libraries use `.dll` without the `lib` prefix.
Native installs and the pre-compiled C library package place these plugins in the same `lib` directory as `libdeepmd_cc` and `libdeepmd_c`.
Python wheels place them in `deepmd/lib`.

The backend plugin search order is:

1. directories listed in {envvar}`DP_BACKEND_PLUGIN_PATH`, split by `:` on Unix and `;` on Windows;
1. the directory that contains `libdeepmd_cc`;
1. the platform dynamic loader search path for the bare plugin library name.

If the requested plugin or its backend runtime cannot be loaded, only that backend fails with a `Unable to load ... backend plugin` error.
Other backends can still run as long as their own plugins and runtime libraries are available.
This also allows a no-backend `libdeepmd_cc` or `libdeepmd_c` build; install or copy the backend plugin next to the library, or set {envvar}`DP_BACKEND_PLUGIN_PATH`, before loading a model that uses that backend.
Build instructions for this layout are in [Install DeePMD-kit's C++ interface](../install/install-from-source.md#install-deepmd-kits-c-interface).

{envvar}`DP_PLUGIN_PATH` is different: it is used for customized OP plugin libraries after the backend has been selected.
Comment thread
coderabbitai[bot] marked this conversation as resolved.

## C interface

Although C is harder to write, the C library will not be affected by different versions of C++ compilers.
Expand Down Expand Up @@ -85,7 +116,7 @@ See {cpp:func}`DP_DeepPotCompute` for details.
You can compile `infer_water.c` using `gcc`:

```sh
gcc infer_water.c -L $deepmd_root/lib -L $tensorflow_root/lib -I $deepmd_root/include -Wl,--no-as-needed -ldeepmd_c -Wl,-rpath=$deepmd_root/lib -Wl,-rpath=$tensorflow_root/lib -o infer_water
gcc infer_water.c -L $deepmd_root/lib -I $deepmd_root/include -Wl,--no-as-needed -ldeepmd_c -Wl,-rpath=$deepmd_root/lib -o infer_water
```

and then run the program:
Expand Down Expand Up @@ -120,7 +151,7 @@ See {cpp:class}`deepmd::hpp::DeepPot` for details.
You can compile `infer_water_hpp.cpp` using `gcc`:

```sh
gcc infer_water_hpp.cpp -L $deepmd_root/lib -L $tensorflow_root/lib -I $deepmd_root/include -Wl,--no-as-needed -ldeepmd_c -Wl,-rpath=$deepmd_root/lib -Wl,-rpath=$tensorflow_root/lib -o infer_water_hpp
gcc infer_water_hpp.cpp -L $deepmd_root/lib -I $deepmd_root/include -Wl,--no-as-needed -ldeepmd_c -Wl,-rpath=$deepmd_root/lib -o infer_water_hpp
```

and then run the program:
Expand Down
29 changes: 28 additions & 1 deletion doc/install/install-from-source.md
Original file line number Diff line number Diff line change
Expand Up @@ -370,12 +370,31 @@ The installation requires CMake 3.25.2 or later for all platforms (CPU, CUDA, an
pip install -U cmake
```

You must enable at least one backend.
For a backend-enabled install, enable at least one backend.
If you only want backend-neutral C/C++ libraries, use the backend-neutral tab below and provide backend plugins at runtime.
If you enable two or more backends, these backend libraries must be built in a compatible way, e.g. using the same `_GLIBCXX_USE_CXX11_ABI` flag.
We recommend using [conda packages](https://docs.deepmodeling.com/faq/conda.html) from [conda-forge](https://conda-forge.org), which are usually compatible to each other.

::::{tab-set}

:::{tab-item} Backend-neutral C/C++ libraries

To build only `libdeepmd_cc` and `libdeepmd_c` without backend plugins, leave all backend options disabled, or set them explicitly:

```bash
cmake -DBUILD_CPP_IF=ON -DBUILD_PY_IF=OFF \
-DENABLE_TENSORFLOW=OFF -DENABLE_PYTORCH=OFF \
-DENABLE_JAX=OFF -DENABLE_PADDLE=OFF \
Comment thread
wanghan-iapcm marked this conversation as resolved.
-DALLOW_NO_BACKEND=ON \
-DCMAKE_INSTALL_PREFIX=$deepmd_root ..
```

`ALLOW_NO_BACKEND=ON` is required as an explicit opt-in so CMake can distinguish this layout from an accidental build with all backends disabled.
This install does not include backend plugins.
Use backend plugin libraries from a backend-enabled build or package at runtime, either by placing them next to the installed C/C++ libraries or by setting {envvar}`DP_BACKEND_PLUGIN_PATH`.
See [C/C++ backend plugins](../inference/cxx.md#backend-plugins) for runtime plugin discovery.
:::

:::{tab-item} TensorFlow {{ tensorflow_icon }} / JAX {{ jax_icon }}

I assume you have activated the TensorFlow Python environment and want to install DeePMD-kit into path `$deepmd_root`, then execute CMake
Expand Down Expand Up @@ -456,6 +475,14 @@ If {cmake:variable}`ENABLE_TENSORFLOW` is `OFF`, the TensorFlow C library is use
{{ paddle_icon }} Whether building the Paddle backend.
:::

:::{cmake:variable} ALLOW_NO_BACKEND

**Type**: `BOOL` (`ON`/`OFF`), Default: `OFF`

Allow building backend-neutral C/C++ libraries with all backend options disabled.
Set this to `ON` only when you plan to provide backend plugin libraries at runtime, for example next to `libdeepmd_cc`/`libdeepmd_c` or through {envvar}`DP_BACKEND_PLUGIN_PATH`.
:::

:::{cmake:variable} TENSORFLOW_ROOT

**Type**: `PATH`
Expand Down
13 changes: 12 additions & 1 deletion source/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ if(ENABLE_TENSORFLOW)
endif()
option(ENABLE_PADDLE "Enable Paddle interface" OFF)
option(BUILD_TESTING "Build test and enable coverage" OFF)
option(ALLOW_NO_BACKEND
"Allow a backend-neutral C/C++ build without built-in backend plugins"
OFF)
set(DEEPMD_C_ROOT
""
CACHE PATH "Path to imported DeePMD-kit C library")
Expand Down Expand Up @@ -438,7 +441,15 @@ if(NOT DEEPMD_C_ROOT)
AND NOT ENABLE_JAX
AND NOT ENABLE_PADDLE
AND NOT BUILD_PY_IF)
message(FATAL_ERROR "No backend is enabled.")
if(ALLOW_NO_BACKEND)
message(STATUS "- none (backend-neutral C/C++ library only)")
else()
message(
FATAL_ERROR
"No backend is enabled. Enable at least one backend, or set "
"ALLOW_NO_BACKEND=ON for a backend-neutral C/C++ library that "
"loads backend plugins at runtime.")
endif()
endif()
endif()

Expand Down
15 changes: 14 additions & 1 deletion source/api_c/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,21 @@ endif(BUILD_PY_IF)

if(PACKAGE_C)
message(STATUS "Packaging C API library")
get_property(DEEPMD_BACKEND_PLUGIN_TARGETS GLOBAL
PROPERTY DEEPMD_BACKEND_PLUGIN_TARGETS)
set(PACKAGE_C_RUNTIME_LIBRARIES "$<TARGET_FILE:${libname}>"
"$<TARGET_FILE:${LIB_DEEPMD_OP}>")
foreach(_target ${DEEPMD_BACKEND_PLUGIN_TARGETS})
list(APPEND PACKAGE_C_RUNTIME_LIBRARIES "$<TARGET_FILE:${_target}>")
endforeach()
string(REPLACE ";" " " PACKAGE_C_RUNTIME_LIBRARIES_CODE
"${PACKAGE_C_RUNTIME_LIBRARIES}")
# follow pypa/auditwheel convention
install(CODE "set(_dp_runtime_libraries ${PACKAGE_C_RUNTIME_LIBRARIES_CODE})")
install(
CODE [[
file(GET_RUNTIME_DEPENDENCIES
LIBRARIES $<TARGET_FILE:deepmd_c> $<TARGET_FILE:deepmd_op>
LIBRARIES ${_dp_runtime_libraries}
RESOLVED_DEPENDENCIES_VAR _r_deps
PRE_EXCLUDE_REGEXES "libgcc_s\\.so.*"
"libstdc\\+\\+\\.so.*"
Expand All @@ -59,6 +69,9 @@ if(PACKAGE_C)
install(TARGETS ${libname} DESTINATION ${CMAKE_BINARY_DIR}/libdeepmd_c/lib)
install(TARGETS ${LIB_DEEPMD_OP}
DESTINATION ${CMAKE_BINARY_DIR}/libdeepmd_c/lib)
foreach(_target ${DEEPMD_BACKEND_PLUGIN_TARGETS})
install(TARGETS ${_target} DESTINATION ${CMAKE_BINARY_DIR}/libdeepmd_c/lib)
endforeach()

set(cmake_files_install_dir
"${CMAKE_BINARY_DIR}/libdeepmd_c/lib/cmake/${CMAKE_PROJECT_NAME}")
Expand Down
137 changes: 115 additions & 22 deletions source/api_cc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,32 +5,32 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/include/version.h.in version.h @ONLY)
file(GLOB LIB_SRC src/*.cc src/*.cpp)
file(GLOB INC_SRC include/*.h ${CMAKE_CURRENT_BINARY_DIR}/version.h)

set(DEEPMD_BACKEND_IMPL_SRC
${CMAKE_CURRENT_SOURCE_DIR}/src/DataModifierTF.cc
${CMAKE_CURRENT_SOURCE_DIR}/src/DeepPotJAX.cc
${CMAKE_CURRENT_SOURCE_DIR}/src/DeepPotPD.cc
${CMAKE_CURRENT_SOURCE_DIR}/src/DeepPotPT.cc
${CMAKE_CURRENT_SOURCE_DIR}/src/DeepPotPTExpt.cc
${CMAKE_CURRENT_SOURCE_DIR}/src/DeepPotTF.cc
${CMAKE_CURRENT_SOURCE_DIR}/src/DeepSpinPT.cc
${CMAKE_CURRENT_SOURCE_DIR}/src/DeepSpinPTExpt.cc
${CMAKE_CURRENT_SOURCE_DIR}/src/DeepSpinTF.cc
${CMAKE_CURRENT_SOURCE_DIR}/src/DeepTensorPT.cc
${CMAKE_CURRENT_SOURCE_DIR}/src/DeepTensorTF.cc)
set(DEEPMD_BACKEND_PLUGIN_SRC
${CMAKE_CURRENT_SOURCE_DIR}/src/DeepPotJAXPlugin.cc
${CMAKE_CURRENT_SOURCE_DIR}/src/DeepPotPDPlugin.cc
${CMAKE_CURRENT_SOURCE_DIR}/src/DeepPotPTExptPlugin.cc
${CMAKE_CURRENT_SOURCE_DIR}/src/DeepPotPTPlugin.cc
${CMAKE_CURRENT_SOURCE_DIR}/src/DeepPotTFPlugin.cc)
list(REMOVE_ITEM LIB_SRC ${DEEPMD_BACKEND_IMPL_SRC}
${DEEPMD_BACKEND_PLUGIN_SRC})

set(libname "${LIB_DEEPMD_CC}")
add_library(${libname} SHARED ${LIB_SRC})

# link: libdeepmd libdeepmd_op libtensorflow_cc libtensorflow_framework
# link: libdeepmd. Backend runtimes are loaded through backend plugins.
target_link_libraries(${libname} PUBLIC ${LIB_DEEPMD})
if(ENABLE_TENSORFLOW)
target_link_libraries(${libname} PRIVATE TensorFlow::tensorflow_cc
TensorFlow::tensorflow_framework)
target_compile_definitions(${libname} PRIVATE BUILD_TENSORFLOW)
endif()
if(ENABLE_PYTORCH AND "${OP_CXX_ABI_PT}" EQUAL "${OP_CXX_ABI}")
target_link_libraries(${libname} PRIVATE "${TORCH_LIBRARIES}")
target_compile_definitions(${libname} PRIVATE BUILD_PYTORCH)
endif()
if(ENABLE_JAX)
target_link_libraries(${libname} PRIVATE TensorFlow::tensorflow_c)
target_compile_definitions(${libname} PRIVATE BUILD_JAX)
endif()
if(ENABLE_PADDLE AND NOT BUILD_PY_IF)
target_link_libraries(${libname} PUBLIC "${PADDLE_LIBRARIES}")
target_compile_definitions(${libname} PUBLIC BUILD_PADDLE)
if(DP_VARIANT STREQUAL "rocm")
target_link_libraries(${libname}
PUBLIC "${hip_LIB_INSTALL_DIR}/libgalaxyhip.so")
endif()
endif()

target_include_directories(
${libname}
Expand All @@ -54,6 +54,99 @@ if(CMAKE_TESTING_ENABLED)
endif()
target_compile_features(${libname} PUBLIC cxx_std_11)

if(BUILD_PY_IF)
set(DEEPMD_API_CC_INSTALL_DESTINATION deepmd/lib/)
else()
set(DEEPMD_API_CC_INSTALL_DESTINATION lib/)
endif()

function(deepmd_configure_backend_plugin target_name)
target_link_libraries(${target_name} PRIVATE ${LIB_DEEPMD_CC})
target_include_directories(
${target_name}
PRIVATE $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>)
target_compile_features(${target_name} PUBLIC cxx_std_11)
set_target_properties(
${target_name}
PROPERTIES INSTALL_RPATH "$ORIGIN;${BACKEND_LIBRARY_PATH}"
INSTALL_RPATH_USE_LINK_PATH TRUE
BUILD_RPATH "$ORIGIN/../op/tf;$ORIGIN/../op/pt;$ORIGIN/../op/pd")
if(CMAKE_TESTING_ENABLED)
target_link_libraries(${target_name} PRIVATE coverage_config)
endif()
install(TARGETS ${target_name}
DESTINATION ${DEEPMD_API_CC_INSTALL_DESTINATION})
set_property(GLOBAL APPEND PROPERTY DEEPMD_BACKEND_PLUGIN_TARGETS
${target_name})
endfunction()

if(ENABLE_TENSORFLOW)
# TensorFlow helper functions in common.cc are compiled with BUILD_TENSORFLOW
# into this plugin so the main libdeepmd_cc can stay backend-neutral.
add_library(
deepmd_backend_tf SHARED
src/DataModifierTF.cc src/DeepPotTF.cc src/DeepPotTFPlugin.cc
src/DeepSpinTF.cc src/DeepTensorTF.cc src/common.cc)
deepmd_configure_backend_plugin(deepmd_backend_tf)
if(UNIX AND NOT APPLE)
target_link_libraries(
deepmd_backend_tf
PRIVATE -Wl,--no-as-needed TensorFlow::tensorflow_cc -Wl,--as-needed
TensorFlow::tensorflow_framework)
else()
target_link_libraries(
deepmd_backend_tf PRIVATE TensorFlow::tensorflow_cc
TensorFlow::tensorflow_framework)
endif()
target_compile_definitions(deepmd_backend_tf PRIVATE BUILD_TENSORFLOW
TF_PRIVATE)
if(Protobuf_LIBRARY)
target_link_libraries(deepmd_backend_tf PRIVATE ${Protobuf_LIBRARY})
endif()
endif()

if(ENABLE_PYTORCH AND "${OP_CXX_ABI_PT}" EQUAL "${OP_CXX_ABI}")
add_library(deepmd_backend_pt SHARED src/DeepPotPT.cc src/DeepPotPTPlugin.cc
src/DeepSpinPT.cc src/DeepTensorPT.cc)
deepmd_configure_backend_plugin(deepmd_backend_pt)
target_link_libraries(deepmd_backend_pt PRIVATE "${TORCH_LIBRARIES}")
target_compile_definitions(deepmd_backend_pt PRIVATE BUILD_PYTORCH)

add_library(
deepmd_backend_ptexpt SHARED
src/DeepPotPTExpt.cc src/DeepPotPTExptPlugin.cc src/DeepSpinPTExpt.cc)
deepmd_configure_backend_plugin(deepmd_backend_ptexpt)
target_link_libraries(deepmd_backend_ptexpt PRIVATE "${TORCH_LIBRARIES}")
target_compile_definitions(deepmd_backend_ptexpt PRIVATE BUILD_PYTORCH)
endif()

if(ENABLE_JAX)
add_library(deepmd_backend_jax SHARED src/DeepPotJAX.cc
src/DeepPotJAXPlugin.cc)
deepmd_configure_backend_plugin(deepmd_backend_jax)
target_link_libraries(deepmd_backend_jax PRIVATE TensorFlow::tensorflow_c)
target_compile_definitions(deepmd_backend_jax PRIVATE BUILD_JAX)
Comment thread
wanghan-iapcm marked this conversation as resolved.
if(ENABLE_TENSORFLOW)
# ENABLE_TENSORFLOW turns ENABLE_JAX on in source/CMakeLists.txt so
# TensorFlow-only user configurations keep the historical ability to load
# JAX2TF SavedModels. Define BUILD_TENSORFLOW too, matching the plugin
# wrapper guard and making that compatibility intentional.
target_compile_definitions(deepmd_backend_jax PRIVATE BUILD_TENSORFLOW)
endif()
endif()

if(ENABLE_PADDLE AND NOT BUILD_PY_IF)
add_library(deepmd_backend_pd SHARED src/DeepPotPD.cc src/DeepPotPDPlugin.cc)
deepmd_configure_backend_plugin(deepmd_backend_pd)
target_link_libraries(deepmd_backend_pd PRIVATE "${PADDLE_LIBRARIES}")
target_compile_definitions(deepmd_backend_pd PRIVATE BUILD_PADDLE)
if(DP_VARIANT STREQUAL "rocm")
target_link_libraries(deepmd_backend_pd
PRIVATE "${hip_LIB_INSTALL_DIR}/libgalaxyhip.so")
endif()
endif()

if(BUILD_PY_IF)
install(TARGETS ${libname} DESTINATION deepmd/lib/)
else(BUILD_PY_IF)
Expand Down
Loading
Loading