Home > Mobile >  Building and distributing a MacOS application using CMake
Building and distributing a MacOS application using CMake

Time:07-28

I think this question has been asked a lot of times but I could not find a solution that works for me.

I have a CMake project for a desktop application, written in C , that uses some libraries (Qt and OpenCV). I developed the project under Windows, but I want to build it for MacOS. To do that, I installed the necessary libraries using brew and I use them in my project using the find_package cmake command.

Everything works fine, but my problem is that I couldn't manage to successfully run my project on another MacOS computer because the libraries are missing (.dylib).

On Windows, I use windeployqt and then I copy the remaining opencv into the executable folder by hand and this works. On MacOS, from what I understood, this is not the case and you have to use install_name_tool to edit the executable with the correct paths.

I tried using macdeployqt that authomatically copies all the necessary libraries into the app bundle (*.app folder) and edits the executable libraries paths.
One problem I encountered is that the OpenCV libraries that are copied into the bundle are linked to the system installed ones. To solve this problem, I wrote a script that runs install_name_tool on every OpenCV library, this solved the issue, but I'm not sure this is the best way of doing it.

Unfortunately, I had another problem I couldn't solve: macdeployqt didn't deploy all the necessary frameworks, and, for some reason, the Qt QDBus framework is missing.

Maybe I am taking the wrong path? I've never used MacOS before, and I'm not sure this is the correct way of building desktop applications. Is there any example project I can use as a reference?

P.s. I'm not using XCode, I just build my project in the terminal using the cmake tool.

Edit

This is an example project I use.

CMakeLists.txt:

cmake_minimum_required(VERSION 3.20)
project(example LANGUAGES CXX)

# find libraries
find_package(OpenCV REQUIRED)
find_package(Qt6 COMPONENTS Widgets Gui OpenGL OpenGLWidgets Multimedia MultimediaWidgets PrintSupport Charts REQUIRED)

add_executable(some_executable)
target_sources(some_executable PRIVATE "main.cpp")

# tel CMake to create a bundle
# see https://doc.qt.io/qt-6/macos-deployment.html
set_target_properties(some_executable PROPERTIES MACOSX_BUNDLE TRUE)

# link libraries
# some opencv libs I use
target_link_libraries(some_executable PRIVATE opencv_core opencv_xfeatures2d opencv_videoio opencv_highgui opencv_video)
# some Qt libs I use
target_link_libraries(some_executable PRIVATE Qt6::Widgets Qt6::Multimedia Qt6::MultimediaWidgets Qt6::PrintSupport Qt6::Charts)

main.cpp

#include <QApplication>
#include <QLabel>
int main(int argc, char** argv) {
    QApplication app(argc, argv);
    QLabel hello;
    hello.setText("Hello There!");
    hello.show();
    return app.exec();
}

deploy.sh

echo Deploying MacOS bundle...

# use this to see the linked libraries
# otool -l some_executable.app/Contents/MacOS/some_executable

# use macreployqt to deploy the necessary libraries and frameworks
macdeployqt some_executable.app

FRAMEWORKS_PATH=some_executable.app/Contents/Frameworks

# wrong: OPENCV_LIB_PATH=/usr/local/Cellar/opencv/4.5.5_2/lib
OPENCV_LIB_PATH=@rpath
OPENCV_VER=405 # <- change this to match the opecv version

echo editing opencv paths...

OPENCV_LIBS=(
"libopencv_calib3d"
"libopencv_core"
"libopencv_dnn"
"libopencv_features2d"
"libopencv_flann"
"libopencv_highgui"
"libopencv_imgcodecs"
"libopencv_imgproc"
"libopencv_ml"
"libopencv_shape"
"libopencv_video"
"libopencv_videoio"
"libopencv_xfeatures2d"
)

replace_opencv_lib_path() {
    # the library to patch
    LIB=$1

    # the linked library
    TO_REPLACE=$2

    install_name_tool -change ${OPENCV_LIB_PATH}/${TO_REPLACE}.${OPENCV_VER}.dylib @executable_path/../Frameworks/${TO_REPLACE}.${OPENCV_VER}.dylib $FRAMEWORKS_PATH/$LIB.${OPENCV_VER}.dylib
}

for lib in ${OPENCV_LIBS[@]}; do
    for lib2 in ${OPENCV_LIBS[@]}; do
        replace_opencv_lib_path $lib $lib2
    done
done

An then I run these commands:

# configure the project
cmake .

# build the project
cmake --build .

# deploy
sudo /bin/sh deploy.sh

# create a DMG file we can test on another computer
sudo macdeployqt some_executable.app -dmg

CodePudding user response:

I just figured that macdeployqt was not deploying the Qt D-Bus framework. To solve the problem, explicitly add the dependency in the CMake file.

So, the solution is to use the code I posted, but link Qt::DBus in the CMakeLists.txt:

...
find_package(Qt6 COMPONENTS ... DBus REQUIRED)
...
target_link_libraries(some_executable PRIVATE Qt6::DBus)

Then everything works fine.

  • Related