Carthage support for a prebuilt .framework (built with static library + aggregator)

Created on 20 Jun 2018  Â·  23Comments  Â·  Source: Carthage/Carthage

  • carthage install method: [ ] .pkg, [x] homebrew, [ ] source
  • which carthage: /usr/local/bin/carthage
  • carthage version: 0.29.0
  • xcodebuild -version: Xcode 9.4.1, Build version 9F2000
  • 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

binary "./<framework-name>.json" == 4.1.3

Carthage Output

$ carthage update
*** Downloading binary-only framework <framework-name> at "file:///Users/Daniel/.../<framework-name>.json"
*** Downloading binary-only framework <framework-name> at "file:///Users/Daniel/.../<framework-name>.json"
*** xcodebuild output can be found in /var/folders/3w/g8q6qv_93k15g87227vqwhbc0000gn/T/carthage-xcodebuild.KT8zF1.log
Failed to read file or folder at /Users/Daniel/.../Carthage/Build/iOS/<framework-name>.framework

Background
We are trying to add Carthage support to a closed source / private iOS SDK. We build the SDK / .framework from a static library target with an aggregator target, which means that there is no dynamic framework target in the project ->

carthage build --no-skip-current
carthage archive YourFrameworkName

fails (since there is no shared framework). We also do not use a .plist file anywhere in the app (in reference to https://github.com/Carthage/Carthage/issues/1077).
Because of this, and because we already have the <framework-name>.framework file, I tried creating a binary only release (https://github.com/Carthage/Carthage/pull/1760/).

Since there is no shared framework target, I need to skip carthage build --no-skip-current, as this leads to this error message:

*** Skipped building <framework-name> due to the error:
Dependency "<framework-name>" has no shared framework schemes

So I mocked the Carthage structure by putting the pre-built .framework to <project-root>/Carthage/Build/iOS and calling carthage archive <framework-name>. This gives me the following output:

*** Found Carthage/Build/iOS/<framework-name>.framework
*** Found Carthage/Build/iOS/<framework-name>.framework.dSYM
Failed to read file or folder at /Users/Daniel/.../Carthage/Build/iOS/<framework-name>.framework

Archiving it manually into a .zip file that only contains Carthage/Build/iOS/<framework-name>.framework and trying to get it via carthage update leads to the error message in the "Carthage Output" point above.

Actual outcome
On carthage update, Carthage downloads the (closed source / private) binary only release / .framework file. It copies it to Carthage/Buidls/iOS but then fails with the above error message.

Expected outcome
Is there a way to offer Carthage support with the described project setup (i.e. skipping carthage build --no-skip-current and carthage archive YourFrameworkName)?

(we are btw. looking into adding a new framework target to the project so we can go the reqular build and archive way, but here we're running into the problem of carthage build --no-skip-current not including the (public) header files to the .framework - this might very well be a problem on our side, but: is this a known issue?)

question

Most helpful comment

no dynamic framework target in the project

So this is a static framework? 0.29.0 does not support static frameworks. Current master does.

brew upgrade carthage --HEAD

Since there is no shared framework target, I need to skip carthage build --no-skip-current, as this leads to this error message:

Didn't you just say you are distributing your private framework via binary? Why are you trying to build it via Carthage if there is no shared scheme?

So I mocked the Carthage structure by putting the pre-built .framework to /Carthage/Build/iOS and calling carthage archive

You don't need to do this.

Archiving it manually into a .zip

Yep this is the way. If you have the binary of the framework they way you want it no need to carthage build & archive. Just grab your .framework and zip it.

Failed to read file or folder at /Users/Daniel/.../Carthage/Build/iOS/.framework

I can't help you here, but you can checkout the source and get started debugging. See https://github.com/Carthage/Carthage/blob/master/CONTRIBUTING.md

All 23 comments

no dynamic framework target in the project

So this is a static framework? 0.29.0 does not support static frameworks. Current master does.

brew upgrade carthage --HEAD

Since there is no shared framework target, I need to skip carthage build --no-skip-current, as this leads to this error message:

Didn't you just say you are distributing your private framework via binary? Why are you trying to build it via Carthage if there is no shared scheme?

So I mocked the Carthage structure by putting the pre-built .framework to /Carthage/Build/iOS and calling carthage archive

You don't need to do this.

Archiving it manually into a .zip

Yep this is the way. If you have the binary of the framework they way you want it no need to carthage build & archive. Just grab your .framework and zip it.

Failed to read file or folder at /Users/Daniel/.../Carthage/Build/iOS/.framework

I can't help you here, but you can checkout the source and get started debugging. See https://github.com/Carthage/Carthage/blob/master/CONTRIBUTING.md

Hi @blender - thank you for the quick reply and the suggestions!
I'll try building the static framework from the master branch. And if that shouldn't work, I'll try to debug the "Failed to read" error.

Hi again,

quick question about the current master branch: I updated carthage (brew upgrade carthage --HEAD) and tried again to load my manually created .zip file (with the /Carthage/Build/iOS structure). This used to give me the error

Failed to read file or folder at /Users/Daniel/.../Carthage/Build/iOS/.framework

but now it says:

$ carthage update --platform iOS
*** Downloading binary-only framework <framework-name> at "file:///Users/Daniel/.../<framework-name>.json"
*** Downloading binary-only framework <framework-name> at "file:///Users/Daniel/.../<framework-name>.json"
*** xcodebuild output can be found in /var/folders/3w/g8q6qv_93k15g87227vqwhbc0000gn/T/carthage-xcodebuild.8cqZii.log
Failed to write to /Users/Daniel/.../Carthage/Build/.<framework-name>.version: Error Domain=NSCocoaErrorDomain Code=4 "The folder “.<framework-name>.version” doesn’t exist." UserInfo={NSFilePath=/Users/Daniel/.../Carthage/Build/.<framework-name>.version, NSUserStringVariant=Folder, NSUnderlyingError=0x7fdea0d2a880 {Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory"}}

Does this mean anything to you? So far, I couldn't really find anything while debugging Carthage from the source files.

Here's btw the package contents of our framework (is Carthage maybe looking for something that isn't there?):

<framework-name>.framework
\ <framework-name> (alias)
\ Headers (alias)
\ Versions
\ \ A
\ \ \ <framework-name>
\ \ \ Headers
\ \ \ \ <the headers>
\ \ Current (alias)

I am investigating the same exact bug with universal frameworks.

Is your framework universal? That structure is for MacOS frameworks (not that is matters)

Yes it is universal - Device and Simulator (not explicitly for MacOS).

No I meant MacOS & iOS. The structure you have is not the usual iOS structure. Again, not that it matters.

I have the same bug with this framework https://github.com/blender/SalesforceDMPiOS/blob/master/Krux.json

@mobru can you another ticket to the bug?

Ah ok. Nope - just iOS.

can you another ticket to the bug?

@blender I'm sorry, what do you mean by that?

(edit: I get the same error with your SalesforceDMPiOS Cartfile, btw)

Hi again @blender!

With the new error message from the master branch and the, as you said, correct way to go for archiving our already existing .framework file not working as expected ("Failed to read file or folder..." on 0.29.0 and "Failed to write to [...] ..version" error on master), that this might be an issue with Carthage itself (especially since you get the same error message on your linked framework)?

@mobru it's an issue with Carthage. I found the problem. Can you confirm you're trying to ship a framework with no Info.plist ?

Hi again, @blender!

Correct, our .framework does not include an Info.plist file.

May I ask why? Just curious

From what I have been told, the SDK is rather old, and there wasn't a library module in Xcode back in the day. Also, the SDK doesn't really need a Info.plist, since it does not provide any information that is necessary for the functionality of the methods.

It's not a valid bundle without an Info.plist though.

~I think it also depends on the structure. Mac OS frameworks and ios frameworks with the macOS structure load just fine.~ They are ~also~ successfully constructed into a bundle

Also static frameworks ~don't have~ seem fine without Info.plist

Should be fixed in 0.30.0 Please confirm and close if fixed

Hi again!

Unfortunately, after updating to 0.30.1, I get the same error as I did originally:

$ carthage update
*** Downloading binary-only framework <framework-name> at "file:///Users/Daniel/,,,/<framework-name>.json"
*** Downloading binary-only framework <framework-name> at "file:///Users/Daniel/,,,/<framework-name>.json"
*** xcodebuild output can be found in /var/folders/3w/g8q6qv_93k15g87227vqwhbc0000gn/T/carthage-xcodebuild.UVf4h0.log
*** Downloading <framework-name>.framework binary at "4.1.8"
Failed to read file or folder at /Users/Daniel/.../Carthage/Build/iOS/<framework-name>.framework

I tried to manually archive the .framework as Carthage/Build/iOS/<framework-name>.framework and Carthage/Build/iOS/Static/<framework-name>.framework - both with the same result.

carthage update does download and unpack the framework though. It does not create a .<framework-name>.version file, however. Also, it does not download any other frameworks that are in the Cartfile - it immediately stops after the error.
But this was the case with 0.29.0 as well.

Hi,

I can't debug your particular problem. However I can tell you where to look:

Here is where Carthage determines if the binary it's downloading is a framework:
https://github.com/Carthage/Carthage/pull/2502/files#diff-3bd7f6198aa606c5ec6931e77cb3c42bR1281

Here is the rest of flow where after the download the version file should be created:
https://github.com/Carthage/Carthage/blob/256ae62/Source/CarthageKit/Project.swift#L574

Hi again @blender,

thank's a lot for the hints, I'll try to get to some debugging ~today~ asap! Will update once I have some results.

Hello everybody,

I run into the same problem trying to implement Chartage.

Using this Cartfile:

github "Alamofire/Alamofire" ~> 4.5.0
github "Alamofire/AlamofireImage" ~> 3.2
binary "https://www.milenica.info/Carthage/AdColony/AdColony.json" == 3.2.1

After running carthage update I get similar error:
Failed to read file or folder at /Users/ ... /Carthage/Build/iOS/AdColony.framework

After some debugging of ChartageKIT I found out that root cause of this is Xcode.swift file in fuction
public func binaryURL(_ packageURL: URL) -> Result

The problem is that bundle?.packageType is nil. It looks like Bundle can not resolve packageType because framework it does not contain Info.plist file.

I wrote some work around aka quick fix that resolves this problem for my use case but some global solution should be found.

if let bundle = bundle
{
    if let startRange = bundle.bundlePath.range(of: "/", options: .backwards, range: nil, locale: nil)
    {
        if let endRange = bundle.bundlePath.range(of: ".framework", options: .backwards, range: nil, locale: nil)
        {
            if endRange.lowerBound > startRange.upperBound
            {
                let binaryName = String(bundle.bundlePath[startRange.upperBound ..< endRange.lowerBound])
                if  binaryName == "AdColony"
                {
                    return .success(packageURL.appendingPathComponent(binaryName))
                }
            }
        }
    }
}

Hi @bataboki since you're investigating this, maybe you can use what I introduced here https://github.com/Carthage/Carthage/pull/2502/files#diff-1f819080896c9817027576b08159594fR44 to get the type package type

Hi @blender I would be happy to get more involved in project, but it is all written in RectiveSwift which I am not familiar with and that adds a level of complexity, especially debugging is a headache with all of the signals. If I get some time to learn RectiveSwift I'll look at this.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

3lvis picture 3lvis  Â·  3Comments

akaffenberger picture akaffenberger  Â·  3Comments

JustinJiaDev picture JustinJiaDev  Â·  3Comments

jdecarlo picture jdecarlo  Â·  3Comments

mdiep picture mdiep  Â·  3Comments