[Development] Puzzled by desktop development priorities, Mac OS specifically [Warning: Rant]

Rutledge Shawn Shawn.Rutledge at digia.com
Tue Aug 6 13:41:41 CEST 2013


> Le mardi 6 août 2013, Rutledge Shawn a écrit :
> 
> On 6 Aug 2013, at 9:57 AM, qtnext wrote:
> 
> > I always package the qml in a ressource file. That is not the issue
> 
> Well the makefile generated by qmake can build a complete .app bundle, with an icon too.  So what extra functionality do you need from macdeployqt?

On 6 Aug 2013, at 10:54 AM, qtnext wrote:

> I don't need macdeployqt to build a complete .app ? I come from windows so mac dev is for me a little bit exotic and i was sure that i need macdeployqt ? How can i create a complete file with qmake ? From qt creator? Or command line ?

Either way.  examples/quick/demos/photosurface and examples/quick/window both have mac icons etc. so you can just go into the directory, qmake and make.  The .pro has

macx: ICON = resources/icon.icns

The icon file was created with Icon Composer which ships with Xcode (I think?).  The qrc file lists all the qml files.  We can see what's in the app bundle:

$ find photosurface.app/
photosurface.app/
photosurface.app//Contents
photosurface.app//Contents/Info.plist
photosurface.app//Contents/MacOS
photosurface.app//Contents/MacOS/photosurface
photosurface.app//Contents/PkgInfo
photosurface.app//Contents/Resources
photosurface.app//Contents/Resources/empty.lproj
photosurface.app//Contents/Resources/photosurface.icns

OK no libraries, so I guess that's what you need the deployment tool for, as Thiago said.  

$ otool -L photosurface.app/Contents/MacOS/photosurface
photosurface.app/Contents/MacOS/photosurface:
	/Users/rutledge/Qt//5.1.0/clang_64/lib/QtQuick.framework/Versions/5/QtQuick (compatibility version 5.1.0, current version 5.1.0)
	/Users/rutledge/Qt//5.1.0/clang_64/lib/QtQml.framework/Versions/5/QtQml (compatibility version 5.1.0, current version 5.1.0)
	/Users/rutledge/Qt//5.1.0/clang_64/lib/QtNetwork.framework/Versions/5/QtNetwork (compatibility version 5.1.0, current version 5.1.0)
	/Users/rutledge/Qt//5.1.0/clang_64/lib/QtCore.framework/Versions/5/QtCore (compatibility version 5.1.0, current version 5.1.0)
	/Users/rutledge/Qt//5.1.0/clang_64/lib/QtGui.framework/Versions/5/QtGui (compatibility version 5.1.0, current version 5.1.0)
	/Users/rutledge/Qt//5.1.0/clang_64/lib/QtWidgets.framework/Versions/5/QtWidgets (compatibility version 5.1.0, current version 5.1.0)
	/System/Library/Frameworks/OpenGL.framework/Versions/A/OpenGL (compatibility version 1.0.0, current version 1.0.0)
	/System/Library/Frameworks/AGL.framework/Versions/A/AGL (compatibility version 1.0.0, current version 1.0.0)
	/usr/lib/libstdc++.6.dylib (compatibility version 7.0.0, current version 56.0.0)
	/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 169.3.0)

It links to libraries on my system so the .app isn't portable.

$ macdeployqt photosurface.app

$ find photosurface.app/
photosurface.app/
photosurface.app//Contents
photosurface.app//Contents/Frameworks
photosurface.app//Contents/Frameworks/QtCore.framework
photosurface.app//Contents/Frameworks/QtCore.framework/Resources
photosurface.app//Contents/Frameworks/QtCore.framework/Versions
photosurface.app//Contents/Frameworks/QtCore.framework/Versions/5
photosurface.app//Contents/Frameworks/QtCore.framework/Versions/5/QtCore
photosurface.app//Contents/Frameworks/QtGui.framework
photosurface.app//Contents/Frameworks/QtGui.framework/Resources
photosurface.app//Contents/Frameworks/QtGui.framework/Versions
photosurface.app//Contents/Frameworks/QtGui.framework/Versions/5
photosurface.app//Contents/Frameworks/QtGui.framework/Versions/5/QtGui
photosurface.app//Contents/Frameworks/QtNetwork.framework
photosurface.app//Contents/Frameworks/QtNetwork.framework/Resources
photosurface.app//Contents/Frameworks/QtNetwork.framework/Versions
photosurface.app//Contents/Frameworks/QtNetwork.framework/Versions/5
photosurface.app//Contents/Frameworks/QtNetwork.framework/Versions/5/QtNetwork
photosurface.app//Contents/Frameworks/QtPrintSupport.framework
photosurface.app//Contents/Frameworks/QtPrintSupport.framework/Resources
photosurface.app//Contents/Frameworks/QtPrintSupport.framework/Versions
photosurface.app//Contents/Frameworks/QtPrintSupport.framework/Versions/5
photosurface.app//Contents/Frameworks/QtPrintSupport.framework/Versions/5/QtPrintSupport
photosurface.app//Contents/Frameworks/QtQml.framework
photosurface.app//Contents/Frameworks/QtQml.framework/Resources
photosurface.app//Contents/Frameworks/QtQml.framework/Versions
photosurface.app//Contents/Frameworks/QtQml.framework/Versions/5
photosurface.app//Contents/Frameworks/QtQml.framework/Versions/5/QtQml
photosurface.app//Contents/Frameworks/QtQuick.framework
photosurface.app//Contents/Frameworks/QtQuick.framework/Resources
photosurface.app//Contents/Frameworks/QtQuick.framework/Versions
photosurface.app//Contents/Frameworks/QtQuick.framework/Versions/5
photosurface.app//Contents/Frameworks/QtQuick.framework/Versions/5/QtQuick
photosurface.app//Contents/Frameworks/QtV8.framework
photosurface.app//Contents/Frameworks/QtV8.framework/Resources
photosurface.app//Contents/Frameworks/QtV8.framework/Versions
photosurface.app//Contents/Frameworks/QtV8.framework/Versions/5
photosurface.app//Contents/Frameworks/QtV8.framework/Versions/5/QtV8
photosurface.app//Contents/Frameworks/QtWidgets.framework
photosurface.app//Contents/Frameworks/QtWidgets.framework/Resources
photosurface.app//Contents/Frameworks/QtWidgets.framework/Versions
photosurface.app//Contents/Frameworks/QtWidgets.framework/Versions/5
photosurface.app//Contents/Frameworks/QtWidgets.framework/Versions/5/QtWidgets
photosurface.app//Contents/Info.plist
photosurface.app//Contents/MacOS
photosurface.app//Contents/MacOS/photosurface
photosurface.app//Contents/PkgInfo
photosurface.app//Contents/PlugIns
photosurface.app//Contents/PlugIns/accessible
photosurface.app//Contents/PlugIns/accessible/libqtaccessiblequick.dylib
photosurface.app//Contents/PlugIns/accessible/libqtaccessiblewidgets.dylib
photosurface.app//Contents/PlugIns/imageformats
photosurface.app//Contents/PlugIns/imageformats/libqgif.dylib
photosurface.app//Contents/PlugIns/imageformats/libqico.dylib
photosurface.app//Contents/PlugIns/imageformats/libqjpeg.dylib
photosurface.app//Contents/PlugIns/imageformats/libqmng.dylib
photosurface.app//Contents/PlugIns/imageformats/libqtga.dylib
photosurface.app//Contents/PlugIns/imageformats/libqtiff.dylib
photosurface.app//Contents/PlugIns/imageformats/libqwbmp.dylib
photosurface.app//Contents/PlugIns/platforms
photosurface.app//Contents/PlugIns/platforms/libqcocoa.dylib
photosurface.app//Contents/PlugIns/printsupport
photosurface.app//Contents/PlugIns/printsupport/libcocoaprintersupport.dylib
photosurface.app//Contents/Resources
photosurface.app//Contents/Resources/empty.lproj
photosurface.app//Contents/Resources/photosurface.icns
photosurface.app//Contents/Resources/qt.conf

So it copied the frameworks in place, good.  But otool still says it links against libs in my home dir installation.  That can be fixed by hand:

install_name_tool -change "/Users/rutledge/Qt//5.1.0/clang_64/lib/QtQuick.framework/Versions/5/QtQuick" "photosurface.app/Contents/Frameworks/QtQuick.framework/Versions/5/QtQuick" photosurface.app/Contents/MacOS/photosurface
install_name_tool -change "/Users/rutledge/Qt//5.1.0/clang_64/lib/QtQml.framework/Versions/5/QtQml" "photosurface.app/Contents/Frameworks/QtQml.framework/Versions/5/QtQml" photosurface.app/Contents/MacOS/photosurface
install_name_tool -change "/Users/rutledge/Qt//5.1.0/clang_64/lib/QtNetwork.framework/Versions/5/QtNetwork" "photosurface.app/Contents/Frameworks/QtNetwork.framework/Versions/5/QtNetwork" photosurface.app/Contents/MacOS/photosurface
install_name_tool -change "/Users/rutledge/Qt//5.1.0/clang_64/lib/QtCore.framework/Versions/5/QtCore" "photosurface.app/Contents/Frameworks/QtCore.framework/Versions/5/QtCore" photosurface.app/Contents/MacOS/photosurface
install_name_tool -change "/Users/rutledge/Qt//5.1.0/clang_64/lib/QtGui.framework/Versions/5/QtGui" "photosurface.app/Contents/Frameworks/QtGui.framework/Versions/5/QtGui" photosurface.app/Contents/MacOS/photosurface
install_name_tool -change "/Users/rutledge/Qt//5.1.0/clang_64/lib/QtWidgets.framework/Versions/5/QtWidgets" "photosurface.app/Contents/Frameworks/QtWidgets.framework/Versions/5/QtWidgets" photosurface.app/Contents/MacOS/photosurface

but then each framework still depends on other frameworks at hardcoded paths:

$ otool -L photosurface.app/Contents/Frameworks/QtQuick.framework/Versions/5/QtQuick
photosurface.app/Contents/Frameworks/QtQuick.framework/Versions/5/QtQuick:
	@executable_path/../Frameworks/QtQuick.framework/Versions/5/QtQuick (compatibility version 5.1.0, current version 5.1.0)
	/Users/rutledge/Qt//5.1.0/clang_64/lib/QtQml.framework/Versions/5/QtQml (compatibility version 5.1.0, current version 5.1.0)
	/Users/rutledge/Qt//5.1.0/clang_64/lib/QtNetwork.framework/Versions/5/QtNetwork (compatibility version 5.1.0, current version 5.1.0)
	/Users/rutledge/Qt//5.1.0/clang_64/lib/QtCore.framework/Versions/5/QtCore (compatibility version 5.1.0, current version 5.1.0)
	/Users/rutledge/Qt//5.1.0/clang_64/lib/QtGui.framework/Versions/5/QtGui (compatibility version 5.1.0, current version 5.1.0)
	/Users/rutledge/Qt//5.1.0/clang_64/lib/QtV8.framework/Versions/5/QtV8 (compatibility version 5.1.0, current version 5.1.0)
	/System/Library/Frameworks/OpenGL.framework/Versions/A/OpenGL (compatibility version 1.0.0, current version 1.0.0)
	/System/Library/Frameworks/AGL.framework/Versions/A/AGL (compatibility version 1.0.0, current version 1.0.0)
	/usr/lib/libstdc++.6.dylib (compatibility version 7.0.0, current version 52.0.0)
	/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 159.1.0)

so yeah that's the stuff that macdeployqt should be taking care of, and isn't.

Rene's script is for Qt 4.  (Kudos on the egrep/awk bit especially.)  I updated it for Qt 5 as follows:

#!/bin/bash
QT_INSTALL_QML=`qmake -query QT_INSTALL_QML`
rsync -avP $QT_INSTALL_QML/ photosurface.app/Contents/MacOS/
function fixpaths {
       QTLIBS=`otool -L $1 | egrep ".*Qt.*framework.*Qt.*" | awk '{ print $1 }'`
       echo "in $1 QTLIBS=" $QTLIBS
       for j in $QTLIBS; do
               qtlib=""
               for k in $(echo $j | tr "/" " "); do
                       qtlib=$k
               done
               install_name_tool -change $j @executable_path/../Frameworks/$qtlib.framework/Versions/5/$qtlib $1
       done
}
for i in `find $1/Contents/MacOS -type f`; do
	fixpaths $i
done
for i in `find $1/Contents/Frameworks -type f`; do
	fixpaths $i
done
for i in `find $1/Contents -name "*.dylib"`; do
	fixpaths $i
done


and now I can build an apparently portable version of the photosurface app like this:

$ rm -rf *.app; make; macdeployqt photosurface.app; ./post-macdeployqt.sh photosurface.app

The rsync step is overkill: it will copy all of Qt Quick Controls, Qt Sensors, Qt Webkit, etc. into this application, but it doesn't use them.  The total app bundle is now 38.6 MB (!) of which about 9 MB is QtQuick imports, most of which I don't need.  macdeployqt could try to find the dependencies and install them, but that would amount to looking for imports in your QML, and then looking for dependencies that those imports import, etc.  And the qml isn't so readily available inside the .app since it's a resource in the executable.  So this seems to be still a bit of a sticky problem.  (Disclaimer: I haven't tried to read and understand what macdeployqt actually does; so it's possible that it just needs minor fixes.)




More information about the Development mailing list