.build.zsh 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. #!/usr/bin/env zsh
  2. builtin emulate -L zsh
  3. setopt EXTENDED_GLOB
  4. setopt PUSHD_SILENT
  5. setopt ERR_EXIT
  6. setopt ERR_RETURN
  7. setopt NO_UNSET
  8. setopt PIPE_FAIL
  9. setopt NO_AUTO_PUSHD
  10. setopt NO_PUSHD_IGNORE_DUPS
  11. setopt FUNCTION_ARGZERO
  12. ## Enable for script debugging
  13. # setopt WARN_CREATE_GLOBAL
  14. # setopt WARN_NESTED_VAR
  15. # setopt XTRACE
  16. autoload -Uz is-at-least && if ! is-at-least 5.2; then
  17. print -u2 -PR "%F{1}${funcstack[1]##*/}:%f Running on Zsh version %B${ZSH_VERSION}%b, but Zsh %B5.2%b is the minimum supported version. Upgrade Zsh to fix this issue."
  18. exit 1
  19. fi
  20. _trap_error() {
  21. print -u2 -PR '%F{1} ✖︎ script execution error%f'
  22. print -PR -e "
  23. Callstack:
  24. ${(j:\n :)funcfiletrace}
  25. "
  26. exit 2
  27. }
  28. build() {
  29. if (( ! ${+SCRIPT_HOME} )) typeset -g SCRIPT_HOME=${ZSH_ARGZERO:A:h}
  30. local host_os=${${(s:-:)ZSH_ARGZERO:t:r}[2]}
  31. local target="${host_os}-${CPUTYPE}"
  32. local project_root=${SCRIPT_HOME:A:h:h}
  33. local buildspec_file="${project_root}/buildspec.json"
  34. trap '_trap_error' ZERR
  35. fpath=("${SCRIPT_HOME}/utils.zsh" ${fpath})
  36. autoload -Uz log_info log_error log_output set_loglevel check_${host_os} setup_${host_os} setup_obs setup_ccache
  37. if [[ ! -r ${buildspec_file} ]] {
  38. log_error \
  39. 'No buildspec.json found. Please create a build specification for your project.' \
  40. 'A buildspec.json.template file is provided in the repository to get you started.'
  41. return 2
  42. }
  43. typeset -g -a skips=()
  44. local -i _verbosity=1
  45. local -r _version='1.0.0'
  46. local -r -a _valid_targets=(
  47. macos-x86_64
  48. macos-arm64
  49. macos-universal
  50. linux-x86_64
  51. )
  52. local -r -a _valid_configs=(Debug RelWithDebInfo Release MinSizeRel)
  53. if [[ ${host_os} == 'macos' ]] {
  54. local -r -a _valid_generators=(Xcode Ninja 'Unix Makefiles')
  55. local generator="${${CI:+Ninja}:-Xcode}"
  56. } else {
  57. local -r -a _valid_generators=(Ninja 'Unix Makefiles')
  58. local generator='Ninja'
  59. }
  60. local -r _usage="
  61. Usage: %B${functrace[1]%:*}%b <option> [<options>]
  62. %BOptions%b:
  63. %F{yellow} Build configuration options%f
  64. -----------------------------------------------------------------------------
  65. %B-t | --target%b Specify target - default: %B%F{green}${host_os}-${CPUTYPE}%f%b
  66. %B-c | --config%b Build configuration - default: %B%F{green}RelWithDebInfo%f%b
  67. %B-s | --codesign%b Enable codesigning (macOS only)
  68. %B--generator%b Specify build system to generate - default: %B%F{green}Ninja%f%b
  69. Available generators:
  70. - Ninja
  71. - Unix Makefiles
  72. - Xcode (macOS only)
  73. %F{yellow} Output options%f
  74. -----------------------------------------------------------------------------
  75. %B-q | --quiet%b Quiet (error output only)
  76. %B-v | --verbose%b Verbose (more detailed output)
  77. %B--skip-[all|build|deps|unpack]%b Skip all|building OBS|checking for dependencies|unpacking dependencies
  78. %B--debug%b Debug (very detailed and added output)
  79. %F{yellow} General options%f
  80. -----------------------------------------------------------------------------
  81. %B-h | --help%b Print this usage help
  82. %B-V | --version%b Print script version information"
  83. local -a args
  84. while (( # )) {
  85. case ${1} {
  86. -t|--target|-c|--config|--generator)
  87. if (( # == 1 )) || [[ ${2:0:1} == '-' ]] {
  88. log_error "Missing value for option %B${1}%b"
  89. log_output ${_usage}
  90. exit 2
  91. }
  92. ;;
  93. }
  94. case ${1} {
  95. --)
  96. shift
  97. args+=($@)
  98. break
  99. ;;
  100. -t|--target)
  101. if (( ! ${_valid_targets[(Ie)${2}]} )) {
  102. log_error "Invalid value %B${2}%b for option %B${1}%b"
  103. log_output ${_usage}
  104. exit 2
  105. }
  106. target=${2}
  107. shift 2
  108. ;;
  109. -c|--config)
  110. if (( ! ${_valid_configs[(Ie)${2}]} )) {
  111. log_error "Invalid value %B${2}%b for option %B${1}%b"
  112. log_output ${_usage}
  113. exit 2
  114. }
  115. BUILD_CONFIG=${2}
  116. shift 2
  117. ;;
  118. -s|--codesign) CODESIGN=1; shift ;;
  119. -q|--quiet) (( _verbosity -= 1 )) || true; shift ;;
  120. -v|--verbose) (( _verbosity += 1 )); shift ;;
  121. -h|--help) log_output ${_usage}; exit 0 ;;
  122. -V|--version) print -Pr "${_version}"; exit 0 ;;
  123. --debug) _verbosity=3; shift ;;
  124. --generator)
  125. if (( ! ${_valid_generators[(Ie)${2}]} )) {
  126. log_error "Invalid value %B${2}%b for option %B${1}%b"
  127. log_output ${_usage}
  128. exit 2
  129. }
  130. generator=${2}
  131. shift 2
  132. ;;
  133. --skip-*)
  134. local _skip="${${(s:-:)1}[-1]}"
  135. local _check=(all deps unpack build)
  136. (( ${_check[(Ie)${_skip}]} )) || log_warning "Invalid skip mode %B${_skip}%b supplied"
  137. typeset -g -a skips=(${skips} ${_skip})
  138. shift
  139. ;;
  140. *) log_error "Unknown option: %B${1}%b"; log_output ${_usage}; exit 2 ;;
  141. }
  142. }
  143. set -- ${(@)args}
  144. set_loglevel ${_verbosity}
  145. check_${host_os}
  146. setup_ccache
  147. typeset -g QT_VERSION
  148. typeset -g DEPLOYMENT_TARGET
  149. typeset -g OBS_DEPS_VERSION
  150. setup_${host_os}
  151. local product_name
  152. local product_version
  153. read -r product_name product_version <<< \
  154. "$(jq -r '. | {name, version} | join(" ")' ${buildspec_file})"
  155. case ${host_os} {
  156. macos)
  157. sed -i '' \
  158. "s/project(\(.*\) VERSION \(.*\))/project(${product_name} VERSION ${product_version})/" \
  159. "${project_root}/CMakeLists.txt"
  160. ;;
  161. linux)
  162. sed -i'' \
  163. "s/project(\(.*\) VERSION \(.*\))/project(${product_name} VERSION ${product_version})/"\
  164. "${project_root}/CMakeLists.txt"
  165. ;;
  166. }
  167. setup_obs
  168. pushd ${project_root}
  169. if (( ! (${skips[(Ie)all]} + ${skips[(Ie)build]}) )) {
  170. log_info "Configuring ${product_name}..."
  171. local _plugin_deps="${project_root:h}/obs-build-dependencies/plugin-deps-${OBS_DEPS_VERSION}-qt${QT_VERSION}-${target##*-}"
  172. local -a cmake_args=(
  173. -DCMAKE_BUILD_TYPE=${BUILD_CONFIG:-RelWithDebInfo}
  174. -DQT_VERSION=${QT_VERSION}
  175. -DCMAKE_PREFIX_PATH="${_plugin_deps}"
  176. )
  177. if (( _loglevel == 0 )) cmake_args+=(-Wno_deprecated -Wno-dev --log-level=ERROR)
  178. if (( _loglevel > 2 )) cmake_args+=(--debug-output)
  179. local num_procs
  180. case ${target} {
  181. macos-*)
  182. autoload -Uz read_codesign
  183. if (( ${+CODESIGN} )) {
  184. read_codesign
  185. }
  186. cmake_args+=(
  187. -DCMAKE_FRAMEWORK_PATH="${_plugin_deps}/Frameworks"
  188. -DCMAKE_OSX_ARCHITECTURES=${${target##*-}//universal/x86_64;arm64}
  189. -DCMAKE_OSX_DEPLOYMENT_TARGET=${DEPLOYMENT_TARGET:-10.15}
  190. -DOBS_CODESIGN_LINKER=ON
  191. -DOBS_BUNDLE_CODESIGN_IDENTITY="${CODESIGN_IDENT:--}"
  192. )
  193. num_procs=$(( $(sysctl -n hw.ncpu) + 1 ))
  194. ;;
  195. linux-*)
  196. if (( ${+CI} )) {
  197. cmake_args+=(-DCMAKE_INSTALL_PREFIX=/usr -DLINUX_PORTABLE=OFF)
  198. }
  199. num_procs=$(( $(nproc) + 1 ))
  200. ;;
  201. }
  202. log_debug "Attempting to configure ${product_name} with CMake arguments: ${cmake_args}"
  203. cmake -S . -B build_${target##*-} -G ${generator} ${cmake_args}
  204. log_info "Building ${product_name}..."
  205. local -a cmake_args=()
  206. if (( _loglevel > 1 )) cmake_args+=(--verbose)
  207. if [[ ${generator} == 'Unix Makefiles' ]] cmake_args+=(--parallel ${num_procs})
  208. cmake --build build_${target##*-} --config ${BUILD_CONFIG:-RelWithDebInfo} ${cmake_args}
  209. }
  210. log_info "Installing ${product_name}..."
  211. local -a cmake_args=()
  212. if (( _loglevel > 1 )) cmake_args+=(--verbose)
  213. cmake --install build_${target##*-} --config ${BUILD_CONFIG:-RelWithDebInfo} --prefix "${project_root}/release" ${cmake_args}
  214. popd
  215. }
  216. build ${@}