From 4a974bb428d3960aface3e1760b33e169c7c733a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Villemot?= <sebastien@dynare.org> Date: Fri, 26 Oct 2018 11:44:26 +0200 Subject: [PATCH] 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. --- src/ComputingTasks.cc | 2 +- src/DataTree.cc | 45 ----------------- src/DataTree.hh | 4 -- src/DynamicModel.cc | 16 ++---- src/DynamicModel.hh | 4 +- src/DynareMain.cc | 67 ++++++++++++++----------- src/DynareMain2.cc | 19 +++---- src/ModFile.cc | 46 ++++------------- src/ModFile.hh | 8 +-- src/ModelTree.cc | 112 ++++++++++++++++++++++++++++++++++++++++++ src/ModelTree.hh | 6 +++ src/StaticModel.cc | 16 ++---- src/StaticModel.hh | 4 +- 13 files changed, 190 insertions(+), 159 deletions(-) diff --git a/src/ComputingTasks.cc b/src/ComputingTasks.cc index 72d669f4..3368a963 100644 --- a/src/ComputingTasks.cc +++ b/src/ComputingTasks.cc @@ -2174,7 +2174,7 @@ PlannerObjectiveStatement::computingPass() void 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 diff --git a/src/DataTree.cc b/src/DataTree.cc index 78947a0d..2b713a81 100644 --- a/src/DataTree.cc +++ b/src/DataTree.cc @@ -829,51 +829,6 @@ DataTree::writePowerDeriv(ostream &output) const << "}" << 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 DataTree::packageDir(const string &package) { diff --git a/src/DataTree.hh b/src/DataTree.hh index bc86662b..1b3453f5 100644 --- a/src/DataTree.hh +++ b/src/DataTree.hh @@ -276,10 +276,6 @@ public: void writePowerDerivCHeader(ostream &output) const; //! Write getPowerDeriv in C 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 class UnknownDerivIDException { diff --git a/src/DynamicModel.cc b/src/DynamicModel.cc index 81ae7133..912f261e 100644 --- a/src/DynamicModel.cc +++ b/src/DynamicModel.cc @@ -27,8 +27,6 @@ #include <iterator> #include <numeric> -#include <boost/filesystem.hpp> - #include "DynamicModel.hh" void @@ -1738,11 +1736,6 @@ DynamicModel::writeDynamicCFile(const string &basename, const int order) const << " * Warning : this file is generated automatically by Dynare" << endl << " * from model file (.mod)" << endl << " */" << endl -#if defined(_WIN32) || defined(__CYGWIN32__) - << "#ifdef _MSC_VER" << endl - << "#define _USE_MATH_DEFINES" << endl - << "#endif" << endl -#endif << "#include <math.h>" << endl; 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 writePowerDerivCHeader(mDynamicModelFile); - writeNormcdfCHeader(mDynamicModelFile); mDynamicModelFile << endl; @@ -1766,7 +1758,6 @@ DynamicModel::writeDynamicCFile(const string &basename, const int order) const mDynamicModelFile << endl; writePowerDeriv(mDynamicModelFile); - writeNormcdf(mDynamicModelFile); mDynamicModelFile.close(); mDynamicMexFile.open(filename_mex, ios::out | ios::binary); @@ -4920,7 +4911,7 @@ DynamicModel::collectBlockVariables() } 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) 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) writeSparseDynamicMFile(basename); else if (use_dll) - writeDynamicCFile(basename, order); + { + writeDynamicCFile(basename, order); + compileDll(basename, "dynamic", mexext, matlabroot, dynareroot); + } else if (julia) writeDynamicJuliaFile(basename); else diff --git a/src/DynamicModel.hh b/src/DynamicModel.hh index 9e1b553a..341221c7 100644 --- a/src/DynamicModel.hh +++ b/src/DynamicModel.hh @@ -23,6 +23,8 @@ using namespace std; #include <fstream> + +#include <boost/filesystem.hpp> #include <boost/crc.hpp> #include "StaticModel.hh" @@ -359,7 +361,7 @@ public: 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; //! 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 void writeParamsDerivativesFile(const string &basename, bool julia) const; diff --git a/src/DynareMain.cc b/src/DynareMain.cc index 3f17bc01..6aff26d3 100644 --- a/src/DynareMain.cc +++ b/src/DynareMain.cc @@ -28,6 +28,9 @@ #endif #include <unistd.h> + +#include <boost/filesystem.hpp> + #include "ParsingDriver.hh" #include "ExtendedPreprocessorTypes.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, WarningConsolidation &warnings_arg, bool nostrict, bool stochastic, bool check_model_changes, bool minimal_workspace, bool compute_xrefs, FileOutputType output_mode, - LanguageOutputType lang, int params_derivs_order, bool transform_unary_ops -#if defined(_WIN32) || defined(__CYGWIN32__) - , bool cygwin, bool msvc, bool mingw -#endif - , JsonOutputPointType json, JsonFileOutputType json_output_mode, bool onlyjson, bool jsonderivsimple - , bool nopreprocessoroutput - ); + LanguageOutputType lang, int params_derivs_order, bool transform_unary_ops, + JsonOutputPointType json, JsonFileOutputType json_output_mode, bool onlyjson, bool jsonderivsimple, + bool nopreprocessoroutput, const string &mexext, const boost::filesystem::path &matlabroot, + const boost::filesystem::path &dynareroot); 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 ¯o_output); @@ -59,10 +59,8 @@ usage() << " [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]" << " [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]" + << " [dll=matlab|octave] [matlabroot=path]" << endl; exit(EXIT_FAILURE); } @@ -99,11 +97,6 @@ main(int argc, char **argv) bool console = false; bool nograph = false; bool nointeractive = false; -#if defined(_WIN32) || defined(__CYGWIN32__) - bool cygwin = false; - bool msvc = false; - bool mingw = false; -#endif string parallel_config_file; bool parallel = false; string cluster_name; @@ -124,6 +117,11 @@ main(int argc, char **argv) bool jsonderivsimple = false; LanguageOutputType language{LanguageOutputType::matlab}; bool nopreprocessoroutput = false; + string mexext; + boost::filesystem::path matlabroot; + boost::filesystem::path dynareroot{argv[0]}; + dynareroot = dynareroot.parent_path(); + dynareroot = dynareroot / ".." / ".."; // Parse options for (int arg = 2; arg < argc; arg++) @@ -180,14 +178,6 @@ main(int argc, char **argv) nograph = true; else if (!strcmp(argv[arg], "nointeractive")) 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)) { if (strlen(argv[arg]) <= 9 || argv[arg][8] != '=') @@ -332,6 +322,28 @@ main(int argc, char **argv) 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 { cerr << "Unknown option: " << argv[arg] << endl; @@ -400,12 +412,9 @@ main(int argc, char **argv) main2(macro_output, basename, debug, clear_all, clear_global, no_tmp_terms, no_log, no_warn, warn_uninit, console, nograph, nointeractive, parallel, config_file, warnings, nostrict, stochastic, check_model_changes, minimal_workspace, - compute_xrefs, output_mode, language, params_derivs_order, transform_unary_ops -#if defined(_WIN32) || defined(__CYGWIN32__) - , cygwin, msvc, mingw -#endif - , json, json_output_mode, onlyjson, jsonderivsimple, nopreprocessoroutput - ); + compute_xrefs, output_mode, language, params_derivs_order, transform_unary_ops, + json, json_output_mode, onlyjson, jsonderivsimple, nopreprocessoroutput, + mexext, matlabroot, dynareroot); return EXIT_SUCCESS; } diff --git a/src/DynareMain2.cc b/src/DynareMain2.cc index 9958aa42..3d7b6dc6 100644 --- a/src/DynareMain2.cc +++ b/src/DynareMain2.cc @@ -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, WarningConsolidation &warnings, bool nostrict, bool stochastic, bool check_model_changes, bool minimal_workspace, bool compute_xrefs, FileOutputType output_mode, - LanguageOutputType language, int params_derivs_order, bool transform_unary_ops -#if defined(_WIN32) || defined(__CYGWIN32__) - , bool cygwin, bool msvc, bool mingw -#endif - , JsonOutputPointType json, JsonFileOutputType json_output_mode, bool onlyjson, bool jsonderivsimple - , bool nopreprocessoroutput - ) + LanguageOutputType language, int params_derivs_order, bool transform_unary_ops, + JsonOutputPointType json, JsonFileOutputType json_output_mode, bool onlyjson, bool jsonderivsimple, + bool nopreprocessoroutput, const string &mexext, const boost::filesystem::path &matlabroot, + const boost::filesystem::path &dynareroot) { 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); else mod_file->writeOutputFiles(basename, clear_all, clear_global, no_log, no_warn, console, nograph, - nointeractive, config_file, check_model_changes, minimal_workspace, compute_xrefs -#if defined(_WIN32) || defined(__CYGWIN32__) - , cygwin, msvc, mingw -#endif - , nopreprocessoroutput - ); + nointeractive, config_file, check_model_changes, minimal_workspace, compute_xrefs, + nopreprocessoroutput, mexext, matlabroot, dynareroot); if (!nopreprocessoroutput) cout << "Preprocessing completed." << endl; diff --git a/src/ModFile.cc b/src/ModFile.cc index 6ff0b55a..9881d863 100644 --- a/src/ModFile.cc +++ b/src/ModFile.cc @@ -789,12 +789,10 @@ ModFile::computingPass(bool no_tmp_terms, FileOutputType output, int params_deri void 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 check_model_changes, bool minimal_workspace, bool compute_xrefs -#if defined(_WIN32) || defined(__CYGWIN32__) - , bool cygwin, bool msvc, bool mingw -#endif - , const bool nopreprocessoroutput - ) const + bool check_model_changes, bool minimal_workspace, bool compute_xrefs, + const bool nopreprocessoroutput, const string &mexext, + const boost::filesystem::path &matlabroot, + const boost::filesystem::path &dynareroot) const { bool hasModelChanged = !dynamic_model.isChecksumMatching(basename, block); 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 << "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 << "M_.eq_nbr = " << dynamic_model.equation_number() << ";" << 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) { - 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); } 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); } - 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); } @@ -1189,11 +1161,11 @@ ModFile::writeExternalFilesJulia(const string &basename, FileOutputType output, mod_file_struct.estimation_present, false, true); if (!no_static) { - static_model.writeStaticFile(basename, false, false, false, true); + static_model.writeStaticFile(basename, false, false, false, "", {}, {}, true); static_model.writeParamsDerivativesFile(basename, true); } 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); } steady_state_model.writeSteadyStateFile(basename, mod_file_struct.ramsey_model_present, true); diff --git a/src/ModFile.hh b/src/ModFile.hh index 04e8cdbe..22a27a4c 100644 --- a/src/ModFile.hh +++ b/src/ModFile.hh @@ -162,12 +162,8 @@ public: */ 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 check_model_changes, bool minimal_workspace, bool compute_xrefs -#if defined(_WIN32) || defined(__CYGWIN32__) - , bool cygwin, bool msvc, bool mingw -#endif - , const bool nopreprocessoroutput - ) const; + bool check_model_changes, bool minimal_workspace, bool compute_xrefs, + const bool nopreprocessoroutput, const string &mexext, const boost::filesystem::path &matlabroot, const boost::filesystem::path &dynareroot) 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; diff --git a/src/ModelTree.cc b/src/ModelTree.cc index a5fa1196..4e3d2959 100644 --- a/src/ModelTree.cc +++ b/src/ModelTree.cc @@ -2308,3 +2308,115 @@ ModelTree::writeJsonModelEquations(ostream &output, bool residuals) const } 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); + } +} diff --git a/src/ModelTree.hh b/src/ModelTree.hh index e335e5d7..ccf27a40 100644 --- a/src/ModelTree.hh +++ b/src/ModelTree.hh @@ -29,6 +29,8 @@ using namespace std; #include <ostream> #include <array> +#include <boost/filesystem.hpp> + #include "DataTree.hh" #include "ExtendedPreprocessorTypes.hh" @@ -338,6 +340,10 @@ private: /*! Copies all the structures that contain ExprNode*, by the converting the pointers into their equivalent in the new tree */ 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: ModelTree(SymbolTable &symbol_table_arg, diff --git a/src/StaticModel.cc b/src/StaticModel.cc index 549dfe0b..80851ee9 100644 --- a/src/StaticModel.cc +++ b/src/StaticModel.cc @@ -25,8 +25,6 @@ #include <cerrno> #include <algorithm> -#include <boost/filesystem.hpp> - #include "StaticModel.hh" #include "DynamicModel.hh" @@ -2061,11 +2059,6 @@ StaticModel::writeStaticCFile(const string &basename) const << " * Warning : this file is generated automatically by Dynare" << 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; 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 writePowerDerivCHeader(output); - writeNormcdfCHeader(output); output << endl; @@ -2089,7 +2081,6 @@ StaticModel::writeStaticCFile(const string &basename) const output << endl; writePowerDeriv(output); - writeNormcdf(output); output.close(); output.open(filename_mex, ios::out | ios::binary); @@ -2174,7 +2165,7 @@ StaticModel::writeStaticJuliaFile(const string &basename) const } 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) writeModelEquationsCode_Block(basename, map_idx, map_idx2); @@ -2186,7 +2177,10 @@ StaticModel::writeStaticFile(const string &basename, bool block, bool bytecode, writeStaticBlockMFSFile(basename); } else if (use_dll) - writeStaticCFile(basename); + { + writeStaticCFile(basename); + compileDll(basename, "static", mexext, matlabroot, dynareroot); + } else if (julia) writeStaticJuliaFile(basename); else diff --git a/src/StaticModel.hh b/src/StaticModel.hh index b7d6aba3..28d4ad87 100644 --- a/src/StaticModel.hh +++ b/src/StaticModel.hh @@ -24,6 +24,8 @@ using namespace std; #include <fstream> +#include <boost/filesystem.hpp> + #include "ModelTree.hh" class DynamicModel; @@ -201,7 +203,7 @@ public: int &u_count_int, bool &file_open) const; //! 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) void writeJsonOutput(ostream &output) const; -- GitLab