Qt provides an extremely simple mechanism for deploying applications on macOS, thanks to macdeployqt tool. Unfortunately, the same does not apply to Qt for macOS applications that reference 3rd party libraries such as OpenCV. In this post, I’ll describe the manual but simple process of adding 3rd party libraries into macOS Application packages in order to eliminate the need for installing those libraries on our target computers.
Let’s assume you’ve used the following lines (or something similar) in your Qt Project (*.pro file) file to include OpenCV in your Qt application:
macx {
INCLUDEPATH += "/path_to_opencv/include"
LIBS += -L"/path_to_opencv/lib" \
-l"opencv_world"
}
In this example, I’ve assumed OpenCV was built with BUILD_opencv_world option set to TRUE (checked during CMake configuration), in order to deal with as few libraries as possible. But this is just for the sake of simplicity in explaining how it’s done, so you can in fact use the same instructions in this post to add any number of 3rd party libraries to your macOS application.
Now, the first thing we need to do after our application is built, is to use macdeployqt tool to include all Qt libraries in our application. Just fire up a Terminal window and use a command similar to the following in order to achieve what we just mentioned:
macdeployqt Example.app
Obviously, Example.app needs to be replaced with the actual name of your application. See macdeployqt documentation for further customization of how this tool is used and what parameters can be passed to it since what we’ve used above is the most simple use case.
The next step, is to copy OpenCV libraries (or single World library) into the application package. In order to do this, you need to copy OpenCV *.dylib file into the following folder under application package:
Example.app/Contents/Frameworks
Make sure you copy the library files and not their aliases into the preceding folder.
Now what you need to do, is to list the dependencies of your Qt Application’s binary executable file. The binary is located in the following folder in your application package:
Example.app/Contents/MacOS
Let’s say your binary file is also called Example, in this case the following file will be your application’s executable binary:
Example.app/Contents/MacOS/Example
In terminal, just cd to this folder and use otool to get the list of the dependencies, as seen here:
cd Example.app/Contents/MacOS
otool -L Example
This will output a list of library dependencies similar to the following:
@rpath/libopencv_world.#.#.dylib (compatibility version #.#.#, current version #.#.#)
@rpath/QtWidgets.framework/Versions/5/QtWidgets (compatibility version #.#.#, current version #.#.#)
@rpath/QtGui.framework/Versions/5/QtGui (compatibility version #.#.#, current version #.#.#)
@rpath/QtCore.framework/Versions/5/QtCore (compatibility version #.#.#, current version #.#.#)
...
What you need to do next, is to update the OpenCV entry (or entries) in the preceding list in order for your application to use the ones you copied into the Frameworks folder instead. This can be done by using install_name_tool as seen here:
install_name_tool -change @rpath/libopencv_world.#.#.dylib @executable_path/../Frameworks/libopencv_world.#.#.#.dylib Example
This should take care of the required dependency path change but to confirm, you can run the following command once again:
otool -L Example
Which should produce and output like this:
@executable_path/../Frameworks/libopencv_world.#.#.#.dylib (compatibility version #.#.#, current version #.#.#)
@rpath/QtWidgets.framework/Versions/5/QtWidgets (compatibility version #.#.#, current version #.#.#)
@rpath/QtGui.framework/Versions/5/QtGui (compatibility version #.#.#, current version #.#.#)
@rpath/QtCore.framework/Versions/5/QtCore (compatibility version #.#.#, current version #.#.#)
Notice the change in the first entry. Now try to run your application and it should have all the necessary dependencies (both Qt and OpenCV libraries) inside the application package itself.