pod-builder 2.0.0.beta.22 → 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,8 +17,8 @@ module PodBuilder
17
17
 
18
18
  platform = analyzer.instance_variable_get("@result").targets.first.platform
19
19
 
20
- install_using_frameworks = analyzer.podfile.root_target_definitions.map(&:uses_frameworks?).uniq.first
21
- podfile.sub!("%%%use_frameworks%%%", install_using_frameworks ? "use_frameworks!" : "")
20
+ podfile.sub!("%%%use_frameworks%%%", install_using_frameworks ? "use_frameworks!" : "use_modular_headers!")
21
+ podfile.sub!("%%%uses_frameworks%%%", install_using_frameworks ? "true" : "false")
22
22
 
23
23
  podfile.sub!("%%%platform_name%%%", platform.name.to_s)
24
24
  podfile.sub!("%%%deployment_version%%%", platform.deployment_target.version)
@@ -45,7 +45,7 @@ module PodBuilder
45
45
 
46
46
  # Don't store .pcm info in binary, see https://forums.swift.org/t/swift-behavior-of-gmodules-and-dsyms/23211/3
47
47
  build_settings['CLANG_ENABLE_MODULE_DEBUGGING'] = 'NO'
48
- build_settings['OTHER_SWIFT_FLAGS'] = "-Xfrontend -no-clang-module-breadcrumbs"
48
+ build_settings['OTHER_SWIFT_FLAGS'] = "$(inherited) -Xfrontend -no-clang-module-breadcrumbs"
49
49
 
50
50
  # Improve compile speed
51
51
  build_settings['COMPILER_INDEX_STORE_ENABLE'] = 'NO'
@@ -180,7 +180,7 @@ module PodBuilder
180
180
  next
181
181
  end
182
182
 
183
- if pod_name = pod_definition_in(line, true)
183
+ if pod_name = pod_definition_in(line, true)
184
184
  if podfile_item = all_buildable_items.detect { |x| x.name == pod_name }
185
185
  marker = podfile_item.prebuilt_marker()
186
186
 
@@ -198,7 +198,7 @@ module PodBuilder
198
198
  dep_item = all_buildable_items.detect { |x| x.name == dep.name }
199
199
 
200
200
  if File.exist?(dep_item.prebuilt_podspec_path) && !dep_item.is_prebuilt
201
- pod_name = dep_item.prebuilt_entry(false)
201
+ pod_name = dep_item.prebuilt_entry(false, false)
202
202
  prebuilt_lines.push("#{line.detect_indentation}#{pod_name}#{marker}\n")
203
203
  end
204
204
 
@@ -384,6 +384,22 @@ module PodBuilder
384
384
  resolved_names.uniq
385
385
  end
386
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
+
387
403
  private
388
404
 
389
405
  def self.podfile_path_transform(path)
@@ -591,7 +607,7 @@ module PodBuilder
591
607
  base = File.expand_path(File.join(PodBuilder::project_path, ".."))
592
608
  bin_js = Dir.glob("#{base}/node_modules/@react-native-community/cli/build/bin.js")
593
609
 
594
- raise "\n\nReact native cli bin_js not found!".red unless bin_js.count == 1
610
+ raise "\n\nReact native cli bin_js not found! Did you run yarn install?".red unless bin_js.count == 1
595
611
  bin_js = bin_js.first
596
612
 
597
613
  config_dest_path = PodBuilder::basepath("rn_config.json")
@@ -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,9 +49,13 @@ 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
- target_s += "#{child_indentation}#{pod.prebuilt_entry(false)}\n"
58
+ target_s += "#{child_indentation}#{pod.prebuilt_entry(false, false)}\n"
53
59
  end
54
60
  pod_entries.each do |pod|
55
61
  target_s += "#{child_indentation}#{pod.entry(true, 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
@@ -401,18 +418,14 @@ module PodBuilder
401
418
  if absolute_path
402
419
  return podspec_path
403
420
  else
404
- pod_path = Pathname.new(podspec_path).relative_path_from(Pathname.new(PodBuilder::project_path)).to_s
421
+ pod_path = Pathname.new(podspec_path).relative_path_from(Pathname.new(PodBuilder::basepath)).to_s
405
422
  end
406
423
  end
407
424
 
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
@@ -2,9 +2,10 @@
2
2
 
3
3
  require 'fourflusher'
4
4
  require 'colored'
5
+ require 'pathname'
5
6
 
6
7
  module PodBuilder
7
- def self.build_for_iosish_platform(sandbox, build_dir, target, device, simulator, configuration, deterministic_build, build_for_apple_silicon)
8
+ def self.build_for_iosish_platform_framework(sandbox, build_dir, target, device, simulator, configuration, deterministic_build, build_for_apple_silicon)
8
9
  raise "\n\nApple silicon hardware still unsupported since it requires to migrate to xcframeworks".red if build_for_apple_silicon
9
10
 
10
11
  dsym_device_folder = File.join(build_dir, "dSYM", device)
@@ -15,10 +16,10 @@ module PodBuilder
15
16
  deployment_target = target.platform_deployment_target
16
17
  target_label = target.cocoapods_target_label
17
18
 
18
- xcodebuild(sandbox, target_label, device, deployment_target, configuration, deterministic_build, [])
19
+ xcodebuild(sandbox, target_label, device, deployment_target, configuration, deterministic_build, [], {})
19
20
  excluded_archs = build_for_apple_silicon ? [] : ["arm64"]
20
- xcodebuild(sandbox, target_label, simulator, deployment_target, configuration, deterministic_build, excluded_archs)
21
-
21
+ xcodebuild(sandbox, target_label, simulator, deployment_target, configuration, deterministic_build, excluded_archs, {})
22
+
22
23
  spec_names = target.specs.map { |spec| [spec.root.name, spec.root.module_name] }.uniq
23
24
  spec_names.each do |root_name, module_name|
24
25
  device_base = "#{build_dir}/#{configuration}-#{device}/#{root_name}"
@@ -47,37 +48,148 @@ module PodBuilder
47
48
 
48
49
  raise "Lipo failed on #{device_lib}" unless system("xcrun lipo -create -output #{device_lib} #{device_lib} #{simulator_lib}")
49
50
 
50
- # Merge swift headers as per Xcode 10.2 release notes
51
- if File.exist?(device_swift_header_path) && File.exist?(simulator_swift_header_path)
52
- device_content = File.read(device_swift_header_path)
53
- simulator_content = File.read(simulator_swift_header_path)
54
- merged_content = %{
55
- #if TARGET_OS_SIMULATOR
56
- #{simulator_content}
57
- #else
58
- #{device_content}
59
- #endif
60
- }
61
- File.write(device_swift_header_path, merged_content)
62
- end
51
+ merge_header_into(device_swift_header_path, simulator_swift_header_path)
63
52
 
64
53
  # Merge device framework into simulator framework (so that e.g swift Module folder is merged)
65
54
  # letting device framework files overwrite simulator ones
66
55
  FileUtils.cp_r(File.join(device_framework_lib, "."), simulator_framework_lib)
67
56
  source_lib = File.dirname(simulator_framework_lib)
68
57
 
69
- 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)
70
60
 
71
- FileUtils.cp_r(device_dsym, dsym_device_folder) if File.exist?(device_dsym)
72
- FileUtils.cp_r(simulator_dsym, dsym_simulator_folder) if File.exist?(simulator_dsym)
61
+ FileUtils.mv(source_lib, build_dir)
73
62
 
74
63
  # Remove frameworks leaving dSYMs
75
64
  FileUtils.rm_rf(device_framework_lib)
76
65
  FileUtils.rm_rf(simulator_framework_lib)
77
66
  end
78
67
  end
68
+
69
+ def self.build_for_iosish_platform_lib(sandbox, build_dir, target, device, simulator, configuration, deterministic_build, build_for_apple_silicon, prebuilt_root_paths)
70
+ raise "\n\nApple silicon hardware still unsupported since it requires to migrate to xcframeworks".red if build_for_apple_silicon
71
+
72
+ deployment_target = target.platform_deployment_target
73
+ target_label = target.cocoapods_target_label
74
+
75
+ spec_names = target.specs.map { |spec| [spec.root.name, spec.root.module_name] }.uniq
76
+
77
+ xcodebuild(sandbox, target_label, device, deployment_target, configuration, deterministic_build, [], prebuilt_root_paths)
78
+ excluded_archs = build_for_apple_silicon ? [] : ["arm64"]
79
+ xcodebuild(sandbox, target_label, simulator, deployment_target, configuration, deterministic_build, excluded_archs, prebuilt_root_paths)
80
+
81
+ spec_names.each do |root_name, module_name|
82
+ simulator_base = "#{build_dir}/#{configuration}-#{simulator}/#{root_name}"
83
+ simulator_lib = "#{simulator_base}/lib#{module_name}.a"
84
+
85
+ device_base = "#{build_dir}/#{configuration}-#{device}/#{root_name}"
86
+ device_lib = "#{device_base}/lib#{root_name}.a"
79
87
 
80
- def self.xcodebuild(sandbox, target, sdk='macosx', deployment_target=nil, configuration, deterministic_build, exclude_archs)
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}")
100
+ end
101
+
102
+ device_headers = Dir.glob("#{device_base}/**/*.h")
103
+ simulator_headers = Dir.glob("#{simulator_base}/**/*.h")
104
+ device_headers.each do |device_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) }
110
+ simulator_only_headers.each do |path|
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)
116
+ end
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
122
+
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
140
+ end
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
153
+ end
154
+ end
155
+ end
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
191
+
192
+ def self.xcodebuild(sandbox, target, sdk='macosx', deployment_target=nil, configuration, deterministic_build, exclude_archs, prebuilt_root_paths)
81
193
  args = %W(-project #{sandbox.project_path.realdirpath} -scheme #{target} -configuration #{configuration} -sdk #{sdk})
82
194
  supported_platforms = { 'iphonesimulator' => 'iOS', 'appletvsimulator' => 'tvOS', 'watchsimulator' => 'watchOS' }
83
195
  if platform = supported_platforms[sdk]
@@ -88,6 +200,9 @@ module PodBuilder
88
200
  if exclude_archs.count > 0 && xcodebuild_version >= 12.0
89
201
  args += ["EXCLUDED_ARCHS=#{exclude_archs.join(" ")}"]
90
202
  end
203
+ prebuilt_root_paths.each do |k, v|
204
+ args += ["#{k.upcase.gsub("-", "_")}_PREBUILT_ROOT=#{v.gsub(/ /, '\ ')}"]
205
+ end
91
206
 
92
207
  environmental_variables = {}
93
208
  if deterministic_build
@@ -148,16 +263,17 @@ module PodBuilder
148
263
  end
149
264
  project.save
150
265
  end
151
-
152
-
153
266
  end
154
267
 
155
268
  Pod::HooksManager.register('podbuilder-rome', :post_install) do |installer_context, user_options|
156
269
  enable_dsym = user_options.fetch('dsym', true)
157
270
  configuration = user_options.fetch('configuration', 'Debug')
271
+ uses_frameworks = user_options.fetch('uses_frameworks', true)
158
272
  if user_options["pre_compile"]
159
273
  user_options["pre_compile"].call(installer_context)
160
274
  end
275
+
276
+ prebuilt_root_paths = JSON.parse(user_options["prebuilt_root_paths"].gsub('=>', ':'))
161
277
 
162
278
  sandbox_root = Pathname(installer_context.sandbox_root)
163
279
  sandbox = Pod::Sandbox.new(sandbox_root)
@@ -170,17 +286,22 @@ Pod::HooksManager.register('podbuilder-rome', :post_install) do |installer_conte
170
286
  build_dir.rmtree if build_dir.directory?
171
287
  targets = installer_context.umbrella_targets.select { |t| t.specs.any? }
172
288
  targets.each do |target|
173
- case target.platform_name
174
- when :ios then PodBuilder::build_for_iosish_platform(sandbox, build_dir, target, 'iphoneos', 'iphonesimulator', configuration, PodBuilder::Configuration.deterministic_build, PodBuilder::Configuration.build_for_apple_silicon)
175
- when :osx then PodBuilder::xcodebuild(sandbox, target.cocoapods_target_label, configuration, PodBuilder::Configuration.deterministic_build, PodBuilder::Configuration.build_for_apple_silicon)
176
- when :tvos then PodBuilder::build_for_iosish_platform(sandbox, build_dir, target, 'appletvos', 'appletvsimulator', configuration, PodBuilder::Configuration.deterministic_build, PodBuilder::Configuration.build_for_apple_silicon)
177
- when :watchos then PodBuilder::build_for_iosish_platform(sandbox, build_dir, target, 'watchos', 'watchsimulator', configuration, PodBuilder::Configuration.deterministic_build, PodBuilder::Configuration.build_for_apple_silicon)
289
+ case [target.platform_name, uses_frameworks]
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)
291
+ when [:osx, true] then PodBuilder::xcodebuild(sandbox, target.cocoapods_target_label, configuration, PodBuilder::Configuration.deterministic_build, PodBuilder::Configuration.build_for_apple_silicon, {})
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)
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)
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)
178
298
  else raise "\n\nUnknown platform '#{target.platform_name}'".red end
179
- end
180
-
299
+ end
300
+
181
301
  raise Pod::Informative, 'The build directory was not found in the expected location.' unless build_dir.directory?
182
302
 
183
- 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
184
305
  Pod::UI.puts "Built #{built_count} #{'items'.pluralize(built_count)}, copying..."
185
306
 
186
307
  base_destination.rmtree if base_destination.directory?
@@ -188,20 +309,23 @@ Pod::HooksManager.register('podbuilder-rome', :post_install) do |installer_conte
188
309
  installer_context.umbrella_targets.each do |umbrella|
189
310
  umbrella.specs.each do |spec|
190
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
191
318
  # Make sure the device target overwrites anything in the simulator build, otherwise iTunesConnect
192
319
  # can get upset about Info.plist containing references to the simulator SDK
193
- frameworks = Pathname.glob("build/#{root_name}/*.framework").reject { |f| f.to_s =~ /Pods[^.]+\.framework/ }
194
-
320
+ files = Pathname.glob("build/#{root_name}/*").reject { |f| f.to_s =~ /Pods[^.]+\.framework/ }
321
+
195
322
  consumer = spec.consumer(umbrella.platform_name)
196
323
  file_accessor = Pod::Sandbox::FileAccessor.new(sandbox.pod_dir(spec.root.name), consumer)
197
- frameworks += file_accessor.vendored_libraries
198
- frameworks += file_accessor.vendored_frameworks
199
- resources = file_accessor.resources
200
-
201
- destination = File.join(base_destination, root_name)
202
- FileUtils.mkdir_p(destination)
203
-
204
- 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)
205
329
  files.each do |file|
206
330
  FileUtils.cp_r(file, destination)
207
331
  end
@@ -226,7 +350,10 @@ Pod::HooksManager.register('podbuilder-rome', :post_install) do |installer_conte
226
350
  end
227
351
 
228
352
  if enable_dsym
229
- FileUtils.mv("#{build_dir}/dSYM", sandbox_root.parent)
353
+ dsym_source = "#{build_dir}/dSYM"
354
+ if File.directory?(dsym_source)
355
+ FileUtils.mv(dsym_source, sandbox_root.parent)
356
+ end
230
357
  else
231
358
  raise "Not implemented"
232
359
  end