build_framework_task.rb 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  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. def self.verify(type)
  19. if type.nil? || (type != IOS && type != OSX && type != WATCHOS)
  20. fail "Unknown framework type. Available types: 'ios', 'osx', 'watchos'."
  21. end
  22. end
  23. end
  24. # This class adds ability to easily configure a building of iOS/OSX framework and execute the build process.
  25. class BuildFrameworkTask
  26. attr_accessor :directory
  27. attr_accessor :build_directory
  28. attr_accessor :framework_type
  29. attr_accessor :framework_name
  30. attr_accessor :workspace
  31. attr_accessor :project
  32. attr_accessor :scheme
  33. attr_accessor :configuration
  34. def initialize
  35. @directory = '.'
  36. @build_directory = './build'
  37. yield self if block_given?
  38. end
  39. def execute
  40. verify
  41. prepare_build
  42. build
  43. end
  44. private
  45. def verify
  46. FrameworkType.verify(@framework_type)
  47. end
  48. def prepare_build
  49. Dir.chdir(@directory) unless @directory.nil?
  50. end
  51. def build
  52. case @framework_type
  53. when FrameworkType::IOS
  54. build_ios_framework
  55. when FrameworkType::OSX
  56. build_osx_framework
  57. when FrameworkType::WATCHOS
  58. build_watchos_framework
  59. end
  60. end
  61. def build_ios_framework
  62. framework_paths = []
  63. framework_paths << build_framework('iphoneos')
  64. framework_paths << build_framework('iphonesimulator')
  65. final_path = final_framework_path
  66. system("rm -rf #{final_path} && cp -R #{framework_paths[0]} #{final_path}")
  67. binary_name = File.basename(@framework_name, '.framework')
  68. system("rm -rf #{final_path}/#{binary_name}")
  69. lipo_command = 'lipo -create'
  70. framework_paths.each do |path|
  71. lipo_command += " #{path}/#{binary_name}"
  72. end
  73. lipo_command += " -o #{final_path}/#{binary_name}"
  74. result = system(lipo_command)
  75. unless result
  76. puts 'Failed to lipo iOS framework.'
  77. exit(1)
  78. end
  79. result
  80. end
  81. def build_watchos_framework
  82. framework_paths = []
  83. framework_paths << build_framework('watchos')
  84. framework_paths << build_framework('watchsimulator')
  85. final_path = final_framework_path
  86. system("rm -rf #{final_path} && cp -R #{framework_paths[0]} #{final_path}")
  87. binary_name = File.basename(@framework_name, '.framework')
  88. system("rm -rf #{final_path}/#{binary_name}")
  89. lipo_command = 'lipo -create'
  90. framework_paths.each do |path|
  91. lipo_command += " #{path}/#{binary_name}"
  92. end
  93. lipo_command += " -o #{final_path}/#{binary_name}"
  94. result = system(lipo_command)
  95. unless result
  96. puts 'Failed to lipo watchOS framework.'
  97. exit(1)
  98. end
  99. result
  100. end
  101. def build_osx_framework
  102. build_path = build_framework('macosx')
  103. final_path = final_framework_path
  104. system("rm -rf #{final_path} && cp -R #{build_path} #{final_path}")
  105. end
  106. def build_framework(sdk)
  107. configuration_directory = configuration_build_directory(sdk)
  108. build_task = BuildTask.new do |t|
  109. t.directory = @directory
  110. t.project = @project
  111. t.workspace = @workspace
  112. t.scheme = @scheme
  113. t.sdk = latest_sdk(sdk)
  114. t.configuration = @configuration
  115. t.actions = [BuildAction::CLEAN, BuildAction::BUILD]
  116. t.formatter = BuildFormatter::XCPRETTY
  117. t.additional_options = { 'CONFIGURATION_BUILD_DIR' => "'#{configuration_directory}'" }
  118. end
  119. result = build_task.execute
  120. unless result
  121. puts "Failed to build framework for #{sdk}."
  122. exit(1)
  123. end
  124. "#{configuration_directory}/#{@framework_name}"
  125. end
  126. def latest_sdk(platform)
  127. sdks = Naturally.sort(`xcodebuild -showsdks`.scan(/-sdk (.*)$/)).reverse.flatten
  128. sdks.select { |s| s =~ /#{platform}/ }[0]
  129. end
  130. def configuration_build_directory(sdk)
  131. "#{@build_directory}/#{@configuration}-#{@framework_type}-#{sdk}"
  132. end
  133. def final_framework_path
  134. "#{@build_directory}/#{@framework_name}"
  135. end
  136. end
  137. end