diff --git a/src/ComputingTasks.cc b/src/ComputingTasks.cc
index 72d669f4fd0438ad098d873bf547bac0caea16a5..3368a963d536ae92f8d78d448d2265b183c5ee25 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 78947a0d2401501fa4d5b5ab1ef47fc481c2474e..2b713a81848649f998c49be10b5c645c580719db 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 bc86662bfcdfb34b09b234f7fe25e04c89527f98..1b3453f50468a94a1c7524d4786eed28282d0339 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 81ae7133da33236ae19fddba0c43abc2932d100e..912f261e43fd8c00cd6fad7eda2d0e5595e50e2f 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 9e1b553a10172c6ca689435794f13410929e3105..341221c711f14ad869a67619a3dbb2252d4ecb6a 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 3f17bc01355e23c0b4aeaf61382f16c9bd8b26da..6aff26d38809778334acdb6214ffcab42340b1c1 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 &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]"
        << " [-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 9958aa42f4b24686e597baa5a62503877082c1dc..3d7b6dc610ce8aa7b715a1775b5d0928bec622cc 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 6ff0b55a47e48efb0a3a2d3ecdf981584f15fc3b..9881d8633fa9cf2d772138ce0bb129b5939de4f7 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 04e8cdbe59a787696c2ea26cf131ae47d2260d77..22a27a4c04eb7aa183168494ce64d786c5cb6826 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 a5fa1196acd187377c35efeebd61636037950f99..4e3d29593aac4d9d5984904b6a89657b8e126339 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 e335e5d7fef39ed83c7146b3bc31781deab095e2..ccf27a40a6d6ab4404f0ea214ed9c17b4ae0bb54 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 549dfe0bd4ff4a24717abf447159982efdd6e347..80851ee9c9014d994ee898d87392c68dd9f3a08e 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 b7d6aba30c0f17802de89c5af121a7e51b3cde34..28d4ad87c9d0691bcc31225e1a59864a3e7285f0 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;