xcframework_converter 0.1.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 +7 -0
- data/README.md +43 -0
- data/bin/xcfconvert +12 -0
- data/lib/arm2sim.swift +166 -0
- data/lib/xcframework_converter.rb +124 -0
- data/lib/xcframework_converter/version.rb +5 -0
- data/lib/xcframework_template.plist +41 -0
- metadata +93 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 261230f022e462a9840a009590e212c543833902b44795f80476971ff828dae7
|
4
|
+
data.tar.gz: 5a383fe7e654d79ea3d292a6369e4ba1d1b177c03f8967c9d6ec4fca2d942563
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: c284b721156bc30b0e818d8048513c023c2e931cb659d7211959f356c08f36f133a61494078edb35b24b490ccd6b15b5c71d7c61b1a42b6da14adab664517700
|
7
|
+
data.tar.gz: 2be83f317ea5fa0e2e108ac81cbfbfaf1095c5738559555fafabcf0f215efaf1c08308f6f01b6fd337b1a190bc319367c7634e6a00a73a0ccbf029edd7471683
|
data/README.md
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
# XcframeworkConverter
|
2
|
+
|
3
|
+
Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/xcframework_converter`. To experiment with that code, run `bin/console` for an interactive prompt.
|
4
|
+
|
5
|
+
TODO: Delete this and the text above, and describe your gem
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
gem 'xcframework_converter'
|
13
|
+
```
|
14
|
+
|
15
|
+
And then execute:
|
16
|
+
|
17
|
+
$ bundle install
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
|
21
|
+
$ gem install xcframework_converter
|
22
|
+
|
23
|
+
## Usage
|
24
|
+
|
25
|
+
TODO: Write usage instructions here
|
26
|
+
|
27
|
+
## Development
|
28
|
+
|
29
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
30
|
+
|
31
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
32
|
+
|
33
|
+
## Contributing
|
34
|
+
|
35
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/xcframework_converter. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/[USERNAME]/xcframework_converter/blob/master/CODE_OF_CONDUCT.md).
|
36
|
+
|
37
|
+
## License
|
38
|
+
|
39
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
40
|
+
|
41
|
+
## Code of Conduct
|
42
|
+
|
43
|
+
Everyone interacting in the XcframeworkConverter project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/xcframework_converter/blob/master/CODE_OF_CONDUCT.md).
|
data/bin/xcfconvert
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: xcfconvert <path/to/Framework.framework>'
|
9
|
+
exit 1
|
10
|
+
end
|
11
|
+
|
12
|
+
XCFrameworkConverter.convert_framework_to_xcframework(Pathname.new(ARGV[0]).realpath)
|
data/lib/arm2sim.swift
ADDED
@@ -0,0 +1,166 @@
|
|
1
|
+
import Foundation
|
2
|
+
import MachO
|
3
|
+
|
4
|
+
// support checking for Mach-O `cmd` and `cmdsize` properties
|
5
|
+
extension Data {
|
6
|
+
var loadCommand: UInt32 {
|
7
|
+
let lc: load_command = withUnsafeBytes { $0.load(as: load_command.self) }
|
8
|
+
return lc.cmd
|
9
|
+
}
|
10
|
+
|
11
|
+
var commandSize: Int {
|
12
|
+
let lc: load_command = withUnsafeBytes { $0.load(as: load_command.self) }
|
13
|
+
return Int(lc.cmdsize)
|
14
|
+
}
|
15
|
+
|
16
|
+
func asStruct<T>(fromByteOffset offset: Int = 0) -> T {
|
17
|
+
return withUnsafeBytes { $0.load(fromByteOffset: offset, as: T.self) }
|
18
|
+
}
|
19
|
+
}
|
20
|
+
|
21
|
+
extension Array where Element == Data {
|
22
|
+
func merge() -> Data {
|
23
|
+
return reduce(into: Data()) { $0.append($1) }
|
24
|
+
}
|
25
|
+
}
|
26
|
+
|
27
|
+
// support peeking at Data contents
|
28
|
+
extension FileHandle {
|
29
|
+
func peek(upToCount count: Int) throws -> Data? {
|
30
|
+
// persist the current offset, since `upToCount` doesn't guarantee all bytes will be read
|
31
|
+
let originalOffset = offsetInFile
|
32
|
+
let data = try read(upToCount: count)
|
33
|
+
try seek(toOffset: originalOffset)
|
34
|
+
return data
|
35
|
+
}
|
36
|
+
}
|
37
|
+
|
38
|
+
enum Transmogrifier {
|
39
|
+
private static func readBinary(atPath path: String) -> (Data, [Data], Data) {
|
40
|
+
guard let handle = FileHandle(forReadingAtPath: path) else {
|
41
|
+
fatalError("Cannot open a handle for the file at \(path). Aborting.")
|
42
|
+
}
|
43
|
+
|
44
|
+
// chop up the file into a relevant number of segments
|
45
|
+
let headerData = try! handle.read(upToCount: MemoryLayout<mach_header_64>.stride)!
|
46
|
+
|
47
|
+
let header: mach_header_64 = headerData.asStruct()
|
48
|
+
if header.magic != MH_MAGIC_64 || header.cputype != CPU_TYPE_ARM64 {
|
49
|
+
fatalError("The file is not a correct arm64 binary. Try thinning (via lipo) or unarchiving (via ar) first.")
|
50
|
+
}
|
51
|
+
|
52
|
+
let loadCommandsData: [Data] = (0..<header.ncmds).map { _ in
|
53
|
+
let loadCommandPeekData = try! handle.peek(upToCount: MemoryLayout<load_command>.stride)
|
54
|
+
return try! handle.read(upToCount: Int(loadCommandPeekData!.commandSize))!
|
55
|
+
}
|
56
|
+
|
57
|
+
let programData = try! handle.readToEnd()!
|
58
|
+
|
59
|
+
try! handle.close()
|
60
|
+
|
61
|
+
return (headerData, loadCommandsData, programData)
|
62
|
+
}
|
63
|
+
|
64
|
+
private static func updateSegment64(_ data: Data, _ offset: UInt32) -> Data {
|
65
|
+
// decode both the segment_command_64 and the subsequent section_64s
|
66
|
+
var segment: segment_command_64 = data.asStruct()
|
67
|
+
|
68
|
+
let sections: [section_64] = (0..<Int(segment.nsects)).map { index in
|
69
|
+
let offset = MemoryLayout<segment_command_64>.stride + index * MemoryLayout<section_64>.stride
|
70
|
+
return data.asStruct(fromByteOffset: offset)
|
71
|
+
}
|
72
|
+
|
73
|
+
// shift segment information by the offset
|
74
|
+
segment.fileoff += UInt64(offset)
|
75
|
+
segment.filesize += UInt64(offset)
|
76
|
+
segment.vmsize += UInt64(offset)
|
77
|
+
|
78
|
+
let offsetSections = sections.map { section -> section_64 in
|
79
|
+
var section = section
|
80
|
+
section.offset += UInt32(offset)
|
81
|
+
section.reloff += section.reloff > 0 ? UInt32(offset) : 0
|
82
|
+
return section
|
83
|
+
}
|
84
|
+
|
85
|
+
var datas = [Data]()
|
86
|
+
datas.append(Data(bytes: &segment, count: MemoryLayout<segment_command_64>.stride))
|
87
|
+
datas.append(contentsOf: offsetSections.map { section in
|
88
|
+
var section = section
|
89
|
+
return Data(bytes: §ion, count: MemoryLayout<section_64>.stride)
|
90
|
+
})
|
91
|
+
|
92
|
+
return datas.merge()
|
93
|
+
}
|
94
|
+
|
95
|
+
private static func updateVersionMin(_ data: Data, _ offset: UInt32, minos: UInt32, sdk: UInt32) -> Data {
|
96
|
+
var command = build_version_command(cmd: UInt32(LC_BUILD_VERSION),
|
97
|
+
cmdsize: UInt32(MemoryLayout<build_version_command>.stride),
|
98
|
+
platform: UInt32(PLATFORM_IOSSIMULATOR),
|
99
|
+
minos: minos << 16 | 0 << 8 | 0,
|
100
|
+
sdk: sdk << 16 | 0 << 8 | 0,
|
101
|
+
ntools: 0)
|
102
|
+
|
103
|
+
return Data(bytes: &command, count: MemoryLayout<build_version_command>.stride)
|
104
|
+
}
|
105
|
+
|
106
|
+
private static func updateDataInCode(_ data: Data, _ offset: UInt32) -> Data {
|
107
|
+
var command: linkedit_data_command = data.asStruct()
|
108
|
+
command.dataoff += offset
|
109
|
+
return Data(bytes: &command, count: data.commandSize)
|
110
|
+
}
|
111
|
+
|
112
|
+
private static func updateSymTab(_ data: Data, _ offset: UInt32) -> Data {
|
113
|
+
var command: symtab_command = data.asStruct()
|
114
|
+
command.stroff += offset
|
115
|
+
command.symoff += offset
|
116
|
+
return Data(bytes: &command, count: data.commandSize)
|
117
|
+
}
|
118
|
+
|
119
|
+
static func processBinary(atPath path: String, minos: UInt32 = 13, sdk: UInt32 = 13) {
|
120
|
+
guard CommandLine.arguments.count > 1 else {
|
121
|
+
fatalError("Please add a path to command!")
|
122
|
+
}
|
123
|
+
let (headerData, loadCommandsData, programData) = readBinary(atPath: path)
|
124
|
+
|
125
|
+
// `offset` is kind of a magic number here, since we know that's the only meaningful change to binary size
|
126
|
+
// having a dynamic `offset` requires two passes over the load commands and is left as an exercise to the reader
|
127
|
+
let offset = UInt32(abs(MemoryLayout<build_version_command>.stride - MemoryLayout<version_min_command>.stride))
|
128
|
+
|
129
|
+
let editedCommandsData = loadCommandsData
|
130
|
+
.map { (lc) -> Data in
|
131
|
+
switch Int32(lc.loadCommand) {
|
132
|
+
case LC_SEGMENT_64:
|
133
|
+
return updateSegment64(lc, offset)
|
134
|
+
case LC_VERSION_MIN_IPHONEOS:
|
135
|
+
return updateVersionMin(lc, offset, minos: minos, sdk: sdk)
|
136
|
+
case LC_DATA_IN_CODE, LC_LINKER_OPTIMIZATION_HINT:
|
137
|
+
return updateDataInCode(lc, offset)
|
138
|
+
case LC_SYMTAB:
|
139
|
+
return updateSymTab(lc, offset)
|
140
|
+
case LC_BUILD_VERSION:
|
141
|
+
fatalError("This arm64 binary already contains an LC_BUILD_VERSION load command!")
|
142
|
+
default:
|
143
|
+
return lc
|
144
|
+
}
|
145
|
+
}
|
146
|
+
.merge()
|
147
|
+
|
148
|
+
var header: mach_header_64 = headerData.asStruct()
|
149
|
+
header.sizeofcmds = UInt32(editedCommandsData.count)
|
150
|
+
|
151
|
+
// reassemble the binary
|
152
|
+
let reworkedData = [
|
153
|
+
Data(bytes: &header, count: MemoryLayout<mach_header_64>.stride),
|
154
|
+
editedCommandsData,
|
155
|
+
programData
|
156
|
+
].merge()
|
157
|
+
|
158
|
+
// save back to disk
|
159
|
+
try! reworkedData.write(to: URL(fileURLWithPath: path))
|
160
|
+
}
|
161
|
+
}
|
162
|
+
|
163
|
+
let binaryPath = CommandLine.arguments[1]
|
164
|
+
let minos = UInt32(CommandLine.arguments[2]) ?? 13
|
165
|
+
let sdk = UInt32(CommandLine.arguments[3]) ?? 13
|
166
|
+
Transmogrifier.processBinary(atPath: binaryPath, minos: minos, sdk: sdk)
|
@@ -0,0 +1,124 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'xcframework_converter/version'
|
4
|
+
|
5
|
+
require 'cocoapods'
|
6
|
+
require 'cocoapods/xcode/xcframework'
|
7
|
+
require 'fileutils'
|
8
|
+
require 'xcodeproj'
|
9
|
+
|
10
|
+
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
11
|
+
|
12
|
+
# Converts a framework (static or dynamic) to XCFrameworks, adding an arm64 simulator patch.
|
13
|
+
# For more info:
|
14
|
+
# static libs: https://bogo.wtf/arm64-to-sim.html
|
15
|
+
# dylibs: https://bogo.wtf/arm64-to-sim-dylibs.html
|
16
|
+
module XCFrameworkConverter
|
17
|
+
class << self
|
18
|
+
def convert_frameworks_to_xcframeworks!(installer)
|
19
|
+
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?
|
26
|
+
|
27
|
+
pod_path = installer.sandbox.pod_dir(Pod::Specification.root_name(spec.name))
|
28
|
+
convert_xcframeworks_if_present(pod_path)
|
29
|
+
|
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
|
39
|
+
|
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
|
46
|
+
|
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
|
69
|
+
|
70
|
+
def patch_arm_binary(slice)
|
71
|
+
require 'macho'
|
72
|
+
|
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
|
79
|
+
end
|
80
|
+
|
81
|
+
def patch_arm_binary_dynamic(slice)
|
82
|
+
extracted_path = slice.path.join('arm64.dylib')
|
83
|
+
`xcrun lipo \"#{slice.binary_path}\" -thin arm64 -output \"#{extracted_path}\"`
|
84
|
+
|
85
|
+
file = MachO::MachOFile.new(extracted_path)
|
86
|
+
sdk_version = file[:LC_VERSION_MIN_IPHONEOS].first.version_string
|
87
|
+
`xcrun vtool -arch arm64 -set-build-version 7 #{sdk_version} #{sdk_version} -replace -output \"#{extracted_path}\" \"#{extracted_path}\"`
|
88
|
+
`xcrun lipo \"#{slice.binary_path}\" -replace arm64 \"#{extracted_path}\" -output \"#{slice.binary_path}\"`
|
89
|
+
extracted_path.rmtree
|
90
|
+
end
|
91
|
+
|
92
|
+
def arm2sim_path
|
93
|
+
Pathname.new(__FILE__).dirname.join('arm2sim.swift')
|
94
|
+
end
|
95
|
+
|
96
|
+
def patch_arm_binary_static(slice)
|
97
|
+
extracted_path = slice.path.join('arm64.a')
|
98
|
+
`xcrun lipo \"#{slice.binary_path}\" -thin arm64 -output \"#{extracted_path}\"`
|
99
|
+
extracted_path_dir = slice.path.join('arm64-objects')
|
100
|
+
extracted_path_dir.mkdir
|
101
|
+
`cd \"#{extracted_path_dir}\" ; ar x \"#{extracted_path}\"`
|
102
|
+
Dir[extracted_path_dir.join('*.o')].each do |object_file|
|
103
|
+
file = MachO::MachOFile.new(object_file)
|
104
|
+
sdk_version = file[:LC_VERSION_MIN_IPHONEOS].first.version_string.to_i
|
105
|
+
`xcrun swift \"#{arm2sim_path}\" \"#{object_file}\" \"#{sdk_version}\" \"#{sdk_version}\"`
|
106
|
+
end
|
107
|
+
`cd \"#{extracted_path_dir}\" ; ar crv \"#{extracted_path}\" *.o`
|
108
|
+
|
109
|
+
`xcrun lipo \"#{slice.binary_path}\" -replace arm64 \"#{extracted_path}\" -output \"#{slice.binary_path}\"`
|
110
|
+
extracted_path_dir.rmtree
|
111
|
+
extracted_path.rmtree
|
112
|
+
end
|
113
|
+
|
114
|
+
def cleanup_unused_archs(slice)
|
115
|
+
supported_archs = slice.supported_archs
|
116
|
+
unsupported_archs = `xcrun lipo \"#{slice.binary_path}\" -archs`.split - supported_archs
|
117
|
+
unsupported_archs.each do |arch|
|
118
|
+
`xcrun lipo \"#{slice.binary_path}\" -remove \"#{arch}\" -output \"#{slice.binary_path}\"`
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
@@ -0,0 +1,41 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
3
|
+
<plist version="1.0">
|
4
|
+
<dict>
|
5
|
+
<key>AvailableLibraries</key>
|
6
|
+
<array>
|
7
|
+
<dict>
|
8
|
+
<key>LibraryIdentifier</key>
|
9
|
+
<string>ios-arm64_x86_64-simulator</string>
|
10
|
+
<key>LibraryPath</key>
|
11
|
+
<string>Placeholder.framework</string>
|
12
|
+
<key>SupportedArchitectures</key>
|
13
|
+
<array>
|
14
|
+
<string>arm64</string>
|
15
|
+
<string>x86_64</string>
|
16
|
+
</array>
|
17
|
+
<key>SupportedPlatform</key>
|
18
|
+
<string>ios</string>
|
19
|
+
<key>SupportedPlatformVariant</key>
|
20
|
+
<string>simulator</string>
|
21
|
+
</dict>
|
22
|
+
<dict>
|
23
|
+
<key>LibraryIdentifier</key>
|
24
|
+
<string>ios-arm64_armv7</string>
|
25
|
+
<key>LibraryPath</key>
|
26
|
+
<string>Placeholder.framework</string>
|
27
|
+
<key>SupportedArchitectures</key>
|
28
|
+
<array>
|
29
|
+
<string>arm64</string>
|
30
|
+
<string>armv7</string>
|
31
|
+
</array>
|
32
|
+
<key>SupportedPlatform</key>
|
33
|
+
<string>ios</string>
|
34
|
+
</dict>
|
35
|
+
</array>
|
36
|
+
<key>CFBundlePackageType</key>
|
37
|
+
<string>XFWK</string>
|
38
|
+
<key>XCFrameworkFormatVersion</key>
|
39
|
+
<string>1.0</string>
|
40
|
+
</dict>
|
41
|
+
</plist>
|
metadata
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: xcframework_converter
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Igor Makarov
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2021-07-19 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: cocoapods
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 1.10.0
|
20
|
+
- - "~>"
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '1'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 1.10.0
|
30
|
+
- - "~>"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '1'
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: xcodeproj
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: 1.20.0
|
40
|
+
- - "~>"
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '1'
|
43
|
+
type: :runtime
|
44
|
+
prerelease: false
|
45
|
+
version_requirements: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - ">="
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: 1.20.0
|
50
|
+
- - "~>"
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: '1'
|
53
|
+
description: Convert an ancient .framework (dynamic or static) to an .xcframework.
|
54
|
+
Add an arm64 Simulator patch.
|
55
|
+
email:
|
56
|
+
- igormaka@gmail.com
|
57
|
+
executables:
|
58
|
+
- xcfconvert
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- README.md
|
63
|
+
- bin/xcfconvert
|
64
|
+
- lib/arm2sim.swift
|
65
|
+
- lib/xcframework_converter.rb
|
66
|
+
- lib/xcframework_converter/version.rb
|
67
|
+
- lib/xcframework_template.plist
|
68
|
+
homepage: https://github.com/igor-makarov/XCFrameworkConverter
|
69
|
+
licenses:
|
70
|
+
- MIT
|
71
|
+
metadata:
|
72
|
+
homepage_uri: https://github.com/igor-makarov/XCFrameworkConverter
|
73
|
+
source_code_uri: https://github.com/igor-makarov/XCFrameworkConverter
|
74
|
+
post_install_message:
|
75
|
+
rdoc_options: []
|
76
|
+
require_paths:
|
77
|
+
- lib
|
78
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 2.4.0
|
83
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
84
|
+
requirements:
|
85
|
+
- - ">="
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '0'
|
88
|
+
requirements: []
|
89
|
+
rubygems_version: 3.1.4
|
90
|
+
signing_key:
|
91
|
+
specification_version: 4
|
92
|
+
summary: Convert an ancient .framework to an .xcframework.
|
93
|
+
test_files: []
|