plasmo_xcodeproj 1.21.1
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/LICENSE +19 -0
- data/README.md +95 -0
- data/bin/xcodeproj +10 -0
- data/lib/xcodeproj/command/config_dump.rb +91 -0
- data/lib/xcodeproj/command/project_diff.rb +56 -0
- data/lib/xcodeproj/command/show.rb +60 -0
- data/lib/xcodeproj/command/sort.rb +44 -0
- data/lib/xcodeproj/command/target_diff.rb +43 -0
- data/lib/xcodeproj/command.rb +63 -0
- data/lib/xcodeproj/config/other_linker_flags_parser.rb +73 -0
- data/lib/xcodeproj/config.rb +386 -0
- data/lib/xcodeproj/constants.rb +465 -0
- data/lib/xcodeproj/differ.rb +239 -0
- data/lib/xcodeproj/gem_version.rb +5 -0
- data/lib/xcodeproj/helper.rb +30 -0
- data/lib/xcodeproj/plist.rb +94 -0
- data/lib/xcodeproj/project/case_converter.rb +90 -0
- data/lib/xcodeproj/project/object/build_configuration.rb +255 -0
- data/lib/xcodeproj/project/object/build_file.rb +84 -0
- data/lib/xcodeproj/project/object/build_phase.rb +369 -0
- data/lib/xcodeproj/project/object/build_rule.rb +109 -0
- data/lib/xcodeproj/project/object/configuration_list.rb +117 -0
- data/lib/xcodeproj/project/object/container_item_proxy.rb +116 -0
- data/lib/xcodeproj/project/object/file_reference.rb +338 -0
- data/lib/xcodeproj/project/object/group.rb +506 -0
- data/lib/xcodeproj/project/object/helpers/build_settings_array_settings_by_object_version.rb +72 -0
- data/lib/xcodeproj/project/object/helpers/file_references_factory.rb +245 -0
- data/lib/xcodeproj/project/object/helpers/groupable_helper.rb +260 -0
- data/lib/xcodeproj/project/object/native_target.rb +751 -0
- data/lib/xcodeproj/project/object/reference_proxy.rb +86 -0
- data/lib/xcodeproj/project/object/root_object.rb +100 -0
- data/lib/xcodeproj/project/object/swift_package_product_dependency.rb +29 -0
- data/lib/xcodeproj/project/object/swift_package_remote_reference.rb +33 -0
- data/lib/xcodeproj/project/object/target_dependency.rb +94 -0
- data/lib/xcodeproj/project/object.rb +534 -0
- data/lib/xcodeproj/project/object_attributes.rb +522 -0
- data/lib/xcodeproj/project/object_dictionary.rb +210 -0
- data/lib/xcodeproj/project/object_list.rb +223 -0
- data/lib/xcodeproj/project/project_helper.rb +341 -0
- data/lib/xcodeproj/project/uuid_generator.rb +132 -0
- data/lib/xcodeproj/project.rb +874 -0
- data/lib/xcodeproj/scheme/abstract_scheme_action.rb +100 -0
- data/lib/xcodeproj/scheme/analyze_action.rb +19 -0
- data/lib/xcodeproj/scheme/archive_action.rb +59 -0
- data/lib/xcodeproj/scheme/build_action.rb +298 -0
- data/lib/xcodeproj/scheme/buildable_product_runnable.rb +55 -0
- data/lib/xcodeproj/scheme/buildable_reference.rb +129 -0
- data/lib/xcodeproj/scheme/command_line_arguments.rb +162 -0
- data/lib/xcodeproj/scheme/environment_variables.rb +170 -0
- data/lib/xcodeproj/scheme/execution_action.rb +86 -0
- data/lib/xcodeproj/scheme/launch_action.rb +179 -0
- data/lib/xcodeproj/scheme/location_scenario_reference.rb +49 -0
- data/lib/xcodeproj/scheme/macro_expansion.rb +34 -0
- data/lib/xcodeproj/scheme/profile_action.rb +57 -0
- data/lib/xcodeproj/scheme/remote_runnable.rb +92 -0
- data/lib/xcodeproj/scheme/send_email_action_content.rb +84 -0
- data/lib/xcodeproj/scheme/shell_script_action_content.rb +77 -0
- data/lib/xcodeproj/scheme/test_action.rb +394 -0
- data/lib/xcodeproj/scheme/xml_element_wrapper.rb +82 -0
- data/lib/xcodeproj/scheme.rb +375 -0
- data/lib/xcodeproj/user_interface.rb +22 -0
- data/lib/xcodeproj/workspace/file_reference.rb +79 -0
- data/lib/xcodeproj/workspace/group_reference.rb +67 -0
- data/lib/xcodeproj/workspace/reference.rb +40 -0
- data/lib/xcodeproj/workspace.rb +277 -0
- data/lib/xcodeproj/xcodebuild_helper.rb +108 -0
- data/lib/xcodeproj.rb +29 -0
- metadata +208 -0
@@ -0,0 +1,751 @@
|
|
1
|
+
module Xcodeproj
|
2
|
+
class Project
|
3
|
+
module Object
|
4
|
+
class AbstractTarget < AbstractObject
|
5
|
+
# @!group Attributes
|
6
|
+
|
7
|
+
# @return [String] The name of the Target.
|
8
|
+
#
|
9
|
+
attribute :name, String
|
10
|
+
|
11
|
+
# @return [String] the name of the build product.
|
12
|
+
#
|
13
|
+
attribute :product_name, String
|
14
|
+
|
15
|
+
# @return [String] Comments associated with this target.
|
16
|
+
#
|
17
|
+
# This is apparently no longer used by Xcode.
|
18
|
+
#
|
19
|
+
attribute :comments, String
|
20
|
+
|
21
|
+
# @return [XCConfigurationList] the list of the build configurations of
|
22
|
+
# the target. This list commonly include two configurations
|
23
|
+
# `Debug` and `Release`.
|
24
|
+
#
|
25
|
+
has_one :build_configuration_list, XCConfigurationList
|
26
|
+
|
27
|
+
# @return [ObjectList<PBXTargetDependency>] the targets necessary to
|
28
|
+
# build this target.
|
29
|
+
#
|
30
|
+
has_many :dependencies, PBXTargetDependency
|
31
|
+
|
32
|
+
public
|
33
|
+
|
34
|
+
# @!group Helpers
|
35
|
+
#--------------------------------------#
|
36
|
+
|
37
|
+
# Gets the value for the given build setting in all the build
|
38
|
+
# configurations or the value inheriting the value from the project
|
39
|
+
# ones if needed.
|
40
|
+
#
|
41
|
+
# @param [String] key
|
42
|
+
# the key of the build setting.
|
43
|
+
#
|
44
|
+
# @param [Bool] resolve_against_xcconfig
|
45
|
+
# whether the resolved setting should take in consideration any
|
46
|
+
# configuration file present.
|
47
|
+
#
|
48
|
+
# @return [Hash{String => String}] The value of the build setting
|
49
|
+
# grouped by the name of the build configuration.
|
50
|
+
#
|
51
|
+
# TODO: Full support for this would require to take into account
|
52
|
+
# the default values for the platform.
|
53
|
+
#
|
54
|
+
def resolved_build_setting(key, resolve_against_xcconfig = false)
|
55
|
+
target_settings = build_configuration_list.get_setting(key, resolve_against_xcconfig, self)
|
56
|
+
project_settings = project.build_configuration_list.get_setting(key, resolve_against_xcconfig)
|
57
|
+
target_settings.merge(project_settings) do |_key, target_val, proj_val|
|
58
|
+
target_includes_inherited = Constants::INHERITED_KEYWORDS.any? { |keyword| target_val.include?(keyword) } if target_val
|
59
|
+
if target_includes_inherited && proj_val
|
60
|
+
if target_val.is_a? String
|
61
|
+
target_val.gsub(Regexp.union(Constants::INHERITED_KEYWORDS), proj_val)
|
62
|
+
else
|
63
|
+
target_val.flat_map { |value| Constants::INHERITED_KEYWORDS.include?(value) ? proj_val : value }
|
64
|
+
end
|
65
|
+
else
|
66
|
+
target_val || proj_val
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# Gets the value for the given build setting, properly inherited if
|
72
|
+
# need, if shared across the build configurations.
|
73
|
+
#
|
74
|
+
# @param [String] key
|
75
|
+
# the key of the build setting.
|
76
|
+
#
|
77
|
+
# @param [Boolean] resolve_against_xcconfig
|
78
|
+
# whether the resolved setting should take in consideration any
|
79
|
+
# configuration file present.
|
80
|
+
#
|
81
|
+
# @raise If the build setting has multiple values.
|
82
|
+
#
|
83
|
+
# @note As it is common not to have a setting with no value for
|
84
|
+
# custom build configurations nil keys are not considered to
|
85
|
+
# determine if the setting is unique. This is an heuristic
|
86
|
+
# which might not closely match Xcode behaviour.
|
87
|
+
#
|
88
|
+
# @return [String] The value of the build setting.
|
89
|
+
#
|
90
|
+
def common_resolved_build_setting(key, resolve_against_xcconfig: false)
|
91
|
+
values = resolved_build_setting(key, resolve_against_xcconfig).values.compact.uniq
|
92
|
+
if values.count <= 1
|
93
|
+
values.first
|
94
|
+
else
|
95
|
+
raise "[Xcodeproj] Consistency issue: build setting `#{key}` has multiple values: `#{resolved_build_setting(key)}`"
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
# @return [String] the SDK that the target should use.
|
100
|
+
#
|
101
|
+
def sdk
|
102
|
+
common_resolved_build_setting('SDKROOT')
|
103
|
+
end
|
104
|
+
|
105
|
+
# @return [Symbol] the name of the platform of the target.
|
106
|
+
#
|
107
|
+
def platform_name
|
108
|
+
return unless sdk
|
109
|
+
if sdk.include? 'iphoneos'
|
110
|
+
:ios
|
111
|
+
elsif sdk.include? 'macosx'
|
112
|
+
:osx
|
113
|
+
elsif sdk.include? 'appletvos'
|
114
|
+
:tvos
|
115
|
+
elsif sdk.include? 'watchos'
|
116
|
+
:watchos
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
# @return [String] the version of the SDK.
|
121
|
+
#
|
122
|
+
def sdk_version
|
123
|
+
return unless sdk
|
124
|
+
sdk.scan(/[0-9.]+/).first
|
125
|
+
end
|
126
|
+
|
127
|
+
# @visibility private
|
128
|
+
#
|
129
|
+
# @return [Hash<Symbol, String>]
|
130
|
+
# The name of the setting for the deployment target by platform
|
131
|
+
# name.
|
132
|
+
#
|
133
|
+
DEPLOYMENT_TARGET_SETTING_BY_PLATFORM_NAME = {
|
134
|
+
:ios => 'IPHONEOS_DEPLOYMENT_TARGET',
|
135
|
+
:osx => 'MACOSX_DEPLOYMENT_TARGET',
|
136
|
+
:tvos => 'TVOS_DEPLOYMENT_TARGET',
|
137
|
+
:watchos => 'WATCHOS_DEPLOYMENT_TARGET',
|
138
|
+
}.freeze
|
139
|
+
|
140
|
+
# @return [String] the deployment target of the target according to its
|
141
|
+
# platform.
|
142
|
+
#
|
143
|
+
def deployment_target
|
144
|
+
return unless setting = DEPLOYMENT_TARGET_SETTING_BY_PLATFORM_NAME[platform_name]
|
145
|
+
common_resolved_build_setting(setting)
|
146
|
+
end
|
147
|
+
|
148
|
+
# @param [String] deployment_target the deployment target to set for
|
149
|
+
# the target according to its platform.
|
150
|
+
#
|
151
|
+
def deployment_target=(deployment_target)
|
152
|
+
return unless setting = DEPLOYMENT_TARGET_SETTING_BY_PLATFORM_NAME[platform_name]
|
153
|
+
build_configurations.each do |config|
|
154
|
+
config.build_settings[setting] = deployment_target
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
# @return [ObjectList<XCBuildConfiguration>] the build
|
159
|
+
# configurations of the target.
|
160
|
+
#
|
161
|
+
def build_configurations
|
162
|
+
build_configuration_list.build_configurations
|
163
|
+
end
|
164
|
+
|
165
|
+
# Adds a new build configuration to the target and populates its with
|
166
|
+
# default settings according to the provided type if one doesn't
|
167
|
+
# exists.
|
168
|
+
#
|
169
|
+
# @note If a build configuration with the given name is already
|
170
|
+
# present no new build configuration is added.
|
171
|
+
#
|
172
|
+
# @param [String] name
|
173
|
+
# The name of the build configuration.
|
174
|
+
#
|
175
|
+
# @param [Symbol] type
|
176
|
+
# The type of the build configuration used to populate the build
|
177
|
+
# settings, must be :debug or :release.
|
178
|
+
#
|
179
|
+
# @return [XCBuildConfiguration] the created build configuration or the
|
180
|
+
# existing one with the same name.
|
181
|
+
#
|
182
|
+
def add_build_configuration(name, type)
|
183
|
+
if existing = build_configuration_list[name]
|
184
|
+
existing
|
185
|
+
else
|
186
|
+
build_configuration = project.new(XCBuildConfiguration)
|
187
|
+
build_configuration.name = name
|
188
|
+
product_type = self.product_type if respond_to?(:product_type)
|
189
|
+
build_configuration.build_settings = ProjectHelper.common_build_settings(type, platform_name, deployment_target, product_type)
|
190
|
+
build_configuration_list.build_configurations << build_configuration
|
191
|
+
build_configuration
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
# @param [String] build_configuration_name
|
196
|
+
# the name of a build configuration.
|
197
|
+
#
|
198
|
+
# @return [Hash] the build settings of the build configuration with the
|
199
|
+
# given name.
|
200
|
+
#
|
201
|
+
#
|
202
|
+
def build_settings(build_configuration_name)
|
203
|
+
build_configuration_list.build_settings(build_configuration_name)
|
204
|
+
end
|
205
|
+
|
206
|
+
# @!group Build Phases Helpers
|
207
|
+
|
208
|
+
# @return [PBXFrameworksBuildPhase]
|
209
|
+
# the frameworks build phases of the target.
|
210
|
+
#
|
211
|
+
def frameworks_build_phases
|
212
|
+
build_phases.find { |bp| bp.class == PBXFrameworksBuildPhase }
|
213
|
+
end
|
214
|
+
|
215
|
+
# @return [Array<PBXCopyFilesBuildPhase>]
|
216
|
+
# the copy files build phases of the target.
|
217
|
+
#
|
218
|
+
def copy_files_build_phases
|
219
|
+
build_phases.grep(PBXCopyFilesBuildPhase)
|
220
|
+
end
|
221
|
+
|
222
|
+
# @return [Array<PBXShellScriptBuildPhase>]
|
223
|
+
# the shell script build phases of the target.
|
224
|
+
#
|
225
|
+
def shell_script_build_phases
|
226
|
+
build_phases.grep(PBXShellScriptBuildPhase)
|
227
|
+
end
|
228
|
+
|
229
|
+
# Adds a dependency on the given target.
|
230
|
+
#
|
231
|
+
# @param [AbstractTarget] target
|
232
|
+
# the target which should be added to the dependencies list of
|
233
|
+
# the receiver. The target may be a target of this target's
|
234
|
+
# project or of a subproject of this project. Note that the
|
235
|
+
# subproject must already be added to this target's project.
|
236
|
+
#
|
237
|
+
# @return [void]
|
238
|
+
#
|
239
|
+
def add_dependency(target)
|
240
|
+
unless dependency_for_target(target)
|
241
|
+
container_proxy = project.new(Xcodeproj::Project::PBXContainerItemProxy)
|
242
|
+
if target.project == project
|
243
|
+
container_proxy.container_portal = project.root_object.uuid
|
244
|
+
else
|
245
|
+
subproject_reference = project.reference_for_path(target.project.path)
|
246
|
+
raise ArgumentError, 'add_dependency received target that belongs to a project that is not this project and is not a subproject of this project' unless subproject_reference
|
247
|
+
container_proxy.container_portal = subproject_reference.uuid
|
248
|
+
end
|
249
|
+
container_proxy.proxy_type = Constants::PROXY_TYPES[:native_target]
|
250
|
+
container_proxy.remote_global_id_string = target.uuid
|
251
|
+
container_proxy.remote_info = target.name
|
252
|
+
|
253
|
+
dependency = project.new(Xcodeproj::Project::PBXTargetDependency)
|
254
|
+
dependency.name = target.name
|
255
|
+
dependency.target = target if target.project == project
|
256
|
+
dependency.target_proxy = container_proxy
|
257
|
+
|
258
|
+
dependencies << dependency
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
# Checks whether this target has a dependency on the given target.
|
263
|
+
#
|
264
|
+
# @param [AbstractTarget] target
|
265
|
+
# the target to search for.
|
266
|
+
#
|
267
|
+
# @return [PBXTargetDependency]
|
268
|
+
#
|
269
|
+
def dependency_for_target(target)
|
270
|
+
dependencies.find do |dep|
|
271
|
+
if dep.target_proxy.remote?
|
272
|
+
subproject_reference = project.reference_for_path(target.project.path)
|
273
|
+
uuid = subproject_reference.uuid if subproject_reference
|
274
|
+
dep.target_proxy.remote_global_id_string == target.uuid && dep.target_proxy.container_portal == uuid
|
275
|
+
else
|
276
|
+
dep.target.uuid == target.uuid
|
277
|
+
end
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
# Creates a new copy files build phase.
|
282
|
+
#
|
283
|
+
# @param [String] name
|
284
|
+
# an optional name for the phase.
|
285
|
+
#
|
286
|
+
# @return [PBXCopyFilesBuildPhase] the new phase.
|
287
|
+
#
|
288
|
+
def new_copy_files_build_phase(name = nil)
|
289
|
+
phase = project.new(PBXCopyFilesBuildPhase)
|
290
|
+
phase.name = name
|
291
|
+
build_phases << phase
|
292
|
+
phase
|
293
|
+
end
|
294
|
+
|
295
|
+
# Creates a new shell script build phase.
|
296
|
+
#
|
297
|
+
# @param (see #new_copy_files_build_phase)
|
298
|
+
#
|
299
|
+
# @return [PBXShellScriptBuildPhase] the new phase.
|
300
|
+
#
|
301
|
+
def new_shell_script_build_phase(name = nil)
|
302
|
+
phase = project.new(PBXShellScriptBuildPhase)
|
303
|
+
phase.name = name
|
304
|
+
build_phases << phase
|
305
|
+
phase
|
306
|
+
end
|
307
|
+
|
308
|
+
public
|
309
|
+
|
310
|
+
# @!group System frameworks
|
311
|
+
#--------------------------------------#
|
312
|
+
|
313
|
+
# Adds a file reference for one or more system framework to the project
|
314
|
+
# if needed and adds them to the Frameworks build phases.
|
315
|
+
#
|
316
|
+
# @param [Array<String>, String] names
|
317
|
+
# The name or the list of the names of the framework.
|
318
|
+
#
|
319
|
+
# @note Xcode behaviour is following: if the target has the same SDK
|
320
|
+
# of the project it adds the reference relative to the SDK root
|
321
|
+
# otherwise the reference is added relative to the Developer
|
322
|
+
# directory. This can create confusion or duplication of the
|
323
|
+
# references of frameworks linked by iOS and OS X targets. For
|
324
|
+
# this reason the new Xcodeproj behaviour is to add the
|
325
|
+
# frameworks in a subgroup according to the platform.
|
326
|
+
#
|
327
|
+
# @return [Array<PBXFileReference>] An array of the newly created file
|
328
|
+
# references.
|
329
|
+
#
|
330
|
+
def add_system_framework(names)
|
331
|
+
Array(names).map do |name|
|
332
|
+
case platform_name
|
333
|
+
when :ios
|
334
|
+
group = project.frameworks_group['iOS'] || project.frameworks_group.new_group('iOS')
|
335
|
+
path_sdk_name = 'iPhoneOS'
|
336
|
+
path_sdk_version = sdk_version || Constants::LAST_KNOWN_IOS_SDK
|
337
|
+
when :osx
|
338
|
+
group = project.frameworks_group['OS X'] || project.frameworks_group.new_group('OS X')
|
339
|
+
path_sdk_name = 'MacOSX'
|
340
|
+
path_sdk_version = sdk_version || Constants::LAST_KNOWN_OSX_SDK
|
341
|
+
when :tvos
|
342
|
+
group = project.frameworks_group['tvOS'] || project.frameworks_group.new_group('tvOS')
|
343
|
+
path_sdk_name = 'AppleTVOS'
|
344
|
+
path_sdk_version = sdk_version || Constants::LAST_KNOWN_TVOS_SDK
|
345
|
+
when :watchos
|
346
|
+
group = project.frameworks_group['watchOS'] || project.frameworks_group.new_group('watchOS')
|
347
|
+
path_sdk_name = 'WatchOS'
|
348
|
+
path_sdk_version = sdk_version || Constants::LAST_KNOWN_WATCHOS_SDK
|
349
|
+
else
|
350
|
+
raise 'Unknown platform for target'
|
351
|
+
end
|
352
|
+
|
353
|
+
path = "Platforms/#{path_sdk_name}.platform/Developer/SDKs/#{path_sdk_name}#{path_sdk_version}.sdk/System/Library/Frameworks/#{name}.framework"
|
354
|
+
unless ref = group.find_file_by_path(path)
|
355
|
+
ref = group.new_file(path, :developer_dir)
|
356
|
+
end
|
357
|
+
frameworks_build_phase.add_file_reference(ref, true)
|
358
|
+
ref
|
359
|
+
end
|
360
|
+
end
|
361
|
+
alias_method :add_system_frameworks, :add_system_framework
|
362
|
+
|
363
|
+
# Adds a file reference for one or more system dylib libraries to the project
|
364
|
+
# if needed and adds them to the Frameworks build phases.
|
365
|
+
#
|
366
|
+
# @param [Array<String>, String] names
|
367
|
+
# The name or the list of the names of the libraries.
|
368
|
+
#
|
369
|
+
# @return [void]
|
370
|
+
#
|
371
|
+
def add_system_library(names)
|
372
|
+
add_system_library_extension(names, 'dylib')
|
373
|
+
end
|
374
|
+
alias_method :add_system_libraries, :add_system_library
|
375
|
+
|
376
|
+
def add_system_library_extension(names, extension)
|
377
|
+
Array(names).each do |name|
|
378
|
+
path = "usr/lib/lib#{name}.#{extension}"
|
379
|
+
files = project.frameworks_group.files
|
380
|
+
unless reference = files.find { |ref| ref.path == path }
|
381
|
+
reference = project.frameworks_group.new_file(path, :sdk_root)
|
382
|
+
end
|
383
|
+
frameworks_build_phase.add_file_reference(reference, true)
|
384
|
+
reference
|
385
|
+
end
|
386
|
+
end
|
387
|
+
private :add_system_library_extension
|
388
|
+
|
389
|
+
# Adds a file reference for one or more system tbd libraries to the project
|
390
|
+
# if needed and adds them to the Frameworks build phases.
|
391
|
+
#
|
392
|
+
# @param [Array<String>, String] names
|
393
|
+
# The name or the list of the names of the libraries.
|
394
|
+
#
|
395
|
+
# @return [void]
|
396
|
+
#
|
397
|
+
def add_system_library_tbd(names)
|
398
|
+
add_system_library_extension(names, 'tbd')
|
399
|
+
end
|
400
|
+
alias_method :add_system_libraries_tbd, :add_system_library_tbd
|
401
|
+
|
402
|
+
public
|
403
|
+
|
404
|
+
# @!group AbstractObject Hooks
|
405
|
+
#--------------------------------------#
|
406
|
+
|
407
|
+
# @return [Hash{String => Hash}] A hash suitable to display the object
|
408
|
+
# to the user.
|
409
|
+
#
|
410
|
+
def pretty_print
|
411
|
+
{
|
412
|
+
display_name => {
|
413
|
+
'Build Phases' => build_phases.map(&:pretty_print),
|
414
|
+
'Build Configurations' => build_configurations.map(&:pretty_print),
|
415
|
+
},
|
416
|
+
}
|
417
|
+
end
|
418
|
+
end
|
419
|
+
|
420
|
+
#-----------------------------------------------------------------------#
|
421
|
+
|
422
|
+
# Represents a target handled by Xcode.
|
423
|
+
#
|
424
|
+
class PBXNativeTarget < AbstractTarget
|
425
|
+
# @!group Attributes
|
426
|
+
|
427
|
+
# @return [PBXBuildRule] the build rules of this target.
|
428
|
+
#
|
429
|
+
has_many :build_rules, PBXBuildRule
|
430
|
+
|
431
|
+
# @return [String] the build product type identifier.
|
432
|
+
#
|
433
|
+
attribute :product_type, String
|
434
|
+
|
435
|
+
# @return [PBXFileReference] the reference to the product file.
|
436
|
+
#
|
437
|
+
has_one :product_reference, PBXFileReference
|
438
|
+
|
439
|
+
# @return [ObjectList<XCSwiftPackageProductDependency>] the Swift package products necessary to
|
440
|
+
# build this target.
|
441
|
+
#
|
442
|
+
has_many :package_product_dependencies, XCSwiftPackageProductDependency
|
443
|
+
|
444
|
+
# @return [String] the install path of the product.
|
445
|
+
#
|
446
|
+
attribute :product_install_path, String
|
447
|
+
|
448
|
+
# @return [ObjectList<AbstractBuildPhase>] the build phases of the
|
449
|
+
# target.
|
450
|
+
#
|
451
|
+
# @note Apparently only PBXCopyFilesBuildPhase and
|
452
|
+
# PBXShellScriptBuildPhase can appear multiple times in a
|
453
|
+
# target.
|
454
|
+
#
|
455
|
+
has_many :build_phases, AbstractBuildPhase
|
456
|
+
|
457
|
+
public
|
458
|
+
|
459
|
+
# @!group Helpers
|
460
|
+
#--------------------------------------#
|
461
|
+
|
462
|
+
# @return [Symbol] The type of the target expressed as a symbol.
|
463
|
+
#
|
464
|
+
def symbol_type
|
465
|
+
Constants::PRODUCT_TYPE_UTI.key(product_type)
|
466
|
+
end
|
467
|
+
|
468
|
+
# @return [Boolean] Whether the target is a test target.
|
469
|
+
#
|
470
|
+
def test_target_type?
|
471
|
+
case symbol_type
|
472
|
+
when :octest_bundle, :unit_test_bundle, :ui_test_bundle
|
473
|
+
true
|
474
|
+
else
|
475
|
+
false
|
476
|
+
end
|
477
|
+
end
|
478
|
+
|
479
|
+
# @return [Boolean] Whether the target is an extension.
|
480
|
+
#
|
481
|
+
def extension_target_type?
|
482
|
+
case symbol_type
|
483
|
+
when :app_extension, :watch_extension, :watch2_extension, :tv_extension, :messages_extension
|
484
|
+
true
|
485
|
+
else
|
486
|
+
false
|
487
|
+
end
|
488
|
+
end
|
489
|
+
|
490
|
+
# @return [Boolean] Whether the target is launchable.
|
491
|
+
#
|
492
|
+
def launchable_target_type?
|
493
|
+
case symbol_type
|
494
|
+
when :application, :command_line_tool
|
495
|
+
true
|
496
|
+
else
|
497
|
+
false
|
498
|
+
end
|
499
|
+
end
|
500
|
+
|
501
|
+
# Adds source files to the target.
|
502
|
+
#
|
503
|
+
# @param [Array<PBXFileReference>] file_references
|
504
|
+
# the files references of the source files that should be added
|
505
|
+
# to the target.
|
506
|
+
#
|
507
|
+
# @param [String] compiler_flags
|
508
|
+
# the compiler flags for the source files.
|
509
|
+
#
|
510
|
+
# @yield_param [PBXBuildFile] each created build file.
|
511
|
+
#
|
512
|
+
# @return [Array<PBXBuildFile>] the created build files.
|
513
|
+
#
|
514
|
+
def add_file_references(file_references, compiler_flags = {})
|
515
|
+
file_references.map do |file|
|
516
|
+
extension = File.extname(file.path).downcase
|
517
|
+
header_extensions = Constants::HEADER_FILES_EXTENSIONS
|
518
|
+
is_header_phase = header_extensions.include?(extension)
|
519
|
+
phase = is_header_phase ? headers_build_phase : source_build_phase
|
520
|
+
|
521
|
+
unless build_file = phase.build_file(file)
|
522
|
+
build_file = project.new(PBXBuildFile)
|
523
|
+
build_file.file_ref = file
|
524
|
+
phase.files << build_file
|
525
|
+
end
|
526
|
+
|
527
|
+
if compiler_flags && !compiler_flags.empty? && !is_header_phase
|
528
|
+
(build_file.settings ||= {}).merge!('COMPILER_FLAGS' => compiler_flags) do |_, old, new|
|
529
|
+
[old, new].compact.join(' ')
|
530
|
+
end
|
531
|
+
end
|
532
|
+
|
533
|
+
yield build_file if block_given?
|
534
|
+
|
535
|
+
build_file
|
536
|
+
end
|
537
|
+
end
|
538
|
+
|
539
|
+
# Adds resource files to the resources build phase of the target.
|
540
|
+
#
|
541
|
+
# @param [Array<PBXFileReference>] resource_file_references
|
542
|
+
# the files references of the resources to the target.
|
543
|
+
#
|
544
|
+
# @return [void]
|
545
|
+
#
|
546
|
+
def add_resources(resource_file_references)
|
547
|
+
resource_file_references.each do |file|
|
548
|
+
next if resources_build_phase.include?(file)
|
549
|
+
build_file = project.new(PBXBuildFile)
|
550
|
+
build_file.file_ref = file
|
551
|
+
resources_build_phase.files << build_file
|
552
|
+
end
|
553
|
+
end
|
554
|
+
|
555
|
+
# Adds on demand resources to the resources build phase of the target.
|
556
|
+
#
|
557
|
+
# @param {String => [Array<PBXFileReference>]} on_demand_resource_tag_files
|
558
|
+
# the files references of the on demand resources to add to the target keyed by the tag.
|
559
|
+
#
|
560
|
+
# @return [void]
|
561
|
+
#
|
562
|
+
def add_on_demand_resources(on_demand_resource_tag_files)
|
563
|
+
on_demand_resource_tag_files.each do |tag, file_refs|
|
564
|
+
file_refs.each do |file_ref|
|
565
|
+
if resources_build_phase.include?(file_ref)
|
566
|
+
existing_build_file = resources_build_phase.build_file(file_ref)
|
567
|
+
existing_build_file.settings ||= {}
|
568
|
+
existing_build_file.settings['ASSET_TAGS'] ||= []
|
569
|
+
existing_build_file.settings['ASSET_TAGS'] << tag
|
570
|
+
existing_build_file.settings['ASSET_TAGS'].uniq!
|
571
|
+
next
|
572
|
+
end
|
573
|
+
build_file = resources_build_phase.add_file_reference(file_ref, true)
|
574
|
+
build_file.settings = (build_file.settings ||= {}).merge('ASSET_TAGS' => [tag])
|
575
|
+
end
|
576
|
+
end
|
577
|
+
end
|
578
|
+
|
579
|
+
# Remove on demand resources from the resources build phase of the target.
|
580
|
+
#
|
581
|
+
# @param {String => [Array<PBXFileReference>]} on_demand_resource_tag_files
|
582
|
+
# the files references of the on demand resources to add to the target keyed by the tag.
|
583
|
+
#
|
584
|
+
# @return [void]
|
585
|
+
#
|
586
|
+
def remove_on_demand_resources(on_demand_resource_tag_files)
|
587
|
+
on_demand_resource_tag_files.each do |tag, file_refs|
|
588
|
+
file_refs.each do |file_ref|
|
589
|
+
build_file = resources_build_phase.build_file(file_ref)
|
590
|
+
next if build_file.nil?
|
591
|
+
asset_tags = build_file.settings['ASSET_TAGS']
|
592
|
+
asset_tags.delete(tag)
|
593
|
+
resources_build_phase.remove_file_reference(file_ref) if asset_tags.empty?
|
594
|
+
end
|
595
|
+
end
|
596
|
+
end
|
597
|
+
|
598
|
+
# Finds or creates the headers build phase of the target.
|
599
|
+
#
|
600
|
+
# @note A target should have only one headers build phase.
|
601
|
+
#
|
602
|
+
# @return [PBXHeadersBuildPhase] the headers build phase.
|
603
|
+
#
|
604
|
+
def headers_build_phase
|
605
|
+
find_or_create_build_phase_by_class(PBXHeadersBuildPhase)
|
606
|
+
end
|
607
|
+
|
608
|
+
# Finds or creates the source build phase of the target.
|
609
|
+
#
|
610
|
+
# @note A target should have only one source build phase.
|
611
|
+
#
|
612
|
+
# @return [PBXSourcesBuildPhase] the source build phase.
|
613
|
+
#
|
614
|
+
def source_build_phase
|
615
|
+
find_or_create_build_phase_by_class(PBXSourcesBuildPhase)
|
616
|
+
end
|
617
|
+
|
618
|
+
# Finds or creates the frameworks build phase of the target.
|
619
|
+
#
|
620
|
+
# @note A target should have only one frameworks build phase.
|
621
|
+
#
|
622
|
+
# @return [PBXFrameworksBuildPhase] the frameworks build phase.
|
623
|
+
#
|
624
|
+
def frameworks_build_phase
|
625
|
+
find_or_create_build_phase_by_class(PBXFrameworksBuildPhase)
|
626
|
+
end
|
627
|
+
|
628
|
+
# Finds or creates the resources build phase of the target.
|
629
|
+
#
|
630
|
+
# @note A target should have only one resources build phase.
|
631
|
+
#
|
632
|
+
# @return [PBXResourcesBuildPhase] the resources build phase.
|
633
|
+
#
|
634
|
+
def resources_build_phase
|
635
|
+
find_or_create_build_phase_by_class(PBXResourcesBuildPhase)
|
636
|
+
end
|
637
|
+
|
638
|
+
private
|
639
|
+
|
640
|
+
# @!group Internal Helpers
|
641
|
+
#--------------------------------------#
|
642
|
+
|
643
|
+
# Find or create a build phase by a given class
|
644
|
+
#
|
645
|
+
# @param [Class] phase_class the class of the build phase to find or create.
|
646
|
+
#
|
647
|
+
# @return [AbstractBuildPhase] the build phase whose class match the given phase_class.
|
648
|
+
#
|
649
|
+
def find_or_create_build_phase_by_class(phase_class)
|
650
|
+
@phases ||= {}
|
651
|
+
unless phase_class < AbstractBuildPhase
|
652
|
+
raise ArgumentError, "#{phase_class} must be a subclass of #{AbstractBuildPhase.class}"
|
653
|
+
end
|
654
|
+
@phases[phase_class] ||= build_phases.find { |bp| bp.class == phase_class } ||
|
655
|
+
project.new(phase_class).tap { |bp| build_phases << bp }
|
656
|
+
end
|
657
|
+
|
658
|
+
public
|
659
|
+
|
660
|
+
# @!group AbstractObject Hooks
|
661
|
+
#--------------------------------------#
|
662
|
+
|
663
|
+
# Sorts the to many attributes of the object according to the display
|
664
|
+
# name.
|
665
|
+
#
|
666
|
+
# Build phases are not sorted as they order is relevant.
|
667
|
+
#
|
668
|
+
def sort(_options = nil)
|
669
|
+
attributes_to_sort = to_many_attributes.reject { |attr| attr.name == :build_phases }
|
670
|
+
attributes_to_sort.each do |attrb|
|
671
|
+
list = attrb.get_value(self)
|
672
|
+
list.sort! do |x, y|
|
673
|
+
x.display_name <=> y.display_name
|
674
|
+
end
|
675
|
+
end
|
676
|
+
end
|
677
|
+
|
678
|
+
def to_hash_as(method = :to_hash)
|
679
|
+
hash_as = super
|
680
|
+
if !hash_as['packageProductDependencies'].nil? && hash_as['packageProductDependencies'].empty?
|
681
|
+
hash_as.delete('packageProductDependencies')
|
682
|
+
end
|
683
|
+
hash_as
|
684
|
+
end
|
685
|
+
|
686
|
+
def to_ascii_plist
|
687
|
+
plist = super
|
688
|
+
if !plist.value['packageProductDependencies'].nil? && plist.value['packageProductDependencies'].empty?
|
689
|
+
plist.value.delete('packageProductDependencies')
|
690
|
+
end
|
691
|
+
plist
|
692
|
+
end
|
693
|
+
end
|
694
|
+
|
695
|
+
#-----------------------------------------------------------------------#
|
696
|
+
|
697
|
+
# Represents a target that only consists in a aggregate of targets.
|
698
|
+
#
|
699
|
+
# @todo Apparently it can't have build rules.
|
700
|
+
#
|
701
|
+
class PBXAggregateTarget < AbstractTarget
|
702
|
+
# @!group Attributes
|
703
|
+
|
704
|
+
# @return [PBXBuildRule] the build phases of the target.
|
705
|
+
#
|
706
|
+
# @note Apparently only PBXCopyFilesBuildPhase and
|
707
|
+
# PBXShellScriptBuildPhase can appear multiple times in a
|
708
|
+
# target.
|
709
|
+
#
|
710
|
+
has_many :build_phases, [PBXCopyFilesBuildPhase, PBXShellScriptBuildPhase]
|
711
|
+
end
|
712
|
+
|
713
|
+
#-----------------------------------------------------------------------#
|
714
|
+
|
715
|
+
# Represents a legacy target which uses an external build tool.
|
716
|
+
#
|
717
|
+
# Apparently it can't have any build phase but the attribute can be
|
718
|
+
# present.
|
719
|
+
#
|
720
|
+
class PBXLegacyTarget < AbstractTarget
|
721
|
+
# @!group Attributes
|
722
|
+
|
723
|
+
# @return [String] e.g "Dir"
|
724
|
+
#
|
725
|
+
attribute :build_working_directory, String
|
726
|
+
|
727
|
+
# @return [String] e.g "$(ACTION)"
|
728
|
+
#
|
729
|
+
attribute :build_arguments_string, String
|
730
|
+
|
731
|
+
# @return [String] e.g "1"
|
732
|
+
#
|
733
|
+
attribute :pass_build_settings_in_environment, String
|
734
|
+
|
735
|
+
# @return [String] e.g "/usr/bin/make"
|
736
|
+
#
|
737
|
+
attribute :build_tool_path, String
|
738
|
+
|
739
|
+
# @return [PBXBuildRule] the build phases of the target.
|
740
|
+
#
|
741
|
+
# @note Apparently only PBXCopyFilesBuildPhase and
|
742
|
+
# PBXShellScriptBuildPhase can appear multiple times in a
|
743
|
+
# target.
|
744
|
+
#
|
745
|
+
has_many :build_phases, AbstractBuildPhase
|
746
|
+
end
|
747
|
+
|
748
|
+
#-----------------------------------------------------------------------#
|
749
|
+
end
|
750
|
+
end
|
751
|
+
end
|