% mtimesx_build compiles mtimesx.c with BLAS libraries %****************************************************************************** % % MATLAB (R) is a trademark of The Mathworks (R) Corporation % % Function: mtimesx_build % Filename: mtimesx_build.m % Programmer: James Tursa % Version: 1.40 % Date: October 4, 2010 % Copyright: (c) 2009, 2010 by James Tursa, All Rights Reserved % % This code uses the BSD License: % % Redistribution and use in source and binary forms, with or without % modification, are permitted provided that the following conditions are % met: % % * Redistributions of source code must retain the above copyright % notice, this list of conditions and the following disclaimer. % * Redistributions in binary form must reproduce the above copyright % notice, this list of conditions and the following disclaimer in % the documentation and/or other materials provided with the distribution % % THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" % AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE % IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE % ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE % LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR % CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF % SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS % INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN % CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) % ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE % POSSIBILITY OF SUCH DAMAGE. % %-- % % mtimesx_build compiles mtimesx.c and mtimesx_RealTimesReal.c with the BLAS % libraries libmwblas.lib (if present) or libmwlapack.lib (if libmwblas.lib % is not present). This function basically works as follows: % % - Opens the current mexopts.bat file in the directory [prefdir], and % checks to make sure that the compiler selected is cl or lcc. If it % is not, then a warning is issued and the compilation continues with % the assumption that the microsoft BLAS libraries will work. % % - Looks for the file libmwblas.lib or libmwlapack.lib files in the % appropriate directory: [matlabroot '\extern\lib\win32\microsoft'] % or [matlabroot '\extern\lib\win32\lcc'] % or [matlabroot '\extern\lib\win64\microsoft'] % or [matlabroot '\extern\lib\win64\lcc'] % % - Changes directory to the directory of the file mtimesx.m. % % - Compiles mtimesx.c (which includes mtimesx_RealTimesReal.c) along with % either libmwblas.lib or libmwlapack.lib depending on the version of % MATLAB. The resulting exedcutable mex file is placed in the same % directory as the source code. The files mtimesx.m, mtimesx.c, and % mtimesx_RealTimesReal.c must all be in the same directory. % % - Changes the directory back to the original directory. % % Change Log: % 2009/Sep/27 --> 1.00, Initial Release % 2010/Feb/15 --> 1.10, Fixed largearrardims typo to largeArrayDims % 2010/Oct/04 --> 1.40, Updated support for OpenMP compiling % %************************************************************************** function mtimesx_build(x) disp(' '); disp('... Build routine for mtimesx'); TRUE = 1; FALSE = 0; %\ % Check for number of inputs & outputs %/ noopenmp = FALSE; if( nargin == 1 ) if( isequal(upper(x),'NOOPENMP') ) noopenmp = TRUE; else error('Invalid input.'); end elseif( nargin ~= 0 ) error('Too many inputs. Expected none.'); end if( nargout ~= 0 ) error('Too many outputs. Expected none.'); end %\ % Check for non-PC %/ disp('... Checking for PC'); try % ispc does not appear in MATLAB 5.3 pc = ispc ; catch % if ispc fails, assume we are on a Windows PC if it's not unix pc = ~isunix ; end if( ~pc ) disp('Non-PC auto build is not currently supported. You will have to'); disp('manually compile the mex routine. E.g., as follows:'); disp(' '); disp('>> blas_lib = ''the_actual_path_and_name_of_your_systems_BLAS_library'''); disp('>> mex(''-DDEFINEUNIX'',''mtimesx.c'',blas_lib)'); disp(' '); disp('or'); disp(' '); disp('>> mex(''-DDEFINEUNIX'',''-largeArrayDims'',''mtimesx.c'',blas_lib)'); disp(' '); error('Unable to compile mtimesx.c'); end %\ % Check to see that mtimesx.c source code is present %/ disp('... Finding path of mtimesx C source code files'); try mname = mfilename('fullpath'); catch mname = mfilename; end cname = [mname(1:end-6) '.c']; if( isempty(dir(cname)) ) disp('Cannot find the file mtimesx.c in the same directory as the'); disp('file mtimesx_build.m. Please ensure that they are in the same'); disp('directory and try again. The following file was not found:'); disp(' '); disp(cname); disp(' '); error('Unable to compile mtimesx.c'); end disp(['... Found file mtimesx.c in ' cname]); %\ % Check to see that mtimesx_RealTimesReal.c source code is present %/ rname = [mname(1:end-13) 'mtimesx_RealTimesReal.c']; if( isempty(dir(rname)) ) disp('Cannot find the file mtimesx_RealTimesReal.c in the same'); disp('directory as the file mtimesx_build.m. Please ensure that'); disp('they are in the same directory and try again. The'); disp('following file was not found:'); disp(' '); disp(rname); disp(' '); error('Unable to compile mtimesx.c'); end disp(['... Found file mtimesx_RealTimesReal.c in ' rname]); %\ % Open the current mexopts.bat file %/ % mexopts = [prefdir '\mexopts.bat']; mexopts = [prefdir '\mex_C_win64.xml']; fid = fopen(mexopts); if( fid == -1 ) error('A C/C++ compiler has not been selected with mex -setup'); end disp(['... Opened the mexopts.bat file in ' mexopts]); disp('... Reading the mexopts.bat file to find the compiler and options used.'); %\ % Check for the correct compiler selected. %/ ok_cl = FALSE; ok_lcc = FALSE; omp_option = ''; compiler = '(unknown)'; compilername = ''; while( TRUE ) tline = fgets(fid); if( isequal(tline,-1) ) break; else if( isempty(compilername) ) y = findstr(tline,'OPTS.BAT'); if( ~isempty(y) ) x = findstr(tline,'rem '); if( ~isempty(x) ) compilername = tline(x+4:y-1); end end end x = findstr(tline,'COMPILER=lcc'); if( ~isempty(x) ) ok_lcc = TRUE; libdir = 'lcc'; compiler = 'LCC'; disp(['... ' compiler ' is the selected compiler']); break; end x = findstr(tline,'COMPILER=cl'); if( ~isempty(x) ) ok_cl = TRUE; libdir = 'microsoft'; compiler = ['Microsoft_' compilername '_cl']; omp_option = ' /openmp'; disp(['... ' compiler ' is the selected compiler']); break; end x = findstr(tline,'COMPILER=bcc32'); if( ~isempty(x) ) ok_cl = TRUE; libdir = 'microsoft'; compiler = ['Borland_' compilername '_bcc32']; disp(['... ' compiler ' is the selected compiler']); disp('... Assuming that Borland will link with Microsoft libraries'); break; end x = findstr(tline,'COMPILER=icl'); if( ~isempty(x) ) ok_cl = TRUE; if( pc ) omp_option = ' -Qopenmp'; else omp_option = ' -openmp'; end libdir = 'microsoft'; compiler = ['Intel_' compilername '_icl']; disp(['... ' compiler ' is the selected compiler']); disp('... Assuming that Intel will link with Microsoft libraries'); break; end x = findstr(tline,'COMPILER=wc1386'); if( ~isempty(x) ) ok_cl = TRUE; libdir = 'microsoft'; compiler = ['Watcom_' compilername '_wc1386']; disp(['... ' compiler ' is the selected compiler']); disp('... Assuming that Watcom will link with Microsoft libraries'); break; end x = findstr(tline,'COMPILER=gcc'); if( ~isempty(x) ) ok_cl = TRUE; libdir = 'microsoft'; omp_option = ' -fopenmp'; compiler = 'GCC'; disp(['... ' compiler ' is the selected compiler']); disp('... Assuming that GCC will link with Microsoft libraries'); break; end end end fclose(fid); %\ % MS Visual C/C++ or lcc compiler has not been selected %/ if( ~(ok_cl | ok_lcc) ) warning('... Supported C/C++ compiler has not been selected with mex -setup'); warning('... Assuming that Selected Compiler will link with Microsoft libraries'); warning('... Continuing at risk ...'); libdir = 'microsoft'; end %\ % If an OpenMP supported compiler is potentially present, make sure that the % necessary compile option is present in the mexopts.bat file on the COMPFLAGS % line. If necessary, build a new mexopts.bat file with the correct option % added to the COMPFLAGS line. %/ while( TRUE ) ok_openmp = FALSE; ok_compflags = FALSE; xname = ''; if( isempty(omp_option) ) disp('... OpenMP compiler not detected ... you may want to check this website:'); disp(' http://openmp.org/wp/openmp-compilers/'); elseif( noopenmp ) disp(['... OpenMP compiler potentially detected, but not checking for ''' omp_option ''' compile option']); else disp('... OpenMP compiler potentially detected'); disp(['... Checking to see that the ''' omp_option ''' compile option is present']); fid = fopen(mexopts); while( TRUE ) tline = fgets(fid); if( isequal(tline,-1) ) break; else x = findstr(tline,'set COMPFLAGS'); if( ~isempty(x) ) ok_compflags = TRUE; x = findstr(tline,omp_option); if( ~isempty(x) ) ok_openmp = TRUE; end break; end end end fclose(fid); if( ~ok_compflags ) warning(['... COMPFLAGS line not found ... ''' omp_option ''' will not be added.']); elseif( ~ok_openmp ) disp(['... The ''' omp_option ''' compile option is not present ... adding it']); xname = [mname(1:end-6) '_mexopts.bat']; disp(['... Creating custom options file ' xname ' with the ''' omp_option ''' option added.']); fid = fopen(mexopts); fidx = fopen(xname,'w'); if( fidx == -1 ) xname = ''; warning(['... Unable to create custom mexopts.bat file ... ''' omp_option ''' will not be added']); else while( TRUE ) tline = fgets(fid); if( isequal(tline,-1) ) break; else x = findstr(tline,'set COMPFLAGS'); if( ~isempty(x) ) n = numel(tline); e = n; while( tline(e) < 32 ) e = e - 1; end tline = [tline(1:e) omp_option tline(e+1:n)]; end fwrite(fidx,tline); end end fclose(fidx); end fclose(fid); end end %\ % Construct full file name of libmwblas.lib and libmwlapack.lib. Note that % not all versions have both files. Earlier versions only had the lapack % file, which contained both blas and lapack routines. %/ comp = computer; mext = mexext; lc = length(comp); lm = length(mext); cbits = comp(max(1:lc-1):lc); mbits = mext(max(1:lm-1):lm); if( isequal(cbits,'64') | isequal(mbits,'64') ) compdir = 'win64'; largearraydims = '-largeArrayDims'; else compdir = 'win32'; largearraydims = ''; end lib_blas = [matlabroot '\extern\lib\' compdir '\' libdir '\libmwblas.lib']; d = dir(lib_blas); if( isempty(d) ) disp('... BLAS library file not found, so linking with the LAPACK library'); lib_blas = [matlabroot '\extern\lib\' compdir '\' libdir '\libmwlapack.lib']; end disp(['... Using BLAS library lib_blas = ''' lib_blas '''']); %\ % Save old directory and change to source code directory %/ cdold = cd; if( length(mname) > 13 ) cd(mname(1:end-13)); end %\ % Do the compile %/ disp('... Now attempting to compile ...'); disp(' '); try if( isunix ) if( isempty(largearraydims) ) if( isempty(xname) ) disp(['mex(''-DDEFINEUNIX'',''' cname ''',lib_blas,''-DCOMPILER=' compiler ''')']); disp(' '); mex('-DDEFINEUNIX',cname,lib_blas,['-DCOMPILER=' compiler]); else disp(['mex(''-f'',''' xname ''',''-DDEFINEUNIX'',''' cname ''',lib_blas,''-DCOMPILER=' compiler ''')']); disp(' '); mex('-f',xname,'-DDEFINEUNIX',cname,lib_blas,['-DCOMPILER=' compiler]); end else if( isempty(xname) ) disp(['mex(''-DDEFINEUNIX'',''' cname ''',''' largearraydims ''',lib_blas,''-DCOMPILER=' compiler ''')']); disp(' '); mex('-DDEFINEUNIX',largearraydims,cname,lib_blas,['-DCOMPILER=' compiler]); else disp(['mex(''-f'',''' xname ''',''-DDEFINEUNIX'',''' cname ''',''' largearraydims ''',lib_blas,''-DCOMPILER=' compiler ''')']); disp(' '); mex('-f',xname,'-DDEFINEUNIX',largearraydims,cname,lib_blas,['-DCOMPILER=' compiler]); end end else if( isempty(largearraydims) ) if( isempty(xname) ) disp(['mex(''' cname ''',lib_blas,''-DCOMPILER=' compiler ''')']); disp(' '); mex(cname,lib_blas,['-DCOMPILER=' compiler]); else disp(['mex(''-f'',''' xname ''',''' cname ''',lib_blas,''-DCOMPILER=' compiler ''')']); disp(' '); mex('-f',xname,cname,lib_blas,['-DCOMPILER=' compiler]); end else if( isempty(xname) ) disp(['mex(''' cname ''',''' largearraydims ''',lib_blas,''-DCOMPILER=' compiler ''')']); disp(' '); mex(cname,largearraydims,lib_blas,['-DCOMPILER=' compiler]); else disp(['mex(''-f'',''' xname ''',''' cname ''',''' largearraydims ''',lib_blas,''-DCOMPILER=' compiler ''')']); disp(' '); mex('-f',xname,cname,largearraydims,lib_blas,['-DCOMPILER=' compiler]); end end end disp('... mex mtimesx.c build completed ... you may now use mtimesx.'); disp(' '); mtimesx; break; catch if( noopenmp ) cd(cdold); disp(' '); disp('... Well, *that* didn''t work either!'); disp(' '); disp('The mex command failed. This may be because you have already run'); disp('mex -setup and selected a non-C compiler, such as Fortran. If this'); disp('is the case, then rerun mex -setup and select a C/C++ compiler.'); disp(' '); error('Unable to compile mtimesx.c'); else disp(' '); disp('... Well, *that* didn''t work ...'); disp(' '); if( isequal(omp_option,' /openmp') ) disp('This may be because an OpenMP compile option was added that the'); disp('compiler did not like. For example, the Standard versions of the'); disp('Microsoft C/C++ compilers do not support OpenMP, only the'); disp('Professional versions do. Attempting to compile again but this'); disp(['time will not add the ''' omp_option ''' option.']) else disp('This may be because an OpenMP compile option was added that the'); disp('compiler did not like. Attempting to compile again, but this time'); disp(['will not add the ''' omp_option ''' option.']) end disp(' '); noopenmp = TRUE; end end end %\ % Restore old directory %/ cd(cdold); return end