dwarfdump intermittently fails when called for binary-only framework
Summary
When using a binary-only framework, Carthage usually (but not always) fails when calling dwarfdump.
I believe this may be due to a bug somewhere within ReactiveTask. If I apply the following diff to avoid the use of ReactiveTask, Carthage correctly runs dwarfdump every time:
diff --git a/Source/CarthageKit/Xcode.swift b/Source/CarthageKit/Xcode.swift
index 24ca0023..2195df41 100644
--- a/Source/CarthageKit/Xcode.swift
+++ b/Source/CarthageKit/Xcode.swift
@@ -1136,11 +1136,25 @@ public func BCSymbolMapsForFramework(_ frameworkURL: URL) -> SignalProducer<URL,
/// Sends a set of UUIDs for each architecture present in the given URL.
private func UUIDsFromDwarfdump(_ url: URL) -> SignalProducer<Set<UUID>, CarthageError> {
- let dwarfdumpTask = Task("/usr/bin/xcrun", arguments: [ "dwarfdump", "--uuid", url.path ])
-
- return dwarfdumpTask.launch()
- .ignoreTaskData()
- .mapError(CarthageError.taskError)
+ return
+ SignalProducer<Data, CarthageError> { observer, disposable in
+ let pipe = Pipe()
+ let process = Process.init()
+ process.launchPath = "/usr/bin/xcrun"
+ process.arguments = [ "dwarfdump", "--uuid", url.path ]
+ process.standardOutput = pipe
+ process.launch()
+ let data = pipe.fileHandleForReading.readDataToEndOfFile()
+ process.waitUntilExit()
+ if process.terminationStatus == 0 {
+ observer.send(value: data)
+ } else {
+ // Ideally we would use `TaskError.shellTaskFailed` here, but since we do not
+ // actually have a task, we cannot do so and just pass on the status code.
+ observer.send(error: .taskError(.posixError(process.terminationStatus)))
+ }
+ observer.sendCompleted()
+ }
.map { String(data: $0, encoding: .utf8) ?? "" }
// If there are no dSYMs (the output is empty but has a zero exit
// status), complete with no values. This can occur if this is a "fake"
I would have made a PR, but I doubt it's desirable to remove the use of tasks completely. My approach above also does not provide a good error message: The lack of an appropriate case in CarthageError makes it impossible to do so, although one could certainly be added.
Unfortunately, the binary-only framework we're using is not publicly distributable so I cannot easily allow you to recreate this problem. If it would be desirable though, I can try to assemble a test case with a different binary framework.
Questions
- carthage install method: [X] .pkg, [ ] homebrew, [X] source (both fail)
-
which carthage: /usr/local/bin/carthage -
carthage version: 0.30.1 -
xcodebuild -version: Xcode 9.4 (Build version 9F1027a) - Are you using
--no-build? No. - Are you using
--no-use-binaries? No. - Are you using
--use-submodules? No. - Are you using
--cache-builds? No. - Are you using
--new-resolver? No.
Cartfile
$ cat Cartfile
github "NYPL-Simplified/NYPLAudiobookToolkit" ~> 1.0.7
binary "AudioEngine.json" ~> 6.1.13
Carthage Output (Failure Type 1)
$ carthage build --platform ios
*** xcodebuild output can be found in /var/folders/8f/4qfblq9n73zdjhyw8swhc3_c0000gr/T/carthage-xcodebuild.YVtbS4.log
*** Downloading binary-only framework AudioEngine at "file:///Users/winniequinn/Documents/Git/NYPLAEToolkit/AudioEngine.json"
A shell task (/usr/bin/xcrun dwarfdump --uuid /Users/winniequinn/Documents/Git/NYPLAEToolkit/Carthage/Build/iOS/AudioEngine.framework/AudioEngine) failed with exit code 1:
error: unable to open ''
Carthage Output (Failure Type 2)
$ carthage build --platform iOS
*** xcodebuild output can be found in /var/folders/8f/4qfblq9n73zdjhyw8swhc3_c0000gr/T/carthage-xcodebuild.Wxnv0A.log
*** Downloading binary-only framework AudioEngine at "file:///Users/winniequinn/Documents/Git/NYPLAudiobookDemo/NYPLAEToolkit/AudioEngine.json"
A shell task (/usr/bin/xcrun dwarfdump --uuid /Users/winniequinn/Documents/Git/NYPLAudiobookDemo/NYPLAEToolkit/Carthage/Build/iOS/AudioEngine.framework/AudioEngine) failed with exit code 1:
error: unable to open '/Users/winniequinn/Documents/Git/NYPLAudiobookDemo/NYPLAEToolkit/Carthage/Build/iOS/AudioEngine.framework/AudioEngine': No such file or directory
Carthage Output (A Rare Success)
$ carthage build --platform ios
*** xcodebuild output can be found in /var/folders/8f/4qfblq9n73zdjhyw8swhc3_c0000gr/T/carthage-xcodebuild.30i9no.log
*** Downloading binary-only framework AudioEngine at "file:///Users/winniequinn/Documents/Git/NYPLAEToolkit/AudioEngine.json"
*** Building scheme "PureLayout_iOS" in PureLayout.xcodeproj
*** Building scheme "NYPLAudiobookToolkit" in NYPLAudiobookToolkit.xcodeproj
Actual Outcome
Carthage usually fails to correctly run dwarfdump. Most often, the error is unable to open ''. Other times, it is No such file or directory. In the latter case, the file actually does exist at the path indicated both before and after dwarfdump is supposed to be called (as verified by setting a breakpoint at Source/CarthageKit/Xcode.swift:1139).
Expected Outcome
Carthage should run dwarfdump correctly and continue.
Really appreciate the thoroughness of the whole report, great writeup! 👏
This is a longshot, but better to check upfront: is ‘iCloud Drive for Documents and Desktop Folders’ enabled on the machine experiencing this issue? Possibly in conjunction with ‘Optimize Mac Storage’ (see System Preferences > iCloud > iCloud Drive > Options)?
That wouldn’t necessarily explain why the switch away from ReactiveTask evaded the bug, though…
One potentially significant difference from the ReactiveTask-less diff, is that url.path gets executed after the start of the SignalProducer.
I’d be curious how the following diff behaves compared to vanilla Carthage 0.31.0:
diff --git a/Source/CarthageKit/Xcode.swift b/Source/CarthageKit/Xcode.swift
index 1e4fa93a..158713bc 100644
--- a/Source/CarthageKit/Xcode.swift
+++ b/Source/CarthageKit/Xcode.swift
@@ -1117,13 +1117,26 @@ public func BCSymbolMapsForFramework(_ frameworkURL: URL) -> SignalProducer<URL,
}
}
+extension URL {
+ static func urlForReachableResource(_ url: URL) throws -> URL {
+ guard try url.checkResourceIsReachable() else {
+ throw NSError(domain: Constants.bundleIdentifier, code: 1)
+ }
+ return url
+ }
+}
+
/// Sends a set of UUIDs for each architecture present in the given URL.
private func UUIDsFromDwarfdump(_ url: URL) -> SignalProducer<Set<UUID>, CarthageError> {
- let dwarfdumpTask = Task("/usr/bin/xcrun", arguments: [ "dwarfdump", "--uuid", url.path ])
-
- return dwarfdumpTask.launch()
- .ignoreTaskData()
- .mapError(CarthageError.taskError)
+ return SignalProducer {
+ Result(at: url, carthageError: CarthageError.readFailed, attempt: URL.urlForReachableResource)
+ }
+ .flatMap(.race) { url in
+ Task("/usr/bin/xcrun", arguments: [ "dwarfdump", "--uuid", url.path ])
+ .launch()
+ .ignoreTaskData()
+ .mapError(CarthageError.taskError)
+ }
.map { String(data: $0, encoding: .utf8) ?? "" }
// If there are no dSYMs (the output is empty but has a zero exit
// status), complete with no values. This can occur if this is a "fake"
@jdhealy No luck, I'm afraid! I am not signed into iCloud on this machine so that rules out those possibilities. I also still intermittently run into the same issue with your patch applied.
Thanks for checking, good to rule that out.
I’ll do some thinking on possible next steps in debugging what the differentiator is in your patch succeeding… 🤔
Any idea about this issue? I have the same issue. I only use binaries in Cartfile. which carthage: /usr/local/homebrew/bin/carthage carthage version: 0.33.0 xcodebuild -version: Xcode 10.1 (& 10.2.1) Are you using --no-build? No. Are you using --no-use-binaries? No. Are you using --use-submodules? No. Are you using --cache-builds? No. Are you using --new-resolver? No.
Is there any update on this issue?
Interesting datapoint on this issue. We recently starting publishing a Binary Project Specification for our closed source SDK. We distribute a sample app via a GitHub repo and also attach a distribution archive to the "Releases" for this repo. When our spec file pointed at these historically constructed archives, using carthage update with our SDK always produced an error (specifically, the aforementioned "Failure Type 1").
Then I decided to retroactively add a binary attachment to our most recent release that adheres to the Carthage archive recommendations ( Archive prebuilt frameworks into one zip file ). The persistent (erroneous) error disappeared.
To confirm that the new archive was responsible for this improvement, I switched the Cartfile in my test app to force it to use an older version, which still points to our historical style of archive, and the error returns. Switch back to our latest release, and the error disappears.
Hope this information proves helpful to others that have been left irritated by this lingering issue.
Is there any update on this issue? I'm still facing intermittent dwarfdump issues while downloading the Firebase binaries using Carthage. Please see: https://github.com/firebase/firebase-ios-sdk/issues/2850
I am seeing this issue exclusively on our CI MacMini machine, intermittently, when calling carthage boostrap with FirebaseRemoteConfig dependency.
A shell task (/usr/bin/xcrun dwarfdump --uuid /Users/<redacted>/Carthage/Build/iOS/FirebaseRemoteConfig.framework/FirebaseRemoteConfig) failed with exit code 1:
error: /Users/<redacted>/Carthage/Build/iOS/FirebaseRemoteConfig.framework/FirebaseRemoteConfig: The file was not recognized as a valid object file
I am also getting a similar issue on Travis ci run.
A shell task (/usr/bin/xcrun dwarfdump --uuid /private/var/folders/z3/_825pg0s3jvf0hb_q8kzmg5h0000gn/T/carthage-archive.IRd5Zx/__MACOSX/Carthage/Build/iOS/SendBirdSDK.framework.dSYM) failed with exit code 1:
893error: /private/var/folders/z3/_825pg0s3jvf0hb_q8kzmg5h0000gn/T/carthage-archive.IRd5Zx/__MACOSX/Carthage/Build/iOS/SendBirdSDK.framework.dSYM/Contents/Resources/DWARF/._SendBirdSDK: The file was not recognized as a valid object file
Yeah. I'm getting this issue on Bitrise CI run as well. Even though - it's way better now, since Protobuf has to be added manually. But not perfect yet.
@GioPalusa, what version of Carthage is invoked in your runs on Bitrise?
@jdhealy, currently i'm running 0.34.0... so not the last release that was released 12 days ago