-
-
Notifications
You must be signed in to change notification settings - Fork 269
Catalina problems
Catalina does not seem to handle exceptions properly. This does not seem to be a problem with Stan code, but affects Stan adversely because
- Stan has many different types of exceptions
- Stan behaves differently depending on which type of exception is thrown
- The occurrence of an exception during MCMC, ADVI, or optimization is probabilistic but likely, even in well-written Stan programs
This wiki page attempts to document what works as what does not work.
Rcpp::sourceCpp(code =
'
#include <Rcpp.h>
// [[Rcpp::export]]
int throw_exception() {
std::stringstream errmsg; errmsg << "this is the expected behavior";
throw std::domain_error(errmsg.str());
return 0;
}
'
)
throw_exception()
The throw_exception()
function returns "this is the expected behavior" on
- Linux, regardless of whether
clang++
org++
is used to compile - Windows, using RTools35
- Mac (Mojave operating system) with
clang++
from CRAN via coatless' installer - Mac (Catalina operating system) with
clang++
from XCode, provided that Rcpp is compiled from source withclang++
from XCode and no binary packages with C++ code from CRAN (readr, ggplot2, etc.) have been loaded - Mac (Catalina operating system), with R installed via homebrew and
clang++
from XCode - Mac (Catalina operating system) with R from CRAN but
g++
installed from homebrew, but this may require that you install Rcpp from source withg++
.
The throw_exception()
function returns "c++ exception (unknown reason)" on
- Mac (Catalina operating system) with
clang++
from CRAN via coatless' installer - Mac (Catalina operating system) with
clang++
from XCode if any binary package with C++ code from CRAN (readr, ggplot2, etc.) has been loaded
Kevin Ushey wrote the following to show which C++ library was used on a Mac
dlls <- getLoadedDLLs()
paths <- vapply(dlls, `[[`, "path", FUN.VALUE = character(1))
invisible(lapply(paths, function(path) {
if (!file.exists(path))
return(FALSE)
output <- system(paste("otool -L", shQuote(path), "| grep libc++ || true"), intern = TRUE)
if (length(output) == 0)
return(FALSE)
writeLines(paste0(path, ":"))
writeLines(output)
}))
For each dynamically loaded library, tt will say something like
/usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 800.6.0)
or
/Library/Frameworks/R.framework/Versions/3.6/Resources/lib/libc++.1.dylib (compatibility version 1.0.0, current version 1.0.0)
When we first encountered this problem back in 2017
https://github.com/jeroen/V8/issues/37#issuecomment-305266135
we were able to fix it with a suggested hack by Kevin Ushey, but the function below seems not to fix the problem on Catalina:
fix_Mac <- function(sm) {
stopifnot(is(sm, "stanmodel"))
dso_last_path <- sm@[email protected]$dso_last_path
CLANG_DIR <- tail(n = 1, grep("clang[456789]",
x = list.dirs("/usr/local", recursive = FALSE),
value = TRUE))
if (length(CLANG_DIR) == 0L) stop("no clang from CRAN found")
LIBCPP <- file.path(CLANG_DIR, "lib", "libc++.1.dylib")
if (!file.exists(LIBCPP)) stop("no unique libc++.1?.dylib found")
Rv <- R.version
GOOD <- file.path("/Library", "Frameworks", "R.framework", "Versions",
paste(Rv$major, substr(Rv$minor, 1, 1), sep = "."),
"Resources", "lib", "libc++.1.dylib")
if (!file.exists(GOOD)) stop(paste(GOOD, "not found"))
cmd <- paste(
"install_name_tool",
"-change",
LIBCPP,
GOOD,
dso_last_path
)
system(cmd)
dyn.unload(dso_last_path)
dyn.load(dso_last_path)
return(invisible(NULL))
}
According to https://libcxx.llvm.org/docs/UsingLibcxx.html , the system version of libc++ can be avoided with something like
clang++ -std=c++11 -stdlib=libc++ -nostdinc++ \
-I<libcxx-install-prefix>/include/c++/v1 \
-L<libcxx-install-prefix>/lib \
-Wl,-rpath,<libcxx-install-prefix>/lib \
test.cpp
where is something like /usr/local/clang[456789]/ . When putting something like that into src/Makevars of a package, it is possible to compile correctly but the linker still uses /usr/lib/libc++.1.dylib even when the environmental variable DYLD_LIBRARY_PATH is set to /usr/local/clang[456789]/lib .
No one has tried this yet, and it is discouraged by Apple in some cases, but it may be possible to statically link the correct version of a C++ library.