build_framework_task.rb 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. #!/usr/bin/env ruby
  2. #
  3. # Copyright (c) 2015-present, Parse, LLC.
  4. # All rights reserved.
  5. #
  6. # This source code is licensed under the BSD-style license found in the
  7. # LICENSE file in the root directory of this source tree. An additional grant
  8. # of patent rights can be found in the PATENTS file in the same directory.
  9. #
  10. require 'naturally'
  11. require_relative 'build_task'
  12. module XCTask
  13. # This class defines all possible framework types for BuildFrameworkTask.
  14. class FrameworkType
  15. IOS = 'ios'
  16. OSX = 'osx'
  17. WATCHOS = 'watchos'
  18. TVOS = 'tvos'
  19. def self.verify(type)
  20. if type.nil? || (type != IOS && type != OSX && type != WATCHOS && type != TVOS)
  21. fail "Unknown framework type. Available types: 'ios', 'osx', 'watchos', 'tvos'."
  22. end
  23. end
  24. end
  25. # This class adds ability to easily configure a building of iOS/OSX framework and execute the build process.
  26. class BuildFrameworkTask
  27. attr_accessor :directory
  28. attr_accessor :build_directory
  29. attr_accessor :framework_type
  30. attr_accessor :framework_name
  31. attr_accessor :workspace
  32. attr_accessor :project
  33. attr_accessor :scheme
  34. attr_accessor :configuration
  35. def initialize
  36. @directory = '.'
  37. @build_directory = './build'
  38. yield self if block_given?
  39. end
  40. def execute
  41. verify
  42. prepare_build
  43. build
  44. end
  45. private
  46. def verify
  47. FrameworkType.verify(@framework_type)
  48. end
  49. def prepare_build
  50. Dir.chdir(@directory) unless @directory.nil?
  51. end
  52. def build
  53. case @framework_type
  54. when FrameworkType::IOS
  55. build_ios_framework
  56. when FrameworkType::OSX
  57. build_osx_framework
  58. when FrameworkType::WATCHOS
  59. build_watchos_framework
  60. when FrameworkType::TVOS
  61. build_tvos_framework
  62. end
  63. end
  64. def build_ios_framework
  65. framework_paths = []
  66. framework_paths << build_framework('iphoneos')
  67. framework_paths << build_framework('iphonesimulator', '"platform=iOS Simulator,name=iPhone 6s"')
  68. final_path = final_framework_path
  69. system("rm -rf #{final_path} && cp -R #{framework_paths[0]} #{final_path}")
  70. binary_name = File.basename(@framework_name, '.framework')
  71. system("rm -rf #{final_path}/#{binary_name}")
  72. lipo_command = 'lipo -create'
  73. framework_paths.each do |path|
  74. lipo_command += " #{path}/#{binary_name}"
  75. end
  76. lipo_command += " -o #{final_path}/#{binary_name}"
  77. result = system(lipo_command)
  78. unless result
  79. puts 'Failed to lipo iOS framework.'
  80. exit(1)
  81. end
  82. result
  83. end
  84. def build_watchos_framework
  85. framework_paths = []
  86. framework_paths << build_framework('watchos')
  87. framework_paths << build_framework('watchsimulator', '"platform=watchOS Simulator,name=Apple Watch - 42mm"')
  88. final_path = final_framework_path
  89. system("rm -rf #{final_path} && cp -R #{framework_paths[0]} #{final_path}")
  90. binary_name = File.basename(@framework_name, '.framework')
  91. system("rm -rf #{final_path}/#{binary_name}")
  92. lipo_command = 'lipo -create'
  93. framework_paths.each do |path|
  94. lipo_command += " #{path}/#{binary_name}"
  95. end
  96. lipo_command += " -o #{final_path}/#{binary_name}"
  97. result = system(lipo_command)
  98. unless result
  99. puts 'Failed to lipo watchOS framework.'
  100. exit(1)
  101. end
  102. result
  103. end
  104. def build_tvos_framework
  105. framework_paths = []
  106. framework_paths << build_framework('appletvos')
  107. framework_paths << build_framework('appletvsimulator', '"platform=tvOS Simulator,name=Apple TV 1080p"')
  108. final_path = final_framework_path
  109. system("rm -rf #{final_path} && cp -R #{framework_paths[0]} #{final_path}")
  110. binary_name = File.basename(@framework_name, '.framework')
  111. system("rm -rf #{final_path}/#{binary_name}")
  112. lipo_command = 'lipo -create'
  113. framework_paths.each do |path|
  114. lipo_command += " #{path}/#{binary_name}"
  115. end
  116. lipo_command += " -o #{final_path}/#{binary_name}"
  117. result = system(lipo_command)
  118. unless result
  119. puts 'Failed to lipo tvOS framework.'
  120. exit(1)
  121. end
  122. result
  123. end
  124. def build_osx_framework
  125. build_path = build_framework('macosx')
  126. final_path = final_framework_path
  127. system("rm -rf #{final_path} && cp -R #{build_path} #{final_path}")
  128. end
  129. def build_framework(sdk, destination = nil)
  130. configuration_directory = configuration_build_directory(sdk)
  131. build_task = BuildTask.new do |t|
  132. t.directory = @directory
  133. t.project = @project
  134. t.workspace = @workspace
  135. t.scheme = @scheme
  136. t.sdk = latest_sdk(sdk)
  137. t.configuration = @configuration
  138. t.destinations = [destination] unless destination.nil?
  139. t.actions = [BuildAction::CLEAN, BuildAction::BUILD]
  140. t.formatter = BuildFormatter::XCPRETTY
  141. t.additional_options = { 'CONFIGURATION_BUILD_DIR' => "'#{configuration_directory}'" }
  142. end
  143. result = build_task.execute
  144. unless result
  145. puts "Failed to build framework for #{sdk}."
  146. exit(1)
  147. end
  148. "#{configuration_directory}/#{@framework_name}"
  149. end
  150. def latest_sdk(platform)
  151. sdks = Naturally.sort(`xcodebuild -showsdks`.scan(/-sdk (.*)$/)).reverse.flatten
  152. sdks.select { |s| s =~ /#{platform}/ }[0]
  153. end
  154. def configuration_build_directory(sdk)
  155. "#{@build_directory}/#{@configuration}-#{@framework_type}-#{sdk}"
  156. end
  157. def final_framework_path
  158. "#{@build_directory}/#{@framework_name}"
  159. end
  160. end
  161. end