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 toqwt
. - 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:
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.
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/
.
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