The preprocessor now compiles the MEX when use_dll is specified

New options "mexext" and "matlabroot" are introduced, so that the preprocessor
knows where to find MATLAB and which architecture to compile for.

Only recent gcc is now supported. A set of optimization flags is used so that
compilation goes reasonably fast on large models.

Consequently, options "msvc", "mingw" and "cygwin" have been removed.
issue#70
Sébastien Villemot 2018-10-26 11:44:26 +02:00
parent 1c33af4844
commit 4a974bb428
No known key found for this signature in database
GPG Key ID: 2CECE9350ECEBE4A
13 changed files with 190 additions and 159 deletions

View File

@ -2174,7 +2174,7 @@ PlannerObjectiveStatement::computingPass()
void void
PlannerObjectiveStatement::writeOutput(ostream &output, const string &basename, bool minimal_workspace) const PlannerObjectiveStatement::writeOutput(ostream &output, const string &basename, bool minimal_workspace) const
{ {
model_tree.writeStaticFile(basename + ".objective", false, false, false, false); model_tree.writeStaticFile(basename + ".objective", false, false, false, "", {}, {}, false);
} }
void void

View File

@ -829,51 +829,6 @@ DataTree::writePowerDeriv(ostream &output) const
<< "}" << endl; << "}" << endl;
} }
void
DataTree::writeNormcdfCHeader(ostream &output) const
{
#if defined(_WIN32) || defined(__CYGWIN32__)
if (isTrinaryOpUsed(TrinaryOpcode::normcdf))
output << "#ifdef _MSC_VER" << endl
<< "double normcdf(double);" << endl
<< "#endif" << endl;
#endif
}
void
DataTree::writeNormcdf(ostream &output) const
{
#if defined(_WIN32) || defined(__CYGWIN32__)
if (isTrinaryOpUsed(TrinaryOpcode::normcdf))
output << endl
<< "#ifdef _MSC_VER" << endl
<< "/*" << endl
<< " * Define normcdf for MSVC compiler" << endl
<< " */" << endl
<< "double normcdf(double x)" << endl
<< "{" << endl
<< "#if _MSC_VER >= 1700" << endl
<< " return 0.5 * erfc(-x * M_SQRT1_2);" << endl
<< "#else" << endl
<< " // From http://www.johndcook.com/blog/cpp_phi" << endl
<< " double a1 = 0.254829592;" << endl
<< " double a2 = -0.284496736;" << endl
<< " double a3 = 1.421413741;" << endl
<< " double a4 = -1.453152027;" << endl
<< " double a5 = 1.061405429;" << endl
<< " double p = 0.3275911;" << endl
<< " int sign = (x < 0) ? -1 : 1;" << endl
<< " x = fabs(x)/sqrt(2.0);" << endl
<< " // From the Handbook of Mathematical Functions by Abramowitz and Stegun, formula 7.1.26" << endl
<< " double t = 1.0/(1.0 + p*x);" << endl
<< " double y = 1.0 - (((((a5*t + a4)*t) + a3)*t + a2)*t + a1)*t*exp(-x*x);" << endl
<< " return 0.5*(1.0 + sign*y);" << endl
<< "#endif" << endl
<< "}" << endl
<< "#endif" << endl;
#endif
}
string string
DataTree::packageDir(const string &package) DataTree::packageDir(const string &package)
{ {

View File

@ -276,10 +276,6 @@ public:
void writePowerDerivCHeader(ostream &output) const; void writePowerDerivCHeader(ostream &output) const;
//! Write getPowerDeriv in C //! Write getPowerDeriv in C
void writePowerDeriv(ostream &output) const; void writePowerDeriv(ostream &output) const;
//! Write the C Header for normcdf when use_dll is used
void writeNormcdfCHeader(ostream &output) const;
//! Write normcdf in C
void writeNormcdf(ostream &output) const;
//! Thrown when trying to access an unknown variable by deriv_id //! Thrown when trying to access an unknown variable by deriv_id
class UnknownDerivIDException class UnknownDerivIDException
{ {

View File

@ -27,8 +27,6 @@
#include <iterator> #include <iterator>
#include <numeric> #include <numeric>
#include <boost/filesystem.hpp>
#include "DynamicModel.hh" #include "DynamicModel.hh"
void void
@ -1738,11 +1736,6 @@ DynamicModel::writeDynamicCFile(const string &basename, const int order) const
<< " * Warning : this file is generated automatically by Dynare" << endl << " * Warning : this file is generated automatically by Dynare" << endl
<< " * from model file (.mod)" << endl << " * from model file (.mod)" << endl
<< " */" << endl << " */" << endl
#if defined(_WIN32) || defined(__CYGWIN32__)
<< "#ifdef _MSC_VER" << endl
<< "#define _USE_MATH_DEFINES" << endl
<< "#endif" << endl
#endif
<< "#include <math.h>" << endl; << "#include <math.h>" << endl;
if (external_functions_table.get_total_number_of_unique_model_block_external_functions()) if (external_functions_table.get_total_number_of_unique_model_block_external_functions())
@ -1756,7 +1749,6 @@ DynamicModel::writeDynamicCFile(const string &basename, const int order) const
// Write function definition if BinaryOpcode::powerDeriv is used // Write function definition if BinaryOpcode::powerDeriv is used
writePowerDerivCHeader(mDynamicModelFile); writePowerDerivCHeader(mDynamicModelFile);
writeNormcdfCHeader(mDynamicModelFile);
mDynamicModelFile << endl; mDynamicModelFile << endl;
@ -1766,7 +1758,6 @@ DynamicModel::writeDynamicCFile(const string &basename, const int order) const
mDynamicModelFile << endl; mDynamicModelFile << endl;
writePowerDeriv(mDynamicModelFile); writePowerDeriv(mDynamicModelFile);
writeNormcdf(mDynamicModelFile);
mDynamicModelFile.close(); mDynamicModelFile.close();
mDynamicMexFile.open(filename_mex, ios::out | ios::binary); mDynamicMexFile.open(filename_mex, ios::out | ios::binary);
@ -4920,7 +4911,7 @@ DynamicModel::collectBlockVariables()
} }
void void
DynamicModel::writeDynamicFile(const string &basename, bool block, bool linear_decomposition, bool bytecode, bool use_dll, int order, bool julia) const DynamicModel::writeDynamicFile(const string &basename, bool block, bool linear_decomposition, bool bytecode, bool use_dll, const string &mexext, const boost::filesystem::path &matlabroot, const boost::filesystem::path &dynareroot, int order, bool julia) const
{ {
if (block && bytecode) if (block && bytecode)
writeModelEquationsCode_Block(basename, map_idx, linear_decomposition); writeModelEquationsCode_Block(basename, map_idx, linear_decomposition);
@ -4933,7 +4924,10 @@ DynamicModel::writeDynamicFile(const string &basename, bool block, bool linear_d
else if (block && !bytecode) else if (block && !bytecode)
writeSparseDynamicMFile(basename); writeSparseDynamicMFile(basename);
else if (use_dll) else if (use_dll)
writeDynamicCFile(basename, order); {
writeDynamicCFile(basename, order);
compileDll(basename, "dynamic", mexext, matlabroot, dynareroot);
}
else if (julia) else if (julia)
writeDynamicJuliaFile(basename); writeDynamicJuliaFile(basename);
else else

View File

@ -23,6 +23,8 @@
using namespace std; using namespace std;
#include <fstream> #include <fstream>
#include <boost/filesystem.hpp>
#include <boost/crc.hpp> #include <boost/crc.hpp>
#include "StaticModel.hh" #include "StaticModel.hh"
@ -359,7 +361,7 @@ public:
void Write_Inf_To_Bin_File_Block(const string &basename, void Write_Inf_To_Bin_File_Block(const string &basename,
const int &num, int &u_count_int, bool &file_open, bool is_two_boundaries, const bool linear_decomposition) const; const int &num, int &u_count_int, bool &file_open, bool is_two_boundaries, const bool linear_decomposition) const;
//! Writes dynamic model file //! Writes dynamic model file
void writeDynamicFile(const string &basename, bool block, bool linear_decomposition, bool bytecode, bool use_dll, int order, bool julia) const; void writeDynamicFile(const string &basename, bool block, bool linear_decomposition, bool bytecode, bool use_dll, const string &mexext, const boost::filesystem::path &matlabroot, const boost::filesystem::path &dynareroot, int order, bool julia) const;
//! Writes file containing parameters derivatives //! Writes file containing parameters derivatives
void writeParamsDerivativesFile(const string &basename, bool julia) const; void writeParamsDerivativesFile(const string &basename, bool julia) const;

View File

@ -28,6 +28,9 @@
#endif #endif
#include <unistd.h> #include <unistd.h>
#include <boost/filesystem.hpp>
#include "ParsingDriver.hh" #include "ParsingDriver.hh"
#include "ExtendedPreprocessorTypes.hh" #include "ExtendedPreprocessorTypes.hh"
#include "ConfigFile.hh" #include "ConfigFile.hh"
@ -41,13 +44,10 @@ void main2(stringstream &in, string &basename, bool debug, bool clear_all, bool
bool nograph, bool nointeractive, bool parallel, ConfigFile &config_file, bool nograph, bool nointeractive, bool parallel, ConfigFile &config_file,
WarningConsolidation &warnings_arg, bool nostrict, bool stochastic, bool check_model_changes, WarningConsolidation &warnings_arg, bool nostrict, bool stochastic, bool check_model_changes,
bool minimal_workspace, bool compute_xrefs, FileOutputType output_mode, bool minimal_workspace, bool compute_xrefs, FileOutputType output_mode,
LanguageOutputType lang, int params_derivs_order, bool transform_unary_ops LanguageOutputType lang, int params_derivs_order, bool transform_unary_ops,
#if defined(_WIN32) || defined(__CYGWIN32__) JsonOutputPointType json, JsonFileOutputType json_output_mode, bool onlyjson, bool jsonderivsimple,
, bool cygwin, bool msvc, bool mingw bool nopreprocessoroutput, const string &mexext, const boost::filesystem::path &matlabroot,
#endif const boost::filesystem::path &dynareroot);
, JsonOutputPointType json, JsonFileOutputType json_output_mode, bool onlyjson, bool jsonderivsimple
, bool nopreprocessoroutput
);
void main1(string &modfile, string &basename, string &modfiletxt, bool debug, bool save_macro, string &save_macro_file, void main1(string &modfile, string &basename, string &modfiletxt, bool debug, bool save_macro, string &save_macro_file,
bool no_line_macro, bool no_empty_line_macro, map<string, string> &defines, vector<string> &path, stringstream &macro_output); bool no_line_macro, bool no_empty_line_macro, map<string, string> &defines, vector<string> &path, stringstream &macro_output);
@ -59,10 +59,8 @@ usage()
<< " [console] [nograph] [nointeractive] [parallel[=cluster_name]] [conffile=parallel_config_path_and_filename] [parallel_slave_open_mode] [parallel_test]" << " [console] [nograph] [nointeractive] [parallel[=cluster_name]] [conffile=parallel_config_path_and_filename] [parallel_slave_open_mode] [parallel_test]"
<< " [-D<variable>[=<value>]] [-I/path] [nostrict] [stochastic] [fast] [minimal_workspace] [compute_xrefs] [output=dynamic|first|second|third] [language=julia]" << " [-D<variable>[=<value>]] [-I/path] [nostrict] [stochastic] [fast] [minimal_workspace] [compute_xrefs] [output=dynamic|first|second|third] [language=julia]"
<< " [params_derivs_order=0|1|2] [transform_unary_ops]" << " [params_derivs_order=0|1|2] [transform_unary_ops]"
#if defined(_WIN32) || defined(__CYGWIN32__)
<< " [cygwin] [msvc] [mingw]"
#endif
<< " [json=parse|check|transform|compute] [jsonstdout] [onlyjson] [jsonderivsimple] [nopathchange] [nopreprocessoroutput]" << " [json=parse|check|transform|compute] [jsonstdout] [onlyjson] [jsonderivsimple] [nopathchange] [nopreprocessoroutput]"
<< " [dll=matlab|octave] [matlabroot=path]"
<< endl; << endl;
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@ -99,11 +97,6 @@ main(int argc, char **argv)
bool console = false; bool console = false;
bool nograph = false; bool nograph = false;
bool nointeractive = false; bool nointeractive = false;
#if defined(_WIN32) || defined(__CYGWIN32__)
bool cygwin = false;
bool msvc = false;
bool mingw = false;
#endif
string parallel_config_file; string parallel_config_file;
bool parallel = false; bool parallel = false;
string cluster_name; string cluster_name;
@ -124,6 +117,11 @@ main(int argc, char **argv)
bool jsonderivsimple = false; bool jsonderivsimple = false;
LanguageOutputType language{LanguageOutputType::matlab}; LanguageOutputType language{LanguageOutputType::matlab};
bool nopreprocessoroutput = false; bool nopreprocessoroutput = false;
string mexext;
boost::filesystem::path matlabroot;
boost::filesystem::path dynareroot{argv[0]};
dynareroot = dynareroot.parent_path();
dynareroot = dynareroot / ".." / "..";
// Parse options // Parse options
for (int arg = 2; arg < argc; arg++) for (int arg = 2; arg < argc; arg++)
@ -180,14 +178,6 @@ main(int argc, char **argv)
nograph = true; nograph = true;
else if (!strcmp(argv[arg], "nointeractive")) else if (!strcmp(argv[arg], "nointeractive"))
nointeractive = true; nointeractive = true;
#if defined(_WIN32) || defined(__CYGWIN32__)
else if (!strcmp(argv[arg], "cygwin"))
cygwin = true;
else if (!strcmp(argv[arg], "msvc"))
msvc = true;
else if (!strcmp(argv[arg], "mingw"))
mingw = true;
#endif
else if (strlen(argv[arg]) >= 8 && !strncmp(argv[arg], "conffile", 8)) else if (strlen(argv[arg]) >= 8 && !strncmp(argv[arg], "conffile", 8))
{ {
if (strlen(argv[arg]) <= 9 || argv[arg][8] != '=') if (strlen(argv[arg]) <= 9 || argv[arg][8] != '=')
@ -332,6 +322,28 @@ main(int argc, char **argv)
usage(); usage();
} }
} }
else if (strlen(argv[arg]) >= 6 && !strncmp(argv[arg], "mexext", 6))
{
string s{argv[arg]};
if (s.length() <= 7 || s.at(6) != '=')
{
cerr << "Incorrect syntax for mexext option" << endl;
usage();
}
s.erase(0, 7);
mexext = s;
}
else if (strlen(argv[arg]) >= 10 && !strncmp(argv[arg], "matlabroot", 10))
{
string s{argv[arg]};
if (s.length() <= 11 || s.at(10) != '=')
{
cerr << "Incorrect syntax for matlabroot option" << endl;
usage();
}
s.erase(0, 11);
matlabroot = boost::filesystem::path{s};
}
else else
{ {
cerr << "Unknown option: " << argv[arg] << endl; cerr << "Unknown option: " << argv[arg] << endl;
@ -400,12 +412,9 @@ main(int argc, char **argv)
main2(macro_output, basename, debug, clear_all, clear_global, main2(macro_output, basename, debug, clear_all, clear_global,
no_tmp_terms, no_log, no_warn, warn_uninit, console, nograph, nointeractive, no_tmp_terms, no_log, no_warn, warn_uninit, console, nograph, nointeractive,
parallel, config_file, warnings, nostrict, stochastic, check_model_changes, minimal_workspace, parallel, config_file, warnings, nostrict, stochastic, check_model_changes, minimal_workspace,
compute_xrefs, output_mode, language, params_derivs_order, transform_unary_ops compute_xrefs, output_mode, language, params_derivs_order, transform_unary_ops,
#if defined(_WIN32) || defined(__CYGWIN32__) json, json_output_mode, onlyjson, jsonderivsimple, nopreprocessoroutput,
, cygwin, msvc, mingw mexext, matlabroot, dynareroot);
#endif
, json, json_output_mode, onlyjson, jsonderivsimple, nopreprocessoroutput
);
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }

View File

@ -32,13 +32,10 @@ main2(stringstream &in, string &basename, bool debug, bool clear_all, bool clear
bool nograph, bool nointeractive, bool parallel, ConfigFile &config_file, bool nograph, bool nointeractive, bool parallel, ConfigFile &config_file,
WarningConsolidation &warnings, bool nostrict, bool stochastic, bool check_model_changes, WarningConsolidation &warnings, bool nostrict, bool stochastic, bool check_model_changes,
bool minimal_workspace, bool compute_xrefs, FileOutputType output_mode, bool minimal_workspace, bool compute_xrefs, FileOutputType output_mode,
LanguageOutputType language, int params_derivs_order, bool transform_unary_ops LanguageOutputType language, int params_derivs_order, bool transform_unary_ops,
#if defined(_WIN32) || defined(__CYGWIN32__) JsonOutputPointType json, JsonFileOutputType json_output_mode, bool onlyjson, bool jsonderivsimple,
, bool cygwin, bool msvc, bool mingw bool nopreprocessoroutput, const string &mexext, const boost::filesystem::path &matlabroot,
#endif const boost::filesystem::path &dynareroot)
, JsonOutputPointType json, JsonFileOutputType json_output_mode, bool onlyjson, bool jsonderivsimple
, bool nopreprocessoroutput
)
{ {
ParsingDriver p(warnings, nostrict); ParsingDriver p(warnings, nostrict);
@ -72,12 +69,8 @@ main2(stringstream &in, string &basename, bool debug, bool clear_all, bool clear
mod_file->writeExternalFiles(basename, output_mode, language, nopreprocessoroutput); mod_file->writeExternalFiles(basename, output_mode, language, nopreprocessoroutput);
else else
mod_file->writeOutputFiles(basename, clear_all, clear_global, no_log, no_warn, console, nograph, mod_file->writeOutputFiles(basename, clear_all, clear_global, no_log, no_warn, console, nograph,
nointeractive, config_file, check_model_changes, minimal_workspace, compute_xrefs nointeractive, config_file, check_model_changes, minimal_workspace, compute_xrefs,
#if defined(_WIN32) || defined(__CYGWIN32__) nopreprocessoroutput, mexext, matlabroot, dynareroot);
, cygwin, msvc, mingw
#endif
, nopreprocessoroutput
);
if (!nopreprocessoroutput) if (!nopreprocessoroutput)
cout << "Preprocessing completed." << endl; cout << "Preprocessing completed." << endl;

View File

@ -789,12 +789,10 @@ ModFile::computingPass(bool no_tmp_terms, FileOutputType output, int params_deri
void void
ModFile::writeOutputFiles(const string &basename, bool clear_all, bool clear_global, bool no_log, bool no_warn, ModFile::writeOutputFiles(const string &basename, bool clear_all, bool clear_global, bool no_log, bool no_warn,
bool console, bool nograph, bool nointeractive, const ConfigFile &config_file, bool console, bool nograph, bool nointeractive, const ConfigFile &config_file,
bool check_model_changes, bool minimal_workspace, bool compute_xrefs bool check_model_changes, bool minimal_workspace, bool compute_xrefs,
#if defined(_WIN32) || defined(__CYGWIN32__) const bool nopreprocessoroutput, const string &mexext,
, bool cygwin, bool msvc, bool mingw const boost::filesystem::path &matlabroot,
#endif const boost::filesystem::path &dynareroot) const
, const bool nopreprocessoroutput
) const
{ {
bool hasModelChanged = !dynamic_model.isChecksumMatching(basename, block); bool hasModelChanged = !dynamic_model.isChecksumMatching(basename, block);
if (!check_model_changes) if (!check_model_changes)
@ -955,32 +953,6 @@ ModFile::writeOutputFiles(const string &basename, bool clear_all, bool clear_glo
<< " error('DYNARE: Can''t find bytecode DLL. Please compile it or remove the ''bytecode'' option.')" << endl << " error('DYNARE: Can''t find bytecode DLL. Please compile it or remove the ''bytecode'' option.')" << endl
<< "end" << endl; << "end" << endl;
// Compile the dynamic MEX file for use_dll option
// When check_model_changes is true, don't force compile if MEX is fresher than source
if (use_dll)
{
#if defined(_WIN32) || defined(__CYGWIN32__)
if (msvc)
// MATLAB/Windows + Microsoft Visual C++
mOutputFile << "dyn_mex('msvc', '" << basename << "', " << !check_model_changes << ")" << endl;
else if (cygwin)
// MATLAB/Windows + Cygwin g++
mOutputFile << "dyn_mex('cygwin', '" << basename << "', " << !check_model_changes << ")" << endl;
else if (mingw)
// MATLAB/Windows + MinGW g++
mOutputFile << "dyn_mex('mingw', '" << basename << "', " << !check_model_changes << ")" << endl;
else
mOutputFile << "if isoctave" << endl
<< " dyn_mex('', '" << basename << "', " << !check_model_changes << ")" << endl
<< "else" << endl
<< " error('When using the USE_DLL option on Matlab, you must give the ''cygwin'', ''msvc'', or ''mingw'' option to the ''dynare'' command')" << endl
<< "end" << endl;
#else
// other configurations
mOutputFile << "dyn_mex('', '" << basename << "', " << !check_model_changes << ")" << endl;
#endif
}
mOutputFile << "M_.orig_eq_nbr = " << mod_file_struct.orig_eq_nbr << ";" << endl mOutputFile << "M_.orig_eq_nbr = " << mod_file_struct.orig_eq_nbr << ";" << endl
<< "M_.eq_nbr = " << dynamic_model.equation_number() << ";" << endl << "M_.eq_nbr = " << dynamic_model.equation_number() << ";" << endl
<< "M_.ramsey_eq_nbr = " << mod_file_struct.ramsey_eq_nbr << ";" << endl << "M_.ramsey_eq_nbr = " << mod_file_struct.ramsey_eq_nbr << ";" << endl
@ -1060,17 +1032,17 @@ ModFile::writeOutputFiles(const string &basename, bool clear_all, bool clear_glo
{ {
if (!no_static) if (!no_static)
{ {
static_model.writeStaticFile(basename, block, byte_code, use_dll, false); static_model.writeStaticFile(basename, block, byte_code, use_dll, mexext, matlabroot, dynareroot, false);
static_model.writeParamsDerivativesFile(basename, false); static_model.writeParamsDerivativesFile(basename, false);
} }
if (linear_decomposition) if (linear_decomposition)
{ {
non_linear_equations_dynamic_model.writeDynamicFile(basename, block, linear_decomposition, byte_code, use_dll, mod_file_struct.order_option, false); non_linear_equations_dynamic_model.writeDynamicFile(basename, block, linear_decomposition, byte_code, use_dll, mexext, matlabroot, dynareroot, mod_file_struct.order_option, false);
non_linear_equations_dynamic_model.writeParamsDerivativesFile(basename, false); non_linear_equations_dynamic_model.writeParamsDerivativesFile(basename, false);
} }
dynamic_model.writeDynamicFile(basename, block, false, byte_code, use_dll, mod_file_struct.order_option, false); dynamic_model.writeDynamicFile(basename, block, false, byte_code, use_dll, mexext, matlabroot, dynareroot, mod_file_struct.order_option, false);
dynamic_model.writeParamsDerivativesFile(basename, false); dynamic_model.writeParamsDerivativesFile(basename, false);
} }
@ -1189,11 +1161,11 @@ ModFile::writeExternalFilesJulia(const string &basename, FileOutputType output,
mod_file_struct.estimation_present, false, true); mod_file_struct.estimation_present, false, true);
if (!no_static) if (!no_static)
{ {
static_model.writeStaticFile(basename, false, false, false, true); static_model.writeStaticFile(basename, false, false, false, "", {}, {}, true);
static_model.writeParamsDerivativesFile(basename, true); static_model.writeParamsDerivativesFile(basename, true);
} }
dynamic_model.writeDynamicFile(basename, block, linear_decomposition, byte_code, use_dll, dynamic_model.writeDynamicFile(basename, block, linear_decomposition, byte_code, use_dll,
mod_file_struct.order_option, true); "", {}, {}, mod_file_struct.order_option, true);
dynamic_model.writeParamsDerivativesFile(basename, true); dynamic_model.writeParamsDerivativesFile(basename, true);
} }
steady_state_model.writeSteadyStateFile(basename, mod_file_struct.ramsey_model_present, true); steady_state_model.writeSteadyStateFile(basename, mod_file_struct.ramsey_model_present, true);

View File

@ -162,12 +162,8 @@ public:
*/ */
void writeOutputFiles(const string &basename, bool clear_all, bool clear_global, bool no_log, bool no_warn, void writeOutputFiles(const string &basename, bool clear_all, bool clear_global, bool no_log, bool no_warn,
bool console, bool nograph, bool nointeractive, const ConfigFile &config_file, bool console, bool nograph, bool nointeractive, const ConfigFile &config_file,
bool check_model_changes, bool minimal_workspace, bool compute_xrefs bool check_model_changes, bool minimal_workspace, bool compute_xrefs,
#if defined(_WIN32) || defined(__CYGWIN32__) const bool nopreprocessoroutput, const string &mexext, const boost::filesystem::path &matlabroot, const boost::filesystem::path &dynareroot) const;
, bool cygwin, bool msvc, bool mingw
#endif
, const bool nopreprocessoroutput
) const;
void writeExternalFiles(const string &basename, FileOutputType output, LanguageOutputType language, const bool nopreprocessoroutput) const; void writeExternalFiles(const string &basename, FileOutputType output, LanguageOutputType language, const bool nopreprocessoroutput) const;
void writeExternalFilesJulia(const string &basename, FileOutputType output, const bool nopreprocessoroutput) const; void writeExternalFilesJulia(const string &basename, FileOutputType output, const bool nopreprocessoroutput) const;

View File

@ -2308,3 +2308,115 @@ ModelTree::writeJsonModelEquations(ostream &output, bool residuals) const
} }
output << endl << "]" << endl; output << endl << "]" << endl;
} }
string
ModelTree::matlab_arch(const string &mexext)
{
if (mexext == "mexglx")
return "glnx86";
else if (mexext == "mexa64")
return "glnxa64";
if (mexext == "mexw32")
return "win32";
else if (mexext == "mexw64")
return "win64";
else if (mexext == "mexmaci")
return "maci";
else if (mexext == "mexmaci64")
return "maci64";
else
{
cerr << "ERROR: 'mexext' option to preprocessor incorrectly set, needed with 'use_dll'" << endl;
exit(EXIT_FAILURE);
}
}
void
ModelTree::compileDll(const string &basename, const string &static_or_dynamic, const string &mexext, const boost::filesystem::path &matlabroot, const boost::filesystem::path &dynareroot)
{
const string opt_flags = "-O3 -g0 --param ira-max-conflict-table-size=1 -fno-forward-propagate -fno-gcse -fno-dce -fno-dse -fno-tree-fre -fno-tree-pre -fno-tree-cselim -fno-tree-dse -fno-tree-dce -fno-tree-pta -fno-gcse-after-reload";
boost::filesystem::path compiler;
ostringstream flags;
string libs;
if (mexext == "mex")
{
// Octave
compiler = matlabroot / "bin" / "mkoctfile";
flags << "--mex";
}
else
{
// MATLAB
compiler = "gcc";
string arch = matlab_arch(mexext);
auto include_dir = matlabroot / "extern" / "include";
flags << "-I " << include_dir;
auto bin_dir = matlabroot / "bin" / arch;
flags << " -L " << bin_dir;
flags << " -fexceptions -DNDEBUG";
libs = "-lmex -lmx -lmat -lmwlapack -lmwblas";
if (mexext == "mexglx" || mexext == "mexa64")
{
// GNU/Linux
flags << " -D_GNU_SOURCE -fPIC -pthread"
<< " -shared -Wl,--no-undefined -Wl,-rpath-link," << bin_dir;
libs += " -lm -lstdc++";
if (mexext == "mexglx")
flags << " -D_FILE_OFFSET_BITS=64 -m32";
else
flags << " -fno-omit-frame-pointer";
}
else if (mexext == "mexw32" || mexext == "mexw64")
{
// Windows
flags << " -static-libgcc -static-libstdc++ -shared";
// Put the MinGW environment shipped with Dynare in the path
boost::filesystem::path mingwpath = dynareroot / (string{"mingw"} + (mexext == "mexw32" ? "32" : "64")) / "bin";
string newpath = "PATH=" + mingwpath.string() + ';' + string{getenv("PATH")};
if (putenv(const_cast<char *>(newpath.c_str())) != 0)
{
cerr << "Can't set PATH" << endl;
exit(EXIT_FAILURE);
}
}
else
{
// macOS
string archs = (mexext == "maci" ? "i386" : "x86_64");
flags << " -fno-common -arch " << archs << " -mmacosx-version-min=10.7 -Wl,-twolevel_namespace -undefined error -bundle";
libs += " -lm -lstdc++";
}
}
auto model_dir = boost::filesystem::path{basename} / "model" / "src";
boost::filesystem::path main_src{model_dir / (static_or_dynamic + ".c")},
mex_src{model_dir / (static_or_dynamic + "_mex.c")};
boost::filesystem::path mex_dir{"+" + basename};
boost::filesystem::path binary{mex_dir / (static_or_dynamic + "." + mexext)};
ostringstream cmd;
#ifdef _WIN32
/* On Windows, system() hands the command over to "cmd.exe /C". We need to
enclose the whole command line within double quotes if we want the inner
quotes to be correctly handled. See "cmd /?" for more details. */
cmd << '"';
#endif
cmd << compiler << " " << opt_flags << " " << flags.str() << " " << main_src << " " << mex_src << " -o " << binary << " " << libs;
#ifdef _WIN32
cmd << '"';
#endif
cout << "Compiling " << static_or_dynamic << " MEX..." << endl << cmd.str() << endl;
if (system(cmd.str().c_str()))
{
cerr << "Compilation failed" << endl;
exit(EXIT_FAILURE);
}
}

View File

@ -29,6 +29,8 @@ using namespace std;
#include <ostream> #include <ostream>
#include <array> #include <array>
#include <boost/filesystem.hpp>
#include "DataTree.hh" #include "DataTree.hh"
#include "ExtendedPreprocessorTypes.hh" #include "ExtendedPreprocessorTypes.hh"
@ -338,6 +340,10 @@ private:
/*! Copies all the structures that contain ExprNode*, by the converting the /*! Copies all the structures that contain ExprNode*, by the converting the
pointers into their equivalent in the new tree */ pointers into their equivalent in the new tree */
void copyHelper(const ModelTree &m); void copyHelper(const ModelTree &m);
//! Returns the name of the MATLAB architecture given the extension used for MEX files
static string matlab_arch(const string &mexext);
//! Compiles the MEX file
static void compileDll(const string &basename, const string &static_or_dynamic, const string &mexext, const boost::filesystem::path &matlabroot, const boost::filesystem::path &dynareroot);
public: public:
ModelTree(SymbolTable &symbol_table_arg, ModelTree(SymbolTable &symbol_table_arg,

View File

@ -25,8 +25,6 @@
#include <cerrno> #include <cerrno>
#include <algorithm> #include <algorithm>
#include <boost/filesystem.hpp>
#include "StaticModel.hh" #include "StaticModel.hh"
#include "DynamicModel.hh" #include "DynamicModel.hh"
@ -2061,11 +2059,6 @@ StaticModel::writeStaticCFile(const string &basename) const
<< " * Warning : this file is generated automatically by Dynare" << endl << " * Warning : this file is generated automatically by Dynare" << endl
<< " * from model file (.mod)" << endl << endl << " * from model file (.mod)" << endl << endl
<< " */" << endl << " */" << endl
#if defined(_WIN32) || defined(__CYGWIN32__)
<< "#ifdef _MSC_VER" << endl
<< "#define _USE_MATH_DEFINES" << endl
<< "#endif" << endl
#endif
<< "#include <math.h>" << endl; << "#include <math.h>" << endl;
if (external_functions_table.get_total_number_of_unique_model_block_external_functions()) if (external_functions_table.get_total_number_of_unique_model_block_external_functions())
@ -2079,7 +2072,6 @@ StaticModel::writeStaticCFile(const string &basename) const
// Write function definition if BinaryOpcode::powerDeriv is used // Write function definition if BinaryOpcode::powerDeriv is used
writePowerDerivCHeader(output); writePowerDerivCHeader(output);
writeNormcdfCHeader(output);
output << endl; output << endl;
@ -2089,7 +2081,6 @@ StaticModel::writeStaticCFile(const string &basename) const
output << endl; output << endl;
writePowerDeriv(output); writePowerDeriv(output);
writeNormcdf(output);
output.close(); output.close();
output.open(filename_mex, ios::out | ios::binary); output.open(filename_mex, ios::out | ios::binary);
@ -2174,7 +2165,7 @@ StaticModel::writeStaticJuliaFile(const string &basename) const
} }
void void
StaticModel::writeStaticFile(const string &basename, bool block, bool bytecode, bool use_dll, bool julia) const StaticModel::writeStaticFile(const string &basename, bool block, bool bytecode, bool use_dll, const string &mexext, const boost::filesystem::path &matlabroot, const boost::filesystem::path &dynareroot, bool julia) const
{ {
if (block && bytecode) if (block && bytecode)
writeModelEquationsCode_Block(basename, map_idx, map_idx2); writeModelEquationsCode_Block(basename, map_idx, map_idx2);
@ -2186,7 +2177,10 @@ StaticModel::writeStaticFile(const string &basename, bool block, bool bytecode,
writeStaticBlockMFSFile(basename); writeStaticBlockMFSFile(basename);
} }
else if (use_dll) else if (use_dll)
writeStaticCFile(basename); {
writeStaticCFile(basename);
compileDll(basename, "static", mexext, matlabroot, dynareroot);
}
else if (julia) else if (julia)
writeStaticJuliaFile(basename); writeStaticJuliaFile(basename);
else else

View File

@ -24,6 +24,8 @@ using namespace std;
#include <fstream> #include <fstream>
#include <boost/filesystem.hpp>
#include "ModelTree.hh" #include "ModelTree.hh"
class DynamicModel; class DynamicModel;
@ -201,7 +203,7 @@ public:
int &u_count_int, bool &file_open) const; int &u_count_int, bool &file_open) const;
//! Writes static model file //! Writes static model file
void writeStaticFile(const string &basename, bool block, bool bytecode, bool use_dll, bool julia) const; void writeStaticFile(const string &basename, bool block, bool bytecode, bool use_dll, const string &mexext, const boost::filesystem::path &matlabroot, const boost::filesystem::path &dynareroot, bool julia) const;
//! Write JSON Output (used by PlannerObjectiveStatement) //! Write JSON Output (used by PlannerObjectiveStatement)
void writeJsonOutput(ostream &output) const; void writeJsonOutput(ostream &output) const;