iOS swift app build fails with cyclic dependency error in Xcode 14+ - ios

I have a swift iOS app with two static libraries - lib1 and lib2 (say). Lib2 has a dependency on Lib1 (i.e it imports Lib1 to use its types). Lib1 and Lib2 are set as dependencies for the AppTarget (when built, results in the .app file).
I get the following cyclic dependency error when building Lib1. Similar error is observed when building the other targets.
SwiftDriverJobDiscovery normal x86_64 Compiling <FileName1>.swift (in target '<Lib1>' from project '<ProjectName>')
error: Cycle inside <Lib1>; building could produce unreliable results.
Cycle details:
→ Target '<Lib1>': Libtool /Users/<user-name>/<some-path>/<Lib1>.a normal
○ Target '<Lib1>' has Swift tasks not blocking downstream targets
○ Target '<Lib1>': SwiftGeneratePch normal x86_64 Compiling bridging header
○ Target '<Lib1>': SwiftCompile normal x86_64 Compiling <FileName2>.swift /Users/<user-name>/<some-path>/<Filename2>.swift
○ Target '<Lib1>': SwiftGeneratePch normal x86_64 Compiling bridging header
Raw dependency cycle trace:
target: ->
node: <all> ->
command: <all> ->
node: /Users/<user-name/<some-path>/<Lib1>.a -> command: P1:target-<Lib1>-6d14b29d8d3402955e18e7b7c2cd5bd8502d5dd7097f7536813aba73cac1c1d5-:Debug:Libtool /Users/<user-name>/<some-path>/<Lib1>.a normal ->
node: /Users/<user-name>/<some-path>/x86_64/<FileName3>-8014457a59adc1f8a995a14873eb809b.o ->
command: P0:target-<Lib1>-6d14b29d8d3402955e18e7b7c2cd5bd8502d5dd7097f7536813aba73cac1c1d5-:Debug:SwiftDriver Compilation <Lib1> normal x86_64 com.apple.xcode.tools.swift.compiler ->
CYCLE POINT ->
customTask: <SwiftDriverJob identifier=-4908891831242875468 arch=x86_64 variant=normal job=<PlannedSwiftDriverJob [target(7)]:GeneratePch <Lib1> dependencies=["target(8)", "target(9)", "target(10)"]> isUsingWholeModuleOptimization=false compilerPath=/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swiftc> ->
customTask: <SwiftDriverJob identifier=-4908891831242875468 arch=x86_64 variant=normal job=<PlannedSwiftDriverJob [target(8)]:Compile <Lib1> <FileName2>.swift dependencies=["target(7)"]> isUsingWholeModuleOptimization=false compilerPath=/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swiftc> ->
customTask: <SwiftDriverJob identifier=-4908891831242875468 arch=x86_64 variant=normal job=<PlannedSwiftDriverJob [target(7)]:GeneratePch <Lib1> dependencies=["target(8)", "target(9)", "target(10)"]> isUsingWholeModuleOptimization=false compilerPath=/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swiftc>
In the above error message, FileName1 and FileName2 are swift files that invoke C++ methods using an intermediate ObjC++ bridge layer. I have two files named FileName3 but different extensions - .swift and .mm. Since, FileName2 is referred as .o here, I think it is referring to FileName3.mm (i.e the ObjC++ file).
I have checked the code thoroughly for any form of cyclic dependency (like, two classes depending on each other - as mentioned in many stackoverflow posts), but it's all good. What's more, the same build worked on Xcode 13.x. After updating to Xcode 14.x, I'm getting this cyclic dependency error.
But in the last three lines of the error message, you can see a cyclic dependency.
First step: [Target(7)] Generate pch and depends on [target(8), target(9), target(10)]
Second step: [Target(8)] Compile FileName2.swift, depends on [target(7)]
Target(7) is dependent on target(8) and target(8) is dependent on target(7). What is target(7), target(8) etc? Where can I find out what kind of target it exactly is?
I use cmake to set the dependencies and generate the Xcode project.
What is this error? What am I missing here?
I've been stuck for days and any help would be greatly appreciated.

After so much time spent on searching, this is the answer.
Checkout ctietze's answer to this post in Apple forum
defaults write com.apple.dt.XCBuild EnableSwiftBuildSystemIntegration 0
After disabling the new build system, I'm not getting the cyclic dependency error anymore.

Related

Link to fat Static Library inside Swift Package

I’m trying to build a Swift Package that wraps a fat static library written in C: libndi_advanced_ios.a from NewTek's Apple Advanced NDI SDK.
I am having trouble linking the pre-compiled library (only headers files and .a binary package is available) to my Swift Package. I have done a lot of research and tried different solutions, but none of them worked. Here is a quick list:
Cannot bundle in an XCFramework because libndi_advanced_ios.a supports multiple platforms (arm_v7, i386, x86_64, arm64) and xcodebuild -create-xcframework return the error binaries with multiple platforms are not supported (this solution is discussed on Swift Forums too);
Using .linkedLibrary in targets as suggested on SPM Documentation (that is outdated) gives the warning system packages are deprecated; use system library targets instead, and I don’t even remember if it builds successfully;
Playing around with different flags and settings (like linkerSettings) has not been successful. Maybe I just missed the right combination.
I can link dozens of Stackoverflow's questions and other posts that didn’t help, but it will be useless (a, b, c).
At the moment I have this configuration:
With Package.swift that contains the following code:
let package = Package(
name: "swift-ndi",
platforms: [.iOS(.v12)],
products: [
.library(
name: "swift-ndi",
targets: ["swift-ndi"])
],
dependencies: [],
targets: [
.target(name: "CiOSNDI", path: "Libraries"),
.target(
name: "swift-ndi",
dependencies: ["CiOSNDI"]),
.testTarget(
name: "swift-ndiTests",
dependencies: ["swift-ndi"]),
]
)
You can find the whole project at alessionossa/swift-ndi.
The only result at the moment are some warnings and the module CiOSNDI do not build:
I tried also .systemLibrary(name: "CiOSNDI", path: "Libraries/"), with this configuration: alessionossa/swift-ndi/tree/systemLibrary; but I get these errors:
NOTE
NDI_include is actually an alias/symbolic link to /Library/NDI Advanced SDK for Apple/include, while NDI_iOS_lib points to /Library/NDI Advanced SDK for Apple/lib/iOS.
I always cleaned build folder after changes to Package.swift.
UPDATE 10/01/2022: libndi_advanced_ios.a requires libc++.tbd. That can be easy linked in an app in Build Phases -> Link Binary With Libraries, but I don’t know how to link in a Swift Package.
Binary targets need to specified with .binary_target. See the docs and example here.
An example of a static library wrapped in an .xcframework looks like this from the file command:
$ file GoogleAppMeasurement.xcframework/ios-arm64_armv7/GoogleAppMeasurement.framework/GoogleAppMeasurement
GoogleAppMeasurement.xcframework/ios-arm64_armv7/GoogleAppMeasurement.framework/GoogleAppMeasurement: Mach-O universal binary with 2 architectures: [arm_v7:current ar archive] [arm64]
GoogleAppMeasurement.xcframework/ios-arm64_armv7/GoogleAppMeasurement.framework/GoogleAppMeasurement (for architecture armv7): current ar archive
GoogleAppMeasurement.xcframework/ios-arm64_armv7/GoogleAppMeasurement.framework/GoogleAppMeasurement (for architecture arm64): current ar archive
One way to create the .xcframework file is to use Firebase's ZipBuilder that creates a .xcframework files from static libraries that are specified with a CocoaPods podspec file.
I also needed to add the NDI SDK as a Swift package dependency in my app.
I found a couple of approaches that worked:
You can create an XCFramework bundle by extracting a thin arm64 library from the universal library:
lipo "/Library/NDI SDK for Apple/lib/iOS/libndi_ios.a" -thin arm64 -output "$STAGING_DIRECTORY/libndi.a"
Then create an XCFramework bundle:
xcodebuild -create-xcframework -library "$STAGING_DIRECTORY/libndi.a" -headers "/Library/NDI SDK for Apple/include" -output "$STAGING_DIRECTORY/Clibndi.xcframework"
I ended up not using this approach because hosting the XCFramework as a downloadable binary release on GitHub required me to make my repo public (see this issue).
Instead I am using a system library target, in my Package.swift:
targets: [
.target(
name: "WrapperLibrary",
dependencies: ["Clibndi"],
linkerSettings: [
.linkedFramework("Accelerate"),
.linkedFramework("VideoToolbox"),
.linkedLibrary("c++")
]),
.systemLibrary(name: "Clibndi")
]
Then, I have WrapperLibrary/Sources/Clibndi/module.modulemap that looks like:
module Clibndi {
header "/Library/NDI SDK for Apple/include/Processing.NDI.Lib.h"
link "ndi_ios"
export *
}
Finally, my application target (part of an Xcode project, not a Swift package) depends on WrapperLibrary, and I had to add "/Library/NDI SDK for Apple/lib/iOS" (including the quotation marks) to "Library Search Paths" in the "Build Settings" tab.
As an alternative to modifying the application target build settings, you could add a pkg-config file to a directory in your pkg-config search paths. For example, /usr/local/lib/pkgconfig/libndi_ios.pc:
NDI_SDK_ROOT=/Library/NDI\ SDK\ for\ Apple
Name: NDI SDK for iOS
Description: The NDI SDK for iOS
Version: 5.1.1
Cflags: -I${NDI_SDK_ROOT}/include
Libs: -L${NDI_SDK_ROOT}/lib/iOS -lndi_ios
Then use .systemLibrary(name: "Clibndi", pkgconfig: "libndi_ios") in your package manifest. I found this less convenient for users than just adding the setting to my application target, however.
Ideally you could add the NDI SDK's dependency library and frameworks to the pkg-config file as well (Libs: -L${NDI_SDK_ROOT}/lib/iOS -lndi_ios -lc++ -framework Accelerate -framework VideoToolbox), but it appears there is a bug in Swift's pkg-config parsing of -framework arguments, so I filed a bug: SR-15933.

Facebook sdk not working if I place the sdk folder inside react-native project?

I am wanting to manually link the Facebook SDK because we don't use cocoapods & don't want to implement it. But for some reason when we build our app on buddybuild, it will fail.
What I've done is placed the FacebookSDK folder inside (not an optimal solution I know):
ios/<ProjectName>/FacebookSDK
I added this folder ($(SRCROOT)/ios/<ProjectName>/FacebookSDK) to the framework search header paths & it still seems to throw errors.
1850
▸ Compiling RCTFBSDKShareDialog.m
1851
» In file included from node_modules/react-native-fbsdk/ios/RCTFBSDK/share/RCTFBSDKShareDialog.m:19:
1852
✗ node_modules/react-native-fbsdk/ios/RCTFBSDK/share/RCTFBSDKShareDialog.h:21:9: fatal error: 'FBSDKShareKit/FBSDKShareKit.h' file not found
1853
» #import <FBSDKShareKit/FBSDKShareKit.h>
1854
» ^
1855
▸ Compiling RCTFBSDKAppEvents.m
1856
» In file included from node_modules/react-native-fbsdk/ios/RCTFBSDK/core/RCTFBSDKAppEvents.m:19:
1857
✗ node_modules/react-native-fbsdk/ios/RCTFBSDK/core/RCTFBSDKAppEvents.h:21:9: fatal error: 'FBSDKCoreKit/FBSDKCoreKit.h' file not found
1858
» #import <FBSDKCoreKit/FBSDKCoreKit.h>
1859
» ^
1860
** BUILD FAILED **
1861
The following build commands failed:
1862
CompileC /tmp/sandbox/582d62aa1d76fc0100f1f6dd/bbbuild/Build/Intermediates/RCTFBSDK.build/Release-iphoneos/RCTFBSDK.build/Objects-normal/armv7/RCTFBSDKAppEvents.o RCTFBSDK/core/RCTFBSDKAppEvents.m normal armv7 objective-c com.apple.compilers.llvm.clang.1_0.compiler
1863
(1 failure)
Any ideas to what I can do? It'd be nice if we could use this solution for now so that all developers (and the buddybuild CI) can pull it instead of having to download the SDK and put it documents folder.
This is generally a result of an incorrectly configured repository with regards to the location of FBSDK dependencies.
If you take a look at: https://github.com/facebook/react-native-fbsdk/blob/master/ios/RCTFBSDK.xcodeproj/project.pbxproj
You will notice that RCTFBSDK will look for dependencies in one of two locations:
~/Documents/FacebookSDK
$(PROJECT_DIR)/../../../ios/Frameworks
The second option is the correct option for continuous integration systems like buddybuild.
In other words, you MUST place your FBSDK dependencies under the "ios/Frameworks" folder in order for it to work on a continuous integration system.
You can find more information about this in our react-native documentations.
Please let me know if this helps!

Library not found for -llib. (clang: error: linker command failed with exit code 1 (use -v to see invocation))

I am working on a project that was previously done and uploaded on app store.When I run this app in Xcode 5.0 it is working fine but when I run this on Xcode Version 5.1.1 (5B1008) I am getting Linker error on both device and simulator.
Error Message- Library not found for -llib. (clang: error: linker command failed with exit code 1 (use -v to see invocation)).
I have searched a lot but I didn't get any thread about Library not found for -llib error. Is there anything I have to change in build settings to resolve this?
Look at the linker command line in detail for the -L options being used:
Then use Terminal or Finder to see if your libXXX.a file exists in those directories. If the library exists elsewhere then you need to configure your Library Search Paths:
However there several details which you have not provided in your question when using a library within an app:
Is the library built as part of the Xcode project/workspace (as in the first image)?
Is the library supplied by a third-party with binary (.a) and header files (as in the second image)?
TL;DR: I ran make in the wrong directory so the paths were messed up.
Problem:
>make
linking ../build/release/yubikey-personalization-gui
/usr/x86_64-suse-linux/bin/ld: cannot find -llib
...
I ran into this when compiling the Yubikey Personalisation Tool. I tracked down the -llib call in my Makefile which looked like this:
...
LINK = #echo linking $# && g++
...
LIBS = $(SUBLIBS) -L/usr/lib64 -L../lib/release -llib -lyubikey -lykpers-1 -lQtGui -L/usr/lib64 -L/usr/X11R6/lib -lQtCore -lpthread
...
$(LINK) $(LFLAGS) -o $(TARGET) $(OBJECTS) $(OBJCOMP) $(LIBS)
So it was setting a variable called LINK which would print "linking" and then call g++, which is the compiler.
Then it set the var LIBS which would hold the ominous -llib.
Then it composes and runs the command $(LINK) ... $(LIBS).
Which runs g++ with the parameter -llib.
And what does that do? Turns out -l<something> is telling the compiler to use the something-library. So it asks for the library called lib here. Which is strangely generic. I figured out that the sources came with a directory called lib/, which was at ../lib.
So starting make from a directory higher up fixed it.
You should remove libstdc++ from other linker flags in your xcode project
https://stackoverflow.com/a/53103383/1344237

Marmalade iOS multiple architectures support

The instruction for building marmalade extension static lib-wrappers from the official site shows how to build only single architecture (armv6) extension. I tried to include many architectures into the project:
if {{defined I3D_OS_IPHONE}}
{
includepath incoming
files
{
["MyTracker Library armv7"]
(incoming/armv7)
"*.o"
["MyTracker Library armv7s"]
(incoming/armv7s)
"*.o"
["MyTracker Library armv64"]
(incoming/armv64)
"*.o"
["source"]
(use_first_found, source/iphone, source/generic)
MyTracker_platform.mm
#Add any iphone-specific files here
}
}
But I got many error messages after trying to build it:
Executing: '/usr/local/bin/scons -Q compiler=clang'
scons: warning: Support for pre-2.7.0 Python version (2.6.8) is deprecated.
If this will cause hardship, contact dev#scons.tigris.org.
File "/usr/local/bin/scons", line 192, in <module>
Librarian [ar] /Users/misha/Documents/MyTracker/lib/iphone/libMyTracker.a
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/ranlib: archive member: /Users/misha/Documents/MyTracker/lib/iphone/libMyTracker.a(MyDispatcher.o) cputype (7) does not match previous archive members cputype (12) (all members must match)
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/ranlib: archive member: /Users/misha/Documents/MyTracker/lib/iphone/libMyTracker.a(MyTracker.o) cputype (16777223) does not match previous archive members cputype (12) (all members must match)
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/ranlib: archive member: /Users/misha/Documents/MyTracker/lib/iphone/libMyTracker.a(MyNetwork.o) cputype (16777228) does not match previous archive members cputype (12) (all members must match)
....
malformed object (unknown load command 1)
ar: internal ranlib command failed
scons: *** [/Users/misha/Documents/MyTracker/lib/iphone/libMyTracker.a] Error 1
Executing 'scons -Q' failed. (return code 2). Retry
error: Executing 'scons -Q' failed. (return code 2)
FAILED (error code=3)
How to build an extension with multiple architectures support?
This is typically not the advised way to handle this. You look like you're trying to bring in symbols from those libs, something that the EDK does not support. Your best option is to include these libs (or most probably, just the arm6/7 lib, depending on how low you want to take it) at deploy time along with the compiled extension and instead, compile the extension using a header file (either supplied by the developer of any SDK you're using, or one you've written to compile those .o libs).
Building for multiple targets is something that is being refactored. My understanding is that at some stage both the documentation and the underlying code has got stale. I believe the approach will be quite different from what you are trying to do - I'm not sure why you are pulling in .o files but generally that does work too well in marmalade.

Can't link MacOS frameworks with CMake

I'm trying to build a subproject with cmake (it's not an xcode project or even an app for iphone, the result is cross-platform console executable, which #includes some inherited from C++ abstract classes, written in objective-c++)
I'm using this guide to link mac os frameworks: http://www.vtk.org/Wiki/CMake:HowToUseExistingOSXFrameworks
and this macro:
macro(ADD_FRAMEWORK fwname appname)
find_library(FRAMEWORK_${fwname}
NAMES ${fwname}
PATHS ${CMAKE_OSX_SYSROOT}/System/Library
PATH_SUFFIXES Frameworks
NO_DEFAULT_PATH)
if( ${FRAMEWORK_${fwname}} STREQUAL FRAMEWORK_${fwname}-NOTFOUND)
MESSAGE(ERROR ": Framework ${fwname} not found")
else()
TARGET_LINK_LIBRARIES(${appname} ${FRAMEWORK_${fwname}})
MESSAGE(STATUS "Framework ${fwname} found at ${FRAMEWORK_${fwname}}")
endif()
endmacro(ADD_FRAMEWORK)
This is the important part in CMakeLists.txt
project(myprojectname)
........
add_executable(mytarget src/mytarget.cpp)
add_framework(CoreMedia mytarget)
add_framework(CoreVideo mytarget)
add_framework(AVFoundation mytarget)
add_framework(Foundation mytarget)
........
And that's what i have when trying to build:
WARNING: Target "mytarget" requests linking to directory "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS6.0.sdk/System/Library/Frameworks/CoreMedia.framework". Targets may link only to libraries. CMake is dropping the item.
WARNING: Target "mytarget" requests linking to directory "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS6.0.sdk/System/Library/Frameworks/CoreVideo.framework". Targets may link only to libraries. CMake is dropping the item.
WARNING: Target "mytarget" requests linking to directory "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS6.0.sdk/System/Library/Frameworks/AVFoundation.framework". Targets may link only to libraries. CMake is dropping the item.
WARNING: Target "mytarget" requests linking to directory "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS6.0.sdk/System/Library/Frameworks/Foundation.framework". Targets may link only to libraries. CMake is dropping the item.
It actually finds all these frameworks, but can't link, which produces a lot of linker errors. I'm pretty sure that that's the reason because i made a testproj using XCode and it has the same errors till i linked all the needed frameworks.
When i just use
FIND_LIBRARY(COREMEDIA_LIB CoreMedia)
...
then COREMEDIA_LIB is set to NOTFOUND - what's going on? :/
I googled a lot but nothing :( Feeling pretty much lost there.
Got the thing: you have to link NOT the frameworkname.framework folder in the TARGET_LINK_LIBRARIES, but the fwname.framework/fwname file! Now it works that way.
The changed macro is this:
macro(ADD_FRAMEWORK fwname appname)
find_library(FRAMEWORK_${fwname}
NAMES ${fwname}
PATHS ${CMAKE_OSX_SYSROOT}/System/Library
PATH_SUFFIXES Frameworks
NO_DEFAULT_PATH)
if( ${FRAMEWORK_${fwname}} STREQUAL FRAMEWORK_${fwname}-NOTFOUND)
MESSAGE(ERROR ": Framework ${fwname} not found")
else()
TARGET_LINK_LIBRARIES(${appname} "${FRAMEWORK_${fwname}}/${fwname}")
MESSAGE(STATUS "Framework ${fwname} found at ${FRAMEWORK_${fwname}}")
endif()
endmacro(ADD_FRAMEWORK)
Hope it will be useful for someone...

Resources