build_framework_task.rb 5.5 KB

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