Commit 0c9f2480 authored by Samuel E. Giddins's avatar Samuel E. Giddins

Merge pull request #3832 from CocoaPods/seg-dynamic

Better vendored framework support
parents 5f9e19c1 7430a599
...@@ -32,7 +32,7 @@ To install release candidates run `[sudo] gem install cocoapods --pre` ...@@ -32,7 +32,7 @@ To install release candidates run `[sudo] gem install cocoapods --pre`
* Embed frameworks into app and watch extensions. * Embed frameworks into app and watch extensions.
[Boris Bügling](https://github.com/neonichu) [Boris Bügling](https://github.com/neonichu)
[#4004](https://github.com/CocoaPods/CocoaPods/pull/4004) [#4004](https://github.com/CocoaPods/CocoaPods/pull/4004)
* Fix missing `$(inherited)` for generated xcconfig `LIBRARY_SEARCH_PATHS` and `HEADER_SEARCH_PATHS` build settings. * Fix missing `$(inherited)` for generated xcconfig `LIBRARY_SEARCH_PATHS` and `HEADER_SEARCH_PATHS` build settings.
[Tyler Fox](https://github.com/smileyborg) [Tyler Fox](https://github.com/smileyborg)
[#3908](https://github.com/CocoaPods/CocoaPods/issues/3908) [#3908](https://github.com/CocoaPods/CocoaPods/issues/3908)
...@@ -41,6 +41,11 @@ To install release candidates run `[sudo] gem install cocoapods --pre` ...@@ -41,6 +41,11 @@ To install release candidates run `[sudo] gem install cocoapods --pre`
[Samuel Giddins](https://github.com/segiddins) [Samuel Giddins](https://github.com/segiddins)
[#4059](https://github.com/CocoaPods/CocoaPods/issues/4059) [#4059](https://github.com/CocoaPods/CocoaPods/issues/4059)
* Include the `-ObjC` linker flag when static `vendored_frameworks` are present.
[Samuel Giddins](https://github.com/segiddins)
[#3870](https://github.com/CocoaPods/CocoaPods/issues/3870)
[#3992](https://github.com/CocoaPods/CocoaPods/issues/3992)
##### Enhancements ##### Enhancements
* Collapse the namespaced public and private pod xcconfig into one single * Collapse the namespaced public and private pod xcconfig into one single
...@@ -78,6 +83,10 @@ To install release candidates run `[sudo] gem install cocoapods --pre` ...@@ -78,6 +83,10 @@ To install release candidates run `[sudo] gem install cocoapods --pre`
[Core#190](https://github.com/CocoaPods/Core/issues/190) [Core#190](https://github.com/CocoaPods/Core/issues/190)
[#2682](https://github.com/CocoaPods/CocoaPods/issues/2682) [#2682](https://github.com/CocoaPods/CocoaPods/issues/2682)
* Add support for dynamic `vendored_frameworks` and `vendored_libraries`.
[Samuel Giddins](https://github.com/segiddins)
[#1993](https://github.com/CocoaPods/CocoaPods/issues/1993)
## 0.38.2 (2015-07-25) ## 0.38.2 (2015-07-25)
......
GIT GIT
remote: https://github.com/CocoaPods/CLAide.git remote: https://github.com/CocoaPods/CLAide.git
revision: 675dd608cd5b3f8b62a4f34da48aff5d0b75d41f revision: 4e7b02d849c3e82dff7c1cdacf33df45516acaf3
branch: master branch: master
specs: specs:
claide (0.9.1) claide (0.9.1)
GIT GIT
remote: https://github.com/CocoaPods/Core.git remote: https://github.com/CocoaPods/Core.git
revision: fd41ee938a5687a39711b0f3d1f9e76dd506dd5d revision: ca6db91dd318f121e5b2008d55f52c62a86d4016
branch: master branch: master
specs: specs:
cocoapods-core (0.38.2) cocoapods-core (0.38.2)
...@@ -24,7 +24,7 @@ GIT ...@@ -24,7 +24,7 @@ GIT
GIT GIT
remote: https://github.com/CocoaPods/Xcodeproj.git remote: https://github.com/CocoaPods/Xcodeproj.git
revision: 186cd802eb8b3b929fbf8bf70b66b6ae52dda72e revision: 47b067acc2554977c9dca6fd38588cc26d449b71
branch: master branch: master
specs: specs:
xcodeproj (0.26.3) xcodeproj (0.26.3)
...@@ -92,7 +92,7 @@ PATH ...@@ -92,7 +92,7 @@ PATH
GEM GEM
remote: https://rubygems.org/ remote: https://rubygems.org/
specs: specs:
activesupport (4.2.3) activesupport (4.2.4)
i18n (~> 0.7) i18n (~> 0.7)
json (~> 1.7, >= 1.7.7) json (~> 1.7, >= 1.7.7)
minitest (~> 5.1) minitest (~> 5.1)
...@@ -132,7 +132,7 @@ GEM ...@@ -132,7 +132,7 @@ GEM
rb-kqueue (>= 0.2) rb-kqueue (>= 0.2)
metaclass (0.0.4) metaclass (0.0.4)
method_source (0.8.2) method_source (0.8.2)
minitest (5.7.0) minitest (5.8.0)
mocha (1.1.0) mocha (1.1.0)
metaclass (~> 0.0.1) metaclass (~> 0.0.1)
mocha-on-bacon (0.2.2) mocha-on-bacon (0.2.2)
......
...@@ -123,7 +123,7 @@ module Pod ...@@ -123,7 +123,7 @@ module Pod
['--no-clean', 'Lint leaves the build directory intact for inspection'], ['--no-clean', 'Lint leaves the build directory intact for inspection'],
['--fail-fast', 'Lint stops on the first failing platform or subspec'], ['--fail-fast', 'Lint stops on the first failing platform or subspec'],
['--use-libraries', 'Lint uses static libraries to install the spec'], ['--use-libraries', 'Lint uses static libraries to install the spec'],
['--sources=https://github.com/artsy/Specs,master', 'The sources from which to pull dependant pods ' \ ['--sources=https://github.com/artsy/Specs,master', 'The sources from which to pull dependent pods ' \
'(defaults to https://github.com/CocoaPods/Specs.git). ' \ '(defaults to https://github.com/CocoaPods/Specs.git). ' \
'Multiple sources must be comma-delimited.'], 'Multiple sources must be comma-delimited.'],
['--private', 'Lint skips checks that apply only to public specs'], ['--private', 'Lint skips checks that apply only to public specs'],
......
...@@ -23,7 +23,7 @@ module Pod ...@@ -23,7 +23,7 @@ module Pod
[ [
['--allow-warnings', 'Allows pushing even if there are warnings'], ['--allow-warnings', 'Allows pushing even if there are warnings'],
['--use-libraries', 'Linter uses static libraries to install the spec'], ['--use-libraries', 'Linter uses static libraries to install the spec'],
['--sources=https://github.com/artsy/Specs,master', 'The sources from which to pull dependant pods ' \ ['--sources=https://github.com/artsy/Specs,master', 'The sources from which to pull dependent pods ' \
'(defaults to all available repos). ' \ '(defaults to all available repos). ' \
'Multiple sources must be comma-delimited.'], 'Multiple sources must be comma-delimited.'],
['--local-only', 'Does not perform the step of pushing REPO to its remote'], ['--local-only', 'Does not perform the step of pushing REPO to its remote'],
......
...@@ -23,7 +23,7 @@ module Pod ...@@ -23,7 +23,7 @@ module Pod
['--no-clean', 'Lint leaves the build directory intact for inspection'], ['--no-clean', 'Lint leaves the build directory intact for inspection'],
['--fail-fast', 'Lint stops on the first failing platform or subspec'], ['--fail-fast', 'Lint stops on the first failing platform or subspec'],
['--use-libraries', 'Lint uses static libraries to install the spec'], ['--use-libraries', 'Lint uses static libraries to install the spec'],
['--sources=https://github.com/artsy/Specs,master', 'The sources from which to pull dependant pods ' \ ['--sources=https://github.com/artsy/Specs,master', 'The sources from which to pull dependent pods ' \
'(defaults to https://github.com/CocoaPods/Specs.git). ' \ '(defaults to https://github.com/CocoaPods/Specs.git). ' \
'Multiple sources must be comma-delimited.'], 'Multiple sources must be comma-delimited.'],
['--private', 'Lint skips checks that apply only to public specs'], ['--private', 'Lint skips checks that apply only to public specs'],
......
...@@ -45,14 +45,10 @@ module Pod ...@@ -45,14 +45,10 @@ module Pod
# #
# @return [String] the output of the command (STDOUT and STDERR). # @return [String] the output of the command (STDOUT and STDERR).
# #
# @todo Find a way to display the live output of the commands. def self.execute_command(executable, command, raise_on_failure = true)
#
def self.execute_command(executable, command, raise_on_failure)
bin = which(executable) bin = which(executable)
raise Informative, "Unable to locate the executable `#{executable}`" unless bin raise Informative, "Unable to locate the executable `#{executable}`" unless bin
require 'shellwords'
command = command.map(&:to_s) command = command.map(&:to_s)
full_command = "#{bin} #{command.join(' ')}" full_command = "#{bin} #{command.join(' ')}"
...@@ -64,7 +60,8 @@ module Pod ...@@ -64,7 +60,8 @@ module Pod
end end
status = popen3(bin, command, stdout, stderr) status = popen3(bin, command, stdout, stderr)
output = stdout.join + stderr.join stdout, stderr = stdout.join, stderr.join
output = stdout + stderr
unless status.success? unless status.success?
if raise_on_failure if raise_on_failure
raise Informative, "#{full_command}\n\n#{output}" raise Informative, "#{full_command}\n\n#{output}"
...@@ -72,6 +69,7 @@ module Pod ...@@ -72,6 +69,7 @@ module Pod
UI.message("[!] Failed: #{full_command}".red) UI.message("[!] Failed: #{full_command}".red)
end end
end end
output output
end end
...@@ -95,6 +93,38 @@ module Pod ...@@ -95,6 +93,38 @@ module Pod
nil nil
end end
# Runs the given command, capturing the desired output.
#
# @param [String] bin
# The binary to use.
#
# @param [Array<#to_s>] command
# The command to send to the binary.
#
# @param [Symbol] capture
# Whether it should raise if the command fails.
#
# @raise If the executable could not be located.
#
# @return [(String, Process::Status)]
# The desired captured output from the command, and the status from
# running the command.
#
def self.capture_command(executable, command, capture: :merge)
bin = which(executable)
raise Informative, "Unable to locate the executable `#{executable}`" unless bin
require 'open3'
command = command.map(&:to_s)
case capture
when :merge then Open3.capture2e(bin, *command)
when :both then Open3.capture3(bin, *command)
when :out then Open3.capture2(bin, *command)
when :err then Open3.capture3(bin, *command).drop(1)
when :none then Open3.capture2(bin, *command).last
end
end
private private
def self.popen3(bin, command, stdout, stderr) def self.popen3(bin, command, stdout, stderr)
......
...@@ -34,7 +34,7 @@ module Pod ...@@ -34,7 +34,7 @@ module Pod
# @return [String] The contents of the embed frameworks script. # @return [String] The contents of the embed frameworks script.
# #
def script def script
script = <<-eos.strip_heredoc script = <<-SH.strip_heredoc
#!/bin/sh #!/bin/sh
set -e set -e
...@@ -47,8 +47,10 @@ module Pod ...@@ -47,8 +47,10 @@ module Pod
{ {
if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then
local source="${BUILT_PRODUCTS_DIR}/$1" local source="${BUILT_PRODUCTS_DIR}/$1"
else elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then
local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")" local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")"
elif [ -r "$1" ]; then
local source="$1"
fi fi
local destination="${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" local destination="${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
...@@ -62,14 +64,24 @@ module Pod ...@@ -62,14 +64,24 @@ module Pod
echo "rsync -av --filter \\"- CVS/\\" --filter \\"- .svn/\\" --filter \\"- .git/\\" --filter \\"- .hg/\\" --filter \\"- Headers\\" --filter \\"- PrivateHeaders\\" --filter \\"- Modules\\" \\"${source}\\" \\"${destination}\\"" echo "rsync -av --filter \\"- CVS/\\" --filter \\"- .svn/\\" --filter \\"- .git/\\" --filter \\"- .hg/\\" --filter \\"- Headers\\" --filter \\"- PrivateHeaders\\" --filter \\"- Modules\\" \\"${source}\\" \\"${destination}\\""
rsync -av --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}" rsync -av --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}"
local basename
basename="$(basename -s .framework "$1")"
binary="${destination}/${basename}.framework/${basename}"
if ! [ -r "$binary" ]; then
binary="${destination}/${basename}"
fi
# Strip invalid architectures so "fat" simulator / device frameworks work on device
if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then
strip_invalid_archs "$binary"
fi
# Resign the code if required by the build settings to avoid unstable apps # Resign the code if required by the build settings to avoid unstable apps
code_sign_if_enabled "${destination}/$(basename "$1")" code_sign_if_enabled "${destination}/$(basename "$1")"
# Embed linked Swift runtime libraries # Embed linked Swift runtime libraries
local basename
basename="$(basename "$1" | sed -E s/\\\\..+// && exit ${PIPESTATUS[0]})"
local swift_runtime_libs local swift_runtime_libs
swift_runtime_libs=$(xcrun otool -LX "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/${basename}.framework/${basename}" | grep --color=never @rpath/libswift | sed -E s/@rpath\\\\/\\(.+dylib\\).*/\\\\1/g | uniq -u && exit ${PIPESTATUS[0]}) swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\\\/\\(.+dylib\\).*/\\\\1/g | uniq -u && exit ${PIPESTATUS[0]})
for lib in $swift_runtime_libs; do for lib in $swift_runtime_libs; do
echo "rsync -auv \\"${SWIFT_STDLIB_PATH}/${lib}\\" \\"${destination}\\"" echo "rsync -auv \\"${SWIFT_STDLIB_PATH}/${lib}\\" \\"${destination}\\""
rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}" rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}"
...@@ -87,15 +99,33 @@ module Pod ...@@ -87,15 +99,33 @@ module Pod
fi fi
} }
eos # Strip invalid architectures
script += "\n" unless frameworks_by_config.values.all?(&:empty?) strip_invalid_archs() {
binary="$1"
# Get architectures for current file
archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | rev)"
stripped=""
for arch in $archs; do
if ! [[ "${VALID_ARCHS}" == *"$arch"* ]]; then
# Strip non-valid architectures in-place
lipo -remove "$arch" -output "$binary" "$binary" || exit 1
stripped="$stripped $arch"
fi
done
if [[ "$stripped" ]]; then
echo "Stripped $binary of architectures:$stripped"
fi
}
SH
script << "\n" unless frameworks_by_config.values.all?(&:empty?)
frameworks_by_config.each do |config, frameworks| frameworks_by_config.each do |config, frameworks|
unless frameworks.empty? unless frameworks.empty?
script += %(if [[ "$CONFIGURATION" == "#{config}" ]]; then\n) script << %(if [[ "$CONFIGURATION" == "#{config}" ]]; then\n)
frameworks.each do |framework| frameworks.each do |framework|
script += " install_framework '#{framework}'\n" script << %( install_framework "#{framework}"\n)
end end
script += "fi\n" script << "fi\n"
end end
end end
script script
......
...@@ -53,11 +53,12 @@ module Pod ...@@ -53,11 +53,12 @@ module Pod
# #
def generate def generate
includes_static_libs = !target.requires_frameworks? includes_static_libs = !target.requires_frameworks?
includes_static_libs ||= pod_targets.flat_map(&:file_accessors).any? { |fa| !fa.vendored_libraries.empty? } includes_static_libs ||= pod_targets.flat_map(&:file_accessors).any? { |fa| !fa.vendored_static_artifacts.empty? }
config = { config = {
'OTHER_LDFLAGS' => '$(inherited) ' + XCConfigHelper.default_ld_flags(target, includes_static_libs), 'OTHER_LDFLAGS' => '$(inherited) ' + XCConfigHelper.default_ld_flags(target, includes_static_libs),
'PODS_ROOT' => target.relative_pods_root, 'PODS_ROOT' => target.relative_pods_root,
'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) COCOAPODS=1', 'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) COCOAPODS=1',
'FRAMEWORK_SEARCH_PATHS' => '$(inherited) ',
} }
@xcconfig = Xcodeproj::Config.new(config) @xcconfig = Xcodeproj::Config.new(config)
...@@ -112,7 +113,7 @@ module Pod ...@@ -112,7 +113,7 @@ module Pod
build_settings['OTHER_CFLAGS'] += ' ' + XCConfigHelper.quote(library_header_search_paths, '-isystem') build_settings['OTHER_CFLAGS'] += ' ' + XCConfigHelper.quote(library_header_search_paths, '-isystem')
end end
if pod_targets.any? { |t| t.should_build? && t.scoped? } if pod_targets.any? { |t| t.should_build? && t.scoped? }
build_settings['FRAMEWORK_SEARCH_PATHS'] = '$(inherited) "$PODS_FRAMEWORK_BUILD_PATH"' build_settings['FRAMEWORK_SEARCH_PATHS'] = '"$PODS_FRAMEWORK_BUILD_PATH"'
end end
@xcconfig.merge!(build_settings) @xcconfig.merge!(build_settings)
else else
......
...@@ -43,6 +43,7 @@ module Pod ...@@ -43,6 +43,7 @@ module Pod
target_search_paths = target.build_headers.search_paths(target.platform) target_search_paths = target.build_headers.search_paths(target.platform)
sandbox_search_paths = target.sandbox.public_headers.search_paths(target.platform) sandbox_search_paths = target.sandbox.public_headers.search_paths(target.platform)
search_paths = target_search_paths.concat(sandbox_search_paths).uniq search_paths = target_search_paths.concat(sandbox_search_paths).uniq
framework_search_paths = target.dependent_targets.flat_map(&:file_accessors).flat_map(&:vendored_frameworks).map { |fw| '${PODS_ROOT}/' << fw.dirname.relative_path_from(target.sandbox.root).to_s }
config = { config = {
'OTHER_LDFLAGS' => XCConfigHelper.default_ld_flags(target), 'OTHER_LDFLAGS' => XCConfigHelper.default_ld_flags(target),
...@@ -50,9 +51,12 @@ module Pod ...@@ -50,9 +51,12 @@ module Pod
'HEADER_SEARCH_PATHS' => XCConfigHelper.quote(search_paths), 'HEADER_SEARCH_PATHS' => XCConfigHelper.quote(search_paths),
'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) COCOAPODS=1', 'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) COCOAPODS=1',
'SKIP_INSTALL' => 'YES', 'SKIP_INSTALL' => 'YES',
'FRAMEWORK_SEARCH_PATHS' => '$(inherited) ' << XCConfigHelper.quote(framework_search_paths)
# 'USE_HEADERMAP' => 'NO' # 'USE_HEADERMAP' => 'NO'
} }
@xcconfig = Xcodeproj::Config.new(config)
if target.requires_frameworks? && target.scoped? if target.requires_frameworks? && target.scoped?
# Only quote the FRAMEWORK_SEARCH_PATHS entry, because it’s a setting that takes multiple values. # Only quote the FRAMEWORK_SEARCH_PATHS entry, because it’s a setting that takes multiple values.
# In addition, quoting CONFIGURATION_BUILD_DIR would make it be interpreted as a relative path. # In addition, quoting CONFIGURATION_BUILD_DIR would make it be interpreted as a relative path.
...@@ -61,10 +65,9 @@ module Pod ...@@ -61,10 +65,9 @@ module Pod
'FRAMEWORK_SEARCH_PATHS' => '"$PODS_FRAMEWORK_BUILD_PATH"', 'FRAMEWORK_SEARCH_PATHS' => '"$PODS_FRAMEWORK_BUILD_PATH"',
'CONFIGURATION_BUILD_DIR' => '$PODS_FRAMEWORK_BUILD_PATH', 'CONFIGURATION_BUILD_DIR' => '$PODS_FRAMEWORK_BUILD_PATH',
} }
config.merge!(build_settings) @xcconfig.merge!(build_settings)
end end
@xcconfig = Xcodeproj::Config.new(config)
XCConfigHelper.add_settings_for_file_accessors_of_target(target, @xcconfig) XCConfigHelper.add_settings_for_file_accessors_of_target(target, @xcconfig)
target.file_accessors.each do |file_accessor| target.file_accessors.each do |file_accessor|
@xcconfig.merge!(file_accessor.spec_consumer.pod_target_xcconfig) @xcconfig.merge!(file_accessor.spec_consumer.pod_target_xcconfig)
......
...@@ -417,11 +417,7 @@ module Pod ...@@ -417,11 +417,7 @@ module Pod
dependencies = pod_targets.select(&:should_build?).flat_map(&:dependencies) dependencies = pod_targets.select(&:should_build?).flat_map(&:dependencies)
dependended_upon_targets = pod_targets.select { |t| dependencies.include?(t.pod_name) && !t.should_build? } dependended_upon_targets = pod_targets.select { |t| dependencies.include?(t.pod_name) && !t.should_build? }
static_libs = dependended_upon_targets.flat_map(&:file_accessors).flat_map do |fa| static_libs = dependended_upon_targets.flat_map(&:file_accessors).flat_map(&:vendored_static_artifacts)
static_frameworks = fa.vendored_frameworks.reject { |fw| `file #{fw + fw.basename('.framework')} 2>&1` =~ /dynamically linked/ }
fa.vendored_libraries + static_frameworks
end
unless static_libs.empty? unless static_libs.empty?
raise Informative, "The '#{aggregate_target.label}' target has " \ raise Informative, "The '#{aggregate_target.label}' target has " \
"transitive dependencies that include static binaries: (#{static_libs.to_sentence})" "transitive dependencies that include static binaries: (#{static_libs.to_sentence})"
......
...@@ -306,6 +306,7 @@ module Pod ...@@ -306,6 +306,7 @@ module Pod
# transitive dependencies can't be deduplicated. # transitive dependencies can't be deduplicated.
pod_targets.flat_map do |target| pod_targets.flat_map do |target|
dependent_targets = transitive_dependencies_for_pod_target(target, pod_targets) dependent_targets = transitive_dependencies_for_pod_target(target, pod_targets)
target.dependent_targets = dependent_targets
if dependent_targets.any?(&:scoped?) if dependent_targets.any?(&:scoped?)
target.scoped target.scoped
else else
......
...@@ -18,8 +18,8 @@ module Pod ...@@ -18,8 +18,8 @@ module Pod
create_info_plist_file create_info_plist_file
create_module_map create_module_map
create_umbrella_header create_umbrella_header
create_embed_frameworks_script
end end
create_embed_frameworks_script
create_bridge_support_file create_bridge_support_file
create_copy_resources_script create_copy_resources_script
create_acknowledgements create_acknowledgements
...@@ -145,10 +145,12 @@ module Pod ...@@ -145,10 +145,12 @@ module Pod
frameworks_by_config = {} frameworks_by_config = {}
target.user_build_configurations.keys.each do |config| target.user_build_configurations.keys.each do |config|
relevant_pod_targets = target.pod_targets.select do |pod_target| relevant_pod_targets = target.pod_targets.select do |pod_target|
pod_target.include_in_build_config?(target_definition, config) && pod_target.should_build? pod_target.include_in_build_config?(target_definition, config)
end end
frameworks_by_config[config] = relevant_pod_targets.map do |pod_target| frameworks_by_config[config] = relevant_pod_targets.flat_map do |pod_target|
"#{target_definition.label}/#{pod_target.product_name}" frameworks = pod_target.file_accessors.flat_map(&:vendored_dynamic_artifacts).map { |fw| "${PODS_ROOT}/#{fw.relative_path_from(sandbox.root)}" }
frameworks << "#{target_definition.label}/#{pod_target.product_name}" if pod_target.should_build? && pod_target.requires_frameworks?
frameworks
end end
end end
generator = Generator::EmbedFrameworksScript.new(frameworks_by_config) generator = Generator::EmbedFrameworksScript.new(frameworks_by_config)
......
...@@ -43,10 +43,10 @@ module Pod ...@@ -43,10 +43,10 @@ module Pod
XCConfigIntegrator.integrate(target, native_targets), XCConfigIntegrator.integrate(target, native_targets),
update_to_cocoapods_0_34, update_to_cocoapods_0_34,
update_to_cocoapods_0_37_1, update_to_cocoapods_0_37_1,
remove_embed_frameworks_script_phases, update_to_cocoapods_0_39,
unless native_targets_to_integrate.empty? unless native_targets_to_integrate.empty?
add_pods_library add_pods_library
add_embed_frameworks_script_phase if target.requires_frameworks? add_embed_frameworks_script_phase
add_copy_resources_script_phase add_copy_resources_script_phase
add_check_manifest_lock_script_phase add_check_manifest_lock_script_phase
true true
...@@ -112,11 +112,30 @@ module Pod ...@@ -112,11 +112,30 @@ module Pod
# @todo This can be removed for CocoaPods 1.0 # @todo This can be removed for CocoaPods 1.0
# #
def update_to_cocoapods_0_37_1 def update_to_cocoapods_0_37_1
(native_targets - native_targets_to_embed_in).any? do |native_target| targets_to_embed = native_targets.select do |target|
EMBED_FRAMEWORK_TARGET_TYPES.include?(target.symbol_type)
end
(native_targets - targets_to_embed).any? do |native_target|
remove_embed_frameworks_script_phase(native_target) remove_embed_frameworks_script_phase(native_target)
end end
end end
# Adds the embed frameworks script when integrating as a static library.
#
# @return [Bool] whether any changes to the project were made.
#
# @todo This can be removed for CocoaPods 1.0
#
def update_to_cocoapods_0_39
requires_update = native_targets_to_embed_in.any? do |target|
!target.shell_script_build_phases.find { |bp| bp.name == 'Embed Pods Frameworks' }
end
if requires_update
add_embed_frameworks_script_phase
true
end
end
# Adds spec product reference to the frameworks build phase of the # Adds spec product reference to the frameworks build phase of the
# {TargetDefinition} integration libraries. Adds a file reference to # {TargetDefinition} integration libraries. Adds a file reference to
# the frameworks group of the project and adds it to the frameworks # the frameworks group of the project and adds it to the frameworks
...@@ -166,19 +185,6 @@ module Pod ...@@ -166,19 +185,6 @@ module Pod
end end
end end
# Delete 'Embed Pods Frameworks' Build Phases, if they exist
# and are not needed anymore due to not integrating the
# dependencies by frameworks.
#
# @return [Bool] whether any changes to the project were made.
#
def remove_embed_frameworks_script_phases
return false if target.requires_frameworks?
native_targets.any? do |native_target|
remove_embed_frameworks_script_phase(native_target)
end
end
# Delete a 'Embed Pods Frameworks' Copy Files Build Phase if present # Delete a 'Embed Pods Frameworks' Copy Files Build Phase if present
# #
# @param [PBXNativeTarget] native_target # @param [PBXNativeTarget] native_target
......
...@@ -152,6 +152,22 @@ module Pod ...@@ -152,6 +152,22 @@ module Pod
paths_for_attribute(:vendored_frameworks, true) paths_for_attribute(:vendored_frameworks, true)
end end
# @return [Array<Pathname>] The paths of the dynamic framework bundles
# that come shipped with the Pod.
#
def vendored_dynamic_frameworks
vendored_frameworks.select do |framework|
dynamic_binary?(framework + framework.basename('.*'))
end
end
# @return [Array<Pathname>] The paths of the static (fake) framework
# bundles that come shipped with the Pod.
#
def vendored_static_frameworks
vendored_frameworks - vendored_dynamic_frameworks
end
# @param [Pathname] framework # @param [Pathname] framework
# The vendored framework to search into. # The vendored framework to search into.
# @return [Pathname] The path of the header directory of the # @return [Pathname] The path of the header directory of the
...@@ -187,6 +203,36 @@ module Pod ...@@ -187,6 +203,36 @@ module Pod
paths_for_attribute(:vendored_libraries) paths_for_attribute(:vendored_libraries)
end end
# @return [Array<Pathname>] The paths of the dynamic libraries
# that come shipped with the Pod.
#
def vendored_dynamic_libraries
vendored_libraries.select do |library|
dynamic_binary?(library)
end
end
# @return [Array<Pathname>] The paths of the static libraries
# that come shipped with the Pod.
#
def vendored_static_libraries
vendored_libraries - vendored_dynamic_libraries
end
# @return [Array<Pathname>] The paths of the dynamic binary artifacts
# that come shipped with the Pod.
#
def vendored_dynamic_artifacts
vendored_dynamic_libraries + vendored_dynamic_frameworks
end
# @return [Array<Pathname>] The paths of the static binary artifacts
# that come shipped with the Pod.
#
def vendored_static_artifacts
vendored_static_libraries + vendored_static_frameworks
end
# @return [Hash{String => Array<Pathname>}] A hash that describes the # @return [Hash{String => Array<Pathname>}] A hash that describes the
# resource bundles of the Pod. The keys represent the name of # resource bundles of the Pod. The keys represent the name of
# the bundle while the values the path of the resources. # the bundle while the values the path of the resources.
...@@ -315,6 +361,17 @@ module Pod ...@@ -315,6 +361,17 @@ module Pod
result.flatten.compact.uniq result.flatten.compact.uniq
end end
# @param [Pathname] binary
# The file to be checked for being a dynamic Mach-O binary.
#
# @return [Boolean] Whether `binary` can be dynamically linked.
#
def dynamic_binary?(binary)
return unless binary.file?
output, status = Executable.capture_command('file', [binary], :capture => :out)
status.success? && output =~ /dynamically linked/
end
#-----------------------------------------------------------------------# #-----------------------------------------------------------------------#
end end
end end
......
...@@ -33,6 +33,11 @@ module Pod ...@@ -33,6 +33,11 @@ module Pod
attr_reader :scoped attr_reader :scoped
alias_method :scoped?, :scoped alias_method :scoped?, :scoped
# @return [Array<PodTarget>] the targets that this target has a dependency
# upon.
#
attr_accessor :dependent_targets
# @param [Array<Specification>] @spec #see spec # @param [Array<Specification>] @spec #see spec
# @param [Array<TargetDefinition>] target_definitions @see target_definitions # @param [Array<TargetDefinition>] target_definitions @see target_definitions
# @param [Sandbox] sandbox @see sandbox # @param [Sandbox] sandbox @see sandbox
...@@ -49,6 +54,7 @@ module Pod ...@@ -49,6 +54,7 @@ module Pod
@build_headers = Sandbox::HeadersStore.new(sandbox, 'Private') @build_headers = Sandbox::HeadersStore.new(sandbox, 'Private')
@file_accessors = [] @file_accessors = []
@resource_bundle_targets = [] @resource_bundle_targets = []
@dependent_targets = []
end end
# @return [Array<PodTarget>] a scoped copy for each target definition. # @return [Array<PodTarget>] a scoped copy for each target definition.
...@@ -60,6 +66,7 @@ module Pod ...@@ -60,6 +66,7 @@ module Pod
target.user_build_configurations = user_build_configurations target.user_build_configurations = user_build_configurations
target.native_target = native_target target.native_target = native_target
target.archs = archs target.archs = archs
target.dependent_targets = dependent_targets.map(&:scoped)
end end
end end
end end
......
...@@ -382,8 +382,8 @@ module Pod ...@@ -382,8 +382,8 @@ module Pod
deployment_target = spec.subspec_by_name(subspec_name).deployment_target(consumer.platform_name) deployment_target = spec.subspec_by_name(subspec_name).deployment_target(consumer.platform_name)
unless file_accessor.nil? unless file_accessor.nil?
dynamic_frameworks = file_accessor.vendored_frameworks.select { |fw| `file #{fw + fw.basename('.framework')} 2>&1` =~ /dynamically linked/ } dynamic_frameworks = file_accessor.vendored_dynamic_frameworks
dynamic_libraries = file_accessor.vendored_libraries.select { |lib| `file #{lib} 2>&1` =~ /dynamically linked/ } dynamic_libraries = file_accessor.vendored_dynamic_libraries
if (dynamic_frameworks.count > 0 || dynamic_libraries.count > 0) && consumer.platform_name == :ios && if (dynamic_frameworks.count > 0 || dynamic_libraries.count > 0) && consumer.platform_name == :ios &&
(deployment_target.nil? || Version.new(deployment_target).major < 8) (deployment_target.nil? || Version.new(deployment_target).major < 8)
error('dynamic', 'Dynamic frameworks and libraries are only supported on iOS 8.0 and onwards.') error('dynamic', 'Dynamic frameworks and libraries are only supported on iOS 8.0 and onwards.')
......
Subproject commit c3a5c5887ee81a34d548accc3e84aea3d071a5b2 Subproject commit 748ad0dac4f5660eba1d191efa89e0fc8d791b0e
...@@ -47,6 +47,8 @@ require 'bundler/setup' ...@@ -47,6 +47,8 @@ require 'bundler/setup'
require 'pretty_bacon' require 'pretty_bacon'
require 'colored' require 'colored'
require 'clintegracon' require 'clintegracon'
require 'fileutils'
require 'integration/file_tree'
require 'integration/xcodeproj_project_yaml' require 'integration/xcodeproj_project_yaml'
require 'tmpdir' require 'tmpdir'
...@@ -69,6 +71,12 @@ CLIntegracon.configure do |c| ...@@ -69,6 +71,12 @@ CLIntegracon.configure do |c|
end end
end end
c.transform_produced '**/*.framework' do |path|
tree = FileTree.to_tree(path)
FileUtils.rm_rf path
File.open(path, 'w') { |f| f << tree }
end
# Register special handling for YAML files # Register special handling for YAML files
paths = [/Podfile\.lock/, /Manifest\.lock$/, /xcodeproj\.yaml$/] paths = [/Podfile\.lock/, /Manifest\.lock$/, /xcodeproj\.yaml$/]
c.has_special_handling_for(*paths) do |path| c.has_special_handling_for(*paths) do |path|
...@@ -115,16 +123,28 @@ describe_cli 'pod' do ...@@ -115,16 +123,28 @@ describe_cli 'pod' do
s.replace_path ROOT.to_s, 'ROOT' s.replace_path ROOT.to_s, 'ROOT'
s.replace_path `which git`.chomp, 'GIT_BIN' s.replace_path `which git`.chomp, 'GIT_BIN'
s.replace_path `which hg`.chomp, 'HG_BIN' if has_mercurial s.replace_path `which hg`.chomp, 'HG_BIN' if has_mercurial
s.replace_path `which bash`.chomp, 'BASH_BIN'
s.replace_path `which curl`.chomp, 'CURL_BIN'
s.replace_user_path 'Library/Caches/CocoaPods', 'CACHES_DIR' s.replace_user_path 'Library/Caches/CocoaPods', 'CACHES_DIR'
s.replace_pattern /#{Dir.tmpdir}\/[\w-]+/i, 'TMPDIR' s.replace_pattern /#{Dir.tmpdir}\/[\w-]+/io, 'TMPDIR'
s.replace_pattern /\d{4}-\d\d-\d\d \d\d:\d\d:\d\d [-+]\d{4}/, '<#DATE#>' s.replace_pattern /\d{4}-\d\d-\d\d \d\d:\d\d:\d\d [-+]\d{4}/, '<#DATE#>'
s.replace_pattern /\(Took \d+.\d+ seconds\)/, '(Took <#DURATION#> seconds)' s.replace_pattern /\(Took \d+.\d+ seconds\)/, '(Took <#DURATION#> seconds)'
s.replace_path %r{ s.replace_path %r{
`[^`]*? # The opening backtick on a plugin path `[^`]*? # The opening backtick on a plugin path
([[[:alnum:]]_+-]+?) # The plugin name ([[[:alnum:]]_+-]+?) # The plugin name
(- ([[:xdigit:]]+ | #{Gem::Version::VERSION_PATTERN}))? # The version or SHA (- ([[:xdigit:]]+ | #{Gem::Version::VERSION_PATTERN}))? # The version or SHA
/lib/cocoapods_plugin.rb # The actual plugin file that gets loaded /lib/cocoapods_plugin.rb # The actual plugin file that gets loaded
}ix, '`\1/lib/cocoapods_plugin.rb' }iox, '`\1/lib/cocoapods_plugin.rb'
# rubocop:disable Style/RegexpLiteral
s.replace_pattern %r{
^(\s* \$ \s (CURL_BIN | #{`which curl`.strip}) .* \n)
^\s* % \s* Total .* \n
^\s* Dload \s* Upload .* \n
(^\s* [[:cntrl:]] .* \n)+
}iox, "\\1\n"
# rubocop:enable Style/RegexpLiteral
end end
describe 'Pod install' do describe 'Pod install' do
...@@ -226,6 +246,13 @@ describe_cli 'pod' do ...@@ -226,6 +246,13 @@ describe_cli 'pod' do
'install --no-repo-update' 'install --no-repo-update'
end end
describe 'Integrates a Pod using a dynamic vendored framework' do
# We have to disable verbose mode by adding --no-verbose here,
# otherwise curl output is included in execution output.
behaves_like cli_spec 'install_vendored_dynamic_framework',
'install --no-repo-update --no-verbose'
end
# @todo add tests for all the hooks API # @todo add tests for all the hooks API
# #
describe 'Runs the Podfile callbacks' do describe 'Runs the Podfile callbacks' do
......
require 'pathname'
module FileTree
def to_tree(path, depth = 0)
path = Pathname(path)
indentation = ' ' * depth * 2
tree = indentation << path.to_path << "\n"
path.children.each do |child|
tree << to_tree(child, depth + 1)
end if path.directory?
tree
end
module_function :to_tree
end
...@@ -8,17 +8,17 @@ module Pod ...@@ -8,17 +8,17 @@ module Pod
'Release' => %w(CrashlyticsFramework.framework), 'Release' => %w(CrashlyticsFramework.framework),
} }
generator = Pod::Generator::EmbedFrameworksScript.new(frameworks) generator = Pod::Generator::EmbedFrameworksScript.new(frameworks)
generator.send(:script).should.include <<-eos.strip_heredoc generator.send(:script).should.include <<-SH.strip_heredoc
if [[ "$CONFIGURATION" == "Debug" ]]; then if [[ "$CONFIGURATION" == "Debug" ]]; then
install_framework 'Pods/Loopback.framework' install_framework "Pods/Loopback.framework"
install_framework 'Reveal.framework' install_framework "Reveal.framework"
fi fi
eos SH
generator.send(:script).should.include <<-eos.strip_heredoc generator.send(:script).should.include <<-SH.strip_heredoc
if [[ "$CONFIGURATION" == "Release" ]]; then if [[ "$CONFIGURATION" == "Release" ]]; then
install_framework 'CrashlyticsFramework.framework' install_framework "CrashlyticsFramework.framework"
fi fi
eos SH
end end
end end
end end
...@@ -158,7 +158,7 @@ module Pod ...@@ -158,7 +158,7 @@ module Pod
end end
it 'does not add the framework build path to the xcconfig' do it 'does not add the framework build path to the xcconfig' do
@xcconfig.to_hash['FRAMEWORK_SEARCH_PATHS'].should.be.nil? @xcconfig.to_hash['FRAMEWORK_SEARCH_PATHS'].should.be.nil
end end
it 'configures the project to load all members that implement Objective-c classes or categories' do it 'configures the project to load all members that implement Objective-c classes or categories' do
......
...@@ -47,6 +47,7 @@ module Pod ...@@ -47,6 +47,7 @@ module Pod
'Pods-acknowledgements.markdown', 'Pods-acknowledgements.markdown',
'Pods-acknowledgements.plist', 'Pods-acknowledgements.plist',
'Pods-dummy.m', 'Pods-dummy.m',
'Pods-frameworks.sh',
'Pods-resources.sh', 'Pods-resources.sh',
'Pods.appstore.xcconfig', 'Pods.appstore.xcconfig',
'Pods.debug.xcconfig', 'Pods.debug.xcconfig',
......
...@@ -108,11 +108,11 @@ module Pod ...@@ -108,11 +108,11 @@ module Pod
phase.nil?.should == false phase.nil?.should == false
end end
it 'does not add an embed frameworks build phase by default' do it 'adds an embed frameworks build phase by default' do
@target_integrator.integrate! @target_integrator.integrate!
target = @target_integrator.send(:native_targets).first target = @target_integrator.send(:native_targets).first
phase = target.shell_script_build_phases.find { |bp| bp.name == 'Embed Pods Frameworks' } phase = target.shell_script_build_phases.find { |bp| bp.name == 'Embed Pods Frameworks' }
phase.nil?.should == true phase.nil?.should == false
end end
it 'does not add an embed frameworks build phase if the target to integrate is a framework' do it 'does not add an embed frameworks build phase if the target to integrate is a framework' do
...@@ -151,25 +151,24 @@ module Pod ...@@ -151,25 +151,24 @@ module Pod
phase.nil?.should == false phase.nil?.should == false
end end
it 'removes existing embed frameworks build phases from integrated framework targets' do it 'does not remove existing embed frameworks build phases from integrated framework targets' do
@pod_bundle.stubs(:requires_frameworks? => true) @pod_bundle.stubs(:requires_frameworks? => true)
@target_integrator.integrate! @target_integrator.integrate!
@pod_bundle.stubs(:requires_frameworks? => false) @pod_bundle.stubs(:requires_frameworks? => false)
target = @target_integrator.send(:native_targets).first target = @target_integrator.send(:native_targets).first
target.stubs(:symbol_type).returns(:framework)
@target_integrator.integrate! @target_integrator.integrate!
phase = target.shell_script_build_phases.find { |bp| bp.name == 'Embed Pods Frameworks' } phase = target.shell_script_build_phases.find { |bp| bp.name == 'Embed Pods Frameworks' }
phase.nil?.should == true phase.should.not.be.nil
end end
it 'removes existing embed frameworks build phases if frameworks are not used anymore' do it 'does not remove existing embed frameworks build phases if frameworks are not used anymore' do
@pod_bundle.stubs(:requires_frameworks? => true) @pod_bundle.stubs(:requires_frameworks? => true)
@target_integrator.integrate! @target_integrator.integrate!
@pod_bundle.stubs(:requires_frameworks? => false) @pod_bundle.stubs(:requires_frameworks? => false)
@target_integrator.integrate! @target_integrator.integrate!
target = @target_integrator.send(:native_targets).first target = @target_integrator.send(:native_targets).first
phase = target.shell_script_build_phases.find { |bp| bp.name == 'Embed Pods Frameworks' } phase = target.shell_script_build_phases.find { |bp| bp.name == 'Embed Pods Frameworks' }
phase.nil?.should == true phase.nil?.should == false
end end
end end
......
...@@ -386,6 +386,7 @@ module Pod ...@@ -386,6 +386,7 @@ module Pod
end end
@installer.stubs(:podfile).returns(podfile) @installer.stubs(:podfile).returns(podfile)
@installer.stubs(:lockfile).returns(nil) @installer.stubs(:lockfile).returns(nil)
Downloader::Git.any_instance.expects(:download).once
Downloader::Git.any_instance.expects(:download_head).once Downloader::Git.any_instance.expects(:download_head).once
Downloader::Git.any_instance.stubs(:checkout_options).returns({}) Downloader::Git.any_instance.stubs(:checkout_options).returns({})
@installer.prepare @installer.prepare
......
...@@ -251,7 +251,7 @@ module Pod ...@@ -251,7 +251,7 @@ module Pod
UI.warnings = '' UI.warnings = ''
set_up_test_repo_for_update set_up_test_repo_for_update
Dir.chdir(test_repo_path) do Dir.chdir(test_repo_path) do
`git remote set-url origin https://example.com` `git remote set-url origin file:///dev/null`
end end
SourcesManager.update(test_repo_path.basename.to_s, true) SourcesManager.update(test_repo_path.basename.to_s, true)
UI.warnings.should.include('not able to update the `master` repo') UI.warnings.should.include('not able to update the `master` repo')
......
...@@ -490,6 +490,13 @@ module Pod ...@@ -490,6 +490,13 @@ module Pod
end end
it 'validates a podspec with dependencies' do it 'validates a podspec with dependencies' do
podspec = stub_podspec(/.*name.*/, '"name": "SBJson",').gsub(/.*version.*/, '"version": "3.2",')
file = write_podspec(podspec, 'SBJson.podspec.json')
spec = Specification.from_file(file)
set = mock
set.stubs(:all_specifications).returns([spec])
Source::Aggregate.any_instance.stubs(:search).with(Dependency.new('SBJson', '~> 3.2')).returns(set)
podspec = stub_podspec(/.*name.*/, '"name": "ZKit",') podspec = stub_podspec(/.*name.*/, '"name": "ZKit",')
podspec.gsub!(/.*requires_arc.*/, '"dependencies": { "SBJson": [ "~> 3.2" ] }, "requires_arc": false') podspec.gsub!(/.*requires_arc.*/, '"dependencies": { "SBJson": [ "~> 3.2" ] }, "requires_arc": false')
file = write_podspec(podspec, 'ZKit.podspec.json') file = write_podspec(podspec, 'ZKit.podspec.json')
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment