Commit 0ba91e13 authored by NICLAUSSE Nicolas's avatar NICLAUSSE Nicolas
Browse files

Merge branch 'feature/sipwrapping' into develop

parents 083f908f 2bcf16e3
......@@ -365,20 +365,16 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/dtkConfigVersion.cmake.in
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/dtkSetTestEnvironment.cmake.in
"${CMAKE_CURRENT_BINARY_DIR}/dtkSetTestEnvironment.cmake" @ONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/dtkCodeCoverage.cmake
"${CMAKE_CURRENT_BINARY_DIR}/dtkCodeCoverage.cmake" @ONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/dtkWrap.cmake
"${CMAKE_CURRENT_BINARY_DIR}/dtkWrap.cmake" COPYONLY)
set_directory_properties(PROPERTIES TEST_INCLUDE_FILE "${CMAKE_CURRENT_BINARY_DIR}/dtkSetTestEnvironment.cmake")
install(FILES
"${CMAKE_CURRENT_BINARY_DIR}/install/dtkConfig.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/dtkConfigVersion.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/dtkCodeCoverage.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/dtkWrap.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/dtkSetTestEnvironment.cmake"
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/dtkCodeCoverage.cmake"
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/dtkWrap.cmake"
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/FindSIP.cmake"
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/FindSIP.py"
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/dtk)
install(EXPORT dtkDepends DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/dtk)
......
# Find SIP
# ~~~~~~~~
#
# SIP website: http://www.riverbankcomputing.co.uk/sip/index.php
#
# Find the installed version of SIP. FindSIP should be called after Python
# has been found.
#
# This file defines the following variables:
#
# SIP_VERSION - The version of SIP found expressed as a 6 digit hex number
# suitable for comparison as a string.
#
# SIP_VERSION_STR - The version of SIP found as a human readable string.
#
# SIP_EXECUTABLE - Path and filename of the SIP command line executable.
#
# SIP_INCLUDE_DIR - Directory holding the SIP C++ header file.
#
# SIP_DEFAULT_SIP_DIR - Default directory where .sip files should be installed
# into.
# Copyright (c) 2007, Simon Edwards <simon@simonzone.com>
# Redistribution and use is allowed according to the terms of the BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
# IF(SIP_VERSION)
# # Already in cache, be silent
# message("SIP already found")
# SET(SIP_FOUND TRUE)
# ELSE(SIP_VERSION)
FIND_FILE(_find_sip_py FindSIP.py PATHS ${CMAKE_MODULE_PATH})
EXECUTE_PROCESS(COMMAND ${PYTHON_EXECUTABLE} ${_find_sip_py} OUTPUT_VARIABLE sip_config)
IF(sip_config)
STRING(REGEX REPLACE "^sip_version:([^\n]+).*$" "\\1" SIP_VERSION_output ${sip_config})
set(SIP_VERSION ${SIP_VERSION_output} CACHE STRING "Sip version" FORCE)
STRING(REGEX REPLACE ".*\nsip_version_str:([^\n]+).*$" "\\1" SIP_VERSION_STR ${sip_config})
STRING(REGEX REPLACE ".*\nsip_bin:([^\n]+).*$" "\\1" SIP_EXECUTABLE_output ${sip_config})
set(SIP_EXECUTABLE ${SIP_EXECUTABLE_output} CACHE STRING "Sip executable" FORCE)
IF(NOT SIP_DEFAULT_SIP_DIR)
STRING(REGEX REPLACE ".*\ndefault_sip_dir:([^\n]+).*$" "\\1" SIP_DEFAULT_SIP_DIR ${sip_config})
set(SIP_MODULE_DIR ${SIP_DEFAULT_SIP_DIR} CACHE STRING "Sip default dir" FORCE)
set(PYQT5_MODULE_DIR "${SIP_DEFAULT_SIP_DIR}/PyQt5" CACHE STRING "PyQt5 module dir" FORCE)
ENDIF(NOT SIP_DEFAULT_SIP_DIR)
STRING(REGEX REPLACE ".*\nsip_inc_dir:([^\n]+).*$" "\\1" SIP_INCLUDE_DIR ${sip_config})
FILE(TO_CMAKE_PATH ${SIP_DEFAULT_SIP_DIR} SIP_DEFAULT_SIP_DIR)
FILE(TO_CMAKE_PATH ${SIP_INCLUDE_DIR} SIP_INCLUDE_DIR)
IF(EXISTS ${SIP_EXECUTABLE})
SET(SIP_FOUND TRUE)
SET(SIP_VERSION)
ELSE()
MESSAGE(STATUS "Found SIP configuration but the sip executable could not be found.")
ENDIF()
ELSE(sip_config)
MESSAGE(STATUS "Found SIP configuration but the sip executable did not output anything.")
ENDIF(sip_config)
IF(SIP_FOUND)
IF(NOT SIP_FIND_QUIETLY)
MESSAGE(STATUS "Found SIP version: ${SIP_VERSION_STR}")
ENDIF(NOT SIP_FIND_QUIETLY)
ELSE(SIP_FOUND)
IF(SIP_FIND_REQUIRED)
MESSAGE(FATAL_ERROR "Could not find SIP")
ENDIF(SIP_FIND_REQUIRED)
ENDIF(SIP_FOUND)
# ENDIF(SIP_VERSION)
# FindSIP.py
#
# Copyright (c) 2007, Simon Edwards <simon@simonzone.com>
# Redistribution and use is allowed according to the terms of the BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
import sys
import sipconfig
sipcfg = sipconfig.Configuration()
print("sip_version:%06.0x" % sipcfg.sip_version)
print("sip_version_str:%s" % sipcfg.sip_version_str)
print("sip_bin:%s" % sipcfg.sip_bin)
print("default_sip_dir:%s" % sipcfg.default_sip_dir)
print("sip_inc_dir:%s" % sipcfg.sip_inc_dir)
......@@ -35,7 +35,10 @@ set(dtk_INCLUDE_DIRS
"@CMAKE_CURRENT_BINARY_DIR@")
include("@CMAKE_BINARY_DIR@/dtkDepends.cmake")
include("@CMAKE_BINARY_DIR@/dtkWrap.cmake")
include("@CMAKE_SOURCE_DIR@/cmake/dtkWrap.cmake")
set(CMAKE_MODULE_PATH
${CMAKE_MODULE_PATH} "@CMAKE_SOURCE_DIR@/cmake/")
set_directory_properties(PROPERTIES TEST_INCLUDE_FILE "@CMAKE_BINARY_DIR@/dtkSetTestEnvironment.cmake")
......@@ -95,6 +98,7 @@ if(DTK_BUILD_SCRIPT)
endif(DTK_BUILD_SCRIPT)
if(DTK_BUILD_WRAPPERS)
set(DTK_PYTHON_WRAPPER @DTK_PYTHON_WRAPPER@)
set(DTK_WRAPPING_PYTHON @DTK_WRAPPING_PYTHON@)
set(DTK_WRAPPING_CSHARP @DTK_WRAPPING_CSHARP@)
set(DTK_WRAPPING_TCL @DTK_WRAPPING_TCL@)
......
......@@ -14,11 +14,54 @@
if(DTK_BUILD_WRAPPERS)
mark_as_advanced(SWIG_DIR)
mark_as_advanced(SWIG_EXECUTABLE)
mark_as_advanced(SWIG_VERSION)
if(NOT DTK_PYTHON_WRAPPER)
set(DTK_PYTHON_WRAPPER SWIG CACHE STRING "Choose the type of python wrapping")
else()
set(DTK_PYTHON_WRAPPER ${DTK_PYTHON_WRAPPER} CACHE STRING "dtk python wrapper")
endif()
set_property(CACHE DTK_PYTHON_WRAPPER PROPERTY STRINGS "SWIG" "SIP")
if(DTK_PYTHON_WRAPPER MATCHES "SIP")
if(APPLE)
set(SIP_DEFAULT_SIP_DIR "/System/Library/Frameworks/Python.framework/Versions/2.7/share/sip")
set(SIP_MODULE_DIR ${SIP_DEFAULT_SIP_DIR})
set(PYQT5_MODULE_DIR "${SIP_DEFAULT_SIP_DIR}/PyQt5")
endif()
find_package(SIP)
else()
find_package(SWIG QUIET)
endif()
if(SIP_FOUND)
set(SIP_PLATFORM "WS_X11")
if(APPLE)
set(SIP_PLATFORM "WS_MACX")
endif()
if(WIN32)
set(SIP_PLATFORM "WS_WIN")
endif()
macro(dtk_wrap_sip project target name input includes deps)
set(wrap_output sip${name}cmodule.cpp ${includes})
find_package(SWIG QUIET)
add_custom_command(
OUTPUT ${wrap_output}
COMMAND ${SIP_EXECUTABLE}
ARGS
"-I" "${PYQT5_MODULE_DIR}/"
"-I" "${dtk_INCLUDE_DIR}/sip"
"-t" "${SIP_PLATFORM}"
"-c" "${CMAKE_CURRENT_BINARY_DIR}/"
${input}
MAIN_DEPENDENCY ${deps}
COMMENT "Wrapping ${input} to python SIP")
set(${target} ${${target}} ${wrap_output})
endmacro(dtk_wrap_sip)
endif(SIP_FOUND)
if(SWIG_FOUND)
......@@ -69,7 +112,9 @@ if(SWIG_FOUND)
else(SWIG_FOUND)
message("DTK_BUILD_WRAPPERS options requires SWIG.")
if(DTK_PYTHON_WRAPPER MATCHES 'SWIG')
message("DTK_BUILD_WRAPPERS options requires SWIG.")
endif(DTK_PYTHON_WRAPPER MATCHES 'SWIG')
endif(SWIG_FOUND)
......@@ -88,7 +133,7 @@ if(TCL_FOUND)
endif(TCL_FOUND)
if(TCL_FOUND)
add_definitions(-DHAVE_TCL) # Towards deprecation
add_definitions(-DHAVE_TCL)
set(DTK_HAVE_TCL 1)
else(TCL_FOUND)
set(DTK_HAVE_TCL 0)
......@@ -113,6 +158,20 @@ else(PYTHONLIBS_FOUND)
set(DTK_HAVE_PYTHON 0)
endif(PYTHONLIBS_FOUND)
mark_as_advanced(SWIG_DIR)
mark_as_advanced(SWIG_EXECUTABLE)
mark_as_advanced(SWIG_VERSION)
mark_as_advanced(SIP_DIR)
mark_as_advanced(SIP_VERSION)
mark_as_advanced(SIP_EXECUTABLE)
mark_as_advanced(_find_sip_py)
mark_as_advanced(SIP_DEFAULT_SIP_DIR)
mark_as_advanced(PYQT5_MODULE_DIR)
mark_as_advanced(Qt5DIR)
mark_as_advanced(SIP_MODULE_DIR)
endif(DTK_BUILD_WRAPPERS)
######################################################################
......
// SIP support for dtkArray.h
// by Giovanni Bajo <rasky <at> develer.com>
// Public domain
// ****************************************************
// SIP generic implementation for dtkArray.h
// ****************************************************
// ALas, this template-based generic implementation is valid only
// if the element type is a SIP-wrapped type. For basic types (int, double, etc.)
// we are forced to cut & paste to provide a specialization.
template<TYPE>
%MappedType dtkArray<TYPE>
{
%TypeHeaderCode
#include <dtkCore/dtkArray.h>
%End
%ConvertFromTypeCode
PyObject *l = PyList_New(sipCpp -> size());
// Create the Python list of the correct length.
if (!l)
return NULL;
// Go through each element in the C++ instance and convert it to a
// wrapped P2d.
for (int i = 0; i < (int)sipCpp->size(); ++i) {
TYPE *cpp = new TYPE(sipCpp->at(i));
PyObject *pobj = sipConvertFromInstance(cpp, sipClass_TYPE, sipTransferObj);
// Get the Python wrapper for the Type instance, creating a new
// one if necessary, and handle any ownership transfer.
if (!pobj) {
// There was an error so garbage collect the Python list.
Py_DECREF(l);
return NULL;
}
// Add the wrapper to the list.
PyList_SET_ITEM(l, i, pobj);
}
// Return the Python list.
return l;
%End
%ConvertToTypeCode
// Check if type is compatible
if (!sipIsErr) {
// Must be any iterable
PyObject *i = PyObject_GetIter(sipPy);
bool iterable = (i != NULL);
Py_XDECREF(i);
return iterable;
}
// Iterate over the object
PyObject *iterator = PyObject_GetIter(sipPy);
PyObject *item;
dtkArray<TYPE> *V = new dtkArray<TYPE>();
while ((item = PyIter_Next(iterator)))
{
if (!sipCanConvertToInstance(item, sipClass_TYPE, SIP_NOT_NONE)) {
PyErr_Format(PyExc_TypeError, "object in iterable cannot be converted to TYPE");
*sipIsErr = 1;
break;
}
int state;
TYPE* p = reinterpret_cast<TYPE*>(
sipConvertToInstance(item, sipClass_TYPE, 0, SIP_NOT_NONE, &state, sipIsErr));
if (!*sipIsErr)
V->push_back(*p);
sipReleaseInstance(p, sipClass_TYPE, state);
Py_DECREF(item);
}
Py_DECREF(iterator);
if (*sipIsErr) {
delete V;
return 0;
}
*sipCppPtr = V;
return sipGetState(sipTransferObj);
%End
};
// ****************************************************
// Specialization for dtkArray<double>
// ****************************************************
%MappedType dtkArray<double>
{
%TypeHeaderCode
#include <dtkCore/dtkArray.h>
%End
%ConvertFromTypeCode
PyObject *l;
// Create the Python list of the correct length.
if ((l = PyList_New(sipCpp -> size())) == NULL)
return NULL;
// Go through each element in the C++ instance and convert it to a
// wrapped object.
for (int i = 0; i < (int)sipCpp -> size(); ++i)
{
// Add the wrapper to the list.
PyList_SET_ITEM(l, i, PyFloat_FromDouble(sipCpp -> at(i)));
}
// Return the Python list.
return l;
%End
%ConvertToTypeCode
// Check if type is compatible
if (sipIsErr == NULL)
{
// Must be any iterable
PyObject *i = PyObject_GetIter(sipPy);
bool iterable = (i != NULL);
Py_XDECREF(i);
return iterable;
}
// Iterate over the object
PyObject *iterator = PyObject_GetIter(sipPy);
PyObject *item;
// Maximum number of elements
int len = PyObject_Size(sipPy);
dtkArray<double> *V = new dtkArray<double>();
V->reserve(len);
if (len)
{
while ((item = PyIter_Next(iterator)))
{
if (!PyNumber_Check(item))
{
PyErr_Format(PyExc_TypeError, "object in iterable is not a number");
*sipIsErr = 1;
break;
}
PyObject *f = PyNumber_Float(item);
V->push_back(PyFloat_AsDouble(f));
Py_DECREF(f);
Py_DECREF(item);
}
Py_DECREF(iterator);
if (*sipIsErr)
{
delete V;
return 0;
}
}
*sipCppPtr = V;
return sipGetState(sipTransferObj);
%End
};
// ****************************************************
// Specialization for dtkArray<int>
// ****************************************************
%MappedType dtkArray<int>
{
%TypeHeaderCode
#include <dtkCore/dtkArray.h>
%End
%ConvertFromTypeCode
PyObject *l;
// Create the Python list of the correct length.
if ((l = PyList_New((SIP_SSIZE_T)sipCpp -> size())) == NULL)
return NULL;
// Go through each element in the C++ instance and convert it to a
// wrapped object.
for (int i = 0; i < (int)sipCpp -> size(); ++i)
{
// Add the wrapper to the list.
PyList_SET_ITEM(l, i, PyInt_FromLong(sipCpp -> at(i)));
}
// Return the Python list.
return l;
%End
%ConvertToTypeCode
// Check if type is compatible
if (sipIsErr == NULL)
{
// Must be any iterable
PyObject *i = PyObject_GetIter(sipPy);
bool iterable = (i != NULL);
Py_XDECREF(i);
return iterable;
}
// Iterate over the object
PyObject *iterator = PyObject_GetIter(sipPy);
PyObject *item;
// Maximum number of elements
int len = PyObject_Size(sipPy);
dtkArray<int> *V = new dtkArray<int>();
V->reserve(len);
if (len)
{
while ((item = PyIter_Next(iterator)))
{
if (!PyInt_Check(item))
{
PyErr_Format(PyExc_TypeError, "object in iterable cannot be converted to float");
*sipIsErr = 1;
break;
}
int val = PyInt_AsLong(item);
V->push_back(val);
Py_DECREF(item);
}
Py_DECREF(iterator);
if (*sipIsErr)
{
delete V;
return 0;
}
}
*sipCppPtr = V;
return sipGetState(sipTransferObj);
%End
};
// ****************************************************
// Specialization for dtkArray<long long>
// ****************************************************
%MappedType dtkArray<long long>
{
%TypeHeaderCode
#include <dtkCore/dtkArray.h>
%End
%ConvertFromTypeCode
PyObject *l;
// Create the Python list of the correct length.
if ((l = PyList_New(sipCpp -> size())) == NULL)
return NULL;
// Go through each element in the C++ instance and convert it to a
// wrapped object.
for (int i = 0; i < (int)sipCpp -> size(); ++i)
{
// Add the wrapper to the list.
PyList_SET_ITEM(l, i, PyInt_FromLong(sipCpp -> at(i)));
}
// Return the Python list.
return l;
%End
%ConvertToTypeCode
// Check if type is compatible
if (sipIsErr == NULL)
{
// Must be any iterable
PyObject *i = PyObject_GetIter(sipPy);
bool iterable = (i != NULL);
Py_XDECREF(i);
return iterable;
}
// Iterate over the object
PyObject *iterator = PyObject_GetIter(sipPy);
PyObject *item;
// Maximum number of elements
Py_ssize_t size = PyObject_Size(sipPy);
if (size == -1) {
Py_DECREF(iterator);
return 0;
}
unsigned int len = size;
dtkArray<long long> *V = new dtkArray<long long>();
V->reserve(len);
if (len)
{
while ((item = PyIter_Next(iterator)))
{
if (!PyInt_Check(item))
{
PyErr_Format(PyExc_TypeError, "object in iterable cannot be converted to float");
*sipIsErr = 1;
break;
}
long long val = PyInt_AsLong(item);
V->push_back(val);
Py_DECREF(item);
}
Py_DECREF(iterator);
if (*sipIsErr)
{
delete V;
return 0;
}
}
*sipCppPtr = V;
return sipGetState(sipTransferObj);
%End
};
class dtkCoreLayerManager
{
%TypeHeaderCode
#include <dtkCore/dtkCoreLayerManager.h>
%End
public:
dtkCoreLayerManager();
~dtkCoreLayerManager();
public:
void record(const QString& plugin_manager_name, dtkCorePluginManagerBase *plugin_manager);
void initialize();
void initialize(const QString& path);
void uninitialize();
void setVerboseLoading(bool value);
bool verboseLoading() const;
void setAutoLoading(bool value);
bool autoLoading() const;
};
class dtkCorePluginBase : public QObject
{
%TypeHeaderCode
#include <dtkCore/dtkCorePluginBase.h>
#include <QtCore>
%End
public:
virtual ~dtkCorePluginBase() ;
public:
virtual void initialize() = 0;
virtual void uninitialize() = 0;
virtual void *create() /Factory/;
};
template <TYPE> class dtkCorePluginFactory : public QObject
{
%TypeHeaderCode
#include <dtkCore/dtkCorePluginFactory.h>
%End
public:
dtkCorePluginFactory();
~dtkCorePluginFactory();
// https://www.riverbankcomputing.com/pipermail/pyqt/2009-June/023375.html
public:
// typedef TYPE *(*creator) ();
public:
void recordPlugin(const QString& key, dtkCorePluginBase *plugin);
public:
TYPE *create(const QString& key) const /Factory/ ;
public:
QStringList keys() const;
};