Problem using libtorch to bind C++ modules to Python

Hi,

I needed to bind C++ torch modules to python, but could not find any detailed documentation anywhere.
So I turned to docstring in code, specifically in torch/python.h, and followed minimal example provided in the comments for simple identity module.

Minimal example below

CMakeLists.txt

cmake_minimum_required(VERSION 3.8 FATAL_ERROR)
project(example VERSION 1.0.0 LANGUAGES C CXX CUDA)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

find_package(Python COMPONENTS Interpreter Development REQUIRED)
find_package(pybind11 CONFIG REQUIRED)
find_package(Torch REQUIRED)

pybind11_add_module(pybind_example tmp.cpp)

target_link_libraries(pybind_example PRIVATE ${TORCH_LIBRARIES})

tmp.cpp

#include <torch/extension.h>
#include <pybind11/pybind11.h>

namespace py = pybind11;

struct Net : torch::nn::Module {
    Net(int in, int out) { }
    torch::Tensor forward(torch::Tensor x) { return x; }
};

PYBIND11_MODULE(my_module, m)
{
    torch::python::bind_module<Net>(m, "Net")
        .def(py::init<int, int>())
        .def("forward", &Net::forward);
}

Code compiles and creates shared library pybind_example.cpython-39-x86_64-linux-gnu.so
Problem occurs on import of created module with error

ImportError: /home/user/tmp/build/pybind_example.cpython-39-x86_64-linux-gnu.so: undefined symbol: THPDtypeType

Am I missing a linking step? THPDtypeType is defined in torch/csrc/Dtype.h, but I don’t see where it is invoked.

Thank you in advance for any help / ideas.

${TORCH_LIBRARIES} doesn’t include header files (such as Python.h) and dynamic link libraries (such as torch_python) required for Python. You must manually add them. If you want to compile it with cmake, you can imitate following CMakeLists.txt template:

cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
project(example LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED on)


# find pybind11
execute_process(
    COMMAND python3 -c "import pybind11;print(pybind11.__path__[0])"
    OUTPUT_VARIABLE PYBIND11_PATH)
string(REPLACE "\n" "/share/cmake" PYBIND11_CMAKE_PREFIX_PATH ${PYBIND11_PATH})
list(APPEND CMAKE_PREFIX_PATH ${PYBIND11_CMAKE_PREFIX_PATH})
find_package(pybind11 REQUIRED)
# Assign ${PYTHON_INCLUDE_DIRS}
execute_process(
    COMMAND python3-config --exec-prefix 
    OUTPUT_VARIABLE PYTHON_INCLUDE_DIRS)
string(REPLACE "\n" "" PYTHON_INCLUDE_DIRS "${PYTHON_INCLUDE_DIRS}")
string(APPEND PYTHON_INCLUDE_DIRS "/include/python3.9")
message(STATUS ${PYTHON_INCLUDE_DIRS})
# Assign ${TORCH_INCLUDE_DIRS}
execute_process(
    COMMAND python3 -c "from torch.utils import cpp_extension;print(cpp_extension.include_paths())"
    OUTPUT_VARIABLE TORCH_INCLUDE_DIRS)
string(REPLACE "[" "" TORCH_INCLUDE_DIRS "${TORCH_INCLUDE_DIRS}")
string(REPLACE "]" "" TORCH_INCLUDE_DIRS "${TORCH_INCLUDE_DIRS}")
string(REPLACE "'" "" TORCH_INCLUDE_DIRS "${TORCH_INCLUDE_DIRS}")
string(REPLACE "\n" "" TORCH_INCLUDE_DIRS "${TORCH_INCLUDE_DIRS}")
string(REPLACE ", " "\;" TORCH_INCLUDE_DIRS_LIST "${TORCH_INCLUDE_DIRS}")
# Assign ${TORCH_LIBRARY_DIRS}
execute_process(
    COMMAND python3 -c "from torch.utils import cpp_extension;print(cpp_extension.library_paths()[0])"
    OUTPUT_VARIABLE TORCH_LIBRARY_DIRS)
string(REPLACE "\n" "" TORCH_LIBRARY_DIRS "${TORCH_LIBRARY_DIRS}")


pybind11_add_module(pybind_example MODULE ${CMAKE_CURRENT_SOURCE_DIR}/tmp.cpp)
foreach(dir IN LISTS TORCH_INCLUDE_DIRS_LIST)
    target_include_directories(pybind_example PRIVATE ${dir})
endforeach()
target_include_directories(pybind_example PRIVATE ${PYTHON_INCLUDE_DIRS})
target_link_directories(pybind_example PRIVATE ${TORCH_LIBRARY_DIRS})
target_link_libraries(pybind_example PRIVATE c10 torch_cpu torch_python)

Of course, you can also compile using g++ or torch.utils.cpp_extension module. You must add -lc10, -ltorch and -ltorch_python to ldflags, and add -I<path_to_python>/include/python3.x, -I<path_to_torch>/include/torch/csrc/api/include and -I<path_to_torch>/include to cxxflags.