xcframework_converter 0.1.3 → 0.2.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: ed8ad6ac521bd6f26cae4e1ed130e7faf4c861c9367d10a591f65ace5e0d0180
4
- data.tar.gz: 3a214bc46c53d8413a4082783d24d9fc4ebecdcf9bc695edd3a1908561eb952c
3
+ metadata.gz: 105e63e07d147cd791c478f9351e73e1f71bbd861160b5a1391d99c7c0affc9d
4
+ data.tar.gz: cf2e6a358aeb0a7018d06a2bf48382ab01d768eb870589da0abddab7044278e3
5
5
  SHA512:
6
- metadata.gz: 23717de292d647163e52c8c2055878b45c7e79dceb01e000bcb29830edb9c26c44e928c1dea8df1ec33f1f224fc7f9bbeb79ca876cd4a14d80cafe0eddfad87e
7
- data.tar.gz: d00b1bf35a52d2d42bba03f84ce88f35e19edab370465acb08d20bb886ced4e534bf5385e0f036aa3ee2ff5b341f612c080873a200142badc79b517fe2493cf4
6
+ metadata.gz: fe005277c05790de2d906188fbc0ab3818b9dd27980bf68bdeb2e56ec3ef2f0184fc61224ddeb32c29689ad316f3179eb51dd4a3345bf423bdd7cd5d75569697
7
+ data.tar.gz: '0805b456eebbfc655bd5991c001b241b29bf614f154615be67be7124d3bc1fc95532a0612647ac1d56e05d10373c97c7f6e14489adb68481e24e6b5a03ff89c6'
@@ -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
+ STDERR.puts "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.2.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'
@@ -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(spec, 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,112 +39,36 @@ 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) })
37
-
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
+ convert_xcframeworks_if_present(spec, frameworks_to_convert)
42
46
  end
43
47
  end
44
48
 
45
- def convert_xcframeworks_if_present(frameworks_to_convert)
49
+ def convert_xcframeworks_if_present(spec, frameworks_to_convert)
46
50
  frameworks_to_convert.each do |path|
47
51
  convert_framework_to_xcframework(path) if Dir.exist?(path)
48
52
  end
53
+ remove_troublesome_xcconfig_items(spec) unless frameworks_to_convert.empty?
49
54
  end
50
55
 
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
56
+ def patch_xcframeworks_if_needed(spec, xcframeworks)
57
+ patched = xcframeworks.map do |path|
58
+ next nil unless Dir.exist?(path)
73
59
 
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
60
+ patch_xcframework(path)
61
+ end.compact
62
+ remove_troublesome_xcconfig_items(spec) unless patched.empty?
80
63
  end
81
64
 
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}"`
94
- end
95
- end
96
-
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
65
+ def remove_troublesome_xcconfig_items(spec)
66
+ # some pods put these as a way to NOT support arm64 sim
67
+ # may stop working if a pod decides to put these in a platform proxy
68
+ spec.attributes_hash['pod_target_xcconfig']&.delete('EXCLUDED_ARCHS[sdk=iphonesimulator*]')
69
+ spec.attributes_hash['user_target_xcconfig']&.delete('EXCLUDED_ARCHS[sdk=iphonesimulator*]')
70
+ spec.attributes_hash['pod_target_xcconfig']&.delete('VALID_ARCHS[sdk=iphonesimulator*]')
71
+ spec.attributes_hash['user_target_xcconfig']&.delete('VALID_ARCHS[sdk=iphonesimulator*]')
136
72
  end
137
73
  end
138
74
  end
metadata CHANGED
@@ -1,14 +1,14 @@
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.2.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-20 00:00:00.000000000 Z
11
+ date: 2022-01-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: cocoapods
@@ -63,7 +63,11 @@ files:
63
63
  - bin/xcfconvert
64
64
  - lib/arm2sim.swift
65
65
  - lib/xcframework_converter.rb
66
+ - lib/xcframework_converter/arm_patcher.rb
67
+ - lib/xcframework_converter/creation.rb
68
+ - lib/xcframework_converter/patching.rb
66
69
  - lib/xcframework_converter/version.rb
70
+ - lib/xcframework_converter/xcframework_ext.rb
67
71
  - lib/xcframework_template.plist
68
72
  homepage: https://github.com/igor-makarov/XCFrameworkConverter
69
73
  licenses: