Linking and Loading *.dylib Files in Go Barcode Reader Modules on macOS
In previous articles, we developed a Go barcode reader module integrating the Dynamsoft Barcode Reader C/C++ SDK for Windows and Linux. In this article, we will extend the module to support macOS.
This article is Part 3 in a 4-Part Series.
- Part 1 - Building a Go Module with C API of Dynamsoft Barcode SDK v9.x
- Part 2 - Integrating Dynamsoft's C++ Barcode SDK v10 into Go Module with a C Wrapper
- Part 3 - Linking and Loading *.dylib Files in Go Barcode Reader Modules on macOS
- Part 4 - Developing a Web Application for Reading Multiple Barcodes with Go and HTML5
Development Environment
- Mac mini (M2, 2023)
- macOS Sonoma 14.2
Prerequisites
-
Xcode Command Line Tools
xcode-select --install
- Go Environment
- Dynamsoft Barcode Reader v9.x License Key
-
Dynamic libraries (
*.dylib
) of Dynamsoft Barcode Reader v9.x for macOS.If you download the C++ SDK package from the official website, you might notice that the macOS libraries are missing. However, there’s no need to worry. Dynamsoft’s top-tier desktop barcode SDK for Python includes all C++ dynamic libraries built for various ABIs (
arm32
,x86
,x64
, andarm64
) and platforms (Windows
,Linux
andmacOS
), and these can be found in the official Python Barcode SDK.First, download the tar.gz file and extract it.
Inside, you’ll discover three folders designated for macOS:
macos
,macos_arm64
andmacos_universal2
. Themacos
folder is for Intel-based Macs,macos_arm64
for Apple Silicon Macs, andmacos_universal2
contains universal dynamic libraries compatible with both Intel-based and Apple Silicon Macs. To ensure our Go module works seamlessly across all Mac platforms, we will utilize the universal dynamic libraries.
Step 1: Adding *.dylib Files to the Go Module
-
In the
lib
directory of your Go module, create a new subfolder namedmac
. Then, transferlibDynamicPdf.dylib
,libDynamsoftBarcodeReader.dylib
, andlibDynamsoftLicenseClient.dylib
from themacos_universal2
directory into the mac folder. -
In the
reader.go
file, define macOS-specificLDFLAGS
using cgo. Usedarwin
as the Go build tag to target macOS environments.package barcode import ( "unsafe" /* #cgo darwin LDFLAGS: -L${SRCDIR}/lib/mac -lDynamsoftBarcodeReader ... */ "C" )
With these steps, your Go barcode reader module is now set up for macOS compatibility. Integrating this module into a Go application may require additional steps.
Step 2: Ensuring Go Tests Pass on macOS
As with Windows and Linux, it’s crucial to pass the Go tests to verify the functionality of the Go barcode reader module on macOS.
Running Go Tests on macOS
Execute go test
in the terminal to initiate the tests.
During testing, we may encounter issues such as:
permission denied
dyld: Library not loaded: libDynamsoftBarcodeReader.dylib
Resolving the Issues
-
Permission Denied: This issue can often be resolved by running the test with
sudo
:sudo go test
-
Dynamic Library Not Loaded: This error indicates that the dynamic linker cannot find
libDynamsoftBarcodeReader.dylib
. To resolve this, ensure the library path is correctly specified. Here are some potential solutions:-
Copy the
libDynamsoftBarcodeReader.dylib
file into either/usr/local/lib
or/usr/lib
.✖ Not recommended due to the requirement for root permissions to copy files into system library directories.
-
Set the
DYLD_LIBRARY_PATH
environment variable, similar to the approach on the Linux platform.✖ Ineffective on macOS Sonoma 14.2.
-
Utilize the
install_name_tool
command to append the library search path to the executable.✔ A viable option. We need to determine how to generate the executable file for Go testing.
-
What Does the go test
Command Do?
When you execute go test
, the Go toolchain compiles the test files (*_test.go
) alongside the package under test into a temporary executable designed exclusively for running tests. Once the test binary is compiled, go test
immediately executes it. Typically, this executable is deleted after the tests have completed.
However, you can manually generate and execute the test binary with the following commands:
go test -c -o testapp
./testapp
Adding Rpath to the Go Test Binary
-
Utilize the
otool
command to inspect the library search path of the Go test binary.otool -L testapp testapp: @rpath/libDynamsoftBarcodeReader.dylib ...
Here,
@rpath
acts as a placeholder that the dynamic linker (dyld
) resolves at runtime, based on the actual rpath entries embedded in the executable. -
Employ the
install_name_tool
command to append the library search path to the Go test binary.install_name_tool -add_rpath ./lib/mac testapp
To verify whether the rpath was added successfully, execute the
otool
command once more.otool -l testapp | grep -A2 LC_RPATH
Writing a Script to Build and Run a Go Test
Create a Shell script named run_mac_test.sh
to compile and execute the Go test binary as follows:
#!/bin/bash
RPATH="./lib/mac"
TARGET="testapp"
go test -c -o $TARGET
if ! otool -l $TARGET | grep -q $RPATH; then
echo "Adding rpath $RPATH to $TARGET"
install_name_tool -add_rpath $RPATH $TARGET
else
echo "RPATH $RPATH already exists in $TARGET"
fi
./$TARGET
rm ./$TARGET
This script first compiles the Go test into a binary named testapp
. It then checks whether the specified RPATH
is already present in the binary. If not, it adds the RPATH
using install_name_tool
. After running the test binary, the script cleans up by removing it.
To ensure the script can be executed directly, it must be given execute permissions:
chmod +x run_mac_test.sh
sudo ./run_mac_test.sh
Step 3: Running Go Barcode Reader Application on macOS
Using the Shell script run_mac_test.sh
as a reference, we can create a new script named run_mac.sh
to compile and execute the Go barcode reader application found in the example
directory.
#!/bin/bash
# Save the original PATH
originalPath=$LD_LIBRARY_PATH
# Get the GOPATH
GOPATH=$(go env GOPATH)
# Find the path to the shared libraries
PACKAGE_PATH=$(find "$GOPATH/pkg/mod/github.com/yushulx" -mindepth 1 -maxdepth 1 -type d | sort -r | head -n 1)
echo "PACKAGE_PATH set to $PACKAGE_PATH"
RPATH="$PACKAGE_PATH/lib/mac"
echo "LIBRARY_PATH set to $LIBRARY_PATH"
TARGET="testapp"
go build -o $TARGET
if ! otool -l $TARGET | grep -q $RPATH; then
echo "Adding rpath $RPATH to $TARGET"
install_name_tool -add_rpath $RPATH $TARGET
else
echo "RPATH $RPATH already exists in $TARGET"
fi
./$TARGET test.png
rm ./$TARGET
The RPATH
is configured using the GOPATH
and the package path of the latest Go barcode reader module. We utilize the go build
command to compile the Go barcode reader application. Subsequently, the install_name_tool
command is employed to append the library search path to the executable.