Using GitHub Action to Build Python Wheel Package for Dynamsoft Barcode Reader

Requirements

Dynamsoft C/C++ Barcode SDK v9.0

Building CPython Extension Project with Scikit-build

If you have read Python development guide, you may know that distutils.core.Extension is the most widely used Python extension builder. However, distutils cannot sequentially build the extension and package the generated library with the package folder when running the pip wheel command for creating a wheel package.

from skbuild import setup
import io

packages = ['barcodeQrSDK']

setup (name = 'barcode-qr-code-sdk',
version = '9.0.3',
description = 'Barcode and QR code scanning SDK for Python',
packages=packages,
include_package_data=False,
)
cmake_minimum_required(VERSION 3.4...3.22)

project(barcodeQrSDK)

find_package(PythonExtensions REQUIRED)

if(CMAKE_HOST_UNIX)
if(CMAKE_HOST_APPLE)
SET(CMAKE_CXX_FLAGS "-std=c++11 -O3 -Wl,-rpath,@loader_path")
SET(CMAKE_INSTALL_RPATH "@loader_path")
else()
SET(CMAKE_CXX_FLAGS "-std=c++11 -O3 -Wl,-rpath=$ORIGIN")
SET(CMAKE_INSTALL_RPATH "$ORIGIN")
endif()
SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
endif()

MESSAGE( STATUS "CPU architecture ${CMAKE_SYSTEM_PROCESSOR}" )
if(CMAKE_HOST_WIN32)
link_directories("${PROJECT_SOURCE_DIR}/lib/win/")
elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
if (CMAKE_SYSTEM_PROCESSOR STREQUAL x86_64)
MESSAGE( STATUS "Link directory: ${PROJECT_SOURCE_DIR}/lib/linux/" )
link_directories("${PROJECT_SOURCE_DIR}/lib/linux/")
elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL armv7l)
MESSAGE( STATUS "Link directory: ${PROJECT_SOURCE_DIR}/lib/arm32/" )
link_directories("${PROJECT_SOURCE_DIR}/lib/arm32/")
elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL aarch64)
MESSAGE( STATUS "Link directory: ${PROJECT_SOURCE_DIR}/lib/aarch64/" )
link_directories("${PROJECT_SOURCE_DIR}/lib/aarch64/")
endif()
elseif(CMAKE_HOST_APPLE)
MESSAGE( STATUS "Link directory: ${PROJECT_SOURCE_DIR}/lib/macos/" )
link_directories("${PROJECT_SOURCE_DIR}/lib/macos/")
endif()
include_directories("${PROJECT_BINARY_DIR}" "${PROJECT_SOURCE_DIR}/include/")

add_library(${PROJECT_NAME} MODULE src/barcodeQrSDK.cpp)
if(CMAKE_HOST_WIN32)
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
target_link_libraries (${PROJECT_NAME} "DynamsoftBarcodeReaderx64")
else()
target_link_libraries (${PROJECT_NAME} "DBRx64")
endif()
else()
target_link_libraries (${PROJECT_NAME} "DynamsoftBarcodeReader" pthread)
endif()

if(CMAKE_HOST_WIN32)
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
"${PROJECT_SOURCE_DIR}/lib/win/"
$<TARGET_FILE_DIR:${PROJECT_NAME}>)
endif()

python_extension_module(barcodeQrSDK)
install(TARGETS barcodeQrSDK LIBRARY DESTINATION barcodeQrSDK)

if(CMAKE_HOST_WIN32)
install (DIRECTORY "${PROJECT_SOURCE_DIR}/lib/win/" DESTINATION barcodeQrSDK)
elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
if (CMAKE_SYSTEM_PROCESSOR STREQUAL x86_64)
install (DIRECTORY "${PROJECT_SOURCE_DIR}/lib/linux/" DESTINATION barcodeQrSDK)
elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL armv7l OR ARM32_BUILD)
install (DIRECTORY "${PROJECT_SOURCE_DIR}/lib/arm32/" DESTINATION barcodeQrSDK)
elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL aarch64)
install (DIRECTORY "${PROJECT_SOURCE_DIR}/lib/aarch64/" DESTINATION barcodeQrSDK)
endif()
elseif(CMAKE_HOST_APPLE)
install (DIRECTORY "${PROJECT_SOURCE_DIR}/lib/macos/" DESTINATION barcodeQrSDK)
endif()
  1. Set build arguments. The rpath is critical for finding dependent shared libraries on Linux and macOS.
  2. Set the directories of header files and libraries.
  3. Build the extension module.
  4. Link external dynamic libraries.
  5. Copy the Python module and dependent libraries to the barcodeQrSDK package folder.
from .barcodeQrSDK import * 
__version__ = version
pip wheel .

Creating Multiple Wheel Packages with GitHub Actions

As we have mentioned above, it drives us crazy to create multiple wheel packages for each version of Python and different platforms. Fortunately, GitHub Actions can relieve us a lot of work.

  1. Go to the repository homepage and click Actions to create a new workflow.
  2. Click set up a workflow yourself to create a custom workflow. We can refer to the examples provided by cibuildwheel.
name: Build and upload to PyPI

on: [push, pull_request]

jobs:
build_wheels:
name: Build wheels on $
runs-on: $
strategy:
matrix:
os: [windows-2019, macos-10.15]

steps:
- uses: actions/checkout@v2

- name: Build wheels
uses: pypa/cibuildwheel@v2.5.0
env:
CIBW_ARCHS_WINDOWS: AMD64
CIBW_ARCHS_MACOS: x86_64
CIBW_ARCHS_LINUX: "x86_64 aarch64"
CIBW_SKIP: "pp* *-win32 *-manylinux_i686"

- uses: actions/upload-artifact@v2
with:
path: ./wheelhouse/*.whl

build_sdist:
name: Build source distribution
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2

- name: Build sdist
run: pipx run build --sdist

- uses: actions/upload-artifact@v2
with:
path: dist/*.tar.gz

upload_pypi:
needs: [build_wheels, build_sdist]
runs-on: ubuntu-latest
# upload to PyPI on every tag starting with 'v'
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
# alternatively, to publish when a GitHub Release is created, use the following rule:
# if: github.event_name == 'release' && github.event.action == 'published'
steps:
- uses: actions/download-artifact@v2
with:
name: artifact
path: dist

- uses: pypa/gh-action-pypi-publish@v1.4.2
with:
user: __token__
password: $
skip_existing: true
CIBW_ARCHS_WINDOWS: AMD64
CIBW_ARCHS_MACOS: x86_64
CIBW_ARCHS_LINUX: "x86_64 aarch64"

Source Code

https://github.com/yushulx/python-barcode-qrcode-sdk

--

--

Manager of Dynamsoft Open Source Projects | Tech Lover

Love podcasts or audiobooks? Learn on the go with our new app.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Xiao Ling

Xiao Ling

Manager of Dynamsoft Open Source Projects | Tech Lover