From: Guillaume Jacquenot on
Dear all,

I have to create a mex interface for MatLab with a fortran 90 code.
The compiler that I have to used is gfortran 4.5 for win xp 32 bits.
My interface needs to read a MatLab string to pass its value to the
fortran code.
This is where problems start: I have problems with function using
string, specially 'mxGetString'

To have a simple example, I want to create a mex fortran program, that
reads a string in MatLab workspace.
(The code is provided below)

I use GNUmex to generate the script compilation process and also to
generate libraries needed to perform the linkage. Since I am using
Gfortran, I have to take special care about strings and MatLab mex and
mx functions.
I use bindings to call the correct library functions with
ISO_C_BINDING.

To get the value of my string, I want to use the two following
commands
ptr=mexGetVariablePtr('base', 'input_fast')
mxGetString(ptr)
where 'input_fast' is the name of the variable I want to read.

However, the value of the pointer provided as a result of
mexGetVariablePtr does not seem to provide a correct value.
Most of the time, its value is zero meaning that an error occurs.
I suspect a problem with the strings as mentioned in the file readme-
fortran.txt provided with gnumex:

"
However, gfortran seems to have a different mechanism for passing
character
strings, and the Fortran versions of these functions do not work.
Thus
mexinterface_c.f90 binds them to the corresponding C-functions (with
mixed
case names). This meens that strings passed to them from gfortran
must have
an ascii zero appended, viz:
call mexprintf('A message'//char(0))
call mexerrmsgtxt('An error occurred'//char(10)//char(0))
"

My problem is, I think, the same as described on this webpage
http://www.rhinocerus.net/forum/lang-fortran/572363-passing-string-argument-matlab-c-function.html
Btw, I tried to contact the author of this post, or leave a message on
the website, without success.
I have tried to compile the code with the -mrtd without success.

Does anyone has an idea, or can anyone can explain why the problem
with my program.

Below is the code of the simple example I want to compile.

Best regards,
Guillaume Jacquenot

My configuration is
windows xp 32 bits
MATLAB Version 7.5.0.342 (R2007b)
GNU Fortran (GCC) 4.5.0 20090421 (experimental) [trunk revision
146519]


Commands used to generated the dll/mexw32 file named
Test_GETSTRING.dll/mexw32
These commands are generated by gnumex and have been modifed add the
preprocessor and other options, such as -mrtd

!gfortran -cpp -mrtd -c -g -DMATLAB_MEX_FILE -fno-underscoring -Wall -
fmessage-length=0 -ffree-line-length-none -oSfun_all.obj -O0 -
DMX_COMPAT_32 Sfun_all.f90
!gfortran -shared d:\GFORTR~1\sfun2\GNUMEX~1\gfortmex.def -g -Wl,--
image-base,0x28000000\n -o Test_GETSTRING.mexw32 -Ld:
\GFORTR~1\sfun2\GNUMEX~1 -mrtd -enable-stdcall-fixup -s Sfun_all.obj -
lflibmx -lflibmex -lflibmat

Once the library has been generated, one needs to create the variable
the library will be looking for.
> input_fast = 'File000.txt'
And then run the library
> Test_GETSTRING
The library should display the value of the string 'input_fast'

Code:

#ifndef mwPointer
#define mwPointer integer(4)
#endif

#ifndef mwSize
#define mwSize integer(4)
#endif

module mexinterface
use, intrinsic :: ISO_C_BINDING
interface

function mxgetpr(pm) bind(c, name = 'MXGETPR')
import c_int, c_ptr
mwPointer :: pm
mwPointer :: mxgetpr
end function mxgetpr
!
function mxgetm(pm) bind(c, name = 'MXGETM')
import c_int
integer(c_int) :: pm, mxgetm
end function mxgetm
!
function mxgetn(pm) bind(c, name = 'MXGETN')
import c_int
integer(c_int) pm, mxgetn
end function mxgetn
!
function mexprintf(s) bind(C, name = 'mexPrintf')
import c_char
character(c_char) s(*)
integer(4) :: mexprintf
end function mexprintf
!

function mexgetvariableptr(workspace,varname) bind(C, name =
'MEXGETVARIABLEPTR')
import c_char
character(kind=c_char), dimension(*) :: workspace
character(kind=c_char), dimension(*) :: varname
mwPointer :: mexgetvariableptr
end function mexgetvariableptr

! GJ
subroutine mexerrmsgtxt(s) bind(C, name = 'mexErrMsgTxt')
import c_char
character(c_char) s(*)
end subroutine mexerrmsgtxt

function mxgetstring(pm, str, strlen) bind(c, name =
'MXGETSTRING')
import c_char, c_int, c_ptr, c_double
mwPointer, intent(in) :: pm
character(c_char), intent(in) :: str
mwSize, intent(in) :: strlen
integer(4) :: mxgetstring
end function mxgetstring

subroutine mexEvalString(command) bind(c, name = 'MEXEVALSTRING')
import c_char
character(c_char) :: command
end subroutine mexEvalString

end interface
end module mexinterface

subroutine mexfunction(nlhs, plhs, nrhs, prhs)
use mexinterface
implicit none
integer :: nlhs, nrhs, plhs(nlhs), prhs(nrhs)
integer :: res, M,N
mwPointer :: GStr
mwPointer :: ptr_retrn
CHARACTER*1024 InpFile
CHARACTER*100 msg

res = mexPrintf('Hello world'//char(10)//char(0))

! Problem
! ptr_retrn = mexGetVariablePtr(c_char_'base', &
! c_char_'input_fast')
!ptr_retrn = mexGetVariablePtr(c_char_'base'//
char(0),c_char_'input_fast'//char(0))
ptr_retrn = mexGetVariablePtr('base','input_fast'//char(0))
! ptr_retrn = mexGetVariablePtr('base'//char(0), 'input_fast')
! Problem

write(msg,'(A7 I15)') 'ptr = ',ptr_retrn
res = mexPrintf(msg)
IF ( ptr_retrn .eq. 0 ) THEN
CALL mexErrMsgTxt(char(10)//'ERROR: variable "input_fast"
does not exist in the MATLAB workspace.'//char(10)//char(0))
ELSE
M = mxGetM(ptr_retrn)
N = mxGetN(ptr_retrn)
write(msg,'(A7 I5)'//char(10)) 'M= ',M
res = mexPrintf(msg)
res = mexPrintf('')
write(msg,'(A7 I5)'//char(10)) 'N= ',N
res = mexPrintf(msg)
GStr = mxGetString(ptr_retrn, InpFile, M*N)
write(msg,'(A7 I15)'//char(10)) 'GStr = ',GStr
res = mexPrintf(msg)
IF (GStr /= 0) THEN
CALL mexErrMsgTxt('Error getting FAST file name from the
MATLAB workspace.'//char(10)//char(0))
ELSE
write(msg,'(A20)'//char(10)) InpFile
res = mexPrintf(msg)
ENDIF
ENDIF
end subroutine mexfunction
From: Tobias Burnus on
On 04/19/2010 11:49 AM, Guillaume Jacquenot wrote:
> I have to create a mex interface for MatLab with a fortran 90 code.
> The compiler that I have to used is gfortran 4.5 for win xp 32 bits.
> My interface needs to read a MatLab string to pass its value to the
> fortran code.
[...]

> To get the value of my string, I want to use the two following
> commands
> ptr=mexGetVariablePtr('base', 'input_fast')

> My problem is, I think, the same as described on this webpage
> http://www.rhinocerus.net/forum/lang-fortran/572363-passing-string-argument-matlab-c-function.html

It would help tremendously if you could also post the function prototype
of the relevant Matlab functions.

[...]
> These commands are generated by gnumex and have been modifed add the
> preprocessor and other options, such as -mrtd

I strongly suggest to avoid -mrtd; as the manual states:
"Warning: this calling convention is incompatible with the one normally
used [...]". As the run-time library of gfortran is compiled with CDECL
(i.e. without -mrtd/STDCALL), you might run into problems such as memory
leaks (very probably) but also all kind of weird behaviour and crashes.

If you need to use STDCALL for a function, simply use directives add the
attribute to the function interfaces which need it. Cf.
http://gcc.gnu.org/onlinedocs/gfortran/GNU-Fortran-Compiler-Directives.html

However, as STDCALL routines are dressed under Windows with the suffix
@<n> (n = bytesize of the arguments), it might well be that Matlab does
not use STDCALL but the default, C calling convention CDECL. In that
case, using -mrtd does not make sense at all.


> function mexprintf(s) bind(C, name = 'mexPrintf')
> import c_char
> character(c_char) s(*)
> integer(4) :: mexprintf
> end function mexprintf

How does the C interface look like? If it uses
"int mexPrintf (char *, ...)"
it won't work: C's "..." is not supported by Fortran's C interoperability.

It might work - when you are lucky - if you do not have any %<...>
printf formats in the string.

Otherwise, all character-taking functions without trailing "..." should
work, however. In any case, one needs to make sure that the strings are
nul ('\0') terminated by appending a //c_null_char to the string arguments.

See also:
http://gcc.gnu.org/onlinedocs/gfortran/Interoperability-with-C.html

(Using ISO_C_Binding, one should also be able to call the Fortran
functions of MatLab - if one knows how the other compiler treats
strings, and if one knows whether it uses CDECL or STDCALL calling
conventions.)

Tobias
From: Guillaume Jacquenot on
On 19 avr, 12:29, Tobias Burnus <bur...(a)net-b.de> wrote:
> On 04/19/2010 11:49 AM, Guillaume Jacquenot wrote:> I have to create a mex interface for MatLab with a fortran 90 code.

> It would help tremendously if you could also post the function prototype
> of the relevant Matlab functions.
>
The Fortran and the C equivalent prototypes are provided at the end of
this mail.
>
> I strongly suggest to avoid -mrtd; as the manual states:
> "Warning: this calling convention is incompatible with the one normally
> used [...]". As the run-time library of gfortran is compiled with CDECL
> (i.e. without -mrtd/STDCALL), you might run into problems such as memory
> leaks (very probably) but also all kind of weird behaviour and crashes.
>

The options -mrtd was the trick used by Erik Toussaint author of the
post
http://www.rhinocerus.net/forum/lang-fortran/572363-passing-string-argument-matlab-c-function.html
With this option, he managed to solve his problem.

> If you need to use STDCALL for a function, simply use directives add the
> attribute to the function interfaces which need it. Cf.http://gcc.gnu.org/onlinedocs/gfortran/GNU-Fortran-Compiler-Directive...
>
> However, as STDCALL routines are dressed under Windows with the suffix
> @<n>  (n = bytesize of the arguments), it might well be that Matlab does
> not use STDCALL but the default, C calling convention CDECL. In that
> case, using -mrtd does not make sense at all.
>
> >     function mexprintf(s) bind(C, name = 'mexPrintf')
> >       import c_char
> >       character(c_char) s(*)
> >       integer(4)  :: mexprintf
> >     end function mexprintf
>
> How does the C interface look like? If it uses
>   "int mexPrintf (char *, ...)"
> it won't work: C's "..." is not supported by Fortran's C interoperability..
>
> It might work - when you are lucky - if you do not have any %<...>
> printf formats in the string.

The function mexPrintf works fine with the little program I provided.
I have not tried with any %<...> printf format

>
> Otherwise, all character-taking functions without trailing "..." should
> work, however. In any case, one needs to make sure that the strings are
> nul ('\0') terminated by appending a //c_null_char to the string arguments.
>
> See also:http://gcc.gnu.org/onlinedocs/gfortran/Interoperability-with-C.html
>
> (Using ISO_C_Binding, one should also be able to call the Fortran
> functions of MatLab - if one knows how the other compiler treats
> strings, and if one knows whether it uses CDECL or STDCALL calling
> conventions.)

I am not familiar with the CDECL or STDCALL convention.
I will investigate what convention is used with g95 and ivf when
interfacing with Matlab

>
> Tobias



Guillaume


Here are the prototypes of the different interface function.

Below,
mwPointer is defined as integer(4)
mwSize is defined as integer(4)

mxGetPr: Get real data elements in mxArray
Fortran prototype
mwPointer mxGetPr(pm)
mwPointer pm
C prototype
double *mxGetPr(const mxArray *pm);

mexPrintf: ANSI C printf-style output routine
Fortran prototype
integer*4 mexPrintf(message)
character*(*) message
C prototype
int mexPrintf(const char *message, ...);

mexGetVariablePtr: Get read-only pointer to variable from another
workspace C
Fortran prototype
mwPointer mexGetVariablePtr(workspace, varname)
character*(*) workspace, varname
C prototype
const mxArray *mexGetVariablePtr(const char *workspace, const char
*varname);

mexErrMsgTxt: Issue error message and return to MATLAB prompt
Fortran prototype
mexErrMsgTxt(errormsg)
character*(*) errormsg
C prototype
void mexErrMsgTxt(const char *errormsg);


mxGetString: Copy string mxArray to C-style string
Fortran prototype
integer*4 mxGetString(pm, str, strlen)
mwPointer pm
character*(*) str
mwSize strlen
C prototype
int mxGetString(const mxArray *pm, char *str, mwSize strlen);


mexEvalString: Execute MATLAB command in caller's workspace
Fortran prototype
integer*4 mexEvalString(command)
character*(*) command
C prototype
int mexEvalString(const char *command);

From: James Tursa on
Guillaume Jacquenot <guillaume.jacquenot(a)gmail.com> wrote in message <dc27edee-b231-460a-9ed0-e831c3248a22(a)x12g2000yqx.googlegroups.com>...
>
> I have to create a mex interface for MatLab with a fortran 90 code.
> The compiler that I have to used is gfortran 4.5 for win xp 32 bits.
> My interface needs to read a MatLab string to pass its value to the
> fortran code.
> This is where problems start: I have problems with function using
> string, specially 'mxGetString'

Rather than trying to link with and use C routines in your Fortran program, you could opt to write your own version of mxGetString to convert the MATLAB string to a regular Fortran string. e.g., an outline of the code:

mwpointer, external :: mxGetData
mwsize, external :: mxGetNumberOfElements
mwpointer chars
mwsize n
character*80 line
:
n = mxGetNumberOfElements(ptr_retrn)
chars = mxGetData(ptr_retrn)
call myGetString(n, %val(chars), line)
:
subroutine myGetString(n, retrn, line)
implicit none
mwsize n
integer(2) retrn(n)
character(len=*) line
mwsize i, m
m = len(line)
do i=1,min(m,n)
line(i:i) = char(retrn(i))
enddo
if( n < m ) line(n+1:) = ' '
return
end subroutine myGetString

This assumes your compiler supports %val( ) and that the characters in the string are not multi-byte characters.

James Tursa
From: James Tursa on
"James Tursa" <aclassyguy_with_a_k_not_a_c(a)hotmail.com> wrote in message <hqq9ov$seu$1(a)fred.mathworks.com>...
>
> ... (It just occurred to me that the isnumeric bit in the result might not be right ... I will have to check on that and get back to you) ...

I just checked and the isnumeric bit is 0 in the result of myCreateString, which is correct so there will not need to be any adjustment.

James Tursa
 |  Next  |  Last
Pages: 1 2
Prev: calculation problem
Next: return to begin of function