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

Sign up to get free protection for your applications and to get access to all the features.
@@ -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