function mexfileOutput = dsPrepareMEX(mfileInput, varargin)
%PREPAREMEX - take an m-file path and compile it using the Matlab coder.
%
% See also: dsGetSolveFile
%
% Author: Jason Sherfey, PhD <jssherfey@gmail.com>
% Copyright (C) 2016 Jason Sherfey, Boston University, USA
% Input args
args = varargin;
% TODO: this block may be unnecesary since checkOptions can handle a struct
if isstruct(args{1})
% User specified an options structure
keyvals = dsOptions2Keyval(args{1});
% Convert it to keyvalues and prepend
keyvals = horzcat(keyvals,args(2:end));
else
keyvals = args;
end
options=dsCheckOptions(keyvals,{...
'verbose_flag',0,{0,1},... % set verbose to 1 by default
'mex_dir_flag',1,{0,1},... % Flag to tell whether or not to search in mex_dir for pre-compiled solve files (solve*_mex*).
'mex_dir',[],[],... % Directory to search for pre-compiled mex files. Can be relative to 'study_dir' or absolute path.
'one_solve_file_flag',0,{0,1},...
'codegen_args',[],[],...
'cluster_flag',0,{0,1},...
},false);
% % Example code for testing mex_dir options:
% eqns={
% 's=10; r=27; b=2.666'
% 'dx/dt=s*(y-x)'
% 'dy/dt=r*x-y-x*z'
% 'dz/dt=-b*z+x*y'
% };
% data=dsSimulate(eqns, 'tspan',[0 100], 'ic',[1 2 .5],'verbose',1, 'solver','rk4', 'study_dir','demo_lorenz','mex_flag',1,'mex_dir_flag',0,'mex_dir',[]);
% data=dsSimulate(eqns, 'tspan',[0 100], 'ic',[1 2 .5],'verbose',1, 'solver','rk4', 'study_dir','demo_lorenz','mex_flag',1,'mex_dir_flag',1,'mex_dir',[]);
% data=dsSimulate(eqns, 'tspan',[0 100], 'ic',[1 2 .5],'verbose',1, 'solver','rk4', 'study_dir','demo_lorenz','mex_flag',1,'mex_dir_flag',1,'mex_dir','mexes_temp');
if isempty(options.mex_dir)
options.mex_dir = dsGetConfig('mex_path');
end
mex_dir = options.mex_dir;
% make mex name from solve_file
[fpath,fname] = fileparts(mfileInput);
mexfileOutput = fullfile(fpath,[fname '_mex']);
if ~exist(mexfileOutput,'file')
if options.verbose_flag
fprintf('Compiling file: %s\n',mfileInput);
fprintf(' to: %s\n',mexfileOutput);
end
compile_start_time=tic;
makeMex(mfileInput, options); % mex-file solver for solve file
madeNewMexBool = true;
if options.verbose_flag
fprintf(' MEX generation complete! \n');
duration = toc(compile_start_time);
if duration < 60
fprintf(' Elapsed time: %.1f seconds. \n', duration);
else
fprintf(' Elapsed time: %.1f minutes. \n', duration/60);
end
end
codemex_dir = fullfile(fileparts(mexfileOutput),'codemex');
if exist(codemex_dir,'dir')
dsVprintf(options, ' Removing temporary codemex directory: %s\n', codemex_dir);
rmdir(codemex_dir,'s');
end
else % mex file exists
madeNewMexBool = false;
dsVprintf(options, 'Using previous compiled file: %s\n', mexfileOutput);
end %if
% If mex_dir is specified, back up the newly compiled mex files to this folder
if (~isempty(mex_dir) && options.mex_dir_flag && ~options.cluster_flag)... % non cluster
|| (~isempty(mex_dir) && options.mex_dir_flag && options.cluster_flag && options.one_solve_file_flag) % cluster only if one_solve_file_flag
[~,solvefile] = fileparts2(mfileInput);
[~,mexfile] = fileparts2(mexfileOutput);
if isempty(dir(fullfile(mex_dir, [solvefile '.m']))) || madeNewMexBool
dsVprintf(options, 'Solve file %s does not yet exist in mex_dir %s. Copying... \n', solvefile,mex_dir);
if ~exist(mex_dir,'dir')
error('Cannot find %s! Make sure it exists and is specified as an *absolute* path', mex_dir);
end
copyfile(mfileInput, mex_dir);
end
if isempty(dir(fullfile(mex_dir, [mexfile '*']))) || madeNewMexBool
dsVprintf(options, 'Mex file %s does not yet exist in mex_dir %s. Copying... \n', mexfile,mex_dir);
if ~exist(mex_dir,'dir')
error('Cannot find %s! Make sure it exists and is specified as an *absolute* path', mex_dir)
end
copyfile([mexfileOutput,'*'], mex_dir);
end
end
end % main fn
%% Subfunctions
function makeMex(file, options)
% Create a MEX configuration object
cfg = coder.config('mex');
% Turn on dynamic memory allocation
cfg.DynamicMemoryAllocation = 'AllVariableSizeArrays';
% Generate MEX function
if isempty(options.codegen_args)
eval(sprintf('codegen -d codemex -config cfg ''%s'' ', file));
else % codegen_args specified
%eval(sprintf('codegen -args %s -d codemex -config cfg %s', 'options.codegen_args', file));
eval(sprintf('codegen -args options.codegen_args -d codemex -config cfg ''%s'' ', file));
end
% TODO: convert eval to feval or call to codegen
end