xcframework_converter 0.1.3 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ed8ad6ac521bd6f26cae4e1ed130e7faf4c861c9367d10a591f65ace5e0d0180
4
- data.tar.gz: 3a214bc46c53d8413a4082783d24d9fc4ebecdcf9bc695edd3a1908561eb952c
3
+ metadata.gz: 2df06815d507bcbbd8d8ea83882fe3c55463dcc9532063d4566f8d196e378ada
4
+ data.tar.gz: f49c4301fb89b90b1e30e77cbee37e175ea1d432a1c104f62131d689857d0a58
5
5
  SHA512:
6
- metadata.gz: 23717de292d647163e52c8c2055878b45c7e79dceb01e000bcb29830edb9c26c44e928c1dea8df1ec33f1f224fc7f9bbeb79ca876cd4a14d80cafe0eddfad87e
7
- data.tar.gz: d00b1bf35a52d2d42bba03f84ce88f35e19edab370465acb08d20bb886ced4e534bf5385e0f036aa3ee2ff5b341f612c080873a200142badc79b517fe2493cf4
6
+ metadata.gz: bdcc77aeb67f7eb84dbb8c469186e27a730616f9fa2c51a9e6a7e9ca91f800b4563858c18fd3c93a91298b911241aad577f9e0ba8086ba198f19932368868701
7
+ data.tar.gz: ea641b22490269b45530b719ca48435092055ed5515b8cce8fe7b9ddc866567a418bdb16d6b463b3482319c664cabd49253f963864a16bfa705fa5dd6ab4faf6
data/bin/xcfpatch ADDED
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'bundler/setup'
5
+ require 'xcframework_converter'
6
+
7
+ if ARGV.empty?
8
+ warn 'Usage: xcfpatch <path/to/XCFramework.xcframework>'
9
+ exit 1
10
+ end
11
+
12
+ XCFrameworkConverter.patch_xcframework(Pathname.new(ARGV[0]).realpath)
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cocoapods'
4
+ require 'cocoapods/xcode/xcframework'
5
+ require 'fileutils'
6
+ require 'xcodeproj'
7
+
8
+ # rubocop:disable Metrics/AbcSize
9
+
10
+ module XCFrameworkConverter
11
+ # Patches a binary (static or dynamic), turning an arm64-device into an arm64-simualtor.
12
+ # For more info:
13
+ # static libs: https://bogo.wtf/arm64-to-sim.html
14
+ # dylibs: https://bogo.wtf/arm64-to-sim-dylibs.html
15
+ module ArmPatcher
16
+ class << self
17
+ def patch_arm_binary(slice)
18
+ require 'macho'
19
+
20
+ case slice.build_type.linkage
21
+ when :dynamic
22
+ patch_arm_binary_dynamic(slice)
23
+ when :static
24
+ patch_arm_binary_static(slice)
25
+ end
26
+
27
+ slice.path.glob('**/arm64*.swiftinterface').each do |interface_file|
28
+ `sed -i '' -E 's/target arm64-apple-ios([0-9.]+) /target arm64-apple-ios\\1-simulator /g' "#{interface_file}"`
29
+ end
30
+ end
31
+
32
+ private
33
+
34
+ def patch_arm_binary_dynamic(slice)
35
+ extracted_path = slice.path.join('arm64.dylib')
36
+ `xcrun lipo \"#{slice.binary_path}\" -thin arm64 -output \"#{extracted_path}\"`
37
+
38
+ file = MachO::MachOFile.new(extracted_path)
39
+ sdk_version = file[:LC_VERSION_MIN_IPHONEOS].first.version_string
40
+ `xcrun vtool -arch arm64 -set-build-version 7 #{sdk_version} #{sdk_version} -replace -output \"#{extracted_path}\" \"#{extracted_path}\"`
41
+ `xcrun lipo \"#{slice.binary_path}\" -replace arm64 \"#{extracted_path}\" -output \"#{slice.binary_path}\"`
42
+ extracted_path.rmtree
43
+ end
44
+
45
+ def arm2sim_path
46
+ Pathname.new(__FILE__).dirname.join('../arm2sim.swift')
47
+ end
48
+
49
+ def patch_arm_binary_static(slice)
50
+ extracted_path = slice.path.join('arm64.a')
51
+ `xcrun lipo \"#{slice.binary_path}\" -thin arm64 -output \"#{extracted_path}\"`
52
+ extracted_path_dir = slice.path.join('arm64-objects')
53
+ extracted_path_dir.mkdir
54
+ `cd \"#{extracted_path_dir}\" ; ar x \"#{extracted_path}\"`
55
+ Dir[extracted_path_dir.join('*.o')].each do |object_file|
56
+ file = MachO::MachOFile.new(object_file)
57
+ sdk_version = file[:LC_VERSION_MIN_IPHONEOS].first.version_string.to_i
58
+ `xcrun swift \"#{arm2sim_path}\" \"#{object_file}\" \"#{sdk_version}\" \"#{sdk_version}\"`
59
+ end
60
+ `cd \"#{extracted_path_dir}\" ; ar crv \"#{extracted_path}\" *.o`
61
+
62
+ `xcrun lipo \"#{slice.binary_path}\" -replace arm64 \"#{extracted_path}\" -output \"#{slice.binary_path}\"`
63
+ extracted_path_dir.rmtree
64
+ extracted_path.rmtree
65
+ end
66
+
67
+ public
68
+
69
+ def cleanup_unused_archs(slice)
70
+ supported_archs = slice.supported_archs
71
+ unsupported_archs = `xcrun lipo \"#{slice.binary_path}\" -archs`.split - supported_archs
72
+ unsupported_archs.each do |arch|
73
+ `xcrun lipo \"#{slice.binary_path}\" -remove \"#{arch}\" -output \"#{slice.binary_path}\"`
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'arm_patcher'
4
+ require_relative 'xcframework_ext'
5
+
6
+ require 'cocoapods'
7
+ require 'cocoapods/xcode/xcframework'
8
+ require 'fileutils'
9
+ require 'xcodeproj'
10
+
11
+ # rubocop:disable Metrics/AbcSize
12
+
13
+ # Converts a framework (static or dynamic) to an XCFramework, adding an arm64 simulator patch.
14
+ # For more info:
15
+ # static libs: https://bogo.wtf/arm64-to-sim.html
16
+ # dylibs: https://bogo.wtf/arm64-to-sim-dylibs.html
17
+ module XCFrameworkConverter
18
+ class << self
19
+ def plist_template_path
20
+ Pathname.new(__FILE__).dirname.join('../xcframework_template.plist')
21
+ end
22
+
23
+ def convert_framework_to_xcframework(path)
24
+ plist = Xcodeproj::Plist.read_from_path(plist_template_path)
25
+ xcframework_path = Pathname.new(path).sub_ext('.xcframework')
26
+ xcframework_path.mkdir
27
+ plist['AvailableLibraries'].each do |slice|
28
+ slice_path = xcframework_path.join(slice['LibraryIdentifier'])
29
+ slice_path.mkdir
30
+ slice['LibraryPath'] = File.basename(path)
31
+ FileUtils.cp_r(path, slice_path)
32
+ end
33
+ Xcodeproj::Plist.write_to_path(plist, xcframework_path.join('Info.plist'))
34
+ FileUtils.rm_rf(path)
35
+ final_framework = Pod::Xcode::XCFramework.open_xcframework(xcframework_path)
36
+ final_framework.slices.each do |slice|
37
+ ArmPatcher.patch_arm_binary(slice) if slice.platform == :ios && slice.platform_variant == :simulator
38
+ ArmPatcher.cleanup_unused_archs(slice)
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'arm_patcher'
4
+ require_relative 'xcframework_ext'
5
+
6
+ require 'cocoapods'
7
+ require 'cocoapods/xcode/xcframework'
8
+ require 'fileutils'
9
+ require 'xcodeproj'
10
+
11
+ # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
12
+
13
+ # Converts a framework (static or dynamic) to an XCFramework, adding an arm64 simulator patch.
14
+ # For more info:
15
+ # static libs: https://bogo.wtf/arm64-to-sim.html
16
+ # dylibs: https://bogo.wtf/arm64-to-sim-dylibs.html
17
+ module XCFrameworkConverter
18
+ class << self
19
+ def patch_xcframework(xcframework_path)
20
+ xcframework = Pod::Xcode::XCFramework.open_xcframework(xcframework_path)
21
+
22
+ return nil if xcframework.slices.any? do |slice|
23
+ slice.platform == :ios &&
24
+ slice.platform_variant == :simulator &&
25
+ slice.supported_archs.include?('arm64')
26
+ end
27
+
28
+ original_arm_slice_identifier = xcframework.slices.find do |slice|
29
+ slice.platform == :ios && slice.supported_archs.include?('arm64')
30
+ end.identifier
31
+
32
+ patched_arm_slice_identifier = 'ios-arm64-simulator'
33
+
34
+ warn "Will patch #{xcframework_path}: #{original_arm_slice_identifier} -> #{patched_arm_slice_identifier}"
35
+
36
+ plist = xcframework.plist
37
+ slice_plist_to_add = plist['AvailableLibraries'].find { |s| s['LibraryIdentifier'] == original_arm_slice_identifier }.dup
38
+ slice_plist_to_add['LibraryIdentifier'] = patched_arm_slice_identifier
39
+ slice_plist_to_add['SupportedArchitectures'] = ['arm64']
40
+ slice_plist_to_add['SupportedPlatformVariant'] = 'simulator'
41
+ plist['AvailableLibraries'] << slice_plist_to_add
42
+
43
+ FileUtils.rm_rf(xcframework_path.join(patched_arm_slice_identifier))
44
+ FileUtils.cp_r(xcframework_path.join(original_arm_slice_identifier), xcframework_path.join(patched_arm_slice_identifier))
45
+
46
+ Xcodeproj::Plist.write_to_path(plist, xcframework_path.join('Info.plist'))
47
+
48
+ xcframework = Pod::Xcode::XCFramework.open_xcframework(xcframework_path)
49
+
50
+ slice = xcframework.slices.find { |s| s.identifier == patched_arm_slice_identifier }
51
+
52
+ ArmPatcher.patch_arm_binary(slice)
53
+ ArmPatcher.cleanup_unused_archs(slice)
54
+
55
+ xcframework_path
56
+ end
57
+ end
58
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module XCFrameworkConverter
4
- VERSION = '0.1.3'
4
+ VERSION = '0.3.1'
5
5
  end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cocoapods'
4
+ require 'cocoapods/xcode/xcframework'
5
+
6
+ module Pod
7
+ module Xcode
8
+ # open XCFramework
9
+ class XCFramework
10
+ def self.open_xcframework(xcframework_path)
11
+ if instance_method(:initialize).arity == 2
12
+ new(File.basename(xcframework_path), xcframework_path.realpath)
13
+ else
14
+ new(xcframework_path.realpath)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'xcframework_converter/creation'
4
+ require_relative 'xcframework_converter/patching'
3
5
  require_relative 'xcframework_converter/version'
4
6
 
5
7
  require 'cocoapods'
@@ -7,7 +9,7 @@ require 'cocoapods/xcode/xcframework'
7
9
  require 'fileutils'
8
10
  require 'xcodeproj'
9
11
 
10
- # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/ModuleLength, Metrics/PerceivedComplexity
12
+ # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
11
13
 
12
14
  # Converts a framework (static or dynamic) to XCFrameworks, adding an arm64 simulator patch.
13
15
  # For more info:
@@ -19,6 +21,16 @@ module XCFrameworkConverter
19
21
  installer.analysis_result.specifications.each do |spec|
20
22
  next if spec.source && spec.local?
21
23
 
24
+ pod_path = installer.sandbox.pod_dir(Pod::Specification.root_name(spec.name))
25
+
26
+ xcframeworks_to_patch = spec.available_platforms.map do |platform|
27
+ consumer = Pod::Specification::Consumer.new(spec, platform)
28
+ consumer.vendored_frameworks.select { |f| File.extname(f) == '.xcframework' }
29
+ .map { |f| pod_path.join(f) }
30
+ end.flatten.uniq
31
+
32
+ patch_xcframeworks_if_needed(xcframeworks_to_patch)
33
+
22
34
  frameworks_to_convert = spec.available_platforms.map do |platform|
23
35
  consumer = Pod::Specification::Consumer.new(spec, platform)
24
36
  before_rename = consumer.vendored_frameworks.select { |f| File.extname(f) == '.framework' }
@@ -27,18 +39,12 @@ module XCFrameworkConverter
27
39
  after_rename = before_rename.map { |f| Pathname.new(f).sub_ext('.xcframework').to_s }
28
40
  proxy = Pod::Specification::DSL::PlatformProxy.new(spec, platform.symbolic_name)
29
41
  proxy.vendored_frameworks = consumer.vendored_frameworks - before_rename + after_rename
30
- before_rename
42
+ before_rename.map { |f| pod_path.join(f) }
31
43
  end.flatten.uniq
32
44
 
33
- next if frameworks_to_convert.empty?
34
-
35
- pod_path = installer.sandbox.pod_dir(Pod::Specification.root_name(spec.name))
36
- convert_xcframeworks_if_present(frameworks_to_convert.map { |f| pod_path.join(f) })
45
+ convert_xcframeworks_if_present(frameworks_to_convert)
37
46
 
38
- # some pods put these as a way to NOT support arm64 sim
39
- # may stop working if a pod decides to put these in a platform proxy
40
- spec.attributes_hash['pod_target_xcconfig']&.delete('EXCLUDED_ARCHS[sdk=iphonesimulator*]')
41
- spec.attributes_hash['user_target_xcconfig']&.delete('EXCLUDED_ARCHS[sdk=iphonesimulator*]')
47
+ remove_troublesome_xcconfig_items(spec)
42
48
  end
43
49
  end
44
50
 
@@ -48,91 +54,19 @@ module XCFrameworkConverter
48
54
  end
49
55
  end
50
56
 
51
- def plist_template_path
52
- Pathname.new(__FILE__).dirname.join('xcframework_template.plist')
53
- end
54
-
55
- def convert_framework_to_xcframework(path)
56
- plist = Xcodeproj::Plist.read_from_path(plist_template_path)
57
- xcframework_path = Pathname.new(path).sub_ext('.xcframework')
58
- xcframework_path.mkdir
59
- plist['AvailableLibraries'].each do |slice|
60
- slice_path = xcframework_path.join(slice['LibraryIdentifier'])
61
- slice_path.mkdir
62
- slice['LibraryPath'] = File.basename(path)
63
- FileUtils.cp_r(path, slice_path)
64
- end
65
- Xcodeproj::Plist.write_to_path(plist, xcframework_path.join('Info.plist'))
66
- FileUtils.rm_rf(path)
67
- final_framework = open_xcframework(xcframework_path)
68
- final_framework.slices.each do |slice|
69
- patch_arm_binary(slice) if slice.platform == :ios && slice.platform_variant == :simulator
70
- cleanup_unused_archs(slice)
71
- end
72
- end
73
-
74
- def open_xcframework(xcframework_path)
75
- if Pod::Xcode::XCFramework.instance_method(:initialize).arity == 2
76
- Pod::Xcode::XCFramework.new(File.basename(xcframework_path), xcframework_path.realpath)
77
- else
78
- Pod::Xcode::XCFramework.new(xcframework_path.realpath)
79
- end
80
- end
81
-
82
- def patch_arm_binary(slice)
83
- require 'macho'
84
-
85
- case slice.build_type.linkage
86
- when :dynamic
87
- patch_arm_binary_dynamic(slice)
88
- when :static
89
- patch_arm_binary_static(slice)
90
- end
91
-
92
- slice.path.glob('**/arm64*.swiftinterface').each do |interface_file|
93
- `sed -i '' -E 's/target arm64-apple-ios([0-9.]+) /target arm64-apple-ios\\1-simulator /g' "#{interface_file}"`
57
+ def patch_xcframeworks_if_needed(xcframeworks)
58
+ xcframeworks.each do |path|
59
+ patch_xcframework(path) if Dir.exist?(path)
94
60
  end
95
61
  end
96
62
 
97
- def patch_arm_binary_dynamic(slice)
98
- extracted_path = slice.path.join('arm64.dylib')
99
- `xcrun lipo \"#{slice.binary_path}\" -thin arm64 -output \"#{extracted_path}\"`
100
-
101
- file = MachO::MachOFile.new(extracted_path)
102
- sdk_version = file[:LC_VERSION_MIN_IPHONEOS].first.version_string
103
- `xcrun vtool -arch arm64 -set-build-version 7 #{sdk_version} #{sdk_version} -replace -output \"#{extracted_path}\" \"#{extracted_path}\"`
104
- `xcrun lipo \"#{slice.binary_path}\" -replace arm64 \"#{extracted_path}\" -output \"#{slice.binary_path}\"`
105
- extracted_path.rmtree
106
- end
107
-
108
- def arm2sim_path
109
- Pathname.new(__FILE__).dirname.join('arm2sim.swift')
110
- end
111
-
112
- def patch_arm_binary_static(slice)
113
- extracted_path = slice.path.join('arm64.a')
114
- `xcrun lipo \"#{slice.binary_path}\" -thin arm64 -output \"#{extracted_path}\"`
115
- extracted_path_dir = slice.path.join('arm64-objects')
116
- extracted_path_dir.mkdir
117
- `cd \"#{extracted_path_dir}\" ; ar x \"#{extracted_path}\"`
118
- Dir[extracted_path_dir.join('*.o')].each do |object_file|
119
- file = MachO::MachOFile.new(object_file)
120
- sdk_version = file[:LC_VERSION_MIN_IPHONEOS].first.version_string.to_i
121
- `xcrun swift \"#{arm2sim_path}\" \"#{object_file}\" \"#{sdk_version}\" \"#{sdk_version}\"`
122
- end
123
- `cd \"#{extracted_path_dir}\" ; ar crv \"#{extracted_path}\" *.o`
124
-
125
- `xcrun lipo \"#{slice.binary_path}\" -replace arm64 \"#{extracted_path}\" -output \"#{slice.binary_path}\"`
126
- extracted_path_dir.rmtree
127
- extracted_path.rmtree
128
- end
129
-
130
- def cleanup_unused_archs(slice)
131
- supported_archs = slice.supported_archs
132
- unsupported_archs = `xcrun lipo \"#{slice.binary_path}\" -archs`.split - supported_archs
133
- unsupported_archs.each do |arch|
134
- `xcrun lipo \"#{slice.binary_path}\" -remove \"#{arch}\" -output \"#{slice.binary_path}\"`
135
- end
63
+ def remove_troublesome_xcconfig_items(spec)
64
+ # some pods put these as a way to NOT support arm64 sim
65
+ # may stop working if a pod decides to put these in a platform proxy
66
+ spec.attributes_hash['pod_target_xcconfig']&.delete('EXCLUDED_ARCHS[sdk=iphonesimulator*]')
67
+ spec.attributes_hash['user_target_xcconfig']&.delete('EXCLUDED_ARCHS[sdk=iphonesimulator*]')
68
+ spec.attributes_hash['pod_target_xcconfig']&.delete('VALID_ARCHS[sdk=iphonesimulator*]')
69
+ spec.attributes_hash['user_target_xcconfig']&.delete('VALID_ARCHS[sdk=iphonesimulator*]')
136
70
  end
137
71
  end
138
72
  end
metadata CHANGED
@@ -1,69 +1,63 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: xcframework_converter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Igor Makarov
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-12-20 00:00:00.000000000 Z
11
+ date: 2022-01-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: cocoapods
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ">="
18
- - !ruby/object:Gem::Version
19
- version: 1.10.0
20
17
  - - "~>"
21
18
  - !ruby/object:Gem::Version
22
- version: '1'
19
+ version: '1.10'
23
20
  type: :runtime
24
21
  prerelease: false
25
22
  version_requirements: !ruby/object:Gem::Requirement
26
23
  requirements:
27
- - - ">="
28
- - !ruby/object:Gem::Version
29
- version: 1.10.0
30
24
  - - "~>"
31
25
  - !ruby/object:Gem::Version
32
- version: '1'
26
+ version: '1.10'
33
27
  - !ruby/object:Gem::Dependency
34
28
  name: xcodeproj
35
29
  requirement: !ruby/object:Gem::Requirement
36
30
  requirements:
37
- - - ">="
38
- - !ruby/object:Gem::Version
39
- version: 1.20.0
40
31
  - - "~>"
41
32
  - !ruby/object:Gem::Version
42
- version: '1'
33
+ version: '1.20'
43
34
  type: :runtime
44
35
  prerelease: false
45
36
  version_requirements: !ruby/object:Gem::Requirement
46
37
  requirements:
47
- - - ">="
48
- - !ruby/object:Gem::Version
49
- version: 1.20.0
50
38
  - - "~>"
51
39
  - !ruby/object:Gem::Version
52
- version: '1'
40
+ version: '1.20'
53
41
  description: Convert an ancient .framework (dynamic or static) to an .xcframework.
54
42
  Add an arm64 Simulator patch.
55
43
  email:
56
44
  - igormaka@gmail.com
57
45
  executables:
58
46
  - xcfconvert
47
+ - xcfpatch
59
48
  extensions: []
60
49
  extra_rdoc_files: []
61
50
  files:
62
51
  - README.md
63
52
  - bin/xcfconvert
53
+ - bin/xcfpatch
64
54
  - lib/arm2sim.swift
65
55
  - lib/xcframework_converter.rb
56
+ - lib/xcframework_converter/arm_patcher.rb
57
+ - lib/xcframework_converter/creation.rb
58
+ - lib/xcframework_converter/patching.rb
66
59
  - lib/xcframework_converter/version.rb
60
+ - lib/xcframework_converter/xcframework_ext.rb
67
61
  - lib/xcframework_template.plist
68
62
  homepage: https://github.com/igor-makarov/XCFrameworkConverter
69
63
  licenses: