How to include libraries in a mex file

59 次查看(过去 30 天)
Hi,
I am trying to make a mex file from a C one. I have a few questions. The main one is the first lines of my program are
#include "fftw3.h"
#include <fftw3.h>
however and although the fftw3 library is installed on my computer, it seems that Matlab is unable to find it as when I compile my program it says
undefined reference to `fftw_plan_many_dft'
etc. It is not the only library that include, I also have the standard stdlib.h, string.h, math.h but they don't seem to be a problem. How could I do for Matlab to understand where to find the library? The fftw3.h is in /usr/include.
Another question is: is it possible to mex non void functions, for example int or double or should I modify them? Finally a very basic question: can I put my C functions in another file and include them to the main mex (the one with mxFunction) with an #include myfunction.h? Cheers.
  1 个评论
Friedrich
Friedrich 2012-3-22
look in the doc:
http://www.mathworks.com/help/releases/R2012a/techdoc/ref/mex.html
-I, -L and -l are the important ones here.

请先登录,再进行评论。

回答(10 个)

Ken Atwell
Ken Atwell 2012-3-23
As Friedrich states, you will need to add a few switches to you call to MEX:
  • -I to indicated the directory where your headers (.h) files are (/usr/include in your case)
  • -L to indicated the directory where you library (.so) files are
  • -l to indicate the name of the library file to linkage against
stdlib.h, string.h are not a problem because they are part of your compiler's distribution, and FFTW is not.
As to the return types of your function, the MEX API entry point must be void:
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
Use nlhs and plhs to return values.
You can put other functions in their own files, or within the C file containing mexFunction -- it is really a matter of style. If you do use separate files, you will need to add them to your MEX command line.

James Tursa
James Tursa 2012-3-26
What happens when you try this:
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <time.h>
#ifdef _WIN32
#include <windows.h>
#else
#include <sys/utsname.h>
#endif
#include "mex.h"
void gft_1dPartitions(unsigned int N, int *partitions) {
[...]
partitions[pcount] = ep;
partitions[pOff-pcount] = en;
[...]
return;
}
void mexFunction( int nlhs, mxArray *plhs[],
int nrhs, const mxArray *prhs[] )
{
int N, *partitions;
int taille,k;
/* get the scalar value of the input x */
/* note: mxGetScalar returns a value, not a pointer */
N = mxGetScalar(prhs[0]);
/* assign a pointer to the output */
taille = 2*round(log2(N))+1;
plhs[0] = mxCreateNumericMatrix(1, taille, mxINT32_CLASS, mxREAL);
partitions = (int*) mxGetData(plhs[0]);
/* Call the subroutine. */
gft_1dPartitions(N, partitions);
return;
}

Carine
Carine 2012-3-26
Hi,
Thanks for your answers Friedrich and Ken, little by little, I am starting to understand how mex works. For the second part of my question, I know the mxFunction should be void. What I meant is to include a C function which returns an integer or a double as
int *ThisFunction(int N){
...
return var}
For one function it is easy to change but as I have many depending on each other, that would be much more convenient for me if possible. Sorry for being so confusing and I hope I have been more clear this time ;-)
  1 个评论
James Tursa
James Tursa 2012-3-26
There should be only one mexFunction in all of your code. You can have as many different source files as you want, but there should be only one mexFunction ... it would be in exactly one of your source files. You do *not* need to change any of your C functions since they are only interfacing with other C code ... they are not interfacing with MATLAB directly. From the nature of your questions I would guess that you are going to need some help with this so I would suggest you post a small sample of code that you are trying to compile into a mex function and then we can help you set up the code and also give you help on the mex commands to use.

请先登录,再进行评论。


Titus Edelhofer
Titus Edelhofer 2012-3-26
Hi,
you don't need to change your code. Yes, the mex interface is with void, but there is nothing wrong doing something like the following
void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
{
// N is the first input argument
int N = (int) mxGetPr(prhs[0])[0];
int result = ThisFunction(int N);
plhs[0] = mxCreateDoubleScalar(result);
}
Or did I miss something?
Titus

Carine
Carine 2012-3-26
Well, Titus, I am sure I am missing something as I had tried something similar but it doesn't work:
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <time.h>
#ifdef _WIN32
#include <windows.h>
#else
#include <sys/utsname.h>
#endif
#include "mex.h"
int *gft_1dPartitions(unsigned int N) {
/*void gft_1dPartitions(unsigned int N, int *partitions) {*/
int *partitions;
[...]
partitions[pcount] = ep;
partitions[pOff-pcount] = en;
[...]
return partitions;
}
void mexFunction( int nlhs, mxArray *plhs[],
int nrhs, const mxArray *prhs[] )
{
int N, *partitions;
int taille,k;
/* get the scalar value of the input x */
/* note: mxGetScalar returns a value, not a pointer */
N = mxGetScalar(prhs[0]);
partitions = gft_1dPartitions(N);
/* assign a pointer to the output */
taille = 2*round(log2(N))+1;
plhs[0] = mxCreateNumericMatrix(1, taille, mxINT32_CLASS, mxREAL);
/*partitions = (int*) mxGetData(plhs[0]);*/
/* Call the subroutine. */
/*gft_1dPartitions(N, partitions);*/
return;
}
And if I try to run it: mxPartitionGFT(16), it only gives me 0's.

Titus Edelhofer
Titus Edelhofer 2012-3-26
Hi,
I see. I would suggest the following:
int *pr;
[...]
// this is the result from the function:
partitions = gft_1dPartitions(N);
// this is the pointer to the result data in plhs:
pr = (int*) mxGetData(plhs[0]);
// copy partitions to pr
memcpy(pr, partions, taille*sizeof(int));
[...]
// probably you need to free the memory?
free(partitions);
Titus

Carine
Carine 2012-3-28
Thanks for your answers. James, this does work but for other applications, I would like to make it work with the C function being of type (int *) instead of void. Titus, I have tried to follow your advice but still can't make it. When I compile it, I've got a message "assignation from a pointer type incompatible" for memcpy. And I don't know if a mxMalloc is useful in the C-function but it doesn't seem to help or work so I comment it. Here is the entire code:
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <time.h>
#ifdef _WIN32
#include <windows.h>
#else
#include <sys/utsname.h>
#endif
#include "mex.h"
int *gft_1dPartitions(unsigned int N) {
/*void gft_1dPartitions(unsigned int N, int *partitions) {*/
int sf = 1;
int cf = 1;
int width = 1;
int pcount = 0;
int pOff;
int *partitions;
int ep,en;
/*partitions = (int *)mxMalloc((round(log2(N))*2+1)*sizeof(int));*/
pOff = round(log2(N))*2-1;
while (sf < N/2) {
ep = cf+width/2-1;
en = N-cf+width/2+1;
if (ep > N) ep = N;
if (width/2 == 0)
ep+=1;
partitions[pcount] = ep;
partitions[pOff-pcount] = en;
pcount++;
sf = sf+width;
if (sf > 2) width *= 2;
cf = sf+width/2;
}
partitions[pOff+1] = -1;
return partitions;
}
void mexFunction( int nlhs, mxArray *plhs[],
int nrhs, const mxArray *prhs[] )
{
int N, *partitions, *pr;
int taille,k, sizpart;
/* get the scalar value of the input x */
/* note: mxGetScalar returns a value, not a pointer */
N = mxGetScalar(prhs[0]);
/* assign a pointer to the output */
taille = 2*round(log2(N))+1;
partitions = gft_1dPartitions(N);
plhs[0] = mxCreateNumericMatrix(1, taille, mxINT32_CLASS, mxREAL);
pr = (int*) mxGetData(plhs[0]);
/* sizpart = mxGetElementSize(partitions);*/
memcpy(pr, partitions, taille*sizeof(int)); /*sizpart);*/
/* Call the subroutine. */
/*gft_1dPartitions(N, partitions);*/
free(partitions);
return;
}
Any other idea? Cheers.
  2 个评论
Jan
Jan 2012-3-28
If you create an mxArray of type UINT32, be sure *not* to create an (int *) pointer to its data. This will crash on 64 bit machines. Better use a (uint32_T *) pointer.
Currently the function is writing to an un-allocated partitions* array. This cannot work.
Jan
Jan 2012-3-28
James suggestion is very good and it is helpful to solve your problem. He is an experienced C-programmer. If his suggestion does not match your program design, it is worth to consider to change the design.

请先登录,再进行评论。


Carine
Carine 2012-4-25
Thanks for all your support and sorry for not answering before but I was busy with other things. For the moment, I've transformed my C functions to be void and then avoid this problems but I am sure there is something obvious I don't understand (a newbie...). So, here is a part of the piece of code I run:
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
/* mwSize N; */
int N, *partitions;
int taille, i;
double *partdouble;
double *sig, *gft, *win, *tmp;
char *windowtype;
void *window;
mxArray *plhs1[1], *prhs1[1];
/* create a pointer to the real data in the input matrix */
sig = mxGetPr(prhs[0]);
/* get dimensions of the input matrix */
N = mxGetM(prhs[0]);
if (N == 1)
N = mxGetN(prhs[0]);
/* Compute partition sizes */
taille = 2*round(log2(N))+1;
partitions = mxMalloc(taille);
/* partitions = (int*) mxGetData(plhs[0]);*/
/* Call the subroutine. */
gft_1dPartitions(N, partitions);
mexPrintf("partitions = %d\n",partitions[1]);
/* create the output matrix */
plhs[0] = mxCreateDoubleMatrix(1, N, mxREAL);
/* plhs[0] = mxCreateNumericMatrix(1, taille, mxINT32_CLASS, mxREAL);*/
/* get a pointer to the real data in the output matrix */
gft = mxGetPr(plhs[0]);
gft[0] = (double)partitions[0];
if (nrhs == 1)
windowtype = "gaussian";
else
windowtype = mxArrayToString(prhs[1]); /*mexGetString*/
if (windowtype != "gaussian" && windowtype != "box")
mexErrMsgTxt("Window type must be gaussian or box");
if (windowtype == "gaussian")
window = &gaussian;
else
window = &box;
mexPrintf("window2 = %s\n", windowtype);
return;
}
So I have nearly emptied the function of its content. Then to run it, I do the following:
mex -I/usr/include -L/usr/lib64/ -lfftw3 gft1d.c
a = randn(1,16); gft1d(a)
It does print out what I have asked:
partitions = 2
window2 = gaussian
but then Matlab crashes. When I try to use the debugger using gdb, http://www.mathworks.es/help/techdoc/matlab_external/f32489.html#bq3wlv9-1, it just tells me
Program received signal SIGUSR1, User defined signal 1.
pthread_cond_wait@@GLIBC_2.3.2 ()
at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S:165
165 62: movl (%rsp), %edi
and I have no clue what it means :-( Any help? Cheers
  1 个评论
James Tursa
James Tursa 2012-4-25
At first glance, it looks like you are not calling mxMalloc correctly in this line:
partitions = mxMalloc(taille);
mxMalloc (like its C counterpart malloc) allocate the number of bytes requested, and I am guessing that taille is the number of *elements* you want for partitions, not the number of *bytes*. So do this instead:
partitions = mxMalloc(taille * sizeof(*partitions));
You should get in the habit of always using the form above for calling mxMalloc (or malloc) in your code. I.e., always have your coded line look like this pattern:
mypointer = malloc( (number_of_elements) * sizeof(*mypointer) );
You can get arguments both ways as to whether or not you should explicitly cast the result of malloc in the above line. In C++ you have to. In C it is optional. Leaving it out in C gives the compiler a chance to generate an error in the above line if the prototype for malloc is missing.

请先登录,再进行评论。


Carine
Carine 2012-4-26
Thanks James! It does work. But now, if I include some more lines in the code, making use of the following function
void fft(int N, double *in, int stride) {
fftw_plan p;
p = fftw_plan_many_dft(1,&N, 1, (fftw_complex *)in, NULL, stride, 0, (fftw_complex *)in, NULL, stride, 0, FFTW_FORWARD, FFTW_ESTIMATE);
printf("fft\n");
fftw_execute(p);
fftw_destroy_plan(p);
}
and using the fftw3 library, Matlab crashes again at the moment of the call of fftw_plan_many_dft. As this code doesn't come from what I have written, I am even more lost :-(
The fft function is called in the following one:
void gaussian(double *win, int N, int freq) {
int i;
double x;
double sum;
for (i = 0; i<N*2; i+=2) {
x = i / (N*2+0.0);
win[i] = abs(freq)/sqrt(2*PI)*exp(-pow((x-0.5),2)*pow(freq,2)/2.0);
win[i+1] = 0.0;
sum += win[i];
}
/* Make sure the window area is 1.0*/
for (i = 0; i<N*2; i+=2) {
win[i] /= sum;
}
shift(win,N,-N/2);
printf("Gaussian shift\n");
fft(N,win,1);
printf("Gaussian fft\n");
}

Carine
Carine 2012-5-2
As I cannot sort it out, I am now trying the suboptimal possibility of using the matlab fft by
void gaussian(double *win, int N, int freq) {
int i;
double x;
double sum;
for (i = 0; i<N*2; i+=2) {
x = i / (N*2+0.0);
win[i] = abs(freq)/sqrt(2*PI)*exp(-pow((x-0.5),2)*pow(freq,2)/2.0);
win[i+1] = 0.0;
sum += win[i];
}
/* Make sure the window area is 1.0*/
for (i = 0; i<N*2; i+=2) {
win[i] /= sum;
}
shift(win,N,-N/2);
/* fft(N,win,1); It doesn't work so use the Matlab fft*/
mexCallMATLAB(1,win,1,&win,"fft");
printf("Gaussian fft\n");
}
But mxCallMATLAB expects a mxArray type and I don't know how to transform my double *win input/output parameter to a mxArray. Could I ask your help again?
Cheers.
  1 个评论
James Tursa
James Tursa 2012-5-3
The best way to turn win into an mxArray is to do it *before* you call gaussian. E.g.,
mxArray *mx;
double *win;
mx = mxCreateDoubleMatrix(1, N*2, mxREAL);
win = mxGetPr(mx);
gaussian( win, N, freq );
But if you can't do it that way for some reason, then you can copy the data inside gaussian(). E.g.,
void gaussian( etc ) {
:
mxArray *mx;
double *pr;
mx = mxCreateDoubleMatrix( 1, N*2, mxREAL );
pr = mxGetPr(mx);
for( i=0; i<N*2; i++ ) {
pr[i] = win[i];
}

请先登录,再进行评论。

类别

Help CenterFile Exchange 中查找有关 Write C Functions Callable from MATLAB (MEX Files) 的更多信息

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by