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

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}")
@@ -287,7 +302,7 @@ module PodBuilder
287
302
  #
288
303
  # When building PodA we need to build both DepA subspecs because they might
289
304
  # contain different code
290
- deps += available_pods.select { |t| root_names.include?(t.root_name) }
305
+ deps += available_pods.select { |t| root_names.include?(t.root_name) && t.root_name != t.name }
291
306
 
292
307
  deps.uniq!
293
308
 
@@ -389,11 +404,7 @@ module PodBuilder
389
404
  end
390
405
 
391
406
  def prebuilt_rel_path
392
- if is_subspec && Configuration.subspecs_to_split.include?(name)
393
- return "#{name}/#{module_name}.framework"
394
- else
395
- return "#{module_name}.framework"
396
- end
407
+ return "#{module_name}.framework"
397
408
  end
398
409
 
399
410
  def prebuilt_podspec_path(absolute_path = true)
@@ -408,11 +419,7 @@ module PodBuilder
408
419
  def prebuilt_entry(include_pb_entry = true, absolute_path = false)
409
420
  podspec_dirname = File.dirname(prebuilt_podspec_path(absolute_path = absolute_path))
410
421
 
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
422
+ entry = "pod '#{name}', :path => '#{podspec_dirname}'"
416
423
 
417
424
  if include_pb_entry && !is_prebuilt
418
425
  entry += prebuilt_marker()
@@ -518,28 +525,9 @@ module PodBuilder
518
525
  end
519
526
  end
520
527
 
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
528
+ def source_files_from(specs)
529
+ files = specs.map { |t| t.attributes_hash.fetch("source_files", []) }.flatten
530
+ return source_files_from_string(files).uniq
543
531
  end
544
532
  end
545
533
  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,80 @@ module PodBuilder
24
24
  indentation = " " * slash_count
25
25
  spec_var = "p#{slash_count}"
26
26
 
27
+ if spec_var == "p1" && item.default_subspecs.count > 0
28
+ podspec += "#{indentation}#{spec_var}.default_subspecs = '#{item.default_subspecs.join("', '")}'\n"
29
+ end
30
+
27
31
  if item.name == name
28
32
  if_exists = lambda { |t| File.exist?(PodBuilder::prebuiltpath("#{item.root_name}/#{t}") || "") }
29
33
 
30
- vendored_frameworks = item.vendored_frameworks + ["#{item.module_name}.framework"]
34
+ vendored_frameworks = item.vendored_frameworks
35
+ if item.default_subspecs.count == 0 && install_using_frameworks
36
+ vendored_frameworks += ["#{item.module_name}.framework"]
37
+ end
38
+
31
39
  existing_vendored_frameworks = vendored_frameworks.select(&if_exists)
32
40
  existing_vendored_frameworks_basename = vendored_frameworks.map { |t| File.basename(t) }.select(&if_exists)
33
41
  vendored_frameworks = (existing_vendored_frameworks + existing_vendored_frameworks_basename).uniq
34
42
 
35
43
  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
44
+ if install_using_frameworks
45
+ existing_vendored_libraries = vendored_libraries.map { |t| "#{item.module_name}/#{t}" }.select(&if_exists)
46
+ existing_vendored_libraries_basename = vendored_libraries.map { |t| File.basename(t) }.select(&if_exists)
47
+ vendored_libraries = (existing_vendored_libraries + existing_vendored_libraries_basename).uniq
48
+
49
+ # .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)
50
+ vendored_libraries.reject! { |t| t.end_with?(".a") }
51
+
52
+ frameworks = all_buildable_items.select { |t| vendored_frameworks.include?("#{t.module_name}.framework") }.uniq
53
+ static_frameworks = frameworks.select { |x| x.is_static }
54
+
55
+ 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
56
+
57
+ exclude_files = static_frameworks.map { |x| x.vendored_framework_path.nil? ? nil : "#{x.vendored_framework_path}/Info.plist" }.compact.flatten.uniq
58
+ public_headers = []
59
+ else
60
+ public_headers = Dir.glob(PodBuilder::prebuiltpath("#{item.root_name}/#{item.root_name}/Headers/**/*.h"))
61
+ vendored_libraries += ["#{item.root_name}/lib#{item.root_name}.a"]
62
+ vendored_libraries.map! { |t| "#{item.root_name}/#{t}" }.select(&if_exists)
63
+
64
+ resources = ["#{item.root_name}/*.{nib,bundle,xcasset,strings,png,jpg,tif,tiff,otf,ttf,ttc,plist,json,caf,wav,p12,momd}"]
65
+
66
+ exclude_files = ["*.modulemap"]
67
+ unless item.swift_version.nil?
68
+ exclude_files += ["Swift Compatibility Header/*", "*.swiftmodule"]
69
+ end
70
+ exclude_files.map! { |t| "#{item.root_name}/#{t}" }
71
+ end
72
+
73
+ entries = lambda { |spec_key, spec_value|
74
+ key = "#{indentation}#{spec_var}.#{spec_key}"
75
+ joined_values = spec_value.map { |t| "#{t}" }.uniq.sort.join("', '")
76
+ "#{key} = '#{joined_values}'\n"
77
+ }
48
78
 
49
79
  if vendored_frameworks.count > 0
50
- podspec += "#{indentation}#{spec_var}.vendored_frameworks = '#{vendored_frameworks.uniq.sort.join("','")}'\n"
80
+ podspec += entries.call("vendored_frameworks", vendored_frameworks)
51
81
  end
52
82
  if vendored_libraries.count > 0
53
- podspec += "#{indentation}#{spec_var}.vendored_libraries = '#{vendored_libraries.uniq.sort.join("','")}'\n"
83
+ podspec += entries.call("vendored_libraries", vendored_libraries)
54
84
  end
55
85
  if item.frameworks.count > 0
56
- podspec += "#{indentation}#{spec_var}.frameworks = '#{item.frameworks.uniq.sort.join("', '")}'\n"
86
+ podspec += entries.call("frameworks", item.frameworks)
57
87
  end
58
88
  if item.libraries.count > 0
59
- podspec += "#{indentation}#{spec_var}.libraries = '#{item.libraries.uniq.sort.join("', '")}'\n"
89
+ podspec += entries.call("libraries", item.libraries)
60
90
  end
61
91
  if resources.count > 0
62
- podspec += "#{indentation}#{spec_var}.resources = '#{resources.uniq.sort.join("', '")}'\n"
92
+ podspec += entries.call("resources", resources)
63
93
  end
64
94
  if exclude_files.count > 0
65
- podspec += "#{indentation}#{spec_var}.exclude_files = '#{exclude_files.uniq.sort.join("', '")}'\n"
95
+ podspec += entries.call("exclude_files", exclude_files)
96
+ end
97
+ if public_headers.count > 0
98
+ podspec += "#{indentation}#{spec_var}.public_header_files = '#{item.root_name}/Headers/**/*.h'\n"
66
99
  end
100
+
67
101
  if item.xcconfig.keys.count > 0
68
102
  xcconfig = Hash.new
69
103
  item.xcconfig.each do |k, v|
@@ -88,6 +122,21 @@ module PodBuilder
88
122
  podspec += "#{indentation}#{spec_var}.xcconfig = #{xcconfig.to_s}\n"
89
123
  end
90
124
  end
125
+ if !install_using_frameworks && spec_var == "p1"
126
+ module_path_files = Dir.glob(PodBuilder.prebuiltpath("#{item.root_name}/**/#{item.root_name}.modulemap"))
127
+ raise "\n\nToo many module maps found for #{item.root_name}".red if module_path_files.count > 1
128
+ if module_path_file = module_path_files.first
129
+ rel_path = Pathname.new(PodBuilder::prebuiltpath).relative_path_from(Pathname.new(PodBuilder::project_path("Pods"))).to_s
130
+ prebuilt_root_var = "#{item.root_name.upcase.gsub("-", "_")}_PREBUILT_ROOT"
131
+ module_map_rel = module_path_file.gsub(PodBuilder::prebuiltpath("#{item.root_name}/#{item.root_name}/"), "")
132
+ static_cfg = { prebuilt_root_var => "$(PODS_ROOT)/#{rel_path}",
133
+ "SWIFT_INCLUDE_PATHS" => "$(inherited) \"$(#{prebuilt_root_var})/#{item.root_name}/#{item.root_name}\"",
134
+ "OTHER_CFLAGS" => "$(inherited) -fmodule-map-file=\"$(#{prebuilt_root_var})/#{item.root_name}/#{item.root_name}/#{module_map_rel}\"",
135
+ "OTHER_SWIFT_FLAGS" => "$(inherited) -Xcc -fmodule-map-file=\"$(#{prebuilt_root_var})/#{item.root_name}/#{item.root_name}/#{module_map_rel}\""
136
+ }
137
+ podspec += "#{indentation}#{spec_var}.xcconfig = #{static_cfg.to_s}\n"
138
+ end
139
+ end
91
140
 
92
141
  deps = item.dependency_names.sort
93
142
  if name == item.root_name
@@ -103,7 +152,7 @@ module PodBuilder
103
152
  end
104
153
  end
105
154
 
106
- valid = valid || vendored_frameworks.count > 0
155
+ valid = valid || (install_using_frameworks ? vendored_frameworks.count > 0 : vendored_libraries.count > 0)
107
156
  end
108
157
 
109
158
  subspec_names = all_buildable_items.map(&:name).select { |t| t.start_with?("#{name}/") }
@@ -117,7 +166,7 @@ module PodBuilder
117
166
  podspec += "\n"
118
167
  end
119
168
 
120
- subspec_keys, subspec_valid = generate_spec_keys_for(subspec_item, subspec, all_buildable_items)
169
+ subspec_keys, subspec_valid = generate_spec_keys_for(subspec_item, subspec, all_buildable_items, install_using_frameworks)
121
170
  valid = valid || subspec_valid
122
171
 
123
172
  if subspec_keys.length > 0
@@ -130,7 +179,7 @@ module PodBuilder
130
179
  return podspec, valid
131
180
  end
132
181
 
133
- def self.generate_podspec_from(all_buildable_items, platform)
182
+ def self.generate_podspec_from(all_buildable_items, platform, install_using_frameworks)
134
183
  prebuilt_podspec_path = all_buildable_items.map(&:prebuilt_podspec_path)
135
184
  prebuilt_podspec_path.each do |path|
136
185
  if File.exist?(path)
@@ -165,7 +214,7 @@ module PodBuilder
165
214
  podspec += " p1.#{platform.safe_string_name.downcase}.deployment_target = '#{platform.deployment_target.version}'\n"
166
215
  podspec += "\n"
167
216
 
168
- main_keys, valid = generate_spec_keys_for(item, item.root_name, all_buildable_items)
217
+ main_keys, valid = generate_spec_keys_for(item, item.root_name, all_buildable_items, install_using_frameworks)
169
218
  if !valid
170
219
  next
171
220
  end
@@ -16,9 +16,10 @@ 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, [])
20
- excluded_archs = build_for_apple_silicon ? [] : ["arm64"]
21
- xcodebuild(sandbox, target_label, simulator, deployment_target, configuration, deterministic_build, excluded_archs)
19
+ xcodebuild(sandbox, target_label, device, deployment_target, configuration, deterministic_build, [], {})
20
+ excluded_archs = ["i386"] # Fixes https://github.com/Subito-it/PodBuilder/issues/17
21
+ excluded_archs += build_for_apple_silicon ? [] : ["arm64"]
22
+ xcodebuild(sandbox, target_label, simulator, deployment_target, configuration, deterministic_build, excluded_archs, {})
22
23
 
23
24
  spec_names = target.specs.map { |spec| [spec.root.name, spec.root.module_name] }.uniq
24
25
  spec_names.each do |root_name, module_name|
@@ -48,29 +49,17 @@ module PodBuilder
48
49
 
49
50
  raise "Lipo failed on #{device_lib}" unless system("xcrun lipo -create -output #{device_lib} #{device_lib} #{simulator_lib}")
50
51
 
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
52
+ merge_header_into(device_swift_header_path, simulator_swift_header_path)
64
53
 
65
54
  # Merge device framework into simulator framework (so that e.g swift Module folder is merged)
66
55
  # letting device framework files overwrite simulator ones
67
56
  FileUtils.cp_r(File.join(device_framework_lib, "."), simulator_framework_lib)
68
57
  source_lib = File.dirname(simulator_framework_lib)
69
58
 
70
- FileUtils.cp_r(source_lib, build_dir)
59
+ FileUtils.mv(device_dsym, dsym_device_folder) if File.exist?(device_dsym)
60
+ FileUtils.mv(simulator_dsym, dsym_simulator_folder) if File.exist?(simulator_dsym)
71
61
 
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)
62
+ FileUtils.mv(source_lib, build_dir)
74
63
 
75
64
  # Remove frameworks leaving dSYMs
76
65
  FileUtils.rm_rf(device_framework_lib)
@@ -78,173 +67,130 @@ module PodBuilder
78
67
  end
79
68
  end
80
69
 
81
- def self.build_for_iosish_platform_lib(sandbox, build_dir, target, device, simulator, configuration, deterministic_build, build_for_apple_silicon)
70
+ def self.build_for_iosish_platform_lib(sandbox, build_dir, target, device, simulator, configuration, deterministic_build, build_for_apple_silicon, prebuilt_root_paths)
82
71
  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
72
 
89
73
  deployment_target = target.platform_deployment_target
90
74
  target_label = target.cocoapods_target_label
91
75
 
92
76
  spec_names = target.specs.map { |spec| [spec.root.name, spec.root.module_name] }.uniq
93
77
 
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
-
78
+ xcodebuild(sandbox, target_label, device, deployment_target, configuration, deterministic_build, [], prebuilt_root_paths)
106
79
  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
80
+ xcodebuild(sandbox, target_label, simulator, deployment_target, configuration, deterministic_build, excluded_archs, prebuilt_root_paths)
118
81
 
119
82
  spec_names.each do |root_name, module_name|
120
83
  simulator_base = "#{build_dir}/#{configuration}-#{simulator}/#{root_name}"
121
84
  simulator_lib = "#{simulator_base}/lib#{module_name}.a"
122
85
 
123
86
  device_base = "#{build_dir}/#{configuration}-#{device}/#{root_name}"
124
- device_lib = "#{device_base}/lib#{module_name}.a"
87
+ device_lib = "#{device_base}/lib#{root_name}.a"
125
88
 
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}`
89
+ if File.file?(device_lib) && File.file?(simulator_lib)
90
+ # Starting with Xcode 12b3 the simulator binary contains an arm64 slice as well which conflict with the one in the device_lib
91
+ # when creating the fat library. A naive workaround is to remove the arm64 from the simulator_lib however this is wrong because
92
+ # we might actually need to have 2 separated arm64 slices, one for simulator and one for device each built with different
93
+ # compile time directives (e.g #if targetEnvironment(simulator))
94
+ #
95
+ # For the time being we remove the arm64 slice bacause otherwise the `xcrun lipo -create -output ...` would fail.
96
+ if `xcrun lipo -info #{simulator_lib}`.include?("arm64")
97
+ `xcrun lipo -remove arm64 #{simulator_lib} -o #{simulator_lib}`
98
+ end
99
+
100
+ raise "Lipo failed on #{device_lib}" unless system("xcrun lipo -create -output #{device_lib} #{device_lib} #{simulator_lib}")
136
101
  end
137
-
138
- raise "Lipo failed on #{device_lib}" unless system("xcrun lipo -create -output #{device_lib} #{device_lib} #{simulator_lib}")
139
102
 
140
- device_headers = Dir.glob("#{device_headers_path}/**/*.h")
141
- simulator_headers = Dir.glob("#{simulator_headers_path}/**/*.h")
103
+ device_headers = Dir.glob("#{device_base}/**/*.h")
104
+ simulator_headers = Dir.glob("#{simulator_base}/**/*.h")
142
105
  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) }
106
+ simulator_path = device_path.gsub(device_base, simulator_base)
107
+
108
+ merge_header_into(device_path, simulator_path)
109
+ end
110
+ simulator_only_headers = simulator_headers - device_headers.map { |t| t.gsub(device_base, simulator_base) }
158
111
  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)
112
+ add_simulator_conditional(path)
113
+ dir_name = File.dirname(path)
114
+ destination_folder = dir_name.gsub(simulator_base, device_base)
115
+ FileUtils.mkdir_p(destination_folder)
116
+ FileUtils.cp(path, destination_folder)
166
117
  end
167
- end
168
-
169
118
 
119
+ swiftmodule_path = "#{simulator_base}/#{root_name}.swiftmodule"
120
+ if File.directory?(swiftmodule_path)
121
+ FileUtils.cp_r("#{swiftmodule_path}/.", "#{device_base}/#{root_name}.swiftmodule")
122
+ end
170
123
 
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}`
124
+ if File.exist?("#{device_base}/#{root_name}.swiftmodule")
125
+ # This is a swift pod with a swiftmodule in the root of the prebuilt folder
126
+ else
127
+ # Objective-C pods have the swiftmodule generated under Pods/Headers/Public
128
+ public_headers_path = "#{Configuration.build_path}/Pods/Headers/Public/#{root_name}"
129
+ module_public_headers_path = "#{Configuration.build_path}/Pods/Headers/Public/#{module_name}"
130
+ if public_headers_path.downcase != module_public_headers_path.downcase && File.directory?(public_headers_path) && File.directory?(module_public_headers_path)
131
+ # For pods with module_name != name we have to move the modulemap files to the root_name one
132
+ module_public_headers_path = "#{Configuration.build_path}/Pods/Headers/Public/#{module_name}"
133
+ FileUtils.cp_r("#{module_public_headers_path}/.", public_headers_path)
134
+ end
135
+ Dir.glob("#{public_headers_path}/**/*.*").each do |path|
136
+ destination_folder = "#{device_base}/Headers" + path.gsub(public_headers_path, "")
137
+ destination_folder = File.dirname(destination_folder)
138
+ FileUtils.mkdir_p(destination_folder)
139
+ FileUtils.cp(path, destination_folder)
140
+ end
195
141
  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)
142
+
143
+ destination_path = "#{build_dir}/#{root_name}"
144
+ if Dir.glob("#{device_base}/**/*.{a,framework,h}").count > 0
145
+ FileUtils.mv(device_base, destination_path)
146
+
147
+ module_maps = Dir.glob("#{destination_path}/**/*.modulemap")
148
+ module_map_device_base = device_base.gsub(/^\/private/, "") + "/"
149
+ module_maps.each do |module_map|
150
+ content = File.read(module_map)
151
+ content.gsub!(module_map_device_base, "")
152
+ File.write(module_map, content)
153
+ end
211
154
  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
155
  end
227
156
  end
228
157
 
158
+ def self.merge_header_into(device_file, simulator_file)
159
+ unless File.exist?(device_file) || File.exist?(simulator_file)
160
+ return
161
+ end
162
+
163
+ device_content = File.file?(device_file) ? File.read(device_file) : ""
164
+ simulator_content = File.file?(simulator_file) ? File.read(simulator_file) : ""
165
+ merged_content = %{
166
+ #if TARGET_OS_SIMULATOR
167
+ // ->
168
+
169
+ #{simulator_content}
170
+
171
+ // ->
172
+ #else
173
+ // ->
174
+
175
+ #{device_content}
176
+
177
+ // ->
178
+ #endif
179
+ }
180
+ File.write(device_file, merged_content)
181
+ end
182
+
183
+ def self.add_simulator_conditional(path)
184
+ file_content = File.read(path)
185
+ content = %{
186
+ #if TARGET_OS_SIMULATOR
187
+ #{file_content}
188
+ #endif
189
+ }
190
+ File.write(path, content)
191
+ end
229
192
 
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)
193
+ def self.xcodebuild(sandbox, target, sdk='macosx', deployment_target=nil, configuration, deterministic_build, exclude_archs, prebuilt_root_paths)
248
194
  args = %W(-project #{sandbox.project_path.realdirpath} -scheme #{target} -configuration #{configuration} -sdk #{sdk})
249
195
  supported_platforms = { 'iphonesimulator' => 'iOS', 'appletvsimulator' => 'tvOS', 'watchsimulator' => 'watchOS' }
250
196
  if platform = supported_platforms[sdk]
@@ -255,6 +201,9 @@ module PodBuilder
255
201
  if exclude_archs.count > 0 && xcodebuild_version >= 12.0
256
202
  args += ["EXCLUDED_ARCHS=#{exclude_archs.join(" ")}"]
257
203
  end
204
+ prebuilt_root_paths.each do |k, v|
205
+ args += ["#{k.upcase.gsub("-", "_")}_PREBUILT_ROOT=#{v.gsub(/ /, '\ ')}"]
206
+ end
258
207
 
259
208
  environmental_variables = {}
260
209
  if deterministic_build
@@ -324,6 +273,8 @@ Pod::HooksManager.register('podbuilder-rome', :post_install) do |installer_conte
324
273
  if user_options["pre_compile"]
325
274
  user_options["pre_compile"].call(installer_context)
326
275
  end
276
+
277
+ prebuilt_root_paths = JSON.parse(user_options["prebuilt_root_paths"].gsub('=>', ':'))
327
278
 
328
279
  sandbox_root = Pathname(installer_context.sandbox_root)
329
280
  sandbox = Pod::Sandbox.new(sandbox_root)
@@ -338,19 +289,20 @@ Pod::HooksManager.register('podbuilder-rome', :post_install) do |installer_conte
338
289
  targets.each do |target|
339
290
  case [target.platform_name, uses_frameworks]
340
291
  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)
292
+ when [:osx, true] then PodBuilder::xcodebuild(sandbox, target.cocoapods_target_label, configuration, PodBuilder::Configuration.deterministic_build, PodBuilder::Configuration.build_for_apple_silicon, {})
342
293
  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
294
  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)
295
+ 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)
296
+ 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)
297
+ 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)
298
+ 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
299
  else raise "\n\nUnknown platform '#{target.platform_name}'".red end
349
300
  end
350
301
 
351
302
  raise Pod::Informative, 'The build directory was not found in the expected location.' unless build_dir.directory?
352
303
 
353
- built_count = installer_context.umbrella_targets.map { |t| t.specs.map(&:name) }.flatten.map { |t| t.split("/").first }.uniq.count
304
+ specs = installer_context.umbrella_targets.map { |t| t.specs.map(&:name) }.flatten.map { |t| t.split("/").first }.uniq
305
+ built_count = Dir["#{build_dir}/*"].select { |t| specs.include?(File.basename(t)) }.count
354
306
  Pod::UI.puts "Built #{built_count} #{'items'.pluralize(built_count)}, copying..."
355
307
 
356
308
  base_destination.rmtree if base_destination.directory?
@@ -358,20 +310,23 @@ Pod::HooksManager.register('podbuilder-rome', :post_install) do |installer_conte
358
310
  installer_context.umbrella_targets.each do |umbrella|
359
311
  umbrella.specs.each do |spec|
360
312
  root_name = spec.name.split("/").first
313
+
314
+ if uses_frameworks
315
+ destination = File.join(base_destination, root_name)
316
+ else
317
+ destination = File.join(base_destination, root_name, root_name)
318
+ end
361
319
  # Make sure the device target overwrites anything in the simulator build, otherwise iTunesConnect
362
320
  # 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
-
321
+ files = Pathname.glob("build/#{root_name}/*").reject { |f| f.to_s =~ /Pods[^.]+\.framework/ }
322
+
365
323
  consumer = spec.consumer(umbrella.platform_name)
366
324
  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
325
+ files += file_accessor.vendored_libraries
326
+ files += file_accessor.vendored_frameworks
327
+ files += file_accessor.resources
328
+
329
+ FileUtils.mkdir_p(destination)
375
330
  files.each do |file|
376
331
  FileUtils.cp_r(file, destination)
377
332
  end