From 171814cc5a36305066b17ec1f55f15a01adfdbf8 Mon Sep 17 00:00:00 2001 From: David Wagner Date: Wed, 21 Jan 2015 15:56:54 +0100 Subject: bindings: bind ILogger and setLogger() This will allow users of the parameter-framework bindings to set a logger; without it, the parameter-framework wasn't able to log anything. Some SWIG features and workarounds must be activated in order to: - Support nested classes; - Derive bound classes and allow C++ to call back the user-created objects; - Properly handle exceptions that may be raised upon errors happening on the user side. Change-Id: I955152a4658eff3307ad595f175f2624a3acfa8c Signed-off-by: David Wagner --- bindings/python/Android.mk | 6 +++++- bindings/python/CMakeLists.txt | 10 +++++++--- bindings/python/pfw.i | 38 +++++++++++++++++++++++++++++++++++++- bindings/python/sample.py | 19 +++++++++++++++++++ 4 files changed, 68 insertions(+), 5 deletions(-) (limited to 'bindings') diff --git a/bindings/python/Android.mk b/bindings/python/Android.mk index 2cfd13d..296d4bc 100644 --- a/bindings/python/Android.mk +++ b/bindings/python/Android.mk @@ -48,7 +48,11 @@ LOCAL_C_INCLUDES := \ # The 'unused-but-set-variable' warning must be disabled because SWIG generates # files that do not respect that constraint. -LOCAL_CFLAGS := -Wno-unused-but-set-variable -fexceptions +# '-DSWIG_PYTHON_SILENT_MEMLEAK' is needed because the "memleak" warning +# pollutes the standard output. At the time of writing, the only warning is +# spurious anyway, as it relates to "ILogger *" which is an abstract +# class/interface class and as such cannot be destroyed. +LOCAL_CFLAGS := -Wno-unused-but-set-variable -fexceptions -DSWIG_PYTHON_SILENT_MEMLEAK # Undefined symbols will be resolved at runtime LOCAL_ALLOW_UNDEFINED_SYMBOLS := true diff --git a/bindings/python/CMakeLists.txt b/bindings/python/CMakeLists.txt index 535c920..e9016b1 100644 --- a/bindings/python/CMakeLists.txt +++ b/bindings/python/CMakeLists.txt @@ -48,9 +48,13 @@ endif(NOT PYTHONLIBS_FOUND) include_directories(${PROJECT_SOURCE_DIR}/parameter/include ${PYTHON_INCLUDE_DIRS}) -# Add some exceptions because files generated by SWIG are not -# "-Wextra"-compliant -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-but-set-variable") +# The 'unused-but-set-variable' warning must be disabled because SWIG generates +# files that do not respect that contraint. +# '-DSWIG_PYTHON_SILENT_MEMLEAK' is needed because the "memleak" warning +# pollutes the standard output. At the time of writing, the only warning is +# spurious anyway, as it relates to "ILogger *" which is an abstract +# class/interface class and as such cannot be destroyed. +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-but-set-variable -DSWIG_PYTHON_SILENT_MEMLEAK") install(TARGETS _PyPfw LIBRARY DESTINATION lib) diff --git a/bindings/python/pfw.i b/bindings/python/pfw.i index c029d13..da01cdc 100644 --- a/bindings/python/pfw.i +++ b/bindings/python/pfw.i @@ -27,7 +27,22 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -%module PyPfw +// The generated python module will be named "PyPfw" +// the "directors" feature is used to derive Python classes and make them look +// like derived C++ classes (calls to virtual methods will be properly +// forwarded to Python) - only on classes for which is it specified, see +// ILogger below.. +%module(directors="1") PyPfw + +%feature("director:except") { + if ($error != NULL) { + throw Swig::DirectorMethodException(); + } +} +%exception { + try { $action } + catch (Swig::DirectorException &e) { SWIG_fail; } +} %include "std_string.i" %include "std_vector.i" @@ -63,6 +78,8 @@ public: bool start(std::string& strError); + void setLogger(ILogger* pLogger); + ISelectionCriterionTypeInterface* createSelectionCriterionType(bool bIsInclusive); ISelectionCriterionInterface* createSelectionCriterion(const std::string& strName, const ISelectionCriterionTypeInterface* pSelectionCriterionType); @@ -155,6 +172,25 @@ public: %clear std::string& strResult; }; +// SWIG nested class support is not complete - cf. +// http://swig.org/Doc2.0/SWIGPlus.html#SWIGPlus_nested_classes +// This link also explains how to trick SWIG and pretend that +// ILogger is a toplevel class (whereas it actually is an inner class of +// CParameterMgrFullConnector +// Logger interface +%feature("director") ILogger; +%nestedworkaround CParameterMgrFullConnector::ILogger; +class ILogger +{ + public: + virtual void log(bool bIsWarning, const std::string& strLog) = 0; + protected: + virtual ~ILogger() {} +}; +%{ +typedef CParameterMgrFullConnector::ILogger ILogger; +%} + class ISelectionCriterionTypeInterface { %{ diff --git a/bindings/python/sample.py b/bindings/python/sample.py index f33ddeb..1208fc9 100755 --- a/bindings/python/sample.py +++ b/bindings/python/sample.py @@ -29,9 +29,28 @@ import PyPfw import sys +import logging + +class MyLogger(PyPfw.ILogger): + def __init__(self): + # Calling the base constructor is necessary: if you don't, MyLogger + # won't be recognised as a derived class of PyPfw.ILogger + super(MyLogger, self).__init__() + + def log(self, is_warning, log): + log_func = logging.warning if is_warning else logging.info + log_func(log) + + +logging.root.setLevel(logging.INFO) pfw = PyPfw.ParameterFramework(sys.argv[1]) +# warning: don't pass MyLogger() directly as argument to setLogger() or it will +# be garbage collected +mylogger = MyLogger() +pfw.setLogger(mylogger); + moodType = pfw.createSelectionCriterionType(False) for numerical, literal in enumerate(["mad", "sad", "glad"]): moodType.addValuePair(numerical, literal) -- cgit v1.1