Cocoapods: Target has transitive dependencies that include static binaries

Created on 4 Jul 2017  路  13Comments  路  Source: CocoaPods/CocoaPods

Report

What did you do?

pod lib lint

What did you expect to happen?

Validation passed

What happened instead?

- ERROR | [iOS] unknown: Encountered an unknown error (The 'Pods-App' target has transitive dependencies that include static binaries: (/private/var/folders/9w/w3nd1hb547l2jxtqbfbv41g40000gn/T/CocoaPods/Lint/Pods/*Path to static framework*)) during validation.

CocoaPods Environment

pod version 1.2.1

Project that demonstrates the issue

https://github.com/VirgilSecurity/virgil-sdk-x

Explanation:
I have Framework1 (https://github.com/VirgilSecurity/virgil-foundation-x) which ships with static framework.
I have Framework2 which depends on Framework1.
Both frameworks are public.
It is true that Framework2 has transitive dependencies with static libraries, so if I'm right it can't be included in project with use_frameworks flag. I want to make it available at least for users who don't use use_frameworks flag. But seems like pod lib lint is now failing, so I can't do pod trunk push. Seems like a month ago it was totally OK (see https://travis-ci.org/VirgilSecurity/virgil-sdk-x/jobs/240715650).
Any advices?

awaiting input

Most helpful comment

@SanjoDeundiak Does adding s.static_framework = true to Framework2's podspec solve the issue?

All 13 comments

Currently the only way to make a CocoaPod that depends on a static library framework CocoaPod is to build the CocoaPod outside of a CocoaPods with a script like this and then add it to the CocoaPod as a vendored_framework.

The pending pull request #6811 would add support for directly creating a static library framework from source.

Do we have a final solution? Transitive dependencies is definitely the hugest obstruction by now for moving from static libraries to dynamics and from OC to swift.

There hasn't been any activity on this issue recently. Due to the high number of incoming GitHub notifications, we have to clean some of the old issues, as many of them have already been resolved with the latest updates.

This issue has not been solved neither in 1.3.1 nor 1.4.0-beta1

@SanjoDeundiak Does adding s.static_framework = true to Framework2's podspec solve the issue?

You can build your own version on a framework.

You just

  • create a new xcodeproj
  • link it with a static library (and public headers for it) or with a static framework. Don't forget to link all of dependent frameworks as well
  • build the project (verify that it builds)
  • build a dynamic framework out of it using a bash script (you will find it below).

Here is an example podspec for a dynamic YandexMapKit built from YandexMapKit.a and its headers.

New podspec

Pod::Spec.new do |s|
  s.name     = 'YandexMapKit'
  s.version  = '1.0.11'
  s.license  = { :type => 'Yandex Map Kit Terms of Use', :file => 'LICENSE.txt' }
  s.summary  = 'Yandex Map Kit for iOS.'
  s.homepage = 'https://github.com/yandexmobile/yandexmapkit-ios'
  s.author   = 'Yandex'
  s.source = { :http => 'http://download.cdn.yandex.net/mapkit/yandex-mapkit-ios-' + s.version.to_s + '.zip' }
  s.description = 'Static library for embedding Yandex.Maps into iOS applications.'
  s.platform = :ios
  s.source_files = 'Headers/*.h'
  s.resources   = ['YandexMapKit.framework/YandexMapKit.bundle', 'YandexMapKit.framework/YandexMapKit_iOS7.bundle']
  s.frameworks = 'AudioToolbox', 'OpenAL', 'AVFoundation', 'CoreData', 'CoreLocation', 'CoreTelephony', 'QuartzCore', 'MessageUI', 'OpenGLES', 'Security', 'SystemConfiguration'
  s.libraries  = 'sqlite3', 'stdc++.6', 'xml2', 'z'
  s.requires_arc = false
  s.ios.vendored_frameworks = 'YandexMapKit.framework'
end

Note the vendored_frameworks frameworks section


And the bash script

#!/bin/bash

# Script builds a universal `YandexMapKit.framework`.
# See ../README.md

# Get to a folder containing the script
scriptRoot=`cd "$(dirname "$0")" && pwd`
derivedDataPath="${scriptRoot}/build"
xcodeprojectPath="$scriptRoot/YandexMapKit.xcodeproj"

# clear build directory
rm -rf "$derivedDataPath"

# build for simulator
echo "building for simulator"
xcodebuild \
    -configuration "Release" \
    -scheme "YandexMapKit" \
    -sdk "iphonesimulator" \
    -project "$xcodeprojectPath" \
    -derivedDataPath "$derivedDataPath"

# build for ios
echo "building for ios"
xcodebuild \
    -configuration "Release" \
    -scheme "YandexMapKit" \
    -sdk "iphoneos" \
    -project "$xcodeprojectPath" \
    -derivedDataPath "$derivedDataPath"

# copy iphone build to create base for universal build
productsPath="$derivedDataPath""/Build/Products"
iphoneFrameworkPath="$productsPath/Release-iphoneos/YandexMapKit.framework"
simulatorFrameworkPath="$productsPath/Release-iphonesimulator/YandexMapKit.framework"
universalFrameworkPath="$productsPath/Release-universal"

cp -r "$iphoneFrameworkPath" "$universalFrameworkPath"

# merge binaries
echo "merging binaries"

lipo -create "$iphoneFrameworkPath/YandexMapKit" "$simulatorFrameworkPath/YandexMapKit" -output "$universalFrameworkPath/YandexMapKit"

lipoOutputRegexp="are:[[:space:]](.*)" # Architectures in the fat file: /long/path/to/YandexMapKit are: i386 x86_64 armv7 arm64 
resultArchitectures=`lipo -info "$universalFrameworkPath/YandexMapKit" | grep -oE "$lipoOutputRegexp" | sed -E "s|$lipoOutputRegexp|\1|"` # i386 x86_64 armv7 arm64 
echo "merged binary has the following architectures: $resultArchitectures"

# place final framework at a proper location
outputFrameworkPath="$scriptRoot/YandexMapKit.framework"
rm -rf "$outputFrameworkPath" # remove exising file for safety
mv "$universalFrameworkPath" "$outputFrameworkPath"

echo "resulting universal YandexMapKit.framework was created at: $(cd $outputFrameworkPath && pwd)"

# clear build directory again
rm -rf "$derivedDataPath"

Check, that the script logs the following strings in the end

merging binaries
merged binary has the following architectures: i386 x86_64 armv7 arm64 

Both simulator's and real device's architectures must be presented in this log. The first one is just for your convenience in debugging on the simulator.

The script builds xcodeproj twice: once for the simulator and once for the real device. Then it merges the binaries using lipo

@paulb777 looks like this solves the issue, but raises another question. How can I support integration for users who adds use_frameworks! to Podfile and those, who doesn't at the same time. I'll try to explain: if user adds use_frameworks! to Podfile, I should import Framework1 functionality to Framework2 using @import Framework1;, but when user doesn't include use_frameworks! to Podfile this is not available, and I should import headers directly like this: #import "SomeHeader.h". Is there some unified way?

@SanjoDeundiak The #import "SomeHeader.h" syntax should work either way. The module syntax will only work if use_frameworks! is specified.

There hasn't been any activity on this issue recently. Due to the high number of incoming GitHub notifications, we have to clean some of the old issues, as many of them have already been resolved with the latest updates.

hi , how to solve this error ?
[!] The 'Pods-DemoMeride' target has transitive dependencies that include static binaries: (/Users/romaltandel/Desktop/Demo1/DemoMeride/Pods/google-cast-sdk/GoogleCastSDK-ios-4.3.1_static/GoogleCast.framework)

@Jignesh1805 did you get any solution for this ?

@ggnebooks I'm also getting this error but with Segment Analytics framework
target has transitive dependencies that include statically linked binaries: (Analytics)

@wvabrinskas i have added s.framework=true inside podspec file

Was this page helpful?
0 / 5 - 0 ratings

Related issues

dawnnnnn picture dawnnnnn  路  3Comments

marzapower picture marzapower  路  3Comments

iosdev-republicofapps picture iosdev-republicofapps  路  3Comments

intelliot picture intelliot  路  3Comments

sonu5 picture sonu5  路  3Comments