From 06bc03aebf8c061a9b3f7ea5e0452aae5267bb9a Mon Sep 17 00:00:00 2001 From: jeremie du boisberranger Date: Fri, 25 Jan 2019 18:32:46 +0100 Subject: [PATCH 1/9] openmp flags in setup and openmp support in CI --- build_tools/travis/install.sh | 9 ++++++++ setup.py | 42 ++++++++++++++++++++++++++++++++++- 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/build_tools/travis/install.sh b/build_tools/travis/install.sh index d79f8845a3d89..d0fb0409987d9 100755 --- a/build_tools/travis/install.sh +++ b/build_tools/travis/install.sh @@ -25,6 +25,13 @@ 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 + # use clang installed by conda which supports OpenMP + export CC=clang + export CXX=clang + # avoid error due to multiple openmp libraries loaded simultaneously + export KMP_DUPLICATE_LIB_OK=TRUE fi make_conda() { @@ -38,6 +45,8 @@ make_conda() { if [ $TRAVIS_OS_NAME = "osx" ] then fname=Miniconda3-latest-MacOSX-x86_64.sh + # we need to install a version on clang which supports OpenMP + TO_INSTALL="$TO_INSTALL llvm-openmp clang" else fname=Miniconda3-latest-Linux-x86_64.sh fi diff --git a/setup.py b/setup.py index cce21f5883c5a..931eb8d5176e8 100755 --- a/setup.py +++ b/setup.py @@ -102,7 +102,47 @@ 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('CC', ''): + # -fopenmp can't be passed as compile arg when using apple clang + return [''] + 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 From 53102d3831308ec76f9237bba8d087790d52734d Mon Sep 17 00:00:00 2001 From: jeremie du boisberranger Date: Tue, 29 Jan 2019 17:40:27 +0100 Subject: [PATCH 2/9] add install doc for mac --- doc/developers/advanced_installation.rst | 26 ++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/doc/developers/advanced_installation.rst b/doc/developers/advanced_installation.rst index b3647f83b92af..1224cb0742ddf 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.23 +- Cython >=0.23 +- OpenMP Running tests requires @@ -102,6 +103,27 @@ 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. + +You first need to install the OpenMP library:: + + brew install libomp + +Then you need to set the following environment variables:: + + export CC="clang -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 + +Finally you can build the package using the standard command. + Installing build dependencies ============================= @@ -111,7 +133,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 From a987f1bd40322e05028547193c0e3daaaff7b6db Mon Sep 17 00:00:00 2001 From: jeremie du boisberranger Date: Tue, 29 Jan 2019 17:54:26 +0100 Subject: [PATCH 3/9] comment --- setup.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 931eb8d5176e8..1bd525ee502e5 100755 --- a/setup.py +++ b/setup.py @@ -110,8 +110,18 @@ def get_openmp_flag(compiler): elif sys.platform == "darwin" and ('icc' in compiler or 'icl' in compiler): return ['-openmp'] elif sys.platform == "darwin" and 'openmp' in os.getenv('CC', ''): - # -fopenmp can't be passed as compile arg when using apple clang + # -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 CC="clang -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'] From 5169c53f56fe1b63090506e9d4d3687541a3ff3a Mon Sep 17 00:00:00 2001 From: jeremie du boisberranger Date: Tue, 29 Jan 2019 20:40:31 +0100 Subject: [PATCH 4/9] revert trailing whitespace --- doc/developers/advanced_installation.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/developers/advanced_installation.rst b/doc/developers/advanced_installation.rst index 1224cb0742ddf..882191d7dcd8e 100644 --- a/doc/developers/advanced_installation.rst +++ b/doc/developers/advanced_installation.rst @@ -46,7 +46,7 @@ Scikit-learn requires: Building Scikit-learn also requires -- Cython >=0.23 +- Cython >=0.23 - OpenMP Running tests requires From 417e6032b584c78add15047cb4fb25c47f227215 Mon Sep 17 00:00:00 2001 From: jeremie du boisberranger Date: Thu, 31 Jan 2019 12:24:15 +0100 Subject: [PATCH 5/9] CC to CPPFLAGS --- build_tools/travis/install.sh | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/build_tools/travis/install.sh b/build_tools/travis/install.sh index d0fb0409987d9..c99986be871fb 100755 --- a/build_tools/travis/install.sh +++ b/build_tools/travis/install.sh @@ -27,10 +27,19 @@ then ccache --max-size 100M --show-stats elif [ $TRAVIS_OS_NAME = "osx" ] then - # use clang installed by conda which supports OpenMP + # install OpenMP not present by default on osx + brew install libomp + + # enable OpenMP support for Apple-clang export CC=clang - export CXX=clang - # avoid error due to multiple openmp libraries loaded simultaneously + 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 + + # avoid error due to multiple OpenMP libraries loaded simultaneously export KMP_DUPLICATE_LIB_OK=TRUE fi @@ -45,8 +54,6 @@ make_conda() { if [ $TRAVIS_OS_NAME = "osx" ] then fname=Miniconda3-latest-MacOSX-x86_64.sh - # we need to install a version on clang which supports OpenMP - TO_INSTALL="$TO_INSTALL llvm-openmp clang" else fname=Miniconda3-latest-Linux-x86_64.sh fi From 0b9512f2016b26a6d3a27a45e3cce19886181460 Mon Sep 17 00:00:00 2001 From: jeremie du boisberranger Date: Thu, 31 Jan 2019 12:26:35 +0100 Subject: [PATCH 6/9] CC to CPPFLAGS --- setup.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/setup.py b/setup.py index 1bd525ee502e5..c4a042c355a5b 100755 --- a/setup.py +++ b/setup.py @@ -109,14 +109,14 @@ def get_openmp_flag(compiler): 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('CC', ''): + 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": + # variables to build with Apple-clang and the brew installed "libomp": # - # export CC="clang -Xpreprocessor -fopenmp" + # 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 @@ -125,7 +125,8 @@ def get_openmp_flag(compiler): return ['-fopenmp'] -OPENMP_EXTENSIONS = [] +OPENMP_EXTENSIONS = ["sklearn.cluster._k_means_lloyd", + "sklearn.cluster._k_means_elkan"] # custom build_ext command to set OpenMP compile flags depending on os and From ec5df734038df4edb502d586df15e38f428e6b01 Mon Sep 17 00:00:00 2001 From: jeremie du boisberranger Date: Thu, 31 Jan 2019 12:36:13 +0100 Subject: [PATCH 7/9] install doc --- doc/developers/advanced_installation.rst | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/doc/developers/advanced_installation.rst b/doc/developers/advanced_installation.rst index f52e39823d37c..ae02dc41df2ad 100644 --- a/doc/developers/advanced_installation.rst +++ b/doc/developers/advanced_installation.rst @@ -46,8 +46,8 @@ Scikit-learn requires: Building Scikit-learn also requires -- OpenMP - Cython >=0.28.5 +- OpenMP Running tests requires @@ -117,8 +117,11 @@ You first need to install the OpenMP library:: Then you need to set the following environment variables:: - export CC="clang -Xpreprocessor -fopenmp" + 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 From 29ad8a163ae8093f30b6bbda01ca535909a35143 Mon Sep 17 00:00:00 2001 From: jeremie du boisberranger Date: Sun, 3 Feb 2019 19:22:14 +0100 Subject: [PATCH 8/9] clang full path for travis & improve adv install doc --- build_tools/travis/install.sh | 4 ++-- doc/developers/advanced_installation.rst | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/build_tools/travis/install.sh b/build_tools/travis/install.sh index c99986be871fb..f36b6bb3d1b0f 100755 --- a/build_tools/travis/install.sh +++ b/build_tools/travis/install.sh @@ -31,8 +31,8 @@ then brew install libomp # enable OpenMP support for Apple-clang - export CC=clang - export CXX=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" diff --git a/doc/developers/advanced_installation.rst b/doc/developers/advanced_installation.rst index ae02dc41df2ad..129f89250aff8 100644 --- a/doc/developers/advanced_installation.rst +++ b/doc/developers/advanced_installation.rst @@ -109,7 +109,8 @@ 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. +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:: From 5411a466410529bc89b7738cd1db04984fe76115 Mon Sep 17 00:00:00 2001 From: jeremie du boisberranger Date: Mon, 4 Feb 2019 09:29:53 +0100 Subject: [PATCH 9/9] clear openmp extensions --- setup.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/setup.py b/setup.py index c4a042c355a5b..7fee206e2c66b 100755 --- a/setup.py +++ b/setup.py @@ -125,8 +125,7 @@ def get_openmp_flag(compiler): return ['-fopenmp'] -OPENMP_EXTENSIONS = ["sklearn.cluster._k_means_lloyd", - "sklearn.cluster._k_means_elkan"] +OPENMP_EXTENSIONS = [] # custom build_ext command to set OpenMP compile flags depending on os and