Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 9 additions & 5 deletions CMake/SofaPython3Tools.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -48,17 +48,23 @@ function(SP3_add_python_package)

cmake_parse_arguments(A "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

set(OUTPUT_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/${SP3_PYTHON_PACKAGES_DIRECTORY}/${A_TARGET_DIRECTORY})
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
set(OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${SP3_PYTHON_PACKAGES_DIRECTORY}/${A_TARGET_DIRECTORY})
endif()


file(GLOB_RECURSE files RELATIVE ${A_SOURCE_DIRECTORY} ${A_SOURCE_DIRECTORY}/*)
foreach(file_relative_path ${files})
set(file_absolute_path ${A_SOURCE_DIRECTORY}/${file_relative_path})
configure_file(
${file_absolute_path}
${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/${SP3_PYTHON_PACKAGES_DIRECTORY}/${A_TARGET_DIRECTORY}/${file_relative_path}
${OUTPUT_DIRECTORY}/${file_relative_path}
@ONLY
)
get_filename_component(relative_directory ${file_relative_path} DIRECTORY)
install(
FILES "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/${SP3_PYTHON_PACKAGES_DIRECTORY}/${A_TARGET_DIRECTORY}/${file_relative_path}"
FILES "${OUTPUT_DIRECTORY}/${file_relative_path}"
DESTINATION "${LIBRARY_OUTPUT_DIRECTORY}/${SP3_PYTHON_PACKAGES_DIRECTORY}/${A_TARGET_DIRECTORY}/${relative_directory}"
)
endforeach()
Expand Down Expand Up @@ -117,7 +123,7 @@ function(SP3_add_python_module)

find_package(pybind11 CONFIG QUIET REQUIRED)

pybind11_add_module(${A_TARGET} SHARED "${A_SOURCES}")
pybind11_add_module(${A_TARGET} SHARED NO_EXTRAS "${A_SOURCES}")
add_library(SofaPython3::${A_TARGET} ALIAS ${A_TARGET})

target_include_directories(${A_TARGET}
Expand All @@ -131,10 +137,8 @@ function(SP3_add_python_module)

if (NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
target_compile_options(${A_TARGET} PRIVATE -Dregister=)
target_compile_options(${A_TARGET} PRIVATE -fvisibility=hidden)
endif()

target_link_libraries(${A_TARGET} PUBLIC pybind11::module)
target_link_libraries(${A_TARGET} PUBLIC "${A_DEPENDS}")

set_target_properties(
Expand Down
3 changes: 3 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,9 @@ set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

# Enable use of folder for IDE like VS
set_property(GLOBAL PROPERTY USE_FOLDERS ON)

# Set the minimum python version to 3.7
set(PYBIND11_PYTHON_VERSION 3.7)

Expand Down
23 changes: 12 additions & 11 deletions bindings/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
project(Bindings)

add_subdirectory(Sofa)
add_subdirectory(SofaRuntime)
add_subdirectory(SofaGui)
add_subdirectory(SofaTypes)
add_subdirectory(Modules)
set(BINDINGS_MODULE_LIST Sofa SofaRuntime SofaGui SofaTypes Modules)

foreach(bindings_module ${BINDINGS_MODULE_LIST})
add_subdirectory(${bindings_module})
endforeach()

if (SP3_WITH_SOFAEXPORTER)
add_subdirectory(SofaExporter)
Expand All @@ -13,12 +13,13 @@ endif()
add_library(${PROJECT_NAME} INTERFACE)
add_library(SofaPython3::${PROJECT_NAME} ALIAS ${PROJECT_NAME})

target_link_libraries(${PROJECT_NAME} INTERFACE ${PROJECT_NAME}.Modules)
target_link_libraries(${PROJECT_NAME} INTERFACE ${PROJECT_NAME}.Sofa)
target_link_libraries(${PROJECT_NAME} INTERFACE ${PROJECT_NAME}.SofaExporter)
target_link_libraries(${PROJECT_NAME} INTERFACE ${PROJECT_NAME}.SofaGui)
target_link_libraries(${PROJECT_NAME} INTERFACE ${PROJECT_NAME}.SofaRuntime)
target_link_libraries(${PROJECT_NAME} INTERFACE ${PROJECT_NAME}.SofaTypes)
foreach(bindings_module ${BINDINGS_MODULE_LIST})
target_link_libraries(${PROJECT_NAME} INTERFACE ${PROJECT_NAME}.${bindings_module})
endforeach()

if (SP3_WITH_SOFAEXPORTER)
target_link_libraries(${PROJECT_NAME} INTERFACE ${PROJECT_NAME}.SofaExporter)
endif()

configure_package_config_file(
"${CMAKE_CURRENT_SOURCE_DIR}/BindingsConfig.cmake.in"
Expand Down
13 changes: 11 additions & 2 deletions bindings/Modules/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
project(Bindings.Modules)

add_subdirectory(src/SofaPython3/SofaBaseTopology)
set(MODULEBINDINGS_MODULE_LIST SofaBaseTopology)

foreach(modulebindings_module ${MODULEBINDINGS_MODULE_LIST})
add_subdirectory(src/SofaPython3/${modulebindings_module})
endforeach()


add_library(${PROJECT_NAME} INTERFACE)
add_library(SofaPython3::${PROJECT_NAME} ALIAS ${PROJECT_NAME})

target_link_libraries(${PROJECT_NAME} INTERFACE ${PROJECT_NAME}.SofaBaseTopology)
foreach(modulebindings_module ${MODULEBINDINGS_MODULE_LIST})
target_link_libraries(${PROJECT_NAME} INTERFACE ${PROJECT_NAME}.${modulebindings_module})
set_target_properties(${PROJECT_NAME}.${modulebindings_module} PROPERTIES FOLDER "Bindings/Modules")
endforeach()

install(TARGETS ${PROJECT_NAME} EXPORT BindingsTargets)
18 changes: 8 additions & 10 deletions bindings/Sofa/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
project(Bindings.Sofa)

add_subdirectory(src/SofaPython3/Sofa/Core)
add_subdirectory(src/SofaPython3/Sofa/Components)
add_subdirectory(src/SofaPython3/Sofa/Helper)
add_subdirectory(src/SofaPython3/Sofa/Simulation)
add_subdirectory(src/SofaPython3/Sofa/Types)
set(SOFABINDINGS_MODULE_LIST Core Components Helper Simulation Types)

foreach(sofabindings_module ${SOFABINDINGS_MODULE_LIST})
add_subdirectory(src/SofaPython3/Sofa/${sofabindings_module})
endforeach()

SP3_add_python_package(
SOURCE_DIRECTORY
Expand All @@ -16,11 +16,9 @@ SP3_add_python_package(
add_library(${PROJECT_NAME} INTERFACE)
add_library(SofaPython3::${PROJECT_NAME} ALIAS ${PROJECT_NAME})

target_link_libraries(${PROJECT_NAME} INTERFACE ${PROJECT_NAME}.Core)
target_link_libraries(${PROJECT_NAME} INTERFACE ${PROJECT_NAME}.Components)
target_link_libraries(${PROJECT_NAME} INTERFACE ${PROJECT_NAME}.Helper)
target_link_libraries(${PROJECT_NAME} INTERFACE ${PROJECT_NAME}.Simulation)
target_link_libraries(${PROJECT_NAME} INTERFACE ${PROJECT_NAME}.Types)
foreach(sofabindings_module ${SOFABINDINGS_MODULE_LIST})
target_link_libraries(${PROJECT_NAME} INTERFACE ${PROJECT_NAME}.${sofabindings_module})
endforeach()

install(TARGETS ${PROJECT_NAME} EXPORT BindingsTargets)

Expand Down
137 changes: 2 additions & 135 deletions bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Base.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,145 +34,12 @@ along with sofaqtquick. If not, see <http://www.gnu.org/licenses/>.

namespace sofapython3 {

/**
* This is the main pybind11 type holder that will manage the underlying reference counter of the SOFA C++ objects. It
* should be used when creating bindings for a C++ class that inherits sofa::core::objectmodel::Base.
*
* \note There is a problem in pybind11 which sometime does a kind of slicing between the python object and its bound
* C++ object. This usually happens when instantiating a virtual (trampoline) class in python that then calls the
* new operator in the pybind11::init() and return the newly created object. Python will sometime destroy the
* initial object before the C++ one is created. We go around this by keeping here a reference to the initial
* python object, hence incrementing its reference counter by one.
*
* See https://github.com/pybind/pybind11/issues/1546 for more details.
* @tparam T
*/

template <typename T>
struct py_shared_ptr : public sofa::core::sptr<T> {
using Base = sofa::core::sptr<T>;
using Base::Base;

py_shared_ptr(const sofa::core::sptr<T> & sptr) : Base(sptr) {}

py_shared_ptr(const sofa::core::sptr<T> & sptr, T * ptr) : Base(ptr) {}

py_shared_ptr(const py_shared_ptr & py_ptr) : Base(py_ptr) {
p_object = py_ptr.p_object;
}

py_shared_ptr(py_shared_ptr & py_ptr) : Base(py_ptr) {
p_object = py_ptr.p_object;
}

void set_object(const pybind11::object & o) {
p_object = o;
}

private:
pybind11::object p_object;
};
using py_shared_ptr = sofa::core::sptr<T>;

} // namespace sofapython3

// Type caster for SP3 and SOFA holders
namespace pybind11::detail {
/**
* This is an alias type caster that converts sofa::core::sptr<T> to sofapython3::py_shared_ptr<T>.
* It is needed for when bound C++ function returns sofa::core::sptr instead of py_shared_ptr while the holder
* type was set to the latter.
* @tparam T
*/
template <typename T>
class type_caster<sofa::core::sptr<T>> {

PYBIND11_TYPE_CASTER (sofa::core::sptr<T> , _("sofa::core::sptr<T>"));

using BaseCaster = copyable_holder_caster<T, sofapython3::py_shared_ptr<T>>;

bool load (pybind11::handle src, bool b)
{
// First make sure the py::object is an instanced of sofapython3::py_shared_ptr<T>
BaseCaster bc;
bool success = bc.load (src, b);
if (!success) {
return false;
}

// Convert the holder_caster to a sofapython3::py_shared_ptr<T> instance
auto base_ptr = static_cast<sofapython3::py_shared_ptr<T>> (bc);

// Take ownership of the py::object
auto h = BaseCaster::cast(base_ptr, return_value_policy(), handle());
auto py_obj = reinterpret_borrow<object>(h);

// Save a copy into the holder so that it doesn't get deleted and thereby creating slicing
base_ptr.set_object(py_obj);

// Set the value to the ptr
value = sofa::core::sptr<T> (base_ptr);
return true;
}

static handle cast (sofa::core::sptr<T> sp,
return_value_policy rvp,
handle h)
{
return BaseCaster::cast (sp, rvp, h);
}
};

template <typename T>
struct always_construct_holder<sofapython3::py_shared_ptr<T>> : always_construct_holder<void, true> { };

/**
* Main type caster that converts python objects to C++ sofapython3::py_shared_ptr<T> objects, and the inverse.
* To avoid slicing (see sofapython3::py_shared_ptr), it will preserve the initial python object when the initial
* python -> C++ conversion happens.
* @tparam T
*/
template <typename T>
class type_caster<sofapython3::py_shared_ptr<T>> {

PYBIND11_TYPE_CASTER (sofapython3::py_shared_ptr<T> , _("sofapython3::py_shared_ptr<T>"));

using BaseCaster = copyable_holder_caster<T, sofapython3::py_shared_ptr<T>>;

bool load (pybind11::handle src, bool b)
{
// First make sure the py::object is an instanced of sofapython3::py_shared_ptr<T>
BaseCaster bc;
bool success = bc.load (src, b);
if (!success) {
return false;
}

// Convert the holder_caster to a sofapython3::py_shared_ptr<T> instance
auto base_ptr = static_cast<sofapython3::py_shared_ptr<T>> (bc);

// Take ownership of the py::object
auto h = BaseCaster::cast(base_ptr, return_value_policy(), handle());
auto py_obj = reinterpret_borrow<object>(h);

// Save a copy into the holder so that it doesn't get deleted and thereby creating slicing
base_ptr.set_object(py_obj);

// Set the value to the ptr
value = base_ptr;
return true;
}

static handle cast (sofapython3::py_shared_ptr<T> sp,
return_value_policy rvp,
handle h)
{
return BaseCaster::cast (sp, rvp, h);
}
};

template <typename T>
struct is_holder_type<T, sofapython3::py_shared_ptr<T>> : std::true_type {};
}
PYBIND11_DECLARE_HOLDER_TYPE(T, sofapython3::py_shared_ptr<T>, true)

namespace sofapython3 {

Expand Down
9 changes: 4 additions & 5 deletions bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -150,12 +150,11 @@ py_shared_ptr<Node> __init__(const std::string& name) {
/// Method: init (beware this is not the python __init__, this is sofa's init())
void init(Node& self) { self.init(ExecParams::defaultInstance()); }

py::object addObject(Node& self, const py::object & object)
py::object addObject(Node& self, BaseObject * object)
{
try {
auto base_object = py::cast<py_shared_ptr<BaseObject>>(object);
if (self.addObject(base_object))
return object;
if (self.addObject(object))
return PythonFactory::toPython(object);
} catch (...) {
throw py::type_error("Trying to add an object that isn't derived from sofa::core::objectmodel::BaseObject.");
}
Expand Down Expand Up @@ -483,7 +482,7 @@ void moduleAddNode(py::module &m) {
p.def("init", &init, sofapython3::doc::sofa::core::Node::initSofa );
p.def("add", &addKwargs, sofapython3::doc::sofa::core::Node::addKwargs);
p.def("addObject", &addObjectKwargs, sofapython3::doc::sofa::core::Node::addObjectKwargs);
p.def("addObject", &addObject, sofapython3::doc::sofa::core::Node::addObject);
p.def("addObject", &addObject, sofapython3::doc::sofa::core::Node::addObject, py::keep_alive<0, 2>());
p.def("createObject", &createObject, sofapython3::doc::sofa::core::Node::createObject);
p.def("addChild", &addChildKwargs, sofapython3::doc::sofa::core::Node::addChildKwargs);
p.def("addChild", &addChild, sofapython3::doc::sofa::core::Node::addChild);
Expand Down
28 changes: 14 additions & 14 deletions bindings/Sofa/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ enable_testing()
add_executable(${PROJECT_NAME} ${SOURCE_FILES} ${HEADER_FILES} ${PYTHON_FILES})
target_link_libraries(${PROJECT_NAME} SofaGTestMain SofaHelper SofaPython3::Plugin SofaPython3::Bindings.Sofa SofaPython3::Bindings.SofaTypes SofaPython3::Bindings.SofaRuntime)
target_compile_definitions(${PROJECT_NAME} PRIVATE "PYTHON_TESTFILES_DIR=\"${CMAKE_CURRENT_SOURCE_DIR}/\"")
set_target_properties(${PROJECT_NAME} PROPERTIES FOLDER "Bindings/Tests")

set(RPATH "$ORIGIN/../lib")
if (APPLE)
Expand All @@ -54,20 +55,19 @@ set_target_properties(

add_test(NAME ${PROJECT_NAME} COMMAND ${PROJECT_NAME})

SP3_configure_directory(${CMAKE_CURRENT_SOURCE_DIR}/Components ${CMAKE_BINARY_DIR}/${RUNTIME_OUTPUT_DIRECTORY}/Components)
install(DIRECTORY ${CMAKE_BINARY_DIR}/${RUNTIME_OUTPUT_DIRECTORY}/Components DESTINATION ${RUNTIME_OUTPUT_DIRECTORY})

SP3_configure_directory(${CMAKE_CURRENT_SOURCE_DIR}/Core ${CMAKE_BINARY_DIR}/${RUNTIME_OUTPUT_DIRECTORY}/Core)
install(DIRECTORY ${CMAKE_BINARY_DIR}/${RUNTIME_OUTPUT_DIRECTORY}/Core DESTINATION ${RUNTIME_OUTPUT_DIRECTORY})

SP3_configure_directory(${CMAKE_CURRENT_SOURCE_DIR}/Helper ${CMAKE_BINARY_DIR}/${RUNTIME_OUTPUT_DIRECTORY}/Helper)
install(DIRECTORY ${CMAKE_BINARY_DIR}/${RUNTIME_OUTPUT_DIRECTORY}/Helper DESTINATION ${RUNTIME_OUTPUT_DIRECTORY})

SP3_configure_directory(${CMAKE_CURRENT_SOURCE_DIR}/Simulation ${CMAKE_BINARY_DIR}/${RUNTIME_OUTPUT_DIRECTORY}/Simulation)
install(DIRECTORY ${CMAKE_BINARY_DIR}/${RUNTIME_OUTPUT_DIRECTORY}/Simulation DESTINATION ${RUNTIME_OUTPUT_DIRECTORY})

SP3_configure_directory(${CMAKE_CURRENT_SOURCE_DIR}/Types ${CMAKE_BINARY_DIR}/${RUNTIME_OUTPUT_DIRECTORY}/Types)
install(DIRECTORY ${CMAKE_BINARY_DIR}/${RUNTIME_OUTPUT_DIRECTORY}/Types DESTINATION ${RUNTIME_OUTPUT_DIRECTORY})
set(DIR_BINDING_LIST Components Core Helper Simulation Types)
get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
foreach(dir_binding ${DIR_BINDING_LIST})
if (_isMultiConfig) # MSVC
foreach(config_type ${CMAKE_CONFIGURATION_TYPES})
SP3_configure_directory(${CMAKE_CURRENT_SOURCE_DIR}/${dir_binding} ${CMAKE_BINARY_DIR}/${RUNTIME_OUTPUT_DIRECTORY}/${config_type}/${dir_binding})
install(DIRECTORY ${CMAKE_BINARY_DIR}/${RUNTIME_OUTPUT_DIRECTORY}/${config_type}/${dir_binding} DESTINATION ${RUNTIME_OUTPUT_DIRECTORY})
endforeach()
else()
SP3_configure_directory(${CMAKE_CURRENT_SOURCE_DIR}/${dir_binding} ${CMAKE_BINARY_DIR}/${RUNTIME_OUTPUT_DIRECTORY}/${dir_binding})
install(DIRECTORY ${CMAKE_BINARY_DIR}/${RUNTIME_OUTPUT_DIRECTORY}/${dir_binding} DESTINATION ${RUNTIME_OUTPUT_DIRECTORY})
endif()
endforeach()

install(
TARGETS ${PROJECT_NAME}
Expand Down
1 change: 1 addition & 0 deletions bindings/Sofa/tests/Core/ForceField.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ def createParticle(node, node_name, use_implicit_scheme, use_iterative_solver):
def rssffScene(use_implicit_scheme=True, use_iterative_solver=True):
SofaRuntime.importPlugin("SofaSparseSolver")
SofaRuntime.importPlugin("SofaExplicitOdeSolver")
SofaRuntime.importPlugin("SofaImplicitOdeSolver")
node = Sofa.Core.Node("root")
node.gravity = [0, -10, 0]
createParticle(node, "particle", use_implicit_scheme, use_iterative_solver)
Expand Down
Loading