xcframework_converter 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|