#1250

Building for iOS errors and some solutions

Opengambhiroopened 1y ago

UPDATE 2025-12-17: Most of the text below documents errors and approaches which didn't work.

The key changes are at the end about the framework path, and having to build twice, first with MacOS SDK path and then with iOS SDK path in shell variables. I don't know how to avoid that.

Trying another iOS build recently using Qt 6.9.3 and iOS 26.2 SDK, thinning with lipo was no longer necessary.

(Note: Qt 6.10.1 had weird UI errors but Qt 6.9.3 worked)


Thanks for the cool project! I started to port an app to CXX-Qt so that I can build it for Android and iOS.

After setting up XCode and Qt Creator, I successfully compiled a "Hello World" app on a MacOS machine and deployed it to an iPad.

(This tutorial was helpful: How to develop a simple Qt app for iPad?)

Qt is installed to ~/Qt/ using their official open source online installer.

At this point my project is very similar to the qml_minimal example.

When trying to build it for iOS, a few errors I was able to solve:

Error: building for 'iOS', but linking in object file ... built for 'macOS'

Have to set the correct Rust target and qmake path in CMakeLists.txt:

if (IOS)
    set(Rust_CARGO_TARGET aarch64-apple-ios)
    set(qmake_path "$ENV{HOME}/Qt/6.8.3/ios/bin/qmake6")
endif()

cxx_qt_import_crate(
    MANIFEST_PATH rust/Cargo.toml
    CRATES simsapa_lib
    LOCKED
    QMAKE ${qmake_path}

    QT_MODULES ...
)

Error: linking with cc failed

error: linking with `cc` failed: exit status: 1
...
  = note: ld: library not found for -lSystem
          clang: error: linker command failed with exit code 1 (use -v to see invocation)

The solution was in this article: Brain Detour - Rust and macOS compilation / linking issue

Have to add this to ~/.zshrc:

export PATH=$PATH:/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib
export LIBRARY_PATH=$LIBRARY_PATH:/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib

Error: Could not open ios ... QtCore.prl file to read libraries to link

In the Qt ios framework folders, the .prl files are under Versions/A/Resources.

I changed that path in qt-build-utils/src/lib.rs directly, but I think it should test somehow when building for ios.

diff --git a/crates/qt-build-utils/src/lib.rs b/crates/qt-build-utils/src/lib.rs
index 7f3a3900..be38cf2b 100644
--- a/crates/qt-build-utils/src/lib.rs
+++ b/crates/qt-build-utils/src/lib.rs
@@ -527,7 +527,7 @@ impl QtBuild {
             let (link_lib, prl_path) = if framework {
                 (
                     format!("framework=Qt{qt_module}"),
-                    format!("{lib_path}/Qt{qt_module}.framework/Resources/Qt{qt_module}.prl"),
+                    format!("{lib_path}/Qt{qt_module}.framework/Versions/A/Resources/Qt{qt_module}.prl"),
                 )
             } else {
                 (

Error: ... QtGui.framework/QtGui found in .prl file for Qt6Gui, but could not extract library base name to pass to linker command line

The .prl contained no form of the library with .a or other suffix, e.g.:

cat QtWidgets.framework/Versions/A/Resources/QtWidgets.prl
...
$$[QT_INSTALL_LIBS]/QtWidgets.framework/QtWidgets
...

You can see in this commit that in parse_cflags.rs I changed it to return the name without the suffix.

It seems to be a quick hack but I don't know how to make it more sophisticated for the correct context.

Error: include/cxx-qt/connection.h:9:10: fatal error: 'QtCore/QObject' file not found

warning: cxx-qt@0.7.1: In file included from src/connection.cpp:7:
warning: cxx-qt@0.7.1: /Users/sumedharama/prods/simsapa-ng-project/simsapa-ng/build/Qt_6_8_3_for_iOS/Debug/cargo/build/aarch64-apple-ios/debug/build/cxx-qt-76d4b2d0e25e8372/out/cxx-qt-build/target/crates/cxx-qt/include/cxx-qt/connection.h:9:10: fatal error: 'QtCore/QObject' file not found
warning: cxx-qt@0.7.1:     9 | #include <QtCore/QObject>
warning: cxx-qt@0.7.1:       |          ^~~~~~~~~~~~~~~~

...

warning: cxx-qt@0.7.1: In file included from /Users/sumedharama/Qt/6.8.3/ios/lib/QtCore.framework/Headers/QtGlobal:1:
warning: cxx-qt@0.7.1: /Users/sumedharama/Qt/6.8.3/ios/lib/QtCore.framework/Headers/qglobal.h:24:10: fatal error: 'QtCore/qtversionchecks.h' file not found
warning: cxx-qt@0.7.1:    24 | #include <QtCore/qtversionchecks.h>
warning: cxx-qt@0.7.1:       |          ^~~~~~~~~~~~~~~~~~~~~~~~~~

Update:

It turns out that the cc-rs builder.flag_if_supported() didn't include the -F framework paths on iOS. Changing it to builder.flag() solved this error.

for framework_path in self.framework_paths() {
    // NOTE: builder.flag_if_supported() doesn't work when building for iOS.
    builder.flag(format!("-F{}", framework_path.display()));
    // Also set the -rpath otherwise frameworks can not be found at runtime
    println!(
        "cargo::rustc-link-arg=-Wl,-rpath,{}",
        framework_path.display()
    );
}

Activity

2
gambhiro1y ago

Continuing:

Error: failed to add native library ... libcxx-qt-cxxqt-generated.a: Unsupported archive identifier

The next error was due to the libraries being generated as universal 'fat' libs (including both arm64 and x86_64 I suppose).

warning: cxx-qt@0.7.1: warning: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ranlib: archive library: /Users/sumedharama/prods/simsapa-ng-project/simsapa-ng/build/Qt_6_8_3_for_iOS/Debug/cargo/build/aarch64-apple-ios/debug/build/cxx-qt-76d4b2d0e25e8372/out/libcxx-qt-call-init-crate_cxx_qt.a the table of contents is empty (no object file members in the library define global symbols)
warning: cxx-qt@0.7.1: warning: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ranlib: archive library: /Users/sumedharama/prods/simsapa-ng-project/simsapa-ng/build/Qt_6_8_3_for_iOS/Debug/cargo/build/aarch64-apple-ios/debug/build/cxx-qt-76d4b2d0e25e8372/out/libcxx-qt-cxxqt-generated.a will be fat and ar(1) will not be able to operate on it
warning: cxx-qt@0.7.1: warning: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ranlib: archive library: /Users/sumedharama/prods/simsapa-ng-project/simsapa-ng/build/Qt_6_8_3_for_iOS/Debug/cargo/build/aarch64-apple-ios/debug/build/cxx-qt-76d4b2d0e25e8372/out/libcxx-qt-cxxqt-generated.a for architecture: x86_64 the table of contents is empty (no object file members in the library define global symbols)
error: failed to add native library /Users/sumedharama/prods/simsapa-ng-project/simsapa-ng/build/Qt_6_8_3_for_iOS/Debug/cargo/build/aarch64-apple-ios/debug/build/cxx-qt-76d4b2d0e25e8372/out/libcxx-qt-cxxqt-generated.a: Unsupported archive identifier

The generated build script was already calling cargo with CARGO_TARGET_AARCH64_APPLE_IOS_LINKER and --target=aarch64-apple-ios.

The only thing which worked was to add a step to the build.rs files (of cxx-qt, cxx-qt-lib and the project being built) to use the lipo tool to 'thin' the generated lib files.

thin_generated_fat_library_with_lipo()

Using lipo in the build scripts worked.

Error: ld: building for 'iOS', but linking in dylib (.../libz.1.tbd) built for 'macOS macCatalyst zippered(macOS/Catalyst)'

The problem is that the wrong (MacOS SDK) libz.1.tbd is picked up from the LIBRARY_PATH that I had set earlier in .zshrc.

Some details of investigation:

The correct -isysroot path is already set in the generated clang command:

/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang++ -Xlinker -reproducible -target arm64-apple-ios16 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS18.4.sdk ...

In CMakeLists.txt:

set(ENV{RUSTFLAGS} "-C link-args=-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS18.4.sdk")

Had removed this warning:

ld: warning: <rdar://113405968> building for 'iOS', but linking in dylib (/Library/Developer/CommandLineTools/SDKs/MacOSX14.4.sdk/usr/lib/libSystem.B.tbd) built for 'macOS macCatalyst zippered(macOS/Catalyst)'

But another still caused clang to fail:

ld: building for 'iOS', but linking in dylib (/Library/Developer/CommandLineTools/SDKs/MacOSX14.4.sdk/usr/lib/libz.1.tbd) built for 'macOS macCatalyst zippered(macOS/Catalyst)'
clang++: error: linker command failed with exit code 1 (use -v to see invocation)

Trying to add -C link-args=-Wl,-syslibroot,/Applications/.../iPhoneOS18.4.sdk to the RUSTFLAGS either in CMakeLists.txt or .cargo/config.toml had no effect.

Getting the build to succeed

These steps produced a successful iOS build.

(1) Remove the project's build/ folder and CMakeLists.txt.user file if exists.

(2) Add this in .zshrc:

MACOS_SDK_CLI="/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib"
IOS_SDK_DEV="/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS18.4.sdk/usr/lib"

export PATH=$MACOS_SDK_CLI:$PATH
export LIBRARY_PATH=$MACOS_SDK_CLI:$LIBRARY_PATH
# export LIBRARY_PATH=$IOS_SDK_DEV:$LIBRARY_PATH

(3) Start Qt Creator from a new terminal session.

$ ./Qt/Qt \Creator.app/Contents/MacOS/Qt\ Creator

Configure Project > Enable the Qt kit for iOS

(4) Build for iOS. This will fail with:

ld: warning: <rdar://113405968> building for 'iOS', but linking in dylib (/Library/Developer/CommandLineTools/SDKs/MacOSX14.4.sdk/usr/lib/libSystem.B.tbd) built for 'macOS macCatalyst zippered(macOS/Catalyst)'
ld: warning: <rdar://113405968> building for 'iOS', but linking in dylib (/Library/Developer/CommandLineTools/SDKs/MacOSX14.4.sdk/usr/lib/libSystem.B.tbd) built for 'macOS macCatalyst zippered(macOS/Catalyst)'
ld: building for 'iOS', but linking in dylib (/Library/Developer/CommandLineTools/SDKs/MacOSX14.4.sdk/usr/lib/libz.1.tbd) built for 'macOS macCatalyst zippered(macOS/Catalyst)'
clang++: error: linker command failed with exit code 1 (use -v to see invocation)

(5) Exit Qt Creator, change LIBRARY_PATH in .zshrc:

# export LIBRARY_PATH=$MACOS_SDK_CLI:$LIBRARY_PATH
export LIBRARY_PATH=$IOS_SDK_DEV:$LIBRARY_PATH

(6) In a new terminal, start Qt Creator, build for iOS again.

** BUILD SUCCEEDED **

And the app deploys to the iPad.

This is a crazy weird dance but I repeated it and is reproducible, however I don't know how to improve on it.

At least it shows that building for iOS is possible.

gambhiro10mo ago

The key changes are at the end about the framework path, and having to build twice, first with MacOS SDK path and then with iOS SDK path in shell variables. I don't know how to avoid that.

Trying another iOS build recently using Qt 6.9.3 and iOS 26.2 SDK, thinning with lipo was no longer necessary.

(Note: Qt 6.10.1 had weird UI errors but Qt 6.9.3 worked)