Details
-
Bug
-
Resolution: Unresolved
-
P3: Somewhat important
-
None
-
6.5.3
-
None
Description
Deploying our Qt application takes several minutes which slows down CI integration and testing.
After tracing and profiling, It look like the macdeployqt tool performs unnecessary calls to otool and install_name_tool. These calls significantly add to the deployment time, especially when the main executable has many @rpath dependencies and the app bundle includes multiple plugins.
Two issues are relatively easy to fix:
- calls to install_name_tool -change with the same old and new @rpath parameters, which has no effect:
install_name_tool -change @rpath/QtCore.framework/Versions/A/QtCore @rpath/QtCore.framework/Versions/A/QtCore MyApp.app/Contents/MacOS/MyApp
- calls to otool -l multiple times on the same library, which could be cached to improve performance.
See the attached patches that:
- Skip install_name_tool when the old and new paths are identical.
- Add a simple cache for otool output.
With both patches applied, macdeployqt runs approximately three times faster on our application.
Another issue is, when using the -executable flag to specify a plugin dylib in the bundle, issue 1 does not occur since @loader_path is use. However, install_name_tool -change is still called with @rpath to other libraries that are not a dependency of the target:
install_name_tool -change @rpath/libfoo.dylib @loader_path/libfoo.dylib MyApp.app/Contents/Frameworks/libplugin.dylib
$ otool -L MyApp.app/Contents/Frameworks/libplugin.dylib | grep -c libfoo 0
It appears that all dependencies of every binaries are considered for name update on each target binary. May be it could check the actual dependencies of the target before invoking install_name_tool ?
To reproduce issues 1 and 2 with the example project from https://doc.qt.io/qt-6/macos-deployment.html#the-mac-deployment-tool:
cd qtbase/tests/manual/examples/widgets/tools/plugandpaint cmake -Bbuild -S . cmake --build build macdeployqt build/app/plugandpaint.app -verbose=3 2> macdeployqt.log
Inspect the log to see unnecessary install_name_tool calls:
$ grep -A3 'Using install_name_tool' macdeployqt.log | cut -f2 -d: | tail | sed 's/to /to /g' change reference "@rpath/QtQml.framework/Versions/A/QtQml" to "@rpath/QtQml.framework/Versions/A/QtQml" Using install_name_tool in "build/app/plugandpaint.app/Contents/PlugIns/platforminputcontexts/libqtvirtualkeyboardplugin.dylib" change reference "@rpath/QtNetwork.framework/Versions/A/QtNetwork" to "@rpath/QtNetwork.framework/Versions/A/QtNetwork" Using install_name_tool in "build/app/plugandpaint.app/Contents/PlugIns/platforminputcontexts/libqtvirtualkeyboardplugin.dylib" change reference "@rpath/QtCore.framework/Versions/A/QtCore" to "@rpath/QtCore.framework/Versions/A/QtCore"
Also, observe repeated otool calls on the same libraries:
grep -A1 'Using otool' macdeployqt.log | grep -o 'inspecting.*' | sort | uniq -c | sort -n | tail 2 inspecting "/opt/local/Qt/6.5.3/macos/lib/QtSvg.framework/Versions/A/QtSvg" 2 inspecting "/opt/local/Qt/6.5.3/macos/lib/QtVirtualKeyboard.framework/Versions/A/QtVirtualKeyboard" 3 inspecting "/opt/local/Qt/6.5.3/macos/lib/QtWidgets.framework/Versions/A/QtWidgets" 4 inspecting "/opt/local/Qt/6.5.3/macos/lib/QtQuick.framework/Versions/A/QtQuick" 6 inspecting "/opt/local/Qt/6.5.3/macos/lib/QtOpenGL.framework/Versions/A/QtOpenGL" 6 inspecting "/opt/local/Qt/6.5.3/macos/lib/QtQmlModels.framework/Versions/A/QtQmlModels" 8 inspecting "/opt/local/Qt/6.5.3/macos/lib/QtQml.framework/Versions/A/QtQml" 12 inspecting "/opt/local/Qt/6.5.3/macos/lib/QtNetwork.framework/Versions/A/QtNetwork" 43 inspecting "/opt/local/Qt/6.5.3/macos/lib/QtGui.framework/Versions/A/QtGui" 53 inspecting "/opt/local/Qt/6.5.3/macos/lib/QtCore.framework/Versions/A/QtCore"