cocoapods-project-gen 0.1.0 → 0.2.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +73 -23
- data/bin/xcframework +11 -0
- data/lib/cocoapods-project-gen/command/command.rb +25 -0
- data/lib/cocoapods-project-gen/command/gen.rb +122 -0
- data/lib/cocoapods-project-gen/gem_version.rb +1 -1
- data/lib/cocoapods-project-gen/gen/build/headers_store.rb +104 -0
- data/lib/cocoapods-project-gen/gen/build/xcode_build.rb +47 -0
- data/lib/cocoapods-project-gen/gen/constants.rb +71 -0
- data/lib/cocoapods-project-gen/gen/pod/pod_copy_cleaner.rb +50 -0
- data/lib/cocoapods-project-gen/gen/pod/project_gen_helper.rb +341 -0
- data/lib/cocoapods-project-gen/gen/pod/swift_module_helper.rb +134 -0
- data/lib/cocoapods-project-gen/gen/product/product_helper.rb +93 -0
- data/lib/cocoapods-project-gen/gen/product.rb +165 -0
- data/lib/cocoapods-project-gen/gen/project_builder.rb +144 -0
- data/lib/cocoapods-project-gen/gen/project_gen.rb +179 -128
- data/lib/cocoapods-project-gen/gen/results.rb +143 -0
- data/lib/cocoapods-project-gen/gen/utils.rb +35 -0
- data/lib/cocoapods-project-gen/gen/xcframework_gen.rb +44 -0
- data/lib/cocoapods-project-gen.rb +14 -7
- metadata +21 -6
- data/lib/cocoapods-project-gen/gen/swift_module_helper.rb +0 -52
@@ -0,0 +1,341 @@
|
|
1
|
+
module ProjectGen
|
2
|
+
module Helper
|
3
|
+
include Pod
|
4
|
+
|
5
|
+
def self.app_target_name(platform)
|
6
|
+
"App-#{platform.string_name}"
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
# The specifications matching the specified pod name
|
12
|
+
#
|
13
|
+
# @param [String] pod_name the name of the pod
|
14
|
+
#
|
15
|
+
# @return [Hash{Specification => Array<Taget>}] the specifications grouped by platform
|
16
|
+
#
|
17
|
+
def specs_for_pods
|
18
|
+
@installer.pod_targets.each_with_object({}) do |pod_target, hash|
|
19
|
+
hash[pod_target.root_spec] ||= []
|
20
|
+
hash[pod_target.root_spec] << pod_target
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def setup_gen_environment
|
25
|
+
project_gen_dir.rmtree if project_gen_dir.exist?
|
26
|
+
project_gen_dir.mkpath
|
27
|
+
@original_config = Pod::Config.instance.clone
|
28
|
+
config.installation_root = project_gen_dir
|
29
|
+
config.silent = !config.verbose
|
30
|
+
end
|
31
|
+
|
32
|
+
# !@group Lint steps
|
33
|
+
def perform_linting
|
34
|
+
podspecs.each do |podspec|
|
35
|
+
linter = Pod::Specification::Linter.new(podspec)
|
36
|
+
linter.lint
|
37
|
+
@results.results.concat(linter.results.to_a)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def podspecs
|
42
|
+
return @podspecs if defined? @podspecs
|
43
|
+
|
44
|
+
additional_podspec_pods = external_podspecs ? Dir.glob(external_podspecs) : []
|
45
|
+
additional_path_pods = include_podspecs ? Dir.glob(include_podspecs) : []
|
46
|
+
@podspecs = (additional_podspec_pods + additional_path_pods).uniq.each_with_object({}) do |path, hash|
|
47
|
+
spec = Pod::Specification.from_file(path)
|
48
|
+
old_spec = hash[spec.name]
|
49
|
+
if old_spec && use_latest
|
50
|
+
hash[spec.name] = [old_spec, spec].max { |old, new| old.version <=> new.version }
|
51
|
+
else
|
52
|
+
hash[spec.name] = spec
|
53
|
+
end
|
54
|
+
end.values
|
55
|
+
end
|
56
|
+
|
57
|
+
def include_specifications
|
58
|
+
(include_podspecs ? Dir.glob(include_podspecs) : []).map do |path|
|
59
|
+
Pod::Specification.from_file(path)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# Returns a list of platforms to lint for a given Specification
|
64
|
+
#
|
65
|
+
# @return [Array<Platform>] platforms to lint for the given specification
|
66
|
+
#
|
67
|
+
def determine_platforms
|
68
|
+
return @determine_platforms if defined?(@determine_platforms) && @determine_platforms == @platform
|
69
|
+
|
70
|
+
platforms = podspecs.flat_map(&:available_platforms).uniq
|
71
|
+
platforms = platforms.map do |platform|
|
72
|
+
default = Pod::Podfile::TargetDefinition::PLATFORM_DEFAULTS[platform.name]
|
73
|
+
deployment_target = podspecs.flat_map do |library_spec|
|
74
|
+
subspecs = determine_subspecs[library_spec]
|
75
|
+
if subspecs && !subspecs.empty?
|
76
|
+
subspecs.map { |s| Pod::Version.new(s.deployment_target(platform.name) || default) }
|
77
|
+
else
|
78
|
+
Pod::Version.new(library_spec.deployment_target(platform.name) || default)
|
79
|
+
end
|
80
|
+
end.max
|
81
|
+
if platform.name == :ios && use_frameworks
|
82
|
+
minimum = Pod::Version.new('8.0')
|
83
|
+
deployment_target = [deployment_target, minimum].max
|
84
|
+
end
|
85
|
+
Pod::Platform.new(platform.name, deployment_target)
|
86
|
+
end.uniq
|
87
|
+
|
88
|
+
unless @platforms.empty?
|
89
|
+
# Validate that the platforms specified are actually supported by the spec
|
90
|
+
platforms = @platforms.map do |platform|
|
91
|
+
matching_platform = platforms.find { |p| p.name == platform.name }
|
92
|
+
unless matching_platform
|
93
|
+
raise Informative, "Platform `#{platform}` is not supported by specification `#{spec}`."
|
94
|
+
end
|
95
|
+
|
96
|
+
matching_platform
|
97
|
+
end.uniq
|
98
|
+
end
|
99
|
+
@platform = platforms
|
100
|
+
@determine_platforms = platforms
|
101
|
+
end
|
102
|
+
|
103
|
+
def determine_subspecs
|
104
|
+
return @determine_subspecs if defined? @determine_subspecs
|
105
|
+
return {} if @only_subspecs.nil?
|
106
|
+
|
107
|
+
subspecs = @only_subspecs.dup
|
108
|
+
ha = podspecs.each_with_object({}) do |podspec, hash|
|
109
|
+
return hash if subspecs.empty?
|
110
|
+
|
111
|
+
base_name = podspec.name
|
112
|
+
s_s = []
|
113
|
+
subspecs.delete_if { |ss| s_s << podspec.subspec_by_name(ss, false) if ss.split('/').shift == base_name }
|
114
|
+
s_s.compact!
|
115
|
+
hash[podspec] = s_s unless s_s.empty?
|
116
|
+
end
|
117
|
+
subspecs.each { |s| results.warning('subspecs', "#{s} should use NAME/NAME.") }
|
118
|
+
@determine_subspecs = ha
|
119
|
+
end
|
120
|
+
|
121
|
+
def validate_vendored_dynamic_frameworks
|
122
|
+
platform = determine_platforms.find { |pl| pl.name == :ios }
|
123
|
+
targets = relative_pod_targets_from_platfrom(platform)
|
124
|
+
targets.flat_map(&:file_accessors).each do |file_accessor|
|
125
|
+
deployment_target = platform.deployment_target
|
126
|
+
dynamic_frameworks = file_accessor.vendored_dynamic_frameworks
|
127
|
+
dynamic_libraries = file_accessor.vendored_dynamic_libraries
|
128
|
+
if (dynamic_frameworks.count.positive? || dynamic_libraries.count.positive?) && platform.name == :ios &&
|
129
|
+
(deployment_target.nil? || deployment_target.major < 8)
|
130
|
+
error('dynamic', 'Dynamic frameworks and libraries are only supported on iOS 8.0 and onwards.')
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def create_app_project
|
136
|
+
p_path = project_gen_dir + 'App.xcodeproj'
|
137
|
+
app_project = if p_path.exist?
|
138
|
+
Xcodeproj::Project.open(p_path)
|
139
|
+
else
|
140
|
+
Xcodeproj::Project.new(File.join(project_gen_dir, 'App.xcodeproj'))
|
141
|
+
end
|
142
|
+
determine_platforms.each do |platform|
|
143
|
+
app_target = Pod::Generator::AppTargetHelper.add_app_target(app_project, platform.name,
|
144
|
+
platform.deployment_target.to_s, Helper.app_target_name(platform))
|
145
|
+
sandbox = Pod::Sandbox.new(config.sandbox_root)
|
146
|
+
info_plist_path = app_project.path.dirname.+("App/#{Helper.app_target_name(platform)}-Info.plist")
|
147
|
+
Pod::Installer::Xcode::PodsProjectGenerator::TargetInstallerHelper.create_info_plist_file_with_sandbox(sandbox,
|
148
|
+
info_plist_path,
|
149
|
+
app_target,
|
150
|
+
'1.0.0',
|
151
|
+
Pod::Platform.new(platform.name),
|
152
|
+
:appl,
|
153
|
+
build_setting_value: "$(SRCROOT)/App/#{Helper.app_target_name(platform)}-Info.plist")
|
154
|
+
Pod::Generator::AppTargetHelper.add_swift_version(app_target, derived_swift_version)
|
155
|
+
app_target.build_configurations.each do |config|
|
156
|
+
# Lint will fail if a AppIcon is set but no image is found with such name
|
157
|
+
# Happens only with Static Frameworks enabled but shouldn't be set anyway
|
158
|
+
config.build_settings.delete('ASSETCATALOG_COMPILER_APPICON_NAME')
|
159
|
+
# Ensure this is set generally but we have seen an issue with ODRs:
|
160
|
+
# see: https://github.com/CocoaPods/CocoaPods/issues/10933
|
161
|
+
config.build_settings['PRODUCT_BUNDLE_IDENTIFIER'] = 'org.cocoapods.${PRODUCT_NAME:rfc1034identifier}'
|
162
|
+
end
|
163
|
+
end
|
164
|
+
app_project.save
|
165
|
+
app_project.recreate_user_schemes
|
166
|
+
end
|
167
|
+
|
168
|
+
# It creates a podfile in memory and builds a library containing the pod
|
169
|
+
# for all available platforms with xcodebuild.
|
170
|
+
#
|
171
|
+
def install_pod
|
172
|
+
%i[validate_targets generate_pods_project integrate_user_project
|
173
|
+
perform_post_install_actions].each { |m| @installer.send(m) }
|
174
|
+
configure_pod_targets(@installer.target_installation_results)
|
175
|
+
|
176
|
+
determine_platforms.each do |platform|
|
177
|
+
validate_dynamic_framework_support(platform.name, @installer.aggregate_targets, platform.deployment_target.to_s)
|
178
|
+
end
|
179
|
+
@installer.pods_project.save
|
180
|
+
end
|
181
|
+
|
182
|
+
# @param [Array<Hash{String, TargetInstallationResult}>] target_installation_results
|
183
|
+
# The installation results to configure
|
184
|
+
#
|
185
|
+
def configure_pod_targets(target_installation_results)
|
186
|
+
target_installation_results.first.values.each do |pod_target_installation_result|
|
187
|
+
pod_target = pod_target_installation_result.target
|
188
|
+
native_target = pod_target_installation_result.native_target
|
189
|
+
native_target.build_configuration_list.build_configurations.each do |build_configuration|
|
190
|
+
(build_configuration.build_settings['OTHER_CFLAGS'] ||= '$(inherited)') << ' -Wincomplete-umbrella'
|
191
|
+
next unless pod_target.uses_swift?
|
192
|
+
|
193
|
+
# The Swift version for the target being validated can be overridden by `--swift-version` or the
|
194
|
+
# `.swift-version` file so we always use the derived Swift version.
|
195
|
+
#
|
196
|
+
# For dependencies, if the derived Swift version is supported then it is the one used. Otherwise, the Swift
|
197
|
+
# version for dependencies is inferred by the target that is integrating them.
|
198
|
+
swift_version = pod_target.spec_swift_versions.map(&:to_s).find do |v|
|
199
|
+
v == derived_swift_version
|
200
|
+
end || pod_target.swift_version
|
201
|
+
build_configuration.build_settings['SWIFT_VERSION'] = swift_version
|
202
|
+
end
|
203
|
+
pod_target_installation_result.test_specs_by_native_target.each do |test_native_target, test_spec|
|
204
|
+
next unless pod_target.uses_swift_for_spec?(test_spec)
|
205
|
+
|
206
|
+
test_native_target.build_configuration_list.build_configurations.each do |build_configuration|
|
207
|
+
swift_version = pod_target == validation_pod_target ? derived_swift_version : pod_target.swift_version
|
208
|
+
build_configuration.build_settings['SWIFT_VERSION'] = swift_version
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
# Produces an error of dynamic frameworks were requested but are not supported by the deployment target
|
215
|
+
#
|
216
|
+
# @param [Array<AggregateTarget>] aggregate_targets
|
217
|
+
# The aggregate targets installed by the installer
|
218
|
+
#
|
219
|
+
# @param [String,Version] deployment_target
|
220
|
+
# The deployment target of the installation
|
221
|
+
#
|
222
|
+
def validate_dynamic_framework_support(platform_name, aggregate_targets, deployment_target)
|
223
|
+
return unless platform_name == :ios
|
224
|
+
return unless deployment_target.nil? || Pod::Version.new(deployment_target).major < 8
|
225
|
+
|
226
|
+
aggregate_targets.each do |target|
|
227
|
+
next unless target.pod_targets.any?(&:uses_swift?)
|
228
|
+
|
229
|
+
uses_xctest = target.spec_consumers.any? do |c|
|
230
|
+
(c.frameworks + c.weak_frameworks).include? 'XCTest'
|
231
|
+
end
|
232
|
+
unless uses_xctest
|
233
|
+
error('swift',
|
234
|
+
'Swift support uses dynamic frameworks and is therefore only supported on iOS > 8.')
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
# @return [Boolean]
|
240
|
+
#
|
241
|
+
def validated?
|
242
|
+
results.result_type != :error && (results.result_type != :warning || allow_warnings)
|
243
|
+
end
|
244
|
+
|
245
|
+
# Returns the pod target for the pod being relatived. Installation must have occurred before this can be invoked.
|
246
|
+
#
|
247
|
+
def relative_pod_targets_from_platfrom(platform)
|
248
|
+
@installer.pod_targets.select { |pt| pt.platform.name == platform.name }
|
249
|
+
end
|
250
|
+
|
251
|
+
# @param [String] platform_name
|
252
|
+
# the name of the platform, which should be declared
|
253
|
+
# in the Podfile.
|
254
|
+
#
|
255
|
+
# @param [String] deployment_target
|
256
|
+
# the deployment target, which should be declared in
|
257
|
+
# the Podfile.
|
258
|
+
#
|
259
|
+
# @param [Boolean] use_frameworks
|
260
|
+
# whether frameworks should be used for the installation
|
261
|
+
#
|
262
|
+
# @param [Array<String>] test_spec_names
|
263
|
+
# the test spec names to include in the podfile.
|
264
|
+
#
|
265
|
+
# @return [Podfile] a podfile that requires the specification on the
|
266
|
+
# current platform.
|
267
|
+
#
|
268
|
+
# @note The generated podfile takes into account whether the linter is
|
269
|
+
# in local mode.
|
270
|
+
#
|
271
|
+
def podfile_from_spec(use_frameworks = true, use_modular_headers = false, use_static_frameworks = false)
|
272
|
+
urls = source_urls
|
273
|
+
all_podspec_pods = podspecs
|
274
|
+
platforms = determine_platforms
|
275
|
+
d_subspecs = determine_subspecs
|
276
|
+
Pod::Podfile.new do
|
277
|
+
install! 'cocoapods', deterministic_uuids: false, warn_for_unused_master_specs_repo: false
|
278
|
+
# By default inhibit warnings for all pods, except the one being validated.
|
279
|
+
inhibit_all_warnings!
|
280
|
+
urls.each { |u| source(u) }
|
281
|
+
platforms.each do |platform|
|
282
|
+
app_name = ProjectGen::Helper.app_target_name(platform)
|
283
|
+
target(app_name) do
|
284
|
+
if use_static_frameworks
|
285
|
+
use_frameworks!(linkage: :static)
|
286
|
+
else
|
287
|
+
use_frameworks!(use_frameworks)
|
288
|
+
end
|
289
|
+
use_modular_headers! if use_modular_headers
|
290
|
+
platform(platform.name, platform.deployment_target.to_s)
|
291
|
+
|
292
|
+
all_podspec_pods.each do |podspec|
|
293
|
+
subspecs = d_subspecs[podspec]
|
294
|
+
if subspecs && !subspecs.empty?
|
295
|
+
subspecs.each do |s|
|
296
|
+
if s.supported_on_platform?(platform)
|
297
|
+
pod s.name, podspec: s.defined_in_file.to_s,
|
298
|
+
inhibit_warnings: false
|
299
|
+
end
|
300
|
+
end
|
301
|
+
elsif podspec.supported_on_platform?(platform)
|
302
|
+
pod podspec.name, podspec: podspec.defined_in_file.to_s,
|
303
|
+
inhibit_warnings: false
|
304
|
+
end
|
305
|
+
end
|
306
|
+
end
|
307
|
+
end
|
308
|
+
end
|
309
|
+
end
|
310
|
+
|
311
|
+
def add_app_project_import
|
312
|
+
app_project = Xcodeproj::Project.open(project_gen_dir + 'App.xcodeproj')
|
313
|
+
app_project.targets.each do |app_target|
|
314
|
+
platform = determine_platforms.find { |pl| pl.name == app_target.platform_name }
|
315
|
+
pod_targets = relative_pod_targets_from_platfrom(platform)
|
316
|
+
pod_targets.each do |pod_target|
|
317
|
+
Pod::Generator::AppTargetHelper.add_app_project_import(app_project, app_target, pod_target, platform.name,
|
318
|
+
Helper.app_target_name(platform))
|
319
|
+
end
|
320
|
+
Pod::Generator::AppTargetHelper.add_xctest_search_paths(app_target) if pod_targets.any? do |pt|
|
321
|
+
pt.spec_consumers.any? do |c|
|
322
|
+
c.frameworks.include?('XCTest') || c.weak_frameworks.include?('XCTest')
|
323
|
+
end
|
324
|
+
end
|
325
|
+
Pod::Generator::AppTargetHelper.add_empty_swift_file(app_project, app_target) if pod_targets.any?(&:uses_swift?)
|
326
|
+
app_project.save
|
327
|
+
Xcodeproj::XCScheme.share_scheme(app_project.path, Helper.app_target_name(platform))
|
328
|
+
pod_targets.each do |pod_target|
|
329
|
+
if shares_pod_target_xcscheme?(pod_target)
|
330
|
+
Xcodeproj::XCScheme.share_scheme(@installer.pods_project.path,
|
331
|
+
pod_target.label)
|
332
|
+
end
|
333
|
+
end
|
334
|
+
end
|
335
|
+
end
|
336
|
+
|
337
|
+
def shares_pod_target_xcscheme?(pod_target)
|
338
|
+
Pathname.new(@installer.pods_project.path + pod_target.label).exist?
|
339
|
+
end
|
340
|
+
end
|
341
|
+
end
|
@@ -0,0 +1,134 @@
|
|
1
|
+
module ProjectGen
|
2
|
+
module SwiftModule
|
3
|
+
# @return [String] the SWIFT_VERSION within the .swift-version file or nil.
|
4
|
+
#
|
5
|
+
def dot_swift_version(podspec)
|
6
|
+
file = podspec.defined_in_file
|
7
|
+
swift_version_path = file.dirname + '.swift-version'
|
8
|
+
return unless swift_version_path.exist?
|
9
|
+
|
10
|
+
swift_version_path.read.strip
|
11
|
+
end
|
12
|
+
|
13
|
+
# @return [String] The derived Swift version to use for validation. The order of precedence is as follows:
|
14
|
+
# - The `--swift-version` parameter is always checked first and honored if passed.
|
15
|
+
# - The `swift_versions` DSL attribute within the podspec, in which case the latest version is always chosen.
|
16
|
+
# - The Swift version within the `.swift-version` file if present.
|
17
|
+
# - If none of the above are set then the `#DEFAULT_SWIFT_VERSION` is used.
|
18
|
+
#
|
19
|
+
def derived_swift_version
|
20
|
+
@derived_swift_version ||= if swift_version
|
21
|
+
swift_version
|
22
|
+
else
|
23
|
+
version = podspecs.map do |podspec|
|
24
|
+
podspec.swift_versions.max || dot_swift_version(podspec)
|
25
|
+
end.compact.max
|
26
|
+
if version
|
27
|
+
version.to_s
|
28
|
+
else
|
29
|
+
Constants::DEFAULT_SWIFT_VERSION
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Performs validation for the version of Swift used during validation.
|
35
|
+
#
|
36
|
+
# An error will be displayed if the user has provided a `swift_versions` attribute within the podspec but is also
|
37
|
+
# using either `--swift-version` parameter or a `.swift-version` file with a Swift version that is not declared
|
38
|
+
# within the attribute.
|
39
|
+
#
|
40
|
+
# The user will be warned that the default version of Swift was used if the following things are true:
|
41
|
+
# - The project uses Swift at all
|
42
|
+
# - The user did not supply a Swift version via a parameter
|
43
|
+
# - There is no `swift_versions` attribute set within the specification
|
44
|
+
# - There is no `.swift-version` file present either.
|
45
|
+
#
|
46
|
+
def validate_swift_version
|
47
|
+
|
48
|
+
specs_for_pods.each_pair do |spec, pod_targets|
|
49
|
+
next unless pod_targets.any?(&:uses_swift?)
|
50
|
+
|
51
|
+
spec_swift_versions = spec.swift_versions.map(&:to_s)
|
52
|
+
|
53
|
+
dot_swift = dot_swift_version(spec)
|
54
|
+
unless spec_swift_versions.empty?
|
55
|
+
message = nil
|
56
|
+
if !dot_swift.nil? && !spec_swift_versions.include?(dot_swift)
|
57
|
+
message = "Specification `#{spec.name}` specifies inconsistent `swift_versions` (#{spec_swift_versions.map do |s|
|
58
|
+
"`#{s}`"
|
59
|
+
end.to_sentence}) compared to the one present in your `.swift-version` file (`#{dot_swift_version}`). " \
|
60
|
+
'Please remove the `.swift-version` file which is now deprecated and only use the `swift_versions` attribute within your podspec.'
|
61
|
+
elsif !swift_version.nil? && !spec_swift_versions.include?(swift_version)
|
62
|
+
message = "Specification `#{spec.name}` specifies inconsistent `swift_versions` (#{spec_swift_versions.map do |s|
|
63
|
+
"`#{s}`"
|
64
|
+
end.to_sentence}) compared to the one passed during gen (`#{swift_version}`)."
|
65
|
+
end
|
66
|
+
unless message.nil?
|
67
|
+
@results.error('swift', message)
|
68
|
+
break
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
if swift_version.nil? && spec.swift_versions.empty?
|
73
|
+
if !dot_swift.nil?
|
74
|
+
# The user will be warned to delete the `.swift-version` file in favor of the `swift_versions` DSL attribute.
|
75
|
+
# This is intentionally not a lint warning since we do not want to break existing setups and instead just soft
|
76
|
+
# deprecate this slowly.
|
77
|
+
#
|
78
|
+
Pod::UI.warn 'Usage of the `.swift_version` file has been deprecated! Please delete the file and use the ' \
|
79
|
+
"`swift_versions` attribute within your podspec instead.\n".yellow
|
80
|
+
else
|
81
|
+
results.warning('swift',
|
82
|
+
'The generator used ' \
|
83
|
+
"Swift `#{Constants::DEFAULT_SWIFT_VERSION}` by default because no Swift version was specified. " \
|
84
|
+
'To specify a Swift version during validation, add the `swift_versions` attribute in your podspec. ' \
|
85
|
+
'Note that usage of a `.swift-version` file is now deprecated.')
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
# Adds a shell script phase, intended only for library targets that contain swift,
|
91
|
+
# to copy the ObjC compatibility header (the -Swift.h file that the swift compiler generates)
|
92
|
+
# to the built products directory. Additionally, the script phase copies the module map, appending a `.Swift`
|
93
|
+
# submodule that references the (moved) compatibility header. Since the module map has been moved, the umbrella header
|
94
|
+
# is _also_ copied, so that it is sitting next to the module map. This is necessary for a successful archive build.
|
95
|
+
#
|
96
|
+
# @param [PBXNativeTarget] native_target
|
97
|
+
# the native target to add the Swift static library script phase into.
|
98
|
+
#
|
99
|
+
# @return [Void]
|
100
|
+
#
|
101
|
+
def add_swift_library_compatibility_header(targets)
|
102
|
+
targets.select(&:build_as_library?).each do |target|
|
103
|
+
relative_module_map_path = target.module_map_path.relative_path_from(target.sandbox.root)
|
104
|
+
relative_umbrella_header_path = target.umbrella_header_path.relative_path_from(target.sandbox.root)
|
105
|
+
shell_script = <<-SH.strip_heredoc
|
106
|
+
COMPATIBILITY_HEADER_ROOT_PATH="${SRCROOT}/${PRODUCT_MODULE_NAME}/#{Constants::COPY_LIBRARY_SWIFT_HEADERS}"
|
107
|
+
COPY_MODULE_MAP_PATH="${COMPATIBILITY_HEADER_ROOT_PATH}/${PRODUCT_MODULE_NAME}.modulemap"
|
108
|
+
ditto "${PODS_ROOT}/#{relative_module_map_path}" "${COPY_MODULE_MAP_PATH}"
|
109
|
+
UMBRELLA_HEADER_PATH="${PODS_ROOT}/#{relative_umbrella_header_path}"
|
110
|
+
if test -f "$UMBRELLA_HEADER_PATH"; then
|
111
|
+
ditto "$UMBRELLA_HEADER_PATH" "${COMPATIBILITY_HEADER_ROOT_PATH}"
|
112
|
+
fi
|
113
|
+
SH
|
114
|
+
|
115
|
+
target.root_spec.script_phases ||= []
|
116
|
+
target.root_spec.script_phases += [{ name: 'Copy Copy generated module header', script: shell_script }]
|
117
|
+
next unless target.uses_swift?
|
118
|
+
|
119
|
+
shell_script = <<-SH.strip_heredoc
|
120
|
+
COMPATIBILITY_HEADER_ROOT_PATH="${SRCROOT}/${PRODUCT_MODULE_NAME}/#{Constants::COPY_LIBRARY_SWIFT_HEADERS}"
|
121
|
+
COPY_COMPATIBILITY_HEADER_PATH="${COMPATIBILITY_HEADER_ROOT_PATH}/${PRODUCT_MODULE_NAME}-Swift.h"#{' '}
|
122
|
+
COPY_MODULE_MAP_PATH="${COMPATIBILITY_HEADER_ROOT_PATH}/${PRODUCT_MODULE_NAME}.modulemap"
|
123
|
+
ditto "${DERIVED_SOURCES_DIR}/${PRODUCT_MODULE_NAME}-Swift.h" "${COPY_COMPATIBILITY_HEADER_PATH}"#{' '}
|
124
|
+
ditto "${BUILT_PRODUCTS_DIR}/${PRODUCT_MODULE_NAME}.swiftmodule" "${COMPATIBILITY_HEADER_ROOT_PATH}/${PRODUCT_MODULE_NAME}.swiftmodule"#{' '}
|
125
|
+
printf "\\n\\nmodule ${PRODUCT_MODULE_NAME}.Swift {\\n header \\"${PRODUCT_MODULE_NAME}-Swift.h\\"\\n requires objc\\n}\\n" >> "${COPY_MODULE_MAP_PATH}"
|
126
|
+
SH
|
127
|
+
target.root_spec.script_phases += [{
|
128
|
+
name: 'Copy Copy generated module and compatibility header',
|
129
|
+
script: shell_script
|
130
|
+
}]
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
require 'cocoapods/target/pod_target'
|
2
|
+
|
3
|
+
module ProjectGen
|
4
|
+
|
5
|
+
require 'delegate'
|
6
|
+
|
7
|
+
class GenTarget < DelegateClass(Pod::PodTarget)
|
8
|
+
def initialize(target)
|
9
|
+
super(target)
|
10
|
+
target.uses_swift?
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
module ProductHelper
|
15
|
+
|
16
|
+
def version
|
17
|
+
root_spec.version
|
18
|
+
end
|
19
|
+
|
20
|
+
def label
|
21
|
+
target.label
|
22
|
+
end
|
23
|
+
|
24
|
+
def scope_suffix
|
25
|
+
target.scope_suffix
|
26
|
+
end
|
27
|
+
|
28
|
+
def static_library_name
|
29
|
+
"lib#{Utils.remove_target_scope_suffix(label, scope_suffix)}.a"
|
30
|
+
end
|
31
|
+
|
32
|
+
def pod_dir
|
33
|
+
root_name = module_basename
|
34
|
+
sandbox.sources_root + root_name
|
35
|
+
end
|
36
|
+
|
37
|
+
def build_as_library?
|
38
|
+
target.build_as_library?
|
39
|
+
end
|
40
|
+
|
41
|
+
def uses_swift?
|
42
|
+
target.uses_swift?
|
43
|
+
end
|
44
|
+
|
45
|
+
def build_as_framework?
|
46
|
+
target.build_as_framework?
|
47
|
+
end
|
48
|
+
|
49
|
+
def module_basename
|
50
|
+
Pod::Specification.root_name(pod_name)
|
51
|
+
end
|
52
|
+
|
53
|
+
def product_name
|
54
|
+
target.product_name
|
55
|
+
end
|
56
|
+
|
57
|
+
def pod_name
|
58
|
+
target.pod_name
|
59
|
+
end
|
60
|
+
|
61
|
+
def product_type
|
62
|
+
target.product_type
|
63
|
+
end
|
64
|
+
|
65
|
+
def file_accessors
|
66
|
+
target.file_accessors
|
67
|
+
end
|
68
|
+
|
69
|
+
def sandbox
|
70
|
+
target.sandbox
|
71
|
+
end
|
72
|
+
|
73
|
+
def xcframework_product_name
|
74
|
+
"#{xcframework_name}.xcframework"
|
75
|
+
end
|
76
|
+
|
77
|
+
def xcframework_name
|
78
|
+
pod_name
|
79
|
+
end
|
80
|
+
|
81
|
+
def root_spec
|
82
|
+
target.root_spec
|
83
|
+
end
|
84
|
+
|
85
|
+
def product_path
|
86
|
+
product_root.join("#{module_basename}-#{product_type}-#{version}")
|
87
|
+
end
|
88
|
+
|
89
|
+
def xcframework_product_path
|
90
|
+
product_path.join(xcframework_product_name)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|