Class: Pod::GDBuilder

Inherits:
Object
  • Object
show all
Defined in:
lib/cocoapods-gd/builder.rb

Instance Method Summary collapse

Constructor Details

#initialize(platform, static_installer, source_dir, static_sandbox_root, public_headers_root, spec, embedded, mangle, dynamic, config, bundle_identifier, exclude_deps) ⇒ GDBuilder

Returns a new instance of GDBuilder.



3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# File 'lib/cocoapods-gd/builder.rb', line 3

def initialize(platform, static_installer, source_dir, static_sandbox_root, public_headers_root, spec, embedded, mangle, dynamic, config, bundle_identifier, exclude_deps)
  @platform = platform
  @static_installer = static_installer
  @source_dir = source_dir
  @static_sandbox_root = static_sandbox_root
  @dynamic_sandbox_root = ""
  @public_headers_root = public_headers_root
  @spec = spec
  @embedded = embedded
  @mangle = mangle
  @dynamic = dynamic
  @config = config
  @bundle_identifier = bundle_identifier
  @exclude_deps = exclude_deps
  @file_accessors = @static_installer.pod_targets.select { |t| t.pod_name == @spec.name }.flat_map(&:file_accessors)
end

Instance Method Details

#build(gd_type) ⇒ Object



20
21
22
23
24
25
26
27
28
29
# File 'lib/cocoapods-gd/builder.rb', line 20

def build(gd_type)
  case gd_type
  when :static_library
    build_static_library
  when :static_framework
    build_static_framework
  when :dynamic_framework
    build_dynamic_framework
  end
end

#build_dynamic_frameworkObject



78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/cocoapods-gd/builder.rb', line 78

def build_dynamic_framework
  # UI.puts("Building dynamic framework #{@spec} with configuration #{@config}")

  # defines = compile
  # build_sim_libraries(defines)

  # if @bundle_identifier
  #   defines = "#{defines} PRODUCT_BUNDLE_IDENTIFIER='#{@bundle_identifier}'"
  # end

  # output = "#{@dynamic_sandbox_root}/build/#{@spec.name}.framework/#{@spec.name}"

  # # clean_directory_for_dynamic_build
  # if @platform.name == :ios
  #   build_dynamic_framework_for_ios(defines, output)
  # else
  #   build_dynamic_framework_for_mac(defines, output)
  # end

  # copy_resources
end

#build_dynamic_framework_for_ios(defines, output) ⇒ Object



100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
# File 'lib/cocoapods-gd/builder.rb', line 100

def build_dynamic_framework_for_ios(defines, output)
  # Specify frameworks to link and search paths
  linker_flags = static_linker_flags_in_sandbox
  defines = "#{defines} OTHER_LDFLAGS='$(inherited) #{linker_flags.join(' ')}'"

  # Build Target Dynamic Framework for both device and Simulator
  device_defines = "#{defines} LIBRARY_SEARCH_PATHS=\"#{Dir.pwd}/#{@static_sandbox_root}/build\" FRAMEWORK_SEARCH_PATHS=\"#{Dir.pwd}/#{@static_sandbox_root}/build\""
  device_options = ios_build_options << ' -sdk iphoneos'
  xcodebuild(device_defines, device_options, 'build', @spec.name.to_s, "#{@dynamic_sandbox_root}")

  sim_defines = "#{defines} LIBRARY_SEARCH_PATHS=\"#{Dir.pwd}/#{@static_sandbox_root}/build-sim\" ONLY_ACTIVE_ARCH=NO"

  xcodebuild(sim_defines, '-sdk iphonesimulator', 'build-sim', @spec.name.to_s, "#{@dynamic_sandbox_root}")

  # Combine architectures
  `lipo #{@dynamic_sandbox_root}/build/#{@spec.name}.framework/#{@spec.name} #{@dynamic_sandbox_root}/build-sim/#{@spec.name}.framework/#{@spec.name} -create -output #{output}`

  FileUtils.mkdir(@platform.name.to_s)
  `mv #{@dynamic_sandbox_root}/build/#{@spec.name}.framework #{@platform.name}`
  # `mv #{@dynamic_sandbox_root}/build/#{@spec.name}.framework.dSYM #{@platform.name}`
end

#build_dynamic_framework_for_mac(defines, _output) ⇒ Object



122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/cocoapods-gd/builder.rb', line 122

def build_dynamic_framework_for_mac(defines, _output)
  # Specify frameworks to link and search paths
  linker_flags = static_linker_flags_in_sandbox
  defines = "#{defines} OTHER_LDFLAGS=\"#{linker_flags.join(' ')}\""

  # Build Target Dynamic Framework for osx
  defines = "#{defines} LIBRARY_SEARCH_PATHS=\"#{Dir.pwd}/#{@static_sandbox_root}/build\""
  xcodebuild(defines, nil, 'build', @spec.name.to_s, @dynamic_sandbox_root.to_s)

  FileUtils.mkdir(@platform.name.to_s)
  `mv #{@dynamic_sandbox_root}/build/#{@spec.name}.framework #{@platform.name}`
  `mv #{@dynamic_sandbox_root}/build/#{@spec.name}.framework.dSYM #{@platform.name}`
end

#build_sim_libraries(defines) ⇒ Object



136
137
138
139
140
# File 'lib/cocoapods-gd/builder.rb', line 136

def build_sim_libraries(defines)
  if @platform.name == :ios
    xcodebuild(defines, "-sdk iphonesimulator OTHER_CFLAGS='-fembed-bitcode -Qunused-arguments'", 'build-sim')
  end
end

#build_static_frameworkObject



49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/cocoapods-gd/builder.rb', line 49

def build_static_framework
  UI.puts("Building static framework #{@spec} with configuration #{@config} with path #{Dir.pwd}")

  defines = compile
  build_sim_libraries(defines)
  create_framework
  output = @fwk.versions_path + Pathname.new(@spec.name)

  if @platform.name == :ios
    build_static_library_for_ios(output)
  else
    build_static_library_for_mac(output)
  end

  copy_headers
  copy_license
  copy_resources
end

#build_static_libraryObject



31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/cocoapods-gd/builder.rb', line 31

def build_static_library
  UI.puts("Building static library #{@spec} with configuration #{@config}")

  defines = compile
  build_sim_libraries(defines)

  platform_path = Pathname.new(@platform.name.to_s)
  platform_path.mkdir unless platform_path.exist?

  output = platform_path + "lib#{@spec.name}.a"

  if @platform.name == :ios
    build_static_library_for_ios(output)
  else
    build_static_library_for_mac(output)
  end
end

#build_static_library_for_ios(output) ⇒ Object



142
143
144
145
146
147
148
149
150
151
152
153
# File 'lib/cocoapods-gd/builder.rb', line 142

def build_static_library_for_ios(output)
  static_libs = static_libs_in_sandbox('build') + static_libs_in_sandbox('build-sim') + vendored_libraries
  static_libs = static_libs.find_all{|n| n.include? "#{@spec.name}"}

  libs = ios_architectures.map do |arch|
    library = "#{@static_sandbox_root}/build/gd-#{arch}.a"
    `libtool -arch_only #{arch} -static -o #{library} #{static_libs.join(' ')}`
    library
  end

  `lipo -create -output #{output} #{libs.join(' ')}`
end

#build_static_library_for_mac(output) ⇒ Object



155
156
157
158
# File 'lib/cocoapods-gd/builder.rb', line 155

def build_static_library_for_mac(output)
  static_libs = static_libs_in_sandbox + vendored_libraries
  `libtool -static -o #{output} #{static_libs.join(' ')}`
end

#build_with_mangling(options) ⇒ Object



160
161
162
163
164
165
166
167
168
# File 'lib/cocoapods-gd/builder.rb', line 160

def build_with_mangling(options)
  UI.puts 'Mangling symbols'
  defines = Symbols.mangle_for_pod_dependencies(@spec.name, @static_sandbox_root)
  defines << ' ' << @spec.consumer(@platform).compiler_flags.join(' ')

  UI.puts 'Building mangled framework'
  xcodebuild(defines, options)
  defines
end

#clean_directory_for_dynamic_buildObject



170
171
172
173
174
175
176
177
# File 'lib/cocoapods-gd/builder.rb', line 170

def clean_directory_for_dynamic_build
  # Remove static headers to avoid duplicate declaration conflicts
  FileUtils.rm_rf("#{@static_sandbox_root}/Headers/Public/#{@spec.name}")
  FileUtils.rm_rf("#{@static_sandbox_root}/Headers/Private/#{@spec.name}")

  # Equivalent to removing derrived data
  FileUtils.rm_rf('Pods/build')
end

#compileObject



179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
# File 'lib/cocoapods-gd/builder.rb', line 179

def compile
  defines = "GCC_PREPROCESSOR_DEFINITIONS='$(inherited) PodsDummy_Pods_#{@spec.name}=PodsDummy_PodGd_#{@spec.name}'"
  defines << ' ' << @spec.consumer(@platform).compiler_flags.join(' ')

  if @platform.name == :ios
    options = ios_build_options
  end
  xcodebuild(defines, options)

  if @mangle
    return build_with_mangling(options)
  end

  defines
end

#copy_headersObject



195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
# File 'lib/cocoapods-gd/builder.rb', line 195

def copy_headers
  headers_source_root = "#{@public_headers_root}/#{@spec.name}"
  Dir.glob("#{headers_source_root}/**/*.h").
    each { |h| `ditto #{h} #{@fwk.headers_path}/#{h.sub(headers_source_root, '')}` }

  swift_path="#{Dir.pwd}/Pods/build/Swift Compatibility Header/#{@spec.name}-Swift.h"
  if File.exist?("#{swift_path}")
    FileUtils.cp("#{swift_path}", "#{Dir.pwd}/ios/#{@spec.name}.framework/Headers/#{@spec.name}-Swift.h")

    modules_path = "#{Dir.pwd}/ios/#{@spec.name}.framework/Modules"
    FileUtils.mkdir_p(modules_path) unless File.exists?(modules_path)
    FileUtils.cp_r("#{Dir.pwd}/Pods/build/#{@spec.name}.swiftmodule/.", "#{modules_path}/#{@spec.name}.swiftmodule")
    FileUtils.cp_r("#{Dir.pwd}/Pods/build-sim/#{@spec.name}.swiftmodule/.", "#{modules_path}/#{@spec.name}.swiftmodule")
    modulemap = <<MAP
framework module #{@spec.name} {
  umbrella header "#{@spec.name}-umbrella.h"

  export *
  module * { export * }
}
module #{@spec.name}.Swift {
header "#{@spec.name}-Swift.h"
requires objc
}
MAP

  File.write("#{modules_path}/module.modulemap", modulemap)
  else
  # If custom 'module_map' is specified add it to the framework distribution
  # otherwise check if a header exists that is equal to 'spec.name', if so
  # create a default 'module_map' one using it.
  if !@spec.module_map.nil?
    module_map_file = @file_accessors.flat_map(&:module_map).first
    module_map = File.read(module_map_file) if Pathname(module_map_file).exist?
  elsif File.exist?("#{@public_headers_root}/#{@spec.name}/#{@spec.name}.h")
    module_map = <<MAP
framework module #{@spec.name} {
  umbrella header "#{@spec.name}.h"

  export *
  module * { export * }
}
MAP
  end

  unless module_map.nil?
    @fwk.module_map_path.mkpath unless @fwk.module_map_path.exist?
    File.write("#{@fwk.module_map_path}/module.modulemap", module_map)
  end
end
end

#copy_licenseObject



247
248
249
250
251
# File 'lib/cocoapods-gd/builder.rb', line 247

def copy_license
  license_file = @spec.license[:file] || 'LICENSE'
  license_file = Pathname.new("#{@static_sandbox_root}/#{@spec.name}/#{license_file}")
  FileUtils.cp(license_file, '.') if license_file.exist?
end

#copy_modulemapObject



334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
# File 'lib/cocoapods-gd/builder.rb', line 334

def copy_modulemap
  path="#{Dir.pwd}/Pods/Headers/Public/"
  FileUtils.mkdir_p(path) unless File.exists?(path)
  list=Dir.entries("#{path}")

  list.each_index do |x|
    if list[x].include?(".")
    else
    modulemap_soure_dir = "#{path}#{list[x]}/#{list[x]}"

    directory_name = "#{Dir.pwd}/build/Release-iphoneos/#{list[x]}"
    FileUtils.mkdir_p(directory_name) unless File.exists?(directory_name)
    modulemap_target_dir = "#{directory_name}/#{list[x]}"

    directory_iphonesimulator = "#{Dir.pwd}/build/Release-iphonesimulator/#{list[x]}"
    FileUtils.mkdir_p(directory_iphonesimulator) unless File.exists?(directory_iphonesimulator)
    modulemap_target_iphonesimulator = "#{directory_iphonesimulator}/#{list[x]}"

    if File.exist?("#{modulemap_soure_dir}.modulemap")
      FileUtils.cp("#{modulemap_soure_dir}.modulemap", "#{modulemap_target_dir}.modulemap")
      FileUtils.cp("#{modulemap_soure_dir}.modulemap", "#{modulemap_target_iphonesimulator}.modulemap")
    end

    if File.exist?("#{modulemap_soure_dir}-umbrella.h")
      FileUtils.cp("#{modulemap_soure_dir}-umbrella.h", "#{modulemap_target_dir}-umbrella.h")
      FileUtils.cp("#{modulemap_soure_dir}-umbrella.h", "#{modulemap_target_iphonesimulator}-umbrella.h")
    end
    end
  end    
end

#copy_resourcesObject



253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
# File 'lib/cocoapods-gd/builder.rb', line 253

def copy_resources
  bundles = Dir.glob("#{@static_sandbox_root}/build/*.bundle")
  if @dynamic
    resources_path = "ios/#{@spec.name}.framework"
    `cp -rp #{@static_sandbox_root}/build/*.bundle #{resources_path} 2>&1`
  else
    `cp -rp #{@static_sandbox_root}/build/*.bundle #{@fwk.resources_path} 2>&1`
    resources = expand_paths(@spec.consumer(@platform).resources)
    if resources.count == 0 && bundles.count == 0
      @fwk.delete_resources
      return
    end
    if resources.count > 0
      `cp -rp #{resources.join(' ')} #{@fwk.resources_path}`
    end
    
    bundle_path="#{Dir.pwd}/ios/#{@spec.name}.framework/Resources/#{@spec.name}.bundle"
    if File.exist?(bundle_path)
      FileUtils.mv(bundle_path, "#{Dir.pwd}/ios/#{@spec.name}.bundle")
    end
  end
end

#create_frameworkObject



276
277
278
279
# File 'lib/cocoapods-gd/builder.rb', line 276

def create_framework
  @fwk = Framework::Tree.new(@spec.name, @platform.name.to_s, @embedded)
  @fwk.make
end

#dependency_countObject



281
282
283
284
285
286
287
288
289
# File 'lib/cocoapods-gd/builder.rb', line 281

def dependency_count
  count = @spec.dependencies.count

  @spec.subspecs.each do |subspec|
    count += subspec.dependencies.count
  end

  count
end

#expand_paths(path_specs) ⇒ Object



291
292
293
294
295
# File 'lib/cocoapods-gd/builder.rb', line 291

def expand_paths(path_specs)
  path_specs.map do |path_spec|
    Dir.glob(File.join(@source_dir, path_spec))
  end
end

#ios_architecturesObject



365
366
367
368
369
370
371
# File 'lib/cocoapods-gd/builder.rb', line 365

def ios_architectures
  archs = %w(x86_64 i386 arm64 armv7 armv7s)
  vendored_libraries.each do |library|
    archs = `lipo -info #{library}`.split & archs
  end
  archs
end

#ios_build_optionsObject



330
331
332
# File 'lib/cocoapods-gd/builder.rb', line 330

def ios_build_options
  "ARCHS=\'#{ios_architectures.join(' ')}\' OTHER_CFLAGS=\'-fembed-bitcode -Qunused-arguments\'"
end


68
69
70
71
72
73
74
75
76
# File 'lib/cocoapods-gd/builder.rb', line 68

def link_embedded_resources
  target_path = @fwk.root_path + Pathname.new('Resources')
  target_path.mkdir unless target_path.exist?

  Dir.glob(@fwk.resources_path.to_s + '/*').each do |resource|
    resource = Pathname.new(resource).relative_path_from(target_path)
    `ln -sf #{resource} #{target_path}`
  end
end

#static_libs_in_sandbox(build_dir = 'build') ⇒ Object



297
298
299
300
301
302
303
304
# File 'lib/cocoapods-gd/builder.rb', line 297

def static_libs_in_sandbox(build_dir = 'build')
  if @exclude_deps
    UI.puts 'Excluding dependencies'
    Dir.glob("#{@static_sandbox_root}/#{build_dir}/lib#{@spec.name}.a")
  else
    Dir.glob("#{@static_sandbox_root}/#{build_dir}/lib*.a")
  end
end

#static_linker_flags_in_sandboxObject



321
322
323
324
325
326
327
328
# File 'lib/cocoapods-gd/builder.rb', line 321

def static_linker_flags_in_sandbox
  linker_flags = static_libs_in_sandbox.map do |lib|
    lib.slice!('lib')
    lib_flag = lib.chomp('.a').split('/').last
    "-l#{lib_flag}"
  end
  linker_flags.reject { |e| e == "-l#{@spec.name}" || e == '-lPods-gd' }
end

#vendored_librariesObject



306
307
308
309
310
311
312
313
314
315
316
317
318
319
# File 'lib/cocoapods-gd/builder.rb', line 306

def vendored_libraries
  if @vendored_libraries
    @vendored_libraries
  end
  file_accessors = if @exclude_deps
                     @file_accessors
                   else
                     @static_installer.pod_targets.flat_map(&:file_accessors)
                   end
  libs = file_accessors.flat_map(&:vendored_static_frameworks).map { |f| f + f.basename('.*') } || []
  libs += file_accessors.flat_map(&:vendored_static_libraries)
  @vendored_libraries = libs.compact.map(&:to_s)
  @vendored_libraries
end

#xcodebuild(defines = '', args = '', build_dir = 'build', target = 'Pods-gd', project_root = @static_sandbox_root, config = @config) ⇒ Object



373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
# File 'lib/cocoapods-gd/builder.rb', line 373

def xcodebuild(defines = '', args = '', build_dir = 'build', target = 'Pods-gd', project_root = @static_sandbox_root, config = @config)
  if defined?(Pod::DONT_CODESIGN)
    args = "#{args} CODE_SIGN_IDENTITY=\"\" CODE_SIGNING_REQUIRED=NO"
  end
  command = "xcodebuild #{defines} #{args} CONFIGURATION_BUILD_DIR=#{build_dir} clean build -UseModernBuildSystem=NO -configuration #{config} -target #{target} -project #{project_root}/Pods.xcodeproj 2>&1"
  copy_modulemap
  output = `#{command}`.lines.to_a

  if $?.exitstatus != 0
    puts UI::BuildFailedReport.report(command, output)

    # Note: We use `Process.exit` here because it fires a `SystemExit`
    # exception, which gives the caller a chance to clean up before the
    # process terminates.
    #
    # See http://ruby-doc.org/core-1.9.3/Process.html#method-c-exit
    Process.exit
  end
end