| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113 |
- """
- Utilities useful during the build.
- """
- # author: Andy Mueller, Gael Varoquaux
- # license: BSD
- import contextlib
- import os
- import sklearn
- from .._min_dependencies import CYTHON_MIN_VERSION
- from ..externals._packaging.version import parse
- from .openmp_helpers import check_openmp_support
- from .pre_build_helpers import basic_check_build
- DEFAULT_ROOT = "sklearn"
- def _check_cython_version():
- message = (
- "Please install Cython with a version >= {0} in order "
- "to build a scikit-learn from source."
- ).format(CYTHON_MIN_VERSION)
- try:
- import Cython
- except ModuleNotFoundError as e:
- # Re-raise with more informative error message instead:
- raise ModuleNotFoundError(message) from e
- if parse(Cython.__version__) < parse(CYTHON_MIN_VERSION):
- message += " The current version of Cython is {} installed in {}.".format(
- Cython.__version__, Cython.__path__
- )
- raise ValueError(message)
- def cythonize_extensions(extension):
- """Check that a recent Cython is available and cythonize extensions"""
- _check_cython_version()
- from Cython.Build import cythonize
- # Fast fail before cythonization if compiler fails compiling basic test
- # code even without OpenMP
- basic_check_build()
- # check simple compilation with OpenMP. If it fails scikit-learn will be
- # built without OpenMP and the test test_openmp_supported in the test suite
- # will fail.
- # `check_openmp_support` compiles a small test program to see if the
- # compilers are properly configured to build with OpenMP. This is expensive
- # and we only want to call this function once.
- # The result of this check is cached as a private attribute on the sklearn
- # module (only at build-time) to be used in the build_ext subclass defined
- # in the top-level setup.py file to actually build the compiled extensions
- # with OpenMP flags if needed.
- sklearn._OPENMP_SUPPORTED = check_openmp_support()
- n_jobs = 1
- with contextlib.suppress(ImportError):
- import joblib
- n_jobs = joblib.cpu_count()
- # Additional checks for Cython
- cython_enable_debug_directives = (
- os.environ.get("SKLEARN_ENABLE_DEBUG_CYTHON_DIRECTIVES", "0") != "0"
- )
- compiler_directives = {
- "language_level": 3,
- "boundscheck": cython_enable_debug_directives,
- "wraparound": False,
- "initializedcheck": False,
- "nonecheck": False,
- "cdivision": True,
- }
- return cythonize(
- extension,
- nthreads=n_jobs,
- compiler_directives=compiler_directives,
- )
- def gen_from_templates(templates):
- """Generate cython files from a list of templates"""
- # Lazy import because cython is not a runtime dependency.
- from Cython import Tempita
- for template in templates:
- outfile = template.replace(".tp", "")
- # if the template is not updated, no need to output the cython file
- if not (
- os.path.exists(outfile)
- and os.stat(template).st_mtime < os.stat(outfile).st_mtime
- ):
- with open(template, "r") as f:
- tmpl = f.read()
- tmpl_ = Tempita.sub(tmpl)
- warn_msg = (
- "# WARNING: Do not edit this file directly.\n"
- f"# It is automatically generated from {template!r}.\n"
- "# Changes must be made there.\n\n"
- )
- with open(outfile, "w") as f:
- f.write(warn_msg)
- f.write(tmpl_)
|