How to Build Linux ARM32 and Aarch64 Barcode QR Scanner in Docker Container
Tags: docker, arm32, aarch64, programming
Published: 2022-06-17 06:22:52

If you want to build and test barcode QR code scanner applications for embedded and IoT devices, such as **Raspberry Pi**, **Arduino**, **Jetson Nano** and so on, a physical device is not must-have for development. This article shows how to use [Dynamsoft Barcode SDK](https://www.dynamsoft.com/barcode-reader/overview/) to build barcode QR code reading applications for Linux ARM32 and Aarch64 (also called ARM64) in Docker container. The sample code is written in C++ and Python.


## Docker Images for Running Linux ARM32 and Aarch64 
Since there are many existing Docker images for Linux ARM32 and Aarch64, we do not need to build them from scratch. The [arm32v7/gcc](https://hub.docker.com/r/arm32v7/gcc/) and [arm64v8/gcc](https://hub.docker.com/r/arm64v8/gcc/) have provided a full GCC environment. We can use them as the base images.

```bash
docker pull arm32v7/gcc
docker pull arm64v8/gcc
```

[multiarch/qemu-user-static](https://hub.docker.com/r/multiarch/qemu-user-static/) is required for emulating ARM32 and Aarch64 instructions on x86_64 Linux. 

```bash
docker run --rm --privileged multiarch/qemu-user-static:register --reset
```
### C++ Barcode QR Code Scanner for Linux ARM32 and Aarch64
Get the [C++ sample code](https://github.com/yushulx/cmake-cpp-barcode-qrcode) developed with Dynamsoft Barcode SDK that supports `Windows (x86_64)`, `macOS(x86_64)`, and `Linux(x86_64, ARM32, and ARM64)`.

```bash
git clone https://github.com/yushulx/cmake-cpp-barcode-qrcode.git
```

We mount the project folder to the Docker container rather than copy it to the container. It is convenient for later distribution.

```bash
docker run --platform linux/arm/v7 -it --rm -v "$PWD":/usr/src/myapp -w /usr/src/myapp arm32v7/gcc 

docker run --platform linux/arm64/v8 -it --rm -v "$PWD":/usr/src/myapp -w /usr/src/myapp arm64v8/gcc 
```

Then install `cmake` and build the project:

```bash
apt install -y cmake
mkdir build 
cmake -B build 
cmake --build build --config release 
cmake --install build
```

The executable file and the shared libraries will be copied to the `dist` folder after running the `--install` command. We can run the application by:

```bash
./dist/BarcodeReader ./images/AllSupportedBarcodeTypes.png ./license-key.txt
```

![aarch64 barcode qrcode scanner](https://www.dynamsoft.com/codepool/img/2022/06/aarch64-barcode-qr-code-scanner.png)

Get the [30-day trial license key](https://www.dynamsoft.com/customer/license/trialLicense?product=dbr) and save it to the `license-key.txt` file.

### Python Barcode QR Code Scanner for Linux ARM32 and Aarch64
Get the source code of the [Python barcode QR code sample](https://github.com/yushulx/python-barcode-qrcode-sdk).

```bash
git clone https://github.com/yushulx/python-barcode-qrcode-sdk.git
```

The GCC Docker images have contained Python environment without `pip`.

We install `pip` firstly, and then install other required Python packages for building the wheel file inside the Docker container.

```bash
apt install python3-pip -y
pip3 install auditwheel patchelf-wrapper
```

Build the Python wheel file and repair it with `auditwheel`. Only the manylinux-supported wheel file can be uploaded to PyPI.

```bash
python3 setup_setuptools.py bdist_wheel
auditwheel repair wheelhouse/{*.whl} --plat manylinux2014_$(uname -m)
```

We can install and test the Python barcode QR code scanner SDK as follows:

```bash
pip3 install wheelhouse/{*.whl}
python3 test.py
```

## GitHub Actions for Building Linux ARM32 and Aarch64 Barcode QR Code Scanner
GitHub Actions is a tool for automating the build and release of software. We can configure action workflow to build, test and distribute our Linux ARM32 and Aarch64 barcode QR code scanner applications.

### GitHub Actions for Building CMake Project
We create two jobs: one for arm32 and one for arm64. The basic steps include:
1. Clone the project from GitHub repository.
2. Set up the QEMU user-static image.
3. Run Docker container to build and test the project.
4. Use zip tool to compress the dist folder.
5. Make the package downloadable as an artifact file.

    ![GitHub build and download](https://www.dynamsoft.com/codepool/img/2022/06/github-action-artifact-download.png)

```yml
name: CMake

on:
  push:
    branches: [ "main" ]
  pull_request:
    branches: [ "main" ]

env:
  # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
  BUILD_TYPE: Release

jobs:
  arm32_build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3  
    
    - name: Set up QEMU
      uses: docker/setup-qemu-action@v2
        
    - name: CMake build and run
      run: |
        docker run --platform linux/arm/v7 --rm -v "$PWD":/usr/src/myapp -w /usr/src/myapp arm32v7/gcc bash -c "apt update && apt install -y cmake; mkdir build && cmake -B build && cmake --build build --config ${{env.BUILD_TYPE}} && cmake --install build; ./dist/BarcodeReader ./images/AllSupportedBarcodeTypes.png ./license-key.txt"
        
    - name: Archive Release
      uses: thedoctor0/zip-release@main
      with:
        type: 'zip'
        filename: arm32.zip
        exclusions: '*.git* /*node_modules/* .editorconfig'
        path: ${{github.workspace}}/dist

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

  arm64_build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3  
    
    - name: Set up QEMU
      uses: docker/setup-qemu-action@v2
        
    - name: CMake build and run
      run: |
        docker run --platform linux/arm64/v8 --rm -v "$PWD":/usr/src/myapp -w /usr/src/myapp arm64v8/gcc bash -c "apt update && apt install -y cmake; mkdir build && cmake -B build && cmake --build build --config ${{env.BUILD_TYPE}} && cmake --install build; ./dist/BarcodeReader ./images/AllSupportedBarcodeTypes.png ./license-key.txt"
        
    - name: Archive Release
      uses: thedoctor0/zip-release@main
      with:
        type: 'zip'
        filename: arm64.zip
        exclusions: '*.git* /*node_modules/* .editorconfig'
        path: ${{github.workspace}}/dist

    - uses: actions/upload-artifact@v2
      with:
        path: ./*.zip
```

### GitHub Actions for Building Python Wheel
The [cibuildwheel](https://cibuildwheel.readthedocs.io/en/stable/) is the official tool to build Python wheel file. It supports manylinux2014 aarch64 Docker image.

Here we only build the aarch64 wheel file with cibuildwheel.
1. Clone the project from GitHub repository.
2. Set up the Python environment.
3. Set up the QEMU user-static image.
4. Build the Python wheel file with cibuildwheel in Docker container.
5. Test the Python barcode QR code scanner SDK.
6. Package all Python wheel files to artifact.
7. Upload all Python wheel files to PyPI.

    ![upload python wheel to pypi](https://www.dynamsoft.com/codepool/img/2022/06/python-wheel-pypi.png)

```yml
name: Build and upload to PyPI

on: [push, pull_request]

jobs:
  build_wheels:
    name: Build wheels on ${{ matrix.os }}
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        os: [ubuntu-20.04]

    steps:
      - uses: actions/checkout@v2

      - name: Set up Python
        uses: actions/setup-python@v4
        with:
          python-version: '3.x'
          
      - name: Set up QEMU
        if: runner.os == 'Linux'
        uses: docker/setup-qemu-action@v2
        with:
          platforms: all
      
      - name: Build wheels
        uses: pypa/cibuildwheel@v2.6.1
        env:
          CIBW_ARCHS_LINUX: aarch64 
      
      - name: Run test.py in develop mode
        run: |
          python setup_setuptools.py develop
          python -m pip install opencv-python
          python --version
          python test.py
      - 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: ${{ secrets.pypi_password }}
          skip_existing: true
```