macOS: use clang if GCC is not available for use_dll

Related to Dynare/dynare#1893 and Dynare/dynare#1894
master
Willi Mutschler 2023-07-11 22:12:03 +02:00 committed by Sébastien Villemot
parent e1e1a753d0
commit 958b0a3800
No known key found for this signature in database
GPG Key ID: 2CECE9350ECEBE4A
2 changed files with 37 additions and 31 deletions

View File

@ -1613,34 +1613,36 @@ ModelTree::matlab_arch(const string &mexext)
}
#ifdef __APPLE__
filesystem::path
ModelTree::findGccOnMacos(const string &mexext)
{
const string macos_gcc_version {"13"};
char dynare_preprocessor_path[PATH_MAX];
uint32_t size = PATH_MAX;
filesystem::path local_gcc_path;
if (_NSGetExecutablePath(dynare_preprocessor_path, &size) == 0)
{
string s = dynare_preprocessor_path;
local_gcc_path = s.substr(0, s.find_last_of("/")) + "/../.brew/bin/gcc-" + macos_gcc_version;
}
// if user did not choose to install gcc locally via the pkg-installer then we need to find GNU gcc
// homebrew binaries are located in /usr/local/bin/ on x86_64 systems and in /opt/homebrew/bin/ on arm64 systems
if (exists(local_gcc_path))
return local_gcc_path;
else if (filesystem::path global_gcc_path {"/usr/local/bin/gcc-" + macos_gcc_version};
exists(global_gcc_path) && mexext == "mexmaci64")
return global_gcc_path;
pair<filesystem::path, bool>
ModelTree::findCompilerOnMacos(const string &mexext)
{
/* Try to find gcc, otherwise use Apples clang compiler.
Homebrew binaries are located in /usr/local/bin/ on x86_64 systems and in
/opt/homebrew/bin/ on arm64 systems.
Apples clang is located both in /usr/bin/gcc and /usr/bin/clang, it
automatically selects x86_64 or arm64 depending on the compile-time
environment. */
const string macos_gcc_version {"13"};
if (filesystem::path global_gcc_path {"/usr/local/bin/gcc-" + macos_gcc_version};
exists(global_gcc_path) && mexext == "mexmaci64")
return { global_gcc_path, false };
else if (filesystem::path global_gcc_path {"/opt/homebrew/bin/gcc-" + macos_gcc_version};
exists(global_gcc_path) && mexext == "mexmaca64")
return global_gcc_path;
return { global_gcc_path, false };
else if (filesystem::path global_clang_path {"/usr/bin/clang"}; exists(global_clang_path))
return { global_clang_path, true };
else
{
cerr << "ERROR: You must install gcc-" << macos_gcc_version
<< " on your system before using the `use_dll` option of Dynare. "
<< "If using MATLAB, you can do this via the Dynare installation package. If using Octave, you should run `brew install gcc-" << macos_gcc_version << "` in a terminal." << endl;
<< "You should install Homebrew";
if (mexext == "mexmaca64")
cerr << " for arm64";
else if (mexext == "mexmaci64")
cerr << " for x86_64";
cerr << " and run `brew install gcc-" << macos_gcc_version << "` in a terminal." << endl;
exit(EXIT_FAILURE);
}
}
@ -1651,11 +1653,13 @@ ModelTree::compileMEX(const filesystem::path &output_dir, const string &output_b
{
assert(!mex_compilation_workers.empty());
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";
const string gcc_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" };
const string clang_opt_flags { "-O3 -g0 --param ira-max-conflict-table-size=1 -Wno-unused-command-line-argument" };
filesystem::path compiler;
ostringstream flags;
string libs;
bool is_clang {false};
if (matlabroot.empty())
{
@ -1692,7 +1696,7 @@ ModelTree::compileMEX(const filesystem::path &output_dir, const string &output_b
#ifdef __APPLE__
else if (mexext == "mexmaci64" || mexext == "mexmaca64")
{
compiler = findGccOnMacos(mexext);
tie(compiler, is_clang) = findCompilerOnMacos(mexext);
flags << " -fno-common -Wl,-twolevel_namespace -undefined error -bundle";
libs += " -lm";
}
@ -1727,7 +1731,7 @@ ModelTree::compileMEX(const filesystem::path &output_dir, const string &output_b
cmd << user_set_compiler << " ";
if (user_set_subst_flags.empty())
cmd << opt_flags << " " << flags.str() << " ";
cmd << (is_clang ? clang_opt_flags : gcc_opt_flags) << " " << flags.str() << " ";
else
cmd << user_set_subst_flags << " ";
@ -1970,16 +1974,17 @@ ModelTree::initializeMEXCompilationWorkers(int numworkers, const filesystem::pat
#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)
/* On macOS, with Octave, enforce our compiler. In particular this is
necessary if weve selected GCC; otherwise Clang will be used, and
it does not accept the same optimization flags (see dynare#1797) */
auto [compiler_path, is_clang] { findCompilerOnMacos(mexext) };
if (setenv("CC", compiler_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)
if (setenv("CXX", compiler_path.c_str(), 1) != 0)
{
cerr << "Can't set CXX environment variable" << endl;
exit(EXIT_FAILURE);

View File

@ -594,8 +594,9 @@ private:
//! Returns the name of the MATLAB architecture given the extension used for MEX files
static string matlab_arch(const string &mexext);
#ifdef __APPLE__
//! Finds a suitable GCC compiler on macOS
static filesystem::path findGccOnMacos(const string &mexext);
/* Finds a suitable compiler on macOS.
The boolean is false if this is GCC and true if this is Clang */
static pair<filesystem::path, bool> findCompilerOnMacos(const string &mexext);
#endif
/* Compiles a MEX file (if link=true) or an object file to be linked later
into a MEX file (if link=false). The compilation is done in separate