iOS -ObjC link option leads to "duplicate symbol" for QtCore.framework
-
Im am working on porting my Qt app (with support for mac, iOS and Android) from Qt 5.15.17 to Qt 6.9 (which already worked out so far :D) and now from QMake using .pro files to CMake.
The initial cause for my problem was this error message when trying to call
"[FIRApp configure]" from my objective-c file application.mm:*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '+[NSData gul_dataByGzippingData:error:]: unrecognized selector sent to class 0x1f10f4610' *** First throw call stack: (0x188a725fc 0x185fed244 0x188bcb008 0x188a755c8 0x188a74ef0 0x1012ce1fc 0x1010cd7d4 0x1010cd60c 0x190806fa8 0x19080a45c 0x19081e620 0x19081d1e8 0x190818ec0 0x1908196c4 0x2137dc644 0x2137da474) libc++abi: terminating due to uncaught exception of type NSException
After a quick search I noted that this is possibly because I did not compile with "-ObjC" flag.
So I tried to do some modifications in my project:
1. I tried to use the flag "-ObjC" using this blocktarget_link_options(${PROJECT_NAME} PUBLIC -ObjC)
But when trying to compile, I receive a lot of errors like
Undefined symbols for architecture arm64: "__swift_FORCE_LOAD_$_swiftCompatibility50", referenced from: __swift_FORCE_LOAD_$_swiftCompatibility50_$_FirebaseCoreInternal in FirebaseCoreInternal[4](_ObjC_HeartbeatController.o) __swift_FORCE_LOAD_$_swiftCompatibility50_$_FirebaseCrashlytics in FirebaseCrashlytics[84](CrashlyticsRemoteConfigManager.o) __swift_FORCE_LOAD_$_swiftCompatibility50_$_FirebaseRemoteConfigInterop in FirebaseRemoteConfigInterop[4](RemoteConfigConstants.o) __swift_FORCE_LOAD_$_swiftCompatibility50_$_FirebaseSessions in FirebaseSessions[6](ApplicationInfo.o) __swift_FORCE_LOAD_$_swiftCompatibility50_$_Promises in Promises[4](Promise.o) __swift_FORCE_LOAD_$_swiftCompatibility50_$_GoogleMobileAds in GoogleMobileAds[arm64][430](GADMarketplaceKitSignals.o) __swift_FORCE_LOAD_$_swiftCompatibility50_$_FBAdMAISKOverlayManager in FBAudienceNetwork[4](FBAdMAISKOverlayManager.o) ... "__swift_FORCE_LOAD_$_swiftCompatibilityConcurrency", referenced from: __swift_FORCE_LOAD_$_swiftCompatibilityConcurrency_$_FirebaseCoreInternal in FirebaseCoreInternal[4](_ObjC_HeartbeatController.o) __swift_FORCE_LOAD_$_swiftCompatibilityConcurrency_$_FirebaseCrashlytics in FirebaseCrashlytics[84](CrashlyticsRemoteConfigManager.o) __swift_FORCE_LOAD_$_swiftCompatibilityConcurrency_$_FirebaseRemoteConfigInterop in FirebaseRemoteConfigInterop[4](RemoteConfigConstants.o) __swift_FORCE_LOAD_$_swiftCompatibilityConcurrency_$_FirebaseSessions in FirebaseSessions[6](ApplicationInfo.o) __swift_FORCE_LOAD_$_swiftCompatibilityConcurrency_$_FirebaseSharedSwift in FirebaseSharedSwift[4](FirebaseDataEncoder.o) __swift_FORCE_LOAD_$_swiftCompatibilityConcurrency_$_Promises in Promises[4](Promise.o) __swift_FORCE_LOAD_$_swiftCompatibilityConcurrency_$_GoogleMobileAds in GoogleMobileAds[arm64][430](GADMarketplaceKitSignals.o) ... "__swift_FORCE_LOAD_$_swiftCompatibilityDynamicReplacements", referenced from: __swift_FORCE_LOAD_$_swiftCompatibilityDynamicReplacements_$_FirebaseCoreInternal in FirebaseCoreInternal[4](_ObjC_HeartbeatController.o) __swift_FORCE_LOAD_$_swiftCompatibilityDynamicReplacements_$_FirebaseCrashlytics in FirebaseCrashlytics[84](CrashlyticsRemoteConfigManager.o) __swift_FORCE_LOAD_$_swiftCompatibilityDynamicReplacements_$_FirebaseRemoteConfigInterop in FirebaseRemoteConfigInterop[4](RemoteConfigConstants.o) __swift_FORCE_LOAD_$_swiftCompatibilityDynamicReplacements_$_FirebaseSessions in FirebaseSessions[6](ApplicationInfo.o) __swift_FORCE_LOAD_$_swiftCompatibilityDynamicReplacements_$_Promises in Promises[4](Promise.o) __swift_FORCE_LOAD_$_swiftCompatibilityDynamicReplacements_$_GoogleMobileAds in GoogleMobileAds[arm64][430](GADMarketplaceKitSignals.o) __swift_FORCE_LOAD_$_swiftCompatibilityDynamicReplacements_$_FBAdMAISKOverlayManager in FBAudienceNetwork[4](FBAdMAISKOverlayManager.o) ... ld: symbol(s) not found for architecture arm64 clang++: error: linker command failed with exit code 1 (use -v to see invocation)
2. Thats why I added the base swift directories to my linker settings using
target_link_directories(${PROJECT_NAME} PUBLIC "/usr/lib/swift" "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/iphoneos" )
But now this leads to a lot of duplicated symbol errors:
duplicate symbol '_OBJC_METACLASS_$_WeakPointerLifetimeTracker' in: /Users/user/Qt/6.9.0/ios/lib/QtCore.framework/QtCore[arm64][166](qcore_mac.mm.o) /Users/user/Qt/6.9.0/ios/lib/QtCore.framework/QtCore[arm64][166](qcore_mac.mm.o) /Users/user/Qt/6.9.0/ios/lib/QtCore.framework/QtCore[arm64][166](qcore_mac.mm.o) duplicate symbol '_OBJC_CLASS_$_RunLoopModeTracker' in: /Users/user/Qt/6.9.0/ios/lib/QtCore.framework/QtCore[arm64][168](qeventdispatcher_cf.mm.o) /Users/user/Qt/6.9.0/ios/lib/QtCore.framework/QtCore[arm64][168](qeventdispatcher_cf.mm.o) /Users/user/Qt/6.9.0/ios/lib/QtCore.framework/QtCore[arm64][168](qeventdispatcher_cf.mm.o) duplicate symbol 'AppleUnifiedLogger::messageHandler(QtMsgType, QMessageLogContext const&, QString const&, QString const&)' in: /Users/user/Qt/6.9.0/ios/lib/QtCore.framework/QtCore[arm64][166](qcore_mac.mm.o) /Users/user/Qt/6.9.0/ios/lib/QtCore.framework/QtCore[arm64][166](qcore_mac.mm.o) /Users/user/Qt/6.9.0/ios/lib/QtCore.framework/QtCore[arm64][166](qcore_mac.mm.o) ...
After a few days of research (and ChatGPTing like a vibe coder xD) I tried a lot of things but wasn't really able to solve this problem at all /
Am I missing something important here or doing anything completely wrong?3. I have created a new empty Test project and tried to dabble around with some flags and compiler properties to embed swift libraries like
XCODE_ATTRIBUTE_ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES
but the problem is the same :/ld: 98 duplicate symbols
clang++: error: linker command failed with exit code 1 (use -v to see invocation)cmake_minimum_required(VERSION 3.16) project(Test VERSION 1.00 LANGUAGES C CXX OBJC OBJCXX Swift) set(CMAKE_INCLUDE_CURRENT_DIR ON) # Set C++ standard (if needed) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(BUILD_SHARED_LIBS OFF) find_package(Qt6 REQUIRED COMPONENTS Quick) qt_standard_project_setup(REQUIRES 6.9) qt_add_executable(appTest main.cpp ) qt_add_qml_module(appTest URI Test VERSION 1.0 QML_FILES Main.qml ) # Qt for iOS sets MACOSX_BUNDLE_GUI_IDENTIFIER automatically since Qt 6.1. # If you are developing for iOS or macOS you should consider setting an # explicit, fixed bundle identifier manually though. set_target_properties(appTest PROPERTIES MACOSX_BUNDLE TRUE WIN32_EXECUTABLE TRUE # MACOSX_BUNDLE_GUI_IDENTIFIER com.example.appTest # MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/ios/Info.plist" MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION} MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} # Sign embedded frameworks # XCODE_EMBED_FRAMEWORKS_CODE_SIGN_ON_COPY ON # Embed Swift libraries # XCODE_ATTRIBUTE_ENABLE_BITCODE "NO" # XCODE_ATTRIBUTE_SWIFT_VERSION "5.6" XCODE_ATTRIBUTE_ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES "NO" # XCODE_ATTRIBUTE_LD_RUNPATH_SEARCH_PATHS "@executable_path/Frameworks" ) target_link_options(appTest PUBLIC -ObjC) # -lz -lswiftCompatibility51 -lswiftCompatibility56) # Link additional Library directory for swift support #target_link_directories(appTest PRIVATE # "/usr/lib/swift" # "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/iphoneos" #) target_link_libraries(appTest PRIVATE Qt6::Quick ) include(GNUInstallDirs) install(TARGETS appTest BUNDLE DESTINATION . LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} )
-
I actually found a solution to my problem :DDD
In fact this was a bug in Qt since 6.7.3:
https://bugreports.qt.io/browse/QTBUG-135978?gerritReviewStatus=Open
which now seems to be fixed https://codereview.qt-project.org/c/qt/qtbase/+/643588A workaround for now suggest here https://bugreports.qt.io/browse/QTBUG-132412
is toConfigure with cmake 3.29+ and the extra -DQT_FORCE_CMP0156_TO_NEW=ON option.
which I did by setting the policy in my root project cmake file right before find_package:
# Enable CMP0156 explicitly to prevent duplicate symbol errors when using -ObjC linker flag if (POLICY CMP0156) message(STATUS "Setting CMP0156 policy to NEW...") set(QT_FORCE_CMP0156_TO_NEW ON CACHE BOOL "Force CMake policy CMP0156 to NEW behavior for Qt6") elseif () message(ERROR "CMP0156 policy not available! Please switch to cmake 3.29+ and Qt6.9") endif ()
-