pod-builder 2.0.0.beta.26 → 2.0.0.beta.27

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.
@@ -7,7 +7,7 @@ module PodBuilder
7
7
  PRE_INSTALL_ACTIONS = ["Pod::Installer::Xcode::TargetValidator.send(:define_method, :verify_no_duplicate_framework_and_library_names) {}"].freeze
8
8
  private_constant :PRE_INSTALL_ACTIONS
9
9
 
10
- def self.from_podfile_items(items, analyzer, build_configuration)
10
+ def self.from_podfile_items(items, analyzer, build_configuration, install_using_frameworks)
11
11
  raise "\n\nno items".red unless items.count > 0
12
12
 
13
13
  sources = analyzer.sources
@@ -17,9 +17,7 @@ module PodBuilder
17
17
 
18
18
  platform = analyzer.instance_variable_get("@result").targets.first.platform
19
19
 
20
- install_using_frameworks = install_using_frameworks(analyzer)
21
-
22
- podfile.sub!("%%%use_frameworks%%%", install_using_frameworks ? "use_frameworks!" : "")
20
+ podfile.sub!("%%%use_frameworks%%%", install_using_frameworks ? "use_frameworks!" : "use_modular_headers!")
23
21
  podfile.sub!("%%%uses_frameworks%%%", install_using_frameworks ? "true" : "false")
24
22
 
25
23
  podfile.sub!("%%%platform_name%%%", platform.name.to_s)
@@ -386,6 +384,22 @@ module PodBuilder
386
384
  resolved_names.uniq
387
385
  end
388
386
 
387
+ def self.install_using_frameworks(analyzer)
388
+ target_settings = analyzer.podfile.target_definition_list.map(&:uses_frameworks?).uniq
389
+ if target_settings.count == 1
390
+ if target_settings.first == false && ENV['DEBUGGING'].nil?
391
+ raise "\n\nOnly framework packaging currently supported. Please add 'use_frameworks!' at Podfile root level (not nested in targets)".red
392
+ end
393
+ return target_settings.first
394
+ elsif target_settings.count > 1
395
+ raise "\n\n'use_frameworks!' should be declared only once at Podfile root level (not nested in targets)".red
396
+ else
397
+ raise "\n\nFailed detecting use_frameworks!"
398
+ end
399
+
400
+ return true
401
+ end
402
+
389
403
  private
390
404
 
391
405
  def self.podfile_path_transform(path)
@@ -678,21 +692,5 @@ module PodBuilder
678
692
 
679
693
  return podfile_content
680
694
  end
681
-
682
- def self.install_using_frameworks(analyzer)
683
- target_settings = analyzer.podfile.target_definition_list.map(&:uses_frameworks?).uniq
684
- if target_settings.count == 1
685
- if target_settings.first == false && ENV['DEBUGGING'].nil?
686
- raise "\n\nOnly framework packaging currently supported. Please add 'use_frameworks!' at Podfile root level (not nested in targets)".red
687
- end
688
- return target_settings.first
689
- elsif target_settings.count > 1
690
- raise "\n\n'use_frameworks!' should be declared only once at Podfile root level (not nested in targets)".red
691
- else
692
- raise "\n\nFailed detecting use_frameworks!"
693
- end
694
-
695
- return true
696
- end
697
695
  end
698
696
  end
@@ -3,7 +3,7 @@ require 'cocoapods/podfile.rb'
3
3
  module Pod
4
4
  class Podfile
5
5
  class TargetDefinition
6
- def pb_to_s(all_buildable_items, indent_level = 0)
6
+ def pb_to_s(all_buildable_items, indent_level = 0, parent_pods = [])
7
7
  indentation = " " * indent_level
8
8
  target_s = "#{indentation}target '#{self.name}' do\n"
9
9
 
@@ -15,7 +15,8 @@ module Pod
15
15
  prebuild_entries = []
16
16
  self.dependencies.each do |dep|
17
17
  if podfile_item = all_buildable_items.detect { |t| t.name == dep.name }
18
- if File.exist?(podfile_item.prebuilt_podspec_path) && !podfile_item.is_prebuilt
18
+ is_prebuilt = all_buildable_items.select { |t| t.root_name == dep.root_name}.all?(&:is_prebuilt)
19
+ if File.exist?(podfile_item.prebuilt_podspec_path) && !is_prebuilt
19
20
  prebuild_entries.push(podfile_item)
20
21
  else
21
22
  pod_entries.push(podfile_item)
@@ -34,7 +35,8 @@ module Pod
34
35
  non_explicit_dependencies.each do |dep|
35
36
  dep_item = all_buildable_items.detect { |x| x.name == dep.name }
36
37
 
37
- if File.exist?(dep_item.prebuilt_podspec_path) && !dep_item.is_prebuilt
38
+ is_prebuilt = all_buildable_items.select { |t| t.root_name == dep.root_name}.all?(&:is_prebuilt)
39
+ if File.exist?(dep_item.prebuilt_podspec_path) && !is_prebuilt
38
40
  prebuild_entries.push(dep_item)
39
41
  else
40
42
  pod_entries.push(dep_item)
@@ -47,6 +49,10 @@ module Pod
47
49
 
48
50
  prebuild_entries = prebuild_entries.uniq.sort_by { |t| t.name }
49
51
  pod_entries = pod_entries.uniq.sort_by { |t| t.name }
52
+
53
+ # Don't include inherited pods
54
+ prebuild_entries.reject! { |t| parent_pods.include?(t) }
55
+ pod_entries.reject! { |t| parent_pods.include?(t) }
50
56
 
51
57
  prebuild_entries.each do |pod|
52
58
  target_s += "#{child_indentation}#{pod.prebuilt_entry(false, false)}\n"
@@ -57,7 +63,7 @@ module Pod
57
63
 
58
64
  if self.children.count > 0
59
65
  target_s += "\n"
60
- target_s += @children.map { |t| t.pb_to_s(all_buildable_items, indent_level + 1) }.join("\n\n")
66
+ target_s += @children.map { |t| t.pb_to_s(all_buildable_items, indent_level + 1, parent_pods + pod_entries + prebuild_entries) }.join("\n\n")
61
67
  end
62
68
 
63
69
  target_s += "#{indentation}end\n"
@@ -79,6 +79,10 @@ module PodBuilder
79
79
  #
80
80
  attr_accessor :build_configuration
81
81
 
82
+ # @return [Array<String>] When building static frameworks we sometimes have to remove module maps from Other C flags to make compilation succeed
83
+ #
84
+ attr_accessor :remove_module_maps
85
+
82
86
  # @return [String] The pod's vendored frameworks
83
87
  #
84
88
  attr_accessor :vendored_frameworks
@@ -180,7 +184,11 @@ module PodBuilder
180
184
 
181
185
  @default_subspecs = extract_array(spec, "default_subspecs")
182
186
  if default_subspec = spec.attributes_hash["default_subspec"]
183
- @default_subspecs.push(default_subspec)
187
+ @default_subspecs.push(default_subspec)
188
+ end
189
+
190
+ if @name == @root_name && @default_subspecs.empty?
191
+ @default_subspecs += all_specs.select { |t| t.name.include?("/") && t.name.split("/").first == @root_name }.map { |t| t.name.split("/").last }
184
192
  end
185
193
 
186
194
  @dependency_names = spec.attributes_hash.fetch("dependencies", {}).keys + default_subspecs.map { |t| "#{@root_name}/#{t}" }
@@ -194,11 +202,18 @@ module PodBuilder
194
202
  @is_static = spec.root.attributes_hash["static_framework"] || false
195
203
  @xcconfig = spec.root.attributes_hash["xcconfig"] || {}
196
204
 
197
- @source_files = source_files_from(spec)
205
+ default_subspecs_specs ||= begin
206
+ subspecs = all_specs.select { |t| t.name.split("/").first == @root_name }
207
+ subspecs.select { |t| @default_subspecs.include?(t.name.split("/").last) }
208
+ end
209
+ root_spec = all_specs.detect { |t| t.name == @root_name } || spec
210
+ @source_files = source_files_from([spec, root_spec] + default_subspecs_specs)
198
211
 
199
212
  @build_configuration = spec.root.attributes_hash.dig("pod_target_xcconfig", "prebuild_configuration") || "release"
200
213
  @build_configuration.downcase!
201
214
 
215
+ @remove_module_maps = spec.root.attributes_hash["remove_module_maps"] || []
216
+
202
217
  default_license = "MIT"
203
218
  @license = spec.root.attributes_hash.fetch("license", {"type"=>"#{default_license}"})["type"] || default_license
204
219
  @summary = spec.root.attributes_hash.fetch("summary", "A summary for #{@name}")
@@ -280,14 +295,16 @@ module PodBuilder
280
295
 
281
296
  root_names = deps.map(&:root_name).uniq
282
297
 
283
- # We need to build all other common subspecs to properly build the item
284
- # Ex.
285
- # PodA depends on DepA/subspec1
286
- # PodB depends on DepA/subspec2
287
- #
288
- # When building PodA we need to build both DepA subspecs because they might
289
- # contain different code
290
- deps += available_pods.select { |t| root_names.include?(t.root_name) }
298
+ unless Configuration.subspecs_to_split.include?(name)
299
+ # We need to build all other common subspecs to properly build the item
300
+ # Ex.
301
+ # PodA depends on DepA/subspec1
302
+ # PodB depends on DepA/subspec2
303
+ #
304
+ # When building PodA we need to build both DepA subspecs because they might
305
+ # contain different code
306
+ deps += available_pods.select { |t| root_names.include?(t.root_name) && t.root_name != t.name && !Configuration.subspecs_to_split.include?(t.name) }
307
+ end
291
308
 
292
309
  deps.uniq!
293
310
 
@@ -390,7 +407,7 @@ module PodBuilder
390
407
 
391
408
  def prebuilt_rel_path
392
409
  if is_subspec && Configuration.subspecs_to_split.include?(name)
393
- return "#{name}/#{module_name}.framework"
410
+ return "Subspecs/#{podspec_name}/#{module_name}.framework"
394
411
  else
395
412
  return "#{module_name}.framework"
396
413
  end
@@ -408,11 +425,7 @@ module PodBuilder
408
425
  def prebuilt_entry(include_pb_entry = true, absolute_path = false)
409
426
  podspec_dirname = File.dirname(prebuilt_podspec_path(absolute_path = absolute_path))
410
427
 
411
- if Configuration.subspecs_to_split.include?(name)
412
- entry = "pod '#{podspec_name}', :path => '#{podspec_dirname}'"
413
- else
414
- entry = "pod '#{name}', :path => '#{podspec_dirname}'"
415
- end
428
+ entry = "pod '#{name}', :path => '#{podspec_dirname}'"
416
429
 
417
430
  if include_pb_entry && !is_prebuilt
418
431
  entry += prebuilt_marker()
@@ -518,28 +531,9 @@ module PodBuilder
518
531
  end
519
532
  end
520
533
 
521
- def source_files_from(spec)
522
- files = spec.root.attributes_hash.fetch("source_files", [])
523
- root_source_files = source_files_from_string(files)
524
-
525
- files = spec.attributes_hash.fetch("source_files", [])
526
- source_files = source_files_from_string(files)
527
-
528
- subspec_source_files = []
529
- if spec.name == spec.root.name
530
- default_podspecs = spec.attributes_hash.fetch("default_subspecs", [])
531
- if default_podspecs.is_a? String
532
- default_podspecs = [default_podspecs]
533
- end
534
- default_podspecs.each do |subspec_name|
535
- if subspec = spec.subspecs.detect { |x| x.name == "#{spec.root.name}/#{subspec_name}" }
536
- files = subspec.attributes_hash.fetch("source_files", [])
537
- subspec_source_files += source_files_from_string(files)
538
- end
539
- end
540
- end
541
-
542
- return source_files + root_source_files + subspec_source_files
534
+ def source_files_from(specs)
535
+ files = specs.map { |t| t.attributes_hash.fetch("source_files", []) }.flatten
536
+ return source_files_from_string(files).uniq
543
537
  end
544
538
  end
545
539
  end
@@ -3,7 +3,7 @@
3
3
 
4
4
  module PodBuilder
5
5
  class Podspec
6
- def self.generate(all_buildable_items, analyzer)
6
+ def self.generate(all_buildable_items, analyzer, install_using_frameworks)
7
7
  unless all_buildable_items.count > 0
8
8
  return
9
9
  end
@@ -11,12 +11,12 @@ module PodBuilder
11
11
  puts "Generating PodBuilder's local podspec".yellow
12
12
 
13
13
  platform = analyzer.instance_variable_get("@result").targets.first.platform
14
- generate_podspec_from(all_buildable_items, platform)
14
+ generate_podspec_from(all_buildable_items, platform, install_using_frameworks)
15
15
  end
16
16
 
17
17
  private
18
18
 
19
- def self.generate_spec_keys_for(item, name, all_buildable_items)
19
+ def self.generate_spec_keys_for(item, name, all_buildable_items, install_using_frameworks)
20
20
  podspec = ""
21
21
  valid = false
22
22
 
@@ -24,46 +24,84 @@ module PodBuilder
24
24
  indentation = " " * slash_count
25
25
  spec_var = "p#{slash_count}"
26
26
 
27
- if item.name == name
28
- if_exists = lambda { |t| File.exist?(PodBuilder::prebuiltpath("#{item.root_name}/#{t}") || "") }
27
+ subspec_prefix = Configuration.subspecs_to_split.include?(item.name) ? "Subspecs/#{item.podspec_name}/" : ""
28
+
29
+ if spec_var == "p1" && item.default_subspecs.count > 0
30
+ podspec += "#{indentation}#{spec_var}.default_subspecs = '#{item.default_subspecs.join("', '")}'\n"
31
+ end
32
+
33
+ if subspec_prefix.length > 0 && Dir["#{PodBuilder::prebuiltpath("#{item.root_name}/#{subspec_prefix}")}/*"].empty?
34
+ podspec += "#{indentation}#{spec_var}.source_files = '*.splittedspec'\n"
35
+ elsif item.name == name
36
+ if_exists = lambda { |t| File.exist?(PodBuilder::prebuiltpath("#{item.root_name}/#{subspec_prefix}#{t}") || "") }
37
+
38
+ vendored_frameworks = item.vendored_frameworks
39
+ if item.default_subspecs.count == 0 && install_using_frameworks
40
+ vendored_frameworks += ["#{item.module_name}.framework"]
41
+ end
29
42
 
30
- vendored_frameworks = item.vendored_frameworks + ["#{item.module_name}.framework"]
31
43
  existing_vendored_frameworks = vendored_frameworks.select(&if_exists)
32
44
  existing_vendored_frameworks_basename = vendored_frameworks.map { |t| File.basename(t) }.select(&if_exists)
33
45
  vendored_frameworks = (existing_vendored_frameworks + existing_vendored_frameworks_basename).uniq
34
46
 
35
47
  vendored_libraries = item.vendored_libraries
36
- existing_vendored_libraries = vendored_libraries.map { |t| "#{item.module_name}/#{t}" }.select(&if_exists)
37
- existing_vendored_libraries_basename = vendored_libraries.map { |t| File.basename(t) }.select(&if_exists)
38
- vendored_libraries = (existing_vendored_libraries + existing_vendored_libraries_basename).uniq
39
-
40
- # .a are static libraries and should not be included again in the podspec to prevent duplicated symbols (in the app and in the prebuilt framework)
41
- vendored_libraries.reject! { |t| t.end_with?(".a") }
42
-
43
- frameworks = all_buildable_items.select { |t| vendored_frameworks.include?("#{t.module_name}.framework") }.uniq
44
- static_frameworks = frameworks.select { |x| x.is_static }
45
-
46
- resources = static_frameworks.map { |x| x.vendored_framework_path.nil? ? nil : "#{x.vendored_framework_path}/*.{nib,bundle,xcasset,strings,png,jpg,tif,tiff,otf,ttf,ttc,plist,json,caf,wav,p12,momd}" }.compact.flatten.uniq
47
- exclude_files = static_frameworks.map { |x| x.vendored_framework_path.nil? ? nil : "#{x.vendored_framework_path}/Info.plist" }.compact.flatten.uniq
48
+ if install_using_frameworks
49
+ existing_vendored_libraries = vendored_libraries.map { |t| "#{item.module_name}/#{t}" }.select(&if_exists)
50
+ existing_vendored_libraries_basename = vendored_libraries.map { |t| File.basename(t) }.select(&if_exists)
51
+ vendored_libraries = (existing_vendored_libraries + existing_vendored_libraries_basename).uniq
52
+
53
+ # .a are static libraries and should not be included again in the podspec to prevent duplicated symbols (in the app and in the prebuilt framework)
54
+ vendored_libraries.reject! { |t| t.end_with?(".a") }
55
+
56
+ frameworks = all_buildable_items.select { |t| vendored_frameworks.include?("#{t.module_name}.framework") }.uniq
57
+ static_frameworks = frameworks.select { |x| x.is_static }
58
+
59
+ resources = static_frameworks.map { |x| x.vendored_framework_path.nil? ? nil : "#{x.vendored_framework_path}/*.{nib,bundle,xcasset,strings,png,jpg,tif,tiff,otf,ttf,ttc,plist,json,caf,wav,p12,momd}" }.compact.flatten.uniq
60
+
61
+ exclude_files = static_frameworks.map { |x| x.vendored_framework_path.nil? ? nil : "#{x.vendored_framework_path}/Info.plist" }.compact.flatten.uniq
62
+ public_headers = []
63
+ else
64
+ public_headers = Dir.glob(PodBuilder::prebuiltpath("#{item.root_name}/#{item.root_name}/Headers/**/*.h"))
65
+ vendored_libraries += ["#{item.root_name}/lib#{item.root_name}.a"]
66
+ vendored_libraries.map! { |t| "#{item.root_name}/#{t}" }.select(&if_exists)
67
+
68
+ resources = ["#{item.root_name}/*.{nib,bundle,xcasset,strings,png,jpg,tif,tiff,otf,ttf,ttc,plist,json,caf,wav,p12,momd}"]
69
+
70
+ exclude_files = ["*.modulemap"]
71
+ unless item.swift_version.nil?
72
+ exclude_files += ["Swift Compatibility Header/*", "*.swiftmodule"]
73
+ end
74
+ exclude_files.map! { |t| "#{item.root_name}/#{t}" }
75
+ end
76
+
77
+ entries = lambda { |spec_key, spec_value|
78
+ key = "#{indentation}#{spec_var}.#{spec_key}"
79
+ joined_values = spec_value.map { |t| "#{subspec_prefix}#{t}" }.uniq.sort.join("', '")
80
+ "#{key} = '#{joined_values}'\n"
81
+ }
48
82
 
49
83
  if vendored_frameworks.count > 0
50
- podspec += "#{indentation}#{spec_var}.vendored_frameworks = '#{vendored_frameworks.uniq.sort.join("','")}'\n"
84
+ podspec += entries.call("vendored_frameworks", vendored_frameworks)
51
85
  end
52
86
  if vendored_libraries.count > 0
53
- podspec += "#{indentation}#{spec_var}.vendored_libraries = '#{vendored_libraries.uniq.sort.join("','")}'\n"
87
+ podspec += entries.call("vendored_libraries", vendored_libraries)
54
88
  end
55
89
  if item.frameworks.count > 0
56
- podspec += "#{indentation}#{spec_var}.frameworks = '#{item.frameworks.uniq.sort.join("', '")}'\n"
90
+ podspec += entries.call("frameworks", item.frameworks)
57
91
  end
58
92
  if item.libraries.count > 0
59
- podspec += "#{indentation}#{spec_var}.libraries = '#{item.libraries.uniq.sort.join("', '")}'\n"
93
+ podspec += entries.call("libraries", item.libraries)
60
94
  end
61
95
  if resources.count > 0
62
- podspec += "#{indentation}#{spec_var}.resources = '#{resources.uniq.sort.join("', '")}'\n"
96
+ podspec += entries.call("resources", resources)
63
97
  end
64
98
  if exclude_files.count > 0
65
- podspec += "#{indentation}#{spec_var}.exclude_files = '#{exclude_files.uniq.sort.join("', '")}'\n"
99
+ podspec += entries.call("exclude_files", exclude_files)
100
+ end
101
+ if public_headers.count > 0
102
+ podspec += "#{indentation}#{spec_var}.public_header_files = '#{item.root_name}/Headers/**/*.h'\n"
66
103
  end
104
+
67
105
  if item.xcconfig.keys.count > 0
68
106
  xcconfig = Hash.new
69
107
  item.xcconfig.each do |k, v|
@@ -88,6 +126,21 @@ module PodBuilder
88
126
  podspec += "#{indentation}#{spec_var}.xcconfig = #{xcconfig.to_s}\n"
89
127
  end
90
128
  end
129
+ if !install_using_frameworks && spec_var == "p1"
130
+ module_path_files = Dir.glob(PodBuilder.prebuiltpath("#{item.root_name}/**/#{item.root_name}.modulemap"))
131
+ raise "\n\nToo many module maps found for #{item.root_name}".red if module_path_files.count > 1
132
+ if module_path_file = module_path_files.first
133
+ rel_path = Pathname.new(PodBuilder::prebuiltpath).relative_path_from(Pathname.new(PodBuilder::project_path("Pods"))).to_s
134
+ prebuilt_root_var = "#{item.root_name.upcase.gsub("-", "_")}_PREBUILT_ROOT"
135
+ module_map_rel = module_path_file.gsub(PodBuilder::prebuiltpath("#{item.root_name}/#{item.root_name}/"), "")
136
+ static_cfg = { prebuilt_root_var => "$(PODS_ROOT)/#{rel_path}",
137
+ "SWIFT_INCLUDE_PATHS" => "$(inherited) \"$(#{prebuilt_root_var})/#{item.root_name}/#{item.root_name}\"",
138
+ "OTHER_CFLAGS" => "$(inherited) -fmodule-map-file=\"$(#{prebuilt_root_var})/#{item.root_name}/#{item.root_name}/#{module_map_rel}\"",
139
+ "OTHER_SWIFT_FLAGS" => "$(inherited) -Xcc -fmodule-map-file=\"$(#{prebuilt_root_var})/#{item.root_name}/#{item.root_name}/#{module_map_rel}\""
140
+ }
141
+ podspec += "#{indentation}#{spec_var}.xcconfig = #{static_cfg.to_s}\n"
142
+ end
143
+ end
91
144
 
92
145
  deps = item.dependency_names.sort
93
146
  if name == item.root_name
@@ -103,7 +156,7 @@ module PodBuilder
103
156
  end
104
157
  end
105
158
 
106
- valid = valid || vendored_frameworks.count > 0
159
+ valid = valid || (install_using_frameworks ? vendored_frameworks.count > 0 : vendored_libraries.count > 0)
107
160
  end
108
161
 
109
162
  subspec_names = all_buildable_items.map(&:name).select { |t| t.start_with?("#{name}/") }
@@ -117,7 +170,7 @@ module PodBuilder
117
170
  podspec += "\n"
118
171
  end
119
172
 
120
- subspec_keys, subspec_valid = generate_spec_keys_for(subspec_item, subspec, all_buildable_items)
173
+ subspec_keys, subspec_valid = generate_spec_keys_for(subspec_item, subspec, all_buildable_items, install_using_frameworks)
121
174
  valid = valid || subspec_valid
122
175
 
123
176
  if subspec_keys.length > 0
@@ -127,10 +180,10 @@ module PodBuilder
127
180
  end
128
181
  end
129
182
 
130
- return podspec, valid
183
+ return podspec, (valid || Configuration.subspecs_to_split.include?(item.name))
131
184
  end
132
185
 
133
- def self.generate_podspec_from(all_buildable_items, platform)
186
+ def self.generate_podspec_from(all_buildable_items, platform, install_using_frameworks)
134
187
  prebuilt_podspec_path = all_buildable_items.map(&:prebuilt_podspec_path)
135
188
  prebuilt_podspec_path.each do |path|
136
189
  if File.exist?(path)
@@ -165,7 +218,7 @@ module PodBuilder
165
218
  podspec += " p1.#{platform.safe_string_name.downcase}.deployment_target = '#{platform.deployment_target.version}'\n"
166
219
  podspec += "\n"
167
220
 
168
- main_keys, valid = generate_spec_keys_for(item, item.root_name, all_buildable_items)
221
+ main_keys, valid = generate_spec_keys_for(item, item.root_name, all_buildable_items, install_using_frameworks)
169
222
  if !valid
170
223
  next
171
224
  end
@@ -16,9 +16,9 @@ module PodBuilder
16
16
  deployment_target = target.platform_deployment_target
17
17
  target_label = target.cocoapods_target_label
18
18
 
19
- xcodebuild(sandbox, target_label, device, deployment_target, configuration, deterministic_build, [])
19
+ xcodebuild(sandbox, target_label, device, deployment_target, configuration, deterministic_build, [], {})
20
20
  excluded_archs = build_for_apple_silicon ? [] : ["arm64"]
21
- xcodebuild(sandbox, target_label, simulator, deployment_target, configuration, deterministic_build, excluded_archs)
21
+ xcodebuild(sandbox, target_label, simulator, deployment_target, configuration, deterministic_build, excluded_archs, {})
22
22
 
23
23
  spec_names = target.specs.map { |spec| [spec.root.name, spec.root.module_name] }.uniq
24
24
  spec_names.each do |root_name, module_name|
@@ -48,29 +48,17 @@ module PodBuilder
48
48
 
49
49
  raise "Lipo failed on #{device_lib}" unless system("xcrun lipo -create -output #{device_lib} #{device_lib} #{simulator_lib}")
50
50
 
51
- # Merge swift headers as per Xcode 10.2 release notes
52
- if File.exist?(device_swift_header_path) && File.exist?(simulator_swift_header_path)
53
- device_content = File.read(device_swift_header_path)
54
- simulator_content = File.read(simulator_swift_header_path)
55
- merged_content = %{
56
- #if TARGET_OS_SIMULATOR
57
- #{simulator_content}
58
- #else
59
- #{device_content}
60
- #endif
61
- }
62
- File.write(device_swift_header_path, merged_content)
63
- end
51
+ merge_header_into(device_swift_header_path, simulator_swift_header_path)
64
52
 
65
53
  # Merge device framework into simulator framework (so that e.g swift Module folder is merged)
66
54
  # letting device framework files overwrite simulator ones
67
55
  FileUtils.cp_r(File.join(device_framework_lib, "."), simulator_framework_lib)
68
56
  source_lib = File.dirname(simulator_framework_lib)
69
57
 
70
- FileUtils.cp_r(source_lib, build_dir)
58
+ FileUtils.mv(device_dsym, dsym_device_folder) if File.exist?(device_dsym)
59
+ FileUtils.mv(simulator_dsym, dsym_simulator_folder) if File.exist?(simulator_dsym)
71
60
 
72
- FileUtils.cp_r(device_dsym, dsym_device_folder) if File.exist?(device_dsym)
73
- FileUtils.cp_r(simulator_dsym, dsym_simulator_folder) if File.exist?(simulator_dsym)
61
+ FileUtils.mv(source_lib, build_dir)
74
62
 
75
63
  # Remove frameworks leaving dSYMs
76
64
  FileUtils.rm_rf(device_framework_lib)
@@ -78,173 +66,130 @@ module PodBuilder
78
66
  end
79
67
  end
80
68
 
81
- def self.build_for_iosish_platform_lib(sandbox, build_dir, target, device, simulator, configuration, deterministic_build, build_for_apple_silicon)
69
+ def self.build_for_iosish_platform_lib(sandbox, build_dir, target, device, simulator, configuration, deterministic_build, build_for_apple_silicon, prebuilt_root_paths)
82
70
  raise "\n\nApple silicon hardware still unsupported since it requires to migrate to xcframeworks".red if build_for_apple_silicon
83
-
84
- device_headers_path = File.join(build_dir, "Headers", device)
85
- simulator_headers_path = File.join(build_dir, "Headers", simulator)
86
- FileUtils.mkdir_p(device_headers_path)
87
- FileUtils.mkdir_p(simulator_headers_path)
88
71
 
89
72
  deployment_target = target.platform_deployment_target
90
73
  target_label = target.cocoapods_target_label
91
74
 
92
75
  spec_names = target.specs.map { |spec| [spec.root.name, spec.root.module_name] }.uniq
93
76
 
94
- xcodebuild(sandbox, target_label, device, deployment_target, configuration, deterministic_build, [])
95
- spec_names.each do |root_name, module_name|
96
- headers_path = "#{sandbox.headers_root.to_s}/Public/#{root_name}"
97
- dest_path = "#{device_headers_path}/#{root_name}"
98
- FileUtils.mkdir_p(dest_path)
99
-
100
- Dir.glob("#{headers_path}/*") do |path|
101
- real_path = Pathname.new(path).realpath
102
- FileUtils.cp_r(real_path, dest_path)
103
- end
104
- end
105
-
77
+ xcodebuild(sandbox, target_label, device, deployment_target, configuration, deterministic_build, [], prebuilt_root_paths)
106
78
  excluded_archs = build_for_apple_silicon ? [] : ["arm64"]
107
- xcodebuild(sandbox, target_label, simulator, deployment_target, configuration, deterministic_build, excluded_archs)
108
- spec_names.each do |root_name, module_name|
109
- headers_path = "#{sandbox.headers_root.to_s}/Public/#{root_name}"
110
- dest_path = "#{simulator_headers_path}/#{root_name}"
111
- FileUtils.mkdir_p(dest_path)
112
-
113
- Dir.glob("#{headers_path}/*") do |path|
114
- real_path = Pathname.new(path).realpath
115
- FileUtils.cp_r(real_path, dest_path)
116
- end
117
- end
79
+ xcodebuild(sandbox, target_label, simulator, deployment_target, configuration, deterministic_build, excluded_archs, prebuilt_root_paths)
118
80
 
119
81
  spec_names.each do |root_name, module_name|
120
82
  simulator_base = "#{build_dir}/#{configuration}-#{simulator}/#{root_name}"
121
83
  simulator_lib = "#{simulator_base}/lib#{module_name}.a"
122
84
 
123
85
  device_base = "#{build_dir}/#{configuration}-#{device}/#{root_name}"
124
- device_lib = "#{device_base}/lib#{module_name}.a"
86
+ device_lib = "#{device_base}/lib#{root_name}.a"
125
87
 
126
- next unless File.file?(device_lib) && File.file?(simulator_lib)
127
-
128
- # Starting with Xcode 12b3 the simulator binary contains an arm64 slice as well which conflict with the one in the device_lib
129
- # when creating the fat library. A naive workaround is to remove the arm64 from the simulator_lib however this is wrong because
130
- # we might actually need to have 2 separated arm64 slices, one for simulator and one for device each built with different
131
- # compile time directives (e.g #if targetEnvironment(simulator))
132
- #
133
- # For the time being we remove the arm64 slice bacause otherwise the `xcrun lipo -create -output ...` would fail.
134
- if `xcrun lipo -info #{simulator_lib}`.include?("arm64")
135
- `xcrun lipo -remove arm64 #{simulator_lib} -o #{simulator_lib}`
88
+ if File.file?(device_lib) && File.file?(simulator_lib)
89
+ # Starting with Xcode 12b3 the simulator binary contains an arm64 slice as well which conflict with the one in the device_lib
90
+ # when creating the fat library. A naive workaround is to remove the arm64 from the simulator_lib however this is wrong because
91
+ # we might actually need to have 2 separated arm64 slices, one for simulator and one for device each built with different
92
+ # compile time directives (e.g #if targetEnvironment(simulator))
93
+ #
94
+ # For the time being we remove the arm64 slice bacause otherwise the `xcrun lipo -create -output ...` would fail.
95
+ if `xcrun lipo -info #{simulator_lib}`.include?("arm64")
96
+ `xcrun lipo -remove arm64 #{simulator_lib} -o #{simulator_lib}`
97
+ end
98
+
99
+ raise "Lipo failed on #{device_lib}" unless system("xcrun lipo -create -output #{device_lib} #{device_lib} #{simulator_lib}")
136
100
  end
137
-
138
- raise "Lipo failed on #{device_lib}" unless system("xcrun lipo -create -output #{device_lib} #{device_lib} #{simulator_lib}")
139
101
 
140
- device_headers = Dir.glob("#{device_headers_path}/**/*.h")
141
- simulator_headers = Dir.glob("#{simulator_headers_path}/**/*.h")
102
+ device_headers = Dir.glob("#{device_base}/**/*.h")
103
+ simulator_headers = Dir.glob("#{simulator_base}/**/*.h")
142
104
  device_headers.each do |device_path|
143
- simulator_path = device_path.gsub(device_headers_path, simulator_headers_path)
144
- if File.exist?(simulator_path)
145
- device_content = File.read(device_path)
146
- simulator_content = File.read(simulator_path)
147
- merged_content = %{
148
- #if TARGET_OS_SIMULATOR
149
- #{simulator_content}
150
- #else
151
- #{device_content}
152
- #endif
153
- }
154
- File.write(device_path, merged_content)
155
- end
156
- end
157
- simulator_only_headers = simulator_headers - device_headers.map { |t| t.gsub(device_headers_path, simulator_headers_path) }
105
+ simulator_path = device_path.gsub(device_base, simulator_base)
106
+
107
+ merge_header_into(device_path, simulator_path)
108
+ end
109
+ simulator_only_headers = simulator_headers - device_headers.map { |t| t.gsub(device_base, simulator_base) }
158
110
  simulator_only_headers.each do |path|
159
- simulator_content = File.read(path)
160
- content = %{
161
- #if TARGET_OS_SIMULATOR
162
- #{simulator_content}
163
- #endif
164
- }
165
- File.write(path, content)
111
+ add_simulator_conditional(path)
112
+ dir_name = File.dirname(path)
113
+ destination_folder = dir_name.gsub(simulator_base, device_base)
114
+ FileUtils.mkdir_p(destination_folder)
115
+ FileUtils.cp(path, destination_folder)
166
116
  end
167
- end
168
-
169
117
 
118
+ swiftmodule_path = "#{simulator_base}/#{root_name}.swiftmodule"
119
+ if File.directory?(swiftmodule_path)
120
+ FileUtils.cp_r("#{swiftmodule_path}/.", "#{device_base}/#{root_name}.swiftmodule")
121
+ end
170
122
 
171
- spec_names = target.specs.map { |spec| [spec.root.name, spec.root.module_name] }.uniq
172
- spec_names.each do |root_name, module_name|
173
- device_base = "#{build_dir}/#{configuration}-#{device}/#{root_name}"
174
- device_lib = "#{device_base}/#{module_name}.framework/#{module_name}"
175
- device_dsym = "#{device_base}/#{module_name}.framework.dSYM"
176
- device_framework_lib = File.dirname(device_lib)
177
- device_swift_header_path = "#{device_framework_lib}/Headers/#{module_name}-Swift.h"
178
-
179
- simulator_base = "#{build_dir}/#{configuration}-#{simulator}/#{root_name}"
180
- simulator_lib = "#{simulator_base}/#{module_name}.framework/#{module_name}"
181
- simulator_dsym = "#{simulator_base}/#{module_name}.framework.dSYM"
182
- simulator_framework_lib = File.dirname(simulator_lib)
183
- simulator_swift_header_path = "#{simulator_framework_lib}/Headers/#{module_name}-Swift.h"
184
-
185
- next unless File.file?(device_lib) && File.file?(simulator_lib)
186
-
187
- # Starting with Xcode 12b3 the simulator binary contains an arm64 slice as well which conflict with the one in the device_lib
188
- # when creating the fat library. A naive workaround is to remove the arm64 from the simulator_lib however this is wrong because
189
- # we might actually need to have 2 separated arm64 slices, one for simulator and one for device each built with different
190
- # compile time directives (e.g #if targetEnvironment(simulator))
191
- #
192
- # For the time being we remove the arm64 slice bacause otherwise the `xcrun lipo -create -output ...` would fail.
193
- if `xcrun lipo -info #{simulator_lib}`.include?("arm64")
194
- `xcrun lipo -remove arm64 #{simulator_lib} -o #{simulator_lib}`
123
+ if File.exist?("#{device_base}/#{root_name}.swiftmodule")
124
+ # This is a swift pod with a swiftmodule in the root of the prebuilt folder
125
+ else
126
+ # Objective-C pods have the swiftmodule generated under Pods/Headers/Public
127
+ public_headers_path = "#{Configuration.build_path}/Pods/Headers/Public/#{root_name}"
128
+ module_public_headers_path = "#{Configuration.build_path}/Pods/Headers/Public/#{module_name}"
129
+ if public_headers_path.downcase != module_public_headers_path.downcase && File.directory?(public_headers_path) && File.directory?(module_public_headers_path)
130
+ # For pods with module_name != name we have to move the modulemap files to the root_name one
131
+ module_public_headers_path = "#{Configuration.build_path}/Pods/Headers/Public/#{module_name}"
132
+ FileUtils.cp_r("#{module_public_headers_path}/.", public_headers_path)
133
+ end
134
+ Dir.glob("#{public_headers_path}/**/*.*").each do |path|
135
+ destination_folder = "#{device_base}/Headers" + path.gsub(public_headers_path, "")
136
+ destination_folder = File.dirname(destination_folder)
137
+ FileUtils.mkdir_p(destination_folder)
138
+ FileUtils.cp(path, destination_folder)
139
+ end
195
140
  end
196
-
197
- raise "Lipo failed on #{device_lib}" unless system("xcrun lipo -create -output #{device_lib} #{device_lib} #{simulator_lib}")
198
-
199
- # Merge swift headers as per Xcode 10.2 release notes
200
- if File.exist?(device_swift_header_path) && File.exist?(simulator_swift_header_path)
201
- device_content = File.read(device_swift_header_path)
202
- simulator_content = File.read(simulator_swift_header_path)
203
- merged_content = %{
204
- #if TARGET_OS_SIMULATOR
205
- #{simulator_content}
206
- #else
207
- #{device_content}
208
- #endif
209
- }
210
- File.write(device_swift_header_path, merged_content)
141
+
142
+ destination_path = "#{build_dir}/#{root_name}"
143
+ if Dir.glob("#{device_base}/**/*.{a,framework,h}").count > 0
144
+ FileUtils.mv(device_base, destination_path)
145
+
146
+ module_maps = Dir.glob("#{destination_path}/**/*.modulemap")
147
+ module_map_device_base = device_base.gsub(/^\/private/, "") + "/"
148
+ module_maps.each do |module_map|
149
+ content = File.read(module_map)
150
+ content.gsub!(module_map_device_base, "")
151
+ File.write(module_map, content)
152
+ end
211
153
  end
212
-
213
- # # Merge device framework into simulator framework (so that e.g swift Module folder is merged)
214
- # # letting device framework files overwrite simulator ones
215
- # FileUtils.cp_r(File.join(device_framework_lib, "."), simulator_framework_lib)
216
- # source_lib = File.dirname(simulator_framework_lib)
217
-
218
- # FileUtils.cp_r(source_lib, build_dir)
219
-
220
- # FileUtils.cp_r(device_dsym, dsym_device_folder) if File.exist?(device_dsym)
221
- # FileUtils.cp_r(simulator_dsym, dsym_simulator_folder) if File.exist?(simulator_dsym)
222
-
223
- # # Remove frameworks leaving dSYMs
224
- # FileUtils.rm_rf(device_framework_lib)
225
- # FileUtils.rm_rf(simulator_framework_lib)
226
154
  end
227
155
  end
228
156
 
157
+ def self.merge_header_into(device_file, simulator_file)
158
+ unless File.exist?(device_file) || File.exist?(simulator_file)
159
+ return
160
+ end
161
+
162
+ device_content = File.file?(device_file) ? File.read(device_file) : ""
163
+ simulator_content = File.file?(simulator_file) ? File.read(simulator_file) : ""
164
+ merged_content = %{
165
+ #if TARGET_OS_SIMULATOR
166
+ // ->
167
+
168
+ #{simulator_content}
169
+
170
+ // ->
171
+ #else
172
+ // ->
173
+
174
+ #{device_content}
175
+
176
+ // ->
177
+ #endif
178
+ }
179
+ File.write(device_file, merged_content)
180
+ end
181
+
182
+ def self.add_simulator_conditional(path)
183
+ file_content = File.read(path)
184
+ content = %{
185
+ #if TARGET_OS_SIMULATOR
186
+ #{file_content}
187
+ #endif
188
+ }
189
+ File.write(path, content)
190
+ end
229
191
 
230
-
231
-
232
-
233
-
234
-
235
-
236
-
237
-
238
-
239
-
240
-
241
-
242
-
243
-
244
-
245
-
246
-
247
- def self.xcodebuild(sandbox, target, sdk='macosx', deployment_target=nil, configuration, deterministic_build, exclude_archs)
192
+ def self.xcodebuild(sandbox, target, sdk='macosx', deployment_target=nil, configuration, deterministic_build, exclude_archs, prebuilt_root_paths)
248
193
  args = %W(-project #{sandbox.project_path.realdirpath} -scheme #{target} -configuration #{configuration} -sdk #{sdk})
249
194
  supported_platforms = { 'iphonesimulator' => 'iOS', 'appletvsimulator' => 'tvOS', 'watchsimulator' => 'watchOS' }
250
195
  if platform = supported_platforms[sdk]
@@ -255,6 +200,9 @@ module PodBuilder
255
200
  if exclude_archs.count > 0 && xcodebuild_version >= 12.0
256
201
  args += ["EXCLUDED_ARCHS=#{exclude_archs.join(" ")}"]
257
202
  end
203
+ prebuilt_root_paths.each do |k, v|
204
+ args += ["#{k.upcase.gsub("-", "_")}_PREBUILT_ROOT=#{v.gsub(/ /, '\ ')}"]
205
+ end
258
206
 
259
207
  environmental_variables = {}
260
208
  if deterministic_build
@@ -324,6 +272,8 @@ Pod::HooksManager.register('podbuilder-rome', :post_install) do |installer_conte
324
272
  if user_options["pre_compile"]
325
273
  user_options["pre_compile"].call(installer_context)
326
274
  end
275
+
276
+ prebuilt_root_paths = JSON.parse(user_options["prebuilt_root_paths"].gsub('=>', ':'))
327
277
 
328
278
  sandbox_root = Pathname(installer_context.sandbox_root)
329
279
  sandbox = Pod::Sandbox.new(sandbox_root)
@@ -338,19 +288,20 @@ Pod::HooksManager.register('podbuilder-rome', :post_install) do |installer_conte
338
288
  targets.each do |target|
339
289
  case [target.platform_name, uses_frameworks]
340
290
  when [:ios, true] then PodBuilder::build_for_iosish_platform_framework(sandbox, build_dir, target, 'iphoneos', 'iphonesimulator', configuration, PodBuilder::Configuration.deterministic_build, PodBuilder::Configuration.build_for_apple_silicon)
341
- when [:osx, true] then PodBuilder::xcodebuild(sandbox, target.cocoapods_target_label, configuration, PodBuilder::Configuration.deterministic_build, PodBuilder::Configuration.build_for_apple_silicon)
291
+ when [:osx, true] then PodBuilder::xcodebuild(sandbox, target.cocoapods_target_label, configuration, PodBuilder::Configuration.deterministic_build, PodBuilder::Configuration.build_for_apple_silicon, {})
342
292
  when [:tvos, true] then PodBuilder::build_for_iosish_platform_framework(sandbox, build_dir, target, 'appletvos', 'appletvsimulator', configuration, PodBuilder::Configuration.deterministic_build, PodBuilder::Configuration.build_for_apple_silicon)
343
293
  when [:watchos, true] then PodBuilder::build_for_iosish_platform_framework(sandbox, build_dir, target, 'watchos', 'watchsimulator', configuration, PodBuilder::Configuration.deterministic_build, PodBuilder::Configuration.build_for_apple_silicon)
344
- when [:ios, false] then PodBuilder::build_for_iosish_platform_lib(sandbox, build_dir, target, 'iphoneos', 'iphonesimulator', configuration, PodBuilder::Configuration.deterministic_build, PodBuilder::Configuration.build_for_apple_silicon)
345
- when [:osx, false] then PodBuilder::xcodebuild(sandbox, target.cocoapods_target_label, configuration, PodBuilder::Configuration.deterministic_build, PodBuilder::Configuration.build_for_apple_silicon)
346
- when [:tvos, false] then PodBuilder::build_for_iosish_platform_lib(sandbox, build_dir, target, 'appletvos', 'appletvsimulator', configuration, PodBuilder::Configuration.deterministic_build, PodBuilder::Configuration.build_for_apple_silicon)
347
- when [:watchos, false] then PodBuilder::build_for_iosish_platform_lib(sandbox, build_dir, target, 'watchos', 'watchsimulator', configuration, PodBuilder::Configuration.deterministic_build, PodBuilder::Configuration.build_for_apple_silicon)
294
+ when [:ios, false] then PodBuilder::build_for_iosish_platform_lib(sandbox, build_dir, target, 'iphoneos', 'iphonesimulator', configuration, PodBuilder::Configuration.deterministic_build, PodBuilder::Configuration.build_for_apple_silicon, prebuilt_root_paths)
295
+ when [:osx, false] then PodBuilder::xcodebuild(sandbox, target.cocoapods_target_label, configuration, PodBuilder::Configuration.deterministic_build, PodBuilder::Configuration.build_for_apple_silicon, prebuilt_root_paths)
296
+ when [:tvos, false] then PodBuilder::build_for_iosish_platform_lib(sandbox, build_dir, target, 'appletvos', 'appletvsimulator', configuration, PodBuilder::Configuration.deterministic_build, PodBuilder::Configuration.build_for_apple_silicon, prebuilt_root_paths)
297
+ when [:watchos, false] then PodBuilder::build_for_iosish_platform_lib(sandbox, build_dir, target, 'watchos', 'watchsimulator', configuration, PodBuilder::Configuration.deterministic_build, PodBuilder::Configuration.build_for_apple_silicon, prebuilt_root_paths)
348
298
  else raise "\n\nUnknown platform '#{target.platform_name}'".red end
349
299
  end
350
300
 
351
301
  raise Pod::Informative, 'The build directory was not found in the expected location.' unless build_dir.directory?
352
302
 
353
- built_count = installer_context.umbrella_targets.map { |t| t.specs.map(&:name) }.flatten.map { |t| t.split("/").first }.uniq.count
303
+ specs = installer_context.umbrella_targets.map { |t| t.specs.map(&:name) }.flatten.map { |t| t.split("/").first }.uniq
304
+ built_count = Dir["#{build_dir}/*"].select { |t| specs.include?(File.basename(t)) }.count
354
305
  Pod::UI.puts "Built #{built_count} #{'items'.pluralize(built_count)}, copying..."
355
306
 
356
307
  base_destination.rmtree if base_destination.directory?
@@ -358,20 +309,23 @@ Pod::HooksManager.register('podbuilder-rome', :post_install) do |installer_conte
358
309
  installer_context.umbrella_targets.each do |umbrella|
359
310
  umbrella.specs.each do |spec|
360
311
  root_name = spec.name.split("/").first
312
+
313
+ if uses_frameworks
314
+ destination = File.join(base_destination, root_name)
315
+ else
316
+ destination = File.join(base_destination, root_name, root_name)
317
+ end
361
318
  # Make sure the device target overwrites anything in the simulator build, otherwise iTunesConnect
362
319
  # can get upset about Info.plist containing references to the simulator SDK
363
- frameworks = Pathname.glob("build/#{root_name}/*.framework").reject { |f| f.to_s =~ /Pods[^.]+\.framework/ }
364
-
320
+ files = Pathname.glob("build/#{root_name}/*").reject { |f| f.to_s =~ /Pods[^.]+\.framework/ }
321
+
365
322
  consumer = spec.consumer(umbrella.platform_name)
366
323
  file_accessor = Pod::Sandbox::FileAccessor.new(sandbox.pod_dir(spec.root.name), consumer)
367
- frameworks += file_accessor.vendored_libraries
368
- frameworks += file_accessor.vendored_frameworks
369
- resources = file_accessor.resources
370
-
371
- destination = File.join(base_destination, root_name)
372
- FileUtils.mkdir_p(destination)
373
-
374
- files = frameworks + resources
324
+ files += file_accessor.vendored_libraries
325
+ files += file_accessor.vendored_frameworks
326
+ files += file_accessor.resources
327
+
328
+ FileUtils.mkdir_p(destination)
375
329
  files.each do |file|
376
330
  FileUtils.cp_r(file, destination)
377
331
  end