diff --git a/NEWS.md b/NEWS.md index bc5515ae..5b1581ad 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,9 @@ # RcppParallel (development version) +* Fixed bundled oneTBB builds and downstream compilation with Clang and libc++ + when targeting macOS 10.12 or earlier, where C++17 aligned allocation is not + available. (#219) + # RcppParallel 6.2.0 diff --git a/R/tbb-autodetected.R.in b/R/tbb-autodetected.R.in index 7cc750e0..0be09b76 100644 --- a/R/tbb-autodetected.R.in +++ b/R/tbb-autodetected.R.in @@ -2,6 +2,7 @@ TBB_ENABLED <- @TBB_ENABLED@ TBB_LIB <- "@TBB_LIB@" TBB_INC <- "@TBB_INC@" +TBB_CXXFLAGS <- "@TBB_CXXFLAGS@" TBB_NAME <- "@TBB_NAME@" -TBB_MALLOC_NAME <- "@TBB_MALLOC_NAME@" \ No newline at end of file +TBB_MALLOC_NAME <- "@TBB_MALLOC_NAME@" diff --git a/R/tbb.R b/R/tbb.R index 6f6a745c..b071833a 100644 --- a/R/tbb.R +++ b/R/tbb.R @@ -57,6 +57,9 @@ tbbCxxFlags <- function() { flags <- c("-DRCPP_PARALLEL_USE_TBB=1") + if (nzchar(TBB_CXXFLAGS)) + flags <- c(flags, TBB_CXXFLAGS) + # if TBB_INC is set, apply those library paths tbbInc <- Sys.getenv("TBB_INC", unset = TBB_INC) if (!file.exists(tbbInc)) { diff --git a/src/Makevars.in b/src/Makevars.in index 7158b732..9f4aeabf 100644 --- a/src/Makevars.in +++ b/src/Makevars.in @@ -10,6 +10,7 @@ TBB_LIB = @TBB_LIB@ TBB_INC = @TBB_INC@ TBB_NAME = @TBB_NAME@ TBB_MALLOC_NAME = @TBB_MALLOC_NAME@ +TBB_CXXFLAGS = @TBB_CXXFLAGS@ PKG_CPPFLAGS = @PKG_CPPFLAGS@ PKG_CXXFLAGS = @PKG_CXXFLAGS@ @@ -28,7 +29,8 @@ tbb: tbb-clean @TBB_LIB="$(TBB_LIB)" TBB_INC="$(TBB_INC)" \ TBB_NAME="$(TBB_NAME)" TBB_MALLOC_NAME="$(TBB_MALLOC_NAME)" \ CC="$(CC)" CFLAGS="$(CFLAGS)" CPPFLAGS="$(CPPFLAGS)" \ - CXX="$(CXX)" CXXFLAGS="$(CXXFLAGS)" LDFLAGS="$(LDFLAGS)" \ + CXX="$(CXX)" CXXFLAGS="$(CXXFLAGS) $(TBB_CXXFLAGS)" \ + LDFLAGS="$(LDFLAGS)" \ CMAKE="$(CMAKE)" "@R@" -s -f install.libs.R --args build # NOTE: we do not want to clean ../inst/lib or ../inst/libs here, diff --git a/tests/test-cxx-flags.R b/tests/test-cxx-flags.R new file mode 100644 index 00000000..722dd711 --- /dev/null +++ b/tests/test-cxx-flags.R @@ -0,0 +1,18 @@ +# Unit tests for the compiler flags handed to downstream packages through +# RcppParallel::CxxFlags(). + +RcppParallel:::test_init() + +flags <- tbbCxxFlags() + +assert(is.character(flags)) +assert(length(flags) == 1L) +assert(!is.na(flags)) +assert(grepl("-DRCPP_PARALLEL_USE_TBB=1", flags, fixed = TRUE)) + +hasNoAlignedAllocation <- grepl( + "-fno-aligned-allocation", + flags, + fixed = TRUE +) +assert(identical(hasNoAlignedAllocation, nzchar(TBB_CXXFLAGS))) diff --git a/tools/config/configure.R b/tools/config/configure.R index 6293fe13..c203a1f8 100644 --- a/tools/config/configure.R +++ b/tools/config/configure.R @@ -1,7 +1,46 @@ # make sure we call correct version of R rExe <- if (.Platform$OS.type == "windows") "R.exe" else "R" -define(R = file.path(R.home("bin"), rExe)) +rPath <- file.path(R.home("bin"), rExe) +define(R = rPath) + +# Clang enables C++17 aligned allocation based on the deployment target, but +# the corresponding libc++ entry points are unavailable before macOS 10.13. +# Probe through R CMD SHLIB so we see the compiler, standard library, flags, +# launchers, and user Makevars settings that will actually build the package. +tbbNeedsNoAlignedAllocation <- function() { + + if (!identical(Sys.info()[["sysname"]], "Darwin")) + return(FALSE) + + probeDir <- tempfile("RcppParallel-configure-") + dir.create(probeDir) + on.exit(unlink(probeDir, recursive = TRUE), add = TRUE) + + source <- file.path(probeDir, "probe.cpp") + writeLines(c( + "#include ", + "#if defined(__clang__) && defined(_LIBCPP_VERSION) && \\", + " defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && \\", + " __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 101300", + "#pragma message(\"RCPP_PARALLEL_NO_ALIGNED_ALLOCATION\")", + "#endif", + "int rcppParallelConfigureProbe;" + ), source) + + output <- tryCatch( + suppressWarnings(system2( + rPath, + c("CMD", "SHLIB", shQuote(source)), + stdout = TRUE, + stderr = TRUE + )), + error = function(cnd) character() + ) + + any(grepl("RCPP_PARALLEL_NO_ALIGNED_ALLOCATION", output, fixed = TRUE)) + +} # check whether user has Makevars file that might cause trouble makevars <- Sys.getenv("R_MAKEVARS_USER", unset = "~/.R/Makevars") @@ -237,7 +276,14 @@ if (!is.na(tbbLib)) { # TBB is always enabled: either one was supplied via TBB_LIB / TBB_ROOT, or we # built the bundled copy, and failing to do either is fatal above define(TBB_ENABLED = TRUE) -define(PKG_CXXFLAGS = "-DRCPP_PARALLEL_USE_TBB=1") +tbbCxxFlags <- if (tbbNeedsNoAlignedAllocation()) { + "-fno-aligned-allocation" +} else { + "" +} +define(TBB_CXXFLAGS = tbbCxxFlags) +pkgCxxFlags <- c("-DRCPP_PARALLEL_USE_TBB=1", tbbCxxFlags) +define(PKG_CXXFLAGS = paste(pkgCxxFlags[nzchar(pkgCxxFlags)], collapse = " ")) # macOS needs some extra flags set if (Sys.info()[["sysname"]] == "Darwin") {