SerialPlot (ported) screenshot

HOWTO: Port serialplot to OS X

Preamble

A brief HOWTO explaining the OS X porting process for /serialplot.

For a detailed voyage of discovery, see Porting serialplot to OS X.

This application is not to be confused with /SerialPlot (note the capitalisation), a Qt application written explicitly for OS X, see Compiling Qt SerialPlot (for OS X).

Note: Using OS X 10.13.6 High Sierra

Application and script: /serialplot_OS_X_port

See also

Links

Initial housekeeping

First, some setup and preparation is required:

  • Download and install QtCreator. You can install QtCreator 4.5 from the repository
  • Create a workspace, i.e. ~/qtcode
  • Download, and unzip serialplot. Copy it into the workspace
  • Download, bunzip2 and untar qwt-6.2.0. Copy it into the workspace. Rename the directory to qwt.
  • Install Qt5, using brew: brew install qt5

Building

First build qwt

Copy qwt-6.2.0 into the workspace. Then bunzip2, untar and rename the directory to be simply  qwt:

$ bunzip2 qwt-6.2.0.tar.bz2
$ tar xvf qwt-6.2.0.tar
$ mv qwt-6.2.0 qwt

Open QtCreator, add or select a Qt5 kit.

In Project mode (left hand sidebar), Manage Kits-> Kit tab-> Select Qt5 kit and then select Clang for both the C and C++ compliers:

Clang compiler for Qt5

Remarkably, qwt compiled/built without an error.

Now, in a terminal, navigate to the qwt directory and run qmake from Qt5:

/usr/local/Cellar/qt@5/5.15.2/bin/qmake

and then make install.

Copy the newly created qwt.framework from ~/qtcode/qwt/lib/qwt.framework to /Library/Frameworks.

Now build serialplot

In QtCreator, add or select a Qt5 kit.

Ensure that in Manage kits, under Build and Run, that Qt5 is using Clang as a compiler for both C and C++, and is not using GCC.

Clang compiler for Qt5

Add to serialplot.pro the following line

INCLUDEPATH += $$PWD/../qwt/src

Add the following line to serialplot.pro (taken from the SerialPlot.pro file for the OS X version of SerialPlot – /SerialPlot):

mac: LIBS += -F$$PWD/../qwt/lib/ -framework qwt

Run qmake.

In plot.cpp, add the line

#include <qwt_scale_map.h>

In zoomer.cpp, add

#include <qwt_text.h>

and then

#include <QPainter>
#include <QPainterPath>
#include <QStack>

In scrollzoomer.cpp, add

#include <QStack>

In plotmenu.cpp, add

#include <QDebug>

In barchart.cpp, add

#include <qwt_text.h>

and

#include "math.h"

Now hit the Build button.

The application should now run. It should be under ~/qtcode/build-serialplot-Qt5-Debug/.

SerialPlot (ported) screenshot

Bundling the frameworks into the application

To make the application portable to other Macs that do not have Qt5 nor Qwt installed, you need to bundle the frameworks into the application bundle.

This can be done manually, or using a script otool_serialplot_qwt_cocoa.sh, which is found in /serialplot_OS_X_port.

Alternatively you can use macdeployqt – which I won’t cover here.

If you want an explanation as to why these commands are necessary then see the whole framework/library dependancy discovery process in the last section of Porting serialplot to OS X.

Bundle Qwt manually

Right click on the application and select Show package contents.

In the Contents folder/directory make a new folder/directory called Frameworks

Copy qwt.framework into this directory

In the terminal, run first

$ install_name_tool -add_rpath @executable_path/../Frameworks serialplot.app/Contents/MacOS/serialplot
error: /Library/Developer/CommandLineTools/usr/bin/install_name_tool: for: serialplot.app/Contents/MacOS/serialplot (for architecture x86_64) option "-add_rpath @executable_path/../Frameworks" would duplicate path, file already has LC_RPATH for: @executable_path/../Frameworks

If you get the above error, don’t worry, it just means that rpath was already set correctly.

then link using

$ install_name_tool -change qwt.framework/Versions/6/qwt @rpath/qwt.framework/Versions/6/qwt serialplot.app/Contents/MacOS/serialplot 

Bundle Qt frameworks manually

Copy the following nine frameworks from /usr/local/Cellar/qt@5/5.15.2/lib/ into serialplot.app/Contents/Frameworks/

  • QtGui.framework
  • QtCore.framework
  • QtSvg.framework
  • QtWidgets.framework
  • QtSerialPort.framework
  • QtNetwork.framework
  • QtConcurrent.framework
  • QtPrintSupport.framework
  • QtOpenGL.framework

You can copy them using the Finder or in a terminal using cp -R ...

Now you have a run a load of commands to set the references, using install_name_tool -change

First for the application binary itself

$ install_name_tool -change /usr/local/opt/qt@5/lib/QtSvg.framework/Versions/5/QtSvg @rpath/QtSvg.framework/Versions/5/QtSvg serialplot.app/Contents/MacOS/serialplot 
$ install_name_tool -change /usr/local/opt/qt@5/lib/QtWidgets.framework/Versions/5/QtWidgets @rpath/QtWidgets.framework/Versions/5/QtWidgets serialplot.app/Contents/MacOS/serialplot
$ install_name_tool -change /usr/local/opt/qt@5/lib/QtGui.framework/Versions/5/QtGui @rpath/QtGui.framework/Versions/5/QtGui serialplot.app/Contents/MacOS/serialplot
$ install_name_tool -change /usr/local/opt/qt@5/lib/QtSerialPort.framework/Versions/5/QtSerialPort @rpath/QtSerialPort.framework/Versions/5/QtSerialPort serialplot.app/Contents/MacOS/serialplot 
$ install_name_tool -change /usr/local/opt/qt@5/lib/QtNetwork.framework/Versions/5/QtNetwork @rpath/QtNetwork.framework/Versions/5/QtNetwork serialplot.app/Contents/MacOS/serialplot 
$ install_name_tool -change /usr/local/opt/qt@5/lib/QtCore.framework/Versions/5/QtCore @rpath/QtCore.framework/Versions/5/QtCore serialplot.app/Contents/MacOS/serialplot

Now to set the references for the Qt frameworks themselves…

Note that you will have to change (i.e. enable) the write permissions before running install_name_tool upon each of the frameworks, see install_name_tool: can’t open input file: *.dylib for writing (Permission denied). Like this:

chmod +w serialplot.app/Contents/Frameworks/QtGui.framework/Versions/5/QtGui

Don’t forget to set the permissions back to read only once you have used install_name_tool.

chmod +w serialplot.app/Contents/Frameworks/QtGui.framework/Versions/5/QtGui

First, we need to point QtGui to QtCore as well, in the same manner that serialplot binary is pointed to the Qt frameworks:

$ install_name_tool -change /usr/local/Cellar/qt@5/5.15.2/lib/QtCore.framework/Versions/5/QtCore @rpath/QtCore.framework/Versions/5/QtCore serialplot.app/Contents/Frameworks/QtGui.framework/Versions/5/QtGui

For QtSvg

$ install_name_tool -change /usr/local/Cellar/qt@5/5.15.2/lib/QtWidgets.framework/Versions/5/QtWidgets @rpath/QtWidgets.framework/Versions/5/QtWidgets serialplot.app/Contents/Frameworks/QtSvg.framework/Versions/5/QtSvg
$ install_name_tool -change /usr/local/Cellar/qt@5/5.15.2/lib/QtGui.framework/Versions/5/QtGui @rpath/QtGui.framework/Versions/5/QtGui serialplot.app/Contents/Frameworks/QtSvg.framework/Versions/5/QtSvg
$ install_name_tool -change /usr/local/Cellar/qt@5/5.15.2/lib/QtCore.framework/Versions/5/QtCore @rpath/QtCore.framework/Versions/5/QtCore serialplot.app/Contents/Frameworks/QtSvg.framework/Versions/5/QtSvg

For QtWidgets

$ install_name_tool -change /usr/local/Cellar/qt@5/5.15.2/lib/QtGui.framework/Versions/5/QtGui @rpath/QtGui.framework/Versions/5/QtGui serialplot.app/Contents/Frameworks/QtWidgets.framework/Versions/5/QtWidgets
$ install_name_tool -change /usr/local/Cellar/qt@5/5.15.2/lib/QtCore.framework/Versions/5/QtCore @rpath/QtCore.framework/Versions/5/QtCore serialplot.app/Contents/Frameworks/QtWidgets.framework/Versions/5/QtWidgets

Now for QtSerialPort and QtNetwork

$ install_name_tool -change /usr/local/Cellar/qt@5/5.15.2/lib/QtCore.framework/Versions/5/QtCore @rpath/QtCore.framework/Versions/5/QtCore serialplot.app/Contents/Frameworks/QtSerialPort.framework/Versions/5/QtSerialPort
$ install_name_tool -change /usr/local/Cellar/qt@5/5.15.2/lib/QtCore.framework/Versions/5/QtCore @rpath/QtCore.framework/Versions/5/QtCore serialplot.app/Contents/Frameworks/QtNetwork.framework/Versions/5/QtNetwork

Bundling Qt frameworks for qwt

In addition to the six Qt frameworks already bundled and referenced, there are three more that Qwt uses:

  • QtConcurrent.framework
  • QtPrintSupport.framework
  • QtOpenGL.framework

Adding the references to these, as well as the four already bundled frameworks.

Setting qwt to look for the bundled QtGui

$ install_name_tool -change /usr/local/opt/qt@5/lib/QtGui.framework/Versions/5/QtGui @rpath/QtGui.framework/Versions/5/QtGui serialplot.app/Contents/Frameworks/qwt.framework/Versions/6/qwt 

Likewise for QtCore, QtWidgets, QtSvg

$ install_name_tool -change /usr/local/opt/qt@5/lib/QtCore.framework/Versions/5/QtCore @rpath/QtCore.framework/Versions/5/QtCore serialplot.app/Contents/Frameworks/qwt.framework/Versions/6/qwt

$ install_name_tool -change /usr/local/opt/qt@5/lib/QtSvg.framework/Versions/5/QtSvg @rpath/QtSvg.framework/Versions/5/QtSvg serialplot.app/Contents/Frameworks/qwt.framework/Versions/6/qwt

$ install_name_tool -change /usr/local/opt/qt@5/lib/QtWidgets.framework/Versions/5/QtWidgets @rpath/QtWidgets.framework/Versions/5/QtWidgets serialplot.app/Contents/Frameworks/qwt.framework/Versions/6/qwt

And then for the three new frameworks, QtConcurrent, QtPrintSupport and QtOpenGL

$ install_name_tool -change /usr/local/opt/qt@5/lib/QtOpenGL.framework/Versions/5/QtOpenGL @rpath/QtOpenGL.framework/Versions/5/QtOpenGL serialplot.app/Contents/Frameworks/qwt.framework/Versions/6/qwt

$ install_name_tool -change /usr/local/opt/qt@5/lib/QtConcurrent.framework/Versions/5/QtConcurrent @rpath/QtConcurrent.framework/Versions/5/QtConcurrent serialplot.app/Contents/Frameworks/qwt.framework/Versions/6/qwt

$ install_name_tool -change /usr/local/opt/qt@5/lib/QtPrintSupport.framework/Versions/5/QtPrintSupport @rpath/QtPrintSupport.framework/Versions/5/QtPrintSupport serialplot.app/Contents/Frameworks/qwt.framework/Versions/6/qwt

Setting the application binary’s reference to the three new Qt frameworks isn’t strictly necessary (I think, in fact I am pretty sure, because they aren’t listed in the output of otool -L for the application binary). However, if you want to, then these are the commands:

$ install_name_tool -change /usr/local/opt/qt@5/lib/QtConcurrent.framework/Versions/5/QtConcurrent @rpath/QtConcurrent.framework/Versions/5/QtConcurrent serialplot.app/Contents/MacOS/serialplot

$ install_name_tool -change /usr/local/opt/qt@5/lib/QtPrintSupport.framework/Versions/5/QtPrintSupport @rpath/QtPrintSupport.framework/Versions/5/QtPrintSupport serialplot.app/Contents/MacOS/serialplot

$ install_name_tool -change /usr/local/opt/qt@5/lib}/QtOpenGL.framework/Versions/5/QtOpenGL @rpath/QtOpenGL.framework/Versions/5/QtOpenGL serialplot.app/Contents/MacOS/serialplot

Fixing the new Qt frameworks references…

QtConcurrent

$ install_name_tool -change /usr/local/Cellar/qt@5/5.15.2/lib/QtCore.framework/Versions/5/QtCore @rpath/QtCore.framework/Versions/5/QtCore serialplot.app/Contents/Frameworks/QtConcurrent.framework/Versions/5/QtConcurrent

QtPrintSupport

$ install_name_tool -change /usr/local/Cellar/qt@5/5.15.2/lib/QtCore.framework/Versions/5/QtCore @rpath/QtCore.framework/Versions/5/QtCore serialplot.app/Contents/Frameworks/QtPrintSupport.framework/Versions/5/QtPrintSupport

$ install_name_tool -change /usr/local/Cellar/qt@5/5.15.2/lib/QtWidgets.framework/Versions/5/QtWidgets @rpath/QtWidgets.framework/Versions/5/QtWidgets serialplot.app/Contents/Frameworks/QtPrintSupport.framework/Versions/5/QtPrintSupport 

$ install_name_tool -change /usr/local/Cellar/qt@5/5.15.2/lib/QtGui.framework/Versions/5/QtGui @rpath/QtGui.framework/Versions/5/QtGui serialplot.app/Contents/Frameworks/QtPrintSupport.framework/Versions/5/QtPrintSupport 

QtOpenGL

$  install_name_tool -change /usr/local/Cellar/qt@5/5.15.2/lib/QtCore.framework/Versions/5/QtCore @rpath/QtCore.framework/Versions/5/QtCore serialplot.app/Contents/Frameworks/QtOpenGL.framework/Versions/5/QtOpenGL

$ install_name_tool -change /usr/local/Cellar/qt@5/5.15.2/lib/QtWidgets.framework/Versions/5/QtWidgets @rpath/QtWidgets.framework/Versions/5/QtWidgets serialplot.app/Contents/Frameworks/QtOpenGL.framework/Versions/5/QtOpenGL

$ install_name_tool -change /usr/local/Cellar/qt@5/5.15.2/lib/QtGui.framework/Versions/5/QtGui @rpath/QtGui.framework/Versions/5/QtGui serialplot.app/Contents/Frameworks/QtOpenGL.framework/Versions/5/QtOpenGL

That is it for the Qt frameworks. We have nearly finished. Only the home straight is left now.

Note: I found that I didn’t need to use install_name_tool -id at all. In fact, doing so caused the application to crash

Checking the name paths

Using otool -L, run these 11 commands

$ otool -L serialplot.app/Contents/MacOS/serialplot
$ otool -L serialplot.app/Contents/Frameworks/QtGui.framework/QtGui
$ otool -L serialplot.app/Contents/Frameworks/QtCore.framework/QtCore
$ otool -L serialplot.app/Contents/Frameworks/QtSvg.framework/QtSvg
$ otool -L serialplot.app/Contents/Frameworks/QtWidgets.framework/QtWidgets
$ otool -L serialplot.app/Contents/Frameworks/QtSerialPort.framework/QtSerialPort
$ otool -L serialplot.app/Contents/Frameworks/QtNetwork.framework/QtNetwork
$ otool -L serialplot.app/Contents/Frameworks/qwt.framework/qwt
$ otool -L serialplot.app/Contents/Frameworks/QtConcurrent.framework/QtConcurrent
$ otool -L serialplot.app/Contents/Frameworks/QtPrintSupport.framework/QtPrintSupport
$ otool -L serialplot.app/Contents/Frameworks/QtOpenGL.framework/QtOpenGL

Bundle libqcocoa.dylib manually

Finally the platform plugin is required.

In serialplot.app/Contents/ make a new directory PlugIns/platforms.

Copy /usr/local/Cellar/qt@5/5.15.2/plugins/platforms/libqcocoa.dylib into serialplot.app/Contents/PlugIns/platforms/. Note the difference in capitalisation of the word “plugins”.

Link this to all nine of the Qt frameworks

$ install_name_tool -change /usr/local/Cellar/qt@5/5.15.2/plugins/platforms/libqcocoa.dylib @rpath/../PlugIns/platforms/libqcocoa.dylib serialplot.app/Contents/Frameworks/QtGui.framework/Versions/5/QtGui
$ install_name_tool -change /usr/local/Cellar/qt@5/5.15.2/plugins/platforms/libqcocoa.dylib @rpath/../PlugIns/platforms/libqcocoa.dylib serialplot.app/Contents/Frameworks/QtSvg.framework/Versions/5/QtSvg
$ install_name_tool -change /usr/local/Cellar/qt@5/5.15.2/plugins/platforms/libqcocoa.dylib @rpath/../PlugIns/platforms/libqcocoa.dylib serialplot.app/Contents/Frameworks/QtCore.framework/Versions/5/QtCore
$ install_name_tool -change /usr/local/Cellar/qt@5/5.15.2/plugins/platforms/libqcocoa.dylib @rpath/../PlugIns/platforms/libqcocoa.dylib serialplot.app/Contents/Frameworks/QtWidgets.framework/Versions/5/QtWidgets
$ install_name_tool -change /usr/local/Cellar/qt@5/5.15.2/plugins/platforms/libqcocoa.dylib @rpath/../PlugIns/platforms/libqcocoa.dylib serialplot.app/Contents/Frameworks/QtSerialPort.framework/Versions/5/QtSerialPort
$ install_name_tool -change /usr/local/Cellar/qt@5/5.15.2/plugins/platforms/libqcocoa.dylib @rpath/../PlugIns/platforms/libqcocoa.dylib serialplot.app/Contents/Frameworks/QtNetwork.framework/Versions/5/QtNetwork
$ install_name_tool -change /usr/local/Cellar/qt@5/5.15.2/plugins/platforms/libqcocoa.dylib @rpath/../PlugIns/platforms/libqcocoa.dylib serialplot.app/Contents/Frameworks/QtConcurrent.framework/Versions/5/QtConcurrent
$ install_name_tool -change /usr/local/Cellar/qt@5/5.15.2/plugins/platforms/libqcocoa.dylib @rpath/../PlugIns/platforms/libqcocoa.dylib serialplot.app/Contents/Frameworks/QtPrintSupport.framework/Versions/5/QtPrintSupport
$ install_name_tool -change /usr/local/Cellar/qt@5/5.15.2/plugins/platforms/libqcocoa.dylib @rpath/../PlugIns/platforms/libqcocoa.dylib serialplot.app/Contents/Frameworks/QtOpenGL.framework/Versions/5/QtOpenGL

All done!!!!!

Note: (platform) plugins do not show up using otool -L, so this is why otool -L has already been run. Running it again will not show different results.

Now the application should be portable.

This is the end, my friend

Leave a comment