This document describes the automated release pipeline for building and distributing NCNN binary packages and Python wheels across multiple platforms. The release process is triggered by pushing git tags and produces platform-specific native binaries (static libraries, frameworks, shared libraries) and Python wheels that are published to PyPI.
For information about the continuous integration and testing infrastructure, see CI/CD Pipeline. For details on building NCNN from source in development environments, see Platform Support and Build System.
The release pipeline activates automatically when a git tag is pushed to the repository. Two parallel workflows execute:
| Workflow | File | Purpose | Outputs |
|---|---|---|---|
release | .github/workflows/release.yml | Native binary packages | Static libraries, frameworks, ZIP archives |
release-python | .github/workflows/release-python.yml | Python distributions | Wheels (.whl), source distribution (.tar.gz) |
Both workflows use the tag name as the version string and extract it via GITHUB_REF environment variable parsing at .github/workflows/release.yml34
Workflow Dispatch: Both workflows also support manual triggering via workflow_dispatch event .github/workflows/release-python.yml6 allowing maintainers to create releases without pushing new tags.
Sources: .github/workflows/release.yml2-5 .github/workflows/release-python.yml2-6
The binary release workflow .github/workflows/release.yml orchestrates builds across 40+ job configurations spanning 15+ platform families. Each platform job produces a ZIP archive containing compiled libraries, headers, and for Linux/Windows builds, optionally tools like converters (onnx2ncnn, caffe2ncnn, mxnet2ncnn) built from tools/
Key Build Phases:
${GITHUB_REF/refs\/tags\//}20251004)actions/upload-artifact@v6 .github/workflows/release.yml51Sources: .github/workflows/release.yml23-35 .github/workflows/release.yml36-55 .github/workflows/release.yml56-94 .github/workflows/release.yml1-22
Each platform follows a common pattern:
lipo merges architectures on Apple platforms .github/workflows/release.yml156-159.framework bundles .github/workflows/release.yml251-263Sources: .github/workflows/release.yml56-94 .github/workflows/release.yml166-278
Apple platforms require custom OpenMP builds because system toolchains lack OpenMP support. The workflow builds OpenMP 18.1.2 from LLVM sources with platform-specific configurations:
Cache Strategy: The workflow uses actions/cache@v5 .github/workflows/release.yml113 with date-stamped keys (e.g., openmp-macos-release-18.1.2-20251004) to persist built OpenMP across workflow runs. Cache keys include the date 20251004 to allow periodic cache refreshes.
OpenMP CMake Configuration .github/workflows/release.yml99-109:
ios.toolchain.cmake .github/workflows/release.yml100 even for macOS to ensure consistent cross-compilation behaviorLIBOMP_ENABLE_SHARED=OFF produces static libomp.a for embedding in frameworksLIBOMP_OMPT_SUPPORT=OFF disables OpenMP Tools interface to reduce binary sizeLIBOMP_USE_HWLOC=OFF removes hardware topology detection dependencyPatches Applied .github/workflows/release.yml129-132:
ef8c35bcf5d9cfdb0764ffde6a63c04ec715bc37.patch - iOS compatibility fixes5c12711f9a21f41bea70566bf15a4026804d6b20.patch - Additional platform support patchesgithub.com/nihui/llvm-projectThe same pattern repeats for other Apple platforms (openmp-ios, openmp-ios-simulator, openmp-mac-catalyst, openmp-tvos, openmp-watchos, openmp-visionos) with platform-specific PLATFORM and ARCHS values .github/workflows/release.yml279-697
Sources: .github/workflows/release.yml95-164 .github/workflows/release.yml99-109 .github/workflows/release.yml111-116 .github/workflows/release.yml129-132 .github/workflows/release.yml279-337
macOS and iOS builds produce Apple Framework bundles instead of raw libraries. The packaging process at .github/workflows/release.yml218-263 creates standard framework directory structures:
ncnn.framework/
Versions/
A/
ncnn # Fat binary library (lipo merged)
Headers/ # Public headers from install/include
ncnn/*.h
Resources/
Info.plist # Framework metadata
Current -> A
ncnn -> Versions/Current/ncnn
Headers -> Versions/Current/Headers
Resources -> Versions/Current/Resources
The Info.plist is generated from a template .github/workflows/release.yml262 with substitutions:
__NAME__ → Framework name (ncnn, openmp, glslang)__IDENTIFIER__ → Bundle identifier (com.tencent.ncnn, org.llvm.openmp, org.khronos.glslang)__VERSION__ → Framework versionVulkan-enabled builds additionally package glslang.framework containing merged libglslang.a and libSPIRV.a .github/workflows/release.yml231-250
Sources: .github/workflows/release.yml218-277
The Python wheel pipeline uses pypa/[email protected] .github/workflows/release-python.yml90 to build wheels for CPython 3.8-3.14 and PyPy. The build process invokes CMake via setup.py which configures NCNN with -DNCNN_PYTHON=ON -DNCNN_VULKAN=ON setup.py98-99
Environment Variables .github/workflows/release-python.yml8-15:
Sources: .github/workflows/release-python.yml1-15 .github/workflows/release-python.yml16-42 .github/workflows/release-python.yml43-272 .github/workflows/release-python.yml273-316
The wheel build matrix at .github/workflows/release-python.yml46-66 defines 17 unique platform/architecture/build combinations:
| Platform | Architecture | Build Types | Line Reference |
|---|---|---|---|
| ubuntu-24.04 | x86_64 | manylinux, musllinux, pypy | 50-52 |
| ubuntu-24.04 | i686 | manylinux, musllinux, pypy | 53-55 |
| ubuntu-24.04-arm | armv7l | manylinux, musllinux | 62-63 |
| ubuntu-24.04-arm | aarch64 | manylinux, musllinux, pypy | 64-66 |
| windows-2025 | x86, AMD64 | CPython | 56-57 |
| windows-2025 | AMD64 | PyPy | 58 |
| windows-11-arm | ARM64 | CPython | 59 |
| macos-15-intel | x86_64 | CPython, PyPy | 60 |
| macos-15 | arm64 | CPython, PyPy | 61 |
RISC-V Special Case: RISC-V builds run in a separate matrix .github/workflows/release-python.yml273-316 using QEMU emulation because GitHub Actions lacks native RISC-V runners. The build explicitly disables XTheadVector extensions via EXTRA_CMAKE_ARGS="-DNCNN_XTHEADVECTOR=OFF" .github/workflows/release-python.yml300
Sources: .github/workflows/release-python.yml43-66 .github/workflows/release-python.yml273-316
cibuildwheel behavior is controlled via CIBW_* environment variables:
Linux Wheels .github/workflows/release-python.yml88-125:
CIBW_ARCHS_LINUX: ${{ matrix.arch }} selects x86_64, i686, armv7l, or aarch64CIBW_BUILD: ${{ matrix.build }} filters by pattern: cp*-manylinux*, cp*-musllinux*, or pp*CIBW_ENABLE: pypy .github/workflows/release-python.yml94 explicitly enables PyPy supportubuntu-24.04-arm runners use native compilation without emulationCIBW_ENVIRONMENT: CMAKE_BUILD_PARALLEL_LEVEL=4 CFLAGS="-mfpu=neon" CXXFLAGS="-mfpu=neon" .github/workflows/release-python.yml109-110Windows Wheels .github/workflows/release-python.yml127-154:
CIBW_BEFORE_BUILD: pip install delvewheel .github/workflows/release-python.yml137 installs Windows wheel repair toolCIBW_REPAIR_WHEEL_COMMAND: delvewheel repair -w {dest_dir} {wheel} .github/workflows/release-python.yml138 bundles dependent DLLs into wheelCIBW_REPAIR_WHEEL_COMMAND: delvewheel repair -w {dest_dir} {wheel} --no-dll "msvcp140.dll;vcomp140.dll" .github/workflows/release-python.yml152 to avoid bundling system runtime DLLsmacOS Wheels .github/workflows/release-python.yml156-257:
openmp-macos-install-20251004 .github/workflows/release-python.yml163 (shared with binary release workflow)CMAKE_TOOLCHAIN_FILE=$GITHUB_WORKSPACE/toolchains/ios.toolchain.cmake .github/workflows/release-python.yml230PLATFORM=MAC ARCHS="x86_64" or PLATFORM=MAC_ARM64 ARCHS="arm64" .github/workflows/release-python.yml230OpenMP_C_FLAGS="-Xclang -fopenmp" OpenMP_CXX_FLAGS="-Xclang -fopenmp" .github/workflows/release-python.yml232Vulkan_LIBRARY=$GITHUB_WORKSPACE/vulkansdk-macos-1.4.335.1/macOS/lib/libMoltenVK.dylib .github/workflows/release-python.yml235MACOSX_DEPLOYMENT_TARGET=$MAC_DEPLOYMENT_TARGET .github/workflows/release-python.yml236RISC-V QEMU Wheels .github/workflows/release-python.yml273-316:
riscv64 with Python versions cp38 through cp314 .github/workflows/release-python.yml281docker/setup-qemu-action@v3 .github/workflows/release-python.yml290 with platforms: allEXTRA_CMAKE_ARGS="-DNCNN_XTHEADVECTOR=OFF" .github/workflows/release-python.yml300 for compatibilitySources: .github/workflows/release-python.yml14 .github/workflows/release-python.yml88-257
The final upload_all job .github/workflows/release-python.yml318-334 collects all wheel and source distribution artifacts then publishes to PyPI:
actions/download-artifact@v7 with merge-multiple: true .github/workflows/release-python.yml326-329 consolidates all wheels into single directorypypa/gh-action-pypi-publish@release/v1 authenticates using ${{ secrets.PYPI_API_TOKEN }} .github/workflows/release-python.yml331-334Source Distribution: Built on ubuntu-latest via python -m build -s .github/workflows/release-python.yml33 validated with twine check dist/* .github/workflows/release-python.yml36
Sources: .github/workflows/release-python.yml17-41 .github/workflows/release-python.yml318-334
The root-level setup.py setup.py implements a custom CMakeBuild extension that invokes CMake during wheel building:
Version String Generation setup.py14-25:
NCNN_VERSION_MAJOR and NCNN_VERSION_MINOR from CMakeLists.txtMAJOR.MINOR.YYYYMMDD1.0.20240115 for version 1.0 built on January 15, 2024CMake Argument Construction setup.py93-133:
Vulkan_LIBRARY → -DVulkan_LIBRARY=...)EXTRA_CMAKE_ARGS allows passing arbitrary CMake flags setup.py41plat_name and map to CMake -A argument setup.py59-64Parallel Building setup.py159-168:
CMAKE_BUILD_PARALLEL_LEVEL environment variableself.parallel if set via -j flagos.cpu_count()Sources: setup.py1-229
The installed wheel uses a simpler setup.py.i template python/setup.py.i that doesn't compile code - it only packages pre-built binaries:
Variables like ${PACKAGE_VERSION} and ${PYTHON_MODULE_EXTENSION} are substituted during CMake configuration. This template enables creating binary wheels from already-compiled NCNN libraries.
Sources: python/setup.py.i1-54
The MANIFEST.in MANIFEST.in specifies source files included in the source distribution:
recursive-include cmake *
recursive-include glslang *
prune glslang/Test
recursive-include src *
recursive-include python *
prune python/pybind11/tests
include CMakeLists.txt
This ensures the sdist contains all necessary build infrastructure (CMake files, sources, glslang compiler) while excluding test files to reduce package size.
Sources: MANIFEST.in1-12
Release artifacts follow consistent naming patterns:
| Artifact Type | Pattern | Example |
|---|---|---|
| Source archive | ncnn-{VERSION}-full-source.zip | ncnn-20240101-full-source.zip |
| Linux static | ncnn-{VERSION}-ubuntu-{DISTRO} | ncnn-20240101-ubuntu-2404 |
| Linux shared | ncnn-{VERSION}-ubuntu-{DISTRO}-shared | ncnn-20240101-ubuntu-2404-shared |
| macOS framework | ncnn-{VERSION}-macos{-vulkan}.zip | ncnn-20240101-macos-vulkan.zip |
| iOS framework | ncnn-{VERSION}-ios{-vulkan}.zip | ncnn-20240101-ios-vulkan.zip |
| Android | ncnn-{VERSION}-android-{ABI} | ncnn-20240101-android-arm64-v8a |
| Windows | ncnn-{VERSION}-windows-vs{YEAR}-{ARCH} | ncnn-20240101-windows-vs2022-x64 |
Version extraction at .github/workflows/release.yml32-34:
Package names use PACKAGENAME environment variable: ncnn-${{ needs.setup.outputs.VERSION }}-{platform-specific-suffix} .github/workflows/release.yml67
Sources: .github/workflows/release.yml32-34 .github/workflows/release.yml40 .github/workflows/release.yml67
Python wheels follow PEP 427 naming: {distribution}-{version}-{python}-{abi}-{platform}.whl
cibuildwheel automatically generates appropriate names:
ncnn-{version}-cp{pyver}-cp{pyver}-manylinux_{glibc}_{arch}.whlncnn-{version}-cp{pyver}-cp{pyver}-musllinux_{musl}_{arch}.whlncnn-{version}-cp{pyver}-cp{pyver}-win_{arch}.whlncnn-{version}-cp{pyver}-cp{pyver}-macosx_{minver}_{arch}.whlExamples from typical build:
ncnn-1.0.20240115-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
ncnn-1.0.20240115-cp311-cp311-win_amd64.whl
ncnn-1.0.20240115-cp312-cp312-macosx_11_0_arm64.whl
Sources: .github/workflows/release-python.yml88-257
Binary Releases:
https://github.com/Tencent/ncnn/releases/tag/{VERSION}Python Wheels:
https://pypi.org/project/ncnn/pip install ncnnPYPI_API_TOKEN repository secret .github/workflows/release-python.yml334Sources: .github/workflows/release-python.yml331-334
Dependency Pinning:
18.1.2 .github/workflows/release.yml981.4.335.1 .github/workflows/release-python.yml217v3.3.1 .github/workflows/release-python.yml9016.4.0 .github/workflows/release.yml8Patches Applied:
ef8c35bcf5d9cfdb0764ffde6a63c04ec715bc37.patch .github/workflows/release.yml1295c12711f9a21f41bea70566bf15a4026804d6b20.patch .github/workflows/release.yml131Sources: .github/workflows/release.yml8-18 .github/workflows/release.yml98 .github/workflows/release-python.yml8-18
Refresh this wiki
This wiki was recently refreshed. Please wait 3 days to refresh again.