xcframework_converter 0.1.2 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c41a9ff61dd6eb5eb00492d2ed59d9a235a3d3085189bff9351d9d6ab175e548
4
- data.tar.gz: b9784bac37bb57065f29a70bb8ec4a7ae19f6a6716375018d2253bb0d6c362cf
3
+ metadata.gz: 81f41d364c13895ffce8f691c7eff5dba6a9f6a4631a5e56bf230c5b0a9df911
4
+ data.tar.gz: 6ba774fcf8d912ff13a3473b0dcea9e24ee5726045be4d22162e5ac2d0d25ecf
5
5
  SHA512:
6
- metadata.gz: f0b0c2d69c02d311046d6dcb2e465d0fe18b7e34409cf423f29fe473117232ab3b39c623a90709586d79d1b5caeb2d5be20986bd730b44e2b3da9809338cb7c0
7
- data.tar.gz: dcab8fdcf810162e00b70b214bd43c41c61b852e294689c819c1d03a456bed13068cd16e7f9956cff42a19871ac1b8c97a6e77c6273686ef8f524fc69b8c09ec
6
+ metadata.gz: 9e5afac8eb28eaa70467b4ad73019d5be7f8cfa39e669f24b86a0b803d90e2cd4e3d3a91e84bf6d8062c88ca5ba07fc592997697361988775b05c79f093fa13a
7
+ data.tar.gz: afab009d7b7115ac48b6c2aadfcd0364efe3f4b4f5ae4db6a3c8dee00a6d5fbdc189e38cff779ae487fa44ce85efffa0f5d66579154aa6ce9838f6caddd1d01f
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.2'
4
+ VERSION = '0.3.0'
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'
@@ -17,7 +19,15 @@ module XCFrameworkConverter
17
19
  class << self
18
20
  def convert_frameworks_to_xcframeworks!(installer)
19
21
  installer.analysis_result.specifications.each do |spec|
20
- next if spec.source && spec.local?
22
+ pod_path = installer.sandbox.pod_dir(Pod::Specification.root_name(spec.name))
23
+
24
+ xcframeworks_to_patch = spec.available_platforms.map do |platform|
25
+ consumer = Pod::Specification::Consumer.new(spec, platform)
26
+ consumer.vendored_frameworks.select { |f| File.extname(f) == '.xcframework' }
27
+ .map { |f| pod_path.join(f) }
28
+ end.flatten.uniq
29
+
30
+ patch_xcframeworks_if_needed(xcframeworks_to_patch)
21
31
 
22
32
  frameworks_to_convert = spec.available_platforms.map do |platform|
23
33
  consumer = Pod::Specification::Consumer.new(spec, platform)
@@ -27,18 +37,12 @@ module XCFrameworkConverter
27
37
  after_rename = before_rename.map { |f| Pathname.new(f).sub_ext('.xcframework').to_s }
28
38
  proxy = Pod::Specification::DSL::PlatformProxy.new(spec, platform.symbolic_name)
29
39
  proxy.vendored_frameworks = consumer.vendored_frameworks - before_rename + after_rename
30
- before_rename
40
+ before_rename.map { |f| pod_path.join(f) }
31
41
  end.flatten.uniq
32
-
33
- next if frameworks_to_convert.empty?
34
42
 
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) })
43
+ convert_xcframeworks_if_present(frameworks_to_convert)
37
44
 
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*]')
45
+ remove_troublesome_xcconfig_items(spec)
42
46
  end
43
47
  end
44
48
 
@@ -48,85 +52,19 @@ module XCFrameworkConverter
48
52
  end
49
53
  end
50
54
 
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 = Pod::Xcode::XCFramework.new(xcframework_path.realpath)
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 patch_arm_binary(slice)
75
- require 'macho'
76
-
77
- case slice.build_type.linkage
78
- when :dynamic
79
- patch_arm_binary_dynamic(slice)
80
- when :static
81
- patch_arm_binary_static(slice)
82
- end
83
-
84
- slice.path.glob('**/arm64*.swiftinterface').each do |interface_file|
85
- `sed -i '' -E 's/target arm64-apple-ios([0-9.]+) /target arm64-apple-ios\\1-simulator /g' "#{interface_file}"`
86
- end
87
- end
88
-
89
- def patch_arm_binary_dynamic(slice)
90
- extracted_path = slice.path.join('arm64.dylib')
91
- `xcrun lipo \"#{slice.binary_path}\" -thin arm64 -output \"#{extracted_path}\"`
92
-
93
- file = MachO::MachOFile.new(extracted_path)
94
- sdk_version = file[:LC_VERSION_MIN_IPHONEOS].first.version_string
95
- `xcrun vtool -arch arm64 -set-build-version 7 #{sdk_version} #{sdk_version} -replace -output \"#{extracted_path}\" \"#{extracted_path}\"`
96
- `xcrun lipo \"#{slice.binary_path}\" -replace arm64 \"#{extracted_path}\" -output \"#{slice.binary_path}\"`
97
- extracted_path.rmtree
98
- end
99
-
100
- def arm2sim_path
101
- Pathname.new(__FILE__).dirname.join('arm2sim.swift')
102
- end
103
-
104
- def patch_arm_binary_static(slice)
105
- extracted_path = slice.path.join('arm64.a')
106
- `xcrun lipo \"#{slice.binary_path}\" -thin arm64 -output \"#{extracted_path}\"`
107
- extracted_path_dir = slice.path.join('arm64-objects')
108
- extracted_path_dir.mkdir
109
- `cd \"#{extracted_path_dir}\" ; ar x \"#{extracted_path}\"`
110
- Dir[extracted_path_dir.join('*.o')].each do |object_file|
111
- file = MachO::MachOFile.new(object_file)
112
- sdk_version = file[:LC_VERSION_MIN_IPHONEOS].first.version_string.to_i
113
- `xcrun swift \"#{arm2sim_path}\" \"#{object_file}\" \"#{sdk_version}\" \"#{sdk_version}\"`
55
+ def patch_xcframeworks_if_needed(xcframeworks)
56
+ xcframeworks.each do |path|
57
+ patch_xcframework(path) if Dir.exist?(path)
114
58
  end
115
- `cd \"#{extracted_path_dir}\" ; ar crv \"#{extracted_path}\" *.o`
116
-
117
- `xcrun lipo \"#{slice.binary_path}\" -replace arm64 \"#{extracted_path}\" -output \"#{slice.binary_path}\"`
118
- extracted_path_dir.rmtree
119
- extracted_path.rmtree
120
59
  end
121
60
 
122
- def cleanup_unused_archs(slice)
123
- supported_archs = slice.supported_archs
124
- unsupported_archs = `xcrun lipo \"#{slice.binary_path}\" -archs`.split - supported_archs
125
- unsupported_archs.each do |arch|
126
- `xcrun lipo \"#{slice.binary_path}\" -remove \"#{arch}\" -output \"#{slice.binary_path}\"`
127
- end
61
+ def remove_troublesome_xcconfig_items(spec)
62
+ # some pods put these as a way to NOT support arm64 sim
63
+ # may stop working if a pod decides to put these in a platform proxy
64
+ spec.attributes_hash['pod_target_xcconfig']&.delete('EXCLUDED_ARCHS[sdk=iphonesimulator*]')
65
+ spec.attributes_hash['user_target_xcconfig']&.delete('EXCLUDED_ARCHS[sdk=iphonesimulator*]')
66
+ spec.attributes_hash['pod_target_xcconfig']&.delete('VALID_ARCHS[sdk=iphonesimulator*]')
67
+ spec.attributes_hash['user_target_xcconfig']&.delete('VALID_ARCHS[sdk=iphonesimulator*]')
128
68
  end
129
69
  end
130
70
  end
131
-
132
- # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
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.2
4
+ version: 0.3.0
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-09 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: