Setting the output directory of mex files in the compiler command - matlab

My Project has the following structure:
MainFolder:
>>InitToolbox.m //Here addpaths are executed
>>Compile.m //Here mex compilations calls are made
AlgorithmsFolder //MATLAB code
UtilitiesFolder //MATLAB code
MexFolder // C++ files
>>test1.cpp
>>test2.cu
Whever I run (either in compile.m or directly in the command line) the following compiler call:
mex -v -largeArrayDims ./MexFolder/test1.cpp ./MexFolder/test2.cu
The output test1.mexw64 is saved in MainFolder.
Is there any way to modify the compiler call to create the .mexw64 file either on the original location of the files or in an specific user defined location?

You want to specify the output directory using the outdir option for mex
mex -v -largeArrayDims ./MexFolder/test1.cpp ./MexFolder/test2.cu -outdir output_directory
"output_directory" above can be any path you want.
It can also be a variable, but that would require you to update the way you're calling mex
outputFolder = 'path/to/folder';
mex('-v', '-largeArrayDims', 'MexFolder/test1.cpp', ...
'MexFolder/test2.cu', '-outputdir', outputFolder);

Related

Control mex link options with g++ from command line

I'm trying to link a library using mex from command line, or more exactly, from a makefile. I do this from a Makefile which I post here:
BDDM_MATLAB = #matlabhome#
MEXCC = $(BDDM_MATLAB)/bin/mex
MEXFLAGS = -v -largeArrayDims -O
MEXEXT = mexa64
TDIR = $(abs_top_srcdir)/test
IDIR = $(abs_top_srcdir)/src
LDIR = $(abs_top_srcdir)/lib
LOP1 = $(CUDA_LDFLAGS) $(LIBS)
SOURCES := $(wildcard *.cpp)
OBJS = $(SOURCES:.cpp=.o)
mTESTS = $(addprefix $(TDIR)/, $(SOURCES:.cpp=.$(MEXEXT)))
all: $(TDIR) $(mTESTS)
$(OBJS) : %.o : %.cpp
$(MEXCC) $(MEXFLAGS) -c -outdir ./ -output $# $(CUDA_CFLAGS) -I$(IDIR) CFLAGS="\$$CFLAGS -std=c99" $^
$(mTESTS) : $(TDIR)/%.$(MEXEXT) : %.o
$(MEXCC) $(MEXFLAGS) -L$(LDIR) -outdir $(TDIR) $^ $(LOP1) -lmpdcm LDFLAGS="-lcudart -lcuda"
.PHONY = $(TDIR)
$(TDIR):
$(MKDIR_P) $#
clean:
$(RM) *.o
libmpdcm is a static library that includes calls to two shared libraries libcuda and libcudart. My environment has
export LD_LIBRARY_PATH=/usr/local/cuda-7.0/lib64:$LD_LIBRARY_PATH:
My make rule produces
/usr/local/MATLAB/R2014a/bin/mex -v -largeArrayDims -O -L/home/eaponte/projects/test_cpp/lib -outdir /home/eaponte/projects/test_cpp/test test_LayeredEEG.o -L/usr/local/cuda/lib64 -lcudart -lcuda -lmpdcm LDFLAGS="-lcudart -lcuda"
This produces the following g++ command:
/usr/bin/gcc -lcudart -lcuda -shared -O -Wl,--version-script,"/usr/local/MATLAB/R2014a/extern/lib/glnxa64/mexFunction.map" test_LayeredEEG.o -lcudart -lcuda -lmpdcm -L/home/eaponte/projects/test_cpp/lib -L/usr/local/cuda/lib64 -L"/usr/local/MATLAB/R2014a/bin/glnxa64" -lmx -lmex -lmat -lm -lstdc++ -o /home/eaponte/projects/test_cpp/test/test_LayeredEEG.mexa64
The problem is that afterwards I get a linking error in Matlab:
Invalid MEX-file '/home/eaponte/projects/test_cpp/test/test_Fmri.mexa64': /home/eaponte/projects/test_cpp/test/test_Fmri.mexa64: undefined symbol: cudaFree
I know that the solution is simply to put the cuda libraries at the end of the g++ command
/usr/bin/gcc -lcudart -lcuda -shared -O -Wl,--version-script,"/usr/local/MATLAB/R2014a/extern/lib/glnxa64/mexFunction.map" test_LayeredEEG.o -lmpdcm -L/home/eaponte/projects/test_cpp/lib -L/usr/local/cuda/lib64 -L"/usr/local/MATLAB/R2014a/bin/glnxa64" -lmx -lmex -lmat -lm -lstdc++ -lcudart -lcuda -o /home/eaponte/projects/test_cpp/test/test_LayeredEEG.mexa64
How can achieve that running mex from command line (or from a Makefile)?
Just to illuminate the problem and solution and offer some help in avoiding the like:
The fundamental rule of linkage with the GNU linker
that your problem makefile transgressed is: In the commandline sequence of entities to be linked, ones that need symbol definitions
must appear before the ones that provide the definitions.
An object file (.o) in the linkage sequence will be incorporated entire in the output executable,
regardless of whether or not it defines any symbols that the executable uses. A library
on the other hand, is merely examined to see if it provides any definitions for symbols
that are thus-far undefined, and only such definitions as it provides are linked into in
the executable (I am simplifying somewhat). Thus, linkage doesn't get started until some object file is seen,
and any library must appear after everything that needs definitions from it.
Breaches of this principle usually arise from inept bundling of some linker flag-options
and some library-options together into a make-variable and its placement in the linkage recipe,
with the result that the bundled options are interpolated at a position that is valid for
the flags but not valid for libraries. This was so in your problem makefile, with LOP1 the
bad bundle.
In the typical case, the bundling causes all of the libraries to be placed before all the object files,
and never mentioned again. So the object files yield undefined symbol errors, because the libraries
they require were seen by the linker before it had discovered any undefined symbols, and were ignored.
In your untypical case, it resulted in libcudart and libcuda being seen later than your only
object file test_LayeredEEG.o - which however required no symbols from them - but earlier than
the only thing that did require symbols from them, the library libmpdcm. So they were ignored,
and you built a .mex64 shared library that had not been linked with them.
Long ago - pre-GCC 4.5 - shared libraries (like libcudart and libcuda) were exempt
from the requirement that they should be needed, at the point when the linker sees them,
in order to be linked. They were linked regardless, like object files, and the belief that
this is so has not entirely died out. It is not so. By default, shared libraries and
static libraries alike are linked if and only if needed-when-seen.
To avoid such traps it is vastly helpful to understand the canonical nomenclature of
the make variables involved in compilation and linkage and their semantics, and
their canonical use in compilation and linkage recipes for make. Mex is a
manipulator of C/C++/Fortran compilers that adds some commandline options of its own:
for make purposes, it is another compiler. For the options that it inherits from and
passes to the underlying compiler, you want to adhere to the usage for that compiler in make recipes.
These are the make variables most likely to matter to you and their meanings:
CC = Your C compiler, e.g. gcc
FC = Your Fortran compiler, e.g. gfortran
CXX = Your C++ compiler, e.g. g++.
LD = Your linker, e.g. ld. But you should know that only for specialized uses
should the linker be directly invoked. Normally, the real linker is invoked on your
behalf by the compiler. It can deduce from the options that you pass it whether you
want compiling done or linking done, and will invoke the appropriate tool. When you
want linking done, it will quietly augment the linker options that you pass with
additional ones that it would be very tiresome to specify, but which ensure
that the linkage acquires all the the correct flags and libraries for the language of the
program you are linking. Consequently almost always, specify your compiler as your
linker.
AR = Your archiving tool (static library builder)
CFLAGS = Options for C compilation
FFLAGS = Options for Fortran compilation
CXXFLAGS = Options for C++ compilation
CPPFLAGS = Options for the C preprocessor, for any compiler that uses it. Avoid the common mistake of writing CPPFLAGS when you mean CXXFLAGS
LDFLAGS = Options for linkage, N.B. excluding library options, -l<name>
LDLIBS = Library options for linkage, -l<name>
And the canonical make rules for compiling and linking:
C source file $< to object file $#:
$(CC) $(CPPFLAGS) $(CFLAGS) -c $# $<
Free-from Fortran file $< to object file $#, with preprocessing:
$(FC) $(CPPFLAGS) $(FFLAGS) -c $# $<
(without preprocessing, remove $(CPPFLAGS))
C++ source file $< to object file $#:
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $# $<
Linking object files $^ into an executable $#:
$(<compiler>) $(LDFLAGS) -o $# $^ $(LDLIBS)
If you can as much as possible write makefiles so that a) you have assigned the right options to the right variables from
this glossary, and b) used the canonical make recipes, then your path will be much smoother.
And BTW...
Your makefile has the following bug:
.PHONY = $(TDIR)
This is apparently an attempt to make $(TDIR) a phony target,
but the syntax is wrong. It should be:
.PHONY: $(TDIR)
what the assignment does is simply create a make variable called, .PHONY with the value of $(TDIR),
and does not make $(TDIR) a phony target.
Which is fortunate, because $(TDIR) is your output directory and not a phony
target.
You wish to ensure that make creates $(TDIR) before you need to output anything into
it, but you do not want it to a normal prequisite of those artefacts, which would oblige
make to rebuild them whenever the timestamp of $(TDIR) was touched. That is presumably
why you thought to make it a phony target.
What you actually want $(TDIR) to be is an order-only prerequsite
of the $(mTESTS) that will be output there. The way to do that is to amend the $(mTESTS) rule to be:
$(mTESTS) : $(TDIR)/%.$(MEXEXT) : %.o | $(TDIR)
This will cause $(TDIR) to be made, if needed, before $(mTESTS) is made, but
nevertheless $(TDIR) will not be considered in determining whether $(mTESTS) does
need to be made.
On the other hand, the targets all and clean are phony targets: no such artefacts
are to be made, so you should tell make so with:
.PHONY: all clean
As pointed out in the comments, the problem was in the order of the dynamic libraries in the compilation flags. After searching the reason for this I found in SO that static libraries need to be linked taking into account the order of dependency. In my case, the library libmpdc had dependencies on libcuda and libcudart but was on the left. The solution is to swap the order in the makefile from:
$(mTESTS) : $(TDIR)/%.$(MEXEXT) : %.o
$(MEXCC) $(MEXFLAGS) -L$(LDIR) -outdir $(TDIR) $^ $(LOP1) -lmpdcm LDFLAGS="-lcudart -lcuda"
to
$(mTESTS) : $(TDIR)/%.$(MEXEXT) : %.o
$(MEXCC) $(MEXFLAGS) -L$(LDIR) -outdir $(TDIR) $^ -lmpdcm $(LOP1)

Compile the C-file in MATLAB

Description
I got a Mathematica Symbolic Toolbox for MATLAB--Version 2.0 here
Then I using the documentation it cotained to compile in MATLAB enviroment
Installation steps:
1)Go to your Mathematica directory and locate the file mathlink.h in
E:\math\Mathematica\5.\AddOns\MathLink\DeveloperKit\Windows\CompilerAdditions\mldev32\include'
and also the file ml32i1m.lib in
E:\math\Mathematica\5.\AddOns\MathLink\DeveloperKit\Windows\CompilerAdditions\mldev32\lib. Copy both files to a predetermined directory (we will refer to this directory as C:\xxx).
2) Copy the content of compressed file math.tar into C:\xxx.
3) Open Matlab command window and execute mex –setup. Choose “Microsoft Visual C/C++ version 6.0 in C:\Program Files\Microsoft Visual Studio”. This tells Matlab that it needs to use a C compiler (as opposed to Fortran compiler). You’ll need Microsoft Visual C/C++ installed. Do not choose the “Lcc C version 2.4 in C:\MATLAB6P1\sys\lcc” option.
4) Open Matlab command window and run mathrun.m. This program will compile the C-file math.c.
The file I got shown as belew:
Then I do step by step
(1) Find the mathlink.h and ml32i1m.lib in the following path
D:\WolframResearch\Mathematica\8.0\SystemFiles\Links\MathLink\DeveloperKit\Windows\CompilerAdditions\mldev32\include
D:\Wolfram Research\Mathematica\8.0\SystemFiles\Links\MathLink\DeveloperKit\Windows\CompilerAdditions\mldev32\lib
(2)Copy the content of compressed file math.zip into C:\XXX
(3) Compile in MATLAB
mex -setup
(4)last setp
addpath C:\XXX
run mathrun.m
I don't know why?
Update
The matlab code in mathrun.m
addpath C:\XXX;
% adds the directory C:\XXX to the list of directories which Matlab "sees" (referred to as paths)
mlpath='C:\XXX' % The directory where mathlink.h is
mllib='C:\XXX\ml32i1m.lib' % The library ml32i1m.lib
% make command
command=sprintf('mex -D__STDC __ -I % s % s % s', mlpath, 'math.c', mllib);
% compile
eval(command)
Seems like the path is not correctly passed to mex, so it cannot find math.c. Comment the original line:
%command=sprintf('mex -D__STDC __ -I % s % s % s', mlpath, 'math.c', mllib);
and add this one instead:
command=sprintf('mex -D__STDC __ -I%s %s %s', mlpath, 'math.c', mllib);
because the mex documentation specifies that there should be no space between the -I switch and the input path. To be really on the safe side, you can even write:
command=sprintf('mex -D__STDC __ -I%s %s %s', mlpath, fullfile(mlpath,'math.c'), mllib);

Errors in linking fortran code that imports a MAT-file [duplicate]

This question already has an answer here:
Reading data from matlab files into C
(1 answer)
Closed 7 years ago.
I have to import a MAT-file in a fortran program. I followed the example file but I am facing some problems while linking. The compilation happens fine.
Minimal code:
#include "fintrf.h"
PROGRAM main
USE ssa
USE dmotifs
USE param
IMPLICIT NONE
! MAT-FILE Declarations !
INTEGER matOpen, matGetDir
INTEGER matGetVariableInfo
INTEGER mp, dir, adir(100), pa
INTEGER mxGetM, mxGetN, matClose
INTEGER ndir, i, clstat
CHARACTER*32 names(100)
!===========================!
if(all(fnames(:)%fn .NE. argfun)) then
write(*,*) "No such motif: ",argfun
write(*,*) "Input format-> main <motifname>"
stop
else
fin=fchton(argfun)
y0=nM2m*analys(p,argfun)
! ==> OPEN MAT-file <== !
mp=matOpen('./PRMS_lxr_29Apr15.mat','r')
if (mp .eq. 0) then
write(6,*) "Can't open MAT-file"
stop
end if
dir = matgetdir(mp, ndir)
if (dir .eq. 0) then
write(6,*) "Can't read MAT-file-directory."
stop
endif
call mxCopyPtrToPtrArray(dir, adir, ndir)
do 20 i=1,ndir
call mxCopyPtrToCharacter(adir(i), names(i), 32)
20 continue
write(6,*) 'Directory of Mat-file:'
do 30 i=1,ndir
write(6,*) names(i)
30 continue
write(6,*) 'Getting Header info from first array.'
pa = matGetVariableInfo(mp, names(1))
write(6,*) 'Retrieved ', names(1)
write(6,*) ' With size ', mxGetM(pa), '-by-', mxGetN(pa)
call mxDestroyArray(pa)
clstat=matClose(mp)
end if
END PROGRAM main
I am using gfortran 4.8.3 for compiling+linking using the default command:
gfortran main.f90 dmotifs.o param.o ssa.o -o main
This code compiles fine (without linking) when I do not include: #include "finitrf.h", otherwise the compiler says
Warning: main.f90:1: Illegal preprocessor directive
I tried renaming finitrf.h to finitrf.f90 but it did not make any difference. Nonetheless during linking I am getting these errors:
main.f90:(.text+0x3ea): undefined reference to `matopen_'
main.f90:(.text+0x487): undefined reference to `matgetdir_'
main.f90:(.text+0x52b): undefined reference to `mxcopyptrtoptrarray_'
main.f90:(.text+0x583): undefined reference to `mxcopyptrtocharacter_'
main.f90:(.text+0x71b): undefined reference to `matgetvariableinfo_'
main.f90:(.text+0x804): undefined reference to `mxgetm_'
main.f90:(.text+0x855): undefined reference to `mxgetn_'
main.f90:(.text+0x89c): undefined reference to `mxdestroyarray_'
main.f90:(.text+0x8b0): undefined reference to `matclose_'
collect2: error: ld returned 1 exit status
Do I need a makefile or add additional arguments in the compile command?
EDIT:
I added the -cpp option and that eliminates the problem of Illegal preprocessor directive
Now when I am compiling with paths to matlab external components (where finitf.h) is, I am still getting the same error.
gfortran main.f90 dmotifs.o param.o ssa.o -I/usr/local/matlab2008a/extern/include -L/usr/local/matlab2008a/extern/lib -cpp -o main
If I provide library path to /usr/local/matlab2008a/bin/glnxa64 that contains other matlab libraries including libmat.so, I still get the same errors.
For lower case file extensions *.f90 or *.f the pre-processor is typically deactivated. To enable that, either rename the (main) file to have a capital extension *.F90 or *.F, or provide the corresponding command-line option (-cpp for gfortran, -fpp for ifort).
Assuming the missing subroutines/functions are actually declared in fintrf.h, this should solve your problem.
You should additionally tell the compiler to link against the libraries containing the Matlab functions.
As pointed out by Alexander Vogt, the compiler requires -cpp option for the pre-processor to recognize the header file and not to treat it as illegal.
Linking requires finitrf.h which is usually located in the <matlabroot>/extern/include and the essential libraries are present in <matlabroot>/bin/<arch>/.
But just specifying this does not work and specification of the exact matlab library seems essential; these are libmat.so and libmx.so.
These libraries are in turn dependent on other libraries so another flag is required to set the rpath.
Finally it works with following command:
gfortran main.f90 dmotifs.o param.o ssa.o -I/usr/local/matlab2008a/extern/include -L/usr/local/matlab2008a/bin/glnxa64 -cpp -o main -lmat -lmx -Wl,-rpath /usr/local/matlab2008a/bin/glnxa64/
or in general
gfortran program.f90 -I<matlabroot>/extern/include -L<matlabroot>/bin/<arch> -cpp -lmat -lmx -Wl, -rpath <matlabroot>/bin/<arch> -o program.out
Also see this post that is about the same problem in C.

Linking to static libraries to build static executable

I am trying to build a static executable of a C program which requires the following libraries from the Postgresql libecpg-dev package: libecpg, libpq, and libpgtypes. The static libraries, libecpg.a, libpq.a, libpgtypes.a, are all located in the same place as their dynamic versions, /usr/lib. I have tried adding the -L option as their path anyway, but I get the same result.
My executable needs to be static so that the binary can be portable so that users will not have to install the libraries onto their systems to use it. The program builds fine when I use the following command with the dynamic libraries: (The -I directory has to be included for some of the Postgresql functions I'm using)
gcc main.o -lecpg -lpq -lpgtypes -I/usr/include/postgresql -o program_name
When I try to link to the static libraries, I am using the following command:
gcc -static main.o -lecpg -lpq -lpgtypes -I/usr/include/postgresql -o program_name
The compiler, however, gives me a long list of "undefined reference" errors as output. There are so many, but here is a small sampling:
/usr/lib/gcc/x86_64-linux-gnu/4.6/../../../../lib/libecpg.a(descriptor.o):
In function `get_descriptors':
(.text+0xc3): undefined reference to `pthread_once'
/usr/lib/gcc/x86_64-linux-gnu/4.6/../../../../lib/libecpg.a(descriptor.o): In function `ECPGdeallocate_desc':
(.text+0x2c6): undefined reference to `pthread_setspecific'
/usr/lib/gcc/x86_64-linux-gnu/4.6/../../../../lib/libecpg.a(descriptor.o): In function `ECPGallocate_desc':
(.text+0x376): undefined reference to `pthread_setspecific'
/usr/lib/gcc/x86_64-linux-gnu/4.6/../../../../lib/libecpg.a(descriptor.o): In function `get_descriptors':
(.text+0xd2): undefined reference to `pthread_getspecific'
When I change the order as follows:
gcc -I/usr/include/postgresql -static -lecpg -lpq -lpgtypes -o program_name main.o
the compiler output instead looks like the following (once again, just a small sampling):
main.c:(.text+0x5c6): undefined reference to `ECPGconnect'
main.c:(.text+0x83e): undefined reference to `ECPGdo'
main.c:(.text+0x843): undefined reference to `ECPGget_sqlca'
main.c:(.text+0x85c): undefined reference to `ECPGdisconnect'
main.c:(.text+0x87c): undefined reference to `ECPGget_sqlca'
I have tried using the -I option all around (along with all of the other options), but nothing seems to work.
I think you just can't create a fully static non-trivial executable in modern Linux distribution anymore. But you can statically include some specific libraries.
Try it like that:
gcc main.o /usr/include/postgresql/libecpg.a /usr/include/postgresql/libecpg.a /usr/include/postgresql/libpq.a /usr/include/postgresql/libpgtypes.a -o program_name

compilemex in Statistical Pattern Recognition Toolbox in Matlab

I am new to Statistical Pattern Recognition Toolbox in matlab.
I am trying to use the oaasvm function in this toolbox. Before using this I need to run the compilemex.m. But when I run it I get the following error
>> compilemex
Compiling MEX files of STPRtool...
mex -O -IC:\Program Files\MATLAB\R2013a\toolbox\stprtool\kernels -outdir C:\Program Files\MATLAB\R2013a\toolbox\stprtool\kernels C:\Program Files\MATLAB\R2013a\toolbox\stprtool\kernels\kernel.c C:\Program Files\MATLAB\R2013a\toolbox\stprtool\kernels\kernel_fun.c
Error using mex (line 206)
The destination directory "C:\Program" cannot be found.
Error in compilemex (line 113)
eval(mexstr);
Can anyone tell how shall I proceed to run the oaasvm code?
As explained by Schorsch in the comments, you need to add quotes around path strings to handle spaces in them.
The fix is easy, edit the file compilemex.m, look for the following section (line 102), and make the below changes:
% -- Compile functions -----------------------------
for i=1:length(fun),
mexstr = ['mex -O -I''' translate(fun(i).include,root) ...
''' -outdir ''' translate(fun(i).outdir, root) ''' '];
for j=1:length(fun(i).source),
mexstr = [mexstr '''' translate(char(fun(i).source(j)),root) ''' '];
end
fprintf('%s\n',mexstr);
eval(mexstr);
end
Basically I've added single quotes (escaped by singe quote) around path strings. The result is that the commands executed will be of the form:
mex -O -I'C:\Documents and Settings\Amro\Desktop\stprtool\kernels'
-outdir 'C:\Documents and Settings\Amro\Desktop\stprtool\kernels'
'C:\Documents and Settings\Amro\Desktop\stprtool\kernels\kernel.c'
'C:\Documents and Settings\Amro\Desktop\stprtool\kernels\kernel_fun.c'
Note that you dont have to place this package inside the MATLAB installation. You can place the extracted folder anywhere on your system, as long as you add it to the MATLAB path addpath