.. _build_system: Setting up a build system ========================= The recommended way to include the modified *asn1c* compiler into a Python package is by using a CMake-based build system. While it is possible to use other build systems, they are **not officially supported** and may require significant manual integration work. In this small tutorial, we will create a ``CMakeLists.txt``-based build system for a Python extension module, using `hatchling `_ as the project builder and `scikit-build-core `_ to integrate CMake into the Python packaging process. .. hint:: You may also want to take a look at the example module in the repository on GitHub that implements a basic extension and a submodule extension here: `example_mod `_ Overview -------- This build setup relies on several components working together: - **asn1cpython-support**: A Python package that provides helper utilities for ASN.1 compilation and integration. It offers a CLI interface to retrieve the installation path of the ``asn1c-bindings`` CMake configuration files. - **asn1c-bindings**: A CMake package that exports helper functions, including :cmake:command:`asn1c_add_extension()`, which generates ASN.1 C sources at configure time, compiles them into Python extension modules, copies stub files, and ensures correct installation paths. - **scikit-build-core** (or compatible PEP 517 build backend): Used as the Python build backend, facilitating CMake-driven builds integrated into standard Python packaging workflows. Prerequisites ------------- Before you begin, ensure the following: * **CMake** between **3.15** and **3.27** (inclusive). * The ASN.1 compiler toolchain (``asn1c``) is installed and accessible via your system PATH, or configured via environment variables or CMake defines such as ``A1C_PATH``. * Python **3.8** or newer. * A working installation of ``pip`` and ``hatch``. Project Structure Example ------------------------- A minimal project might look like this: .. code-block:: example-mod/ ├── CMakeLists.txt ├── example.asn ├── src/ │ ├── example_mod/ # Python sources go here │ └── generated/ # Populated by the ASN.1 compiler at configure time ├── pyproject.toml └── README.md In this example: * ``example.asn`` is your ASN.1 schema. * ``src/generated`` will hold generated C and Python files during the configure step. * ``CMakeLists.txt`` defines how to build your extension. * ``pyproject.toml`` configures the Python overall project. CMake Setup ----------- CMake is a cross-platform build system that uses ``CMakeLists.txt`` files to define build rules. In our case, we need a total of three steps to create a new extension: 1. Finding the CMake package ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The ``asn1cpython-support`` package includes a helper command that tells CMake where the ``asn1c-bindings`` package is installed. The following snippet can be used to insert the required package into the search path of CMake: .. code-block:: cmake # Retrieve the path to asn1c-bindings CMake package via the Python helper execute_process( COMMAND "${Python_EXECUTABLE}" -m asn1cpython_support --cmake-dir OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE asn1c-bindings_ROOT ) # Load the asn1c-bindings CMake package find_package(asn1c-bindings CONFIG REQUIRED) .. note:: You must list ``asn1cpython-support`` in the ``[build-system] requires`` section of your ``pyproject.toml``, otherwise CMake will not be able to find the helper. For instance: .. code-block:: toml [build-system] # just add the python package as a build dependency requires = ["hatchling", "scikit-build-core~=0.9.0", "asn1cpython-support"] 2. Adding a new extension ~~~~~~~~~~~~~~~~~~~~~~~~~ The :cmake:command:`asn1c_add_extension()` function declares a Python extension module that will be generated and compiled automatically. This call performs multiple actions, which include running the ``asn1c`` compiler at configure time to generate C and Python interface files, adds them to a new Python extension and ensures the generated ``.pyi`` type stub file is renamed and installed correctly. .. code-block:: cmake # Add an ASN.1 extension module. asn1c_add_extension( NAME _example_mod ASN_FILES ${CMAKE_CURRENT_SOURCE_DIR}/example.asn ) Python Packaging Integration ---------------------------- When using ``scikit-build-core`` together with *hatchling*, your ``pyproject.toml`` could look like this: .. code-block:: toml :caption: pyproject.toml [build-system] requires = ["hatchling", "scikit-build-core~=0.9.0", "asn1cpython-support"] build-backend = "hatchling.build" [project] name = "example-mod" version = "1.0.0" description = "Example Python extension built from ASN.1" readme = "README.md" dependencies = ["bitarray"] # Needed for BIT STRING type [tool.hatch.build.targets.wheel.hooks.scikit-build] experimental = true # Optional: define custom compiler or skeleton paths # [tool.scikit-build.cmake.define] # A1C_PATH = "path/to/custom/asn1c" # A1C_SKELETONS_PATH = "path/to/skeletons" This configuration allows you to build your package with: .. code-block:: bash pip install . # or hatch build