diff --git a/configure b/configure index 2402ecef1..14c92a350 100755 --- a/configure +++ b/configure @@ -75,62 +75,34 @@ fi # necessarily here in configure). Hence use -fopenmp directly for this detection step. # printf not echo to pass checkbashisms w.r.t. to the \n -cat < test-omp.c -#include -int main() { - return omp_get_num_threads(); +# Usage: "user-facing string" "CFLAGS" "LDFLAGS" +check_openmp_flags () { + printf "* checking if %s... " "$1" + if "${R_HOME}/bin/Rscript" tools/check-openmp-flags.R "${PKG_CFLAGS} $2" "${PKG_LIBS} $3" >> config.log 2>&1; then + echo "yes" + export R_OPENMP_CFLAGS="$2" + export R_OPENMP_LIBS="$3" + export R_OPENMP_ENABLED=1 + return 0 + else + echo "no" + return 1 + fi } -EOF detect_openmp () { + R_OPENMP_CFLAGS= + R_OPENMP_LIBS= - if [ "$(uname)" = "Linux" ]; then - - printf "%s" "* checking if R installation supports OpenMP without any extra hints... " - if "${R_HOME}/bin/R" CMD SHLIB test-omp.c >> config.log 2>&1; then - echo "yes" - export R_OPENMP_ENABLED=1 - return - else - echo "no" - fi - + check_openmp_flags "R installation is configured to use OpenMP" '$(SHLIB_OPENMP_CFLAGS)' '$(SHLIB_OPENMP_CFLAGS)' && return - printf "%s" "* checking if R installation supports openmp with \"-fopenmp\" flag... " - if ${CC} ${CFLAGS} -fopenmp test-omp.c >> config.log 2>&1; then - echo "yes" - export PKG_CFLAGS="${PKG_CFLAGS} -fopenmp" - export R_OPENMP_ENABLED=1 - return - else - echo "no" - fi - fi # uname=Linux + # https://github.com/Rdatatable/data.table/issues/6409 + check_openmp_flags "R installation supports OpenMP with \"-fopenmp\" flag" -fopenmp -fopenmp && return if [ "$(uname)" = "Darwin" ]; then # https://mac.r-project.org/openmp - printf "%s" "* checking if R installation supports OpenMP with \"-Xclang -fopenmp\" ... " - if CPPFLAGS="${CPPFLAGS} -Xclang -fopenmp" PKG_LIBS="-lomp" "${R_HOME}/bin/R" CMD SHLIB test-omp.c >> config.log 2>&1; then - echo "yes" - export PKG_CFLAGS="${PKG_CFLAGS} -Xclang -fopenmp" - export PKG_LIBS="${PKG_LIBS} -lomp" - export R_OPENMP_ENABLED=1 - return - else - echo "no" - fi - - # https://github.com/Rdatatable/data.table/issues/6409 - printf "%s" "* checking if R installation supports OpenMP with \"-fopenmp\" ... " - if CPPFLAGS="${CPPFLAGS} -fopenmp" "${R_HOME}/bin/R" CMD SHLIB test-omp.c >> config.log 2>&1; then - echo "yes" - export PKG_CFLAGS="${PKG_CFLAGS} -fopenmp" - export R_OPENMP_ENABLED=1 - return - else - echo "no" - fi + check_openmp_flags "R installation supports OpenMP with \"-Xclang -fopenmp\" " "-Xclang -fopenmp" "-lomp" && return if [ "$(uname -m)" = "arm64" ]; then HOMEBREW_PREFIX=/opt/homebrew @@ -139,18 +111,9 @@ detect_openmp () { fi if [ -e "${HOMEBREW_PREFIX}/opt/libomp" ]; then - printf "%s" "* checking if libomp installation at ${HOMEBREW_PREFIX}/opt/libomp can be used... " LIBOMP_INCLUDE="-I${HOMEBREW_PREFIX}/opt/libomp/include -Xclang -fopenmp" LIBOMP_LINK="-L${HOMEBREW_PREFIX}/opt/libomp/lib -lomp" - if ${CC} ${CFLAGS} ${LIBOMP_INCLUDE} ${LIBOMP_LINK} test-omp.c >> config.log 2>&1; then - echo "yes" - export PKG_CFLAGS="${PKG_CFLAGS} ${LIBOMP_INCLUDE}" - export PKG_LIBS="${PKG_LIBS} ${LIBOMP_LINK}" - export R_OPENMP_ENABLED=1 - return - else - echo "no" - fi + check_openmp_flags "libomp installation at ${HOMEBREW_PREFIX}/opt/libomp can be used" "${LIBOMP_INCLUDE}" "${LIBOMP_LINK}" && return fi fi # uname=Darwin @@ -160,8 +123,6 @@ detect_openmp () { } detect_openmp -# Clean up. -rm -f test-omp.* a.out if [ "${R_OPENMP_ENABLED}" = "0" ]; then echo "***" @@ -171,10 +132,8 @@ if [ "${R_OPENMP_ENABLED}" = "0" ]; then echo "*** https://github.com/Rdatatable/data.table/wiki/Installation" echo "*** Continuing installation without OpenMP support..." echo "***" - sed -e "s|@openmp_cflags@||" src/Makevars.in > src/Makevars -else - sed -e "s|@openmp_cflags@|\$(SHLIB_OPENMP_CFLAGS)|" src/Makevars.in > src/Makevars fi +sed -e "s|@openmp_cflags@|${R_OPENMP_CFLAGS}|" -e "s|@openmp_libs@|${R_OPENMP_LIBS}|" src/Makevars.in > src/Makevars # retain user supplied PKG_ env variables, #4664. See comments in Makevars.in too. sed -e "s|@PKG_CFLAGS@|$PKG_CFLAGS|" src/Makevars > src/Makevars.tmp && mv src/Makevars.tmp src/Makevars diff --git a/src/Makevars.in b/src/Makevars.in index fcfaceba9..d98c69ca2 100644 --- a/src/Makevars.in +++ b/src/Makevars.in @@ -1,5 +1,5 @@ PKG_CFLAGS = @PKG_CFLAGS@ @openmp_cflags@ @zlib_cflags@ -PKG_LIBS = @PKG_LIBS@ @openmp_cflags@ @zlib_libs@ +PKG_LIBS = @PKG_LIBS@ @openmp_libs@ @zlib_libs@ # See WRE $1.2.1.1. But retain user supplied PKG_* too, #4664. # WRE states ($1.6) that += isn't portable and that we aren't allowed to use it. # Otherwise we could use the much simpler PKG_LIBS += @openmp_cflags@ -lz. diff --git a/tools/check-openmp-flags.R b/tools/check-openmp-flags.R new file mode 100644 index 000000000..c2332593d --- /dev/null +++ b/tools/check-openmp-flags.R @@ -0,0 +1,40 @@ +args <- commandArgs(TRUE) +stopifnot(`Usage: Rscript check-openmp-flags.R CFLAGS LIBS` = length(args) == 2) +# We'll need to create Makevars (and object and DLL files too) +setwd(tempdir()) +cat(sprintf( + "Testing if OpenMP works with CFLAGS='%s' and LIBS='%s':\n", + args[[1]], args[[2]] +)) + +# It must be a 'Makevars' for constructs like $(SHLIB_OPENMP_CFLAGS) to work: +writeLines(c( + paste("PKG_CFLAGS =", args[[1]]), + paste("PKG_LIBS =", args[[2]]) +), "Makevars") + +# Will succeed to compile even without OpenMP but return 0 +writeLines(" +#ifdef _OPENMP + #include +#endif +void test_openmp(int * result) { + int sum = 0; +#ifdef _OPENMP + // Have to test an actual OpenMP operation: simpler tests may succeed for a broken configuration, #6642 + #pragma omp parallel for reduction(+:sum) num_threads(2) + for (int i = 1; i <= 2; ++i) sum += i; +#endif + *result = sum; +} +", "test.c") + +# May fail to compile anyway +stopifnot(tools::Rcmd("SHLIB --preclean test.c") == 0) + +dyn.load(paste0("test", .Platform$dynlib.ext)) +ans <- .C("test_openmp", ans = integer(1))$ans +desired <- 3L +cat(sprintf("Test result: %d (must be %d; should be 0 for disabled OpenMP)\n", ans, desired)) +stopifnot(`Test failed` = identical(ans, desired)) +cat("Success\n")