diff --git a/COMPILING_WINDOWS.md b/COMPILING_WINDOWS.md new file mode 100644 index 0000000..c37847b --- /dev/null +++ b/COMPILING_WINDOWS.md @@ -0,0 +1,35 @@ +# Compiling for Windows with Microsoft Tools # + +This branch compiles on Windows using the free (as in beer) Microsoft Visual +Studio 2008 Express Edition. This seems the easiest compiler to use for building +64bit (it is hard to build mex64 files with mingw-64 on windows). + +You will need: + +1. [Microsoft Visual Studio 2008 Express Edition](http://www.microsoft.com/express/downloads/) +2. [Microsoft Windows SDK](http://msdn.microsoft.com/en-us/windows/bb980924.aspx) +3. [Python 2.6 for Windows](http://python.org/download/) + +The SDK is only required for [64 bit](http://tinyurl.com/3afmcka) (it extends VS +Express Edition with 64 bit tools). I used *Microsoft Windows SDK for Windows 7 +and .NET Framework 3.5 Service Pack 1* (I think Framework 3.5 matches VS 2008 +version). With these installed you should be able to run `mex -setup`. + +With mex setup correctly there is a `makeall.m` file which runs a one line mex +command to build the package. You may need to adjust the paths there to point to +your Python installation. + +# Binaries # + +If MATLAB's `mexext` command tells you `mexw64`, then you may be able to skip +the compilation and just drop +[pymex.mexw64](http://cloud.github.com/downloads/robince/pymex/pymex.mexw64) +into your pymex directory. You do still need the pymex distribution and to have +Python 2.6 installed. There is currently no difference between this and the +master branch other than small changes to enable compilation with Visual Studio, +so it shouldn't matter which branch you have out. Note that this binary was +compiled under MATLAB 2009a in Windows 7 with VS 2008 EE. It should work with +newer versions of MATLAB (but not older), not sure about other windows versions. +You may need the [VS 2008 Redistributable Package](http://tinyurl.com/6rm54q) + + diff --git a/Makefile b/Makefile index 64d6fdd..11e8e57 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,6 @@ -PYTHON ?= python2.6 -MATLAB_SCRIPT ?= matlab -TMW_ROOT ?= $(shell ${MATLAB_SCRIPT} -e | grep MATLAB= | sed s/^MATLAB=//) - -CFLAGS=$(shell ${PYTHON}-config --cflags) -CLIBS=$(shell ${PYTHON}-config --libs) -LDFLAGS=$(shell ${PYTHON}-config --ldflags) -L$(shell ${PYTHON}-config --prefix)/lib +PYDIR ?= C:/Python26 +CFLAGS= -I$(shell cygpath -m ${PYDIR}/include) +CLIBS= $(shell cygpath -m ${PYDIR}/libs/libpython26.a) BUILDBRANCH = $(shell git branch --no-color | sed -e '/^[^*]/d' -e 's/* \(.*\)/\1/') ifeq ($(BUILDBRANCH),) @@ -16,23 +12,22 @@ ifeq ($(BUILDTAG),) endif BUILDNAME = $(BUILDBRANCH)/$(BUILDTAG) -MEXEXT ?= $(shell ${TMW_ROOT}/bin/mexext) +MEXEXT ?= $(shell mexext.bat) DEBUG ?= $(if $(wildcard .debug_1),1,0) TARGET = pymex.${MEXEXT} MEXFLAGS ?= -MEXENV = CFLAGS="\$$CFLAGS ${CFLAGS}" CLIBS="\$$CLIBS ${CLIBS}" LDFLAGS="\$$LDFLAGS ${LDFLAGS}" -MEX = ${TMW_ROOT}/bin/mex +MEX = mex.bat all: ${TARGET} ${TARGET}: pymex.c sharedfuncs.c commands.c *module.c pymex.h .debug_${DEBUG} @echo building $(BUILDNAME) - $(MEX) $(MEXFLAGS) $(MEXENV) \ + $(MEX) $(MEXFLAGS) $(CFLAGS) \ -DPYMEX_DEBUG_FLAG=$(DEBUG) \ -DPYMEX_BUILD="$(BUILDNAME)" \ - pymex.c sharedfuncs.c *module.c + pymex.c sharedfuncs.c *module.c $(CLIBS) .debug_0: @echo "Debug disabled." diff --git a/commands.c b/commands.c old mode 100644 new mode 100755 index aed8da5..f166d10 --- a/commands.c +++ b/commands.c @@ -184,6 +184,7 @@ PYMEX(TO_PYOBJECT, 1,1, plhs[0] = box(Any_mxArray_to_PyObject(prhs[0])); }) +#if PYMEX_DEBUG_FLAG PYMEX(CALL, 2,3, "Calls a callable python object. In addition to the " "object itself, the second argument is a cell array or tuple " @@ -197,7 +198,7 @@ PYMEX(CALL, 2,3, if (mxIsCell(prhs[1])) args = mxCell_to_PyTuple(prhs[1]); else - args = unbox(prhs[1]); + args = unboxn(prhs[1]); if (!args || !PyTuple_Check(args)) mexErrMsgIdAndTxt("python:NotTuple", "args must be a tuple"); PyObject *kwargs = NULL; @@ -206,7 +207,6 @@ PYMEX(CALL, 2,3, if (kwargs && !PyDict_Check(kwargs)) mexErrMsgIdAndTxt("python:NoKWargs", "kwargs must be a dict or null"); } - #if PYMEX_DEBUG_FLAG PyObject *crepr = PyObject_Repr(callobj); PyObject *arepr = PyObject_Repr(args); PyObject *krepr = kwargs ? PyObject_Repr(kwargs) : NULL; @@ -219,10 +219,38 @@ PYMEX(CALL, 2,3, Py_XDECREF(crepr); Py_XDECREF(arepr); Py_XDECREF(krepr); - #endif PyObject *result = PyObject_Call(callobj, args, kwargs); plhs[0] = box(result); + Py_XDECREF(args); }) +#else +PYMEX(CALL, 2,3, + "Calls a callable python object. In addition to the " + "object itself, the second argument is a cell array or tuple " + "of arguments. An optional third argument is a dict of keyword arguments. " + "No output unpacking is done. The standard object wrapper class implements that.", + { + PyObject *callobj = unbox(prhs[0]); + if (!PyCallable_Check(callobj)) + mexErrMsgIdAndTxt("python:NotCallable", "tried to call object which is not callable."); + PyObject *args = NULL; + if (mxIsCell(prhs[1])) + args = mxCell_to_PyTuple(prhs[1]); + else + args = unboxn(prhs[1]); + if (!args || !PyTuple_Check(args)) + mexErrMsgIdAndTxt("python:NotTuple", "args must be a tuple"); + PyObject *kwargs = NULL; + if (nrhs > 2) { + kwargs = unbox(prhs[2]); + if (kwargs && !PyDict_Check(kwargs)) + mexErrMsgIdAndTxt("python:NoKWargs", "kwargs must be a dict or null"); + } + PyObject *result = PyObject_Call(callobj, args, kwargs); + plhs[0] = box(result); + Py_XDECREF(args); + }) +#endif PYMEX(IS_CALLABLE, 1,1, "Tests the object to see if it is callable.", diff --git a/engmodule.c b/engmodule.cpp similarity index 100% rename from engmodule.c rename to engmodule.cpp diff --git a/makeall.m b/makeall.m new file mode 100755 index 0000000..7be0b6e --- /dev/null +++ b/makeall.m @@ -0,0 +1,11 @@ + + +%mex -IC:\Python26\include pymex.cpp +%mex -IC:\Python26\include sharedfuncs.cpp +% mex -IC:\Python26\include engmodule.cpp +% mex -IC:\Python26\include mexmodule.cpp +%mex -IC:\Python26\include mxmodule.cpp +%mex -IC:\Python26\include matmodule.cpp + + +mex -v -IC:\Python26\include pymex.cpp sharedfuncs.cpp engmodule.cpp matmodule.cpp mexmodule.cpp mxmodule.cpp C:\Python26\libs\python26.lib diff --git a/matmodule.c b/matmodule.cpp similarity index 100% rename from matmodule.c rename to matmodule.cpp diff --git a/mexmodule.c b/mexmodule.cpp old mode 100644 new mode 100755 similarity index 93% rename from mexmodule.c rename to mexmodule.cpp index 77488f2..e78bf49 --- a/mexmodule.c +++ b/mexmodule.cpp @@ -82,18 +82,23 @@ static PyObject *m_call(PyObject *self, PyObject *args, PyObject *kwargs) { return NULL; Py_DECREF(fakeargs); int nargin = PySequence_Size(args); - mxArray *inargs[nargin]; + mxArray **inargs; + inargs = new mxArray*[nargin]; int i; for (i=0; i= 0; if (nargout < 0) nargout = 1; - mxArray *outargs[nargout]; + mxArray **outargs; + outargs = new mxArray*[nargout]; mxArray *err = mexCallMATLABWithTrap(nargout, outargs, nargin, inargs, "feval"); - if (err) + delete [] inargs; + if (err) { + delete [] outargs; return _raiselasterror(NULL); + } else { if (tupleout) { PyObject *outseq = PyTuple_New(nargout); @@ -104,12 +109,16 @@ static PyObject *m_call(PyObject *self, PyObject *args, PyObject *kwargs) { : mxArrayPtr_New(outargs[i]) ); } + delete [] outargs; return outseq; } - else + else { + mxArray *outzero = outargs[0]; + delete [] outargs; return wrap - ? Any_mxArray_to_PyObject(outargs[0]) - : mxArrayPtr_New(outargs[0]); + ? Any_mxArray_to_PyObject(outzero) + : mxArrayPtr_New(outzero); + } } } @@ -133,11 +142,7 @@ static PyMethodDef mex_methods[] = { #endif PyMODINIT_FUNC initmexmodule(void) { PyObject *m = Py_InitModule3("mex", mex_methods, - #if MATLAB_MEX_FILE - "MATLAB Extension API module" - #else "MATLAB Extension API module (only available inside MATLAB)" - #endif ); if (!m) return; diff --git a/mxmodule.c b/mxmodule.cpp old mode 100644 new mode 100755 similarity index 98% rename from mxmodule.c rename to mxmodule.cpp index 52d0afe..640e7f1 --- a/mxmodule.c +++ b/mxmodule.cpp @@ -2,8 +2,8 @@ For full license details, see the LICENSE file. */ #define MXMODULE -#import "pymex.h" -#import "structmember.h" +#include "pymex.h" +#include "structmember.h" static PyObject *dowrap(PyObject *cobj) { PyObject *nargs = PyTuple_New(0); @@ -21,7 +21,8 @@ static PyObject *dowrap(PyObject *cobj) { #define DIMS_FROM_SEQ(A) \ mwSize ndim = PySequence_Size(A); \ - mwSize dims[ndim]; \ + mwSize *dims; \ + dims = new mwSize[ndim]; \ mwSize i; \ for (i=0; i < ndim; i++) { \ PyObject *item = PySequence_GetItem(A, i); \ @@ -50,6 +51,7 @@ static PyObject *CreateCellArray(PyObject *self, PyObject *args, PyObject *kw) { DIMS_FROM_SEQ(pydims); Py_DECREF(pydims); mxArray *cell = mxCreateCellArray(ndim, dims); + delete [] dims; if (wrap) return dowrap(mxArrayPtr_New(cell)); else @@ -59,17 +61,18 @@ static PyObject *CreateCellArray(PyObject *self, PyObject *args, PyObject *kw) { static PyObject *CreateNumericArray(PyObject *self, PyObject *args, PyObject *kw) { static char *kwlist[] = {"dims", "mxclass", "complexity", "wrap", NULL}; PyObject *pydims = NULL; - mxClassID class = mxDOUBLE_CLASS; + mxClassID class_id = mxDOUBLE_CLASS; mxComplexity complexity = mxREAL; int wrap = 0; if (!PyArg_ParseTupleAndKeywords(args, kw, "|Oiii", kwlist, - &pydims, &class, &complexity, &wrap)) + &pydims, &class_id, &complexity, &wrap)) return NULL; if (!pydims) pydims = PyTuple_New(0); else Py_INCREF(pydims); DIMS_FROM_SEQ(pydims); Py_DECREF(pydims); - mxArray *array = mxCreateNumericArray(ndim, dims, class, complexity); + mxArray *array = mxCreateNumericArray(ndim, dims, class_id, complexity); + delete [] dims; if (wrap) return dowrap(mxArrayPtr_New(array)); else @@ -88,6 +91,7 @@ static PyObject *CreateStructArray(PyObject *self, PyObject *args, PyObject *kw) DIMS_FROM_SEQ(pydims); Py_DECREF(pydims); mxArray *array = mxCreateStructArray(ndim, dims, 0, NULL); + delete [] dims; if (wrap) return dowrap(mxArrayPtr_New(array)); else @@ -106,6 +110,7 @@ static PyObject *CreateCharArray(PyObject *self, PyObject *args, PyObject *kw) { DIMS_FROM_SEQ(pydims); Py_DECREF(pydims); mxArray *array = mxCreateCharArray(ndim, dims); + delete [] dims; if (wrap) return dowrap(mxArrayPtr_New(array)); else @@ -225,8 +230,8 @@ static PyObject *mxArray_mxGetClassID(PyObject *self) { } static PyObject *mxArray_mxGetClassName(PyObject *self) { - const char *class = mxGetClassName(mxArrayPtr(self)); - return PyBytes_FromString(class); + const char *class_id = mxGetClassName(mxArrayPtr(self)); + return PyBytes_FromString(class_id); } static PyObject *mxArray_mxCalcSingleSubscript(PyObject *self, PyObject *args) { @@ -238,14 +243,17 @@ static PyObject *mxArray_mxCalcSingleSubscript(PyObject *self, PyObject *args) { "Can't calculate %ld-dimensional subscripts for %ld-dimensional array", (long) len, (long) dims); } - mwIndex subs[len]; + mwIndex *subs; + subs = new mwIndex[len]; mwIndex i; for (i=0; i 2 and self.shape[-1] == 1: + # need to squeeze + # should really squeeze only last axis but + # axis kw only supported in >1.7.0 + self = np.squeeze(self) mxclass = select_mxclass_by_dtype(self.dtype.type) cobj = mx.create_numeric_array(mxclass = mxclass, dims = self.shape) diff --git a/sharedfuncs.c b/sharedfuncs.cpp old mode 100644 new mode 100755 similarity index 98% rename from sharedfuncs.c rename to sharedfuncs.cpp index 2ab791d..f980141 --- a/sharedfuncs.c +++ b/sharedfuncs.cpp @@ -125,7 +125,7 @@ mxArray *box (PyObject *pyobj) { if (!boxed) return NULL; if (pyobj) mexLock(); mxArray *ptr_field = mxGetProperty(boxed, 0, "pointer"); - void **ptr = mxGetData(ptr_field); + void **ptr = (void **) mxGetData(ptr_field); *ptr = (void*) pyobj; mxSetProperty(boxed, 0, "pointer", ptr_field); return boxed; @@ -145,7 +145,7 @@ PyObject *unbox (const mxArray *mxobj) { return PyErr_Format(MATLABError, "Unboxed pointer is null."); } else { - void **ptr = mxGetData(mxGetProperty(mxobj, 0, "pointer")); + void **ptr = (void **) mxGetData(mxGetProperty(mxobj, 0, "pointer")); return (PyObject *) *ptr; } } @@ -168,7 +168,7 @@ PyObject *unboxn (const mxArray *mxobj) { it does not check this before doing the mxGetProperty */ bool mxIsPyNull (const mxArray *mxobj) { - void **ptr = mxGetData(mxGetProperty(mxobj, 0, "pointer")); + void **ptr= (void **) mxGetData(mxGetProperty(mxobj, 0, "pointer")); return !*ptr; }