xcframework_converter 0.5.0 → 0.6.0

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: bc55b13f203a5434a0844c4e3e2bdab78de4cf7e9c518a4e504eb4513aaa65d6
4
- data.tar.gz: 2867a3113f62112a2b324ec4822613edaa8168fbc75a2dc6ac398a074b481028
3
+ metadata.gz: 77324350e0b69d68739d71e4e2bd510b2c46e82076d82c066eb1af2ab7019ff0
4
+ data.tar.gz: dd8c817ba142772da87f18c46fffe50f32e2bad22d4bb8a9e3101650b38818a0
5
5
  SHA512:
6
- metadata.gz: 6664a2115bd38a245669ac19a3504359641c790e613a472fe38f755c8f20c23bd38caa57333b6c5817e3d14c7185df8521ecb7394f28a431529d7f8ca5bcdfbe
7
- data.tar.gz: 2cef2f4dc73b1e9091bd5f3580ec1c307ec40e5248c9732e0de781aa5d8a0b33f9e27e3befda29c5d924c9a6fccc9ef3aa1f9f6d11588297b796cedb66abf69a
6
+ metadata.gz: e7a7693803108e192822db1f4ab0de16bed32d4dc134dd3a69b1b6e54eab4e185e4d466d0626ecd46adc4c0bee677de8a9b8ca28d99485a0f5975147133cd94b
7
+ data.tar.gz: 59a9cac8d54309ddd9efea3901425ad5499cccac741cd6d35cb4a493794a8cf35d083ad63ba6e0528065cd717ee1521c7a8794cd445d2093813f65336af9209e
@@ -104,7 +104,7 @@ public enum Transmogrifier {
104
104
  return datas.merge()
105
105
  }
106
106
 
107
- private static func updateVersionMin(_ data: Data, _ offset: UInt32, minos: UInt32, sdk: UInt32) -> Data {
107
+ private static func createLcBuildVersion(minos: UInt32, sdk: UInt32) -> Data {
108
108
  var command = build_version_command(cmd: UInt32(LC_BUILD_VERSION),
109
109
  cmdsize: UInt32(MemoryLayout<build_version_command>.stride),
110
110
  platform: UInt32(PLATFORM_IOSSIMULATOR),
@@ -115,6 +115,15 @@ public enum Transmogrifier {
115
115
  return Data(bytes: &command, count: MemoryLayout<build_version_command>.stride)
116
116
  }
117
117
 
118
+ private static func updateLcBuildVersion(_ data: Data, minos: UInt32, sdk: UInt32) -> Data {
119
+ var command: build_version_command = data.asStruct()
120
+ command.platform = UInt32(PLATFORM_IOSSIMULATOR)
121
+ command.minos = minos << 16 | 0 << 8 | 0
122
+ command.sdk = sdk << 16 | 0 << 8 | 0
123
+
124
+ return Data(bytes: &command, count: data.count)
125
+ }
126
+
118
127
  private static func updateDataInCode(_ data: Data, _ offset: UInt32) -> Data {
119
128
  var command: linkedit_data_command = data.asStruct()
120
129
  command.dataoff += offset
@@ -154,8 +163,6 @@ public enum Transmogrifier {
154
163
  }
155
164
 
156
165
  if contains_LC_VERSION_MIN_IPHONEOS {
157
- // `offset` is kind of a magic number here, since we know that's the only meaningful change to binary size
158
- // having a dynamic `offset` requires two passes over the load commands and is left as an exercise to the reader
159
166
  return updatePreiOS12ObjectFile
160
167
  } else {
161
168
  return updatePostiOS12ObjectFile
@@ -167,7 +174,7 @@ public enum Transmogrifier {
167
174
  let cmd = Int32(bitPattern: lc.loadCommand)
168
175
  switch cmd {
169
176
  case LC_BUILD_VERSION:
170
- return updateVersionMin(lc, 0, minos: minos, sdk: sdk)
177
+ return updateLcBuildVersion(lc, minos: minos, sdk: sdk)
171
178
  default:
172
179
  return lc
173
180
  }
@@ -182,28 +189,25 @@ public enum Transmogrifier {
182
189
  case LC_SEGMENT_64:
183
190
  return updateSegment64(lc, offset)
184
191
  case LC_VERSION_MIN_IPHONEOS:
185
- return updateVersionMin(lc, offset, minos: minos, sdk: sdk)
192
+ return createLcBuildVersion(minos: minos, sdk: sdk)
186
193
  case LC_DATA_IN_CODE, LC_LINKER_OPTIMIZATION_HINT:
187
194
  return updateDataInCode(lc, offset)
188
195
  case LC_SYMTAB:
189
196
  return updateSymTab(lc, offset)
190
197
  case LC_BUILD_VERSION:
191
- return updateVersionMin(lc, offset, minos: minos, sdk: sdk)
198
+ fatalError("pre-12 object file shold not contain LC_BUILD_VERSION!")
192
199
  default:
193
200
  return lc
194
201
  }
195
202
  }
196
203
 
197
204
  static func updateDylibFile(lc: Data, minos: UInt32, sdk: UInt32) -> Data {
198
- // `offset` is kind of a magic number here, since we know that's the only meaningful change to binary size
199
- // having a dynamic `offset` requires two passes over the load commands and is left as an exercise to the reader
200
- let offset = UInt32(abs(MemoryLayout<build_version_command>.stride - MemoryLayout<version_min_command>.stride))
201
205
  let cmd = Int32(bitPattern: lc.loadCommand)
202
206
  guard cmd != LC_BUILD_VERSION else {
203
207
  fatalError("This arm64 binary already contains an LC_BUILD_VERSION load command!")
204
208
  }
205
209
  if cmd == LC_VERSION_MIN_IPHONEOS {
206
- return updateVersionMin(lc, offset, minos: minos, sdk: sdk)
210
+ return createLcBuildVersion(minos: minos, sdk: sdk)
207
211
  }
208
212
  return lc
209
213
  }
@@ -37,9 +37,8 @@ module XCFrameworkConverter
37
37
  extracted_path = slice.path.join('arm64.dylib')
38
38
  `xcrun lipo \"#{slice.binary_path}\" -thin arm64 -output \"#{extracted_path}\"`
39
39
 
40
- file = MachO::MachOFile.new(extracted_path)
41
- sdk_version = file[:LC_VERSION_MIN_IPHONEOS].first.version_string
42
- `xcrun vtool -arch arm64 -set-build-version 7 #{sdk_version} #{sdk_version} -replace -output \"#{extracted_path}\" \"#{extracted_path}\"`
40
+ minos_version, sdk_version = version_strings(extracted_path).map(&:to_i)
41
+ `xcrun vtool -arch arm64 -set-build-version 7 #{minos_version} #{sdk_version} -replace -output \"#{extracted_path}\" \"#{extracted_path}\"`
43
42
  `xcrun lipo \"#{slice.binary_path}\" -replace arm64 \"#{extracted_path}\" -output \"#{slice.binary_path}\"`
44
43
  extracted_path.rmtree
45
44
  end
@@ -63,36 +62,61 @@ module XCFrameworkConverter
63
62
  `xcrun lipo \"#{slice.binary_path}\" -thin arm64 -output \"#{extracted_path}\"`
64
63
  extracted_path_dir = slice.path.join('arm64-objects')
65
64
  extracted_path_dir.mkdir
66
- object_files = `ar t \"#{extracted_path}\"`.split("\n").map(&:chomp).sort
67
- .select { |o| o.end_with?('.o') }
68
- .group_by(&:itself).transform_values(&:count)
69
- processed_files = []
70
- index = 0
71
- while object_files.any?
72
- object_files.keys.each do |object_file|
73
- file_shard = Digest::MD5.hexdigest(object_file).to_s[0..2]
74
- file_dir = extracted_path_dir.join("#{index}-#{file_shard}")
75
- file_path = file_dir.join(object_file)
76
- file_dir.mkdir unless file_dir.exist?
77
- `ar p \"#{extracted_path}\" \"#{object_file}\" > \"#{file_path}\"`
78
- macho_file = MachO::MachOFile.new(file_path)
79
- sdk_version = macho_file[:LC_VERSION_MIN_IPHONEOS].first.version_string.to_i
80
- `\"#{arm2sim_path}\" \"#{file_path}\" \"#{sdk_version}\" \"#{sdk_version}\"`
81
- $stderr.printf '.'
82
- processed_files << file_path
65
+ if macho_file_type(extracted_path) == :object
66
+ patch_object_file(extracted_path)
67
+ else
68
+ object_files = `ar t \"#{extracted_path}\"`.split("\n").map(&:chomp).sort
69
+ .select { |o| o.end_with?('.o') }
70
+ .group_by(&:itself).transform_values(&:count)
71
+ processed_files = []
72
+ index = 0
73
+ while object_files.any?
74
+ object_files.keys.each do |object_file|
75
+ file_shard = Digest::MD5.hexdigest(object_file).to_s[0..2]
76
+ file_dir = extracted_path_dir.join("#{index}-#{file_shard}")
77
+ file_path = file_dir.join(object_file)
78
+ file_dir.mkdir unless file_dir.exist?
79
+ `ar p \"#{extracted_path}\" \"#{object_file}\" > \"#{file_path}\"`
80
+ patch_object_file(file_path)
81
+ $stderr.printf '.'
82
+ processed_files << file_path
83
+ end
84
+ `ar d \"#{extracted_path}\" #{object_files.keys.map(&:shellescape).join(' ')}`
85
+ $stderr.printf '#'
86
+ object_files.reject! { |_, count| count <= index + 1 }
87
+ index += 1
83
88
  end
84
- `ar d \"#{extracted_path}\" #{object_files.keys.map(&:shellescape).join(' ')}`
85
- $stderr.printf '#'
86
- object_files.reject! { |_, count| count <= index + 1 }
87
- index += 1
89
+ $stderr.puts
90
+ `cd \"#{extracted_path_dir}\" ; ar cqv \"#{extracted_path}\" #{processed_files.map(&:shellescape).join(' ')}`
88
91
  end
89
- $stderr.puts
90
- `cd \"#{extracted_path_dir}\" ; ar cqv \"#{extracted_path}\" #{processed_files.map(&:shellescape).join(' ')}`
91
92
  `xcrun lipo \"#{slice.binary_path}\" -replace arm64 \"#{extracted_path}\" -output \"#{slice.binary_path}\"`
92
93
  extracted_path_dir.rmtree
93
94
  extracted_path.rmtree
94
95
  end
95
96
 
97
+ def macho_file_type(file_path)
98
+ MachO.open(file_path).filetype
99
+ rescue MachO::MagicError
100
+ nil
101
+ end
102
+
103
+ def patch_object_file(file_path)
104
+ minos_version, sdk_version = version_strings(file_path).map(&:to_i)
105
+ `\"#{arm2sim_path}\" \"#{file_path}\" \"#{minos_version}\" \"#{sdk_version}\"`
106
+ end
107
+
108
+ def version_strings(file_path)
109
+ macho_file = MachO::MachOFile.new(file_path)
110
+ if (version_min_command = macho_file.load_commands.find { |c| c.is_a?(MachO::LoadCommands::VersionMinCommand) })
111
+ return [version_min_command.version_string, version_min_command.sdk_string]
112
+ end
113
+ if (build_version_command = macho_file.load_commands.find { |c| c.is_a?(MachO::LoadCommands::BuildVersionCommand) })
114
+ return [build_version_command.minos_string, build_version_command.sdk_string]
115
+ end
116
+
117
+ raise "Could not find version strings in #{file_path}"
118
+ end
119
+
96
120
  public
97
121
 
98
122
  def cleanup_unused_archs(slice)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module XCFrameworkConverter
4
- VERSION = '0.5.0'
4
+ VERSION = '0.6.0'
5
5
  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.5.0
4
+ version: 0.6.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: 2022-05-09 00:00:00.000000000 Z
11
+ date: 2022-05-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: cocoapods