use_dll: under Windows, append MinGW location to the PATH variable only once

Previously, the MinGW location was appended multiple times to the PATH
variable, which in some cases would make the variable too long and thus
dysfunctional.

The variable is now initialized once when the worker threads are created.

By the way, move the macOS+Octave environment variable initializations to the
same place, for consistency.
master
Sébastien Villemot 2023-03-20 17:54:32 +01:00
parent a219c68543
commit bff80c0eaf
No known key found for this signature in database
GPG Key ID: 2CECE9350ECEBE4A
10 changed files with 79 additions and 71 deletions

View File

@ -2458,7 +2458,7 @@ PlannerObjectiveStatement::writeOutput(ostream &output, const string &basename,
for (const auto &temporary_terms_derivative : model_tree.getTemporaryTermsDerivatives())
output << temporary_terms_derivative.size() << "; ";
output << "];" << endl;
model_tree.writeStaticFile(basename + ".objective", false, "", {}, {}, false);
model_tree.writeStaticFile(basename + ".objective", false, "", {}, false);
}
void

View File

@ -2412,7 +2412,7 @@ DynamicModel::computeBlockDynJacobianCols()
}
void
DynamicModel::writeDynamicFile(const string &basename, bool use_dll, const string &mexext, const filesystem::path &matlabroot, const filesystem::path &dynareroot, bool julia) const
DynamicModel::writeDynamicFile(const string &basename, bool use_dll, const string &mexext, const filesystem::path &matlabroot, bool julia) const
{
filesystem::path model_dir{basename};
model_dir /= "model";
@ -2443,7 +2443,7 @@ DynamicModel::writeDynamicFile(const string &basename, bool use_dll, const strin
// Legacy representation
if (use_dll)
writeModelCFile<true>(basename, mexext, matlabroot, dynareroot);
writeModelCFile<true>(basename, mexext, matlabroot);
else if (!julia) // M-files
writeDynamicMFile(basename);
// The legacy representation is no longer produced for Julia
@ -2454,7 +2454,7 @@ DynamicModel::writeDynamicFile(const string &basename, bool use_dll, const strin
// Sparse representation
if (use_dll)
writeSparseModelCFiles<true>(basename, mexext, matlabroot, dynareroot);
writeSparseModelCFiles<true>(basename, mexext, matlabroot);
else if (julia)
writeSparseModelJuliaFiles<true>(basename);
else // MATLAB/Octave

View File

@ -367,7 +367,7 @@ public:
void updateVarAndTrendModel() const;
//! Writes dynamic model file (+ bytecode)
void writeDynamicFile(const string &basename, bool use_dll, const string &mexext, const filesystem::path &matlabroot, const filesystem::path &dynareroot, bool julia) const;
void writeDynamicFile(const string &basename, bool use_dll, const string &mexext, const filesystem::path &matlabroot, bool julia) const;
//! Writes file containing parameters derivatives
template<bool julia>

View File

@ -503,7 +503,8 @@ main(int argc, char **argv)
}
if (mod_file->use_dll)
ModelTree::initializeMEXCompilationWorkers(max(jthread::hardware_concurrency(), 1U));
ModelTree::initializeMEXCompilationWorkers(max(jthread::hardware_concurrency(), 1U),
dynareroot, mexext);
if (json == JsonOutputPointType::parsing)
mod_file->writeJsonOutput(basename, json, json_output_mode, onlyjson);
@ -533,7 +534,7 @@ main(int argc, char **argv)
else
mod_file->writeMOutput(basename, clear_all, clear_global, no_warn, console, nograph,
nointeractive, config_file, check_model_changes, minimal_workspace, compute_xrefs,
mexext, matlabroot, dynareroot, onlymodel, gui, notime);
mexext, matlabroot, onlymodel, gui, notime);
/* Ensures that workers are not destroyed before they finish compiling.
Also ensures that the preprocessor final message is printed after the end of

View File

@ -770,8 +770,7 @@ ModFile::writeMOutput(const string &basename, bool clear_all, bool clear_global,
bool console, bool nograph, bool nointeractive, const ConfigFile &config_file,
bool check_model_changes, bool minimal_workspace, bool compute_xrefs,
const string &mexext,
const filesystem::path &matlabroot,
const filesystem::path &dynareroot, bool onlymodel, bool gui, bool notime) const
const filesystem::path &matlabroot, bool onlymodel, bool gui, bool notime) const
{
if (basename.empty())
{
@ -1043,11 +1042,11 @@ ModFile::writeMOutput(const string &basename, bool clear_all, bool clear_global,
{
if (!no_static)
{
static_model.writeStaticFile(basename, use_dll, mexext, matlabroot, dynareroot, false);
static_model.writeStaticFile(basename, use_dll, mexext, matlabroot, false);
static_model.writeParamsDerivativesFile<false>(basename);
}
dynamic_model.writeDynamicFile(basename, use_dll, mexext, matlabroot, dynareroot, false);
dynamic_model.writeDynamicFile(basename, use_dll, mexext, matlabroot, false);
dynamic_model.writeParamsDerivativesFile<false>(basename);
}
@ -1069,10 +1068,10 @@ ModFile::writeJuliaOutput(const string &basename) const
{
if (!no_static)
{
static_model.writeStaticFile(basename, false, "", {}, {}, true);
static_model.writeStaticFile(basename, false, "", {}, true);
static_model.writeParamsDerivativesFile<true>(basename);
}
dynamic_model.writeDynamicFile(basename, use_dll, "", {}, {}, true);
dynamic_model.writeDynamicFile(basename, use_dll, "", {}, true);
dynamic_model.writeParamsDerivativesFile<true>(basename);
}
steady_state_model.writeSteadyStateFile(basename, true);

View File

@ -1,5 +1,5 @@
/*
* Copyright © 2006-2022 Dynare Team
* Copyright © 2006-2023 Dynare Team
*
* This file is part of Dynare.
*
@ -173,7 +173,7 @@ public:
bool console, bool nograph, bool nointeractive, const ConfigFile &config_file,
bool check_model_changes, bool minimal_workspace, bool compute_xrefs,
const string &mexext, const filesystem::path &matlabroot,
const filesystem::path &dynareroot, bool onlymodel, bool gui, bool notime) const;
bool onlymodel, bool gui, bool notime) const;
void writeJuliaOutput(const string &basename) const;

View File

@ -1616,7 +1616,7 @@ ModelTree::findGccOnMacos(const string &mexext)
#endif
filesystem::path
ModelTree::compileMEX(const filesystem::path &output_dir, const string &output_basename, const string &mexext, const vector<filesystem::path> &input_files, const filesystem::path &matlabroot, const filesystem::path &dynareroot, bool link) const
ModelTree::compileMEX(const filesystem::path &output_dir, const string &output_basename, const string &mexext, const vector<filesystem::path> &input_files, const filesystem::path &matlabroot, bool link) const
{
assert(!mex_compilation_workers.empty());
@ -1637,22 +1637,6 @@ ModelTree::compileMEX(const filesystem::path &output_dir, const string &output_b
// Octave
compiler = matlabroot / "bin" / "mkoctfile";
flags << "--mex";
#ifdef __APPLE__
/* On macOS, enforce GCC, otherwise Clang will be used, and it does not
accept our custom optimization flags (see dynare#1797) */
filesystem::path gcc_path {findGccOnMacos(mexext)};
if (setenv("CC", gcc_path.c_str(), 1) != 0)
{
cerr << "Can't set CC environment variable" << endl;
exit(EXIT_FAILURE);
}
// We also define CXX, because that is used for linking
if (setenv("CXX", gcc_path.c_str(), 1) != 0)
{
cerr << "Can't set CXX environment variable" << endl;
exit(EXIT_FAILURE);
}
#endif
}
else
{
@ -1672,22 +1656,8 @@ ModelTree::compileMEX(const filesystem::path &output_dir, const string &output_b
<< " -shared -Wl,--no-undefined -Wl,-rpath-link," << bin_dir;
libs += " -lm";
}
else if (mexext == "mexw64")
{
// Windows
flags << " -static-libgcc -shared";
// Put the MinGW environment shipped with Dynare in the path
auto mingwpath = dynareroot / "mingw64" / "bin";
string newpath = "PATH=" + mingwpath.string() + ';' + getenv("PATH");
/* We cant use setenv() since it is not available on MinGW. Note
that putenv() seems to make a copy of the string on MinGW, contrary
to what is done on GNU/Linux and macOS. */
if (putenv(const_cast<char *>(newpath.c_str())) != 0)
{
cerr << "Can't set PATH" << endl;
exit(EXIT_FAILURE);
}
}
else if (mexext == "mexw64") // Windows
flags << " -static-libgcc -shared";
#ifdef __APPLE__
else if (mexext == "mexmaci64" || mexext == "mexmaca64")
{
@ -1866,7 +1836,8 @@ ModelTree::getRHSFromLHS(expr_t lhs) const
}
void
ModelTree::initializeMEXCompilationWorkers(int numworkers)
ModelTree::initializeMEXCompilationWorkers(int numworkers, const filesystem::path &dynareroot,
const string &mexext)
{
assert(numworkers > 0);
assert(mex_compilation_workers.empty());
@ -1917,6 +1888,44 @@ ModelTree::initializeMEXCompilationWorkers(int numworkers)
mex_compilation_cv.notify_all();
}
});
/* Set some environment variables needed for compilation on Windows/MATLAB
and macOS/Octave.
For Windows/MATLAB, this should be done only once, because otherwise
the PATH variable can become too long and GCC will not be found. */
if (mexext == "mexw64")
{
// Put the MinGW environment shipped with Dynare in the path
auto mingwpath = dynareroot / "mingw64" / "bin";
string newpath = "PATH=" + mingwpath.string() + ';' + getenv("PATH");
/* We cant use setenv() since it is not available on MinGW. Note that
putenv() seems to make an internal copy of the string on MinGW,
contrary to what is done on GNU/Linux and macOS. */
if (putenv(const_cast<char *>(newpath.c_str())) != 0)
{
cerr << "Can't set PATH" << endl;
exit(EXIT_FAILURE);
}
}
#ifdef __APPLE__
else if (mexext == "mex")
{
/* On macOS, with Octave, enforce GCC, otherwise Clang will be used, and
it does not accept our custom optimization flags (see dynare#1797) */
filesystem::path gcc_path {findGccOnMacos(mexext)};
if (setenv("CC", gcc_path.c_str(), 1) != 0)
{
cerr << "Can't set CC environment variable" << endl;
exit(EXIT_FAILURE);
}
// We also define CXX, because that is used for linking
if (setenv("CXX", gcc_path.c_str(), 1) != 0)
{
cerr << "Can't set CXX environment variable" << endl;
exit(EXIT_FAILURE);
}
}
#endif
}
void

View File

@ -309,7 +309,7 @@ protected:
// Writes and compiles dynamic/static file (C version, legacy representation)
template<bool dynamic>
void writeModelCFile(const string &basename, const string &mexext, const filesystem::path &matlabroot, const filesystem::path &dynareroot) const;
void writeModelCFile(const string &basename, const string &mexext, const filesystem::path &matlabroot) const;
// Writes per-block residuals and temporary terms (incl. for derivatives)
template<ExprNodeOutputType output_type>
@ -377,7 +377,7 @@ protected:
// Writes and compiles the sparse representation of the model in C
template<bool dynamic>
void writeSparseModelCFiles(const string &basename, const string &mexext, const filesystem::path &matlabroot, const filesystem::path &dynareroot) const;
void writeSparseModelCFiles(const string &basename, const string &mexext, const filesystem::path &matlabroot) const;
// Writes the sparse representation of the model in Julia
// Assumes that the directory <MODFILE>/model/julia/ already exists
@ -583,7 +583,7 @@ private:
blocking. The dependency of a linked MEX file upon intermediary objects is
nicely handled. Returns the name of the output file (to be reused later as
input file if link=false). */
filesystem::path compileMEX(const filesystem::path &output_dir, const string &output_basename, const string &mexext, const vector<filesystem::path> &input_files, const filesystem::path &matlabroot, const filesystem::path &dynareroot, bool link = true) const;
filesystem::path compileMEX(const filesystem::path &output_dir, const string &output_basename, const string &mexext, const vector<filesystem::path> &input_files, const filesystem::path &matlabroot, bool link = true) const;
public:
ModelTree(SymbolTable &symbol_table_arg,
@ -625,8 +625,10 @@ public:
If no such equation can be found, throws an ExprNode::MatchFailureExpression */
expr_t getRHSFromLHS(expr_t lhs) const;
// Initialize the MEX compilation workers
static void initializeMEXCompilationWorkers(int numworkers);
/* Initialize the MEX compilation workers (and some environment variables
needed for finding GCC) */
static void initializeMEXCompilationWorkers(int numworkers, const filesystem::path &dynareroot,
const string &mexext);
// Waits until the MEX compilation queue is empty
static void waitForMEXCompilationWorkers();
@ -922,8 +924,7 @@ ModelTree::writeModelFileHelper() const
template<bool dynamic>
void
ModelTree::writeModelCFile(const string &basename, const string &mexext,
const filesystem::path &matlabroot,
const filesystem::path &dynareroot) const
const filesystem::path &matlabroot) const
{
ofstream output;
auto open_file = [&output](const filesystem::path &p)
@ -974,7 +975,7 @@ ModelTree::writeModelCFile(const string &basename, const string &mexext,
<< endl;
output.close();
object_files.push_back(compileMEX(model_src_dir, funcname + "_tt" , mexext, { source_tt },
matlabroot, dynareroot, false));
matlabroot, false));
const string prototype_main
{
@ -1013,7 +1014,7 @@ ModelTree::writeModelCFile(const string &basename, const string &mexext,
<< endl;
output.close();
object_files.push_back(compileMEX(model_src_dir, funcname, mexext, { source_main },
matlabroot, dynareroot, false));
matlabroot, false));
}
const filesystem::path filename { model_src_dir / (dynamic ? "dynamic.c" : "static.c") };
@ -1123,8 +1124,7 @@ ModelTree::writeModelCFile(const string &basename, const string &mexext,
output.close();
object_files.push_back(filename);
compileMEX(packageDir(basename), dynamic ? "dynamic" : "static", mexext, object_files, matlabroot,
dynareroot);
compileMEX(packageDir(basename), dynamic ? "dynamic" : "static", mexext, object_files, matlabroot);
}
template<ExprNodeOutputType output_type>
@ -2611,8 +2611,7 @@ ModelTree::writeSparseModelMFiles(const string &basename) const
template<bool dynamic>
void
ModelTree::writeSparseModelCFiles(const string &basename, const string &mexext,
const filesystem::path &matlabroot,
const filesystem::path &dynareroot) const
const filesystem::path &matlabroot) const
{
constexpr ExprNodeOutputType output_type {dynamic ? ExprNodeOutputType::CSparseDynamicModel : ExprNodeOutputType::CSparseStaticModel};
auto [d_sparse_output, tt_sparse_output] = writeModelFileHelper<output_type>();
@ -2654,7 +2653,7 @@ ModelTree::writeSparseModelCFiles(const string &basename, const string &mexext,
output.close();
auto power_deriv_object {compileMEX(model_src_dir, (prefix + "power_deriv"),
mexext, { power_deriv_src },
matlabroot, dynareroot, false)};
matlabroot, false)};
size_t ttlen {0};
@ -2731,7 +2730,7 @@ ModelTree::writeSparseModelCFiles(const string &basename, const string &mexext,
<< endl;
output.close();
tt_object_files.push_back(compileMEX(model_src_dir, funcname + "_tt", mexext, { source_tt },
matlabroot, dynareroot, false));
matlabroot, false));
const string prototype_main {"void " + funcname + "(const double *restrict y, const double *restrict x, const double *restrict params" + ss_argin + ", const double *restrict T, double *restrict " + (i == 0 ? "residual" : "g" + to_string(i) + "_v") + ")"};
@ -2754,7 +2753,7 @@ ModelTree::writeSparseModelCFiles(const string &basename, const string &mexext,
<< endl;
output.close();
auto main_object_file {compileMEX(model_src_dir, funcname, mexext, { source_main },
matlabroot, dynareroot, false)};
matlabroot, false)};
const filesystem::path source_mex { model_src_dir / (funcname + "_mex.c")};
int nargin {5+static_cast<int>(dynamic)+3*static_cast<int>(i == 1)};
@ -2837,7 +2836,7 @@ ModelTree::writeSparseModelCFiles(const string &basename, const string &mexext,
vector<filesystem::path> mex_input_files { power_deriv_object, main_object_file, source_mex };
for (int j {0}; j <= i; j++)
mex_input_files.push_back(tt_object_files[j]);
compileMEX(mex_dir, funcname, mexext, mex_input_files, matlabroot, dynareroot);
compileMEX(mex_dir, funcname, mexext, mex_input_files, matlabroot);
}
if (block_decomposed)
@ -2926,7 +2925,7 @@ ModelTree::writeSparseModelCFiles(const string &basename, const string &mexext,
}
output << "}" << endl;
output.close();
compileMEX(block_dir, funcname, mexext, { source_mex, power_deriv_object }, matlabroot, dynareroot);
compileMEX(block_dir, funcname, mexext, { source_mex, power_deriv_object }, matlabroot);
}
}
}

View File

@ -456,7 +456,7 @@ StaticModel::writeStaticMCompatFile(const string &basename) const
}
void
StaticModel::writeStaticFile(const string &basename, bool use_dll, const string &mexext, const filesystem::path &matlabroot, const filesystem::path &dynareroot, bool julia) const
StaticModel::writeStaticFile(const string &basename, bool use_dll, const string &mexext, const filesystem::path &matlabroot, bool julia) const
{
filesystem::path model_dir{basename};
model_dir /= "model";
@ -487,7 +487,7 @@ StaticModel::writeStaticFile(const string &basename, bool use_dll, const string
// Legacy representation
if (use_dll)
writeModelCFile<false>(basename, mexext, matlabroot, dynareroot);
writeModelCFile<false>(basename, mexext, matlabroot);
else if (!julia) // M-files
writeStaticMFile(basename);
// The legacy representation is no longer produced for Julia
@ -498,7 +498,7 @@ StaticModel::writeStaticFile(const string &basename, bool use_dll, const string
// Sparse representation
if (use_dll)
writeSparseModelCFiles<false>(basename, mexext, matlabroot, dynareroot);
writeSparseModelCFiles<false>(basename, mexext, matlabroot);
else if (julia)
writeSparseModelJuliaFiles<false>(basename);
else // MATLAB/Octave

View File

@ -125,7 +125,7 @@ public:
void computingPass(int derivsOrder, int paramsDerivsOrder, const eval_context_t &eval_context, bool no_tmp_terms, bool block);
//! Writes static model file (+ bytecode)
void writeStaticFile(const string &basename, bool use_dll, const string &mexext, const filesystem::path &matlabroot, const filesystem::path &dynareroot, bool julia) const;
void writeStaticFile(const string &basename, bool use_dll, const string &mexext, const filesystem::path &matlabroot, bool julia) const;
//! Write JSON Output (used by PlannerObjectiveStatement)
void writeJsonOutput(ostream &output) const;