From b43d105c1f22541e9d942f32af04acf731f89792 Mon Sep 17 00:00:00 2001 From: Willi Mutschler <willi@mutschler.eu> Date: Mon, 16 Oct 2023 17:47:57 +0200 Subject: [PATCH] Backporting provisions and clang support for Apple Silicon (arm64) - provisions for Apple Silicon package (backported fe8aaf44fdef66ea965f976e585e1daf48194562) - ModelTree::findGccOnMacOS() now returns a std::filesystem::path (backported bae04fa89954ae0f4594e9fe8d38073b3e0ae51f) - use_dll: under Windows, append MinGW location to the PATH variable only once [By the way, move the macOS+Octave environment variable initializations to the same place, for consistency.] (backported bff80c0eaf39ba5c05be92900bbf09b16c7f9452) - macOS: use clang if GCC is not available for use_dll [Related to Dynare/dynare#1893 and Dynare/dynare#1894] (backported 958b0a380072c2c650fe9effa0f9b4001f5bd4f7) --- src/ModelTree.cc | 64 ++++++++++++++++++++++++++++-------------------- src/ModelTree.hh | 7 +++--- 2 files changed, 42 insertions(+), 29 deletions(-) diff --git a/src/ModelTree.cc b/src/ModelTree.cc index d1c3ca01..0b206ff7 100644 --- a/src/ModelTree.cc +++ b/src/ModelTree.cc @@ -1,5 +1,5 @@ /* - * Copyright © 2003-2021 Dynare Team + * Copyright © 2003-2023 Dynare Team * * This file is part of Dynare. * @@ -1903,6 +1903,8 @@ ModelTree::matlab_arch(const string &mexext) } else if (mexext == "mexmaci64") return "maci64"; + else if (mexext == "mexmaca64") + return "maca64"; else { cerr << "ERROR: 'mexext' option to preprocessor incorrectly set, needed with 'use_dll'" << endl; @@ -1911,29 +1913,36 @@ ModelTree::matlab_arch(const string &mexext) } #ifdef __APPLE__ -string -ModelTree::findGccOnMacos() + +pair<filesystem::path, bool> +ModelTree::findCompilerOnMacos(const string &mexext) { + /* Try to find gcc, otherwise use Apple’s clang compiler. + Homebrew binaries are located in /usr/local/bin/ on x86_64 systems and in + /opt/homebrew/bin/ on arm64 systems. + Apple’s 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"}; - char dynare_preprocessor_path[PATH_MAX]; - uint32_t size = PATH_MAX; - string 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 (filesystem::exists(local_gcc_path)) - return local_gcc_path; - else if (string global_gcc_path = "/usr/local/bin/gcc-" + macos_gcc_version; - filesystem::exists(global_gcc_path)) - return global_gcc_path; + 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, 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); } } @@ -1942,11 +1951,13 @@ ModelTree::findGccOnMacos() void ModelTree::compileMEX(const string &basename, const string &funcname, const string &mexext, const vector<filesystem::path> &src_files, const filesystem::path &matlabroot, const filesystem::path &dynareroot) const { - 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()) { @@ -1960,16 +1971,17 @@ ModelTree::compileMEX(const string &basename, const string &funcname, const stri 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) */ - string gcc_path = findGccOnMacos(); - if (setenv("CC", gcc_path.c_str(), 1) != 0) + /* On macOS, with Octave, enforce our compiler. In particular this is + necessary if we’ve 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); @@ -2011,9 +2023,9 @@ ModelTree::compileMEX(const string &basename, const string &funcname, const stri } } #ifdef __APPLE__ - else if (mexext == "mexmaci64") + else if (mexext == "mexmaci64" || mexext == "mexmaca64") { - compiler = findGccOnMacos(); + tie(compiler, is_clang) = findCompilerOnMacos(mexext); flags << " -fno-common -Wl,-twolevel_namespace -undefined error -bundle"; libs += " -lm"; } @@ -2049,7 +2061,7 @@ ModelTree::compileMEX(const string &basename, const string &funcname, const stri 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 << " "; diff --git a/src/ModelTree.hh b/src/ModelTree.hh index 0c54edf9..bcf3da0b 100644 --- a/src/ModelTree.hh +++ b/src/ModelTree.hh @@ -1,5 +1,5 @@ /* - * Copyright © 2003-2021 Dynare Team + * Copyright © 2003-2023 Dynare Team * * This file is part of Dynare. * @@ -399,8 +399,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 string findGccOnMacos(); + /* 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 void compileMEX(const string &basename, const string &funcname, const string &mexext, const vector<filesystem::path> &src_files, const filesystem::path &matlabroot, const filesystem::path &dynareroot) const; -- GitLab