xcframework_converter 0.1.1 → 0.2.1

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: 73791ebb8115008970a6beb4f8365313af86757023c0e04046410be09c58bf11
4
- data.tar.gz: d4f69fa6eba4f1f501b6dd382719efeb8a3ece77926b2b39a79c8e09e8ff2206
3
+ metadata.gz: 5109f0543cf6df9ebebacdcdc107e1a9bdfc11e365d918d62775678a9742a51a
4
+ data.tar.gz: 76cbc87f54d47b30e6c371f72c6855439e359eb620c0971821985b8c5697ad42
5
5
  SHA512:
6
- metadata.gz: 33020857576ceb88146c5fed0d793e28daaf653f06ba904eb4f24a9cc56cf504edc7152aab68b249ab026d0e2f89aca32b2890d0e80b1f74613933f35da3d7e8
7
- data.tar.gz: 8130336cd0406ee3386cf3b89fc2bf687d7b2ae20bacc46cb82986b5058f925e4a89e3f2b4c7ca0a0ddc5b5faf4275e70eb4f238929eaf0fc6344554b0723941
6
+ metadata.gz: 3a5650ef13956e95ee516e8d226afa1f282baf3c6268ea52b267c9fb0b5854aa6fc60a9bdf14e315e2274642f584c493da1231f111959f7494875a8d28dc253a
7
+ data.tar.gz: 545cff6294e8dc3734d0599a03dd40f48e0b1016bd7df06e0efba44e9b297373d64cded2c84004961cd3504b0aed9e2d7595ceda162a0f85d36abc8a318efabd
@@ -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.1'
4
+ VERSION = '0.2.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'
@@ -17,112 +19,54 @@ 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 unless spec.attributes_hash['vendored_frameworks']
21
-
22
- frameworks = Array(spec.attributes_hash['vendored_frameworks'])
23
- unconverted_frameworks = frameworks.select { |f| File.extname(f) == '.framework' }
24
- next if unconverted_frameworks.empty?
25
- next if spec.local?
22
+ next if spec.source && spec.local?
26
23
 
27
24
  pod_path = installer.sandbox.pod_dir(Pod::Specification.root_name(spec.name))
28
- convert_xcframeworks_if_present(pod_path)
29
25
 
30
- converted_frameworks = unconverted_frameworks.map do |path|
31
- Pathname.new(path).sub_ext('.xcframework').to_s
32
- end
33
- spec.attributes_hash['vendored_frameworks'] = frameworks - unconverted_frameworks + converted_frameworks
34
- # some pods put these as a way to NOT support arm64 sim
35
- spec.attributes_hash['pod_target_xcconfig']&.delete('EXCLUDED_ARCHS[sdk=iphonesimulator*]')
36
- spec.attributes_hash['user_target_xcconfig']&.delete('EXCLUDED_ARCHS[sdk=iphonesimulator*]')
37
- end
38
- end
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
39
31
 
40
- def convert_xcframeworks_if_present(pod_path)
41
- unconverted_paths = Dir[pod_path.join('**/*.framework')] - Dir[pod_path.join('**/*.xcframework/**/*')]
42
- unconverted_paths.each do |path|
43
- convert_framework_to_xcframework(path)
44
- end
45
- end
32
+ patch_xcframeworks_if_needed(spec, xcframeworks_to_patch)
46
33
 
47
- def plist_template_path
48
- Pathname.new(__FILE__).dirname.join('xcframework_template.plist')
49
- end
50
-
51
- def convert_framework_to_xcframework(path)
52
- plist = Xcodeproj::Plist.read_from_path(plist_template_path)
53
- xcframework_path = Pathname.new(path).sub_ext('.xcframework')
54
- xcframework_path.mkdir
55
- plist['AvailableLibraries'].each do |slice|
56
- slice_path = xcframework_path.join(slice['LibraryIdentifier'])
57
- slice_path.mkdir
58
- slice['LibraryPath'] = File.basename(path)
59
- FileUtils.cp_r(path, slice_path)
60
- end
61
- Xcodeproj::Plist.write_to_path(plist, xcframework_path.join('Info.plist'))
62
- FileUtils.rm_rf(path)
63
- final_framework = Pod::Xcode::XCFramework.new(xcframework_path.realpath)
64
- final_framework.slices.each do |slice|
65
- patch_arm_binary(slice) if slice.platform == :ios && slice.platform_variant == :simulator
66
- cleanup_unused_archs(slice)
67
- end
68
- end
34
+ frameworks_to_convert = spec.available_platforms.map do |platform|
35
+ consumer = Pod::Specification::Consumer.new(spec, platform)
36
+ before_rename = consumer.vendored_frameworks.select { |f| File.extname(f) == '.framework' }
37
+ next [] if before_rename.empty?
69
38
 
70
- def patch_arm_binary(slice)
71
- require 'macho'
39
+ after_rename = before_rename.map { |f| Pathname.new(f).sub_ext('.xcframework').to_s }
40
+ proxy = Pod::Specification::DSL::PlatformProxy.new(spec, platform.symbolic_name)
41
+ proxy.vendored_frameworks = consumer.vendored_frameworks - before_rename + after_rename
42
+ before_rename.map { |f| pod_path.join(f) }
43
+ end.flatten.uniq
72
44
 
73
- case slice.build_type.linkage
74
- when :dynamic
75
- patch_arm_binary_dynamic(slice)
76
- when :static
77
- patch_arm_binary_static(slice)
78
- end
45
+ convert_xcframeworks_if_present(spec, frameworks_to_convert)
79
46
 
80
- slice.path.glob('**/arm64*.swiftinterface').each do |interface_file|
81
- `sed -i '' -E 's/target arm64-apple-ios([0-9.]+) /target arm64-apple-ios\\1-simulator /g' "#{interface_file}"`
47
+ remove_troublesome_xcconfig_items(spec)
82
48
  end
83
49
  end
84
50
 
85
- def patch_arm_binary_dynamic(slice)
86
- extracted_path = slice.path.join('arm64.dylib')
87
- `xcrun lipo \"#{slice.binary_path}\" -thin arm64 -output \"#{extracted_path}\"`
88
-
89
- file = MachO::MachOFile.new(extracted_path)
90
- sdk_version = file[:LC_VERSION_MIN_IPHONEOS].first.version_string
91
- `xcrun vtool -arch arm64 -set-build-version 7 #{sdk_version} #{sdk_version} -replace -output \"#{extracted_path}\" \"#{extracted_path}\"`
92
- `xcrun lipo \"#{slice.binary_path}\" -replace arm64 \"#{extracted_path}\" -output \"#{slice.binary_path}\"`
93
- extracted_path.rmtree
94
- end
95
-
96
- def arm2sim_path
97
- Pathname.new(__FILE__).dirname.join('arm2sim.swift')
51
+ def convert_xcframeworks_if_present(spec, frameworks_to_convert)
52
+ frameworks_to_convert.each do |path|
53
+ convert_framework_to_xcframework(path) if Dir.exist?(path)
54
+ end
98
55
  end
99
56
 
100
- def patch_arm_binary_static(slice)
101
- extracted_path = slice.path.join('arm64.a')
102
- `xcrun lipo \"#{slice.binary_path}\" -thin arm64 -output \"#{extracted_path}\"`
103
- extracted_path_dir = slice.path.join('arm64-objects')
104
- extracted_path_dir.mkdir
105
- `cd \"#{extracted_path_dir}\" ; ar x \"#{extracted_path}\"`
106
- Dir[extracted_path_dir.join('*.o')].each do |object_file|
107
- file = MachO::MachOFile.new(object_file)
108
- sdk_version = file[:LC_VERSION_MIN_IPHONEOS].first.version_string.to_i
109
- `xcrun swift \"#{arm2sim_path}\" \"#{object_file}\" \"#{sdk_version}\" \"#{sdk_version}\"`
57
+ def patch_xcframeworks_if_needed(spec, xcframeworks)
58
+ xcframeworks.each do |path|
59
+ patch_xcframework(path) if Dir.exist?(path)
110
60
  end
111
- `cd \"#{extracted_path_dir}\" ; ar crv \"#{extracted_path}\" *.o`
112
-
113
- `xcrun lipo \"#{slice.binary_path}\" -replace arm64 \"#{extracted_path}\" -output \"#{slice.binary_path}\"`
114
- extracted_path_dir.rmtree
115
- extracted_path.rmtree
116
61
  end
117
62
 
118
- def cleanup_unused_archs(slice)
119
- supported_archs = slice.supported_archs
120
- unsupported_archs = `xcrun lipo \"#{slice.binary_path}\" -archs`.split - supported_archs
121
- unsupported_archs.each do |arch|
122
- `xcrun lipo \"#{slice.binary_path}\" -remove \"#{arch}\" -output \"#{slice.binary_path}\"`
123
- 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*]')
124
70
  end
125
71
  end
126
72
  end
127
-
128
- # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
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.1
4
+ version: 0.2.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-08-01 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: