Skip to content

Commit

Permalink
improve OpenMP detection on macOS (#6034)
Browse files Browse the repository at this point in the history
* improve OpenMP detection on macOS

* detect LLVM OpenMP builds

* remove some comments

* define _OPENMP when using LLVM libomp

* fix nesting for 'echo no'

* let openmp warning stand out a bit more

* Always redirect to config.log, not /dev/null

* NEWS

* Restore deletion of all test-omp* artefacts

* try and reduce diff by restoring comment

* reduce diff: delete in same order

* annotate 'fi' for readability

---------

Co-authored-by: Michael Chirico <michaelchirico4@gmail.com>
  • Loading branch information
kevinushey and MichaelChirico authored Apr 3, 2024
1 parent 898dce3 commit 096b20f
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 24 deletions.
2 changes: 2 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@
7. Updated a test relying on `>` working for comparing language objects to a string, which will be deprecated by R, [#5977](https://github.com/Rdatatable/data.table/issues/5977); no user-facing effect. Thanks to R-core for continuously improving the language.
8. OpenMP detection when building from source on Mac is improved, [#4348](https://github.com/Rdatatable/data.table/issues/4348). Thanks @jameshester and @kevinushey for the request and @kevinushey for the PR, @jameslamb for the advice and @s-u of R-core for ensuring CRAN machines are configured to support the uxpected setup.
# data.table [v1.15.0](https://github.com/Rdatatable/data.table/milestone/29) (30 Jan 2024)
## BREAKING CHANGE
Expand Down
89 changes: 73 additions & 16 deletions configure
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ esac

msg=0
NOZLIB=1 # if pkg-config is not available then zlib will be disabled for higher chance of compilation success
pkg-config --version >/dev/null 2>&1
pkg-config --version >> config.log 2>&1
if [ $? -ne 0 ]; then
echo "*** pkg-config is not installed."
msg=1
Expand All @@ -33,9 +33,9 @@ else
else
NOZLIB=0
lib=`pkg-config --libs zlib`
expr -- "$lib" : ".*-lz$" >/dev/null # -- for FreeBSD, #4652
expr -- "$lib" : ".*-lz$" >> config.log # -- for FreeBSD, #4652
if [ $? -ne 0 ]; then
expr -- "$lib" : ".*-lz " >/dev/null
expr -- "$lib" : ".*-lz " >> config.log
# would use \b in one expr but MacOS does not support \b
if [ $? -ne 0 ]; then
echo "*** pkg-config is installed and 'pkg-config --exists zlib' succeeds but"
Expand Down Expand Up @@ -81,36 +81,93 @@ int main() {
}
EOF

# First, try R CMD SHLIB to see if R can already compile
# things using OpenMP without any extra help from data.table
"${R_HOME}/bin/R" CMD SHLIB test-omp.c >/dev/null 2>&1 || R_NO_OPENMP=1
detect_openmp () {

if [ "$R_NO_OPENMP" = "1" ]; then
# Compilation failed -- try forcing -fopenmp instead.
R_NO_OPENMP=0
"${CC}" "${CFLAGS}" -fopenmp test-omp.c || R_NO_OPENMP=1
# TODO: and then nothing seems to be done with this outcome
else
echo "R CMD SHLIB supports OpenMP without any extra hint"
fi
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


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

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" LDFLAGS="${LDFLAGS} -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

if [ "$(uname -m)" = "arm64" ]; then
HOMEBREW_PREFIX=/opt/homebrew
else
HOMEBREW_PREFIX=/usr/local
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
fi

fi # uname=Darwin

# No support for OpenMP available
export R_OPENMP_ENABLED=0
}

detect_openmp
# Clean up.
rm -f test-omp.* a.out

# Write to Makevars
if [ "$R_NO_OPENMP" = "1" ]; then
if [ "${R_OPENMP_ENABLED}" = "0" ]; then
echo "***"
echo "*** OpenMP not supported! data.table uses OpenMP to automatically"
echo "*** parallelize operations like sorting, grouping, file reading, etc."
echo "*** For details on how to install the necessary toolchains on your OS see:"
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

# 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
sed -e "s|@PKG_LIBS@|$PKG_LIBS|" src/Makevars > src/Makevars.tmp && mv src/Makevars.tmp src/Makevars

# optional dependency on zlib
if [ "$NOZLIB" = "1" ]; then
echo "*** Compilation without compression support in fwrite"
Expand Down
19 changes: 11 additions & 8 deletions src/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -321,15 +321,18 @@ int GetVerbose(void) {

// # nocov start
SEXP hasOpenMP(void) {
// Just for use by onAttach (hence nocov) to avoid an RPRINTF from C level which isn't suppressable by CRAN
// There is now a 'grep' in CRAN_Release.cmd to detect any use of RPRINTF in init.c, which is
// why RPRINTF is capitalized in this comment to avoid that grep.
// .Platform or .Machine in R itself does not contain whether OpenMP is available because compiler and flags are per-package.
#ifdef _OPENMP

#if defined(_OPENMP)
// gcc build of libomp
return ScalarInteger(_OPENMP); // return the version; e.g. 201511 (i.e. 4.5)
#else
return ScalarInteger(0); // 0 rather than NA so that if() can be used on the result
#endif
#elif defined(KMP_VERSION_BUILD)
// LLVM builds of libomp
return ScalarInteger(KMP_VERSION_BUILD);
#else
// no OpenMP support detected
return ScalarInteger(0);
#endif

}
// # nocov end

Expand Down
8 changes: 8 additions & 0 deletions src/myomp.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@

// Compatibility define for LLVM builds of libomp.
#ifdef KMP_VERSION_BUILD
# ifndef _OPENMP
# define _OPENMP KMP_VERSION_BUILD
# endif
#endif

#ifdef _OPENMP
#include <omp.h>
#if _OPENMP >= 201511
Expand Down

1 comment on commit 096b20f

@barracuda156
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kevinushey @MichaelChirico This does not work with GCC on macOS: #6409

Please sign in to comment.