File: cmakelists.md

package info (click to toggle)
scikit-build-core 0.11.6-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 2,588 kB
  • sloc: python: 14,643; ansic: 254; cpp: 134; sh: 27; fortran: 18; makefile: 7
file content (174 lines) | stat: -rw-r--r-- 6,665 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
# Authoring your CMakeLists

Scikit-build-core provides a variety of useful variables for your CMakeLists.

## Detecting Scikit-build-core

You can write CMakeLists that support running inside and outside
scikit-build-core using the `${SKBUILD}` variable. This will be defined to "2"
for scikit-build-core (and "1" for classic scikit-build). You can also detect
the version of scikit-build-core with `${SKBUILD_CORE_VERSION}`.

## Accessing information

Scikit-build-core provides several useful variables:

- `${SKBUILD_PROJECT_NAME}`: The name of the project.
- `${SKBUILD_PROJECT_VERSION}`: The version of the project in a form CMake can
  use.
- `${SKBUILD_PROJECT_VERSION_FULL}`: The exact version of the project including
  dev & local suffix.
- `${SKBUILD_STATE}`: The run state, one of `sdist`, `wheel`, `metadata_wheel`,
  `editable`, or `metadata_editable`.

## Finding Python

You can directly use FindPython:

```cmake
find_package(Python COMPONENTS Interpreter Development.Module REQUIRED)
```

You always want to find at least `Interpreter` and the `Module` component of the
`Development` package. You do not want to find the entire `Development` package,
as that include `Embed` component, which is not always present and is not
related to making Python extension modules.

If you are making a Limited API / Stable ABI package, you'll need the
`Development.SABIModule` component instead (CMake 3.26+). You can use the
`SKBUILD_SABI_COMPONENT` variable to check to see if it was requested. You can
get the version requested with `${SKBUILD_SABI_VERSION}`.

<!-- prettier-ignore-start -->
:::{warning}
:name: soabi

If you want to cross-compile to Windows ARM, you'll need to use
`${SKBUILD_SOABI}`, which is always correct, instead of trusting FindPython's
`Python_SOABI` value. You can manually set the extension suffix after making a
target:

```cmake
if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
    set_property (TARGET ${name} PROPERTY SUFFIX ".${SKBUILD_SOABI}.pyd")
else()
    set_property (TARGET ${name} PROPERTY SUFFIX ".${SKBUILD_SOABI}${CMAKE_SHARED_MODULE_SUFFIX}")
endif()
```
<!-- prettier-ignore-end -->

A quicker way to do this would be to instead override `Python_SOABI` after
`find_package(Python)`:

```cmake
set(Python_SOABI ${SKBUILD_SOABI})
```

However, this isn't officially supported upstream, and only works due to the way
this variable is used when creating targets.

:::

If you want to use the old, deprecated FindPythonInterp and FindPythonLibs
instead, you can. Though it should be noted that FindPythonLibs requires a trick
to make it work properly if a Python library is not preset (like in manylinux):
you have to set `PYTHON_LIBRARY` to something (doesn't matter what) to make it
succeed.

## Finding other packages

Scikit-build-core includes various pythonic paths to the CMake search paths by
default so that usually you only need to include the dependent project inside
the `build-system.requires` section. Note that `cmake` and `ninja` should not be
included in that section.

See [search paths section](../configuration/search_paths.md) for more details on
how the search paths are constructed.

## Install directories

Scikit-build-core will install directly into platlib, which will end up in
site-packages. If you are used to scikit-build, you might find targeting
`/<module_name>` to be more natural. You can mimic the old behavior with a
configuration option (`wheel.install-dir`). However, scikit-build-core is more
powerful, and allows you to install multiple packages or top-level extension
modules if you need to.

You can access all of the possible output directories, regardless of
configuration, with the variables:

- `${SKBUILD_PLATLIB_DIR}`: The original platlib directory. Anything here goes
  directly to site-packages when a wheel is installed.
- `${SKBUILD_DATA_DIR}`: The data directory. Anything here goes to the root of
  the environment when a wheel is installed (use with care).
- `${SKBUILD_HEADERS_DIR}`: The header directory. Anything in here gets
  installed to Python's header directory.
- `${SKBUILD_SCRIPTS_DIR}`: The scripts directory. Anything placed in here will
  go to `bin` (Unix) or `Scripts` (Windows).
- `${SKBUILD_METADATA_DIR}`: The dist-info directory. Licenses go in the
  `licenses` subdirectory. _Note that CMake is not run in the
  `prepare_metadata_\*` hooks, so anything written to this directory will only
  be present when writing wheels.\_
- `${SKBUILD_NULL_DIR}`: Anything installed here will not be placed in the
  wheel.

## Limited API / Stable ABI

You can activate the Stable ABI by setting `tool.scikit-build.wheel.py-api`
equal to a valid CPython
[Python Tag](https://packaging.python.org/en/latest/specifications/platform-compatibility-tags/#python-tag)
in your `pyproject.toml`:

```toml
[tool.scikit-build]
wheel.py-api = "cp38"
```

When you do that, `${SKBUILD_SABI_COMPONENT}` will be set to
`Development.SABIModule` if you can target this (new enough CPython), and will
remain an empty string otherwise (PyPy). This allows the following idiom:

```cmake
find_package(Python REQUIRED COMPONENTS Interpreter Development.Module ${SKBUILD_SABI_COMPONENT})
```

This will require the `Development.SABIModule` component only if
scikit-build-core is driving the compilation and is targeting ABI3. If you want
to support Stable ABI from outside scikit-build-core, look into the
`OPTIONAL_COMPONENTS` flag for `find_package`.

When defining your module, if you only support the Stable ABI after some point,
you should use (for example for 3.11):

```cmake
if(NOT "${SKBUILD_SABI_VERSION}" STREQUAL "")
  python_add_library(some_ext MODULE WITH_SOABI USE_SABI ${SKBUILD_SABI_VERSION} ...)
else()
  python_add_library(some_ext MODULE WITH_SOABI ...)
endif()
```

If you have a lot of libraries, you can conditionally save these two items into
a variable with `set(USE_SABI USE_SABI ${SKBUILD_SABI_VERSION})` and use it in
all your `python_add_library` calls:

```
if(NOT "${SKBUILD_SABI_VERSION}" STREQUAL "")
  set(USE_SABI "USE_SABI ${SKBUILD_SABI_VERSION}")
endif()

python_add_library(some_ext MODULE WITH_SOABI ${USE_SABI} ...)
```

This will define `Py_LIMITED_API` for you. If you want to support building
directly from CMake, you need to protect this for Python version,
`Python_INTERPRETER_ID STREQUAL Python`, and free-threading Python 3.13+ doesn't
support ABI3 either.

If you are using `nanobind`'s `nanobind_add_module`, the `STABLE_ABI` flag does
this automatically for you for 3.12+.

## Future additions

Scikit-build-core does not include helpers for F2Py or Cython like scikit-build
classic yet. These will be carefully reimagined soon.