Skip to content

Instantly share code, notes, and snippets.

@sigsergv
Last active February 10, 2019 23:01
Show Gist options
  • Save sigsergv/82925dc88e351078d42b to your computer and use it in GitHub Desktop.
Save sigsergv/82925dc88e351078d42b to your computer and use it in GitHub Desktop.

Overview

This document describes how to compile GQRX using native OSX Qt 5 and libraries from brew.

Requierements

Skip any part if you have corresponding component already installed.

Mac OS X 10.10 Yosemite

Didn't check other versions.

homebrew

Install using instructions from official homebrew site.

Install XCode

https://developer.apple.com/xcode/download/

Actually you need just Command Line Tools, you can find that dmg package here: https://developer.apple.com/downloads/ (apple id required).

Qt5

Install Qt 5.5 Opensource:

  • go to official page;
  • click “Download Now” button and download .dmg package;
  • open and install Qt 5.5 into $HOME/Qt

I have checked Qt version 5.3 and I think any 5.* version will do, btw.

Also make sure that you don't have qt installed via homebrew, it will break build and introduce weird compile errors.

cmake

brew install cmake

osmosdr

Open terminal and execute the following commands:

brew tap chleggett/gr-osmosdr
brew install gr-osmosdr

If you have troubles here try to install Cheetah manually:

pip install Cheetah

Thanks to https://github.com/chleggett/homebrew-gqrx .

Compiling gqrx

Download gqrx itself:

mkdir ~/gqrx-osx
cd ~/gqrx-osx
git clone https://github.com/csete/gqrx.git
mkdir build
cd build
export Qt5_DIR=~/Qt/5.5/clang_64/lib/cmake/Qt5
cmake ../gqrx
make

At this moment you have compiled working version of gqrx in the directory src, you can start it from the terminal:

./src/gqrx

If you want standalone .app file without any external dependencies, execute this magic:

mkdir -p gqrx.app/Contents/MacOS gqrx.app/Contents/Resources
echo 'APPL????' > gqrx.app/Contents/PkgInfo
cp ../gqrx/resources/icons/gqrx.icns gqrx.app/Contents/Resources
cp src/gqrx gqrx.app/Contents/MacOS

Now create file gqrx.app/Contents/Info.plist with the following content:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>NSPrincipalClass</key>
    <string>NSApplication</string>

    <key>CFBundleIconFile</key>
    <string>gqrx.icns</string>

    <key>CFBundlePackageType</key>
    <string>APPL</string>

    <key>CFBundleGetInfoString</key>
    <string>Created by Qt/CMake</string>

    <key>CFBundleSignature</key>
    <string>????</string>

    <key>CFBundleExecutable</key>
    <string>gqrx</string>

    <key>CFBundleIdentifier</key>
    <string>dk.gqrx</string>
</dict>
</plist>

Now convert gqrx.dmg to a redistributable package, first step:

~/Qt/5.5/clang_64/bin/macdeployqt gqrx.app -verbose=3 2> macdeployqt.log

Before the next step you need to get script fix-deps.py, it's in the same gist below, or you can just download it using this commands:

curl -L -o fix-deps.py https://gist.github.com/sigsergv/82925dc88e351078d42b/raw/e3b69c3710730ecd27e8bfb144fa44f954afa8bb/fix-deps.py
chmod +x fix-deps.py

Execute it (in the durectory ~/gqrx-osx/build!):

./fix-deps.py

You should see a few lines of text followed by text Finished!, if you don't see Finished! then something gone wrong.

At the end you should get file gqrx.app that doesn't contain any non-system external dependencies.

#!/usr/bin/python
import os
import subprocess
import re
import shutil
from pprint import pprint as pp
OTR_RE = re.compile('^\t([^ ]+) (.+)')
SPLIT = re.compile('[\n\r]+')
LP_RE = re.compile('@loader_path/(.+)$')
FPREFIX = 'gqrx.app/Contents/Frameworks/'
LIB_PATHS = ['/usr/local/opt/boost/lib/']
lib_deps = {}
def iteration(pass_num):
print '\nFixing dependencied, pass: {0}'.format(pass_num)
for root, dirs, files in os.walk(FPREFIX):
for fn in files:
if not fn.endswith('.dylib'):
continue
lib_path = os.path.join(root, fn)
deps = []
output = subprocess.check_output(['otool', '-L', lib_path])
for line in SPLIT.split(output):
mo = OTR_RE.match(line)
if mo is None:
continue
d = mo.group(1)
if d.startswith('/System/') or d.startswith('/usr/lib') or d.startswith('@executable_path'):
continue
deps.append(d)
lib_deps[lib_path.replace(FPREFIX, '')] = deps
counter = 0
for lib_name, deps in lib_deps.iteritems():
for d in deps:
mo = LP_RE.match(d)
if mo is None:
continue
counter += 1
lib = mo.group(1)
new_fn = os.path.join(FPREFIX, lib)
missing = lib_deps.get(lib, None) is None
if missing:
print 'Library `{0}` is missing, trying to fix'.format(lib)
for p in LIB_PATHS:
fn = os.path.join(p, lib)
if os.path.exists(fn):
print ' found {0}, copy to {1}'.format(fn, new_fn)
shutil.copy(fn, new_fn)
os.chmod(new_fn, 0o644)
# fix ID
cmd = ['install_name_tool', '-id', '@executable_path/../Frameworks/{0}'.format(lib), new_fn]
subprocess.check_output(cmd)
else:
print 'File `{0}`: referense to shared library broken: `{1}`, trying to fix'.format(os.path.join(FPREFIX, lib_name), lib)
cmd = ['install_name_tool', '-change', '@loader_path/{0}'.format(lib), '@executable_path/../Frameworks/{0}'.format(lib), \
os.path.join(FPREFIX, lib_name)]
subprocess.check_output(cmd)
return counter
for x in range(30):
if iteration(x+1) == 0:
print 'Finished!'
break
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment