Skip to content

Instantly share code, notes, and snippets.

@sultanqasim
Last active February 16, 2024 16:32
Show Gist options
  • Save sultanqasim/765aa38fa12e099da4ac14838e9af8ae to your computer and use it in GitHub Desktop.
Save sultanqasim/765aa38fa12e099da4ac14838e9af8ae to your computer and use it in GitHub Desktop.
SigDigger build script for my unofficial branch for Mac OS (including Apple Silicon)
#!/bin/sh
#
set -eux
BREW_PREFIX="$(brew --prefix)"
CPU_COUNT="$(sysctl -n hw.ncpu)"
QT_PATH="${HOME}/Qt/6.5.3/macos"
# Homebrew dependencies
brew update
brew install volk fftw libsndfile libxml2 portaudio dylibbundler
brew tap pothosware/homebrew-pothos
#brew install pothossoapy soapyairspyhf # broken build
brew install soapyrtlsdr soapyhackrf soapybladerf soapyairspy soapyredpitaya soapyiris limesuite soapyplutosdr
brew install --head soapyuhd # avoiding C++14 compilation issue, as fix hasn't yet been tagged in a release
# get the code
if [ ! -e sigutils ]; then
git clone -b develop --recurse-submodules https://github.com/sultanqasim/sigutils.git
fi
if [ ! -e suscan ]; then
git clone -b develop --recurse-submodules https://github.com/sultanqasim/suscan.git
fi
if [ ! -e SuWidgets ]; then
git clone -b develop https://github.com/sultanqasim/SuWidgets
fi
if [ ! -e SigDigger ]; then
git clone -b develop https://github.com/sultanqasim/SigDigger.git
fi
# prepare the deploy path
DEPLOYROOT="$(pwd)/deploy-root"
export PKG_CONFIG_PATH="$DEPLOYROOT/usr/lib/pkgconfig"
rm -rf "$DEPLOYROOT"
mkdir -p "$DEPLOYROOT"
# build the source dependencies
(
cd sigutils
rm -rf build
mkdir -p build
cd build
cmake .. -DCMAKE_INSTALL_PREFIX="$DEPLOYROOT/usr" -DCMAKE_SKIP_RPATH=ON -DCMAKE_SKIP_INSTALL_RPATH=ON -DCMAKE_BUILD_TYPE=Release
make -j${CPU_COUNT}
make install
)
(
cd suscan
rm -rf build
mkdir -p build
cd build
cmake .. -DCMAKE_INSTALL_PREFIX="$DEPLOYROOT/usr" -DCMAKE_SKIP_RPATH=ON -DCMAKE_SKIP_INSTALL_RPATH=ON -DCMAKE_PREFIX_PATH="$DEPLOYROOT/usr" -DCMAKE_BUILD_TYPE=Release
make -j${CPU_COUNT}
make install
)
(
cd SuWidgets
"${QT_PATH}/bin/qmake" SuWidgetsLib.pro PREFIX="$DEPLOYROOT/usr" "CONFIG += release"
make clean
make -j${CPU_COUNT}
make install
)
# build SigDigger
(
cd SigDigger
"${QT_PATH}/bin/qmake" SigDigger.pro PREFIX="$DEPLOYROOT/usr" SUWIDGETS_PREFIX="$DEPLOYROOT/usr" "CONFIG += release"
make clean
make -j${CPU_COUNT}
make install
)
# utility functions
function excluded()
{
excludelist="libc++.1.dylib libSystem.B.dylib"
for ef in `echo $excludelist`; do
if [ "$ef" == "$1" ]; then
return 0
fi
done
return 1
}
function find_lib()
{
SANE_DIRS="/usr/lib $BREW_PREFIX/lib $LIBPATH"
for i in $SANE_DIRS; do
if [ -f "$i/$1" ]; then
echo "$i/$1"
return 0
fi
done
return 1
}
function embed_soapysdr()
{
SOAPYSDRVER=`pkg-config SoapySDR --modversion | sed 's/\([0-9]*\.[0-9]*\)\..*/\1/g'`
MODDIR="$BREW_PREFIX/lib/SoapySDR/modules$SOAPYSDRVER"
mkdir -p "$LIBPATH/SoapySDR/"
cp -RLfv "$MODDIR" "$LIBPATH/SoapySDR"
# rename module directory without . to make codesign friendly
mv "$LIBPATH/SoapySDR/modules$SOAPYSDRVER" "$LIBPATH/SoapySDR/modules"
# copy in all dependencies
for f in "$LIBPATH/SoapySDR/modules"/*; do
dylibbundler -cd -of -b -x "$f" -d "$LIBPATH" -p "@executable_path/../Frameworks/"
done
# fix duplicate library
rm "$LIBPATH/libSoapySDR.0.8.dylib"
ln -s "./"`basename "$LIBPATH/libSoapySDR.0.8."*".dylib"` "$LIBPATH/libSoapySDR.0.8.dylib"
# make sure local soapy modules are used, not homebrew ones
ESCAPED_BREW_PREFIX=$(printf '%s\n' "$BREW_PREFIX" | sed -e 's/[\/&]/\\&/g')
ZSTR=$(printf 'z%.0s' $(seq 1 ${#BREW_PREFIX}))
LC_ALL=C sed -e 's/'"${ESCAPED_BREW_PREFIX}"'/'"${ZSTR}"'/' "$LIBPATH/libSoapySDR.0.8."*".dylib" >_delme_soapy
mv _delme_soapy "$LIBPATH/libSoapySDR.0.8."*".dylib"
return 0
}
function deploy_deps()
{
embed_soapysdr
cp -RLfv "$BREW_PREFIX/opt/gcc/lib/gcc/current/libgcc_s.1.1.dylib" "$LIBPATH"
}
function swap_uhd()
{
# my hacked fork of uhd with fast retuning
# https://github.com/sultanqasim/uhd
#
# build by running:
# mkdir -p uhd/host/build
# cd uhd/host/build
# cmake .. -DCMAKE_BUILD_TYPE=Release -DENABLE_SIM=OFF
# make -j5
cp uhd/host/build/lib/libuhd.4.6.0.dylib "$LIBPATH/"
dylibbundler -cd -of -b -x "$LIBPATH/libuhd.4.6.0.dylib" -d "$LIBPATH" -p "@executable_path/../Frameworks/"
}
function remove_full_paths()
{
FULLPATH="$2"
if [[ "$2" == *".framework"* ]]; then
FWNAME=`basename "$FULLPATH"`
RPATHNAME='@executable_path/../Frameworks/'"$FWNAME.framework/Versions/A/$FWNAME"
else
RPATHNAME='@executable_path/../Frameworks/'`basename "$FULLPATH"`
fi
install_name_tool -change "$FULLPATH" "$RPATHNAME" "$1"
}
function remove_full_path_stdin () {
while read line; do
remove_full_paths "$1" "$line"
done
}
function ensure_rpath()
{
for i in "$LIBPATH"/*.dylib "$LIBPATH/SoapySDR/modules"*/*.so "$BUNDLEPATH"/Contents/MacOS/*; do
if ! [ -L "$i" ]; then
chmod u+rw "$i"
echo "Fixing "`basename $i`"..."
otool -L "$i" | grep '\t'"$BREW_PREFIX/" | tr -d '\t' | cut -f1 -d ' ' | remove_full_path_stdin "$i";
otool -L "$i" | grep '\t@rpath/.*\.dylib' | tr -d '\t' | cut -f1 -d ' ' | remove_full_path_stdin "$i";
fi
done
}
function fix_loader_path()
{
# $1 is library name, $2 is dependency path relative to BREW_PREFIX
DEPNAME=`basename "$2"`
install_name_tool -change "@loader_path/../../../../$2" "@executable_path/../Frameworks/$DEPNAME" "$LIBPATH/$1"
}
function fix_loader_path_and_copy_lib()
{
FILENAME=`basename "$2"`
fix_loader_path "$1" "$2"
cp -p "$BREW_PREFIX/$2" "$LIBPATH/$FILENAME"
}
function copy_su_libs()
{
cp -fv "$DEPLOYROOT/usr/lib/libsigutils.1.dylib" "$LIBPATH"
cp -fv "$DEPLOYROOT/usr/lib/libsuscan.0."*.*".dylib" "$LIBPATH"
cp -fv "$DEPLOYROOT/usr/lib/libsuwidgets.0.dylib" "$LIBPATH"
}
function fix_sndfile()
{
# workaround for homebrew libsndfile path issues
fix_loader_path_and_copy_lib "libsndfile.1.dylib" "opt/libogg/lib/libogg.0.dylib"
fix_loader_path_and_copy_lib "libsndfile.1.dylib" "opt/libvorbis/lib/libvorbisenc.2.dylib"
fix_loader_path_and_copy_lib "libsndfile.1.dylib" "opt/flac/lib/libFLAC.12.dylib"
fix_loader_path_and_copy_lib "libsndfile.1.dylib" "opt/opus/lib/libopus.0.dylib"
fix_loader_path_and_copy_lib "libsndfile.1.dylib" "opt/mpg123/lib/libmpg123.0.dylib"
fix_loader_path_and_copy_lib "libsndfile.1.dylib" "opt/lame/lib/libmp3lame.0.dylib"
fix_loader_path_and_copy_lib "libsndfile.1.dylib" "opt/libvorbis/lib/libvorbis.0.dylib"
}
function fix_plist()
{
plutil -replace CFBundleIdentifier -string "$BUNDLEID" "$PLISTPATH"
plutil -replace CFBundleName -string "SigDigger" "$PLISTPATH"
plutil -replace CFBundleDevelopmentRegion -string "en" "$PLISTPATH"
}
function copy_usrp_fw()
{
mkdir -p "${BUNDLEPATH}/Contents/share/uhd/images"
cp "${BREW_PREFIX}/share/uhd/images/usrp_b2"* "${BUNDLEPATH}/Contents/share/uhd/images/"
}
function sign_code()
{
find "$BUNDLEPATH" -name '*.framework' -or -name '*.dylib' -or -name '*.so' | {
while read -r f; do
codesign --sign - --force --preserve-metadata=entitlements,requirements,flags,runtime "${f}"
done
}
codesign --sign - --force --preserve-metadata=entitlements,requirements,flags,runtime "${BUNDLEPATH}/Contents/MacOS/SigDigger"
codesign --sign - --force --preserve-metadata=entitlements,requirements,flags,runtime "$BUNDLEPATH"
}
function create_dmg()
{
rm -Rfv "$STAGINGDIR"
mkdir -p "$STAGINGDIR"
cp -Rfv "$BUNDLEPATH" "$STAGINGDIR"
hdiutil create -verbose -volname SigDigger -srcfolder "$STAGINGDIR" -ov -format UDZO "$DMG_NAME"
}
# turn it into a complete app bundle with all libraries included
BUNDLEID="org.actinid.SigDigger"
BUNDLEPATH="$DEPLOYROOT/usr/bin/SigDigger.app"
PLISTPATH="$BUNDLEPATH/Contents/Info.plist"
RSRCPATH="$BUNDLEPATH/Contents/Resources"
LIBPATH="$BUNDLEPATH/Contents/Frameworks"
BINPATH="$BUNDLEPATH/Contents/MacOS"
STAGINGDIR="$DEPLOYROOT/SigDigger.dir"
DMG_NAME="SigDigger.dmg"
"${QT_PATH}/bin/macdeployqt" "$BUNDLEPATH"
cp -Rfv "$DEPLOYROOT/usr/share/suscan" "$RSRCPATH"
cp -fv "$DEPLOYROOT/usr/bin/suscli" "$BINPATH"
cp -fv `which SoapySDRUtil` "$BINPATH"
copy_su_libs
deploy_deps
swap_uhd
fix_sndfile
ensure_rpath
fix_plist
copy_usrp_fw
sign_code
create_dmg
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment