Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 40 additions & 29 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,35 +1,36 @@
PATH
remote: .
specs:
cocoapods-rome (1.0.1)
cocoapods (= 1.8.0.beta.1)
cocoapods-rome (1.1.0)
cocoapods (~> 1.0)
fourflusher (~> 2.0)

GEM
remote: https://rubygems.org/
specs:
CFPropertyList (3.0.0)
activesupport (4.2.11.1)
i18n (~> 0.7)
CFPropertyList (3.0.2)
activesupport (5.2.4.4)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 0.7, < 2)
minitest (~> 5.1)
thread_safe (~> 0.3, >= 0.3.4)
tzinfo (~> 1.1)
algoliasearch (1.26.1)
addressable (2.7.0)
public_suffix (>= 2.0.2, < 5.0)
algoliasearch (1.27.5)
httpclient (~> 2.8, >= 2.8.3)
json (>= 1.5.1)
atomos (0.1.3)
bacon (1.2.0)
claide (1.0.3)
cocoapods (1.8.0.beta.1)
activesupport (>= 4.0.2, < 5)
cocoapods (1.10.0)
addressable (~> 2.6)
claide (>= 1.0.2, < 2.0)
cocoapods-core (= 1.8.0.beta.1)
cocoapods-core (= 1.10.0)
cocoapods-deintegrate (>= 1.0.3, < 2.0)
cocoapods-downloader (>= 1.2.2, < 2.0)
cocoapods-downloader (>= 1.4.0, < 2.0)
cocoapods-plugins (>= 1.0.0, < 2.0)
cocoapods-search (>= 1.0.0, < 2.0)
cocoapods-stats (>= 1.0.0, < 2.0)
cocoapods-trunk (>= 1.3.1, < 2.0)
cocoapods-trunk (>= 1.4.0, < 2.0)
cocoapods-try (>= 1.1.0, < 2.0)
colored2 (~> 3.1)
escape (~> 0.0.4)
Expand All @@ -38,48 +39,58 @@ GEM
molinillo (~> 0.6.6)
nap (~> 1.0)
ruby-macho (~> 1.4)
xcodeproj (>= 1.11.1, < 2.0)
cocoapods-core (1.8.0.beta.1)
activesupport (>= 4.0.2, < 6)
xcodeproj (>= 1.19.0, < 2.0)
cocoapods-core (1.10.0)
activesupport (> 5.0, < 6)
addressable (~> 2.6)
algoliasearch (~> 1.0)
concurrent-ruby (~> 1.1)
fuzzy_match (~> 2.0.4)
nap (~> 1.0)
netrc (~> 0.11)
public_suffix
typhoeus (~> 1.0)
cocoapods-deintegrate (1.0.4)
cocoapods-downloader (1.2.2)
cocoapods-downloader (1.4.0)
cocoapods-plugins (1.0.0)
nap
cocoapods-search (1.0.0)
cocoapods-stats (1.1.0)
cocoapods-trunk (1.3.1)
cocoapods-trunk (1.5.0)
nap (>= 0.8, < 2.0)
netrc (~> 0.11)
cocoapods-try (1.1.0)
cocoapods-try (1.2.0)
colored2 (3.1.2)
concurrent-ruby (1.1.5)
concurrent-ruby (1.1.7)
escape (0.0.4)
ethon (0.12.0)
ffi (>= 1.3.0)
ffi (1.13.1)
fourflusher (2.3.1)
fuzzy_match (2.0.4)
gh_inspector (1.1.3)
httpclient (2.8.3)
i18n (0.9.5)
i18n (1.8.5)
concurrent-ruby (~> 1.0)
json (2.2.0)
minitest (5.11.3)
json (2.3.1)
minitest (5.14.2)
molinillo (0.6.6)
nanaimo (0.2.6)
nanaimo (0.3.0)
nap (1.1.0)
netrc (0.11.0)
public_suffix (4.0.6)
rake (13.0.1)
ruby-macho (1.4.0)
thread_safe (0.3.6)
tzinfo (1.2.5)
typhoeus (1.4.0)
ethon (>= 0.9.0)
tzinfo (1.2.8)
thread_safe (~> 0.1)
xcodeproj (1.12.0)
xcodeproj (1.19.0)
CFPropertyList (>= 2.3.3, < 4.0)
atomos (~> 0.1.3)
claide (>= 1.0.2, < 2.0)
colored2 (~> 3.1)
nanaimo (~> 0.2.6)
nanaimo (~> 0.3.0)

PLATFORMS
ruby
Expand All @@ -91,4 +102,4 @@ DEPENDENCIES
rake

BUNDLED WITH
1.17.2
1.17.3
41 changes: 41 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,47 @@ dSYM/
└── Alamofire
```

### XCFrameworks

The plugin builds Universal FAT framework by default. If you would instead prefer to build XCFramework, set `xcframework` to `true` in user options.

```ruby
platform :osx, '10.10'

plugin 'cocoapods-rome', {
dsym: true,
configuration: 'Release',
xcframework: true
}

target 'caesar' do
pod 'Alamofire'
end

```
### Build flags

If you would like to pass custom flags to xcodebuild, set `flags` key with an array of flags to be included.

#### Example
An example to build an XCFramework with Swift's ABI compatibility.

```ruby
platform :osx, '10.10'

plugin 'cocoapods-rome', {
dsym: true,
configuration: 'Release',
xcframework: true,
flags: ['BUILD_LIBRARY_FOR_DISTRIBUTION=YES']
}

target 'caesar' do
pod 'Alamofire'
end

```

## Hooks

The plugin allows you to provides hooks that will be called during the installation process.
Expand Down
2 changes: 1 addition & 1 deletion cocoapods-rome.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Xcode}
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
spec.require_paths = ["lib"]

spec.add_dependency "cocoapods", '1.8.0.beta.1'
spec.add_dependency "cocoapods", '~> 1.0'
spec.add_dependency "fourflusher", "~> 2.0"

spec.add_development_dependency "bundler", "~> 1.3"
Expand Down
2 changes: 1 addition & 1 deletion lib/cocoapods-rome/gem_version.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module CocoapodsRome
VERSION = "1.0.1"
VERSION = "1.1.0"
end
96 changes: 74 additions & 22 deletions lib/cocoapods-rome/post_install.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,39 +4,79 @@
'appletvsimulator' => 'tvOS',
'watchsimulator' => 'watchOS' }

def build_for_iosish_platform(sandbox, build_dir, target, device, simulator, configuration)
def build_for_iosish_platform(sandbox, build_dir, target, device, simulator, flags, configuration, build_xcframework=false)
deployment_target = target.platform_deployment_target
target_label = target.cocoapods_target_label

xcodebuild(sandbox, target_label, device, deployment_target, configuration)
xcodebuild(sandbox, target_label, simulator, deployment_target, configuration)
xcodebuild(sandbox, target_label, device, deployment_target, flags, configuration)
xcodebuild(sandbox, target_label, simulator, deployment_target, flags, configuration)

spec_names = target.specs.map { |spec| [spec.root.name, spec.root.module_name] }.uniq
spec_names.each do |root_name, module_name|
executable_path = "#{build_dir}/#{root_name}"
device_lib = "#{build_dir}/#{configuration}-#{device}/#{root_name}/#{module_name}.framework/#{module_name}"
device_framework_lib = File.dirname(device_lib)
simulator_lib = "#{build_dir}/#{configuration}-#{simulator}/#{root_name}/#{module_name}.framework/#{module_name}"
device_lib = "#{build_dir}/#{configuration}-#{device}/#{root_name}/#{module_name}.framework"
simulator_lib = "#{build_dir}/#{configuration}-#{simulator}/#{root_name}/#{module_name}.framework"

if build_xcframework
build_xcframework([device_lib, simulator_lib], build_dir, module_name)
else
executable_path = "#{build_dir}/#{root_name}"
build_universal_framework(device_lib, simulator_lib, build_dir, executable_path, module_name)
end

next unless File.file?(device_lib) && File.file?(simulator_lib)
FileUtils.rm device_lib if File.file?(device_lib)
FileUtils.rm simulator_lib if File.file?(simulator_lib)
end
end

lipo_log = `lipo -create -output #{executable_path} #{device_lib} #{simulator_lib}`
puts lipo_log unless File.exist?(executable_path)
def build_for_macos_platform(sandbox, build_dir, target, flags, configuration, build_xcframework=false)
target_label = target.cocoapods_target_label
xcodebuild(sandbox, target_label, flags, configuration)

FileUtils.mv executable_path, device_lib, :force => true
FileUtils.mv device_framework_lib, build_dir, :force => true
FileUtils.rm simulator_lib if File.file?(simulator_lib)
FileUtils.rm device_lib if File.file?(device_lib)
spec_names = target.specs.map { |spec| [spec.root.name, spec.root.module_name] }.uniq
spec_names.each do |root_name, module_name|
if build_xcframework
framework = "#{build_dir}/#{configuration}/#{root_name}/#{module_name}.framework"
build_xcframework([framework], build_dir, module_name)
end
end
end

def xcodebuild(sandbox, target, sdk='macosx', deployment_target=nil, configuration)
def xcodebuild(sandbox, target, sdk='macosx', deployment_target=nil, flags=nil, configuration)
args = %W(-project #{sandbox.project_path.realdirpath} -scheme #{target} -configuration #{configuration} -sdk #{sdk})
args += flags unless flags.nil?
platform = PLATFORMS[sdk]
args += Fourflusher::SimControl.new.destination(:oldest, platform, deployment_target) unless platform.nil?
Pod::Executable.execute_command 'xcodebuild', args, true
end

def build_universal_framework(device_lib, simulator_lib, build_dir, destination, module_name)
device_executable = "#{device_lib}/#{module_name}"
simulator_executable = "#{simulator_lib}/#{module_name}"

raise Pod::Informative, 'Framework executables were not found in the expected location.' unless File.file?(device_executable) && File.file?(simulator_executable)

device_framework_lib = File.dirname(device_executable)
lipo_log = `lipo -create -output #{destination} #{device_executable} #{simulator_executable}`
puts lipo_log unless File.exist?(destination)

FileUtils.mv destination, device_executable, :force => true
FileUtils.mv device_framework_lib, build_dir, :force => true
end

def build_xcframework(frameworks, build_dir, module_name)
output = "#{build_dir}/#{module_name}.xcframework"
return if File.exist?(output)

args = %W(-create-xcframework -output #{output})

frameworks.each do |framework|
return unless File.exist?(framework)
args += %W(-framework #{framework})
end

Pod::Executable.execute_command 'xcodebuild', args, true
end
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would suggest a couple of additions to this function. Sometimes we can have references to the same dependencies through other dependencies (e.g. we can have RxSwift but also RxTest which requires RxSwift) which can lead to duplicates and errors then.

def build_xcframework(frameworks, build_dir, module_name)
  xcframework = "#{build_dir}/#{module_name}.xcframework"
  return if File.exist?(xcframework) 

  args = %W(-create-xcframework -output #{xcframework})

  frameworks.each do |framework|
    return unless File.exist?(framework) 
    args += %W(-framework #{framework})
  end

  Pod::Executable.execute_command 'xcodebuild', args, true
end

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cool. thanks. will include

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello guys!

Congrats to this pull request! Awesome work! 😍😍
I was testing this fork within my setup, and after adding the changes provided by Alex, it works perfectly given those changes also prevent some issues with aggregated targets, given some of them won't produce any frameworks and those checks will allow to detect that and skip the XCFramework generation.

I was wondering if you're planning to merge this soon, given that after going further on the setup within my project, I did flag some other major issues happening on the last steps (copy phase) from Rome. It would be great if I could create a pull request after those changes gets merged back in master. 🙏 🙏 🙏

Again, great work! 🌟 🌟 This is a major step forward into actively support Rome.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown

@AlexShubin AlexShubin Jan 30, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for checking it out, @Ricowere! I'll add it as a suggestion. Also I don't think we're aware of merging plans, I'd gladly know it too :)


def enable_debug_information(project_path, configuration)
project = Xcodeproj::Project.open(project_path)
project.targets.each do |target|
Expand All @@ -63,12 +103,23 @@ def copy_dsym_files(dsym_destination, configuration)
Pod::HooksManager.register('cocoapods-rome', :post_install) do |installer_context, user_options|
enable_dsym = user_options.fetch('dsym', true)
configuration = user_options.fetch('configuration', 'Debug')
build_xcframework = user_options.fetch('xcframework', false)

flags = []

# Setting SKIP_INSTALL=NO to access the built frameworks inside the archive created
# instead of searching in Xcode’s default derived data folder
flags << "SKIP_INSTALL=NO" if build_xcframework

# Use custom flags passed via user options, if any
flags += user_options["flags"] if user_options["flags"]

if user_options["pre_compile"]
user_options["pre_compile"].call(installer_context)
end

sandbox_root = Pathname(installer_context.sandbox_root)
sandbox = Pod::Sandbox.new(sandbox_root)
sandbox = installer_context.sandbox

enable_debug_information(sandbox.project_path, configuration) if enable_dsym

Expand All @@ -81,19 +132,20 @@ def copy_dsym_files(dsym_destination, configuration)
targets = installer_context.umbrella_targets.select { |t| t.specs.any? }
targets.each do |target|
case target.platform_name
when :ios then build_for_iosish_platform(sandbox, build_dir, target, 'iphoneos', 'iphonesimulator', configuration)
when :osx then xcodebuild(sandbox, target.cocoapods_target_label, configuration)
when :tvos then build_for_iosish_platform(sandbox, build_dir, target, 'appletvos', 'appletvsimulator', configuration)
when :watchos then build_for_iosish_platform(sandbox, build_dir, target, 'watchos', 'watchsimulator', configuration)
when :ios then build_for_iosish_platform(sandbox, build_dir, target, 'iphoneos', 'iphonesimulator', flags, configuration, build_xcframework)
when :osx then build_for_macos_platform(sandbox, build_dir, target, flags, configuration, build_xcframework)
when :tvos then build_for_iosish_platform(sandbox, build_dir, target, 'appletvos', 'appletvsimulator', flags, configuration, build_xcframework)
when :watchos then build_for_iosish_platform(sandbox, build_dir, target, 'watchos', 'watchsimulator', flags, configuration, build_xcframework)
else raise "Unknown platform '#{target.platform_name}'" end
end

raise Pod::Informative, 'The build directory was not found in the expected location.' unless build_dir.directory?

# Make sure the device target overwrites anything in the simulator build, otherwise iTunesConnect
# can get upset about Info.plist containing references to the simulator SDK
frameworks = Pathname.glob("build/*/*/*.framework").reject { |f| f.to_s =~ /Pods[^.]+\.framework/ }
frameworks += Pathname.glob("build/*.framework").reject { |f| f.to_s =~ /Pods[^.]+\.framework/ }
build_type = build_xcframework ? "xcframework" : "framework"
frameworks = Pathname.glob("build/*/*/*.#{build_type}").reject { |f| f.to_s =~ /Pods[^.]+\.#{build_type}/ }
frameworks += Pathname.glob("build/*.#{build_type}").reject { |f| f.to_s =~ /Pods[^.]+\.#{build_type}/ }

resources = []

Expand Down