Run-time error for Qt application on ios built via

2019-05-05 06:43发布

问题:

Hi stackoverflowers :)

If I build a Qt/qmake sample project (in my case the "analog clock" example) and deploy it to a device running iOS 7.1 everything goes smooth: the app executes flawlessly on the device. Chapeau - the folks from digia did a formidable job to integrate the ios toolchain into their Qt workflow.

However, if I translate the qmake project into a CMake project, things don't go that smooth anymore. I've attached the analog clock example from the Qt-5.3.1 release (see below) where I added a CMakeLists.txt and a script that runs CMake to generate an XCode project for iOS. The project compiles and even links (I had to add some additional link libraries, see CMake source file). Yay.

But here's the trap: The app crashes at run-time with the following error message:

Error: Failed to load platform plugin “ios”

As a comment in this thread states one has to "force load" libqios via the project settings. Doing this didn't improve the situation much, it only changed the error message to:

Error: You are creating QApplication before calling UIApplicationMain. If you are writing a native iOS application, and only want to use Qt for parts of the application, a good place to create QApplication is from within 'applicationDidFinishLaunching' inside your UIApplication delegate.

I have two questions:

  • Does anyone have an idea what the problem is with the run-time errors? I know that qmake (and the corresponding ios mkspecs) do quite some magic. But how to translate that to CMake?
  • Why do I have to link several libs (harfbuzzng, qios, libpng, and several iOS frameworks) manually to my target? Shouldn't find_package(Qt5 ...) do this job for me?

Here is the link to a zip file containing my Qt-CMake project. The Qt version I'm using is Qt-5.3.1 for iOS.

Edit: I found out that the qmake sample doesn't work just like this if you tear it out of the Qt examples folder structure. Look at the Qt example directly: path/to/Qt/examples/widgets/widgets/analogclock.

回答1:

After a few hours of digging around I found a way how to create a CMake project for my Qt application for iOS. The key hints I got via Google and by checking the output generated by qmake. I found the scripts that actually do the whole magic and applied parts of it to my CMake sources.

This is the recipe that worked for me. For the sake of completeness, I added also the steps that I was already aware of when I posted above question:

  • Introduce CMake to the ios tool chain. See cmake/toolchain/ios.toolchain.cmake of my sample project. It sets several CMake properties and looks for the necessary tools and frameworks. (I don't recall anymore where I have that file from - but it is used in several other projects too if you Google for it.) You have to pass this setup file as an argument to CMake (see below).

  • Set several target properties of your executable to turn it into an (iOS) app bundle. Should be clear. Note that there's a template Info.plist.in that will be completed by CMake.

  • Fix 1: Link missing libraries and frameworks to the app manually in CMake. For some reason, find_package(Qt5 ...) doesn't return a complete list of dependencies. Very probable that I'm missing something here, though.

  • Fix 2: Make sure to force-load libqios in order to avoid the error message about the missing iOS plugin. In CMake:

    set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -force_load ${YOUR_QT_ROOT_PATH}/plugins/platforms/libqios.a" )

  • Fix 3: Remove the storyboard key in the Info.plist.in. This step I don't understand in detail. The means was inspired by this post on stackoverflow.

    <key>UIMainStoryboardFile</key> <string>main</string>

  • Fix 4: And now the cherry on the top: for iOS you have to rename the main() function with a corresponding "C" formatted version. Apparently, Qt comes with it's own main entry point and renames the one that you wrote as qtmn(). This qmake magic is performed by this script: your/qt/root/path/mkspecs/macx-ios-clang/rename_main.sh. I don't understand the complete mechanics behind this in detail. In my case, I was fine with renaming the function signature of main:

    // Replace... int main(int argc, char *argv[])

    // ... with this line: extern "C" int qtmn(int argc, char *argv[])

Here is again the same project I was referring to in the question, this time with the fixes applied from above. To build this project simply call build_ios.sh, and open the xcodeproj file that is created in the build folder.

Note: Working assumptions are that a correct version of XCode (5.1.1 in my case) is available and that you own a valid signing identity (change it in the CMakeLists.txt!). Furthermore, in my sample project (see below) I assume OpenCV built for iOS is available. I needed it to work around a linker problem: there were some objects missing from libpng that are shipped with OpenCV.

I hope this was helpful.



标签: c++ ios qt cmake qt5