Skip to content

Commit

Permalink
docs: c++ package example (#2717)
Browse files Browse the repository at this point in the history
Co-authored-by: Hofer-Julian <30049909+Hofer-Julian@users.noreply.github.com>
  • Loading branch information
tdejager and Hofer-Julian authored Dec 17, 2024
1 parent 6fbe854 commit e391f44
Show file tree
Hide file tree
Showing 10 changed files with 380 additions and 22 deletions.
97 changes: 97 additions & 0 deletions docs/build/cpp_package.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
# Tutorial: Building a C++ package

This example shows how to build a C++ project with CMake and use it together with `pixi-build`.
To read more about how building packages work with pixi see the [Getting Started](./getting_started.md) guide.

We'll start off by creating a project that use [nanobind](https://github.com/wjakob/nanobind) to build Python bindings.
That we can also test using pixi.
We'll later combine this example together with a Python package.

## Creating a new project

To get started, create a new project with pixi:

```bash
pixi init python_bindings
```

This should give you the basic `pixi.toml` to get started.

We'll now create the following source directory structure:
```bash
python_bindings/
├── CMakeLists.txt
├── pixi.toml
├── .gitignore
└── src
└── bindings.cpp
```

## Creating the project files
Next up we'll create the:

- `pixi.toml` file that will be used to configure pixi.
- `CMakeLists.txt` file that will be used to build the bindings.
- `src/bindings.cpp` file that will contain the bindings.

### The `pixi.toml` file
Use the following `pixi.toml` file, you can hover over the annotations to see why each step was added.

```toml
--8<-- "docs/source_files/pixi_projects/pixi_build_cpp/pixi.toml"
```

1. Add the **preview** feature `pixi-build` that enables pixi to build the package.
2. These are the workspace dependencies, and we add a reference to our own package.
3. Let's add a task that will run our test, for this we require a python interpreter.
4. This is where we specify the package name and version.
This section denotes that there is both a workspace and a package defined by this `pixi.toml` file.
5. We use `pixi-build-cmake` as the build-system, so that we get the backend to build cmake packages.
6. We use the [nanobind](https://github.com/wjakob/nanobind) package to build our bindings.
7. We need python to build the bindings, so we add a host dependency on the `python_abi` package.
8. We override the cmake version to ensure it matches our `CMakeLists.txt` file.

### The `CMakeLists.txt` file

Next lets add the `CMakeList.txt` file:
```CMake
--8<-- "docs/source_files/pixi_projects/pixi_build_cpp/CMakeLists.txt"
```

1. Find `python`, this actually finds anything above 3.8, but we are using 3.8 as a minimum version.
2. Because we are using `python` in a conda environment we need to query the python interpreter to find the `nanobind` package.
3. Because we want to make the installation directory independent of the python version, we query the python `site-packages` directory.
4. Find the installed nanobind package.
5. Use our bindings file as the source file.
6. Install the bindings into the designated prefix.

### The `src/bindings.cpp` file

Next lets add the `src/bindings.cpp` file, this one is quite simple:

```cpp
--8<-- "docs/source_files/pixi_projects/pixi_build_cpp/src/bindings.cpp"
```

1. We define a function that will be used to add two numbers together.
2. We bind this function to the python module using the `nanobind` package.

## Testing if everything works
Now that we have created the files we can test if everything works:

```bash
$ pixi run start
3
```

This command builds the bindings, installs them and then runs the `test` task.

## Conclusion

In this tutorial, we created a pixi package using C++.
It can be used as-is, to upload to a conda channel.
In another tutorial we will learn how to add multiple pixi packages to the same workspace and let one pixi package use another.

Thanks for reading! Happy Coding 🚀

Any questions? Feel free to reach out or share this tutorial on [X](https://twitter.com/prefix_dev), [join our Discord](https://discord.gg/kKV8ZxyzY4), [e-mail](mailto:hi@prefix.dev) us or follow our [GitHub](https://github.com/prefix-dev).
25 changes: 21 additions & 4 deletions docs/build/getting_started.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,30 @@ The vision is to enable building of packages from source, for any language, on a
4. Workspace dependencies cannot be inherited.

## Setting up the Manifest


```toml
--8<-- "docs/source_files/pixi_tomls/simple_pixi_build.toml:full"
```

Since the build feature is still in preview, you have to add "pixi-build" to `workspace.preview`.

```toml
--8<-- "docs/source_files/pixi_tomls/simple_pixi_build.toml:preview"
```

In `package` you specify properties specific to the package you want to build.

```toml
--8<-- "docs/source_files/pixi_tomls/simple_pixi_build.toml:package"
```

Packages are built by using build backends.
By specifying `package.build-system.build-backend` and `package.build-system.channels` you determine which backend is used and from which channel it will be downloaded.
In this example, we are using `pixi-build-python` in order to build a Python package.
If the package itself has dependencies they need to be mentioned here.
The different kinds of dependencies are explained at the [dependency types chapter](dependency_types.md).

This is what the `pixi.toml` file looks like for a simple Python package:
```toml
--8<-- "docs/source_files/pixi_tomls/simple_pixi_build.toml:all"
--8<-- "docs/source_files/pixi_tomls/simple_pixi_build.toml:build-system"
```

1. Specifies workspace properties like the name, channels, and platforms. This is currently an alias for `project`.
Expand Down
27 changes: 27 additions & 0 deletions docs/source_files/pixi_projects/pixi_build_cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
cmake_minimum_required(VERSION 3.20...3.27)
project(python_bindings)

find_package(Python 3.8 COMPONENTS Interpreter Development.Module REQUIRED) # (1)!

execute_process(
COMMAND "${Python_EXECUTABLE}" -m nanobind --cmake_dir
OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE nanobind_ROOT
) # (2)!

execute_process(
COMMAND ${Python_EXECUTABLE} -c "import sysconfig; print(sysconfig.get_path('purelib'))"
OUTPUT_VARIABLE PYTHON_SITE_PACKAGES
OUTPUT_STRIP_TRAILING_WHITESPACE
) # (3)!

find_package(nanobind CONFIG REQUIRED) # (4)!

nanobind_add_module(${PROJECT_NAME} src/bindings.cpp) # (5)!

install( # (6)!
TARGETS ${PROJECT_NAME}
EXPORT ${PROJECT_NAME}Targets
LIBRARY DESTINATION ${PYTHON_SITE_PACKAGES}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${BINDIR}
)
168 changes: 168 additions & 0 deletions docs/source_files/pixi_projects/pixi_build_cpp/pixi.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

27 changes: 27 additions & 0 deletions docs/source_files/pixi_projects/pixi_build_cpp/pixi.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
[workspace]
channels = ["https://prefix.dev/conda-forge"]
platforms = ["osx-arm64", "linux-64", "win-64"]
preview = ["pixi-build"] # (1)!

[dependencies] # (2)!
python = ">=3.12, <3.13"
python_bindings = { path = "." }

[tasks]
start = "python -c 'import python_bindings as b; print(b.add(1, 2))'" # (3)!

[package] # (4)!
name = "python_bindings"
version = "0.1.0"

[build-system]
build-backend = { name = "pixi-build-cmake", version = "*" } # (5)!
channels = [
"https://prefix.dev/pixi-build-backends",
"https://prefix.dev/conda-forge",
]

[host-dependencies]
cmake = ">=3.20, <3.27" # (8)!
nanobind = ">=2.4.0, <2.5.0" # (6)!
python_abi = ">=3.12, <3.13" # (7)!
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#include <nanobind/nanobind.h>

int add(int a, int b) { return a + b; } // (1)!

NB_MODULE(python_bindings, m)
{
m.def("add", &add); // (2)!
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit e391f44

Please sign in to comment.