diff --git a/build_tools/travis/install.sh b/build_tools/travis/install.sh index d79f8845a3d89..f36b6bb3d1b0f 100755 --- a/build_tools/travis/install.sh +++ b/build_tools/travis/install.sh @@ -25,6 +25,22 @@ then # export CCACHE_LOGFILE=/tmp/ccache.log # ~60M is used by .ccache when compiling from scratch at the time of writing ccache --max-size 100M --show-stats +elif [ $TRAVIS_OS_NAME = "osx" ] +then + # install OpenMP not present by default on osx + brew install libomp + + # enable OpenMP support for Apple-clang + export CC=/usr/bin/clang + export CXX=/usr/bin/clang++ + export CPPFLAGS="$CPPFLAGS -Xpreprocessor -fopenmp" + export CFLAGS="$CFLAGS -I/usr/local/opt/libomp/include" + export CXXFLAGS="$CXXFLAGS -I/usr/local/opt/libomp/include" + export LDFLAGS="$LDFLAGS -L/usr/local/opt/libomp/lib -lomp" + export DYLD_LIBRARY_PATH=/usr/local/opt/libomp/lib + + # avoid error due to multiple OpenMP libraries loaded simultaneously + export KMP_DUPLICATE_LIB_OK=TRUE fi make_conda() { diff --git a/doc/developers/advanced_installation.rst b/doc/developers/advanced_installation.rst index 8f6f8496c3606..129f89250aff8 100644 --- a/doc/developers/advanced_installation.rst +++ b/doc/developers/advanced_installation.rst @@ -46,7 +46,8 @@ Scikit-learn requires: Building Scikit-learn also requires -- Cython >=0.28.5 +- Cython >=0.28.5 +- OpenMP Running tests requires @@ -102,6 +103,31 @@ On Unix-like systems, you can simply type ``make`` in the top-level folder to build in-place and launch all the tests. Have a look at the ``Makefile`` for additional utilities. +Mac OSX +------- + +The default C compiler, Apple-clang, on Mac OSX does not directly support +OpenMP. The first solution to build scikit-learn is to install another C +compiler such as gcc or llvm-clang. Another solution is to enable OpenMP +support on the default Apple-clang. In the following we present how to +configure this second option. + +You first need to install the OpenMP library:: + + brew install libomp + +Then you need to set the following environment variables:: + + export CC=clang + export CXX=clang++ + export CPPFLAGS="$CPPFLAGS -Xpreprocessor -fopenmp" + export CFLAGS="$CFLAGS -I/usr/local/opt/libomp/include" + export CXXFLAGS="$CXXFLAGS -I/usr/local/opt/libomp/include" + export LDFLAGS="$LDFLAGS -L/usr/local/opt/libomp/lib -lomp" + export DYLD_LIBRARY_PATH=/usr/local/opt/libomp/lib + +Finally you can build the package using the standard command. + Installing build dependencies ============================= @@ -111,7 +137,7 @@ Linux Installing from source requires you to have installed the scikit-learn runtime dependencies, Python development headers and a working C/C++ compiler. Under Debian-based operating systems, which include Ubuntu:: - + sudo apt-get install build-essential python3-dev python3-setuptools \ python3-numpy python3-scipy \ libatlas-dev libatlas3-base diff --git a/setup.py b/setup.py index cce21f5883c5a..7fee206e2c66b 100755 --- a/setup.py +++ b/setup.py @@ -102,7 +102,57 @@ def run(self): shutil.rmtree(os.path.join(dirpath, dirname)) -cmdclass = {'clean': CleanCommand} +def get_openmp_flag(compiler): + if sys.platform == "win32" and ('icc' in compiler or 'icl' in compiler): + return ['/Qopenmp'] + elif sys.platform == "win32": + return ['/openmp'] + elif sys.platform == "darwin" and ('icc' in compiler or 'icl' in compiler): + return ['-openmp'] + elif sys.platform == "darwin" and 'openmp' in os.getenv('CPPFLAGS', ''): + # -fopenmp can't be passed as compile flag when using Apple-clang. + # OpenMP support has to be enabled during preprocessing. + # + # For example, our macOS wheel build jobs use the following environment + # variables to build with Apple-clang and the brew installed "libomp": + # + # export CPPFLAGS="$CPPFLAGS -Xpreprocessor -fopenmp" + # export CFLAGS="$CFLAGS -I/usr/local/opt/libomp/include" + # export LDFLAGS="$LDFLAGS -L/usr/local/opt/libomp/lib -lomp" + # export DYLD_LIBRARY_PATH=/usr/local/opt/libomp/lib + return [''] + # Default flag for GCC and clang: + return ['-fopenmp'] + + +OPENMP_EXTENSIONS = [] + + +# custom build_ext command to set OpenMP compile flags depending on os and +# compiler +# build_ext has to be imported after setuptools +from numpy.distutils.command.build_ext import build_ext # noqa + + +class build_ext_subclass(build_ext): + def build_extensions(self): + if hasattr(self.compiler, 'compiler'): + compiler = self.compiler.compiler[0] + else: + compiler = self.compiler.__class__.__name__ + + openmp_flag = get_openmp_flag(compiler) + + for e in self.extensions: + if e.name in OPENMP_EXTENSIONS: + e.extra_compile_args += openmp_flag + e.extra_link_args += openmp_flag + + build_ext.build_extensions(self) + + +cmdclass = {'clean': CleanCommand, 'build_ext': build_ext_subclass} + # Optional wheelhouse-uploader features # To automate release of binary packages for scikit-learn we need a tool