xcode-archive-cache 0.0.8.pre.2 → 0.0.10

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.
@@ -13,7 +13,7 @@ module XcodeArchiveCache
13
13
  # @return [Hash{String => Container}]
14
14
  # Target build settings keyed by target name
15
15
  #
16
- def extract_per_target(build_settings)
16
+ def extract_per_target(build_settings, fix_simulator)
17
17
  per_target_settings = build_settings.split("Build settings for action")
18
18
  result = Hash.new
19
19
 
@@ -22,6 +22,7 @@ module XcodeArchiveCache
22
22
  target_name = get_target_name(parsed_settings)
23
23
  next unless target_name
24
24
 
25
+ replace_platform_with_simulator(parsed_settings) if fix_simulator
25
26
  filtered_settings = filter.filter(parsed_settings)
26
27
  result[target_name] = Container.new(parsed_settings, filtered_settings)
27
28
  end
@@ -65,6 +66,25 @@ module XcodeArchiveCache
65
66
  result
66
67
  end
67
68
 
69
+
70
+ # @param [Hash{String => String}] settings
71
+ #
72
+ def replace_platform_with_simulator(settings)
73
+ original_platform = settings[EFFECTIVE_PLATFORM_NAME_KEY]
74
+ simulator_platform = settings[CORRESPONDING_SIMULATOR_PLATFORM_NAME_KEY]
75
+ settings[EFFECTIVE_PLATFORM_NAME_KEY] = "-#{simulator_platform}"
76
+
77
+ configuration = settings[CONFIGURATION_KEY]
78
+ path_regexp = Regexp.new("#{configuration}#{original_platform}")
79
+ simulator_path = "#{configuration}-#{simulator_platform}"
80
+ settings.each do |key, value|
81
+ settings[key] = value.gsub(path_regexp, simulator_path)
82
+ end
83
+ end
84
+
85
+ EFFECTIVE_PLATFORM_NAME_KEY = "EFFECTIVE_PLATFORM_NAME".freeze
86
+ CORRESPONDING_SIMULATOR_PLATFORM_NAME_KEY = "CORRESPONDING_SIMULATOR_PLATFORM_NAME".freeze
87
+ CONFIGURATION_KEY = "CONFIGURATION".freeze
68
88
  TARGET_NAME_KEY = "TARGETNAME".freeze
69
89
 
70
90
  # @param [Hash{String => String}] parsed_settings
@@ -10,7 +10,7 @@ module XcodeArchiveCache
10
10
  # Machine-dependent settings i.e. paths, user names, group names are rejected
11
11
  #
12
12
  def filter(settings, settings_to_keep = SETTINGS_TO_KEEP)
13
- filtered_settings = settings.select {|name, _| settings_to_keep.include?(name)}
13
+ filtered_settings = settings.select { |name, _| settings_to_keep.include?(name) }
14
14
  SETTINGS_TO_STRIP.each do |name|
15
15
  value = filtered_settings[name]
16
16
  next if value == nil
@@ -44,7 +44,9 @@ module XcodeArchiveCache
44
44
  # splitting will be broken, but probability of
45
45
  # someone using such path is quite low (or it isn't ?)
46
46
  #
47
- value_components = value_without_quotes.split(/\s-/)
47
+ value_components = value_without_quotes
48
+ .split(/^-|\s-/)
49
+ .select { |component| component.length > 0 }
48
50
 
49
51
  index = 0
50
52
  indices_to_remove = []
@@ -66,7 +68,8 @@ module XcodeArchiveCache
66
68
  kept_components.push(component) unless indices_to_remove.include?(component_index)
67
69
  end
68
70
 
69
- kept_components.join(" -")
71
+ result = kept_components.join(" -")
72
+ result.length > 0 ? "-#{result}" : ""
70
73
  end
71
74
 
72
75
  # TODO: extend
@@ -283,6 +286,7 @@ module XcodeArchiveCache
283
286
  output-file-map
284
287
  save-optimization-record-path
285
288
  working-directory
289
+ fmodule-map-file
286
290
  )
287
291
  end
288
292
  end
@@ -3,6 +3,11 @@ module XcodeArchiveCache
3
3
 
4
4
  FULL_PRODUCT_NAME_KEY = "FULL_PRODUCT_NAME".freeze
5
5
  DWARF_DSYM_FILE_NAME_KEY = "DWARF_DSYM_FILE_NAME".freeze
6
+ MODULEMAP_FILE_KEY = "MODULEMAP_FILE".freeze
7
+ SWIFT_OBJC_INTERFACE_HEADER_NAME_KEY = "SWIFT_OBJC_INTERFACE_HEADER_NAME".freeze
8
+ SWIFT_MODULE_NAME_KEY = "SWIFT_MODULE_NAME".freeze
9
+ PRODUCT_MODULE_NAME_KEY = "PRODUCT_MODULE_NAME".freeze
10
+ DERIVED_SOURCES_DIR_KEY = "DERIVED_SOURCES_DIR".freeze
6
11
 
7
12
  class Container
8
13
 
@@ -58,9 +63,11 @@ module XcodeArchiveCache
58
63
  end
59
64
  end
60
65
 
66
+ should_fix_settings = executor.set_up_for_simulator?
67
+
61
68
  threads.each do |thread|
62
69
  project_path, all_targets_settings = thread.value
63
- per_target_settings = extractor.extract_per_target(all_targets_settings)
70
+ per_target_settings = extractor.extract_per_target(all_targets_settings, should_fix_settings)
64
71
  set_project_settings(project_path, per_target_settings)
65
72
  end
66
73
  end
@@ -45,7 +45,7 @@ module XcodeArchiveCache
45
45
 
46
46
  # @param [String] characters
47
47
  #
48
- # @return [String]
48
+ # @return [Regexp]
49
49
  #
50
50
  def create_entry_regex(characters = SETTING_NAME_CHARACTERS)
51
51
  Regexp.new("\\$[({]#{characters}[)}]")
@@ -7,9 +7,9 @@ module XcodeArchiveCache
7
7
  # @param [Xcodeproj::Project::Object::XCBuildConfiguration] build_configuration
8
8
  # @param [String] path
9
9
  #
10
- def add_framework_search_path(build_configuration, path)
10
+ def replace_or_add_framework_search_path(build_configuration, target_name, path)
11
11
  debug("using framework search path #{path}")
12
- add_flag_to_configuration(build_configuration, FRAMEWORK_SEARCH_PATHS_KEY, path_to_search_path(path))
12
+ replace_or_add_flag(build_configuration, [FRAMEWORK_SEARCH_PATHS_KEY], nil, [target_name], path_to_search_path(path), true)
13
13
  end
14
14
 
15
15
  # @param [Xcodeproj::Project::Object::XCBuildConfiguration] build_configuration
@@ -26,6 +26,37 @@ module XcodeArchiveCache
26
26
  # @param [Xcodeproj::Project::Object::XCBuildConfiguration] build_configuration
27
27
  # @param [XcodeArchiveCache::BuildGraph::Node] node
28
28
  #
29
+ def add_static_lib_linker_flag(build_configuration, node)
30
+ flag = get_linker_flag(node)
31
+ if flag
32
+ debug("using ld flag #{flag}")
33
+ add_linker_flag(build_configuration, flag)
34
+ end
35
+ end
36
+
37
+ # @param [Xcodeproj::Project::Object::XCBuildConfiguration] build_configuration
38
+ # @param [XcodeArchiveCache::BuildGraph::Node] node
39
+ #
40
+ def add_static_lib_libtool_flag(build_configuration, node)
41
+ flag = get_linker_flag(node)
42
+ if flag
43
+ debug("using libtool flag #{flag}")
44
+ add_libtool_flag(build_configuration, flag)
45
+ end
46
+ end
47
+
48
+ # @param [Xcodeproj::Project::Object::XCBuildConfiguration] build_configuration
49
+ # @param [String] path
50
+ #
51
+ def add_swift_include_path(build_configuration, path)
52
+ debug("adding #{path} to SWIFT_INCLUDE_PATHS")
53
+ add_flag_to_configuration(build_configuration, SWIFT_INCLUDE_PATHS_KEY, path_to_search_path(path))
54
+ end
55
+
56
+ # @param [Xcodeproj::Project::Object::XCBuildConfiguration] build_configuration
57
+ # @param [String] artifact_location
58
+ # @param [XcodeArchiveCache::BuildGraph::Node] node
59
+ #
29
60
  def add_framework_headers_iquote(build_configuration, artifact_location, node)
30
61
  headers_search_path = get_framework_headers_iquote(artifact_location, node)
31
62
  debug("using -iquote path #{headers_search_path}")
@@ -35,9 +66,9 @@ module XcodeArchiveCache
35
66
  # @param [Xcodeproj::Project::Object::XCBuildConfiguration] build_configuration
36
67
  # @param [String] path
37
68
  #
38
- def add_library_search_path(build_configuration, path)
69
+ def replace_or_add_library_search_path(build_configuration, target_name, path)
39
70
  debug("using library search path #{path}")
40
- add_flag_to_configuration(build_configuration, LIBRARY_SEARCH_PATHS_KEY, path_to_search_path(path))
71
+ replace_or_add_flag(build_configuration, [LIBRARY_SEARCH_PATHS_KEY], nil, [target_name], path_to_search_path(path), true)
41
72
  end
42
73
 
43
74
  # @param [Xcodeproj::Project::Object::XCBuildConfiguration] build_configuration
@@ -64,15 +95,32 @@ module XcodeArchiveCache
64
95
  add_cflag(build_configuration, path_to_capital_i(path))
65
96
  end
66
97
 
98
+ # @param [Xcodeproj::Project::Object::XCBuildConfiguration] build_configuration
99
+ # @param [Array<String>] old_modulemap_names
100
+ # @param [String] path
101
+ #
102
+ def fix_module_map_path(build_configuration, old_modulemap_names, path)
103
+ debug("using #{path}")
104
+
105
+ settings_with_modulemaps = [OTHER_CFLAGS_KEY, OTHER_CPLUSPLUSFLAGS_KEY, OTHER_SWIFT_FLAGS_KEY]
106
+ replace_or_add_flag(build_configuration, settings_with_modulemaps, MODULE_MAP_FLAG, old_modulemap_names, path_to_search_path(path), false)
107
+ end
108
+
67
109
  private
68
110
 
69
111
  FRAMEWORK_SEARCH_PATHS_KEY = "FRAMEWORK_SEARCH_PATHS"
70
112
  LIBRARY_SEARCH_PATHS_KEY = "LIBRARY_SEARCH_PATHS"
71
113
  HEADER_SEARCH_PATHS_KEY = "HEADER_SEARCH_PATHS"
72
114
  OTHER_CFLAGS_KEY = "OTHER_CFLAGS"
115
+ OTHER_CPLUSPLUSFLAGS_KEY = "OTHER_CPLUSPLUSFLAGS"
73
116
  OTHER_LDFLAGS_KEY = "OTHER_LDFLAGS"
117
+ OTHER_LIBTOOLFLAGS_KEY = "OTHER_LIBTOOLFLAGS"
118
+ OTHER_SWIFT_FLAGS_KEY = "OTHER_SWIFT_FLAGS"
119
+ SWIFT_INCLUDE_PATHS_KEY = "SWIFT_INCLUDE_PATHS"
74
120
  INHERITED_SETTINGS_VALUE = "$(inherited)"
75
121
 
122
+ MODULE_MAP_FLAG = "-fmodule-map-file="
123
+
76
124
  # @param [Xcodeproj::Project::Object::XCBuildConfiguration] build_configuration
77
125
  # @param [String] flag
78
126
  #
@@ -80,6 +128,13 @@ module XcodeArchiveCache
80
128
  add_flag_to_configuration(build_configuration, OTHER_LDFLAGS_KEY, flag)
81
129
  end
82
130
 
131
+ # @param [Xcodeproj::Project::Object::XCBuildConfiguration] build_configuration
132
+ # @param [String] flag
133
+ #
134
+ def add_libtool_flag(build_configuration, flag)
135
+ add_flag_to_configuration(build_configuration, OTHER_LIBTOOLFLAGS_KEY, flag)
136
+ end
137
+
83
138
  # @param [Xcodeproj::Project::Object::XCBuildConfiguration] build_configuration
84
139
  # @param [String] flag
85
140
  #
@@ -167,6 +222,120 @@ module XcodeArchiveCache
167
222
 
168
223
  "-framework \"#{framework_name}\""
169
224
  end
225
+
226
+ # @param [XcodeArchiveCache::BuildGraph::Node] node
227
+ #
228
+ # @return [String]
229
+ #
230
+ # libSomething.a -> -lSomething
231
+ #
232
+ def get_linker_flag(node)
233
+ return unless node.product_file_name
234
+
235
+ node.product_file_name.gsub(/^lib/, "-l").gsub(/\.a$/, "")
236
+ end
237
+
238
+ # @param [Xcodeproj::Project::Object::XCBuildConfiguration] build_configuration
239
+ # @param [Array<String>] setting_keys
240
+ # @param [String] flag_name
241
+ # @param [Array<String>] possible_old_values
242
+ # @param [String] new_value
243
+ #
244
+ def replace_or_add_flag(build_configuration, setting_keys, flag_name, possible_old_values, new_value, add_if_missing)
245
+ replaced = false
246
+
247
+ setting_keys.each do |setting|
248
+ replaced = replace_flag_value(build_configuration.build_settings, setting, flag_name, possible_old_values, new_value) || replaced
249
+ end
250
+
251
+ if build_configuration.base_configuration_reference
252
+ xcconfig_path = build_configuration.base_configuration_reference.real_path
253
+ project_dir = File.dirname(build_configuration.project.path)
254
+
255
+ replaced = replace_flag_value_in_xcconfig_recursively(xcconfig_path, project_dir, setting_keys, flag_name, possible_old_values, new_value) || replaced
256
+ end
257
+
258
+ if !replaced && add_if_missing
259
+ full_value = get_full_flag_value(flag_name, new_value)
260
+
261
+ setting_keys.each do |setting|
262
+ add_flag_to_configuration(build_configuration, setting, full_value)
263
+ end
264
+ end
265
+ end
266
+
267
+ # @param [String] xcconfig_path
268
+ # @param [String] project_dir
269
+ # @param [Array<String>] setting_keys
270
+ # @param [String] flag_name
271
+ # @param [Array<String>] possible_old_values
272
+ # @param [String] new_value
273
+ #
274
+ def replace_flag_value_in_xcconfig_recursively(xcconfig_path, project_dir, setting_keys, flag_name, possible_old_values, new_value)
275
+ debug("changing #{possible_old_values} to #{new_value} in #{File.basename(xcconfig_path)}")
276
+ return unless File.exist?(xcconfig_path)
277
+
278
+ replaced = false
279
+ xcconfig = Xcodeproj::Config.new(xcconfig_path)
280
+
281
+ setting_keys.each do |key|
282
+ replaced = replace_flag_value(xcconfig.attributes, key, flag_name, possible_old_values, new_value) || replaced
283
+ end
284
+
285
+ xcconfig.save_as(Pathname.new(xcconfig_path))
286
+
287
+ xcconfig.includes.each do |included_xcconfig|
288
+ included_xcconfig_path = File.join(project_dir, included_xcconfig)
289
+ replaced = replace_flag_value_in_xcconfig_recursively(included_xcconfig_path, project_dir, setting_keys, flag_name, possible_old_values, new_value) || replaced
290
+ end
291
+
292
+ replaced
293
+ end
294
+
295
+ # @param [Hash] attributes
296
+ # @param [String] setting_key
297
+ # @param [String] flag_name
298
+ # @param [Array<String>] possible_old_values
299
+ # @param [String] new_value
300
+ #
301
+ def replace_flag_value(attributes, setting_key, flag_name, possible_old_values, new_value)
302
+ build_settings = attributes[setting_key]
303
+ return unless build_settings
304
+
305
+ replaced = false
306
+ is_string = build_settings.is_a?(String)
307
+ build_settings = build_settings.split(" ") if is_string
308
+ full_value = get_full_flag_value(flag_name, new_value)
309
+ old_value_regexps = possible_old_values.map { |value| Regexp.new("#{value}\"*$") }
310
+
311
+ updated_settings = build_settings
312
+ .map { |line| line.split(" ") }
313
+ .flatten
314
+ .map do |line|
315
+ if flag_name
316
+ next line unless line.include?(flag_name)
317
+ end
318
+
319
+ updated_line = line
320
+
321
+ old_value_regexps.each do |regexp|
322
+ if regexp.match?(line)
323
+ replaced = true
324
+ updated_line = full_value
325
+ break
326
+ end
327
+ end
328
+
329
+ updated_line
330
+ end
331
+
332
+ attributes[setting_key] = is_string ? updated_settings.join(" ") : updated_settings
333
+ replaced
334
+ end
335
+
336
+ def get_full_flag_value(flag_name, value)
337
+ "#{flag_name}#{value}"
338
+ end
170
339
  end
171
340
  end
172
341
  end
@@ -12,11 +12,21 @@ module XcodeArchiveCache
12
12
  debug("removing #{prebuilt_target.name} from #{dependent_target.display_name}")
13
13
 
14
14
  remove_from_dependencies(prebuilt_target, dependent_target)
15
+ remove_from_linking(prebuilt_node, dependent_target)
15
16
  remove_from_schemes(prebuilt_target, dependent_target)
16
17
 
17
18
  debug("finished removing #{prebuilt_target.name} from #{dependent_target.display_name}")
18
19
  end
19
20
 
21
+ # @param [XcodeArchiveCache::BuildGraph::Node] prebuilt_node
22
+ # @param [Xcodeproj::Project::Object::PBXNativeTarget] dependent_target
23
+ #
24
+ # @return [Boolean]
25
+ #
26
+ def is_linked(prebuilt_node, dependent_target)
27
+ !find_linked(prebuilt_node, dependent_target).empty?
28
+ end
29
+
20
30
  private
21
31
 
22
32
  # @param [Xcodeproj::Project::Object::PBXNativeTarget] prebuilt_target
@@ -46,7 +56,7 @@ module XcodeArchiveCache
46
56
  #
47
57
  def remove_from_linking(prebuilt_node, dependent_target)
48
58
  debug("product name is #{prebuilt_node.product_file_name}")
49
- frameworks = dependent_target.frameworks_build_phase.files.select {|file| file.display_name == prebuilt_node.product_file_name}
59
+ frameworks = find_linked(prebuilt_node, dependent_target)
50
60
  debug("found #{frameworks.length} linked products")
51
61
 
52
62
  frameworks.each do |framework|
@@ -67,6 +77,17 @@ module XcodeArchiveCache
67
77
  end
68
78
  end
69
79
 
80
+ # @param [Xcodeproj::Project::Object::PBXNativeTarget] dependent_target
81
+ # @param [XcodeArchiveCache::BuildGraph::Node] prebuilt_node
82
+ #
83
+ # @return [Array<PBXBuildFile>]
84
+ #
85
+ def find_linked(prebuilt_node, dependent_target)
86
+ return [] unless dependent_target.frameworks_build_phase
87
+
88
+ dependent_target.frameworks_build_phase.files.select {|file| file.display_name == prebuilt_node.product_file_name}
89
+ end
90
+
70
91
  # @param [Xcodeproj::Project::Object::PBXNativeTarget] target
71
92
  #
72
93
  # @return [Array<Xcodeproj::XCScheme>]
@@ -9,6 +9,7 @@ module XcodeArchiveCache
9
9
  def initialize(storage)
10
10
  @storage = storage
11
11
  @build_settings_interpolator = XcodeArchiveCache::BuildSettings::StringInterpolator.new
12
+ @modulemap_header_path_extractor = XcodeArchiveCache::Modulemap::HeaderPathExtractor.new
12
13
  end
13
14
 
14
15
  # @param [XcodeArchiveCache::BuildGraph::Node] node
@@ -19,17 +20,36 @@ module XcodeArchiveCache
19
20
 
20
21
  node.native_target.copy_files_build_phases.each do |build_phase|
21
22
  file_paths = build_phase.files
22
- .map {|build_file| get_real_path(build_file)}
23
+ .map { |build_file| get_real_path(build_file) }
23
24
  .compact
24
25
  .uniq
25
- .select {|path| File.extname(path) == ".h"}
26
+ .select { |path| File.extname(path) == ".h" }
26
27
  destination_path = get_destination_dir_path(node, build_phase)
27
28
  storage.store_headers(node, destination_path, file_paths)
28
29
 
29
30
  header_count += file_paths.length
30
31
  end
31
32
 
32
- debug("found #{header_count} headers")
33
+ if node.has_static_library_product?
34
+ headers_file_paths = node.native_target
35
+ .headers_build_phase
36
+ .files
37
+ .select { |file| file.settings && file.settings["ATTRIBUTES"].include?("Public") }
38
+ .map { |header| get_real_path(header) }
39
+ .uniq
40
+ storage.store_default_headers(node, headers_file_paths)
41
+
42
+ header_count += headers_file_paths.length
43
+ end
44
+
45
+ modulemap_file_path = node.original_modulemap_file_path
46
+ if modulemap_file_path && File.exist?(modulemap_file_path)
47
+ header_file_paths = modulemap_header_path_extractor.extract_all_paths(modulemap_file_path)
48
+ storage.store_modulemap_headers(node, header_file_paths)
49
+ header_count += header_file_paths.length
50
+ end
51
+
52
+ debug("found #{header_count} header(s)")
33
53
  end
34
54
 
35
55
  private
@@ -42,6 +62,10 @@ module XcodeArchiveCache
42
62
  #
43
63
  attr_reader :build_settings_interpolator
44
64
 
65
+ # @return [XcodeArchiveCache::Modulemap::HeaderPathExtractor]
66
+ #
67
+ attr_reader :modulemap_header_path_extractor
68
+
45
69
  # @param [Xcodeproj::Project::Object::PBXBuildFile] build_file
46
70
  #
47
71
  # @return [String]
@@ -14,13 +14,14 @@ module XcodeArchiveCache
14
14
  @dependency_remover = DependencyRemover.new
15
15
  @build_flags_changer = BuildFlagsChanger.new
16
16
  @pods_fixer = PodsScriptFixer.new
17
+ @modulemap_fixer = XcodeArchiveCache::Modulemap::HeaderPathFixer.new(storage)
17
18
  @framework_embedder = FrameworkEmbedder.new
18
19
  end
19
20
 
20
21
  # @param [XcodeArchiveCache::BuildGraph::Graph] graph
21
22
  #
22
23
  def perform_internal_injection(graph)
23
- inject_unpacked(graph.nodes)
24
+ inject_unpacked_and_rebuilt(graph.nodes)
24
25
  add_header_paths(graph.nodes)
25
26
  save_graph_projects(graph)
26
27
  end
@@ -34,9 +35,15 @@ module XcodeArchiveCache
34
35
  return
35
36
  end
36
37
 
38
+ no_rebuild_performed = root_node.state == :unpacked
39
+
37
40
  graph.nodes.each do |node|
38
- headers_mover.prepare_headers_for_injection(node)
39
- add_as_prebuilt_dependency(node, target, node.is_root)
41
+ if no_rebuild_performed || node.state == :rebuilt_and_cached
42
+ headers_mover.prepare_headers_for_injection(node)
43
+ modulemap_fixer.fix_modulemap(node)
44
+ end
45
+
46
+ add_as_prebuilt_dependency(node, target)
40
47
  remove_native_target_from_project(node)
41
48
  end
42
49
 
@@ -51,8 +58,8 @@ module XcodeArchiveCache
51
58
  pods_fixer.fix_embed_frameworks_script(target, graph, storage.container_dir_path)
52
59
  pods_fixer.fix_copy_resources_script(target, graph, storage.container_dir_path)
53
60
  else
54
- framework_nodes = graph.nodes.select {|node| node.has_framework_product?}
55
- framework_file_paths = framework_nodes.map {|node| File.join(storage.get_storage_path(node), node.product_file_name)}
61
+ framework_nodes = graph.nodes.select { |node| node.has_framework_product? }
62
+ framework_file_paths = framework_nodes.map { |node| File.join(storage.get_storage_path(node), node.product_file_name) }
56
63
  framework_embedder.embed(framework_file_paths, target)
57
64
  end
58
65
 
@@ -86,16 +93,26 @@ module XcodeArchiveCache
86
93
  #
87
94
  attr_reader :pods_fixer
88
95
 
96
+ # @return [ModulemapFixer]
97
+ #
98
+ attr_reader :modulemap_fixer
99
+
89
100
  # @return [FrameworkEmbedder]
90
101
  #
91
102
  attr_reader :framework_embedder
92
103
 
93
104
  # @param [Array<XcodeArchiveCache::BuildGraph::Node>] nodes
94
105
  #
95
- def inject_unpacked(nodes)
96
- cached_nodes = nodes.select {|node| node.state == :unpacked}
106
+ def inject_unpacked_and_rebuilt(nodes)
107
+ cached_nodes = nodes.select { |node| node.state == :unpacked }
97
108
  cached_nodes.each do |node|
98
109
  headers_mover.prepare_headers_for_injection(node)
110
+ modulemap_fixer.fix_modulemap(node)
111
+ add_as_prebuilt_to_dependents(node)
112
+ end
113
+
114
+ built_nodes = nodes.select { |node| node.state == :rebuilt_and_cached }
115
+ built_nodes.each do |node|
99
116
  add_as_prebuilt_to_dependents(node)
100
117
  end
101
118
  end
@@ -104,10 +121,11 @@ module XcodeArchiveCache
104
121
  #
105
122
  def add_header_paths(nodes)
106
123
  header_storage_paths = storage.get_all_headers_storage_paths
124
+ return if header_storage_paths.length == 0
107
125
 
108
126
  nodes
109
127
  .select(&:waiting_for_rebuild)
110
- .each {|node| add_header_paths_to_target(node.native_target, header_storage_paths)}
128
+ .each { |node| add_header_paths_to_target(node.native_target, header_storage_paths) }
111
129
  end
112
130
 
113
131
  # @param [Xcodeproj::Project::Object::PBXNativeTarget] target
@@ -133,8 +151,7 @@ module XcodeArchiveCache
133
151
  .all_dependent_nodes
134
152
  .select(&:waiting_for_rebuild)
135
153
  dependent_to_rebuild.each do |dependent_node|
136
- should_link = prebuilt_node.dependent.include?(dependent_node)
137
- add_as_prebuilt_dependency(prebuilt_node, dependent_node.native_target, should_link)
154
+ add_as_prebuilt_dependency(prebuilt_node, dependent_node.native_target)
138
155
  end
139
156
 
140
157
  remove_native_target_from_project(prebuilt_node)
@@ -145,13 +162,16 @@ module XcodeArchiveCache
145
162
  def save_graph_projects(graph)
146
163
  projects = graph.nodes.map(&:native_target).map(&:project).uniq
147
164
  debug("updating #{projects.length} projects")
148
- projects.each {|project| project.save}
165
+ projects.each { |project| project.save }
149
166
  end
150
167
 
151
168
  # @param [XcodeArchiveCache::BuildGraph::Node] prebuilt_node
152
169
  # @param [Xcodeproj::Project::Object::PBXNativeTarget] dependent_target
153
170
  #
154
- def add_as_prebuilt_dependency(prebuilt_node, dependent_target, should_link)
171
+ def add_as_prebuilt_dependency(prebuilt_node, dependent_target)
172
+ target_identifier = get_target_identifier(dependent_target)
173
+ return if prebuilt_node.targets_injected_to.include?(target_identifier)
174
+
155
175
  debug("adding #{prebuilt_node.name} as prebuilt to #{dependent_target.display_name}")
156
176
 
157
177
  unless prebuilt_node.has_acceptable_product?
@@ -161,9 +181,11 @@ module XcodeArchiveCache
161
181
  if prebuilt_node.has_framework_product?
162
182
  add_as_prebuilt_framework(prebuilt_node, dependent_target)
163
183
  elsif prebuilt_node.has_static_library_product?
164
- add_as_prebuilt_static_lib(prebuilt_node, dependent_target, should_link)
184
+ add_as_prebuilt_static_lib(prebuilt_node, dependent_target)
165
185
  end
166
186
 
187
+ prebuilt_node.targets_injected_to.push(target_identifier)
188
+
167
189
  debug("done with #{prebuilt_node.name} for #{dependent_target.display_name}")
168
190
  end
169
191
 
@@ -174,22 +196,41 @@ module XcodeArchiveCache
174
196
  build_configuration = find_build_configuration(dependent_target)
175
197
 
176
198
  artifact_location = storage.get_storage_path(prebuilt_node)
177
- build_flags_changer.add_framework_search_path(build_configuration, artifact_location)
199
+ build_flags_changer.replace_or_add_framework_search_path(build_configuration, prebuilt_node.native_target.name, artifact_location)
178
200
  build_flags_changer.add_framework_headers_iquote(build_configuration, artifact_location, prebuilt_node)
179
201
 
202
+ if dependency_remover.is_linked(prebuilt_node, dependent_target)
203
+ build_flags_changer.add_framework_linker_flag(build_configuration, prebuilt_node)
204
+ end
205
+
180
206
  dependency_remover.remove_dependency(prebuilt_node, dependent_target)
181
207
  end
182
208
 
183
209
  # @param [XcodeArchiveCache::BuildGraph::Node] prebuilt_node
184
210
  # @param [Xcodeproj::Project::Object::PBXNativeTarget] dependent_target
185
- # @param [Boolean] should_link
186
211
  #
187
- def add_as_prebuilt_static_lib(prebuilt_node, dependent_target, should_link)
212
+ def add_as_prebuilt_static_lib(prebuilt_node, dependent_target)
188
213
  build_configuration = find_build_configuration(dependent_target)
189
214
 
190
- if should_link
191
- artifact_location = storage.get_storage_path(prebuilt_node)
192
- build_flags_changer.add_library_search_path(build_configuration, artifact_location)
215
+ injected_modulemap_file_path = storage.get_modulemap_path(prebuilt_node)
216
+ if injected_modulemap_file_path
217
+ modulemap_file_names = [prebuilt_node.resulting_modulemap_file_name]
218
+ build_flags_changer.fix_module_map_path(build_configuration, modulemap_file_names, injected_modulemap_file_path)
219
+
220
+ original_modulemap_path = prebuilt_node.original_modulemap_file_path
221
+ add_header_paths_to_target(dependent_target, [File.dirname(original_modulemap_path)])
222
+ end
223
+
224
+ artifact_location = storage.get_storage_path(prebuilt_node)
225
+ build_flags_changer.replace_or_add_library_search_path(build_configuration, prebuilt_node.native_target.name, artifact_location)
226
+ build_flags_changer.add_swift_include_path(build_configuration, artifact_location)
227
+
228
+ if dependency_remover.is_linked(prebuilt_node, dependent_target)
229
+ if dependent_target.product_type == Xcodeproj::Constants::PRODUCT_TYPE_UTI[:static_library]
230
+ build_flags_changer.add_static_lib_libtool_flag(build_configuration, prebuilt_node)
231
+ else
232
+ build_flags_changer.add_static_lib_linker_flag(build_configuration, prebuilt_node)
233
+ end
193
234
  end
194
235
 
195
236
  dependency_remover.remove_dependency(prebuilt_node, dependent_target)
@@ -198,7 +239,7 @@ module XcodeArchiveCache
198
239
  # @param [Xcodeproj::Project::Object::PBXNativeTarget] target
199
240
  #
200
241
  def find_build_configuration(target)
201
- build_configuration = target.build_configurations.select {|configuration| configuration.name == configuration_name}.first
242
+ build_configuration = target.build_configurations.select { |configuration| configuration.name == configuration_name }.first
202
243
  unless build_configuration
203
244
  raise Informative, "#{configuration_name} build configuration not found on target #{node.name}"
204
245
  end
@@ -223,6 +264,14 @@ module XcodeArchiveCache
223
264
  debug("deleting #{node.name} target")
224
265
  node.native_target.project.targets.delete(node.native_target)
225
266
  end
267
+
268
+ # @param [Xcodeproj::Project::Object::PBXNativeTarget] target
269
+ #
270
+ # @return [String]
271
+ #
272
+ def get_target_identifier(target)
273
+ target.uuid + target.project.path.realpath.to_s
274
+ end
226
275
  end
227
276
  end
228
277
  end