How to Build and Publish Snap Packages with Linux Shared Libraries
When you want to release a proprietary tool or SDK, which is not open source, to Linux platforms, it is a nightmare. You have to make multiple packages and do more tests to guarantee compatibility for different Linux distributions. Is it possible to only create one pre-built package? We can use Snap, which is a software deployment and package management system, working across a range of Linux distributions.
Installing Snap and Snapcraft
Follow the guide to install the tool on different Linux distributions.
Here are the steps for Debian:
$ sudo apt update $ sudo apt install snapd $ sudo snap install snapcraft –classic
I initially tried to install snapcraft on WSL but failed with the error message:
Interacting with snapd is not yet supported on Windows Subsystem for Linux. This command has been left available for documentation purposes only.
Then I selected Ubuntu 20.04 as the alternative. We can install the hello-world package to make a test:
$ sudo snap install hello-world hello-world 6.4 from Canonical✓ installed $ hello-world Hello World!
Building and Publishing Snap Package with Snapcraft
Snapcraft is a command-line tool used to build and publish snap packages.
Run the following command to generate an empty project with a snapcraft.yaml file:
$ snapcraft init Created snap/snapcraft.yaml.
In the following paragraphs, I will take Dynamsoft Barcode Reader SDK as an example, showing how to package a Linux app and its dependent shared library.
Download Dynamsoft Barcode Reader for Linux.
Extract the header file and shared library from the SDK and put them into the project.
The essential part of the Makefile is “install”. We have to copy both the executable file and shared library to the corresponding directory:
CC=gcc CCFLAGS=-c LDFLAGS=-L ./lib DBRLIB=-lDynamsoftBarcodeReader STDLIB=-lstdc++ TARGET=barcode-reader OBJECT=ReadBarcode.o SOURCE=ReadBarcode.cpp # build rule for target. $(TARGET): $(OBJECT) $(CC) -o $(TARGET) $(OBJECT) $(STDLIB) $(DBRLIB) $(LDFLAGS) # target to build an object file $(OBJECT): $(SOURCE) $(CC) $(CCFLAGS) $(SOURCE) install: mkdir -p $(DESTDIR)/usr/bin/ cp ./barcode-reader $(DESTDIR)/usr/bin/ mkdir -p $(DESTDIR)/usr/lib cp ./lib/libDynamsoftBarcodeReader.so $(DESTDIR)/usr/lib # the clean target .PHONY : clean clean: rm -f $(OBJECT) $(TARGET)
Edit the snapcraft.yaml file:
name: barcode-reader base: core18 version: '7.4' summary: Barcode SDK for 1D barcode, QR Code, Data Matrix, PDF417, Aztec Code, MaxiCode description: | An enterprise-class barcode SDK that enables you to efficiently embed barcode reading functionality in your web, desktop or mobile applications with a few lines of code. icon: snap/gui/logo.png grade: stable confinement: strict parts: barcode-reader: plugin: make build-packages: [gcc, g++, make] stage-packages: [libstdc++6] source: src apps: barcode-reader: command: barcode-reader plugs: [home]
Each snap package is sandboxed, running in a constrained environment, and thus I need to add the home plugin in order to make my barcode reader app load image files from $HOME directory.
We can build or clean the snap package as follows:
snapcraft snapcraft clean dbr -s pull
Before publishing the package to the snap store, we’d better test it locally. Run the command to install the package from local disk:
sudo snap install --dangerous barcode-reader_7.4_amd64.snap
Run the app:
If everything works fine, we can publish the package to the snap store:
$ snapcraft login $ snapcraft push --release=stable barcode-reader_7.4_amd64.snap
Here is my page: https://snapcraft.io/barcode-reader.
Lastly, we should beautify the store presence by editing relevant information.
How to Build a Linux App with the Shared library inside Snap Package
Install the barcode-reader package:
$ sudo snap install barcode-reader
Find the directory of the shared library and set the LD_LIBRARY_PATH:
$ export LD_LIBRARY_PATH=/snap/barcode-reader/current/usr/lib/
Build your own barcode reading app:
$ gcc -o app <source.cpp> -L /snap/barcode-reader/current/usr/lib/ -lDynamsoftBarcodeReader -lstdc++ $ ./app
Instead, we can use -rpath to build the barcode app without setting LD_LIBRARY_PATH :
$ gcc -o app <source.cpp> -L /snap/barcode-reader/current/usr/lib/ -lDynamsoftBarcodeReader -lstdc++ -Wl,-rpath=/snap/barcode-reader/current/usr/lib/ $ ./app