Skip to content

Commit

Permalink
[Docs] document build hooks
Browse files Browse the repository at this point in the history
  • Loading branch information
tttapa committed Mar 24, 2024
1 parent fbf878b commit f25a9b1
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 7 deletions.
1 change: 1 addition & 0 deletions docs/Config.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ Defines how to perform an editable install (PEP 660). See https://tttapa.github.
| Option | Description | Type | Default |
|--------|-------------|------|---------|
| `mode` | Mechanism to use for editable installations. Either write a wrapper \_\_init\_\_.py file, install an import hook, or install symlinks to the original files. | `'wrapper'` \| `'hook'` \| `'symlink'` | `'symlink'` |
| `build_hook` | Automatically re-build any changed files and C extension modules when the package is first imported by Python. It is recommended to use a fast generator like Ninja. Currently, the only mode that supports build hooks is `symlink`. | bool | `false` |

## sdist
Specifies the files that should be included in the source distribution for this package.
Expand Down
57 changes: 53 additions & 4 deletions docs/Editable-install.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,22 @@ Alternatively, you can add it to your local configuration,
mode = "hook"
```

> **Note**: only Python files are made “editable”. You'll still have to run
> `pip install -e .` again to rebuild your C extension modules if you
> modify any C/C++/Fortran source files.
> **Note**: by default, only Python files are made “editable”. You'll still have
> to run `pip install -e .` again to rebuild your C extension modules
> if you modify any C/C++/Fortran source files.
> To automatically rebuild C extension modules, set
> `editable.mode = "symlink"` and `editable.build_hook = true` in the
> [configuration](Config.html).
> See the [Build hooks](#build-hooks) section below for details.
The following sections go into the details of the different modes.
```toml
[tool.py-build-cmake.editable]
mode = "symlink"
build_hook = true
```

The following sections go into the details of the different editable
installation modes.

## Wrapper

Expand Down Expand Up @@ -209,6 +220,44 @@ The Wheel package format does not support symbolic links, so only a `.pth` file
is included in the Wheel, and the actual files and symlinks are copied to a
hidden folder in the project's source directory, [as proposed by PEP 660](https://peps.python.org/pep-0660/#what-to-put-in-the-wheel).

# Build hooks

During development, py-build-cmake can be configured to automatically recompile
any C extension modules that changed. This is done by setting the
`editable.build_hook` option to `true`. Under the hood, this will cause a hook
to be installed in the [meta path](https://docs.python.org/3/reference/import.html#import-hooks),
which will invoke `cmake --build` and `cmake --install` when your package is
first imported.

Modern build systems like Ninja are very fast at figuring out whether anything
has to be recompiled, so the overhead of this hook is relatively low when no
files changed.

Keep in mind that C extension modules cannot be unloaded or reloaded after they
have been imported once. You need to restart the Python interpreter for any
changes to take effect. This is why the build is only carried out during the
first import (and before the module is first loaded).

To avoid depending on packages in Pip's temporary build directory or virtual
environment, you can use the `--no-build-isolation` flag:

```sh
pip install -e . --no-build-isolation
```

This requires you to install any dependencies into your environment beforehand.

The only mode that is currently supported is `symlink`. This is because
`symlink` mode installs the extension modules into a hidden folder inside of the
project folder, whereas the `hook` and `wrapper` modes include the extension
modules in the package. In such a case, the build hook would have to install its
artifacts into the Python site-packages directory directly. This comes with the
risk of installing files that were not included in the original package's RECORD
(e.g. if the user modifies any CMake code or options), and these files would not
be cleaned up when uninstalling the package. Files left behind by old packages
could cause all kinds of issues that are hard to debug, so py-build-cmake simply
does not allow this.

---

<small>
Expand Down
8 changes: 5 additions & 3 deletions src/py_build_cmake/config/options/pyproject_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,11 @@ def get_options(project_path: Path, *, test: bool = False):
default=DefaultValueValue("symlink"),
options=["wrapper", "hook", "symlink"]),
BoolConfigOption("build_hook",
"Automatically re-build any changed files when the "
"package is first imported. It is recommended to use "
"a fast generator like Ninja.",
"Automatically re-build any changed files and C "
"extension modules when the package is first "
"imported by Python. It is recommended to use a fast "
"generator like Ninja. Currently, the only "
"mode that supports build hooks is `symlink`.",
default=DefaultValueValue(False)),
]) # fmt: skip

Expand Down

0 comments on commit f25a9b1

Please sign in to comment.