diff --git a/CMakeLists.txt b/CMakeLists.txt index 9603e10f..f119d504 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,11 +34,8 @@ include(SofaPython3Tools) # OPTIONS include(CMakeDependentOption) -if (SP3_COMPILED_AS_SOFA_SUBPROJECT) - option(SP3_BUILD_TEST "Compile the automatic tests for SofaPython3, along with the gtest library." ${SOFA_BUILD_TESTS}) -else() - option(SP3_BUILD_TEST "Compile the automatic tests for SofaPython3, along with the gtest library." ON) -endif() +# If SOFA_BUILD_TESTS exists and is OFF, then this option will be auto-disabled +cmake_dependent_option(SP3_BUILD_TEST "Compile the automatic tests for SofaPython3, along with the gtest library." ON "SOFA_BUILD_TESTS OR NOT DEFINED SOFA_BUILD_TESTS" OFF) find_package(SofaExporter QUIET) CMAKE_DEPENDENT_OPTION(SP3_WITH_SOFAEXPORTER "Bind the SOFA exporter component." ON "SofaExporter_FOUND" OFF) @@ -83,20 +80,7 @@ set(PYBIND11_PYTHON_VERSION 3.7) # Find Python3 executable and set PYTHON_EXECUTABLE before finding pybind11 # to be sure that pybind11 relies on the right Python version -set(python_version "${PYBIND11_PYTHON_VERSION}") -set(python_version_flag "") -if(PYTHON_EXECUTABLE) - execute_process( - COMMAND "${PYTHON_EXECUTABLE}" "--version" - OUTPUT_VARIABLE cmd_output - ) - string(REGEX MATCH "[0-9]+\.[0-9]+" python_exec_version "${cmd_output}") - if(python_exec_version VERSION_GREATER_EQUAL PYBIND11_PYTHON_VERSION) - set(python_version "${python_exec_version}") - set(python_version_flag "EXACT") - endif() -endif() -find_package(Python ${python_version} ${python_version_flag} COMPONENTS Interpreter Development REQUIRED) +find_package(Python ${PYBIND11_PYTHON_VERSION} COMPONENTS Interpreter Development REQUIRED) set(PYTHON_VERSION ${Python_VERSION}) set(PYTHON_EXECUTABLE ${Python_EXECUTABLE}) set(PYTHON_LIBRARIES ${Python_LIBRARIES}) diff --git a/Plugin/src/SofaPython3/PythonEnvironment.cpp b/Plugin/src/SofaPython3/PythonEnvironment.cpp index 4959b7f5..4dc4c5d9 100644 --- a/Plugin/src/SofaPython3/PythonEnvironment.cpp +++ b/Plugin/src/SofaPython3/PythonEnvironment.cpp @@ -118,6 +118,8 @@ PythonEnvironmentData* PythonEnvironment::getStaticData() return m_staticdata; } +std::string PythonEnvironment::pluginLibraryPath = ""; + SOFAPYTHON3_API py::module PythonEnvironment::importFromFile(const std::string& module, const std::string& path, py::object* globals) { PythonEnvironment::gil lock; @@ -238,6 +240,17 @@ void PythonEnvironment::Init() // python modules are automatically reloaded at each scene loading //setAutomaticModuleReload( true ); + + // Initialize pluginLibraryPath by reading PluginManager's map + std::map& map = PluginManager::getInstance().getPluginMap(); + for( const auto& elem : map) + { + Plugin p = elem.second; + if ( p.getModuleName() == sofa_tostring(SOFA_TARGET) ) + { + pluginLibraryPath = elem.first; + } + } } void PythonEnvironment::executePython(std::function cb) @@ -329,11 +342,6 @@ void PythonEnvironment::addPythonModulePathsForPlugins(const std::string& plugin added = true; } } - - if(!added) - { - msg_warning("PythonEnvironment") << "No python dir found in " << pluginsDirectory; - } } void PythonEnvironment::addPythonModulePathsForPluginsByName(const std::string& pluginName) @@ -352,7 +360,30 @@ void PythonEnvironment::addPythonModulePathsForPluginsByName(const std::string& return; } } - msg_warning("PythonEnvironment") << pluginName << " not found in PluginManager's map."; + msg_info("SofaPython3") << pluginName << " not found in PluginManager's map."; +} + +void PythonEnvironment::addPluginManagerCallback() +{ + PluginManager::getInstance().addOnPluginLoadedCallback(pluginLibraryPath, + [](const std::string& pluginLibraryPath, const Plugin& plugin) { + // WARNING: loaded plugin must be organized like plugin_name/lib/plugin_name.so + for ( auto path : sofa::helper::system::PluginRepository.getPaths() ) + { + std::string pluginRoot = FileSystem::cleanPath( path + "/" + plugin.getModuleName() ); + if ( FileSystem::exists(pluginRoot) && FileSystem::isDirectory(pluginRoot) ) + { + addPythonModulePathsForPlugins(pluginRoot); + return; + } + } + } + ); +} + +void PythonEnvironment::removePluginManagerCallback() +{ + PluginManager::getInstance().removeOnPluginLoadedCallback(pluginLibraryPath); } diff --git a/Plugin/src/SofaPython3/PythonEnvironment.h b/Plugin/src/SofaPython3/PythonEnvironment.h index 7c2a5d75..2236e072 100644 --- a/Plugin/src/SofaPython3/PythonEnvironment.h +++ b/Plugin/src/SofaPython3/PythonEnvironment.h @@ -57,6 +57,11 @@ class SOFAPYTHON3_API PythonEnvironment const std::string& path, pybind11::object* globals = nullptr); + /// Add a new callback in PluginManager to auto-add future + /// loaded plugins to sys.path + static void addPluginManagerCallback(); + static void removePluginManagerCallback(); + /// Add a path to sys.path, the list of search path for Python modules. static void addPythonModulePath(const std::string& path); @@ -134,6 +139,7 @@ class SOFAPYTHON3_API PythonEnvironment private: static PythonEnvironmentData* getStaticData() ; + static std::string pluginLibraryPath; }; } // namespace sofapython3 diff --git a/Plugin/src/SofaPython3/PythonTestExtractor.cpp b/Plugin/src/SofaPython3/PythonTestExtractor.cpp index 1f674eb9..d0594500 100644 --- a/Plugin/src/SofaPython3/PythonTestExtractor.cpp +++ b/Plugin/src/SofaPython3/PythonTestExtractor.cpp @@ -29,6 +29,8 @@ #include using sofa::helper::system::PluginManager; +#include + using sofa::helper::system::SetDirectory; namespace py = pybind11; diff --git a/Plugin/src/SofaPython3/initModule.cpp b/Plugin/src/SofaPython3/initModule.cpp index 63b9857b..4c2cd7af 100644 --- a/Plugin/src/SofaPython3/initModule.cpp +++ b/Plugin/src/SofaPython3/initModule.cpp @@ -52,6 +52,7 @@ void initExternalModule() PythonEnvironment::Init(); first = false; } + PythonEnvironment::addPluginManagerCallback(); } const char* getModuleName() diff --git a/SofaPython3Config.cmake.in b/SofaPython3Config.cmake.in index aa0c2be9..c9db0053 100644 --- a/SofaPython3Config.cmake.in +++ b/SofaPython3Config.cmake.in @@ -11,11 +11,7 @@ include(SofaPython3Tools) # Find Python3 executable and set PYTHON_EXECUTABLE before finding pybind11 # to be sure that pybind11 relies on the right Python version -set(python_version @PYTHON_VERSION@) -set(python_version_flag @python_version_flag@) - -find_package(Python ${python_version} ${python_version_flag} COMPONENTS Interpreter Development REQUIRED) - +find_package(Python @PYBIND11_PYTHON_VERSION@ COMPONENTS Interpreter Development REQUIRED) set(PYTHON_VERSION ${Python_VERSION}) set(PYTHON_EXECUTABLE ${Python_EXECUTABLE}) set(PYTHON_LIBRARIES ${Python_LIBRARIES}) diff --git a/bindings/CMakeLists.txt b/bindings/CMakeLists.txt index 4257e2a0..ab23b7a3 100644 --- a/bindings/CMakeLists.txt +++ b/bindings/CMakeLists.txt @@ -8,12 +8,16 @@ endif() # This will set rpaths relative to SP3 plugin library if(UNIX) set(CMAKE_INSTALL_RPATH + "$ORIGIN" + "$$ORIGIN" "$ORIGIN/../lib" "$$ORIGIN/../lib" ) if(APPLE) set(CMAKE_MACOSX_RPATH ON) list(APPEND CMAKE_INSTALL_RPATH + "@loader_path" + "@executable_path" "@loader_path/../lib" "@executable_path/../lib" ) diff --git a/bindings/Modules/tests/main.cpp b/bindings/Modules/tests/main.cpp index 028ac5b1..64125d49 100644 --- a/bindings/Modules/tests/main.cpp +++ b/bindings/Modules/tests/main.cpp @@ -24,6 +24,8 @@ #include #include +#include +using sofa::helper::logging::MessageDispatcher; /// static build of the test list diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Base.cpp b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Base.cpp index f8dc3021..65908db1 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Base.cpp +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Base.cpp @@ -126,16 +126,8 @@ void BindingBase::SetAttr(py::object self, const std::string& s, py::object valu return; } - /// We are falling back to dynamically adding the objet into the object dict. - py::dict t = self.attr("__dict__"); - if(!t.is_none()) - { - t[s.c_str()] = value; - return; - } - - /// Well this should never happen unless there is no __dict__ - throw py::attribute_error("Unable to set attribute '"+s+"', unknow data type"); + // If it's not a data or a link, rely on object implementation of __setattr__ + py::module::import("builtins").attr("object").attr("__setattr__")(self, s, value); } void BindingBase::SetAttr(Base& self, const std::string& s, py::object value) diff --git a/bindings/Sofa/tests/PythonModule_Sofa_test.cpp b/bindings/Sofa/tests/PythonModule_Sofa_test.cpp index 81ee5a06..5bcdc374 100644 --- a/bindings/Sofa/tests/PythonModule_Sofa_test.cpp +++ b/bindings/Sofa/tests/PythonModule_Sofa_test.cpp @@ -31,6 +31,7 @@ using std::string; #include #include +#include using sofa::helper::logging::MessageDispatcher; using sofa::helper::logging::MainPerComponentLoggingMessageHandler; diff --git a/bindings/SofaGui/src/SofaPython3/SofaGui/Module_SofaGui.cpp b/bindings/SofaGui/src/SofaPython3/SofaGui/Module_SofaGui.cpp index 0ec7a1e5..85f0a9d8 100644 --- a/bindings/SofaGui/src/SofaPython3/SofaGui/Module_SofaGui.cpp +++ b/bindings/SofaGui/src/SofaPython3/SofaGui/Module_SofaGui.cpp @@ -22,6 +22,14 @@ #include #include +#include +#include +#include +using sofa::helper::system::FileSystem; + +#if SOFAGUI_HAVE_SOFAGUIQT +#include +#endif // SOFAGUI_HAVE_SOFAGUIQT #include "Binding_BaseGui.h" #include "Binding_GUIManager.h" @@ -55,6 +63,26 @@ PYBIND11_MODULE(Gui, m) { :members: )doc"; +#if SOFAGUI_HAVE_SOFAGUIQT + std::string sofaPrefixAbsolute = sofa::helper::Utils::getSofaPathPrefix(); + std::string inputFilepath = FileSystem::cleanPath(sofaPrefixAbsolute + "/bin/qt.conf"); + bool success = sofa::gui::qt::loadQtConfWithCustomPrefix(inputFilepath, sofaPrefixAbsolute); + if(success) + { + msg_info("Sofa.Gui") << "Loaded qt.conf from " << inputFilepath << " customized with Prefix = " << sofaPrefixAbsolute; + } + else + { + msg_warning("Sofa.Gui") << "Failed loading and/or customizing qt.conf from " << inputFilepath; + + std::cout << "qt_resource_data:" << std::endl; + for (int i = 0 ; i < qt_resource_data.size() ; ++i) { + std::cout << qt_resource_data[i]; + } + std::cout << std::endl; + } +#endif // SOFAGUI_HAVE_SOFAGUIQT + // This is needed to make sure the GuiMain library (libSofaGuiMain.so) is correctly // linked since the GUIs are statically created during the load of the library. sofa::gui::initSofaGui(); @@ -63,4 +91,5 @@ PYBIND11_MODULE(Gui, m) { moduleAddBaseGui(m); moduleAddGuiManager(m); } -} \ No newline at end of file + +} // namespace sofapython3 diff --git a/bindings/SofaRuntime/src/SofaPython3/SofaRuntime/Timer/Submodule_Timer.cpp b/bindings/SofaRuntime/src/SofaPython3/SofaRuntime/Timer/Submodule_Timer.cpp index 9bab6e14..e2cd11f1 100644 --- a/bindings/SofaRuntime/src/SofaPython3/SofaRuntime/Timer/Submodule_Timer.cpp +++ b/bindings/SofaRuntime/src/SofaPython3/SofaRuntime/Timer/Submodule_Timer.cpp @@ -18,13 +18,13 @@ * Contact information: contact@sofa-framework.org * ******************************************************************************/ -#include -#include -using sofa::helper::AdvancedTimer; - #include "Submodule_Timer.h" #include "Submodule_Timer_doc.h" +#include +#include +using sofa::helper::AdvancedTimer; + #include #include diff --git a/bindings/SofaRuntime/tests/PythonModule_SofaRuntime_test.cpp b/bindings/SofaRuntime/tests/PythonModule_SofaRuntime_test.cpp index 49f722f3..cb43a625 100644 --- a/bindings/SofaRuntime/tests/PythonModule_SofaRuntime_test.cpp +++ b/bindings/SofaRuntime/tests/PythonModule_SofaRuntime_test.cpp @@ -31,6 +31,7 @@ using std::string; #include #include +#include using sofa::helper::logging::MessageDispatcher; using sofa::helper::logging::MainPerComponentLoggingMessageHandler;