Welcome to scikit-build

scikit-build is a Python build system for CPython C/C++/Fortran/Cython extensions using CMake.

The scikit-build package is fundamentally just glue between the setuptools Python module and CMake.

The next generation of scikit-build, scikit-build-core, is currently under development. This provides a simple, reliable build backend for CMake that does not use setuptools and provides a lot of new features. Scikit-build-core can also power a setuptools-based extension system, which will eventually become the backend for scikit-build (classic). If you do not require extensive customization of the build process, you should consider trying scikit-build-core instead of scikit-build.

To get started, see this example. For more examples, see scikit-build-sample-projects.

Installation

Install package with pip

To install with pip:

$ pip install scikit-build

Install from source

To install scikit-build from the latest source, first obtain the source code:

$ git clone https://github.com/scikit-build/scikit-build
$ cd scikit-build

then install with:

$ pip install .

or:

$ pip install -e .

for development.

Dependencies

Python Packages

The project has a few common Python package dependencies. These can be seen in setup.py and pyproject.toml.

Compiler Toolchain

The same compiler toolchain used to build the CPython interpreter should also be available. Refer to the CPython Developer’s Guide for details about the compiler toolchain for your operating system.

For example, on Ubuntu Linux, install with:

$ sudo apt-get install build-essential

On Mac OSX, install XCode to build packages for the system Python.

On Windows, install the version of Visual Studio used to create the target version of CPython

CMake

The easiest way to get CMake is to add it to the pyproject.toml file. With pip 10 or later, this will cause the CMake Python package to be downloaded and installed when your project is built.

To manually install the cmake package from PyPI:

$ pip install cmake

To install the cmake package in conda:

$ conda install -c conda-forge cmake

You can also download the standard CMake binaries for your platform.

Alternatively, build CMake from source with a C++ compiler if binaries are not available for your operating system.

Why should I use scikit-build ?

Scikit-build is a replacement for distutils.core.Extension with the following advantages:

Basic Usage

Example of setup.py, CMakeLists.txt and pyproject.toml

The full example code is Here

Make a fold name my_project as your project root folder, place the following in your project’s setup.py file:

from skbuild import setup  # This line replaces 'from setuptools import setup'
setup(
    name="hello-cpp",
    version="1.2.3",
    description="a minimal example package (cpp version)",
    author='The scikit-build team',
    license="MIT",
    packages=['hello'],
    python_requires=">=3.7",
)

Your project now uses scikit-build instead of setuptools.

Next, add a CMakeLists.txt to describe how to build your extension. In the following example, a C++ extension named _hello is built:

cmake_minimum_required(VERSION 3.18...3.22)

project(hello)

find_package(PythonExtensions REQUIRED)

add_library(_hello MODULE hello/_hello.cxx)
python_extension_module(_hello)
install(TARGETS _hello LIBRARY DESTINATION hello)

Then, add a pyproject.toml to list the build system requirements:

[build-system]
requires = [
    "setuptools>=42",
    "scikit-build>=0.13",
    "cmake>=3.18",
    "ninja",
]
build-backend = "setuptools.build_meta"

Make a hello folder inside my_project folder and place _hello.cxx and __init__.py inside hello folder.

Now every thing is ready, go to my_project’s parent folder and type following command to install your extension:

pip install my_project/.

If you want to see the detail of installation:

pip install my_project/. -v

Try your new extension:

$ python
Python 3.10.4 (main, Jun 29 2022, 12:14:53) [GCC 11.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import hello
>>> hello.hello("scikit-build")
Hello, scikit-build!
>>>

You can add lower limits to cmake or scikit-build as needed. Ninja should be limited to non-Windows systems, as MSVC 2017+ ships with Ninja already, and there are fall-backs if Ninja is missing, and the Python Ninja seems to be less likely to find MSVC than the built-in one currently.

Note

By default, scikit-build looks in the project top-level directory for a file named CMakeLists.txt. It will then invoke cmake executable specifying a generator matching the python being used.

Setup options

setuptools options

The section below documents some of the options accepted by the setup() function. These currently must be passed in your setup.py, not in setup.cfg, as scikit-build intercepts them and inspects them. This restriction may be relaxed in the future. Setuptools options not listed here can be placed in setup.cfg as normal.

  • packages: Explicitly list of all packages to include in the distribution. Setuptools will not recursively scan the source tree looking for any directory with an __init__.py file. To automatically generate the list of packages, see Using find_package().

  • package_dir: A mapping of package to directory names

  • include_package_data: If set to True, this tells setuptools to automatically include any data files it finds inside your package directories that are specified by your MANIFEST.in file. For more information, see the setuptools documentation section on Including Data Files. scikit-build matches the setuptools behavior of defaulting this parameter to True if a pyproject.toml file exists and contains either the project or tool.setuptools table.

  • package_data: A dictionary mapping package names to lists of glob patterns. For a complete description and examples, see the setuptools documentation section on Including Data Files. You do not need to use this option if you are using include_package_data, unless you need to add e.g. files that are generated by your setup script and build process. (And are therefore not in source control or are files that you don’t want to include in your source distribution.)

  • exclude_package_data: Dictionary mapping package names to lists of glob patterns that should be excluded from the package directories. You can use this to trim back any excess files included by include_package_data. For a complete description and examples, see the setuptools documentation section on Including Data Files.

  • py_modules: List all modules rather than listing packages. More details in the Listing individual modules section of the distutils documentation.

  • data_files: Sequence of (directory, files) pairs. Each (directory, files) pair in the sequence specifies the installation directory and the files to install there. More details in the Installing Additional Files section of the setuptools documentation.

  • entry_points: A dictionary mapping entry point group names to strings or lists of strings defining the entry points. Entry points are used to support dynamic discovery of services or plugins provided by a project. See Dynamic Discovery of Services and Plugins for details and examples of the format of this argument. In addition, this keyword is used to support Automatic Script Creation. Note that if using pyproject.toml for configuration, the requirement to put entry_points in setup.py also requires that the project section include entry_points in the dynamic section.

  • scripts: List of python script relative paths. If the first line of the script starts with #! and contains the word python, the Distutils will adjust the first line to refer to the current interpreter location. More details in the Installing Scripts section of the distutils documentation.

New in version 0.8.0.

  • zip_safe: A boolean indicating if the Python packages may be run directly from a zip file. If not already set, scikit-build sets this option to False. See Setting the zip_safe flag section of the setuptools documentation.

Note

As specified in the Wheel documentation, the universal and python-tag options have no effect.

scikit-build options

Scikit-build augments the setup() function with the following options:

For example:

setup(
  [...]
  cmake_args=['-DSOME_FEATURE:BOOL=OFF']
  [...]
  )
  • cmake_install_dir: relative directory where the CMake artifacts are installed. By default, it is set to an empty string.

  • cmake_source_dir: Relative directory containing the project CMakeLists.txt. By default, it is set to the top-level directory where setup.py is found.

  • cmake_process_manifest_hook: Python function consuming the list of files to be installed produced by cmake. For example, cmake_process_manifest_hook can be used to exclude static libraries from the built wheel.

For example:

def exclude_static_libraries(cmake_manifest):
    return list(filter(lambda name: not (name.endswith('.a')), cmake_manifest))

setup(
  [...]
  cmake_process_manifest_hook=exclude_static_libraries
  [...]
)

New in version 0.5.0.

  • cmake_with_sdist: Boolean indicating if CMake should be executed when running sdist command. Setting this option to True is useful when part of the sources specified in MANIFEST.in are downloaded by CMake. By default, this option is False.

New in version 0.7.0.

  • cmake_languages: Tuple of languages that the project use, by default ('C', 'CXX',). This option ensures that a generator is chosen that supports all languages for the project.

  • cmake_minimum_required_version: String identifying the minimum version of CMake required to configure the project.

  • cmake_install_target: Name of the target to “build” for installing the artifacts into the wheel. By default, this option is set to install, which is always provided by CMake. This can be used to only install certain components.

For example:

install(TARGETS foo COMPONENT runtime)
add_custom_target(foo-install-runtime
    ${CMAKE_COMMAND}
    -DCMAKE_INSTALL_COMPONENT=runtime
    -P "${PROJECT_BINARY_DIR}/cmake_install.cmake"
    DEPENDS foo
    )

Scikit-build changes the following options:

New in version 0.7.0.

  • setup_requires: If cmake is found in the list, it is explicitly installed first by scikit-build.

Command line options

Warning: Passing options to setup.py is deprecated and may be removed in a future release. Environment variables can be used instead for most options.

usage: setup.py [global_opts] cmd1 [cmd1_opts] [cmd2 [cmd2_opts] ...] [skbuild_opts] [cmake_configure_opts] [-- [cmake_opts] [-- [build_tool_opts]]]
or: setup.py --help [cmd1 cmd2 ...]
or: setup.py --help-commands
or: setup.py cmd --help

There are few types of options:

setuptools, scikit-build and CMake configure options can be passed normally, the cmake and build_tool set of options needs to be separated by --:

Arguments following a "--" are passed directly to CMake (e.g. -DSOME_FEATURE:BOOL=ON).
Arguments following a second "--" are passed directly to  the build tool.

setuptools options

For more details, see the official documentation.

scikit-build extends the global set of setuptools options with:

New in version 0.4.0.

Global options:
  [...]
  --hide-listing      do not display list of files being included in the
                      distribution

New in version 0.5.0.

Global options:
  [...]
  --force-cmake       always run CMake
  --skip-cmake        do not run CMake

Note

As specified in the Wheel documentation, the --universal and --python-tag options have no effect.

scikit-build options

scikit-build options:
  --build-type       specify the CMake build type (e.g. Debug or Release)
  -G , --generator   specify the CMake build system generator
  -j N               allow N build jobs at once
  [...]

New in version 0.7.0.

scikit-build options:
  [...]
  --cmake-executable specify the path to the cmake executable

New in version 0.8.0.

scikit-build options:
  [...]
  --skip-generator-test  skip generator test when a generator is explicitly selected using --generator

CMake Configure options

New in version 0.10.1.

These options are relevant when configuring a project and can be passed as global options using setup.py or pip install.

The CMake options accepted as global options are any of the following:

-C<initial-cache>            = Pre-load a script to populate the cache.
-D<var>[:<type>]=<value>     = Create or update a cmake cache entry.

Warning

The CMake configure option should be passed without spaces. For example, use -DSOME_FEATURE:BOOL=ON instead of -D SOME_FEATURE:BOOL=ON.

CMake options

These are any specific to CMake. See list of CMake options.

For example:

-DSOME_FEATURE:BOOL=OFF

build tool options

These are specific to the underlying build tool (e.g msbuild.exe, make, ninja).

Advanced Usage

How to test if scikit-build is driving the compilation ?

To support the case of code base being built as both a standalone project and a python wheel, it is possible to test for the variable SKBUILD:

if(SKBUILD)
  message(STATUS "The project is built using scikit-build")
endif()

Adding cmake as building requirement only if not installed or too low a version

If systematically installing cmake wheel is not desired, it is possible to set it using an in-tree backend. For this purpose place the following configuration in your pyproject.toml:

[build-system]
requires = [
  "setuptools>=42",
  "packaging",
  "scikit-build",
  "ninja; platform_system!='Windows'"
]
build-backend = "backend"
backend-path = ["_custom_build"]

then you can implement a thin wrapper around build_meta in the _custom_build/backend.py file:

from setuptools import build_meta as _orig

prepare_metadata_for_build_wheel = _orig.prepare_metadata_for_build_wheel
build_wheel = _orig.build_wheel
build_sdist = _orig.build_sdist
get_requires_for_build_sdist = _orig.get_requires_for_build_sdist

def get_requires_for_build_wheel(config_settings=None):
    from packaging import version
    from skbuild.exceptions import SKBuildError
    from skbuild.cmaker import get_cmake_version
    packages = []
    try:
        if version.parse(get_cmake_version()) < version.parse("3.4"):
            packages.append('cmake')
    except SKBuildError:
        packages.append('cmake')

    return _orig.get_requires_for_build_wheel(config_settings) + packages

Also see scikit-build-core where this is a built-in feature.

Enabling parallel build

Ninja

If Ninja generator is used, the associated build tool (called ninja) will automatically parallelize the build based on the number of available CPUs.

To limit the number of parallel jobs, the build tool option -j N can be passed to ninja.

For example, to limit the number of parallel jobs to 3, the following could be done:

python setup.py bdist_wheel -- -- -j3

For complex projects where more granularity is required, it is also possible to limit the number of simultaneous link jobs, or compile jobs, or both.

Indeed, starting with CMake 3.11, it is possible to configure the project with these options:

For example, to have at most 5 compile jobs and 2 link jobs, the following could be done:

python setup.py bdist_wheel -- \
  -DCMAKE_JOB_POOL_COMPILE:STRING=compile \
  -DCMAKE_JOB_POOL_LINK:STRING=link \
  '-DCMAKE_JOB_POOLS:STRING=compile=5;link=2'

Unix Makefiles

If Unix Makefiles generator is used, the associated build tool (called make) will NOT automatically parallelize the build, the user has to explicitly pass option like -j N.

For example, to limit the number of parallel jobs to 3, the following could be done:

python setup.py bdist_wheel -- -- -j3

Visual Studio IDE

If Visual Studio IDE generator is used, there are two types of parallelism:

  • target level parallelism

  • object level parallelism

Warning

Since finding the right combination of parallelism can be challenging, whenever possible we recommend to use the Ninja generator.

To adjust the object level parallelism, the compiler flag /MP[processMax] could be specified. To learn more, read /MP (Build with Multiple Processes).

For example:

set CXXFLAGS=/MP4
python setup.py bdist_wheel

The target level parallelism can be set from command line using /maxcpucount:N. This defines the number of simultaneous MSBuild.exe processes. To learn more, read Building Multiple Projects in Parallel with MSBuild.

For example:

python setup.py bdist_wheel -- -- /maxcpucount:4

Support for isolated build

New in version 0.8.0.

As specified in PEP 518, dependencies required at install time can be specified using a pyproject.toml file. Starting with pip 10.0, pip reads the pyproject.toml file and installs the associated dependencies in an isolated environment. See the pip build system interface documentation.

An isolated environment will be created when using pip to install packages directly from source or to create an editable installation.

scikit-build supports these use cases as well as the case where the isolated environment support is explicitly disabled using the pip option --no-build-isolation available with the install, download and wheel commands.

Optimized incremental build

To optimize the developer workflow, scikit-build reconfigures the CMake project only when needed. It caches the environment associated with the generator as well as the CMake execution properties.

The CMake properties are saved in a CMake spec file responsible to store the CMake executable path, the CMake configuration arguments, the CMake version as well as the environment variables PYTHONNOUSERSITE and PYTHONPATH.

If there are no CMakeCache.txt file or if any of the CMake properties changes, scikit-build will explicitly reconfigure the project calling skbuild.cmaker.CMaker.configure().

If a file is added to the CMake build system by updating one of the CMakeLists.txt file, scikit-build will not explicitly reconfigure the project. Instead, the generated build-system will automatically detect the change and reconfigure the project after skbuild.cmaker.CMaker.make() is called.

Environment variable configuration

Scikit-build support environment variables to configure some options. These are:

SKBUILD_CONFIGURE_OPTIONS/CMAKE_ARGS

This will add configuration options when configuring CMake. SKBUILD_CONFIGURE_OPTIONS will be used instead of CMAKE_ARGS if both are defined.

SKBUILD_BUILD_OPTIONS

Pass options to the build.

Cross-compilation

See CMake Toolchains.

Introduction to dockross

Note

To be documented. See #227.

Using dockcross-manylinux to generate Linux wheels

Note

To be documented. See #227.

Using dockcross-mingwpy to generate Windows wheels

Note

To be documented. See #227.

Examples for scikit-build developers

Note

To be documented. See #227.

Provide small, self-contained setup function calls for (at least) two use cases:

  • when a CMakeLists.txt file already exists

  • when a user wants scikit-build to create a CMakeLists.txt file based on the user specifying some input files.

C Runtime, Compiler and Build System Generator

scikit-build uses sensible defaults allowing to select the C runtime matching the official CPython recommendations. It also ensures developers remain productive by selecting an alternative environment if recommended one is not available.

The table below lists the different C runtime implementations, compilers and their usual distribution mechanisms for each operating systems.

Linux

MacOSX

Windows

C runtime

GNU C Library (glibc)

libSystem library

Microsoft C run-time library

Compiler

GNU compiler (gcc)

clang

Microsoft C/C++ Compiler (cl.exe)

Provenance

Package manager

OSX SDK within XCode

Build system generator

Since scikit-build simply provides glue between setuptools and CMake, it needs to choose a CMake generator to configure the build system allowing to build of CPython C extensions.

The table below lists the generator supported by scikit-build:

Operating System

Linux

MacOSX

Windows

CMake Generator

  1. Ninja

  2. Unix Makefiles

  1. Ninja

  2. Visual Studio

  3. NMake Makefiles

  4. NMake Makefiles JOM

When building a project, scikit-build iteratively tries each generator (in the order listed in the table) until it finds a working one.

For more details about CMake generators, see CMake documentation.

Ninja

  • Supported platform(s): Linux, MacOSX and Windows

  • If ninja executable is in the PATH, the associated generator is used to setup the project build system based on ninja files.

  • In a given python environment, installing the ninja python package with pip install ninja will ensure that ninja is in the PATH.

Note

Automatic parallelism

An advantage of ninja is that it automatically parallelizes the build based on the number of CPUs. See Enabling parallel build.

Note

Ninja on Windows

When Ninja generator is used on Windows, scikit-build will make sure the project is configured and built with the appropriate [3] environment (equivalent of calling vcvarsall.bat x86 or vcvarsall.bat amd64).

When Visual Studio >= 2017 is used, ninja is available by default thanks to the Microsoft CMake extension:

C:/Program Files (x86)/Microsoft Visual Studio/2017/Professional/Common7/IDE/CommonExtensions/Microsoft/CMake/Ninja/ninja.exe

Unix Makefiles

  • Supported platform(s): Linux, MacOSX

  • scikit-build uses this generator to generate a traditional Makefile based build system.

Visual Studio IDE

  • Supported platform(s): Windows

  • scikit-build uses the generator corresponding to selected version of Visual Studio and generate a solution file based build system.

Architecture

CPython Version

x86 (32-bit)

x64 (64-bit)

3.7 and above

Visual Studio 17 2022 Visual Studio 16 2019 Visual Studio 15 2017

Visual Studio 17 2022 Win64 Visual Studio 16 2019 Win64 Visual Studio 15 2017 Win64

Note

The Visual Studio generators can not be used when only alternative environments are installed, in that case Ninja or NMake Makefiles are used.

NMake Makefiles

  • Supported platform(s): Windows

  • scikit-build will make sure the project is configured and built with the appropriate [3] environment (equivalent of calling vcvarsall.bat x86 or vcvarsall.bat amd64).

Note

NMake Makefiles JOM

The NMake Makefiles JOM generator is supported but it is not automatically used by scikit-build (even if jom executable is in the PATH), it always needs to be explicitly specified. For example:

python setup.py build -G "NMake Makefiles JOM"

For more details, see scikit-build options.

Linux

scikit-build uses the toolchain set using CC (and CXX) environment variables. If no environment variable is set, it defaults to gcc.

To build compliant Linux wheels, scikit-build also supports the manylinux platform described in PEP-0513. We recommend the use of dockcross/manylinux-x64 and dockcross/manylinux-x86. These images are optimized for building Linux wheels using scikit-build.

MacOSX

scikit-build uses the toolchain set using CC (and CXX) environment variables. If no environment variable is set, it defaults to the Apple compiler installed with XCode.

Default Deployment Target and Architecture

New in version 0.7.0.

The default deployment target and architecture selected by scikit-build are hard-coded for MacOSX and are respectively 10.9 and x86_64.

This means that the platform name associated with the bdist_wheel command is:

macosx-10.9-x86_64

and is equivalent to building the wheel using:

python setup.py bdist_wheel --plat-name macosx-10.9-x86_64

Respectively, the values associated with the corresponding CMAKE_OSX_DEPLOYMENT_TARGET and CMAKE_OSX_ARCHITECTURES CMake options that are automatically used to configure the project are the following:

CMAKE_OSX_DEPLOYMENT_TARGET:STRING=10.9
CMAKE_OSX_ARCHITECTURES:STRING=x86_64

As illustrated in the table below, choosing 10.9 as deployment target to build MacOSX wheels will allow them to work on System CPython, the Official CPython, Macports and also Homebrew installations of CPython.

List of platform names for each CPython distributions, CPython and OSX versions.

CPython Distribution

CPython Version

OSX Version

get_platform() [1]

Official CPython

3.9, 3.10

10.9

macosx-10.9-universal2

3.8

11

macosx-11.0-universal2

3.7, 3.8, 3.9, 3.10

10.9

macosx-10.9-x86_64

Macports CPython

3.x

Current

Depends on current macOS version.

Homebrew CPython

3.x

Current

The information above have been adapted from the excellent Spinning wheels article written by Matthew Brett.

Default SDK and customization

New in version 0.7.0.

By default, scikit-build lets CMake discover the most recent SDK available on the system during the configuration of the project. CMake internally uses the logic implemented in the Platform/Darwin-Initialize.cmake CMake module.

Customizing SDK

New in version 0.7.0.

If needed, this can be overridden by explicitly passing the CMake option CMAKE_OSX_SYSROOT. For example:

python setup.py bdist_wheel -- -DCMAKE_OSX_SYSROOT:PATH=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk

Customizing Deployment Target and Architecture

New in version 0.11.0.

Deployment target can be customized by setting the MACOSX_DEPLOYMENT_TARGET environment variable.

New in version 0.7.0.

Deployment target and architecture can be customized by associating the --plat-name macosx-<deployment_target>-<arch> option with the bdist_wheel command.

For example:

python setup.py bdist_wheel --plat-name macosx-10.9-x86_64

scikit-build also sets the value of CMAKE_OSX_DEPLOYMENT_TARGET and CMAKE_OSX_ARCHITECTURES option based on the provided platform name. Based on the example above, the options used to configure the associated CMake project are:

-DCMAKE_OSX_DEPLOYMENT_TARGET:STRING=10.9
-DCMAKE_OSX_ARCHITECTURES:STRING=x86_64

libstdc++ vs libc++

Before OSX 10.9, the default was libstdc++.

With OSX 10.9 and above, the default is libc++.

Forcing the use of libstdc++ on newer version of OSX is still possible using the flag -stdlib=libstdc++. That said, doing so will report the following warning:

clang: warning: libstdc++ is deprecated; move to libc++
  • libstdc++:

    This is the GNU Standard C++ Library v3 aiming to implement the ISO 14882 Standard C++ library.

  • libc++:

    This is a new implementation of the C++ standard library, targeting C++11.

Windows

Microsoft C run-time and Visual Studio version

On windows, scikit-build looks for the version of Visual Studio matching the version of CPython being used. The selected Visual Studio version also defines which Microsoft C run-time and compiler are used:

Python version

3.7 and above

Microsoft C run-time

ucrtbase.dll

Compiler version

MSVC++ 14.0

Visual Studio version

2017

Installing compiler and Microsoft C run-time

As outlined above, installing a given version of Visual Studio will automatically install the corresponding compiler along with the Microsoft C run-time libraries.

This means that if you already have the corresponding version of Visual Studio installed, your environment is ready.

Nevertheless, since older version of Visual Studio are not available anymore, this next table references links for installing alternative environments:

Download links for Windows SDK and Visual Studio.

CPython version

Download links for Windows SDK or Visual Studio

3.7 and above

or

These links have been copied from the great article [2] of Steve Dower, engineer at Microsoft.

Footnotes

CMake modules

To facilitate the writing of CMakeLists.txt used to build CPython C/C++/Cython extensions, scikit-build provides the following CMake modules:

Cython

Find cython executable.

This module will set the following variables in your project:

CYTHON_EXECUTABLE

path to the cython program

CYTHON_VERSION

version of cython

CYTHON_FOUND

true if the program was found

For more information on the Cython project, see https://cython.org/.

Cython is a language that makes writing C extensions for the Python language as easy as Python itself.

The following functions are defined:

add_cython_target

Create a custom rule to generate the source code for a Python extension module using cython.

add_cython_target(<Name> [<CythonInput>]

[EMBED_MAIN] [C | CXX] [PY2 | PY3] [OUTPUT_VAR <OutputVar>])

<Name> is the name of the new target, and <CythonInput> is the path to a cython source file. Note that, despite the name, no new targets are created by this function. Instead, see OUTPUT_VAR for retrieving the path to the generated source for subsequent targets.

If only <Name> is provided, and it ends in the “.pyx” extension, then it is assumed to be the <CythonInput>. The name of the input without the extension is used as the target name. If only <Name> is provided, and it does not end in the “.pyx” extension, then the <CythonInput> is assumed to be <Name>.pyx.

The Cython include search path is amended with any entries found in the INCLUDE_DIRECTORIES property of the directory containing the <CythonInput> file. Use include_directories to add to the Cython include search path.

Options:

EMBED_MAIN

Embed a main() function in the generated output (for stand-alone applications that initialize their own Python runtime).

C | CXX

Force the generation of either a C or C++ file. By default, a C file is generated, unless the C language is not enabled for the project; in this case, a C++ file is generated by default.

PY2 | PY3

Force compilation using either Python-2 or Python-3 syntax and code semantics. By default, Python-2 syntax and semantics are used if the major version of Python found is 2. Otherwise, Python-3 syntax and semantics are used.

OUTPUT_VAR <OutputVar>

Set the variable <OutputVar> in the parent scope to the path to the generated source file. By default, <Name> is used as the output variable name.

Defined variables:

<OutputVar>

The path of the generated source file.

Cache variables that affect the behavior include:

CYTHON_ANNOTATE

Whether to create an annotated .html file when compiling.

CYTHON_FLAGS

Additional flags to pass to the Cython compiler.

Example usage

find_package(Cython)

# Note: In this case, either one of these arguments may be omitted; their
# value would have been inferred from that of the other.
add_cython_target(cy_code cy_code.pyx)

add_library(cy_code MODULE ${cy_code})
target_link_libraries(cy_code ...)

NumPy

Find the include directory for numpy/arrayobject.h as well as other NumPy tools like conv-template and from-template.

This module sets the following variables:

NumPy_FOUND

True if NumPy was found.

NumPy_INCLUDE_DIRS

The include directories needed to use NumpPy.

NumPy_VERSION

The version of NumPy found.

NumPy_CONV_TEMPLATE_EXECUTABLE

Path to conv-template executable.

NumPy_FROM_TEMPLATE_EXECUTABLE

Path to from-template executable.

The module will also explicitly define one cache variable:

NumPy_INCLUDE_DIR

Note

To support NumPy < v0.15.0 where from-template and conv-template are not declared as entry points, the module emulates the behavior of standalone executables by setting the corresponding variables with the path the the python interpreter and the path to the associated script. For example:

set(NumPy_CONV_TEMPLATE_EXECUTABLE /path/to/python /path/to/site-packages/numpy/distutils/conv_template.py CACHE STRING "Command executing conv-template program" FORCE)

set(NumPy_FROM_TEMPLATE_EXECUTABLE /path/to/python /path/to/site-packages/numpy/distutils/from_template.py CACHE STRING "Command executing from-template program" FORCE)

PythonExtensions

This module defines CMake functions to build Python extension modules and stand-alone executables.

The following variables are defined:

PYTHON_PREFIX                     - absolute path to the current Python
                                    distribution's prefix
PYTHON_SITE_PACKAGES_DIR          - absolute path to the current Python
                                    distribution's site-packages directory
PYTHON_RELATIVE_SITE_PACKAGES_DIR - path to the current Python
                                    distribution's site-packages directory
                                    relative to its prefix
PYTHON_SEPARATOR                  - separator string for file path
                                    components.  Equivalent to ``os.sep`` in
                                    Python.
PYTHON_PATH_SEPARATOR             - separator string for PATH-style
                                    environment variables.  Equivalent to
                                    ``os.pathsep`` in Python.
PYTHON_EXTENSION_MODULE_SUFFIX    - suffix of the compiled module. For example, on
                                    Linux, based on environment, it could be ``.cpython-35m-x86_64-linux-gnu.so``.

The following functions are defined:

python_extension_module

For libraries meant to be used as Python extension modules, either dynamically loaded or directly linked. Amend the configuration of the library target (created using add_library) with additional options needed to build and use the referenced library as a Python extension module.

python_extension_module(<Target>

[LINKED_MODULES_VAR <LinkedModVar>] [FORWARD_DECL_MODULES_VAR <ForwardDeclModVar>] [MODULE_SUFFIX <ModuleSuffix>])

Only extension modules that are configured to be built as MODULE libraries can be runtime-loaded through the standard Python import mechanism. All other modules can only be included in standalone applications that are written to expect their presence. In addition to being linked against the libraries for these modules, such applications must forward declare their entry points and initialize them prior to use. To generate these forward declarations and initializations, see python_modules_header.

If <Target> does not refer to a target, then it is assumed to refer to an extension module that is not linked at all, but compiled along with other source files directly into an executable. Adding these modules does not cause any library configuration modifications, and they are not added to the list of linked modules. They still must be forward declared and initialized, however, and so are added to the forward declared modules list.

If the associated target is of type MODULE_LIBRARY, the LINK_FLAGS target property is used to set symbol visibility and export only the module init function. This applies to GNU and MSVC compilers.

Options:

LINKED_MODULES_VAR <LinkedModVar>

Name of the variable referencing a list of extension modules whose libraries must be linked into the executables of any stand-alone applications that use them. By default, the global property PY_LINKED_MODULES_LIST is used.

FORWARD_DECL_MODULES_VAR <ForwardDeclModVar>

Name of the variable referencing a list of extension modules whose entry points must be forward declared and called by any stand-alone applications that use them. By default, the global property PY_FORWARD_DECL_MODULES_LIST is used.

MODULE_SUFFIX <ModuleSuffix>

Suffix appended to the python extension module file. The default suffix is retrieved using sysconfig.get_config_var("SO")", if not available, the default is then .so on unix and .pyd on windows. Setting the variable PYTHON_EXTENSION_MODULE_SUFFIX in the caller scope defines the value used for all extensions not having a suffix explicitly specified using MODULE_SUFFIX parameter.

python_standalone_executable

python_standalone_executable(<Target>)

For standalone executables that initialize their own Python runtime (such as when building source files that include one generated by Cython with the –embed option). Amend the configuration of the executable target (created using add_executable) with additional options needed to properly build the referenced executable.

python_modules_header

Generate a header file that contains the forward declarations and initialization routines for the given list of Python extension modules. <Name> is the logical name for the header file (no file extensions). <HeaderFilename> is the actual destination filename for the header file (e.g.: decl_modules.h).

python_modules_header(<Name> [HeaderFilename]

[FORWARD_DECL_MODULES_LIST <ForwardDeclModList>] [HEADER_OUTPUT_VAR <HeaderOutputVar>] [INCLUDE_DIR_OUTPUT_VAR <IncludeDirOutputVar>])

without the extension is used as the logical name. If only <Name> is

If only <Name> is provided, and it ends in the “.h” extension, then it is assumed to be the <HeaderFilename>. The filename of the header file provided, and it does not end in the “.h” extension, then the <HeaderFilename> is assumed to <Name>.h.

The exact contents of the generated header file depend on the logical <Name>. It should be set to a value that corresponds to the target application, or for the case of multiple applications, some identifier that conveyes its purpose. It is featured in the generated multiple inclusion guard as well as the names of the generated initialization routines.

The generated header file includes forward declarations for all listed modules, as well as implementations for the following class of routines:

int <Name>_<Module>(void)

Initializes the python extension module, <Module>. Returns an integer handle to the module.

void <Name>_LoadAllPythonModules(void)

Initializes all listed python extension modules.

void CMakeLoadAllPythonModules(void);

Alias for <Name>_LoadAllPythonModules whose name does not depend on <Name>. This function is excluded during preprocessing if the preprocessing macro EXCLUDE_LOAD_ALL_FUNCTION is defined.

void Py_Initialize_Wrapper();

Wrapper arpund Py_Initialize() that initializes all listed python extension modules. This function is excluded during preprocessing if the preprocessing macro EXCLUDE_PY_INIT_WRAPPER is defined. If this function is generated, then Py_Initialize() is redefined to a macro that calls this function.

Options:

FORWARD_DECL_MODULES_LIST <ForwardDeclModList>

List of extension modules for which to generate forward declarations of their entry points and their initializations. By default, the global property PY_FORWARD_DECL_MODULES_LIST is used.

HEADER_OUTPUT_VAR <HeaderOutputVar>

Name of the variable to set to the path to the generated header file. By default, <Name> is used.

INCLUDE_DIR_OUTPUT_VAR <IncludeDirOutputVar>

Name of the variable to set to the path to the directory containing the generated header file. By default, <Name>_INCLUDE_DIRS is used.

Defined variables:

<HeaderOutputVar>

The path to the generated header file

<IncludeDirOutputVar>

Directory containing the generated header file

Example usage

find_package(PythonExtensions)
find_package(Cython)
find_package(Boost COMPONENTS python)

# Simple Cython Module -- no executables
add_cython_target(_module.pyx)
add_library(_module MODULE ${_module})
python_extension_module(_module)

# Mix of Cython-generated code and C++ code using Boost Python
# Stand-alone executable -- no modules
include_directories(${Boost_INCLUDE_DIRS})
add_cython_target(main.pyx CXX EMBED_MAIN)
add_executable(main boost_python_module.cxx ${main})
target_link_libraries(main ${Boost_LIBRARIES})
python_standalone_executable(main)

# stand-alone executable with three extension modules:
# one statically linked, one dynamically linked, and one loaded at runtime
#
# Freely mixes Cython-generated code, code using Boost-Python, and
# hand-written code using the CPython API.

# module1 -- statically linked
add_cython_target(module1.pyx)
add_library(module1 STATIC ${module1})
python_extension_module(module1
                        LINKED_MODULES_VAR linked_module_list
                        FORWARD_DECL_MODULES_VAR fdecl_module_list)

# module2 -- dynamically linked
include_directories(${Boost_INCLUDE_DIRS})
add_library(module2 SHARED boost_module2.cxx)
target_link_libraries(module2 ${Boost_LIBRARIES})
python_extension_module(module2
                        LINKED_MODULES_VAR linked_module_list
                        FORWARD_DECL_MODULES_VAR fdecl_module_list)

# module3 -- loaded at runtime
add_cython_target(module3a.pyx)
add_library(module3 MODULE ${module3a} module3b.cxx)
target_link_libraries(module3 ${Boost_LIBRARIES})
python_extension_module(module3
                        LINKED_MODULES_VAR linked_module_list
                        FORWARD_DECL_MODULES_VAR fdecl_module_list)

# application executable -- generated header file + other source files
python_modules_header(modules
                      FORWARD_DECL_MODULES_LIST ${fdecl_module_list})
include_directories(${modules_INCLUDE_DIRS})

add_cython_target(mainA)
add_cython_target(mainC)
add_executable(main ${mainA} mainB.cxx ${mainC} mainD.c)

target_link_libraries(main ${linked_module_list} ${Boost_LIBRARIES})
python_standalone_executable(main)

The following functions are defined:

add_python_library

Add a library that contains a mix of C, C++, Fortran, Cython, F2PY, Template, and Tempita sources. The required targets are automatically generated to “lower” source files from their high-level representation to a file that the compiler can accept.

add_python_library(<Name>

SOURCES [source1 [source2 …]] [INCLUDE_DIRECTORIES [dir1 [dir2 …]] [LINK_LIBRARIES [lib1 [lib2 …]] [DEPENDS [source1 [source2 …]]])

Example usage

find_package(PythonExtensions)

file(GLOB arpack_sources ARPACK/SRC/*.f ARPACK/UTIL/*.f)

 add_python_library(arpack_scipy
   SOURCES ${arpack_sources}
           ${g77_wrapper_sources}
   INCLUDE_DIRECTORIES ARPACK/SRC
 )
add_python_extension

Add a extension that contains a mix of C, C++, Fortran, Cython, F2PY, Template, and Tempita sources. The required targets are automatically generated to “lower” source files from their high-level representation to a file that the compiler can accept.

add_python_extension(<Name>

SOURCES [source1 [source2 …]] [INCLUDE_DIRECTORIES [dir1 [dir2 …]] [LINK_LIBRARIES [lib1 [lib2 …]] [DEPENDS [source1 [source2 …]]])

Example usage

find_package(PythonExtensions)

file(GLOB arpack_sources ARPACK/SRC/*.f ARPACK/UTIL/*.f)

 add_python_extension(arpack_scipy
   SOURCES ${arpack_sources}
           ${g77_wrapper_sources}
   INCLUDE_DIRECTORIES ARPACK/SRC
 )

F2PY

The purpose of the F2PY –Fortran to Python interface generator– project is to provide a connection between Python and Fortran languages.

F2PY is a Python package (with a command line tool f2py and a module f2py2e) that facilitates creating/building Python C/API extension modules that make it possible to call Fortran 77/90/95 external subroutines and Fortran 90/95 module subroutines as well as C functions; to access Fortran 77 COMMON blocks and Fortran 90/95 module data, including allocatable arrays from Python.

For more information on the F2PY project, see http://www.f2py.com/.

The following variables are defined:

F2PY_EXECUTABLE      - absolute path to the F2PY executable
F2PY_VERSION_STRING  - the version of F2PY found
F2PY_VERSION_MAJOR   - the F2PY major version
F2PY_VERSION_MINOR   - the F2PY minor version
F2PY_VERSION_PATCH   - the F2PY patch version

Note

By default, the module finds the F2PY program associated with the installed NumPy package.

Example usage

Assuming that a package named method is declared in setup.py and that the corresponding directory containing __init__.py also exists, the following CMake code can be added to method/CMakeLists.txt to ensure the C sources associated with cylinder_methods.f90 are generated and the corresponding module is compiled:

find_package(F2PY REQUIRED)

set(f2py_module_name "_cylinder_methods")
set(fortran_src_file "${CMAKE_CURRENT_SOURCE_DIR}/cylinder_methods.f90")

set(generated_module_file ${CMAKE_CURRENT_BINARY_DIR}/${f2py_module_name}${PYTHON_EXTENSION_MODULE_SUFFIX})

add_custom_target(${f2py_module_name} ALL
  DEPENDS ${generated_module_file}
  )

add_custom_command(
  OUTPUT ${generated_module_file}
  COMMAND ${F2PY_EXECUTABLE}
    -m ${f2py_module_name}
    -c
    ${fortran_src_file}
  WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
  )

install(FILES ${generated_module_file} DESTINATION methods)

Warning

Using f2py with -c argument means that f2py is also responsible to build the module. In that case, CMake is not used to find the compiler and configure the associated build system.

The following functions are defined:

add_f2py_target

Create a custom rule to generate the source code for a Python extension module using f2py.

add_f2py_target(<Name> [<F2PYInput>]

[OUTPUT_VAR <OutputVar>])

<Name> is the name of the new target, and <F2PYInput> is the path to a pyf source file. Note that, despite the name, no new targets are created by this function. Instead, see OUTPUT_VAR for retrieving the path to the generated source for subsequent targets.

If only <Name> is provided, and it ends in the “.pyf” extension, then it is assumed to be the <F2PYInput>. The name of the input without the extension is used as the target name. If only <Name> is provided, and it does not end in the “.pyf” extension, then the <F2PYInput> is assumed to be <Name>.pyf.

Options:

OUTPUT_VAR <OutputVar>

Set the variable <OutputVar> in the parent scope to the path to the generated source file. By default, <Name> is used as the output variable name.

DEPENDS [source [source2...]]

Sources that must be generated before the F2PY command is run.

Defined variables:

<OutputVar>

The path of the generated source file.

Example usage

find_package(F2PY)

# Note: In this case, either one of these arguments may be omitted; their
# value would have been inferred from that of the other.
add_f2py_target(f2py_code f2py_code.pyf)

add_library(f2py_code MODULE ${f2py_code})
target_link_libraries(f2py_code ...)

They can be included using find_package:

find_package(Cython REQUIRED)
find_package(NumPy REQUIRED)
find_package(PythonExtensions REQUIRED)
find_package(F2PY REQUIRED)

For more details, see the respective documentation of each modules.

Contributing

Contributions are welcome, and they are greatly appreciated! Every little bit helps, and credit will always be given.

Types of Contributions

You can contribute in many ways:

Report Bugs

Report bugs at https://github.com/scikit-build/scikit-build/issues.

If you are reporting a bug, please include:

  • Your operating system name and version.

  • Any details about your local setup that might be helpful in troubleshooting.

  • Detailed steps to reproduce the bug.

Fix Bugs

Look through the GitHub issues for bugs. Anything tagged with “bug” is open to whoever wants to implement it.

Implement Features

Look through the GitHub issues for features. Anything tagged with “feature” is open to whoever wants to implement it.

Write Documentation

The scikit-build project could always use more documentation. We welcome help with the official scikit-build docs, in docstrings, or even on blog posts and articles for the web.

Submit Feedback

The best way to send feedback is to file an issue at https://github.com/scikit-build/scikit-build/issues.

If you are proposing a new feature:

  • Explain in detail how it would work.

  • Keep the scope as narrow as possible, to make it easier to implement.

  • Remember that this is a volunteer-driven project, and that contributions are welcome :)

Get Started

Ready to contribute? Here’s how to set up scikit-build for local development.

  1. Fork the scikit-build repo on GitHub.

  2. Clone your fork locally:

    $ git clone git@github.com:your_name_here/scikit-build.git
    

    You can use the gh command line application to do these last two steps, as well.

  3. Make sure you have nox installed using pipx install nox. If you don’t have pipx, you can install it with pip install pipx. (You can install nox with pip instead, but nox is an application, not a library, and applications should always use pipx.) You can install both of these packages from brew on macOS/linux. You can also use pipx run nox instead.

  4. Create a branch for local development:

    $ git checkout -b name-of-your-bugfix-or-feature
    

    Now you can make your changes locally.

  5. When you’re done making changes, check that your changes pass our linters and the tests:

    $ nox

    If you would like to check all Python versions and you don’t happen to have them all installed locally, you can use the manylinux docker image instead:

    $ docker run –rm -itv $PWD:/src -w /src quay.io/pypa/manylinux_2_24_x86_64:latest pipx run nox

  6. Commit your changes and push your branch to GitHub:

    $ git add -u .
    $ git commit -m "Your detailed description of your changes."
    $ git push origin name-of-your-bugfix-or-feature
    
  7. Submit a pull request through the GitHub website or the gh command line application.

Pull Request Guidelines

Before you submit a pull request, check that it meets these guidelines:

  1. The pull request should include tests.

  2. If the pull request adds functionality, the docs should be updated. Put your new functionality into a function with a docstring, and add the feature to the list in README.rst.

  3. The pull request should work for Python 3.7+ and PyPy. Make sure that the tests pass for all supported Python versions in CI on your PR.

Tips

To run a subset of tests:

$ nox -s tests -- tests/test_skbuild.py

You can build and serve the docs:

$ nox -s docs -- serve

You can build an SDist and a wheel in the dist folder:

$ nox -s build

Hacking

Controlling CMake using scikit-build

You can drive CMake directly using scikit-build:

""" Use scikit-build's `cmaker` to control CMake configuration and build.

1. Use `cmaker` to define an object that provides convenient access to
   CMake's configure and build functionality.

2. Use defined object, `maker`, to call `configure()` to read the
   `CMakeLists.txt` file in the current directory and generate a Makefile,
   Visual Studio solution, or whatever is appropriate for your platform.

3. Call `make()` on the object to execute the build with the
   appropriate build tool and perform installation to the local directory.
"""
from skbuild import cmaker
maker = cmaker.CMaker()

maker.configure()

maker.make()

See skbuild.cmaker.CMaker for more details.

Internal API

skbuild

skbuild package

scikit-build is an improved build system generator for CPython C extensions.

This module provides the glue between the setuptools Python module and CMake.

skbuild.setup(*, cmake_args: Sequence[str] = (), cmake_install_dir: str = '', cmake_source_dir: str = '', cmake_with_sdist: bool = False, cmake_languages: Sequence[str] = ('C', 'CXX'), cmake_minimum_required_version: str | None = None, cmake_process_manifest_hook: Callable[[list[str]], list[str]] | None = None, cmake_install_target: str = 'install', **kw: Any) Distribution[source]

This function wraps setup() so that we can run cmake, make, CMake build, then proceed as usual with setuptools, appending the CMake-generated output as necessary.

The CMake project is re-configured only if needed. This is achieved by (1) retrieving the environment mapping associated with the generator set in the CMakeCache.txt file, (2) saving the CMake configure arguments and version in skbuild.constants.CMAKE_SPEC_FILE(): and (3) re-configuring only if either the generator or the CMake specs change.

Subpackages
skbuild.command package

Collection of objects allowing to customize behavior of standard distutils and setuptools commands.

class skbuild.command.CommandMixinProtocol(*args, **kwargs)[source]

Bases: Protocol

Protocol for commands that use CMake.

build_base: str
distribution: Distribution
finalize_options(*args: object, **kwargs: object) None[source]
install_lib: str | None
install_platlib: str
outfiles: list[str]
class skbuild.command.set_build_base_mixin[source]

Bases: object

Mixin allowing to override distutils and setuptools commands.

finalize_options(*args: object, **kwargs: object) None[source]

Override built-in function and set a new build_base.

Submodules
skbuild.command.bdist module

This module defines custom implementation of bdist setuptools command.

class skbuild.command.bdist.bdist(dist)[source]

Bases: set_build_base_mixin, bdist

Custom implementation of bdist setuptools command.

skbuild.command.bdist_wheel module

This module defines custom implementation of bdist_wheel setuptools command.

class skbuild.command.bdist_wheel.bdist_wheel(dist, **kw)[source]

Bases: set_build_base_mixin, bdist_wheel

Custom implementation of bdist_wheel setuptools command.

run(*args: object, **kwargs: object) None[source]

Handle –hide-listing option.

write_wheelfile(wheelfile_base: str, _: None = None) None[source]

Write skbuild <version> as a wheel generator. See PEP-0427 for more details.

skbuild.command.build module

This module defines custom implementation of build setuptools command.

class skbuild.command.build.build(dist, **kw)[source]

Bases: set_build_base_mixin, build

Custom implementation of build setuptools command.

skbuild.command.build_ext module

This module defines custom implementation of build_ext setuptools command.

class skbuild.command.build_ext.build_ext(dist, **kw)[source]

Bases: set_build_base_mixin, build_ext

Custom implementation of build_ext setuptools command.

copy_extensions_to_source() None[source]

This function is only-called when doing inplace build.

It is customized to ensure the extensions compiled using distutils are copied back to the source tree instead of the skbuild.constants.CMAKE_INSTALL_DIR().

skbuild.command.build_py module

This module defines custom implementation of build_py setuptools command.

class skbuild.command.build_py.build_py(dist, **kw)[source]

Bases: set_build_base_mixin, build_py

Custom implementation of build_py setuptools command.

build_module(module: str | list[str] | tuple[str, ...], module_file: str, package: str) None[source]

Handle –hide-listing option.

Increments outfiles_count.

find_modules() list[tuple[str, str, str]][source]

Finds individually-specified Python modules, ie. those listed by module name in ‘self.py_modules’. Returns a list of tuples (package, module_base, filename): ‘package’ is a tuple of the path through package-space to the module; ‘module_base’ is the bare (no packages, no dots) module name, and ‘filename’ is the path to the “.py” file (relative to the distribution root) that implements the module.

initialize_options() None[source]

Handle –hide-listing option.

Initializes outfiles_count.

run(*args: object, **kwargs: object) None[source]

Handle –hide-listing option.

Display number of copied files. It corresponds to the value of outfiles_count.

skbuild.command.clean module

This module defines custom implementation of clean setuptools command.

class skbuild.command.clean.clean(dist, **kw)[source]

Bases: set_build_base_mixin, clean

Custom implementation of clean setuptools command.

run() None[source]

After calling the super class implementation, this function removes the directories specific to scikit-build.

skbuild.command.egg_info module

This module defines custom implementation of egg_info setuptools command.

class skbuild.command.egg_info.egg_info(dist, **kw)[source]

Bases: set_build_base_mixin, egg_info

Custom implementation of egg_info setuptools command.

finalize_options(*args: Any, **kwargs: Any) None[source]

Override built-in function and set a new build_base.

skbuild.command.generate_source_manifest module

This module defines custom generate_source_manifest setuptools command.

class skbuild.command.generate_source_manifest.generate_source_manifest(dist)[source]

Bases: set_build_base_mixin, Command

Custom setuptools command generating a MANIFEST file if not already provided.

description = 'generate source MANIFEST'
finalize_options(*args: object, **kwargs: object) None[source]

Set final values for all the options that this command supports.

initialize_options() None[source]

Set default values for all the options that this command supports.

run() None[source]

If neither a MANIFEST, nor a MANIFEST.in file is provided, and we are in a git repo, try to create a MANIFEST.in file from the output of git ls-tree –name-only -r HEAD.

We need a reliable way to tell if an existing MANIFEST file is one we’ve generated. distutils already uses a first-line comment to tell if the MANIFEST file was generated from MANIFEST.in, so we use a dummy file, _skbuild_MANIFEST, to avoid confusing distutils.

skbuild.command.install module

This module defines custom implementation of install setuptools command.

class skbuild.command.install.install(dist, **kw)[source]

Bases: set_build_base_mixin, install

Custom implementation of install setuptools command.

finalize_options(*args: Any, **kwargs: Any) None[source]

Ensure that if the distribution is non-pure, all modules are installed in self.install_platlib.

Note

setuptools.dist.Distribution.has_ext_modules() is overridden in setuptools_wrap.setup().

skbuild.command.install_lib module

This module defines custom implementation of install_lib setuptools command.

class skbuild.command.install_lib.install_lib(dist, **kw)[source]

Bases: set_build_base_mixin, install_lib

Custom implementation of install_lib setuptools command.

install() list[str][source]

Handle –hide-listing option.

skbuild.command.install_scripts module

This module defines custom implementation of install_scripts setuptools command.

class skbuild.command.install_scripts.install_scripts(dist, **kw)[source]

Bases: set_build_base_mixin, install_scripts

Custom implementation of install_scripts setuptools command.

run(*args: Any, **kwargs: Any) None[source]

Handle –hide-listing option.

skbuild.command.sdist module

This module defines custom implementation of sdist setuptools command.

class skbuild.command.sdist.sdist(dist, **kw)[source]

Bases: set_build_base_mixin, sdist

Custom implementation of sdist setuptools command.

make_archive(base_name: str, _format: str, root_dir: str | None = None, base_dir: str | None = None, owner: str | None = None, group: str | None = None) str[source]

Handle –hide-listing option.

make_release_tree(base_dir: str, files: Sequence[str]) None[source]

Handle –hide-listing option.

run(*args: object, **kwargs: object) None[source]

Force egg_info.egg_info command to run.

skbuild.command.test module
skbuild.platform_specifics package

This package provides get_platform() allowing to get an instance of abstract.CMakePlatform matching the current platform.

This folder contains files the define CMake’s defaults for given platforms. Any of them can be overridden by either command line or by environment variables.

class skbuild.platform_specifics.CMakeGenerator(name: str, env: Mapping[str, str] | None = None, toolset: str | None = None, arch: str | None = None, args: Iterable[str] | None = None)[source]

Bases: object

Represents a CMake generator.

__init__(name: str, env: Mapping[str, str] | None = None, toolset: str | None = None, arch: str | None = None, args: Iterable[str] | None = None) None[source]

Instantiate a generator object with the given name.

By default, os.environ is associated with the generator. Dictionary passed as env parameter will be merged with os.environ. If an environment variable is set in both os.environ and env, the variable in env is used.

Some CMake generators support a toolset specification to tell the native build system how to choose a compiler. You can also include CMake arguments.

property architecture: str | None

Architecture associated with the CMake generator.

property description: str

Name of CMake generator with properties describing the environment (e.g toolset)

property name: str

Name of CMake generator.

property toolset: str | None

Toolset specification associated with the CMake generator.

skbuild.platform_specifics.get_platform() CMakePlatform[source]

Return an instance of abstract.CMakePlatform corresponding to the current platform.

Submodules
skbuild.platform_specifics.abstract module

This module defines objects useful to discover which CMake generator is supported on the current platform.

class skbuild.platform_specifics.abstract.CMakeGenerator(name: str, env: Mapping[str, str] | None = None, toolset: str | None = None, arch: str | None = None, args: Iterable[str] | None = None)[source]

Bases: object

Represents a CMake generator.

__init__(name: str, env: Mapping[str, str] | None = None, toolset: str | None = None, arch: str | None = None, args: Iterable[str] | None = None) None[source]

Instantiate a generator object with the given name.

By default, os.environ is associated with the generator. Dictionary passed as env parameter will be merged with os.environ. If an environment variable is set in both os.environ and env, the variable in env is used.

Some CMake generators support a toolset specification to tell the native build system how to choose a compiler. You can also include CMake arguments.

property architecture: str | None

Architecture associated with the CMake generator.

property description: str

Name of CMake generator with properties describing the environment (e.g toolset)

property name: str

Name of CMake generator.

property toolset: str | None

Toolset specification associated with the CMake generator.

class skbuild.platform_specifics.abstract.CMakePlatform[source]

Bases: object

This class encapsulates the logic allowing to get the identifier of a working CMake generator.

Derived class should at least set default_generators.

static cleanup_test() None[source]

Delete test project directory.

static compile_test_cmakelist(cmake_exe_path: str, candidate_generators: Iterable[CMakeGenerator], cmake_args: Iterable[str] = ()) CMakeGenerator | None[source]

Attempt to configure the test project with each CMakeGenerator from candidate_generators.

Only cmake arguments starting with -DCMAKE_ are used to configure the test project.

The function returns the first generator allowing to successfully configure the test project using cmake_exe_path.

property default_generators: list[CMakeGenerator]

List of generators considered by get_best_generator().

property generator_installation_help: str

Return message guiding the user for installing a valid toolchain.

get_best_generator(generator_name: str | None = None, skip_generator_test: bool = False, languages: Iterable[str] = ('CXX', 'C'), cleanup: bool = True, cmake_executable: str = 'cmake', cmake_args: Iterable[str] = (), architecture: str | None = None) CMakeGenerator[source]

Loop over generators to find one that works by configuring and compiling a test project.

Parameters:
  • generator_name (str | None) – If provided, uses only provided generator, instead of trying default_generators.

  • skip_generator_test (bool) – If set to True and if a generator name is specified, the generator test is skipped. If no generator_name is specified and the option is set to True, the first available generator is used.

  • languages (tuple) – The languages you’ll need for your project, in terms that CMake recognizes.

  • cleanup (bool) – If True, cleans up temporary folder used to test generators. Set to False for debugging to see CMake’s output files.

  • cmake_executable (str) – Path to CMake executable used to configure and build the test project used to evaluate if a generator is working.

  • cmake_args (tuple) – List of CMake arguments to use when configuring the test project. Only arguments starting with -DCMAKE_ are used.

Returns:

CMake Generator object

Return type:

CMakeGenerator or None

Raises:

skbuild.exceptions.SKBuildGeneratorNotFoundError

get_generator(generator_name: str) CMakeGenerator[source]

Loop over generators and return the first that matches the given name.

get_generators(generator_name: str) list[CMakeGenerator][source]

Loop over generators and return all that match the given name.

static write_test_cmakelist(languages: Iterable[str]) None[source]

Write a minimal CMakeLists.txt useful to check if the requested languages are supported.

skbuild.platform_specifics.bsd module

This module defines object specific to BSD platform.

class skbuild.platform_specifics.bsd.BSDPlatform[source]

Bases: UnixPlatform

BSD implementation of abstract.CMakePlatform.

skbuild.platform_specifics.cygwin module

This module defines object specific to Cygwin platform.

class skbuild.platform_specifics.cygwin.CygwinPlatform[source]

Bases: CMakePlatform

Cygwin implementation of abstract.CMakePlatform.

property generator_installation_help: str

Return message guiding the user for installing a valid toolchain.

skbuild.platform_specifics.linux module

This module defines object specific to Linux platform.

class skbuild.platform_specifics.linux.LinuxPlatform[source]

Bases: UnixPlatform

Linux implementation of abstract.CMakePlatform

static build_essential_install_cmd() tuple[str, str][source]

Return a tuple of the form (distribution_name, cmd).

cmd is the command allowing to install the build tools in the current Linux distribution. It set to an empty string if the command is not known.

distribution_name is the name of the current distribution. It is set to an empty string if the distribution could not be determined.

property generator_installation_help: str

Return message guiding the user for installing a valid toolchain.

skbuild.platform_specifics.osx module

This module defines object specific to OSX platform.

class skbuild.platform_specifics.osx.OSXPlatform[source]

Bases: UnixPlatform

OSX implementation of abstract.CMakePlatform.

property generator_installation_help: str

Return message guiding the user for installing a valid toolchain.

skbuild.platform_specifics.aix module

This module defines object specific to AIX platform.

class skbuild.platform_specifics.aix.AIXPlatform[source]

Bases: UnixPlatform

AIX implementation of abstract.CMakePlatform.

property generator_installation_help: str

Return message guiding the user for installing a valid toolchain.

skbuild.platform_specifics.platform_factory module

This modules implements the logic allowing to instantiate the expected abstract.CMakePlatform.

skbuild.platform_specifics.platform_factory.get_platform() CMakePlatform[source]

Return an instance of abstract.CMakePlatform corresponding to the current platform.

skbuild.platform_specifics.unix module

This module defines object specific to Unix platform.

class skbuild.platform_specifics.unix.UnixPlatform[source]

Bases: CMakePlatform

Unix implementation of abstract.CMakePlatform.

skbuild.platform_specifics.windows module

This module defines object specific to Windows platform.

class skbuild.platform_specifics.windows.CMakeVisualStudioCommandLineGenerator(name: str, year: str, toolset: str | None = None, args: Iterable[str] | None = None)[source]

Bases: CMakeGenerator

Represents a command-line CMake generator initialized with a specific Visual Studio environment.

__init__(name: str, year: str, toolset: str | None = None, args: Iterable[str] | None = None)[source]

Instantiate CMake command-line generator.

The generator name can be values like Ninja, NMake Makefiles or NMake Makefiles JOM.

The year defines the Visual Studio environment associated with the generator. See VS_YEAR_TO_VERSION.

If set, the toolset defines the Visual Studio Toolset to select.

The platform (32-bit or 64-bit or ARM) is automatically selected.

class skbuild.platform_specifics.windows.CMakeVisualStudioIDEGenerator(year: str, toolset: str | None = None)[source]

Bases: CMakeGenerator

Represents a Visual Studio CMake generator.

__init__(year: str, toolset: str | None = None) None[source]

Instantiate a generator object with its name set to the Visual Studio generator associated with the given year (see VS_YEAR_TO_VERSION), the current platform (32-bit or 64-bit) and the selected toolset (if applicable).

class skbuild.platform_specifics.windows.CachedEnv[source]

Bases: TypedDict

Stored environment.

INCLUDE: str
LIB: str
PATH: str
skbuild.platform_specifics.windows.VS_YEAR_TO_VERSION = {'2017': 15, '2019': 16, '2022': 17}

Describes the version of Visual Studio supported by CMakeVisualStudioIDEGenerator and CMakeVisualStudioCommandLineGenerator.

The different version are identified by their year.

class skbuild.platform_specifics.windows.WindowsPlatform[source]

Bases: CMakePlatform

Windows implementation of abstract.CMakePlatform.

property generator_installation_help: str

Return message guiding the user for installing a valid toolchain.

skbuild.platform_specifics.windows.find_visual_studio(vs_version: int) str[source]

Return Visual Studio installation path associated with vs_version or an empty string if any.

The vs_version corresponds to the Visual Studio version to lookup. See VS_YEAR_TO_VERSION.

Note

  • Returns path based on the result of invoking vswhere.exe.

skbuild.utils package

This module defines functions generally useful in scikit-build.

class skbuild.utils.CommonLog(*args, **kwargs)[source]

Bases: Protocol

Protocol for loggers with an info method.

info(_CommonLog__msg: str, *args: object) None[source]
class skbuild.utils.Distribution(script_name: str)[source]

Bases: NamedTuple

Distribution stand-in.

script_name: str

Alias for field number 0

class skbuild.utils.PythonModuleFinder(packages: Sequence[str], package_dir: Mapping[str, str], py_modules: Sequence[str], alternative_build_base: str | None = None)[source]

Bases: build_py

Convenience class to search for python modules.

This class is based on distutils.command.build_py.build_by and provides a specialized version of find_all_modules().

check_module(module: str, module_file: str) bool[source]

Return True if module_file belongs to module.

distribution: Distribution
find_all_modules(project_dir: str | None = None) list[Any | tuple[str, str, str]][source]

Compute the list of all modules that would be built by project located in current directory, whether they are specified one-module-at-a-time py_modules or by whole packages packages.

By default, the function will search for modules in the current directory. Specifying project_dir parameter allow to change this.

Return a list of tuples (package, module, module_file).

find_package_modules(package: str, package_dir: str) Iterable[tuple[str, str, str]][source]

Temporally prepend the alternative_build_base to module_file. Doing so will ensure modules can also be found in other location (e.g skbuild.constants.CMAKE_INSTALL_DIR).

skbuild.utils.distribution_hide_listing(distribution: Distribution | Distribution) Iterator[bool | int][source]

Given a distribution, this context manager temporarily sets distutils threshold to WARN if --hide-listing argument was provided.

It yields True if --hide-listing argument was provided.

skbuild.utils.mkdir_p(path: str) None[source]

Ensure directory path exists. If needed, parent directories are created.

skbuild.utils.parse_manifestin(template: str) list[str][source]

This function parses template file (usually MANIFEST.in)

class skbuild.utils.push_dir(directory: str | None = None, make_directory: bool = False)[source]

Bases: ContextDecorator

Context manager to change current directory.

skbuild.utils.to_platform_path(path: OptStr) OptStr[source]

Return a version of path where all separator are os.sep

skbuild.utils.to_unix_path(path: OptStr) OptStr[source]

Return a version of path where all separator are /

Submodules
skbuild.cmaker module

This module provides an interface for invoking CMake executable.

class skbuild.cmaker.CMaker(cmake_executable: str = 'cmake')[source]

Bases: object

Interface to CMake executable.

Example:
>>> # Setup dummy repo
>>> from skbuild.cmaker import CMaker
>>> import ubelt as ub
>>> from os.path import join
>>> repo_dpath = ub.ensure_app_cache_dir('skbuild', 'test_cmaker')
>>> ub.delete(repo_dpath)
>>> src_dpath = ub.ensuredir(join(repo_dpath, 'SRC'))
>>> cmake_fpath = join(src_dpath, 'CMakeLists.txt')
>>> open(cmake_fpath, 'w').write(ub.codeblock(
        '''
        cmake_minimum_required(VERSION 3.5.0)
        project(foobar NONE)
        file(WRITE "${CMAKE_BINARY_DIR}/foo.txt" "# foo")
        install(FILES "${CMAKE_BINARY_DIR}/foo.txt" DESTINATION ".")
        install(CODE "message(STATUS \\"Project has been installed\\")")
        message(STATUS "CMAKE_SOURCE_DIR:${CMAKE_SOURCE_DIR}")
        message(STATUS "CMAKE_BINARY_DIR:${CMAKE_BINARY_DIR}")
        '''
>>> ))
>>> # create a cmaker instance in the dummy repo, configure, and make.
>>> from skbuild.utils import push_dir
>>> with push_dir(repo_dpath):
>>>     cmkr = CMaker()
>>>     config_kwargs = {'cmake_source_dir': str(src_dpath)}
>>>     print('--- test cmaker configure ---')
>>>     env = cmkr.configure(**config_kwargs)
>>>     print('--- test cmaker make ---')
>>>     cmkr.make(env=env)
static check_for_bad_installs() None[source]

This function tries to catch files that are meant to be installed outside the project root before they are actually installed.

Indeed, we can not wait for the manifest, so we try to extract the information (install destination) from the CMake build files *.cmake found in skbuild.constants.CMAKE_BUILD_DIR().

It raises skbuild.exceptions.SKBuildError if it found install destination outside of skbuild.constants.CMAKE_INSTALL_DIR().

configure(clargs: Sequence[str] = (), generator_name: str | None = None, skip_generator_test: bool = False, cmake_source_dir: str = '.', cmake_install_dir: str = '', languages: Sequence[str] = ('C', 'CXX'), cleanup: bool = True) dict[str, str][source]

Calls cmake to generate the Makefile/VS Solution/XCode project.

clargs: tuple

List of command line arguments to pass to cmake executable.

generator_name: string

The string representing the CMake generator to use. If None, uses defaults for your platform.

skip_generator_test: bool

If set to True and if a generator name is specified (either as a keyword argument or as clargs using -G <generator_name>), the generator test is skipped.

cmake_source_dir: string

Path to source tree containing a CMakeLists.txt

cmake_install_dir: string

Relative directory to append to skbuild.constants.CMAKE_INSTALL_DIR().

languages: tuple

List of languages required to configure the project and expected to be supported by the compiler. The language identifier that can be specified in the list corresponds to the one recognized by CMake.

cleanup: bool

If True, cleans up temporary folder used to test generators. Set to False for debugging to see CMake’s output files.

Return a mapping of the environment associated with the selected skbuild.platform_specifics.abstract.CMakeGenerator.

Mapping of the environment can also be later retrieved using get_cached_generator_env().

static get_cached(variable_name: str) str | None[source]

If set, returns the variable cached value from the skbuild.constants.CMAKE_BUILD_DIR(), otherwise returns None

get_cached_generator_env() dict[str, str] | None[source]

If any, return a mapping of environment associated with the cached generator.

classmethod get_cached_generator_name() str | None[source]

Reads and returns the cached generator from the skbuild.constants.CMAKE_BUILD_DIR():. Returns None if not found.

static get_python_include_dir(python_version: str) str | None[source]

Get include directory associated with the current python interpreter.

Args:

python_version (str): python version, may be partial.

Returns:

PathLike: python include dir

Example:
>>> # xdoc: +IGNORE_WANT
>>> from skbuild.cmaker import CMaker
>>> python_version = CMaker.get_python_version()
>>> python_include_dir = CMaker.get_python_include_dir(python_version)
>>> print('python_include_dir = {!r}'.format(python_include_dir))
python_include_dir = '.../conda/envs/py37/include/python3.7m'
static get_python_library(python_version: str) str | None[source]

Get path to the python library associated with the current python interpreter.

Args:

python_version (str): python version, may be partial.

Returns:

PathLike: python_library : python shared library

Example:
>>> # xdoc: +IGNORE_WANT
>>> from skbuild.cmaker import CMaker
>>> python_version = CMaker.get_python_version()
>>> python_library = CMaker.get_python_include_dir(python_version)
>>> print('python_library = {!r}'.format(python_library))
python_library = '.../conda/envs/py37/include/python3.7m'
static get_python_version() str[source]

Get version associated with the current python interpreter.

Returns:

str: python version string

Example:
>>> # xdoc: +IGNORE_WANT
>>> from skbuild.cmaker import CMaker
>>> python_version = CMaker.get_python_version()
>>> print('python_version = {!r}'.format(python_version))
python_version = '3.7'
install() list[str][source]

Returns a list of file paths to install via setuptools that is compatible with the data_files keyword argument.

make(clargs: Sequence[str] = (), config: str = 'Release', source_dir: str = '.', install_target: str = 'install', env: Mapping[str, str] | None = None) None[source]

Calls the system-specific make program to compile code.

install_target: string

Name of the target responsible to install the project. Default is “install”.

Note

To workaround CMake issue #8438. See https://gitlab.kitware.com/cmake/cmake/-/issues/8438 Due to a limitation of CMake preventing from adding a dependency on the “build-all” built-in target, we explicitly build the project first when the install target is different from the default on.

make_impl(clargs: list[str], config: str, source_dir: str, install_target: str | None, env: Mapping[str, str] | None = None) None[source]

Precondition: clargs does not have –config nor –install-target options. These command line arguments are extracted in the caller function make with clargs, config = pop_arg(’–config’, clargs, config)

This is a refactor effort for calling the function make twice in case the install_target is different than the default install.

skbuild.cmaker.get_cmake_version(cmake_executable: str = 'cmake') str[source]

Runs CMake and extracts associated version information. Raises skbuild.exceptions.SKBuildError if it failed to execute CMake.

Example:
>>> # xdoc: IGNORE_WANT
>>> from skbuild.cmaker import get_cmake_version
>>> print(get_cmake_version())
3.14.4
skbuild.cmaker.has_cmake_cache_arg(cmake_args: list[str], arg_name: str, arg_value: str | None = None) bool[source]

Return True if -D<arg_name>:TYPE=<arg_value> is found in cmake_args. If arg_value is None, return True only if -D<arg_name>: is found in the list.

skbuild.cmaker.pop_arg(arg: str, args: Sequence[str], default: None = None) tuple[list[str], str | None][source]
skbuild.cmaker.pop_arg(arg: str, args: Sequence[str], default: str) tuple[list[str], str]

Pops an argument arg from an argument list args and returns the new list and the value of the argument if present and a default otherwise.

skbuild.constants module

This module defines constants commonly used in scikit-build.

skbuild.constants.CMAKE_BUILD_DIR() str[source]

CMake build directory.

skbuild.constants.CMAKE_DEFAULT_EXECUTABLE = 'cmake'

Default path to CMake executable.

skbuild.constants.CMAKE_INSTALL_DIR() str[source]

CMake install directory.

skbuild.constants.CMAKE_SPEC_FILE() str[source]

CMake specification file storing CMake version, CMake configuration arguments and environment variables PYTHONNOUSERSITE and PYTHONPATH.

skbuild.constants.SETUPTOOLS_INSTALL_DIR() str[source]

Setuptools install directory.

skbuild.constants.SKBUILD_DIR() str[source]

Top-level directory where setuptools and CMake directories are generated.

skbuild.constants.SKBUILD_MARKER_FILE() str[source]

Marker file used by skbuild.command.generate_source_manifest.generate_source_manifest.run().

skbuild.constants.set_skbuild_plat_name(plat_name: str) None[source]

Set platform name associated with scikit-build functions returning a path:

skbuild.constants.skbuild_plat_name() str[source]

Get platform name formatted as <operating_system>[-<operating_system_version>]-<machine_architecture>.

Default value corresponds to _default_skbuild_plat_name() and can be overridden with set_skbuild_plat_name().

Examples of values are macosx-10.9-x86_64, linux-x86_64, linux-i686 or win-am64.

skbuild.exceptions module

This module defines exceptions commonly used in scikit-build.

exception skbuild.exceptions.SKBuildError[source]

Bases: RuntimeError

Exception raised when an error occurs while configuring or building a project.

exception skbuild.exceptions.SKBuildGeneratorNotFoundError[source]

Bases: SKBuildError

Exception raised when no suitable generator is found for the current platform.

exception skbuild.exceptions.SKBuildInvalidFileInstallationError[source]

Bases: SKBuildError

Exception raised when a file is being installed into an invalid location.

skbuild.setuptools_wrap module

This module provides functionality for wrapping key infrastructure components from distutils and setuptools.

skbuild.setuptools_wrap.create_skbuild_argparser() ArgumentParser[source]

Create and return a scikit-build argument parser.

skbuild.setuptools_wrap.get_default_include_package_data() bool[source]

Include package data if pyproject.toml contains the project or tool.setuptools table.

skbuild.setuptools_wrap.parse_args() tuple[list[str], str | None, bool, list[str], list[str]][source]

This function parses the command-line arguments sys.argv and returns the tuple (setuptools_args, cmake_executable, skip_generator_test, cmake_args, build_tool_args) where each *_args element corresponds to a set of arguments separated by --.

skbuild.setuptools_wrap.parse_skbuild_args(args: Sequence[str], cmake_args: Sequence[str], build_tool_args: Sequence[str]) tuple[list[str], str | None, bool, list[str], list[str]][source]

Parse arguments in the scikit-build argument set. Convert specified arguments to proper format and append to cmake_args and build_tool_args. Returns the tuple (remaining arguments, cmake executable, skip_generator_test).

skbuild.setuptools_wrap.setup(*, cmake_args: Sequence[str] = (), cmake_install_dir: str = '', cmake_source_dir: str = '', cmake_with_sdist: bool = False, cmake_languages: Sequence[str] = ('C', 'CXX'), cmake_minimum_required_version: str | None = None, cmake_process_manifest_hook: Callable[[list[str]], list[str]] | None = None, cmake_install_target: str = 'install', **kw: Any) Distribution[source]

This function wraps setup() so that we can run cmake, make, CMake build, then proceed as usual with setuptools, appending the CMake-generated output as necessary.

The CMake project is re-configured only if needed. This is achieved by (1) retrieving the environment mapping associated with the generator set in the CMakeCache.txt file, (2) saving the CMake configure arguments and version in skbuild.constants.CMAKE_SPEC_FILE(): and (3) re-configuring only if either the generator or the CMake specs change.

skbuild.setuptools_wrap.strip_package(package_parts: Sequence[str], module_file: str) str[source]

Given package_parts (e.g. ['foo', 'bar']) and a module_file (e.g. foo/bar/jaz/rock/roll.py), starting from the left, this function will strip the parts of the path matching the package parts and return a new string (e.g jaz/rock/roll.py).

The function will work as expected for either Windows or Unix-style module_file and this independently of the platform.

Internal CMake Modules

targetLinkLibrariesWithDynamicLookup

Public Functions

The following functions are defined:

target_link_libraries_with_dynamic_lookup(<Target> [<Libraries>])

Useful to “weakly” link a loadable module. For example, it should be used when compiling a loadable module when the symbols should be resolve from the run-time environment where the module is loaded, and not a specific system library.

Like proper linking, except that the given <Libraries> are not necessarily linked. Instead, the <Target> is produced in a manner that allows for symbols unresolved within it to be resolved at runtime, presumably by the given <Libraries>. If such a target can be produced, the provided <Libraries> are not actually linked.

It links a library to a target such that the symbols are resolved at run-time not link-time.

The linker is checked to see if it supports undefined symbols when linking a shared library. If it does then the library is not linked when specified with this function.

On platforms that do not support weak-linking, this function works just like target_link_libraries.

Note

For OSX it uses undefined dynamic_lookup. This is similar to using -shared on Linux where undefined symbols are ignored.

For more details, see blog from Tim D. Smith.

check_dynamic_lookup

Check if the linker requires a command line flag to allow leaving symbols unresolved when producing a target of type <TargetType> that is weakly-linked against a dependency of type <LibType>.

<TargetType>

can be one of “STATIC”, “SHARED”, “MODULE”, or “EXE”.

<LibType>

can be one of “STATIC”, “SHARED”, or “MODULE”.

Long signature:

check_dynamic_lookup(<TargetType>
                     <LibType>
                     <ResultVar>
                     [<LinkFlagsVar>])

Short signature:

check_dynamic_lookup(<ResultVar>) # <TargetType> set to "MODULE"
                                  # <LibType> set to "SHARED"

The result is cached between invocations and recomputed only when the value of CMake’s linker flag list changes; CMAKE_STATIC_LINKER_FLAGS if <TargetType> is “STATIC”, and CMAKE_SHARED_LINKER_FLAGS otherwise.

Defined variables:

<ResultVar>

Whether the current C toolchain supports weak-linking for target binaries of type <TargetType> that are weakly-linked against a dependency target of type <LibType>.

<LinkFlagsVar>

List of flags to add to the linker command to produce a working target binary of type <TargetType> that is weakly-linked against a dependency target of type <LibType>.

HAS_DYNAMIC_LOOKUP_<TargetType>_<LibType>

Cached, global alias for <ResultVar>

DYNAMIC_LOOKUP_FLAGS_<TargetType>_<LibType>

Cached, global alias for <LinkFlagsVar>

Private Functions

The following private functions are defined:

Warning

These functions are not part of the scikit-build API. They exist purely as an implementation detail and may change from version to version without notice, or even be removed.

We mean it.

_get_target_type
_get_target_type(<ResultVar> <Target>)

Shorthand for querying an abbreviated version of the target type of the given <Target>.

<ResultVar> is set to:

  • “STATIC” for a STATIC_LIBRARY,

  • “SHARED” for a SHARED_LIBRARY,

  • “MODULE” for a MODULE_LIBRARY,

  • and “EXE” for an EXECUTABLE.

Defined variables:

<ResultVar>

The abbreviated version of the <Target>’s type.

_test_weak_link_project(<TargetType>
                        <LibType>
                        <ResultVar>
                        <LinkFlagsVar>)

Attempt to compile and run a test project where a target of type <TargetType> is weakly-linked against a dependency of type <LibType>:

  • <TargetType> can be one of “STATIC”, “SHARED”, “MODULE”, or “EXE”.

  • <LibType> can be one of “STATIC”, “SHARED”, or “MODULE”.

Defined variables:

<ResultVar>

Whether the current C toolchain can produce a working target binary of type <TargetType> that is weakly-linked against a dependency target of type <LibType>.

<LinkFlagsVar>

List of flags to add to the linker command to produce a working target binary of type <TargetType> that is weakly-linked against a dependency target of type <LibType>.

Credits

Please see the GitHub project page at https://github.com/scikit-build/scikit-build/graphs/contributors

Release Notes

This is the list of changes to scikit-build between each release. For full details, see the commit logs at https://github.com/scikit-build/scikit-build

Next Release

We are hard at work on the next generation of scikit-build scikit-build-core, which will eventually replace the backend here. We are also continuing to fix bugs, make improvements, and backport changes here.

Scikit-build 0.17.6

A small fix release with some new platforms and better testing, including CPython 3.12.0b1.

Bug fixes

Testing

  • Tests now pass on CPython 3.12.0b1 in #879.

  • Tests no longer use pytest-virtualenv in #879.

  • isolated marker now includes test_distribution tests in #879.

  • Tests avoid incorrect get_map match by @keszybz in #990.

  • Fedora testing fix by @LecrisUT in #986 and #938.

Miscellaneous

  • Docs improvements in #979.

Scikit-build 0.17.5

A small fix release fixing the passing on of generator specific arguments. This fixes some cases where the Ninja generator was found but then was unable to build. NetBSD was reported to work, so was added to the BSD’s supported.

Bug fixes

  • Generator args were missing for actual compile in #975.

  • Add support for netbsd & pyodide (future) in #977.

Scikit-build 0.17.4

A followup fix to the issue 0.17.3 tried to fix. We now have a method to manually test downstream packages, too.

Bug fixes

  • Make sure include dir is found even if the lib is not present in #974.

Scikit-build 0.17.3

A small release related to PYTHON_LIBRARY handling changes in 0.17.2; scikit-build 0.17.3 returns an empty string from get_python_library if no Python library is present (like on manylinux), where 0.17.2 returned None, and previous versions returned a non-existent path. Note that adding REQUIRED to find_package(PythonLibs will fail, but it is incorrect (you must not link to libPython.so) and was really just injecting a non-existent path before.

Bug fixes

  • Keep get_python_library return type string if python lib non-existing for now in #959.

  • Avoid ‘not found’ warning if libs are not found by FindPythonExtensions in #960.

  • FindNumPy should not call FindPythonLibs in #958.

Scikit-build 0.17.2

Another small release with fixes for non-MSVC Windows platforms.

Bug fixes

  • RPM spec fix by @LecrisUT in #937.

  • Validate value before returning library path by @dlech in #942.

  • Only add Python_LIBRARY on Windows MSVC in #943 and #944.

  • Slightly nicer traceback for failed compiler in #947.

Testing

  • Hide a few warnings that are expected in #948.

Scikit-build 0.17.1

This is a small release fixing a few bugs; the primary one being a change that was triggering a bug in older FindPython. The unused variable messages have been deactivated to simplify output, as well.

Bug fixes

  • Older (<3.24) CMake breaks when lib specified in #932.

  • An error output was missing formatting in #931.

  • Make empty CMAKE_OSX_DEPLOYMENT_TARGET a warning (bug in conda-forge’s clang activation fixed upstream) in #934.

  • Remove unused variable warnings by in #930.

Testing

Scikit-build 0.17.0

A lot of bug fixes are present in this release, focusing on Windows, PyPy, and cross compiling. We’ve also improved the compatibility with default setuptools behaviors a little, and enabled some things that were previously unavailable, like overriding the build type via the cmake argument environment variables. We’ve expanded our CI matrix to include Windows and macOS PyPy and some Fortran tests on Linux. This release requires Python 3.7+.

Bug fixes

  • Match setuptools behavior for include_package_data default. by @vyasr in #873.

  • Misc. fixes for F2PY and PythonExtensions modules by @benbovy in #495.

  • Provide more useful error if user provides CMAKE_INSTALL_PREFIX by @vyasr in #872.

  • Stop assuming that .pyx files are in the same directory as CMakeLists.txt by @vyasr in #871.

  • Allow build type overriding in #902.

  • Detect PyPy library correctly on Windows by user:gershnik in #904.

  • Include library for FindPython for better Windows cross-compiles in #913. Thanks to user:maxbachmann for testing.

  • Fix logic for default generator when cross-compiling for ARM on Windows in #917 by @dlech.

  • Use f2py’s get_include if present in #877.

  • Fix support for cross-compilation exception using targetLinkLibrariesWithDynamicLookup by @erykoff in #901.

  • Treat empty MACOSX_DEPLOYMENT_TARGET as if it was unset in #918.

Testing

  • Add hello fortran sample package + tests by @benbovy in #493.

  • Add sdist check & fix in #906.

  • Fix some setuptools types in #888.

  • Add PyPy Win & macOS to the CI in #907.

  • Add tests for Python 3.12 Linux alphas in #922.

Miscellaneous

  • Drop Python 3.6 in #862.

  • Move building backend to hatchling in #870.

  • Avoid mutating function input parameters in #899.

  • Use _compat/typing name in #869.

Scikit-build 0.16.7

This is expected to be the final release series supporting Python 3.6. 0.17 will require Python 3.7+ and start removing deprecated functionality.

  • Added SKBUILD_GNU_SKIP_LOCAL_SYMBOL_EXPORT_OVERRIDE to disable script in #848, thanks to @aaron-bray and @vyasr.

  • Address a new warning from setuptools in our test suite in #859.

  • Move to using Ruff, update to Black 23, and use Flynt to move more code to f-strings.

Scikit-build 0.16.6

  • Fix a discovery regression in 0.16.5 when a cmake folder or cmake.py was present in #848.

  • Correct an issue in the tests where a generator wasn’t expanded into a list in #850.

Scikit-build 0.16.5

  • Use cmake module if installed over system installs in #839.

  • Support setting of -DCMAKE_SYSTEM_PROCESSOR if passed for selecting an arch, useful for cross compiling on conda-forge in #843.

  • Fixed a rare encoded error output string on Windows in #842.

  • Better granularity in extras in #838.

  • Add test markers for nosetuptoolsscm and isolated (helpful for package distributions building scikit-build itself like conda) in #837.

Scikit-build 0.16.4

This releases backports additions for Windows ARM cross-compiling via cibuildwheel from scikit-build-core 0.1.4.

  • Initial experimental support for Windows ARM cross-compile in #824 and #818

  • Replace mailing list with GitHub Discussions board in #823

  • Some CI updates in #811 and #812

Scikit-build 0.16.3

This release fixes logging issues using setuptools 65.6+ affecting our tests. Pytest 7.2+ is now supported. setup.py <command> and setup_requires are deprecated, and tests are marked as such.

  • Fix typo in usage.rst in #795, thanks to @chohner.

  • Support pytest 7.2+ in #801.

  • Change warning filtering in #802.

  • Handle logging changes in setuptools 65.6+ in #807.

  • Add deprecated markers to some tests in #807.

  • Allow known warnings to show up in the tests #807.

Scikit-build 0.16.2

This addresses one more small regression with the FindPython change from 0.16.0 that was affecting conda. #793.

Scikit-build 0.16.1

This was a quick patch release that fixed a missing Python requires setting and some missing files #790, and addressed a warning from setuptools in the tests.

Scikit-build 0.16.0

This release adds support for Python 3.11 and removes support for Python 2.7 and 3.5 (#688). Testing and static checking improved, including being fully statically typed internally (though setuptools is not fully typed, so it is of limited use).

All deprecated setuptools/distutils features are also deprecated in scikit-build, like the test command, easy_install, etc. Editable mode is still unsupported. Python 3.6 support is deprecated. Older versions of CMake (<3.15) are not recommended; a future version will remove support for older CMake’s (along with providing a better mechanism for ensuring a proper CMake is available). If you need any of these features, please open or find an issue explaining what and why you need something.

New Features

  • Cython module now supports FindPython mode. #743

  • PyPy is discovered without extra settings in FindPython mode #744

Bug fixes

  • FindPython mode uses a new path specification, should help make it usable. #774

  • Better flushing and output streams for more consistent output ordering. #781

Documentation

  • scikit-build mailing list transitioned to the scikit-build GitHub Discussions board. See #800. * Transitioning away from the mailing list and adopting the GitHub Discussions will provide a more integrated platform enabling us to more effectively engage with the community. * After sending a last message describing the transition, the mailing list was updated to be read-only and the welcome message was updated to redirect visitor toward the Discussions board.

Scikit-build 0.15.0

This release is the final (again) release for Python < 3.6 and MSVC<2017. Support for FindPython from CMake 3.12+ was added, including FindPython2. Support for Cygwin added.

New Features

Bug fixes

  • Fixed issue with distutils usage in Python 3.10. Thanks to @SuperSandro2000 for the contribution in #700.

Scikit-build 0.14.1

This release fixes a regression, and reverts a fix in 0.14.0. Some changes made to CI to fix recent removals.

Bug fixes

  • Fix issue with SKBUILD_CONFIGURE_OPTIONS not being read.

  • Reverted manifest install changes.

Scikit-build 0.14.0

This is the final release for Python < 3.6 and MSVC<2017.

New Features

  • Add support for --install-target scikit-build command line option. And cmake_install_target in setup.py. Allows providing an install target different than the default install. Thanks @phcerdan for the contribution. See #477.

Bug fixes

  • The manifest install location computation was fixed. Thanks @kratsg for the contribution in #682. (Reverted in 0.14.1)

  • Byte-compilation was skipped due to a missing return. Thanks @pekkarr in #678.

  • Packages can now be computed from the same shared collections, before this could confuse Scikit-build. Thanks @vyasr in #675.

  • Fixed library detection for PyPy 3.9. Thanks @rkaminsk in #673.

Internal

  • Scikit-build now uses pyproject.toml and setuptools_scm to build. If you are packaging scikit-build itself, you might need to update your requirements. See #634.

  • The codebase is now formatted with Black. #665

Scikit-build 0.13.1

This release fixes two bugs affecting Windows. Users should use "ninja; platform_system!='Windows", at least for now, since MSVC ships with Ninja, and that Ninja is better at finding the matching MSVC than the Python package is. Including it may slow down the search and force the IDE generator instead, but will at least no longer discover GCC instead.

Bug fixes

  • On Windows, don’t let Ninja find something other than what it’s supposed to look for. Ensure the Ninja package is used for the search, just like normal runs, if installed. #652.

  • Do not throw an error when printing info and a logger is disconnected. #652

Scikit-build 0.13.0

This is likely one of the final releases to support Python 2.7 and 3.5; future releases will likely target at least Python 3.6+ and MSCV 2017+.

If you are using scikit-build via pyproject.toml, please remember to include setuptools and wheel. A future version of scikit-build may remove the setuptools install-time hard requirement.

New Features

  • CMake module Cython now uses Cython default arguments. This no longer adds --no-docstrings in Release and MinSizeRel builds, so Cython docstrings are now retained by default. Additionally, --embed-positions is no longer added to Debug and RelWithDebInfo builds. Users can enable these and other Cython arguments via the option CYTHON_FLAGS. See #518 and #519, thanks to @bdice for the improvement.

  • Experimental support for ARM64 on Windows. Thanks to @gaborkertesz-linaro in #612.

  • Support for MSVC 2022. Thanks to @tttapa for the contribution in #627.

  • Support the modern form of target_link_libraries, via SKBUILD_LINK_LIBRARIES_KEYWORD (somewhat experimental). Thanks to @maxbachmann in #611.

Bug fixes

  • Update the Ninja path if using the ninja package. This fixes repeated isolated builds. Further path inspection and updates for isolated builds may be considered in the future. #631, thanks to @RUrlus and @segevfiner for help in tracking this down.

  • Allow OpenBSD to pass the platform check (untested). See #586.

  • Avoid forcing the min macOS version. Behaviour is now inline with setuptools. Users should set MACOSX_DEPLOYMENT_TARGET when building (automatic with cibuildwheel), otherwise you will get the same value Python was compiled with. Note: This may seem like a regression for PyPy until the next release (7.3.8), since it was compiled with 10.7, which is too old to build with on modern macOS - manually set MACOSX_DEPLOYMENT_TARGET (including setting it if unset in your setup.py) for PyPy until 7.3.8. #607

  • Fix logging issue when using Setuptools 60.2+. #623

  • MacOS cross compiling support fix (for conda-forge) for built-in modules. Thanks to @isuruf for the contribution in #622.

  • Better detection of the library path, fixes some issues with PyPy. Thanks to @rkaminsk for the contribution in #620 and #630. PyPy is now part of our testing matrix as of #624. Also @robtaylor in #632.

  • Fixed issue when cross-compiling on conda-forge (probably upstream bug, but easy to avoid). #646.

Scikit-build 0.12.0

The scikit-build GitHub organization welcomes @henryiii and @mayeut as core contributors and maintainers. Both are also maintainers of cibuildwheel.

@henryiii is a pybind11 and pypa/build maintainer, has been instrumental in adding Apple Silicon support, adding support for Visual Studio 2019, updating the Continuous Integration infrastructure, as well as helping review & integrate contributions, and addressing miscellaneous issues. Additionally, @henryiii has worked on an example project to build with pybind11 and scikit-build.

@mayeut is a manylinux maintainer and focused his effort on updating the cmake-python-distributions and ninja-python-distributions so that the corresponding wheels are available on all supported platforms including Apple Silicon and all flavors of manylinux.

New Features

  • Support Apple Silicon, including producing Universal2 wheels (#530) and respecting standard setuptools cross-compile variables (#555). Thanks to @YannickJadoul for the contributions.

  • Support MSVC 2019 without having to run it with the MSVC activation variables, just like 2017 and earlier versions. Thanks to @YannickJadoul for the contribution in #526.

Bug fixes

  • Support -A and -T internally when setting up MSVC generators. Architecture now always passed through -A to MSVC generators. Thanks @YannickJadoul for the contribution. See #557 and #536.

  • Fixed a regression that caused setuptools to complain about unknown setup option (cmake_process_manifest_hook). Thanks @Jmennius for the contribution. See #498.

  • If it applies, ensure generator toolset is used to configure the project. Thanks @YannickJadoul for the contributions. See #526.

  • Read CYTHON_FLAGS where needed, instead of once, allowing the user to define multiple modules with different flags. Thanks @oiffrig for the contributions in #536.

  • Avoid an IndexError if prefix was empty. Thanks @dfaure for the contributions in #522.

Documentation

Tests

  • Improve and simplify Continuous Integration infrastructure.

    • Support nox for running the tests locally. See #540.

    • Use GitHub Actions for Continuous Integration and remove use of scikit-ci, tox, TravisCI, AppVeyor and CircleCI. See #549, #551 and #552.

    • Add support for testing against Python 3.10. See #565.

    • Style checking handled by pre-commit. See #541.

    • Check for misspellings adding GitHub Actions workflow using codespell. See #541.

  • Fix linting error F522 reported with flake8 >= 3.8.x. Thanks @benbovy for the contributions. See #494.

  • Fix regex in tests to support Python 3.10. Thanks @mgorny for the contributions in #544.

Scikit-build 0.11.1

Bug fixes

Documentation

  • Fix link in Conda: Step-by-step release guide available in Making a release section.

Scikit-build 0.11.0

New Features

  • Add a hook to process the cmake install manifest building the wheel. The hook function can be specified as an argument to the setup() function. This can be used e.g. to prevent installing cmake configuration files, headers, or static libraries with the wheel. Thanks @SylvainCorlay for the contribution. See #473.

  • Add support for passing CMake configure options like -DFOO:STRING:bar as global setuptools or pip options.

  • Add support for building project using PyPy or PyPy3. See https://pypy.org See #407.

  • Add support for OS/400 (now known as IBM i). Thanks @jwoehr for the contribution. See #444.

  • Display CMake command used to configure the project. Thanks @native-api for the contribution. See #443.

  • CMake modules:

    • Improve CMake module F2PY adding add_f2py_target() CMake function allowing to generate *-f2pywrappers.f and *module.c files from *.pyf files. Thanks @xoviat for the contribution.

    • Update CMake module PythonExtensions adding add_python_library() and add_python_extension(). Thanks @xoviat for the contribution.

Bug fixes

  • Fix python 2.7 installation ensuring setuptools < 45 is required. See #478.

  • Fix unclosed file resource in skbuild.cmaker.CMaker.check_for_bad_installs(). Thanks @Nic30 for the suggestion. See #429.

  • Update CMake module PythonExtensions:

    • Ensure correct suffix is used for compiled python module on windows. See #383.

    • Fix warning using EXT_SUFFIX config variable instead of deprecated SO variable. See #381.

  • Honor the MACOSX_DEPLOYMENT_TARGET environment variable if it is defined on macOS. Thanks @certik for the contribution. See #441.

  • Fix CMake module F2PY to ensure the f2py executable specific to the python version being used is found. See #449. Thanks @bnavigator for the contribution.

  • Replace platform.linux_distribution() which was removed in Python 3.8 by a call to distro.id(). This adds the distro package as dependency. See #458. Thanks @bnavigator for the contribution.

Documentation

  • Add notes section to the For maintainers top-level category that includes a comparison between sysconfig and distutils.sysconfig modules.

  • Remove obsolete comment in cmaker.py. See #439. Thanks @isuruf

Tests

  • Update initialize_git_repo_and_commit to prevent signing message on system with commit signing enabled globally.

Scikit-build 0.10.0

New Features

  • Improve message displayed when discovering a working environment for building projects. For example, instead of displaying -- Trying "Ninja" generator, it now displays a message like -- Trying "Ninja (Visual Studio 15 2017 Win64 v140)" generator.

Bug fixes

  • Checking generator candidates can now handle handle paths and binaries with spaces, so that setup.py --cmake-executable "C:/Program Files (x86)/cmake/cmake.exe" works as expected. Contributed by @jokva. See #400.

  • Fix sdist command to ensure symlinks in original source tree are maintained. Contributed by @anibali. See #401.

  • Ensure use of bdist_egg or bdist_rpm commands trigger build using cmake.

  • Fix default value returned by skbuild.constants.skbuild_plat_name() on macOS. See #417.

Internal API

Documentation

Tests

  • Introduce check_sdist_content() and fix tests that are checking content of sdist to account for changes introduced in Python 3.8 and backported to python 2.7, 3.6 and 3.7. The changes introduced in python/cpython#9419 adds directory entries to ZIP files created by distutils. Thanks @anibali for the contribution. See #404.

  • Fix check_wheel_content() to consider changes in 0.33.1 < wheel.__version__ < 0.33.4 where directory entries are included when building wheel. See pypa/wheel#294 <https://github.com/pypa/wheel/issues/294>.

  • Fix reporting of AssertionError raised in check_wheel_content() function by relocating the source code into a dedicated module tests.pytest_helpers and by adding a conftest.py configuration file registering it for pytest assertion rewriting. See https://docs.pytest.org/en/latest/writing_plugins.html#assertion-rewriting and #403.

  • Fix test_generator_selection when building with “Visual C++ for Python 2.7” installed for all users. This addresses failure associated with win_c_compilervs2008cxx_compilervs2008python2.7 when running test in scikit-build-feedstock where “Visual C++ for Python 2.7” is installed using (vcpython27 chocolatey package.

  • Continuous Integration

    • Add support for Azure Pipelines for Python 3.7 32-bit and 64-bit

    • AppVeyor: Disable test for Python 3.7 32-bit and 64-bit.

    • CircleCI: Update version of docker images from jessie to stretch. This addresses issue circleci/circleci-images#370.

    • TravisCI: Remove obsolete Python 3.4 testing. It reached end-of-life on March 18 2019.

Scikit-build 0.9.0

New Features

  • Add support for building distutils based extensions associated with ext_modules setup keyword along side skbuild based extensions. This means using build_ext command (and associated --inplace argument) is supported. Thanks @Erotemic for the contribution. See #284.

Bug fixes

  • Fix build of wheels if path includes spaces. See issue #375. Thanks @padraic-padraic for the contribution.

  • Ensure wheel platform name is correctly set when providing custom CMAKE_OSX_DEPLOYMENT_TARGET and CMAKE_OSX_ARCHITECTURES values are provided. Thanks @nonhermitian for the contribution. See #377.

  • Fix testing with recent version of pytest by updating the pytest-runner requirements expression in setup.py. Thanks @mackelab for the contribution.

Scikit-build 0.8.1

Bug fixes

  • Fix bdist_wheel command to support wheel >= 0.32.0. Thanks @fbudin69500 for reporting issue #360.

Tests

  • Fix test_distribution.py updating use of Path.files() and requiring path.py>=11.5.0.

Scikit-build 0.8.0

New Features

  • Introduced skbuild.constants.CMAKE_DEFAULT_EXECUTABLE to facilitate distribution of scikit-build in package manager like Nixpkgs where all paths to dependencies are hardcoded. Suggested by @FRidh.

  • Setup keywords:

    • If not already set, zip_safe option is set to False. Suggested by @blowekamp.

  • Add support for --skip-generator-test when a generator is explicitly selected using --generator. This allows to speed up overall build when the build environment is known.

Bug fixes

  • Fix support for building project with CMake source directory outside of the setup.py directory. See #335 fixed by @massich.

  • Fix reading of .cmake files having any character not available in CP-1252 (the default code page on windows). See #334 fixed by @bgermann.

  • Fix parsing of macOS specific arguments like --plat-name macosx-X.Y-x86_64 and -DCMAKE_OSX_DEPLOYMENT_TARGET:STRING=X.Y and ensure that the ones specified as command line arguments override the default values or the one hard-coded in the cmake_args setup keyword. Thanks @yonip for the help addressing #342.

  • Support case where relative directory set in package_dir has an ending slash. For example, specifying package_dir={'awesome': 'src/awesome/'}, is now properly handled.

  • Fix support for isolated build environment ensuring the CMake project is reconfigured when pip install -e . is called multiple times. See #352.

Documentation

Tests

  • Add check_wheel_content utility function.

  • Skip test_setup_requires_keyword_include_cmake if running in conda test environment or if https://pypi.org is not reachable. Suggested by @Luthaf.

  • Continuous Integration

    • TravisCI:

      • Remove testing of linux now covered by CircleCI, add testing for Python 3.5, 3.6 and 3.7 on macOS.

      • Ensure system python uses latest version of pip

    • AppVeyor, CircleCI: Add testing for Python 3.7

    • Remove uses of unneeded $<RUN_ENV> command wrapper. scikit-build should already take care of setting up the expected environment.

    • Always install up-to-date scikit-ci and scikit-ci-addons.

    • Simplify release process managing versioning with python-versioneer and update Making a release documentation.

Scikit-build 0.7.1

Documentation

  • Fix description and classifier list in setup.py.

  • Fix link in README.

Scikit-build 0.7.0

New Features

  • Faster incremental build by re-configuring the project only if needed. This was achieved by (1) adding support to retrieve the environment mapping associated with the generator set in the CMakeCache.txt file, (2) introducing a CMake spec file storing the CMake version as well as the the CMake arguments and (3) re-configuring only if either the generator or the CMake specs change. Thanks @xoviat for the contribution. See #301.

  • CMake modules:

    • CMake module PythonExtensions: Set symbol visibility to export only the module init function. This applies to GNU and MSVC compilers. Thanks @xoviat. See #299.

    • Add CMake module F2PY useful to find the f2py executable for building Python extensions with Fortran. Thanks to @xoviat for moving forward with the integration. Concept for the module comes from the work of @scopatz done in PyNE project. See #273.

    • Update CMake module NumPy setting variables NumPy_CONV_TEMPLATE_EXECUTABLE and NumPy_FROM_TEMPLATE_EXECUTABLE. Thanks @xoviat for the contribution. See #278.

  • Setup keywords:

    • Add support for cmake_languages setup keyword.

    • Add support for include_package_data and exclude_package_data setup keywords as well as parsing of MANIFEST.in. See #315. Thanks @reiver-dev for reporting the issue.

    • Add support for cmake_minimum_required_version setup keyword. See #312. Suggested by @henryiii.

    • Install cmake if found in setup_requires list. See #313. Suggested by @henryiii.

  • Add support for --cmake-executable scikit-build command line option. Thanks @henryborchers for the suggestion. See #317.

  • Use _skbuild/platform-X.Y instead of _skbuild to build package. This allows to have a different build directory for each python version. Thanks @isuruf for the suggestion and @xoviat for contributing the feature. See #283.

  • Run cmake and develop command when command test is executed.

Bug fixes

  • Fix support of --hide-listing when building wheel.

  • CMake module Cython: Fix escaping of spaces associated with CYTHON_FLAGS when provided as command line arguments to the cython executable through CMake cache entries. See #265 fixed by @neok-m4700.

  • Ensure package data files specified in the setup() function using package_data keyword are packaged and installed.

  • Support specifying a default directory for all packages not already associated with one using syntax like package_dir={'':'src'} in setup.py. Thanks @benjaminjack for reporting the issue. See #274.

  • Improve --skip-cmake command line option support so that it can re-generate a source distribution or a python wheel without having to run cmake executable to re-configure and build. Thanks to @jonwoodring for reporting the issue on the mailing list.

  • Set skbuild <version> as wheel generator. See PEP-0427 and #191.

  • Ensure MANIFEST.in is considered when generating source distribution. Thanks @seanlis for reporting the problem and providing an initial patch, and thanks @henryiii for implementing the corresponding test. See #260.

  • Support generation of source distribution for git repository having submodules. This works only for version of git >= 2.11 supporting the --recurse-submodules option with ls-files command.

Internal API

Python Support

  • Tests using Python 3.3.x were removed and support for this version of python is not guaranteed anymore. Support was removed following the deprecation warnings reported by version 0.31.0 of wheel package, these were causing the tests test_source_distribution and test_wheel to fail.

Tests

  • Speedup execution of tests that do not require any CMake language enabled. This is achieved by (1) introducing the test project hello-no-language, (2) updating test utility functions execute_setup_py and project_setup_py_test to accept the optional parameter disable_languages_test allowing to skip unneeded compiler detection in test project used to verify that the selected CMake generator works as expected, and (3) updating relevant tests to use the new test project and parameters.

    Overall testing time on all continuous integration services was reduced:

    • AppVeyor:

      • from ~16 to ~7 minutes for 64 and 32-bit Python 2.7 tests done using Visual Studio Express 2008

      • from more than 2 hours to ~50 minutes for 64 and 32-bit Python 3.5 tests done using Visual Studio 2015. Improvement specific to Python 3.x were obtained by caching the results of slow calls to distutils.msvc9compiler.query_vcvarsall (for Python 3.3 and 3.4) and distutils._msvccompiler._get_vc_env (for Python 3.5 and above). These functions were called multiple times to create the list of skbuild.platform_specifics.windows.CMakeVisualStudioCommandLineGenerator used in skbuild.platform_specifics.windows.WindowsPlatform.

    • CircleCI: from ~7 to ~5 minutes.

    • TravisCI: from ~21 to ~10 minutes.

  • Update maximum line length specified in flake8 settings from 80 to 120 characters.

  • Add prepend_sys_path utility function.

  • Ensure that the project directory is prepended to sys.path when executing test building sample project with the help of execute_setup_py function.

  • Add codecov config file for better defaults and prevent associated Pull Request checks from reporting failure when coverage only slightly changes.

Documentation

Cleanups

  • Fix miscellaneous pylint warnings.

Scikit-build 0.6.1

Bug fixes

  • Ensure CMake arguments passed to scikit-build and starting with -DCMAKE_* are passed to the test project allowing to determine which generator to use. For example, this ensures that arguments like -DCMAKE_MAKE_PROGRAM:FILEPATH=/path/to/program are passed. See #256.

Documentation

  • Update Making a release section including instructions to update README.rst with up-to-date pypi download statistics based on Google big table.

Scikit-build 0.6.0

New features

  • Improve py_modules support: Python modules generated by CMake are now properly included in binary distribution.

  • Improve developer mode support for py_modules generated by CMake.

Bug fixes

  • Do not implicitly install python modules when the beginning of their name match a package explicitly listed. For example, if a project has a package foo/__init__.py and a module fooConfig.py, and only package foo was listed in setup.py, fooConfig.py is not installed anymore.

  • CMake module targetLinkLibrariesWithDynamicLookup: Fix the caching of dynamic lookup variables. See #240 fixed by @blowekamp.

Requirements

  • wheel: As suggested by @thewtex, unpinning version of the package by requiring >=0.29.0 instead of ==0.29.0 will avoid uninstalling a newer version of wheel package on up-to-date system.

Documentation

Tests

  • Extend test_hello, test_setup, and test_sdist_hide_listing to (1) check if python modules are packaged into source and wheel distributions and (2) check if python modules are copied into the source tree when developer mode is enabled.

Internal API

Scikit-build 0.5.1

Bug fixes

  • Ensure file copied in “develop” mode have “mode bits” maintained.

Scikit-build 0.5.0

New features

  • If available, uses Ninja build system generator on all platforms. An advantages is that ninja automatically parallelizes the build based on the number of CPUs.

  • Automatically set the expected Visual Studio environment when Ninja or NMake Makefiles generators are used.

  • Support Microsoft Visual C++ Compiler for Python 2.7. See #216.

  • Update long signature: <LinkFlagsVar> is now optional

  • Add support for short signature: check_dynamic_lookup(<ResultVar>). See SimpleITK/SimpleITK#80.

Bug fixes

  • Fix scikit-build source distribution and add test. See #214 Thanks @isuruf for reporting the issue.

  • Support building extension within a virtualenv on windows. See #119.

Documentation

  • hacking:

Requirements

  • setuptools: As suggested by @mivade in #212, remove the hard requirement for ==28.8.0 and require version >= 28.0.0. This allows to “play” nicely with conda where it is problematic to update the version of setuptools. See pypa/pip#2751 and ContinuumIO/anaconda-issues#542.

Tests

  • Improve “push_dir” tests to not rely on build directory name. Thanks @isuruf for reporting the issue.

  • travis/install_pyenv: Improve MacOSX build time updating scikit-ci-addons

  • Add get_cmakecache_variables utility function.

Internal API

Cleanups

  • appveyor.yml:

  • Remove unused “on_failure: event logging” and “notifications: GitHubPullRequest”

  • Remove unused SKIP env variable

Scikit-build 0.4.0

New features

  • Add support for --hide-listing option

  • allow to build distributions without displaying files being included

  • useful when building large project on Continuous Integration service limiting the amount of log produced by the build

  • CMake module: skbuild/resources/cmake/FindPythonExtensions.cmake

  • Function python_extension_module: add support for module suffix

Bug fixes

  • Do not package python modules under “purelib” dir in non-pure wheel

  • CMake module: skbuild/resources/cmake/targetLinkLibrariesWithDynamicLookup.cmake:

  • Fix the logic checking for cross-compilation (the regression was introduced by #51 and #47

  • It configure the text project setting CMAKE_ENABLE_EXPORTS to ON. Doing so ensure the executable compiled in the test exports symbols (if supported by the underlying platform)

Docs

Tests

  • tests/samples: Simplify project removing unneeded install rules and file copy

  • Simplify continuous integration

  • Makefile:

  • Fix coverage target

  • Add docs-only target allowing to regenerate the Sphinx documentation without opening a new page in the browser.

Scikit-build 0.3.0

New features

  • Improve support for “pure”, “CMake” and “hybrid” python package

  • a “pure” package is a python package that have all files living in the project source tree

  • an “hybrid” package is a python package that have some files living in the project source tree and some files installed by CMake

  • a “CMake” package is a python package that is fully generated and installed by CMake without any of his files existing in the source tree

  • Add support for source distribution. See #84

  • Add support for setup arguments specific to scikit-build:

  • cmake_args: additional option passed to CMake

  • cmake_install_dir: relative directory where the CMake project being built should be installed

  • cmake_source_dir: location of the CMake project

  • Add CMake module FindNumPy.cmake

  • Automatically set package_dir to reasonable defaults

  • Support building project without CMakeLists.txt

Bug fixes

  • Fix dispatch of arguments to setuptools, CMake and build tool. See #118

  • Force binary wheel generation. See #106

  • Fix support for py_modules (6716723)

  • Do not raise error if calling “clean” command twice

Documentation

Tests

  • Ensure each test run in a dedicated temporary directory

  • Add tests to raise coverage from 70% to 91%

  • Refactor CI testing infrastructure introducing CI drivers written in python for AppVeyor, CircleCI and TravisCI

  • Switch from nose to py.test

  • Relocate sample projects into a dedicated home: https://github.com/scikit-build/scikit-build-sample-projects

Cleanups

  • Refactor commands introducing set_build_base_mixin and new_style

  • Remove unused code

History

PyCMake was created at SciPy 2014 in response to general difficulties building C++ and Fortran based Python extensions across platforms. It was renamed to “scikit-build” in 2016.

Making a release

A core developer should use the following steps to create a release X.Y.Z of scikit-build on PyPI and Conda.

Prerequisites

Documentation conventions

The commands reported below should be evaluated in the same terminal session.

Commands to evaluate starts with a dollar sign. For example:

$ echo "Hello"
Hello

means that echo "Hello" should be copied and evaluated in the terminal.

Setting up environment

  1. First, register for an account on PyPI.

  2. If not already the case, ask to be added as a Package Index Maintainer.

  3. Create a ~/.pypirc file with your login credentials:

    [distutils]
    index-servers =
      pypi
      pypitest
    
    [pypi]
    username=<your-username>
    password=<your-password>
    
    [pypitest]
    repository=https://test.pypi.org/legacy/
    username=<your-username>
    password=<your-password>
    

where <your-username> and <your-password> correspond to your PyPI account.

PyPI: Step-by-step

  1. Make sure that all CI tests are passing on GitHub Actions and Azure Pipelines.

  2. Download the latest sources (or use an existing git checkout)

$ cd /tmp && \
  git clone git@github.com:scikit-build/scikit-build && \
  cd scikit-build
  1. List all tags sorted by creation date

$ git tag -l --sort creatordate
  1. Choose the next release version number

$ release=X.Y.Z

Warning

To ensure the packages are uploaded on PyPI, tags must match this regular expression: ^[0-9]+(\.[0-9]+)*(\.post[0-9]+)?$.

  1. In CHANGES.rst replace Next Release section header with Scikit-build X.Y.Z and commit the changes.

$ git add CHANGES.rst && \
  git commit -m "Scikit-build $release"
  1. Tag the release

$ git tag --sign -m "Scikit-build $release" $release main

Warning

We recommend using a GPG signing key to sign the tag.

  1. Publish both the release tag and the main branch

$ git push origin $release && \
  git push origin main
  1. Make a GitHub release. Paste the converted release notes as markdown; convert using

cat CHANGES.rst | pandoc -f rst -t gfm

and then edit the result (it will not be perfect) to prepare the body of the release. You can also try clipboardtomarkdown or copying to a draft discord post. PRs should be converted to simple #<number> form. Be sure to use the tag you just pushed as the tag version, and Scikit-build X.Y.Z should be the name.

Note

For examples of releases, see https://github.com/scikit-build/scikit-build/releases

  1. Add a Next Release section back in CHANGES.rst, commit and push local changes.

$ git add CHANGES.rst && \
  git commit -m "CHANGES.rst: Add \"Next Release\" section [ci skip]" && \
  git push origin main
  1. Add an entry to the Announcements category of the scikit-build discussions board.

Conda: Step-by-step

Warning

Publishing on conda requires to have corresponding the corresponding Github release.

After a GitHub release is created in the scikit-build project and after the conda-forge Autoticking Bot creates a pull request on the scikit-build-feedstock , follow these steps to finalize the conda package release:

  1. Review the pull-request

  2. Merge pull-request

In case the bot failed (e.g because of GH rate limitation) and in order to explicitly release a new version on conda-forge, follow the steps below:

  1. Choose the next release version number (that matches with the PyPI version last published)

$ release=X.Y.Z
  1. Fork scikit-build-feedstock

First step is to fork scikit-build-feedstock repository. This is the recommended best practice by conda.

  1. Clone forked feedstock

    Fill the YOURGITHUBUSER part.

    $ YOURGITHUBUSER=user
    $ cd /tmp && git clone https://github.com/$YOURGITHUBUSER/scikit-build-feedstock.git
    
  2. Download corresponding source for the release version

$ cd /tmp && \
  wget https://github.com/scikit-build/scikit-build/archive/$release.tar.gz
  1. Create a new branch

    $ cd scikit-build-feedstock && \
      git checkout -b $release
    
  2. Modify meta.yaml

    Update the version string and sha256.

    We have to modify the sha and the version string in the meta.yaml file.

    For linux flavors:

    $ sed -i "1s/.*/{% set version = \"$release\" %}/" recipe/meta.yaml && \
      sha=$(openssl sha256 /tmp/$release.tar.gz | awk '{print $2}') && \
      sed -i "2s/.*/{% set sha256 = \"$sha\" %}/" recipe/meta.yaml
    

    For macOS:

    $ sed -i -- "1s/.*/{% set version = \"$release\" %}/" recipe/meta.yaml && \
      sha=$(openssl sha256 /tmp/$release.tar.gz | awk '{print $2}') && \
      sed -i -- "2s/.*/{% set sha256 = \"$sha\" %}/" recipe/meta.yaml
    

    Commit local changes.

    $ git add recipe/meta.yaml && \
        git commit -m "scikit-build v$release version"
    
  3. Push the changes

    $ git push origin $release
    
  4. Create a Pull Request

    Create a pull request against the main repository. If the tests are passed a new release will be published on Anaconda cloud.

Indices and tables

Publications

Please use the first citation when referencing scikit-build in scientific publications.

  • Jean-Christophe Fillion-Robin, Matt McCormick, Omar Padron, Max Smolens, Michael Grauer, & Michael Sarahan. (2018, July 13). jcfr/scipy_2018_scikit-build_talk: SciPy 2018 Talk | scikit-build: A Build System Generator for CPython C/C++/Fortran/Cython Extensions. Zenodo. https://doi.org/10.5281/zenodo.2565368

  • Schreiner, Henry, Rickerby, Joe, Grosse-Kunstleve, Ralf, Jakob, Wenzel, Darbois, Matthieu, Gokaslan, Aaron, Fillion-Robin, Jean-Christophe, & McCormick, Matt. (2022, August 1). Building Binary Extensions with pybind11, scikit-build, and cibuildwheel. https://doi.org/10.25080/majora-212e5952-033

History

PyCMake was created at SciPy 2014 in response to general difficulties building C++ and Fortran based Python extensions across platforms. It was renamed to “scikit-build” in 2016. Scikit-build-core was started in 2022.

Known Issues

These issues are likely to be addressed in upcoming releases, and are already addressed in scikit-build-core.

  • Editable installs do not work with the latest versions of Setuptools (and had issues with older versions, too).

  • Configuration scikit-build cares about _must_ be specified in setup() currently.

  • The cache directory (_skbuild) may need to be deleted between builds in some cases (like rebuilding with a different Python interpreter).

  • AIX requires a newer version of CMake than the IBM-supplied CMake 3.22.0 from the AIX Toolbox for Open Source Software. We currently recommend building CMake from source on AIX.

We are also working on improving scikit-build, so there are some upcoming changes and deprecations:

  • All deprecated setuptools/distutils features are also deprecated in scikit-build, like the test command, easy_install, etc.

  • Older versions of CMake (<3.15) are not recommended; a future version will remove support for older CMake’s (along with providing a better mechanism for ensuring a proper CMake is available).

If you need any of these features, please open or find an issue explaining what and why you need something.

Miscellaneous

Support for this work was provided by NSF grant OAC-2209877.