1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841
|
\documentclass[12pt]{article}
\usepackage{amsmath}
\usepackage{fancyheadings}
\setlength{\oddsidemargin}{0.0in}
\setlength{\textwidth}{6.5in}
\setlength{\topmargin}{-0.5in}
\setlength{\textheight}{9.0in}
\bibliographystyle{unsrt}
\renewcommand{\baselinestretch}{1.0}
\newcommand{\mwrap}{\textsc{MWrap}}
\newcommand{\gOR}{ $|$ }
\title{\mwrap\ User Guide\\ Version 1.3}
\author{D.~Bindel, A.~Barnett, Z.~Gimbutas, M.~Rachh, L.~Lu, R.~Laboissi\`ere}
\date{2026-02-24}
\pagestyle{fancy}
%%\headrulewidth 1.5pt
%%\footrulewidth 1.5pt
\chead{\mwrap}
\lhead{}
\rhead{}
\cfoot{\thepage}
\begin{document}
\maketitle
\section{Introduction}
\mwrap\ is an interface generation system in the spirit of SWIG or
matwrap. From a set of augmented MATLAB script files, \mwrap\ will
generate a MEX gateway to desired C/C++ function calls and MATLAB
function files to access that gateway. The details of converting to
and from MATLAB's data structures, and of allocating and freeing
temporary storage, are hidden from the user.
\mwrap\ files look like MATLAB scripts with specially formatted
extra lines that describe calls to C/C++. For example, the following
code is converted into a call to the C {\tt strncat} function:
\begin{verbatim}
$ #include <string.h>
function foobar;
s1 = 'foo';
s2 = 'bar';
# strncat(inout cstring[128] s1, cstring s2, int 127);
fprintf('Should be foobar: %s\n', s1);
\end{verbatim}
There are two structured comments in this file. The line
beginning with \verb|$| tells \mwrap\ that this line is C/C++
support code, and the line beginning with \verb|#| describes
a call to the C {\tt strncat} function. The call description
includes information about the C type to be used for the input
arguments, and also describes which parameters are used for input
and for output.
From this input file, \mwrap\ produces two output files: a C file
which will be compiled with the MATLAB {\tt mex} script, and a MATLAB
script which calls that MEX file. If the above file is {\tt foobar.mw},
for example, we would generate an interface file {\tt foobar.m} and a
MEX script {\tt fbmex.mex} with the lines
\begin{verbatim}
mwrap -mex fbmex -m foobar.m foobar.mw
mwrap -mex fbmex -c fbmex.c foobar.mw
mex fbmex.c
\end{verbatim}
At this point, we can run the {\tt foobar} script from the MATLAB prompt:
\begin{verbatim}
>> foobar
Should be foobar: foobar
\end{verbatim}
Versions of GNU Octave released after mid-2006 support much of
MATLAB's MEX interface. Simple {\mwrap}-generated code should work
with GNU Octave. To compile for GNU Octave, use \texttt{mkoctfile
--mex} instead of invoking \texttt{mex}. GNU Octave does not
implement MATLAB's object model, so code that uses MATLAB's
object-oriented facilities will not function with GNU Octave.
\section{\mwrap\ command line}
The {\tt mwrap} command line has the following form:
\begin{verbatim}
mwrap [-mex outputmex] [-m output.m] [-c outputmex.c] [-mb]
[-list] [-catch] [-i8] [-c99complex] [-cppcomplex] [-gpu]
infile1 infile2 ...
\end{verbatim}
where
\begin{itemize}
\item {\tt -mex} specifies the name of the MEX function that the
generated MATLAB functions will call. This name will generally be
the same as the prefix for the C/C++ output file name.
\item {\tt -m} specifies the name of the MATLAB script to be
generated.
\item {\tt -c} specifies the name of the C MEX file to be generated.
The MEX file may contain stubs corresponding to several different
generated MATLAB files.
\item {\tt -mb} tells \mwrap\ to redirect MATLAB function output to
files named in the input. In this mode, the processor will change
MATLAB function output files whenever it encounters a line
beginning with \verb|@|. If \verb|@| occurs alone on a line,
MATLAB output will be turned off; if the line begins with \verb|@function|,
the line will be treated as the first line of a function, and the m-file
name will be deduced from the function name; and otherwise, the characters
after \verb|@| (up to the next set of white space) will be treated as a
filename, and \mwrap\ will try to write to that file.
\item {\tt -list} tells \mwrap\ to print to the standard output the
names of all files that would be generated from redirect output by
the {\tt -mb} flag.
\item {\tt -catch} tells \mwrap\ to surround library calls in try/catch
blocks in order to intercept C++ exceptions.
\item {\tt -i8} tells \mwrap\ to convert {\tt int}, {\tt long}, {\tt
uint}, {\tt ulong} types to {\tt int64\_t}, {\tt uint64\_t}. This
provides a convenient way to interface with {\tt -fdefault-integer-8}
and {\tt -i8} flags used by Fortran compilers.
\item {\tt -c99complex} tells \mwrap\ to use the C99 complex floating
point types as the default {\tt dcomplex} and {\tt fcomplex} types.
\item {\tt -cppcomplex} tells \mwrap\ to use the C++ complex floating
point types as the default {\tt dcomplex} and {\tt fcomplex} types.
\item {\tt -gpu} tells \mwrap\ to add support code for MATLAB gpuArray.
\end{itemize}
\section{Interface syntax}
\subsection{Input line types}
\mwrap\ recognizes six types of lines, based on the first non-space
characters at the start of the line:
\begin{itemize}
\item C support lines begin with \verb|$|. These
lines are copied into the C code that makes up the MEX file.
Typically, such support lines are used to include any necessary
header files; they can also be used to embed short functions.
\item Blocks of C support can be opened by the line \verb|$[|
and closed by the line \verb|$]|. Like lines beginning with \verb|$|,
lines that fall between the opening and closing markers are copied into
the C code that makes up the MEX file.
\item C call lines begin with \verb|#|. These lines are
parsed in order to generate an interface function as part of the MEX
file and a MATLAB call line to invoke that interface function. C
call lines can refer to variables declared in the local MATLAB
environment.
\item Input redirection lines (include lines) begin with \verb|@include|.
The input file name should not be quoted in any way.
\item Output redirection lines begin with \verb|@|. %
Output redirection is used to specify several generated MATLAB
scripts with a single input file.
\item Comment lines begin with \verb|//|. Comment lines are not included
in any output file.
\item All other lines are treated as ordinary MATLAB code, and are
passed through to a MATLAB output file without further processing.
\end{itemize}
\subsection{C call syntax}
The complete syntax for \mwrap\ call statements is given in
Figure~\ref{mwrap-syntax-fig}. Each statement makes a function or
method call, and optionally assigns the output to a variable. For
each argument or return variable, we specify the type and also say
whether the variable is being used for input, for output, or for both.
Variables are given by names which should be valid identifiers in the
local MATLAB environment where the call is to be made. Input
arguments can also be given numeric values, though it is still necessary
to provide type information.
There are three types of call specifications. Ordinary functions
not attached to a class can be called by name:
\begin{verbatim}
# do_something();
\end{verbatim}
To create a new C++ object instance, we use the {\tt new} command
\begin{verbatim}
# Thermometer* therm = new Thermometer(double temperature0);
\end{verbatim}
And once we have a handle to an object, we can invoke methods on it
\begin{verbatim}
# double temperature = therm->Thermometer.get_temperature();
\end{verbatim}
Object deletion is handled just like an ordinary function call
\begin{verbatim}
# delete(Thermometer* therm);
\end{verbatim}
Intrinsic operators like {\tt sizeof} can also be invoked in this manner.
The type specifications are \emph{only} used to determine how \mwrap\
should handle passing data between MATLAB and a C/C++ statement;
the types specified in the call sequence should be compatible with
a corresponding C/C++ definition, but they need not be identical to the
types in a specific function or method declaration.
An \mwrap\ type specification consists of three parts. The first
(optional) part says whether the given variable will be used for input
({\tt input}), for output ({\tt output}), or for both. The second
part gives the basic type name for the variable; this may be an
intrinsic type like {\tt int} or {\tt double}, a string, an object
type, or a MATLAB intrinsic (see Section~\ref{type-section}).
Finally, there may be modifiers to specify that this is a pointer, a
reference, or an array. Array and string arguments may also have
explicitly provided size information. In the example from the
introduction, for example the argument declaration
\begin{verbatim}
inout cstring[128] s1
\end{verbatim}
tells \mwrap\ that {\tt s1} is a C string which is used for input and output,
and that the buffer used should be at least 128 characters long.
Identifiers in \mwrap\ may include C++ scope specifications to indicate
that a function or method belongs to some namespace or that it is a static
member of a class. That is, it is valid to write something like
\begin{verbatim}
std::ostream* os = foo->get_ostream();
\end{verbatim}
Scoped names may be used for types or for method names, but it is an
unchecked error to use a scoped name for a parameter or return
variable.
\begin{figure}
\begin{center}
\begin{tabular}{l@{ := }l}
statement & returnvar {\tt = } func {\tt (} args {\tt );} \\
& func {\tt (} args {\tt );} \\
& {\tt typedef numeric} {\it type-id} {\tt ;} \\
& {\tt typedef dcomplex} {\it type-id} {\tt ;} \\
& {\tt typedef fcomplex} {\it type-id} {\tt ;} \\
& {\tt class} {\it child-id} {\tt :}
{\it parent-id} {\tt ,} {\it parent-id} {\tt ,} $\ldots$
\vspace{5mm} \\
func & {\it function-id} \\
& {\tt FORTRAN} {\it function-id} \\
& {\it this-id} {\tt .} {\it class-id} {\tt ->} {\it method-id}\\
& {\tt new} {\it class-id}
\vspace{5mm} \\
args & arg {\tt ,} arg {\tt ,} $\ldots$ \gOR\ $\epsilon$ \\
arg & devicespec iospec type {\it var-id} \\
& devicespec ispec type {\it value} \\
returnvar & type {\it var-id}
\vspace{5mm} \\
devicespec & {\tt cpu} \gOR\ {\tt gpu} \gOR\ $\epsilon$ \\
iospec & {\tt input} \gOR\ {\tt output} \gOR\ {\tt inout} \gOR\
$\epsilon$ \\
ispec & {\tt input} \gOR\ $\epsilon$ \\
type & {\it type-id} \gOR
{\it type-id} {\tt *} \gOR\
{\it type-id} {\tt \&} \gOR\
{\it type-id} {\tt [} dims {\tt]} \gOR\
{\it type-id} {\tt [} dims {\tt] \&} \\
dims & dim {\tt ,} dim {\tt ,} $\ldots$ \gOR\ $\epsilon$ \\
dim & {\it var-id} \gOR\ {\it number}
\end{tabular}
\caption{\mwrap\ call syntax}
\label{mwrap-syntax-fig}
\end{center}
\end{figure}
\section{Variable types}
\label{type-section}
\mwrap\ recognizes several different general types of variables as well
as constant expressions:
\subsection{Numeric types}
{\it Scalars} are intrinsic numeric types in C/C++: {\tt double}, {\tt
float}, {\tt long}, {\tt int}, {\tt char}, {\tt ulong}, {\tt uint},
{\tt uchar}, {\tt bool}, {\tt int32\_t}, {\tt uint32\_t}, {\tt
int64\_t}, {\tt uint64\_t}, {\tt ptrdiff\_t} and {\tt size\_t}.
These are the numeric types that \mwrap\ knows about by default, but
if necessary, new numeric types can be declared using {\tt typedef}
commands. For example, if we wanted to use {\tt float64\_t} as a
numeric type, we would need the line
\begin{verbatim}
# typedef numeric float64_t;
\end{verbatim}
Ordinary scalars cannot be used as output arguments.
{\it Scalar pointers} are pointers to the recognized numeric
intrinsics. They are assumed to refer to {\em one} variable; that
is, a {\tt double*} in \mwrap\ is a pointer to one double in memory,
which is different from a double array ({\tt double[]}).
{\it Scalar references} are references to the recognized numeric
intrinsics.
{\it Arrays} store arrays of recognized numeric intrinsics.
They may have explicitly specified dimensions (in the case of pure
return arrays and pure output arguments, they \emph{must} have explicitly
specified dimensions), but the dimensions can also be automatically
determined from the input data. If only one dimension is provided,
return and output arrays are allocated as column vectors.
If a function is declared to return an array or a scalar pointer
and the C return value is NULL, \mwrap\ will pass an empty array
back to MATLAB. If an empty array is passed to a function as an
input array argument, \mwrap\ will interpret that argument as NULL.
{\it Array references} are references to numeric arrays, such
as in a function whose C++ prototype looks like
\begin{verbatim}
void output_array(const double*& data);
\end{verbatim}
Array references may only be used as output arguments, and the array
must have explicitly specified dimensions. If the value of the data
pointer returned from the C++ function is NULL, \mwrap\ will pass an
empty array back to MATLAB.
{\it Complex} scalars pose a special challenge. C++ and C99 provide
distinct complex types, and some C89 libraries define complex numbers
via structures. If the {\tt -cppcomplex} or {\tt -c99complex} flags
are specified, {\tt mwrap} will automatically define complex double
and single precision types {\tt dcomplex} and {\tt fcomplex} which are
bound to the C++ or C99 double-precision and single-precision complex
types. More generally, we allow complex numbers which are
conceptually pairs of floats or doubles to be defined using {\tt
typedef fcomplex} and {\tt typedef dcomplex} commands. For example,
in C++, we might use the following commands to set up a double complex
type {\tt cmplx} (which is equivalent to the {\tt dcomplex} type when
the {\tt -cppcomplex} flag is used):
\begin{verbatim}
$ #include <complex>
$ typedef std::complex<double> cmplx; // Define a complex type
$ #define real_cmplx(z) (z).real() // Accessors for real, imag
$ #define imag_cmplx(z) (z).imag() // (req'd for complex types)
$ #define setz_cmplx(z,r,i) *z = dcomplex(r,i)
# typedef dcomplex cmplx;
\end{verbatim}
The macro definitions {\tt real\_cmplx}, {\tt imag\_cmplx}, and {\tt
setz\_cmplz} are used by \mwrap\ to read or write the real and imaginary parts
of a number of type {\tt cmplx}. Similar macro definitions must be provided
for any other complex type to be used.
Other than any setup required to define what will be used as a complex
type, complex scalars can be used in all the same ways that real and
integer scalars are used.
\subsection{Strings}
{\it Strings} are C-style null-terminated character strings.
They are specified by the \mwrap\ type {\tt cstring}. A {\tt cstring}
type is not equivalent to a {\tt char[]} type, since the latter is
treated as an array of numbers (represented by a double vector in MATLAB)
in which zero is given no particular significance.
The dimensions can be of a {\tt cstring} can explicitly specified or
they can be implicit. When a C string is used for output, the size
of the corresponding character buffer \emph{must} be given; and when
a C string is used for input, the size of the corresponding character
buffer should not be given.
If a function is declared to return a C string and the return value
is NULL, \mwrap\ will pass back the scalar 0.
\subsection{Objects}
{\it Objects} are variables with any base type other than one of the
recognized intrinsics (or the {\tt mxArray} pass-through -- see below).
This can lead to somewhat startling results when, for example,
\mwrap\ decides a {\tt size\_t} is a dynamic object type (this will only
give surprises if one tries to pass in a numeric value). If a function
or method returns an object, \mwrap\ will make a copy of the return object
on the heap and pass back that copy.
{\it Object references} are treated the same as objects, except
that when a function returns an object reference, \mwrap\ will
return the address associated with that reference, rather than
making a new copy of the object.
{\it Object pointers} may either point to a valid object of the
appropriate type or to NULL (represented by zero). This is
different from the treatment of objects and object references. When
a NULL value is specified for a {\tt this} argument, an object
argument, or an object reference argument, \mwrap\ will generate a
MATLAB error message.
If the wrapped code uses an object hierarchy, you can use \mwrap\ class
declarations so that valid casts to parent types will be performed
automatically. For example, the declaration
\begin{verbatim}
# class Child : Parent1, Parent2;
\end{verbatim}
tells \mwrap\ that an object of type {\tt Child} may be passed in where
an object of type {\tt Parent1} is required. The generated code works
correctly with C++ multiple inheritance.
Objects cannot be declared as output or inout parameters, but that just
means that the identity of an object parameter does not change during a
call. There's nothing wrong with changing the internal state of the object.
By default, \mwrap\ stores non-NULL object references in strings.
However, for MATLAB 2008a and onward, \mwrap\ will also interpret as objects
any classes with a readable property {\tt mwptr}. This can be used, for
example, to implement class wrappers using the new {\tt classdef} keyword.
In order to use this feature, the macro {\tt R2008OO} must be defined
by adding the argument {\tt -DR2008OO} to the {\tt mex} compile line.
\subsection{{\tt mxArray}}
The {\it mxArray} type in \mwrap\ refers to MATLAB's basic
object type (also called {\tt mxArray}). {\tt mxArray} arguments
can be used as input or output arguments (but not as inout arguments),
or as return values. On input, {\tt mxArray} is mapped to C type
{\tt const mxArray*}; on output, it is mapped to {\tt mxArray**}; and
on return, it is mapped to {\tt mxArray*}. For example, the line
\begin{verbatim}
# mxArray do_something(mxArray in_arg, output mxArray out_arg);
\end{verbatim}
is compatible with a function defined as
\begin{verbatim}
mxArray* do_something(const mxArray* in_arg, mxArray** out_arg);
\end{verbatim}
Note that the header file {\tt mex.h} must be included for this
function declaration to make any sense.
The primary purpose for the mxArray pass through is to allow
specialized routines to read the internal storage of MATLAB sparse
matrices (and possibly other structures) for a few routines without
giving up the convenience of the \mwrap\ framework elsewhere.
\subsection{Auto-converted objects}
If there is a natural mapping from some MATLAB data structure to
a C/C++ object type, you can use a typedef to tell \mwrap\ to perform
automatic conversion. For example, if we wanted {\tt Foo} to be
automatically converted from some MATLAB data structure on input, then
we would add the line
\begin{verbatim}
# typedef mxArray Foo;
\end{verbatim}
With this declaration, {\tt Foo} objects are automatically converted
from {\tt mxArray} to the corresponding C++ type on input, and back to
{\tt mxArray} objects on output. It is assumed that \mwrap\ {\em owns
the argument objects} and {\em does not own the return objects}.
This feature should not be used when the C++ side keeps a pointer or
reference to a passed object, or when the caller is responsible for deleting
a dynamically allocated return object.
Auto-converted objects rely on the following user-defined functions:
\begin{verbatim}
Foo* mxWrapGet_Foo(const mxArray* a, const char** e);
mxArray* mxWrapSet_Foo(Foo* o);
Foo* mxWrapAlloc_Foo();
void mxWrapFree_Foo(Foo* o);
\end{verbatim}
Not all functions are needed for all uses of an auto-converted type.
The functions play the following roles:
\begin{enumerate}
\item
The \verb|mxWrapGet_Foo| function is used to convert an input argument
to the corresponding C++ representation. If an error occurs during
conversion, the second argument should be pointed toward an error message
string. It is assumed that this conversion function will catch any thrown
exceptions.
\item
The \verb|mxWrapSet_Foo| function is used to convert an output argument
or return value to the corresponding C++ representation.
\item
The \verb|mxWrapAlloc_Foo| function is used to allocate a new temporary
for use as an output argument.
\item
The \verb|mxWrapFree_Foo| function is used to deallocate a temporary
created by \verb|mxWrapGet_Foo| or \verb|mxWrapAlloc_Foo|.
\end{enumerate}
The point of auto-converted objects is to simplify wrapper design for
codes that make heavy use of things like C++ vector classes (for example).
The system does {\em not} provide the same flexibility as the {\tt mxArray}
object, nor is it as flexible as a sequence of \mwrap\ calls to explicitly
create and manage temporaries and their conversion to and from MATLAB objects.
At present, the behavior when you try to involve an auto-converted object
in an inheritance relation is undefined. Don't try it at home.
\subsection{Constants}
The {\it const} type in \mwrap\ refers to a C/C++ symbolic constant or
global variable. The name of the variable is output directly into the
compiled code. For example, to print a string to {\tt stderr}, we can
write
\begin{verbatim}
# fprintf(const stderr, cstring s);
\end{verbatim}
\subsection{{\tt mxSINGLE\_CLASS} and {\tt mxDOUBLE\_CLASS}}
By default, {\tt mwrap 0.33} expected all input and output numeric
MATLAB variables to be of {\tt mxDOUBLE\_CLASS}. The newest version of
{\tt mwrap (0.33.12+)} allows {\tt mxSINGLE\_CLASS} for {\tt float}
and {\tt fcomplex} types. An error {\tt 'Invalid array argument,
mxSINGLE/DOUBLE\_CLASS expected'} will be issued if a mismatched
Matlab variable is detected during runtime. The user is expected to
perform the required type conversions manually using {\tt single} or
{\tt double} MATLAB commands.
\subsection{{\tt mxCHAR\_CLASS}}
{\tt mwrap (1.2+)} allows character constants of {\tt mxCHAR\_CLASS}
for {\tt char} types and forces type checking. An error {\tt 'Invalid
array argument, mxCHAR\_CLASS expected'} will be issued if a
mismatched Matlab variable is detected during runtime. The user is
expected to perform the required type conversions manually using {\tt
char} MATLAB command.
\subsection{GPU array passing}
\label{gpu-section}
When the {\tt -gpu} flag is specified, \mwrap\ adds support for
MATLAB {\tt gpuArray} objects. The {\tt gpu} device specifier can be
placed before the usual {\tt input}, {\tt output}, or {\tt inout}
keywords to indicate that an array argument resides on the GPU:
\begin{verbatim}
# func(gpu input double[n] x, gpu output double[n] y, int n);
\end{verbatim}
For GPU input arrays, \mwrap\ verifies that the argument is a {\tt
gpuArray}, then obtains a read-only device pointer via {\tt
mxGPUGetDataReadOnly}. For GPU output arrays, \mwrap\ creates a
new {\tt mxGPUArray} with {\tt mxGPUCreateGPUArray} and obtains a
writable device pointer via {\tt mxGPUGetData}. For GPU inout
arrays, the input device pointer is reused and the same {\tt
mxGPUArray} is returned as output.
The {\tt gpu} specifier may be freely combined with ordinary (CPU)
arguments in the same function call, allowing mixed host/device
interfaces. The {\tt -gpu} flag causes \mwrap\ to emit {\tt
\#include <gpu/mxGPUArray.h>} and a call to {\tt mxInitGPU()} in
the MEX initialization code. The MEX file must be compiled with
MATLAB's GPU-enabled {\tt mex} compiler ({\tt nvmex} or {\tt mex}
with CUDA support).
The default device specifier is {\tt cpu}, which can be omitted.
\section{Example}
An event queue stores pairs $(i, t)$ pairs, $i$ is an identifier for
some event and $t$ is a time associated with the event. Events can be
added to the queue in whatever order, but they are removed in
increasing order by time. In this example, we bind to a C++ event
queue implementation based on the C++ standard template library
priority queue. The example code is in {\tt
example/eventq/eventq\_class.mw} and {\tt
example/eventq/eventq\_handle.mw}; an alternate version of the code
in {\tt example/eventq/eventq\_plain.mw} illustrates a different way
of organizing the same interface. The {\tt example/eventq2}
subdirectory provides yet another implementation, this one capable of
storing arbitrary MATLAB arrays rather than just integers.
\subsection{Event queue using old MATLAB OO}
We begin by defining an event as a pair (double, int), and an
event queue as an STL priority queue of such pairs, sorted in
descending order:
\begin{verbatim}
$ #include <queue>
$
$ typedef std::pair<double, int> Event;
$ typedef std::priority_queue< Event,
$ std::vector<Event>,
$ std::greater<Event> > EventQueue;
\end{verbatim}
Now we specify the code to wrap the individual methods. For this
example, we will take advantage of the object oriented features in
MATLAB, and map the methods of the C++ event queue class onto methods
of a MATLAB wrapper class called {\tt eventq}. We begin with bindings
for the constructor and destructor. We will compile the MATLAB
functions for the interface using the {\tt -mb} flag, so that we can
specify these functions (and all the others) in the same file:
\begin{verbatim}
@ @eventq/eventq.m -------------------------------------
function [qobj] = eventq();
qobj = [];
# EventQueue* q = new EventQueue();
qobj.q = q;
qobj = class(qobj, 'eventq');
@ @eventq/destroy.m -------------------------------------
function destroy(qobj);
q = qobj.q;
# delete(EventQueue* q);
\end{verbatim}
The {\tt empty} method returns a {\tt bool}, but \mwrap\ does not
know about {\tt bool} variables. A {\tt bool} result can be saved
as an integer, though, so we will simply do that:
\begin{verbatim}
@ @eventq/empty.m -------------------------------------
function [e] = empty(qobj)
q = qobj.q;
# int e = q->EventQueue.empty();
\end{verbatim}
Because {\tt pop\_event} needs to return two values (the event identifier
and the time), we use reference arguments to pass out the information.
\begin{verbatim}
@ @eventq/pop_event.m -------------------------------------
function [id, t] = pop_event(qobj)
$ void pop_event(EventQueue* q, int& id, double& t) {
$ t = q->top().first;
$ id = q->top().second;
$ q->pop();
$ }
$
q = qobj.q;
# pop_event(EventQueue* q, output int& id, output double& t);
\end{verbatim}
In MATLAB, it may make sense to simultaneously push several events.
However, our event queue class only provides basic interfaces to
push one event at a time. We could write a MATLAB loop to add events
to the queue one at a time, but for illustrating how to use \mwrap,
it is better to write the loop in C:
\begin{verbatim}
@ @eventq/push_event.m -------------------------------------
function push_event(qobj, id, t)
$ void push_events(EventQueue* q, int* id, double* t, int m)
$ {
$ for (int i = 0; i < m; ++i)
$ q->push(Event(t[i], id[i]));
$ }
$
q = qobj.q;
m = length(id);
# push_events(EventQueue* q, int[m] id, double[m] t, int m);
\end{verbatim}
\subsection{Event queue using new MATLAB OO}
Starting with MATLAB 7.6 (release 2008A), MATLAB supports a new single-file
OO programming style. Particularly convenient for writing wrappers is the
{\em handle} class system, which allows the user to define destructors that
are called automatically when an instance is destroyed by the system (because
all references to the instance have gone out of scope). As a programming
convenience, \mwrap\ automatically interprets a class with the property
{\tt mwptr} as a container for an \mwrap\ object\footnote{This functionality
is only enabled when {\tt -DR2008OO} is specified as an argument on the
MEX command line. This restriction is in place so that the files generated
by \mwrap\ can remain compatible with Octave and with older versions
of MATLAB.}.
For example, the following file provides an alternate implementation
of the event queue class described in the previous section.
\begin{verbatim}
$ #include <queue>
$
$ typedef std::pair<double, int> Event;
$ typedef std::priority_queue< Event,
$ std::vector<Event>,
$ std::greater<Event> > EventQueue;
@ eventqh.m ----------------------------------------------
classdef eventqh < handle
properties
mwptr
end
methods
function [qobj] = eventqh(obj)
# EventQueue* q = new EventQueue();
qobj.mwptr = q;
end
function delete(q)
#delete(EventQueue* q);
end
function e = empty(q)
# int e = q->EventQueue.empty();
end
function [id, t] = pop(q)
$ void pop_event(EventQueue* q, int& id, double& t) {
$ t = q->top().first;
$ id = q->top().second;
$ q->pop();
$ }
# pop_event(EventQueue* q, output int& id, output double& t);
end
function push(q, id, t)
$ void push_events(EventQueue* q, int* id, double* t, int m)
$ {
$ for (int i = 0; i < m; ++i)
$ q->push(Event(t[i], id[i]));
$ }
m = length(id);
# push_events(EventQueue* q, int[m] id, double[m] t, int m);
end
end
end
\end{verbatim}
This implementation of the event queue class allows for automatic cleanup:
\begin{verbatim}
q = eventqh(); % Construct a new queue
clear q; % The C++ object gets correctly deleted here
\end{verbatim}
{\bf Warning}: When using MATLAB handle classes for automatic cleanup,
be sure to avoid situations where multiple MATLAB handle objects have
been given responsible for deleting a single C/C++ object. If you need
to have more than one MATLAB handle for a single C/C++ object,
I recommend using a reference counted pointer class as an
intermediate\footnote{
For more information on reference counted pointer classes, I recommend
reading {\em More Effective C++} by Scott Meyers.
}.
\section{FORTRAN bindings}
It is possible to use \mwrap\ to bind FORTRAN functions (though the
generated MEX file is still a C/C++ file). FORTRAN bindings can be
specified using the {\tt FORTRAN} keyword immediately before a function
name; for example:
\begin{verbatim}
# double sum = FORTRAN dasum(int n, double[n] x, int 1);
\end{verbatim}
FORTRAN parameters are treated differently from C parameters in the
following ways:
\begin{enumerate}
\item
\mwrap\ does not allow objects to be passed into FORTRAN functions.
\item
Scalar and reference arguments are automatically converted to pointer
arguments from the C side to match FORTRAN call-by-reference semantics.
\item
A warning is generated when passing C strings into FORTRAN. The generated
code will work with compilers that produce f2c-compatible code (including
g77/g95), but it will not work with all FORTRAN compilers.
\item
Only simple numeric values can be returned from FORTRAN. A warning is
generated when returning complex values, as different FORTRAN compilers
follow different protocols when returning complex numbers. The generated
code for complex return types will work with some f2c-compatible compilers,
but by no means all.
\end{enumerate}
Internally, \mwrap\ defines macros for different FORTRAN name-mangling
conventions, and it declares appropriate prototypes (and protects them
from C++ compiler name mangling). By default, \mwrap\ assumes that
the f2c name mangling convention is being used (this convention is
followed by Sun FORTRAN, g77, and g95); however, the following flags
can be passed to the {\tt mex} script to change this behavior:
\begin{itemize}
\item
{\tt -DMWF77\_CAPS} -- Assume the FORTRAN compiler uses all-caps
names and no extra underscores. Used by Compaq FORTRAN, and Intel fortran compiler on windows (I think).
\item
{\tt -DMWF77\_UNDERSCORE1} -- Append a single underscore to an
all-lower-case name. Used by the GNU FORTRAN compiler and the Intel fortran compiler on UNIX systems (I think).
\item
{\tt -DMWF77\_UNDERSCORE0} -- Append no underscore to an
all-lower-case name. Used by the GNU fortran with the -fno-underscoring flag
\end{itemize}
It is possible to use the {\tt typedef numeric} construct to introduce
new types corresponding to FORTRAN data types. For example, if the
header file {\tt f2c.h} is available (and the types defined therein are
appropriate for the compiler) we might have
\begin{verbatim}
% Use the f2c integer type...
$ #include "f2c.h"
# typedef numeric integer;
# double sum = FORTRAN dasum(integer n, double[n] x, integer 1);
\end{verbatim}
No attempt is made to automatically produce these type maps, though.
\section{Logging}
For profiling and coverage testing, it is sometimes useful to track the
number of calls that are made through \mwrap. If {\tt mymex} is the name
of the generated MEX file, then we can access profile information as
follows:
\begin{verbatim}
% Enable profiler
mymex('*profile on*');
% Run some tests here...
% Print to screen and to a log file
mymex('*profile report*');
mymex('*profile log*', 'log.txt');
% Disable profiler
mymex('*profile off*');
\end{verbatim}
The MEX file will be locked in memory as long as profiling is active.
\end{document}
|