media-suite_helper.sh 82 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522
  1. #!/bin/bash
  2. # shellcheck disable=SC2154,SC2120,SC2119,SC2034,SC1090,SC1117,SC2030,SC2031
  3. if [[ ! $cpuCount =~ ^[0-9]+$ ]]; then
  4. cpuCount=$(($(nproc) / 2))
  5. fi
  6. : "${bits:=64bit}"
  7. curl_opts=(/usr/bin/curl --connect-timeout 15 --retry 3
  8. --retry-delay 5 --silent --location --insecure --fail)
  9. if test -n "$(tput colors)" && test "$(tput colors)" -ge 8; then
  10. bold=$(tput bold)
  11. blue=$(tput setaf 12)
  12. orange=$(tput setaf 11)
  13. purple=$(tput setaf 13)
  14. green=$(tput setaf 2)
  15. red=$(tput setaf 1)
  16. reset=$(tput sgr0)
  17. fi
  18. ncols=72
  19. [[ -f "$LOCALBUILDDIR"/grep.exe ]] &&
  20. rm -f "$LOCALBUILDDIR"/{7za,wget,grep}.exe
  21. do_simple_print() {
  22. local plain=false formatString dateValue newline='\n' OPTION OPTIND
  23. while getopts ':np' OPTION; do
  24. case "$OPTION" in
  25. n) newline='' ;;
  26. p) plain=true ;;
  27. *) break ;;
  28. esac
  29. done
  30. shift "$((OPTIND - 1))"
  31. if [[ $timeStamp == y ]]; then
  32. formatString="${purple}"'%(%H:%M:%S)T'"${reset}"' '
  33. dateValue='-1'
  34. elif $plain; then
  35. formatString='\t'
  36. fi
  37. if ! $plain; then
  38. formatString+="${bold}├${reset} "
  39. fi
  40. printf "$formatString"'%b'"${reset}${newline}" $dateValue "$*"
  41. }
  42. do_print_status() {
  43. local _prefix _prefixpad=0
  44. if [[ $1 == prefix ]]; then
  45. _prefix="$2" && shift 2
  46. _prefixpad=2
  47. fi
  48. local name="$1 " color="$2" status="$3" pad
  49. eval printf -v pad ".%.s" "{1..$ncols}"
  50. if [[ $timeStamp == y ]]; then
  51. printf "${purple}"'%(%H:%M:%S)T'"${reset}"' %s%s %s [%s]\n' -1 "$_prefix" "${bold}$name${reset}" \
  52. "${pad:0:$((ncols - _prefixpad - ${#name} - ${#status} - 12))}" "${color}${status}${reset}"
  53. else
  54. printf '%s%s %s [%s]\n' "$_prefix" "${bold}$name${reset}" \
  55. "${pad:0:$((ncols - _prefixpad - ${#name} - ${#status} - 2))}" "${color}${status}${reset}"
  56. fi
  57. }
  58. do_print_progress() {
  59. case $logging$timeStamp in
  60. yy) printf "${purple}"'%(%H:%M:%S)T'"${reset}"' %s\n' -1 "$([[ $1 =~ ^[a-zA-Z] ]] && echo "${bold}├${reset} ")$*..." ;;
  61. yn)
  62. [[ $1 =~ ^[a-zA-Z] ]] &&
  63. printf '%s' "${bold}├${reset} "
  64. echo -e "$*..."
  65. ;;
  66. *)
  67. set_title "$* in $(get_first_subdir)"
  68. if [[ $timeStamp == y ]]; then
  69. printf "${purple}"'%(%H:%M:%S)T'"${reset}"' %s\n' -1 "${bold}$* in $(get_first_subdir)${reset}"
  70. else
  71. echo -e "${bold}$* in $(get_first_subdir)${reset}"
  72. fi
  73. ;;
  74. esac
  75. }
  76. set_title() {
  77. printf '\033]0;media-autobuild_suite %s\a' "($bits)${1:+: $1}"
  78. }
  79. do_exit_prompt() {
  80. if [[ -n $build32$build64 ]]; then # meaning "executing this in the suite's context"
  81. create_diagnostic
  82. zip_logs
  83. fi
  84. do_prompt "$*"
  85. [[ -n $build32$build64 ]] && exit 1
  86. }
  87. cd_safe() {
  88. cd "$1" || do_exit_prompt "Failed changing to directory $1."
  89. }
  90. test_newer() {
  91. [[ $1 == installed ]] && local installed=y && shift
  92. local file
  93. local files=("$@")
  94. local cmp="${files[-1]}"
  95. [[ $installed ]] && cmp="$(file_installed "$cmp")"
  96. [[ ${#files[@]} -gt 1 ]] && unset 'files[-1]'
  97. [[ -f $cmp ]] || return 0
  98. for file in "${files[@]}"; do
  99. [[ $installed ]] && file="$(file_installed "$file")"
  100. [[ -f $file ]] &&
  101. [[ $file -nt $cmp ]] && return
  102. done
  103. return 1
  104. }
  105. # vcs_get_default_ref git
  106. vcs_get_default_ref() {
  107. case ${1:-$(vcs_get_current_type)} in
  108. git) echo "origin/HEAD" ;;
  109. svn) echo "HEAD" ;;
  110. hg) echo "default" ;;
  111. *) echo "unknown" && return 1 ;;
  112. esac
  113. }
  114. # vcs_get_current_type /build/myrepo
  115. vcs_get_current_type() (
  116. cd "${1:-$(get_first_subdir -f)}" 2> /dev/null || return 1
  117. for file in .*; do
  118. case $file in
  119. \.git) git rev-parse --is-inside-work-tree > /dev/null 2>&1 && echo "git" ;;
  120. \.hg) hg id --id > /dev/null 2>&1 && echo "hg" ;;
  121. \.svn) svn info --depth empty > /dev/null 2>&1 && echo "svn" ;;
  122. *) false ;;
  123. esac && return 0
  124. done
  125. echo "unknown"
  126. return 1
  127. )
  128. # check_valid_vcs /build/ffmpeg-git git
  129. check_valid_vcs() {
  130. case ${2:-$(vcs_get_current_type "${1:-$PWD}")} in
  131. git) [[ -d ${1:-$PWD}/.git ]] ;; # && git -C "${1:-$PWD}" fsck --no-progress ;;
  132. hg) [[ -d ${1:-$PWD}/.hg ]] ;; # && hg verify -q ;;
  133. svn) [[ -d ${1:-$PWD}/.svn ]] ;;
  134. *) return 1 ;;
  135. esac
  136. }
  137. # vcs_get_current_head /build/ffmpeg-git git
  138. vcs_get_current_head() {
  139. case ${2:-$(vcs_get_current_type "$1")} in
  140. git) git -C "${1:-$PWD}" rev-parse HEAD ;;
  141. hg) hg -R "${1:-$PWD}" identify --id ;;
  142. svn) svn info --show-item last-changed-revision "${1:-$PWD}" ;;
  143. *) return 1 ;;
  144. esac
  145. }
  146. # vcs_test_remote "svn://svn.mplayerhq.hu/mplayer/trunk" svn
  147. vcs_test_remote() {
  148. case $2 in # Need to find a good way to detect remote vcs type. GitHub provides svn and git from the same url.
  149. git) GIT_TERMINAL_PROMPT=0 git ls-remote -q --refs "$1" > /dev/null 2>&1 ;;
  150. hg) hg --noninteractive identify "$1" > /dev/null 2>&1 ;;
  151. svn) svn --non-interactive ls "$1" > /dev/null 2>&1 ;;
  152. *) return 1 ;;
  153. esac
  154. }
  155. # vcs_clone https://gitlab.com/libtiff/libtiff.git tiff v4.1.0
  156. vcs_clone() (
  157. set -x
  158. vcsURL=$1 vcsFolder=$2 ref=$3 vcsType=${4:-git}
  159. [[ -z $vcsURL ]] && return 1
  160. : "${vcsFolder:=$(basename "$vcsURL" .git)}" "${ref:=$(vcs_get_default_ref "$vcsType")}"
  161. check_valid_vcs "$vcsFolder-$vcsType" "$vcsType" && return 0
  162. rm -rf "$vcsFolder-$vcsType"
  163. case $vcsType in
  164. git)
  165. case $- in
  166. *i*) unset GIT_TERMINAL_PROMPT ;;
  167. *) export GIT_TERMINAL_PROMPT=0 ;;
  168. esac
  169. git clone "$vcsURL" "$vcsFolder-git"
  170. git -C "$vcsFolder-git" reset --hard "$ref"
  171. ;;
  172. hg) hg --noninteractive clone -u "$ref" "$vcsURL" "$vcsFolder-hg" ;;
  173. svn) svn --non-interactive checkout -r "$ref" "$vcsURL" "$vcsFolder-svn" ;;
  174. *) return 1 ;;
  175. esac
  176. check_valid_vcs "$vcsFolder-$vcsType" "$vcsType"
  177. )
  178. vcs_reset() (
  179. set -x
  180. case ${2:-$(vcs_get_current_type)} in
  181. git)
  182. git config remote.origin.url > /dev/null 2>&1 ||
  183. [[ -n $vcsURL ]] && git remote set-url origin "$vcsURL"
  184. git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*"
  185. git checkout --no-track -fB ab-suite
  186. git reset --hard "$(vcs_get_latest_tag "$1" git)"
  187. ;;
  188. hg) hg update -C -r "$1" ;;
  189. svn) svn revert --recursive . ;;
  190. *) return 1 ;;
  191. esac
  192. )
  193. vcs_update() (
  194. set -x
  195. case ${2:-$(vcs_get_current_type)} in
  196. git)
  197. [[ -f $(git rev-parse --git-dir)/shallow ]] && unshallow="--unshallow" || unshallow=''
  198. git fetch -t $unshallow origin
  199. git reset --hard "$(vcs_get_latest_tag "$1" git)"
  200. ;;
  201. hg)
  202. hg pull
  203. hg update -C -r "$1"
  204. ;;
  205. svn) svn update -r "$1" ;;
  206. *) return 1 ;;
  207. esac
  208. )
  209. # vcs_log d4996a600ca0334235a4b66beae5b5c3474535c4 81172b5e3ac0d3130ff7b639ed7efed5baa1195c
  210. # Defaults to last 5 commits
  211. vcs_log() {
  212. case ${3:-$(vcs_get_current_type)} in
  213. git) git log --no-merges --pretty="%ci: %an - %h%n %s" "${1:-HEAD~5}".."${2:-HEAD}" ;;
  214. hg) hg log --template '{date|localdate|isodatesec}: {author|person} - {node|short}\n {desc|firstline}\n' \
  215. -r "reverse(${1:--5}:${2:-tip})" ;;
  216. svn) ;; # No easy way to generate a svn changelog with the same format. Plus it's really only mplayer.
  217. # Maybe use svn log --xml and format xml
  218. *) return 1 ;;
  219. esac
  220. }
  221. # vcs_get_latest_tag "libopenmpt-*"
  222. vcs_get_latest_tag() (
  223. if ! case ${2:-$(vcs_get_current_type)}/${1:-unknown} in
  224. git/LATEST) git describe --abbrev=0 --tags "$(git rev-list --tags --max-count=1)" 2> /dev/null ;;
  225. git/GREATEST) git describe --abbrev=0 --tags 2> /dev/null ;;
  226. git/*\**) git describe --abbrev=0 --tags "$(git tag -l "$1" --sort=-version:refname | head -1)" 2> /dev/null ;;
  227. *) false ;;
  228. esac then
  229. echo "$1"
  230. fi
  231. )
  232. # do_mabs_clone "$vcsURL" "$vcsFolder" "$ref" "$vcsType"
  233. # For internal use for fallback links
  234. do_mabs_clone() {
  235. {
  236. vcs_test_remote "$1" "$4" &&
  237. log -qe "$4.clone" vcs_clone "$1" "$2" "$3" "$4"
  238. } || {
  239. vcs_test_remote "https://gitlab.com/m-ab-s/${1##*/}" git &&
  240. log -qe "$4.clone" vcs_clone "https://gitlab.com/m-ab-s/${1##*/}" "$2" "$3" git
  241. }
  242. check_valid_vcs "$2-$4" "$4"
  243. }
  244. # get source from VCS
  245. # example:
  246. # do_vcs "url#branch|revision|tag|commit=NAME" "folder"
  247. do_vcs() {
  248. local vcsType="${1%::*}" vcsURL="${1#*::}" vcsFolder="$2" vcsCheck=("${_check[@]}")
  249. local vcsBranch="${vcsURL#*#}" ref
  250. local deps=("${_deps[@]}") && unset _deps
  251. [[ $vcsType == "$vcsURL" ]] && vcsType="git"
  252. [[ $vcsBranch == "$vcsURL" ]] && vcsBranch=""
  253. ref=$(vcs_get_default_ref "$vcsType")
  254. vcsURL="${vcsURL%#*}"
  255. : "${vcsFolder:=$(basename "$vcsURL" .git)}"
  256. if [[ -n $vcsBranch ]]; then
  257. ref=${vcsBranch##*=}
  258. [[ $vcsType/${vcsBranch%%=*}/$ref == git/branch/${ref%/*} ]] && ref=origin/$ref
  259. fi
  260. cd_safe "$LOCALBUILDDIR"
  261. if ! check_valid_vcs "$vcsFolder-$vcsType" "$vcsType"; then
  262. rm -rf "$vcsFolder-$vcsType"
  263. do_print_progress " Running $vcsType clone for $vcsFolder"
  264. if do_mabs_clone "$vcsURL" "$vcsFolder" "$ref" "$vcsType"; then
  265. touch "$vcsFolder-$vcsType"/recently_{updated,checked}
  266. else
  267. echo "$vcsFolder $vcsType seems to be down"
  268. echo "Try again later or <Enter> to continue"
  269. do_prompt "if you're sure nothing depends on it."
  270. return
  271. fi
  272. fi
  273. cd_safe "$vcsFolder-$vcsType"
  274. if [[ $ffmpegUpdate == onlyFFmpeg && $vcsFolder != ffmpeg && $vcsFolder != mpv ]] &&
  275. files_exist "${vcsCheck[@]:-$vcsFolder.pc}"; then
  276. do_print_status "${vcsFolder} ${vcsType}" "$green" "Already built"
  277. return 1
  278. fi
  279. log -q "$vcsType.reset" vcs_reset "$ref"
  280. oldHead=$(vcs_get_current_head "$PWD" "$vcsType")
  281. if ! [[ -f recently_checked && recently_checked -nt "$LOCALBUILDDIR"/last_run ]]; then
  282. do_print_progress " Running $vcsType update for $vcsFolder"
  283. log -q "$vcsType.update" vcs_update "$ref"
  284. newHead=$(vcs_get_current_head "$PWD" "$vcsType")
  285. touch recently_checked
  286. else
  287. newHead="$oldHead"
  288. fi
  289. rm -f custom_updated
  290. check_custom_patches
  291. if [[ $oldHead != "$newHead" || -f custom_updated ]]; then
  292. touch recently_updated
  293. rm -f ./build_successful{32,64}bit{,_*}
  294. if [[ $build32$build64$bits == yesyes64bit ]]; then
  295. new_updates="yes"
  296. new_updates_packages="$new_updates_packages [$vcsFolder]"
  297. fi
  298. {
  299. echo "$vcsFolder"
  300. vcs_log "$oldHead" "$newHead"
  301. echo
  302. } >> "$LOCALBUILDDIR"/newchangelog
  303. do_print_status "┌ ${vcsFolder} ${vcsType}" "$orange" "Updates found"
  304. elif [[ -f recently_updated ]] &&
  305. [[ ! -f build_successful$bits || -n $flavor && ! -f build_successful${bits}_${flavor} ]]; then
  306. do_print_status "┌ ${vcsFolder} ${vcsType}" "$orange" "Recently updated"
  307. elif [[ -n ${vcsCheck[*]} ]] && ! files_exist "${vcsCheck[@]}"; then
  308. do_print_status "┌ ${vcsFolder} ${vcsType}" "$orange" "Files missing"
  309. elif [[ -n ${deps[*]} ]] && test_newer installed "${deps[@]}" "${vcsCheck[0]}"; then
  310. do_print_status "┌ ${vcsFolder} ${vcsType}" "$orange" "Newer dependencies"
  311. else
  312. do_print_status "${vcsFolder} ${vcsType}" "$green" "Up-to-date"
  313. [[ ! -f recompile ]] &&
  314. return 1
  315. do_print_status "┌ ${vcsFolder} ${vcsType}" "$orange" "Forcing recompile"
  316. do_print_status prefix "${bold}├${reset} " "Found recompile flag" "$orange" "Recompiling"
  317. fi
  318. return 0
  319. }
  320. guess_dirname() {
  321. expr "$1" : '\(.\+\)\.\(tar\(\.\(gz\|bz2\|xz\)\)\?\|7z\|zip\)$'
  322. }
  323. check_hash() {
  324. local file="$1" check="$2" md5sum sha256sum
  325. if [[ -z $file || ! -f $file ]]; then
  326. return 1
  327. elif [[ -z $check ]]; then
  328. # if no hash to check, just check if the file exists
  329. return 0
  330. fi
  331. sha256sum=$(sha256sum "$file" | cut -d' ' -f1)
  332. if [[ $check == print ]]; then
  333. echo "$sha256sum"
  334. else
  335. md5sum=$(md5sum "$file" | cut -d' ' -f1)
  336. if [[ $sha256sum == "$check" || $md5sum == "$check" ]]; then
  337. return 0
  338. fi
  339. do_simple_print "${orange}Hash mismatch, file may be broken: ${check} != ${sha256sum} || ${md5sum}"
  340. return 1
  341. fi
  342. }
  343. # get wget download
  344. do_wget() {
  345. local nocd=false norm=false quiet=false notmodified=false hash
  346. while true; do
  347. case $1 in
  348. -c) nocd=true && shift ;;
  349. -r) norm=true && shift ;;
  350. -q) quiet=true && shift ;;
  351. -h) hash="$2" && shift 2 ;;
  352. -z) notmodified=true && shift ;;
  353. --)
  354. shift
  355. break
  356. ;;
  357. *) break ;;
  358. esac
  359. done
  360. local url="$1" archive="$2" dirName="$3" response_code=000 curlcmds=("${curl_opts[@]}") tries=1 temp_file
  361. if [[ -z $archive ]]; then
  362. # remove arguments and filepath
  363. archive=${url%%\?*}
  364. archive=${archive##*/}
  365. fi
  366. if [[ -f $url ]]; then
  367. return 1
  368. fi
  369. archive=${archive:-"$(/usr/bin/curl -sI "$url" | grep -Eo 'filename=.*$' | sed 's/filename=//')"}
  370. [[ -z $dirName ]] && dirName=$(guess_dirname "$archive")
  371. $nocd || cd_safe "$LOCALBUILDDIR"
  372. $notmodified && [[ -f $archive ]] && curlcmds+=(-z "$archive" -R)
  373. [[ $hash ]] && tries=3
  374. if [[ -f $archive ]] && [[ $hash ]] && check_hash "$archive" "$hash"; then
  375. $quiet || do_print_status prefix "${bold}├${reset} " "${dirName:-$archive}" "$green" "File up-to-date"
  376. tries=0
  377. fi
  378. while [[ $tries -gt 0 ]]; do
  379. temp_file=$(mktemp)
  380. response_code=$("${curlcmds[@]}" -w "%{http_code}" -o "$temp_file" "$url")
  381. if [[ -f $archive ]] && diff -q "$archive" "$temp_file" > /dev/null 2>&1; then
  382. $quiet || do_print_status prefix "${bold}├${reset} " "${dirName:-$archive}" "$green" "File up-to-date"
  383. rm -f "$temp_file"
  384. break
  385. fi
  386. ((tries -= 1))
  387. case $response_code in
  388. 2**)
  389. $quiet || do_print_status "┌ ${dirName:-$archive}" "$orange" "Downloaded"
  390. check_hash "$temp_file" "$hash" && cp -f "$temp_file" "$archive"
  391. rm -f "$temp_file"
  392. break
  393. ;;
  394. 304)
  395. $quiet || do_print_status "┌ ${dirName:-$archive}" "$orange" "File up-to-date"
  396. rm -f "$temp_file"
  397. break
  398. ;;
  399. esac
  400. if check_hash "$archive" "$hash"; then
  401. printf '%b\n' "${orange}${archive}${reset}" \
  402. '\tFile not found online. Using local copy.'
  403. else
  404. do_print_status "└ ${dirName:-$archive}" "$red" "Failed"
  405. printf '%s\n' "Error $response_code while downloading $url" \
  406. "<Ctrl+c> to cancel build or <Enter> to continue"
  407. do_prompt "if you're sure nothing depends on it."
  408. rm -f "$temp_file"
  409. return 1
  410. fi
  411. done
  412. $norm || add_to_remove "$(pwd)/$archive"
  413. do_extract "$archive" "$dirName"
  414. ! $norm && [[ -n $dirName ]] && ! $nocd && add_to_remove
  415. [[ -z $response_code || $response_code != "304" ]] && return 0
  416. }
  417. real_extract() {
  418. local archive="$1" dirName="$2" archive_type
  419. [[ -z $archive ]] && return 1
  420. archive_type=$(expr "$archive" : '.\+\(tar\(\.\(gz\|bz2\|xz\)\)\?\|7z\|zip\)$')
  421. [[ ! $dirName ]] && dirName=$(guess_dirname "$archive" || echo "${archive}")
  422. case $archive_type in
  423. zip | 7z)
  424. 7z x -aoa -o"$dirName" "$archive"
  425. ;;
  426. tar*)
  427. [[ -n $dirName && ! -d $dirName ]] && mkdir -p "$dirName"
  428. [[ $archive_type == tar.* ]] && 7z x -aoa "$archive"
  429. [[ $(tar -tf "$archive" | cut -d'/' -f1 | sort -u | wc -l) == 1 ]] && strip_comp="--strip-components=1"
  430. if ! tar $strip_comp -C "$dirName" -xf "${1%.tar*}.tar"; then
  431. 7z x -aoa "${archive%.tar*}.tar" -o"$dirName"
  432. fi
  433. rm -f "${archive%.tar*}.tar"
  434. ;;
  435. esac
  436. local temp_dir
  437. temp_dir=$(find "$dirName/" -maxdepth 1 ! -wholename "$dirName/")
  438. if [[ -n $temp_dir && $(wc -l <<< "$temp_dir") == 1 ]]; then
  439. find "$temp_dir" -maxdepth 1 ! -wholename "$temp_dir" -exec mv -t "$dirName/" {} +
  440. rmdir "$temp_dir" 2> /dev/null
  441. fi
  442. }
  443. do_extract() {
  444. local nocd="${nocd:-false}"
  445. local archive="$1" dirName="$2"
  446. # accepted: zip, 7z, tar, tar.gz, tar.bz2 and tar.xz
  447. [[ -z $dirName ]] && dirName=$(guess_dirname "$archive")
  448. if [[ $dirName != "." && -d $dirName ]]; then
  449. if [[ $build32 == "yes" ]] &&
  450. [[ ! -f "$dirName"/build_successful32bit || -n $flavor && ! -f "$dirName/build_successful32bit_${flavor}" ]]; then
  451. rm -rf "$dirName"
  452. elif [[ $build64 == "yes" ]] &&
  453. [[ ! -f "$dirName"/build_successful64bit || -n $flavor && ! -f "$dirName/build_successful64bit_${flavor}" ]]; then
  454. rm -rf "$dirName"
  455. fi
  456. elif [[ -d $dirName ]]; then
  457. $nocd || cd_safe "$dirName"
  458. return 0
  459. elif ! expr "$archive" : '.\+\(tar\(\.\(gz\|bz2\|xz\)\)\?\|7z\|zip\)$' > /dev/null; then
  460. return 0
  461. fi
  462. log "extract" real_extract "$archive" "$dirName"
  463. $nocd || cd_safe "$dirName"
  464. }
  465. do_wget_sf() {
  466. # do_wget_sf "faac/faac-src/faac-1.28/faac-$_ver.tar.bz2" "faac-$_ver"
  467. local hash
  468. [[ $1 == "-h" ]] && hash="$2" && shift 2
  469. local url="https://download.sourceforge.net/$1"
  470. shift 1
  471. check_custom_patches
  472. if [[ -n $hash ]]; then
  473. do_wget -h "$hash" "$url" "$@"
  474. else
  475. do_wget "$url" "$@"
  476. fi
  477. }
  478. do_strip() {
  479. local cmd exts nostrip file
  480. local cmd=(strip)
  481. local nostrip="x265|x265-numa|ffmpeg|ffprobe|ffplay"
  482. local exts="exe|dll|com|a"
  483. [[ -f $LOCALDESTDIR/bin-video/mpv.exe.debug ]] && nostrip+="|mpv"
  484. for file; do
  485. if [[ $file =~ \.($exts)$ && ! $file =~ ($nostrip)\.exe$ ]]; then
  486. do_print_progress Stripping
  487. break
  488. fi
  489. done
  490. for file; do
  491. local orig_file="$file"
  492. if ! file="$(file_installed "$orig_file")"; then
  493. continue
  494. fi
  495. if [[ $file =~ \.(exe|com)$ ]] &&
  496. [[ ! $file =~ ($nostrip)\.exe$ ]]; then
  497. cmd+=(--strip-all)
  498. elif [[ $file =~ \.dll$ ]] ||
  499. [[ $file =~ x265(|-numa)\.exe$ ]]; then
  500. cmd+=(--strip-unneeded)
  501. elif ! disabled debug && [[ $file =~ \.a$ ]]; then
  502. cmd+=(--strip-debug)
  503. else
  504. file=""
  505. fi
  506. [[ $file ]] &&
  507. { eval "${cmd[@]}" "$file" 2> /dev/null ||
  508. eval "${cmd[@]}" "$file" -o "$file.stripped" 2> /dev/null; }
  509. [[ -f ${file}.stripped ]] && mv -f "${file}"{.stripped,}
  510. done
  511. }
  512. do_pack() {
  513. local file
  514. local cmd=(/opt/bin/upx -9 -qq)
  515. local nopack=""
  516. local exts="exe|dll"
  517. [[ $bits == 64bit ]] && enabled_any libtls openssl && nopack="ffmpeg|mplayer|mpv"
  518. for file; do
  519. if [[ $file =~ \.($exts)$ && ! $file =~ ($nopack)\.exe$ ]]; then
  520. do_print_progress Packing with UPX
  521. break
  522. fi
  523. done
  524. for file; do
  525. local orig_file="$file"
  526. if ! file="$(file_installed "$orig_file")"; then
  527. continue
  528. fi
  529. if [[ $file =~ \.($exts)$ ]] &&
  530. ! [[ -n $nopack && $file =~ ($nopack)\.exe$ ]]; then
  531. [[ $stripping == y ]] && cmd+=("--strip-relocs=0")
  532. else
  533. file=""
  534. fi
  535. [[ $file ]] && eval "${cmd[@]}" "$file"
  536. done
  537. }
  538. do_zipman() {
  539. local file files
  540. local man_dirs=(/local{32,64}/share/man)
  541. files=$(find "${man_dirs[@]}" -type f \! -name "*.gz" \! -name "*.db" \! -name "*.bz2" 2> /dev/null)
  542. for file in $files; do
  543. gzip -9 -n -f "$file"
  544. rm -f "$file"
  545. done
  546. }
  547. # check if compiled file exist
  548. do_checkIfExist() {
  549. local packetName
  550. packetName="$(get_first_subdir)"
  551. local packageDir="${LOCALBUILDDIR}/${packetName}"
  552. local buildSuccessFile="${packageDir}/build_successful${bits}"
  553. local dry="${dry:-n}"
  554. local check=()
  555. if [[ -n $1 ]]; then
  556. check+=("$@")
  557. else
  558. check+=("${_check[@]}")
  559. unset _check
  560. fi
  561. unset_extra_script
  562. [[ -z ${check[*]} ]] && echo "No files to check" && return 1
  563. if [[ $dry == y ]]; then
  564. files_exist -v -s "${check[@]}"
  565. return $?
  566. fi
  567. if files_exist -v "${check[@]}"; then
  568. [[ $stripping == y ]] && do_strip "${check[@]}"
  569. [[ $packing == y ]] && do_pack "${check[@]}"
  570. do_print_status "└ $packetName" "$blue" "Updated"
  571. [[ $build32 == yes || $build64 == yes ]] && [[ -d $packageDir ]] &&
  572. touch "$buildSuccessFile"
  573. else
  574. [[ $build32 == yes || $build64 == yes ]] && [[ -d $packageDir ]] &&
  575. rm -f "$buildSuccessFile"
  576. do_print_status "└ $packetName" "$red" "Failed"
  577. if ${_notrequired:-false}; then
  578. printf '%s\n' \
  579. "$orange"'Package failed to build, but is not required; proceeding with compilation.'"$reset"
  580. else
  581. printf '%s\n' \
  582. '' "Try deleting '$packageDir' and start the script again." \
  583. 'If you are sure there are no dependencies, <Enter> to continue building.'
  584. do_prompt "Close this window if you wish to stop building."
  585. fi
  586. fi
  587. }
  588. file_installed() {
  589. local file silent
  590. [[ $1 == "-s" ]] && silent=true && shift
  591. case $1 in
  592. /* | ./*)
  593. file="$1"
  594. ;;
  595. *.pc)
  596. file="lib/pkgconfig/$1"
  597. ;;
  598. *.a | *.la | *.lib)
  599. file="lib/$1"
  600. ;;
  601. *.h | *.hpp | *.c)
  602. file="include/$1"
  603. ;;
  604. *)
  605. file="$1"
  606. ;;
  607. esac
  608. [[ ${file::1} != "/" ]] && file="$LOCALDESTDIR/$file"
  609. ${silent:-false} || echo "$file"
  610. test -e "$file"
  611. }
  612. files_exist() {
  613. local verbose list soft ignorebinaries term='\n' file
  614. while true; do
  615. case $1 in
  616. -v) verbose=y && shift ;;
  617. -l) list=y && shift ;;
  618. -s) soft=y && shift ;;
  619. -b) ignorebinaries=y && shift ;;
  620. -l0) list=y && term='\0' && shift ;;
  621. --)
  622. shift
  623. break
  624. ;;
  625. *) break ;;
  626. esac
  627. done
  628. [[ $list ]] && verbose= && soft=y
  629. for opt; do
  630. if file=$(file_installed "$opt"); then
  631. [[ $verbose && $soft ]] && do_print_status "├ $file" "${green}" "Found"
  632. if [[ $list ]]; then
  633. if [[ $ignorebinaries && $file =~ .(exe|com)$ ]]; then
  634. continue
  635. fi
  636. printf "%s%b" "$file" "$term"
  637. fi
  638. else
  639. [[ $verbose ]] && do_print_status prefix "${bold}├${reset} " "$file" "${red}" "Not found"
  640. [[ ! $soft ]] && return 1
  641. fi
  642. done
  643. return 0
  644. }
  645. pc_exists() {
  646. for opt; do
  647. local _pkg=${opt%% *}
  648. local _check=${opt#$_pkg}
  649. [[ $_pkg == "$_check" ]] && _check=""
  650. [[ $_pkg == *.pc ]] || _pkg="${LOCALDESTDIR}/lib/pkgconfig/${_pkg}.pc"
  651. pkg-config --exists --silence-errors "${_pkg}${_check}" || return
  652. done
  653. }
  654. do_install() {
  655. [[ $1 == dry ]] && local dryrun=y && shift
  656. local files=("$@")
  657. local dest="${files[-1]}"
  658. [[ ${dest::1} != "/" ]] && dest="$(file_installed "$dest")"
  659. [[ ${#files[@]} -gt 1 ]] && unset 'files[-1]'
  660. [[ ${dest: -1:1} == "/" ]] && mkdir -p "$dest"
  661. if [[ -n $dryrun ]]; then
  662. echo install -D -p "${files[@]}" "$dest"
  663. else
  664. extra_script pre install
  665. install -D -p "${files[@]}" "$dest"
  666. extra_script post install
  667. fi
  668. }
  669. do_uninstall() {
  670. local dry quiet all files
  671. [[ $1 == dry ]] && dry=y && shift
  672. [[ $1 == q ]] && quiet=y && shift
  673. [[ $1 == all ]] && all=y && shift
  674. if [[ $all ]]; then
  675. mapfile -t files < <(files_exist -l "$@")
  676. else
  677. mapfile -t files < <(files_exist -l -b "$@")
  678. fi
  679. if [[ -n ${files[*]} ]]; then
  680. [[ ! $quiet ]] && do_print_progress Running uninstall
  681. if [[ $dry ]]; then
  682. echo "rm -rf ${files[*]}"
  683. else
  684. rm -rf "${files[@]}"
  685. fi
  686. fi
  687. }
  688. do_pkgConfig() {
  689. local pkg="${1%% *}"
  690. local pc_check="${1#$pkg}"
  691. local pkg_and_version="$pkg"
  692. [[ $pkg == "$pc_check" ]] && pc_check=""
  693. local version=$2
  694. local deps=("${_deps[@]}") && unset _deps
  695. [[ ! $version && $pc_check ]] && version="${pc_check#*= }"
  696. [[ "$version" ]] && pkg_and_version="${pkg} ${version}"
  697. if ! pc_exists "${pkg}"; then
  698. do_print_status "${pkg_and_version}" "$red" "Not installed"
  699. elif ! pc_exists "${pkg}${pc_check}"; then
  700. do_print_status "${pkg_and_version}" "$orange" "Outdated"
  701. elif [[ -n ${deps[*]} ]] && test_newer installed "${deps[@]}" "${pkg}.pc"; then
  702. do_print_status "${pkg_and_version}" "$orange" "Newer dependencies"
  703. elif [[ -n ${_check[*]} ]] && ! files_exist "${_check[@]}"; then
  704. do_print_status "${pkg_and_version}" "$orange" "Files missing"
  705. else
  706. do_print_status "${pkg_and_version}" "$green" "Up-to-date"
  707. return 1
  708. fi
  709. }
  710. do_readoptionsfile() {
  711. local filename="$1"
  712. if [[ -f $filename ]]; then
  713. sed -r '# remove commented text
  714. s/#.*//
  715. # delete empty lines
  716. /^\s*$/d
  717. # remove leading whitespace
  718. s/^\s+//
  719. # remove trailing whitespace
  720. s/\s+$//
  721. ' "$filename" | tr -d '\r' # cut cr out from any crlf files
  722. echo "Imported options from ${filename##*/}" >&2
  723. fi
  724. }
  725. do_readbatoptions() {
  726. local varname="$1"
  727. # shellcheck disable=SC1117
  728. printf '%s\n' "${bat[@]}" |
  729. sed -En "/set ${varname}=/,/[^^]$/p" |
  730. sed -E "/^:/d;s/(set ${varname}=| \\^|\")//g;s/ /\\n/g" |
  731. sed -E '/^#/d;/^[^-]/{s/^/--enable-/g}'
  732. }
  733. do_getFFmpegConfig() {
  734. local license="${1:-nonfree}"
  735. FFMPEG_DEFAULT_OPTS=()
  736. if [[ -f "/trunk/media-autobuild_suite.bat" && $ffmpegChoice =~ (n|z|f) ]]; then
  737. IFS=$'\r\n' read -d '' -r -a bat < /trunk/media-autobuild_suite.bat
  738. mapfile -t FFMPEG_DEFAULT_OPTS < <(do_readbatoptions "ffmpeg_options_(builtin|basic)")
  739. local option
  740. [[ $ffmpegChoice != n ]] && while read -r option; do
  741. FFMPEG_DEFAULT_OPTS+=("$option")
  742. done < <(do_readbatoptions "ffmpeg_options_zeranoe")
  743. [[ $ffmpegChoice == f ]] && while read -r option; do
  744. FFMPEG_DEFAULT_OPTS+=("$option")
  745. done < <(do_readbatoptions "ffmpeg_options_full(|_shared)")
  746. echo "Imported default FFmpeg options from .bat"
  747. else
  748. local custom_opts_file="$LOCALBUILDDIR/ffmpeg_options.txt"
  749. if [[ -f "$LOCALBUILDDIR/ffmpeg_options_$bits.txt" ]]; then
  750. custom_opts_file="$LOCALBUILDDIR/ffmpeg_options_$bits.txt"
  751. fi
  752. IFS=$'\n' read -d '' -r -a FFMPEG_DEFAULT_OPTS < <(do_readoptionsfile "$custom_opts_file")
  753. unset FFMPEG_DEFAULT_OPTS_SHARED
  754. if [[ -f "$LOCALBUILDDIR/ffmpeg_options_shared.txt" ]]; then
  755. IFS=$'\n' read -d '' -r -a FFMPEG_DEFAULT_OPTS_SHARED < <(
  756. do_readoptionsfile "$LOCALBUILDDIR/ffmpeg_options_shared.txt"
  757. )
  758. fi
  759. fi
  760. FFMPEG_OPTS=()
  761. for opt in "${FFMPEG_BASE_OPTS[@]}" "${FFMPEG_DEFAULT_OPTS[@]}"; do
  762. [[ -n $opt ]] && FFMPEG_OPTS+=("$opt")
  763. done
  764. echo "License: $license"
  765. # we set these accordingly for static or shared
  766. do_removeOption "--(en|dis)able-(shared|static)"
  767. # OK to use GnuTLS for rtmpdump if not nonfree since GnuTLS was built for rtmpdump anyway
  768. # If nonfree will use SChannel if neither openssl/libtls or gnutls are in the options
  769. if ! enabled_any libtls openssl gnutls &&
  770. { enabled librtmp || [[ $rtmpdump == y ]]; }; then
  771. if [[ $license == nonfree ]] ||
  772. [[ $license == lgpl* && $rtmpdump == n ]]; then
  773. do_addOption --enable-openssl
  774. else
  775. do_addOption --enable-gnutls
  776. fi
  777. do_removeOption "--enable-(gmp|gcrypt|mbedtls)"
  778. fi
  779. local _all_tls="--enable-(mbedtls|gnutls|openssl|libtls|schannel)"
  780. if enabled_any libtls openssl && [[ $license != gpl* ]]; then
  781. # prefer openssl/libtls if both are in options and not gpl
  782. # prefer openssl over libtls if both enabled
  783. local _prefer=libtls
  784. if enabled openssl; then
  785. _prefer=openssl
  786. fi
  787. do_removeOption "${_all_tls}"
  788. do_addOption "--enable-${_prefer}"
  789. elif enabled mbedtls; then
  790. # prefer mbedtls if any other tls libs are enabled and gpl
  791. do_removeOption "${_all_tls}"
  792. do_addOption --enable-mbedtls
  793. elif enabled gnutls; then
  794. do_removeOption "${_all_tls}"
  795. do_addOption --enable-gnutls
  796. elif ! disabled schannel; then
  797. # fallback to schannel if no other tls libs are enabled
  798. do_addOption --enable-schannel
  799. fi
  800. enabled_any lib{vo-aacenc,aacplus,utvideo,dcadec,faac,ebur128,ndi_newtek,ndi-newtek,ssh} netcdf &&
  801. do_removeOption "--enable-(lib(vo-aacenc|aacplus|utvideo|dcadec|faac|ebur128|ndi_newtek|ndi-newtek|ssh)|netcdf)" &&
  802. sed -ri 's;--enable-(lib(vo-aacenc|aacplus|utvideo|dcadec|faac|ebur128|ndi_newtek|ndi-newtek|ssh)|netcdf);;g' \
  803. "$LOCALBUILDDIR/ffmpeg_options.txt"
  804. }
  805. do_changeFFmpegConfig() {
  806. local license="${1:-nonfree}"
  807. do_print_progress Changing options to comply to "$license"
  808. # if w32threads is disabled, pthreads is used and needs this cflag
  809. # decklink includes zvbi, which requires pthreads
  810. if disabled w32threads || enabled pthreads || enabled_all decklink libzvbi || enabled libvmaf; then
  811. do_removeOption --enable-w32threads
  812. do_addOption --disable-w32threads
  813. fi
  814. # add options for static kvazaar
  815. enabled libkvazaar && do_addOption --extra-cflags=-DKVZ_STATIC_LIB
  816. # get libs restricted by license
  817. local config_script=configure
  818. [[ $(get_first_subdir) != "ffmpeg-git" ]] && config_script="$LOCALBUILDDIR/ffmpeg-git/configure"
  819. [[ -f $config_script ]] || do_exit_prompt "There's no configure script to retrieve libs from"
  820. eval "$(sed -n '/EXTERNAL_LIBRARY_GPL_LIST=/,/^"/p' "$config_script" | tr -s '\n' ' ')"
  821. eval "$(sed -n '/HWACCEL_LIBRARY_NONFREE_LIST=/,/^"/p' "$config_script" | tr -s '\n' ' ')"
  822. eval "$(sed -n '/EXTERNAL_LIBRARY_NONFREE_LIST=/,/^"/p' "$config_script" | tr -s '\n' ' ')"
  823. eval "$(sed -n '/EXTERNAL_LIBRARY_VERSION3_LIST=/,/^"/p' "$config_script" | tr -s '\n' ' ')"
  824. # handle gpl libs
  825. local gpl
  826. read -ra gpl <<< "${EXTERNAL_LIBRARY_GPL_LIST//_/-} gpl"
  827. if [[ $license == gpl* || $license == nonfree ]] &&
  828. { enabled_any "${gpl[@]}" || ! disabled postproc; }; then
  829. do_addOption --enable-gpl
  830. else
  831. do_removeOptions "${gpl[*]/#/--enable-} --enable-postproc --enable-gpl"
  832. fi
  833. # handle (l)gplv3 libs
  834. local version3
  835. read -ra version3 <<< "${EXTERNAL_LIBRARY_VERSION3_LIST//_/-}"
  836. if [[ $license =~ (l|)gplv3 || $license == nonfree ]] && enabled_any "${version3[@]}"; then
  837. do_addOption --enable-version3
  838. else
  839. do_removeOptions "${version3[*]/#/--enable-} --enable-version3"
  840. fi
  841. local nonfreehwaccel
  842. read -ra nonfreehwaccel <<< "(${HWACCEL_LIBRARY_NONFREE_LIST//_/-}"
  843. if [[ $license == "nonfree" ]] && enabled_any "${nonfreehwaccel[@]}"; then
  844. do_addOption --enable-nonfree
  845. else
  846. do_removeOptions "${nonfreehwaccel[*]/#/--enable-} --enable-nonfree"
  847. fi
  848. # cuda-only workarounds
  849. if verify_cuda_deps; then
  850. if enabled libnpp; then
  851. echo -e "${orange}FFmpeg and related apps will depend on CUDA SDK to run!${reset}"
  852. local fixed_CUDA_PATH
  853. fixed_CUDA_PATH="$(cygpath -sm "$CUDA_PATH")"
  854. do_addOption "--extra-cflags=-I$fixed_CUDA_PATH/include"
  855. do_addOption "--extra-ldflags=-L$fixed_CUDA_PATH/lib/x64"
  856. fi
  857. if enabled cuda-nvcc; then
  858. local fixed_CUDA_PATH_UNIX
  859. fixed_CUDA_PATH_UNIX="$(cygpath -u "$CUDA_PATH")"
  860. nvcc.exe --help &> /dev/null || export PATH="$PATH:$fixed_CUDA_PATH_UNIX/bin"
  861. echo -e "${orange}FFmpeg and related apps will depend on Nvidia drivers!${reset}"
  862. fi
  863. else
  864. do_removeOption "--enable-(libnpp|cuda-nvcc)"
  865. fi
  866. # handle gpl-incompatible libs
  867. local nonfreegpl
  868. read -ra nonfreegpl <<< "${EXTERNAL_LIBRARY_NONFREE_LIST//_/-}"
  869. if enabled_any "${nonfreegpl[@]}"; then
  870. if [[ $license == "nonfree" ]] && enabled gpl; then
  871. do_addOption --enable-nonfree
  872. elif [[ $license == gpl* ]]; then
  873. do_removeOptions "${nonfreegpl[*]/#/--enable-}"
  874. fi
  875. # no lgpl here because they are accepted with it
  876. fi
  877. if ! disabled debug "debug=gdb"; then
  878. # fix issue with ffprobe not working with debug and strip
  879. do_addOption --disable-stripping
  880. fi
  881. # both openssl and mbedtls don't need gcrypt/gmp for rtmpe
  882. enabled_any openssl mbedtls && do_removeOption "--enable-(gcrypt|gmp)"
  883. # remove libs that don't work with shared
  884. if [[ $ffmpeg =~ "shared" || $ffmpeg =~ "both" ]]; then
  885. FFMPEG_OPTS_SHARED=()
  886. for opt in "${FFMPEG_OPTS[@]}" "${FFMPEG_DEFAULT_OPTS_SHARED[@]}"; do
  887. FFMPEG_OPTS_SHARED+=("$opt")
  888. done
  889. fi
  890. if [[ $ffmpeg == "bothstatic" ]]; then
  891. do_removeOption "--enable-(opencl|opengl|cuda-nvcc|libnpp|libopenh264)"
  892. fi
  893. }
  894. opt_exists() {
  895. local array="${1}[@]" && shift 1
  896. local opt value
  897. for opt; do
  898. for value in "${!array}"; do
  899. [[ $value =~ $opt ]] && return
  900. done
  901. done
  902. return 1
  903. }
  904. enabled() {
  905. test "${FFMPEG_OPTS[*]}" != "${FFMPEG_OPTS[*]#--enable-$1}"
  906. }
  907. disabled() {
  908. test "${FFMPEG_OPTS[*]}" != "${FFMPEG_OPTS[*]#--disable-$1}"
  909. }
  910. enabled_any() {
  911. local opt
  912. for opt; do
  913. enabled "$opt" && return 0
  914. done
  915. return 1
  916. }
  917. disabled_any() {
  918. local opt
  919. for opt; do
  920. disabled "$opt" && return 0
  921. done
  922. return 1
  923. }
  924. enabled_all() {
  925. local opt
  926. for opt; do
  927. enabled "$opt" || return 1
  928. done
  929. return 0
  930. }
  931. disabled_all() {
  932. local opt
  933. for opt; do
  934. disabled "$opt" || return 1
  935. done
  936. return 0
  937. }
  938. do_getMpvConfig() {
  939. local MPV_TEMP_OPTS=()
  940. MPV_OPTS=()
  941. if [[ -f "/trunk/media-autobuild_suite.bat" && $ffmpegChoice =~ (n|z|f) ]]; then
  942. IFS=$'\r\n' read -d '' -r -a bat < /trunk/media-autobuild_suite.bat
  943. mapfile -t MPV_TEMP_OPTS < <(do_readbatoptions "mpv_options_(builtin|basic)")
  944. local option
  945. [[ $ffmpegChoice == f ]] && while read -r option; do
  946. [[ -n $option ]] && MPV_TEMP_OPTS+=("$option")
  947. done < <(do_readbatoptions "mpv_options_full")
  948. echo "Imported default mpv options from .bat"
  949. else
  950. IFS=$'\n' read -d '' -r -a MPV_TEMP_OPTS < <(do_readoptionsfile "$LOCALBUILDDIR/mpv_options.txt")
  951. fi
  952. do_removeOption MPV_TEMP_OPTS \
  953. "--(en|dis)able-(vapoursynth-lazy|libguess|static-build|enable-gpl3|egl-angle-lib|encoding|crossc|dvdread)"
  954. for opt in "${MPV_TEMP_OPTS[@]}"; do
  955. [[ -n $opt ]] && MPV_OPTS+=("$opt")
  956. done
  957. }
  958. mpv_enabled() {
  959. local option
  960. [[ $mpv == n ]] && return 1
  961. for option in "${MPV_OPTS[@]}"; do
  962. [[ $option =~ "--enable-$1"$ ]] && return
  963. done
  964. return 1
  965. }
  966. mpv_disabled() {
  967. local option
  968. [[ $mpv == n ]] && return 0
  969. for option in "${MPV_OPTS[@]}"; do
  970. [[ $option =~ "--disable-$1"$ ]] && return
  971. done
  972. return 1
  973. }
  974. mpv_enabled_any() {
  975. local opt
  976. for opt; do
  977. mpv_enabled "$opt" && return 0
  978. done
  979. return 1
  980. }
  981. mpv_enabled_all() {
  982. local opt
  983. for opt; do
  984. mpv_enabled "$opt" || return 1
  985. done
  986. }
  987. mpv_disabled_all() {
  988. local opt
  989. for opt; do
  990. mpv_disabled "$opt" || return 1
  991. done
  992. }
  993. mpv_enable() {
  994. local opt newopts=()
  995. for opt in "${MPV_OPTS[@]}"; do
  996. if [[ $opt =~ "--disable-$1"$ ]]; then
  997. newopts+=("--enable-$1")
  998. else
  999. newopts+=("$opt")
  1000. fi
  1001. done
  1002. MPV_OPTS=("${newopts[@]}")
  1003. }
  1004. mpv_disable() {
  1005. local opt newopts=()
  1006. for opt in "${MPV_OPTS[@]}"; do
  1007. if [[ $opt =~ "--enable-$1"$ ]]; then
  1008. newopts+=("--disable-$1")
  1009. else
  1010. newopts+=("$opt")
  1011. fi
  1012. done
  1013. MPV_OPTS=("${newopts[@]}")
  1014. }
  1015. do_addOption() {
  1016. local varname="$1" array opt
  1017. if [[ ${varname#--} == "$varname" ]]; then
  1018. array="$varname" && shift 1
  1019. else
  1020. array="FFMPEG_OPTS"
  1021. fi
  1022. for opt; do
  1023. ! opt_exists "$array" "$opt" && declare -ag "$array+=(\"$opt\")"
  1024. done
  1025. }
  1026. do_removeOption() {
  1027. local varname="$1"
  1028. local arrayname
  1029. if [[ ${varname#--} == "$varname" ]]; then
  1030. arrayname="$varname" && shift 1
  1031. else
  1032. arrayname="FFMPEG_OPTS"
  1033. fi
  1034. local option="$1"
  1035. local basearray temp=()
  1036. basearray="${arrayname}[@]"
  1037. local orig=("${!basearray}")
  1038. for ((i = 0; i < ${#orig[@]}; i++)); do
  1039. if [[ ! ${orig[$i]} =~ ^${option}$ ]]; then
  1040. temp+=("${orig[$i]}")
  1041. fi
  1042. done
  1043. # shellcheck disable=SC1117,SC1083
  1044. eval "$arrayname"=\(\"\${temp[@]}\"\)
  1045. }
  1046. do_removeOptions() {
  1047. local option
  1048. local shared=$2
  1049. for option in $1; do
  1050. do_removeOption "$option" "$shared"
  1051. done
  1052. }
  1053. do_patch() {
  1054. local binarypatch="--binary"
  1055. case $1 in -p) binarypatch="" && shift ;; esac
  1056. local patch="${1%% *}" # Location or link to patch.
  1057. local patchName="${1##* }" # Basename of file. (test-diff-files.diff)
  1058. local am=false # Use git am to apply patch. Use with .patch files
  1059. local strip=${3:-1} # Leading directories to strip. "patch -p${strip}"
  1060. [[ $patchName == "$patch" ]] && patchName="${patch##*/}"
  1061. [[ $2 == am ]] && am=true
  1062. # hack for URLs without filename
  1063. patchName=${patchName:-"$(/usr/bin/curl -sI "$patch" | grep -Eo 'filename=.*$' | sed 's/filename=//')"}
  1064. [[ -z $patchName ]] &&
  1065. printf '%b\n' "${red}Failed to apply patch '$patch'" \
  1066. "Patch without filename, ignoring. Specify an explicit filename.${reset}" &&
  1067. return 1
  1068. # Just don't. Make a fork or use the suite's directory as the root for
  1069. # your diffs or manually edit the scripts if you are trying to modify
  1070. # the helper and compile scripts. If you really need to, use patch instead.
  1071. # Else create a patch file for the individual folders you want to apply
  1072. # the patch to.
  1073. [[ $PWD == "$LOCALBUILDDIR" ]] &&
  1074. do_exit_prompt "Running patches in the build folder is not supported.
  1075. Please make a patch for individual folders or modify the script directly"
  1076. # Filter out patches that would require curl; else
  1077. # check if the patch is a local patch and copy it to the current dir
  1078. if ! do_wget -c -r -q "$patch" "$patchName" && [[ -f $patch ]]; then
  1079. patch="$(
  1080. cd_safe "$(dirname "$patch")"
  1081. printf '%s' "$(pwd -P)" '/' "$(basename -- "$patch")"
  1082. )" # Resolve fullpath
  1083. [[ ${patch%/*} != "$PWD" ]] && cp -f "$patch" "$patchName" > /dev/null 2>&1
  1084. fi
  1085. if [[ -f $patchName ]]; then
  1086. if $am; then
  1087. git apply --check --ignore-space-change --ignore-whitespace "$patchName" > /dev/null 2>&1 &&
  1088. git am -q --ignore-whitespace --no-gpg-sign "$patchName" > /dev/null 2>&1 &&
  1089. return 0
  1090. git am -q --abort > /dev/null 2>&1
  1091. else
  1092. patch --dry-run $binarypatch -s -N -p"$strip" -i "$patchName" > /dev/null 2>&1 &&
  1093. patch $binarypatch -s -N -p"$strip" -i "$patchName" &&
  1094. return 0
  1095. fi
  1096. printf '%b\n' "${orange}${patchName}${reset}" \
  1097. '\tPatch could not be applied with `'"$($am && echo "git am" || echo "patch")"'`. Continuing without patching.'
  1098. else
  1099. printf '%b\n' "${orange}${patchName}${reset}" \
  1100. '\tPatch not found anywhere. Continuing without patching.'
  1101. fi
  1102. return 1
  1103. }
  1104. do_custom_patches() {
  1105. local patch
  1106. for patch in "$@"; do
  1107. [[ ${patch##*.} == "patch" ]] && do_patch "$patch" am
  1108. [[ ${patch##*.} == "diff" ]] && do_patch "$patch"
  1109. done
  1110. }
  1111. do_cmake() {
  1112. local bindir=""
  1113. local root=".."
  1114. local cmake_build_dir=""
  1115. while [[ -n $* ]]; do
  1116. case "$1" in
  1117. global | audio | video)
  1118. bindir="-DCMAKE_INSTALL_BINDIR=$LOCALDESTDIR/bin-$1"
  1119. shift
  1120. ;;
  1121. builddir=*)
  1122. cmake_build_dir="${1#*=}"
  1123. shift
  1124. ;;
  1125. skip_build_dir)
  1126. local skip_build_dir=y
  1127. shift
  1128. ;;
  1129. *)
  1130. if [[ -d "./$1" ]]; then
  1131. [[ -n $skip_build_dir ]] && root="./$1" || root="../$1"
  1132. shift
  1133. elif [[ -d "../$1" ]]; then
  1134. root="../$1"
  1135. shift
  1136. fi
  1137. break
  1138. ;;
  1139. esac
  1140. done
  1141. local PKG_CONFIG="$LOCALDESTDIR/bin/ab-pkg-config-static.bat"
  1142. [[ -z $skip_build_dir ]] && create_build_dir "$cmake_build_dir"
  1143. # use this array to pass additional parameters to cmake
  1144. local cmake_extras=()
  1145. extra_script pre cmake
  1146. [[ -f "$(get_first_subdir -f)/do_not_reconfigure" ]] &&
  1147. return
  1148. # shellcheck disable=SC2086
  1149. log "cmake" cmake "$root" -G Ninja -DBUILD_SHARED_LIBS=off \
  1150. -DCMAKE_TOOLCHAIN_FILE="$LOCALDESTDIR/etc/toolchain.cmake" \
  1151. -DCMAKE_INSTALL_PREFIX="$LOCALDESTDIR" -DUNIX=on \
  1152. -DCMAKE_BUILD_TYPE=Release $bindir "$@" "${cmake_extras[@]}"
  1153. extra_script post cmake
  1154. unset cmake_extras
  1155. }
  1156. do_ninja() {
  1157. extra_script pre ninja
  1158. log "build" ninja "$@"
  1159. extra_script post ninja
  1160. }
  1161. do_ninjainstall() {
  1162. extra_script pre install
  1163. cpuCount=1 log "install" ninja install "$@"
  1164. extra_script post install
  1165. }
  1166. do_cmakeinstall() {
  1167. do_cmake "$@"
  1168. do_ninja
  1169. do_ninjainstall
  1170. }
  1171. do_meson() {
  1172. local bindir=""
  1173. local root=".."
  1174. case "$1" in
  1175. global | audio | video)
  1176. bindir="--bindir=bin-$1"
  1177. ;;
  1178. *)
  1179. [[ -d "./$1" ]] && root="../$1" || bindir="$1"
  1180. ;;
  1181. esac
  1182. shift 1
  1183. create_build_dir
  1184. # use this array to pass additional parameters to meson
  1185. local meson_extras=()
  1186. extra_script pre meson
  1187. [[ -f "$(get_first_subdir -f)/do_not_reconfigure" ]] &&
  1188. return
  1189. # shellcheck disable=SC2086
  1190. PKG_CONFIG=pkg-config CC=${CC/ccache /}.bat CXX=${CXX/ccache /}.bat \
  1191. log "meson" meson "$root" --default-library=static --buildtype=release \
  1192. --prefix="$LOCALDESTDIR" --backend=ninja $bindir "$@" "${meson_extras[@]}"
  1193. extra_script post meson
  1194. unset meson_extras
  1195. }
  1196. do_mesoninstall() {
  1197. do_meson "$@"
  1198. do_ninja
  1199. do_ninjainstall
  1200. }
  1201. do_rust() {
  1202. log "rust.update" "$RUSTUP_HOME/bin/cargo.exe" update
  1203. # use this array to pass additional parameters to cargo
  1204. local rust_extras=()
  1205. extra_script pre rust
  1206. [[ -f "$(get_first_subdir -f)/do_not_reconfigure" ]] &&
  1207. return
  1208. log "rust.build" "$RUSTUP_HOME/bin/cargo.exe" build --release \
  1209. --target="$CARCH"-pc-windows-gnu \
  1210. --jobs="$cpuCount" "$@" "${rust_extras[@]}"
  1211. extra_script post rust
  1212. unset rust_extras
  1213. }
  1214. compilation_fail() {
  1215. [[ -z $build32$build64 ]] && return 1
  1216. local reason="$1"
  1217. local operation="${reason,,}"
  1218. if [[ $logging == y ]]; then
  1219. echo "Likely error (tail of the failed operation logfile):"
  1220. tail "ab-suite.${operation}.log"
  1221. echo "${red}$reason failed. Check $(pwd -W)/ab-suite.$operation.log${reset}"
  1222. fi
  1223. if ${_notrequired:-false}; then
  1224. echo "This isn't required for anything so we can move on."
  1225. return 1
  1226. else
  1227. echo "${red}This is required for other packages, so this script will exit.${reset}"
  1228. create_diagnostic
  1229. zip_logs
  1230. echo "Make sure the suite is up-to-date before reporting an issue. It might've been fixed already."
  1231. do_prompt "Try running the build again at a later time."
  1232. exit 1
  1233. fi
  1234. }
  1235. strip_ansi() {
  1236. local txtfile newfile
  1237. for txtfile; do
  1238. [[ $txtfile != "${txtfile//stripped/}" ]] && continue
  1239. local name="${txtfile%.*}" ext="${txtfile##*.}"
  1240. [[ $txtfile != "$name" ]] &&
  1241. newfile="$name.stripped.$ext" || newfile="$txtfile-stripped"
  1242. sed 's/\x1b\[[0-9;]*[a-zA-Z]//g' "$txtfile" > "$newfile"
  1243. done
  1244. }
  1245. zip_logs() {
  1246. local failed url
  1247. failed=$(get_first_subdir)
  1248. strip_ansi "$LOCALBUILDDIR"/*.log
  1249. rm -f "$LOCALBUILDDIR/logs.zip"
  1250. (
  1251. cd "$LOCALBUILDDIR" > /dev/null || do_exit_prompt "Did you delete /build?"
  1252. {
  1253. echo /trunk/media-autobuild_suite.bat
  1254. [[ $failed != . ]] && find "$failed" -name "*.log"
  1255. find . -maxdepth 1 -name "*.stripped.log" -o -name "*_options.txt" -o -name "media-suite_*.sh" \
  1256. -o -name "last_run" -o -name "media-autobuild_suite.ini" -o -name "diagnostics.txt" -o -name "patchedFolders"
  1257. } | sort -uo failedFiles
  1258. 7za -mx=9 a logs.zip -- @failedFiles > /dev/null && rm failedFiles
  1259. )
  1260. [[ ! -f $LOCALBUILDDIR/no_logs && -n $build32$build64 ]] &&
  1261. url="$(cd "$LOCALBUILDDIR" && /usr/bin/curl -sF'file=@logs.zip' https://0x0.st)"
  1262. echo
  1263. if [[ $url ]]; then
  1264. echo "${green}All relevant logs have been anonymously uploaded to $url"
  1265. echo "${green}Copy and paste ${red}[logs.zip]($url)${green} in the GitHub issue.${reset}"
  1266. elif [[ -f "$LOCALBUILDDIR/logs.zip" ]]; then
  1267. echo "${green}Attach $(cygpath -w "$LOCALBUILDDIR/logs.zip") to the GitHub issue.${reset}"
  1268. else
  1269. echo "${red}Failed to generate logs.zip!${reset}"
  1270. fi
  1271. }
  1272. log() {
  1273. local errorOut=true quiet=false ret OPTION OPTIND
  1274. while getopts ':qe' OPTION; do
  1275. case "$OPTION" in
  1276. e) errorOut=false ;;
  1277. q) quiet=true ;;
  1278. *) break ;;
  1279. esac
  1280. done
  1281. shift "$((OPTIND - 1))"
  1282. [[ $1 == quiet ]] && quiet=true && shift # Temp compat with old style just in case
  1283. local name="${1// /.}" _cmd="$2" extra
  1284. shift 2
  1285. $quiet || do_print_progress Running "$name"
  1286. [[ $_cmd =~ ^(make|ninja)$ ]] && extra="-j$cpuCount"
  1287. if [[ $logging == "y" ]]; then
  1288. printf 'CPPFLAGS: %s\nCFLAGS: %s\nCXXFLAGS: %s\nLDFLAGS: %s\n%s %s\n' "$CPPFLAGS" "$CFLAGS" "$CXXFLAGS" "$LDFLAGS" "$_cmd${extra:+ $extra}" "$*" > "ab-suite.$name.log"
  1289. $_cmd $extra "$@" >> "ab-suite.$name.log" 2>&1 ||
  1290. { [[ $extra ]] && $_cmd -j1 "$@" >> "ab-suite.$name.log" 2>&1; }
  1291. else
  1292. $_cmd $extra "$@" || { [[ $extra ]] && $_cmd -j1 "$@"; }
  1293. fi
  1294. case ${ret:=$?} in
  1295. 0) return 0 ;;
  1296. *) $errorOut && compilation_fail "$name" || return $ret ;;
  1297. esac
  1298. }
  1299. create_build_dir() {
  1300. local print_build_dir=false nocd=${nocd:-false} norm=false build_root build_dir getoptopt OPTARG OPTIND
  1301. while getopts ":pcrC:" getoptopt; do
  1302. case $getoptopt in
  1303. p) print_build_dir=true ;;
  1304. c) nocd=true ;;
  1305. r) norm=true ;;
  1306. C) build_root="$OPTARG" ;;
  1307. \?)
  1308. echo "Invalid Option: -$OPTARG" 1>&2
  1309. return 1
  1310. ;;
  1311. :)
  1312. echo "Invalid option: $OPTARG requires an argument" 1>&2
  1313. return 1
  1314. ;;
  1315. esac
  1316. done
  1317. shift $((OPTIND - 1))
  1318. build_dir="${build_root:+$build_root/}build${1:+-$1}-$bits"
  1319. if [[ -d $build_dir && ! -f $(get_first_subdir -f)/do_not_clean ]]; then
  1320. $norm || rm -rf "$build_dir" ||
  1321. (cd_safe "$build_dir" && rm -rf ./*)
  1322. fi
  1323. [[ ! -d $build_dir ]] && mkdir -p "$build_dir"
  1324. $nocd || cd_safe "$build_dir"
  1325. $print_build_dir && printf '%s\n' "$build_dir"
  1326. }
  1327. get_external_opts() {
  1328. local array="$1"
  1329. local pkgname
  1330. pkgname="$(get_first_subdir)"
  1331. local optsfile="$LOCALBUILDDIR/${pkgname%-*}_options.txt"
  1332. if [[ -n $array ]]; then
  1333. # shellcheck disable=SC2034
  1334. IFS=$'\n' read -d '' -r -a tmp < <(do_readoptionsfile "$optsfile")
  1335. declare -ag "$array+=(\"\${tmp[@]}\")"
  1336. else
  1337. do_readoptionsfile "$optsfile"
  1338. fi
  1339. }
  1340. do_separate_conf() {
  1341. local bindir=""
  1342. local last config_path
  1343. case "$1" in
  1344. global | audio | video)
  1345. bindir="--bindir=$LOCALDESTDIR/bin-$1"
  1346. ;;
  1347. *) bindir="$1" ;;
  1348. esac
  1349. shift 1
  1350. for last; do true; done
  1351. if test -x "${last}/configure"; then
  1352. config_path="$last"
  1353. else
  1354. config_path=".."
  1355. create_build_dir
  1356. fi
  1357. do_configure --disable-shared --enable-static "$bindir" "$@"
  1358. }
  1359. do_separate_confmakeinstall() {
  1360. do_separate_conf "$@"
  1361. do_make
  1362. do_makeinstall
  1363. cd_safe ..
  1364. }
  1365. do_configure() {
  1366. # use this array to pass additional parameters to configure
  1367. local conf_extras=()
  1368. extra_script pre configure
  1369. [[ -f "$(get_first_subdir -f)/do_not_reconfigure" ]] &&
  1370. return
  1371. log "configure" ${config_path:-.}/configure --prefix="$LOCALDESTDIR" "$@" \
  1372. "${conf_extras[@]}"
  1373. extra_script post configure
  1374. unset conf_extras
  1375. }
  1376. do_qmake() {
  1377. extra_script pre qmake
  1378. log "qmake" qmake "$@"
  1379. extra_script post qmake
  1380. }
  1381. do_make() {
  1382. extra_script pre make
  1383. log "make" make "$@"
  1384. extra_script post make
  1385. }
  1386. do_makeinstall() {
  1387. extra_script pre install
  1388. log "install" make install "$@"
  1389. extra_script post install
  1390. }
  1391. do_hide_pacman_sharedlibs() {
  1392. local packages="$1"
  1393. local revert="$2"
  1394. local files
  1395. files="$(pacman -Qql "$packages" 2> /dev/null | /usr/bin/grep .dll.a)"
  1396. for file in $files; do
  1397. if [[ -f "${file%*.dll.a}.a" ]]; then
  1398. if [[ -z $revert ]]; then
  1399. mv -f "${file}" "${file}.dyn"
  1400. elif [[ -n $revert && -f "${file}.dyn" && ! -f ${file} ]]; then
  1401. mv -f "${file}.dyn" "${file}"
  1402. elif [[ -n $revert && -f "${file}.dyn" ]]; then
  1403. rm -f "${file}.dyn"
  1404. fi
  1405. fi
  1406. done
  1407. }
  1408. do_hide_all_sharedlibs() {
  1409. local dryrun="${dry:-n}"
  1410. local files
  1411. files="$(find /mingw{32,64}/lib /mingw{32/i686,64/x86_64}-w64-mingw32/lib -name "*.dll.a" 2> /dev/null)"
  1412. local tomove=()
  1413. for file in $files; do
  1414. [[ -f "${file%*.dll.a}.a" ]] && tomove+=("$file")
  1415. done
  1416. if [[ $dryrun == "n" ]]; then
  1417. printf '%s\n' "${tomove[@]}" | xargs -ri mv -f '{}' '{}.dyn'
  1418. else
  1419. printf '%s\n' "${tomove[@]}"
  1420. fi
  1421. }
  1422. do_unhide_all_sharedlibs() {
  1423. local dryrun="${dry:-n}"
  1424. local files
  1425. files="$(find /mingw{32,64}/lib /mingw{32/i686,64/x86_64}-w64-mingw32/lib -name "*.dll.a.dyn" 2> /dev/null)"
  1426. local tomove=()
  1427. local todelete=()
  1428. for file in $files; do
  1429. if [[ -f ${file%*.dyn} ]]; then
  1430. todelete+=("$file")
  1431. else
  1432. tomove+=("${file%*.dyn}")
  1433. fi
  1434. done
  1435. if [[ $dryrun == "n" ]]; then
  1436. printf '%s\n' "${todelete[@]}" | xargs -ri rm -f '{}'
  1437. printf '%s\n' "${tomove[@]}" | xargs -ri mv -f '{}.dyn' '{}'
  1438. else
  1439. printf 'rm %s\n' "${todelete[@]}"
  1440. printf '%s\n' "${tomove[@]}"
  1441. fi
  1442. }
  1443. do_pacman_install() {
  1444. local pkg msyspackage=false pkgs
  1445. while true; do
  1446. case "$1" in
  1447. -m) msyspackage=true && shift ;;
  1448. *) break ;;
  1449. esac
  1450. done
  1451. for pkg; do
  1452. if ! $msyspackage && [[ $pkg != "${MINGW_PACKAGE_PREFIX}-"* ]]; then
  1453. pkgs="${pkgs:+$pkgs }${MINGW_PACKAGE_PREFIX}-${pkg}"
  1454. else
  1455. pkgs="${pkgs:+$pkgs }${pkg}"
  1456. fi
  1457. done
  1458. for pkg in $pkgs; do
  1459. pacman -Qqe "$pkg" > /dev/null 2>&1 && continue
  1460. do_simple_print -n "Installing ${pkg#$MINGW_PACKAGE_PREFIX-}... "
  1461. if pacman -S --overwrite "/usr/*" --overwrite "/mingw64/*" --overwrite "/mingw32/*" --noconfirm --ask=20 --needed "$pkg" > /dev/null 2>&1; then
  1462. pacman -D --asexplicit "$pkg" > /dev/null
  1463. if $msyspackage; then
  1464. /usr/bin/grep -q "^${pkg}$" /etc/pac-msys-extra.pk > /dev/null 2>&1 ||
  1465. echo "${pkg}" >> /etc/pac-msys-extra.pk
  1466. else
  1467. /usr/bin/grep -q "^${pkg#$MINGW_PACKAGE_PREFIX-}$" /etc/pac-mingw-extra.pk > /dev/null 2>&1 ||
  1468. echo "${pkg#$MINGW_PACKAGE_PREFIX-}" >> /etc/pac-mingw-extra.pk
  1469. fi
  1470. echo "done"
  1471. else
  1472. echo "failed"
  1473. fi
  1474. done
  1475. sort -uo /etc/pac-mingw-extra.pk{,} > /dev/null 2>&1
  1476. sort -uo /etc/pac-msys-extra.pk{,} > /dev/null 2>&1
  1477. do_hide_all_sharedlibs
  1478. }
  1479. do_pacman_remove() {
  1480. local pkg msyspackage=false pkgs
  1481. while true; do
  1482. case "$1" in
  1483. -m) msyspackage=true ;;
  1484. *) break ;;
  1485. esac
  1486. done
  1487. for pkg; do
  1488. if ! $msyspackage && [[ $pkg != "${MINGW_PACKAGE_PREFIX}-"* ]]; then
  1489. pkgs="${pkgs:+$pkgs }${MINGW_PACKAGE_PREFIX}-${pkg}"
  1490. else
  1491. pkgs="${pkgs:+$pkgs }${pkg}"
  1492. fi
  1493. done
  1494. for pkg in $pkgs; do
  1495. if $msyspackage; then
  1496. [[ -f /etc/pac-msys-extra.pk ]] &&
  1497. sed -i "/^${pkg}$/d" /etc/pac-msys-extra.pk > /dev/null 2>&1
  1498. else
  1499. [[ -f /etc/pac-mingw-extra.pk ]] &&
  1500. sed -i "/^${pkg#$MINGW_PACKAGE_PREFIX-}$/d" /etc/pac-mingw-extra.pk > /dev/null 2>&1
  1501. fi
  1502. pacman -Qqe "$pkg" > /dev/null 2>&1 || continue
  1503. do_simple_print -n "Uninstalling ${pkg#$MINGW_PACKAGE_PREFIX-}... "
  1504. do_hide_pacman_sharedlibs "$pkg" revert
  1505. if pacman -Rs --noconfirm --ask=20 "$pkg" > /dev/null 2>&1; then
  1506. echo "done"
  1507. else
  1508. pacman -D --asdeps "$pkg" > /dev/null 2>&1
  1509. echo "failed"
  1510. fi
  1511. done
  1512. sort -uo /etc/pac-mingw-extra.pk{,} > /dev/null 2>&1
  1513. sort -uo /etc/pac-msys-extra.pk{,} > /dev/null 2>&1
  1514. do_hide_all_sharedlibs
  1515. }
  1516. do_prompt() {
  1517. # from http://superuser.com/a/608509
  1518. while read -r -s -e -t 0.1; do :; done
  1519. read -r -p "$1" ret
  1520. }
  1521. do_autoreconf() {
  1522. local basedir
  1523. basedir=$(get_first_subdir -f)
  1524. if { [[ -f $basedir/recently_updated ]] &&
  1525. find "$basedir" -name "build_successful*" -exec false {} +; } ||
  1526. [[ ! -f configure ]]; then
  1527. extra_script pre autoreconf
  1528. log "autoreconf" autoreconf -fiv "$@"
  1529. extra_script post autoreconf
  1530. fi
  1531. }
  1532. do_autogen() {
  1533. local basedir
  1534. basedir=$(get_first_subdir -f)
  1535. if { [[ -f $basedir/recently_updated ]] &&
  1536. find "$basedir" -name "build_successful*" -exec false {} +; } ||
  1537. [[ ! -f configure ]]; then
  1538. safe_git_clean -q
  1539. extra_script pre autogen
  1540. log "autogen" ./autogen.sh "$@"
  1541. extra_script post autogen
  1542. fi
  1543. }
  1544. get_first_subdir() {
  1545. local subdir="${PWD#*$LOCALBUILDDIR/}" fullpath=false OPTION OPTIND
  1546. while getopts ':f' OPTION; do
  1547. case "$OPTION" in
  1548. f) fullpath=true ;;
  1549. *) break ;;
  1550. esac
  1551. done
  1552. shift "$((OPTIND - 1))"
  1553. if [[ $subdir != "$PWD" ]]; then
  1554. $fullpath && printf '%s' "$LOCALBUILDDIR/"
  1555. echo "${subdir%%/*}"
  1556. else
  1557. $fullpath && echo "$PWD" || echo "."
  1558. fi
  1559. }
  1560. clean_html_index() {
  1561. local url="$1"
  1562. local filter="${2:-(?<=href=\")[^\"]+\.(tar\.(gz|bz2|xz)|7z)}"
  1563. "${curl_opts[@]}" -l "$url" | grep -ioP "$filter" | sort -uV
  1564. }
  1565. get_last_version() {
  1566. local filelist="$1"
  1567. local filter="$2"
  1568. local version="$3"
  1569. local ret
  1570. ret="$(/usr/bin/grep -E "$filter" <<< "$filelist" | sort -V | tail -1)"
  1571. [[ -n $version ]] && ret="$(/usr/bin/grep -oP "$version" <<< "$ret")"
  1572. echo "$ret"
  1573. }
  1574. create_debug_link() {
  1575. for file; do
  1576. if [[ -f $file && ! -f "$file".debug ]]; then
  1577. echo "Stripping and creating debug link for ${file##*/}..."
  1578. objcopy --only-keep-debug "$file" "$file".debug
  1579. if [[ ${file: -3} == "dll" ]]; then
  1580. strip --strip-debug "$file"
  1581. else
  1582. strip --strip-all "$file"
  1583. fi
  1584. objcopy --add-gnu-debuglink="$file".debug "$file"
  1585. fi
  1586. done
  1587. }
  1588. get_vs_prefix() {
  1589. unset vsprefix
  1590. local winvsprefix
  1591. local regkey="/HKLM/software/vapoursynth/path"
  1592. local embedded
  1593. embedded="$(find "$LOCALDESTDIR"/bin-video -iname vspipe.exe)"
  1594. if [[ -n $embedded ]]; then
  1595. # look for .dlls in bin-video
  1596. vsprefix="${embedded%/*}"
  1597. elif [[ $bits == 64bit ]] && winvsprefix="$(regtool -q get "$regkey")"; then
  1598. # check in native HKLM for installed VS (R31+)
  1599. [[ -n $winvsprefix && -f "$winvsprefix/core64/vspipe.exe" ]] &&
  1600. vsprefix="$(cygpath -u "$winvsprefix")/core64"
  1601. elif winvsprefix="$(regtool -qW get "$regkey")"; then
  1602. # check in 32-bit registry for installed VS
  1603. [[ -n $winvsprefix && -f "$winvsprefix/core${bits%bit}/vspipe.exe" ]] &&
  1604. vsprefix="$(cygpath -u "$winvsprefix/core${bits%bit}")"
  1605. elif [[ -n $(command -v vspipe.exe 2> /dev/null) ]]; then
  1606. # last resort, check if vspipe is in path
  1607. vsprefix="$(dirname "$(command -v vspipe.exe)")"
  1608. fi
  1609. if [[ -n $vsprefix && -f "$vsprefix/vapoursynth.dll" && -f "$vsprefix/vsscript.dll" ]]; then
  1610. local bitness
  1611. bitness="$(file "$vsprefix/vapoursynth.dll")"
  1612. { [[ $bits == 64bit && $bitness == *x86-64* ]] ||
  1613. [[ $bits == 32bit && $bitness == *80386* ]]; } &&
  1614. return 0
  1615. else
  1616. return 1
  1617. fi
  1618. }
  1619. get_cl_path() {
  1620. { type cl.exe && cl --help; } > /dev/null 2>&1 && return 0
  1621. local _suite_vswhere=/opt/bin/vswhere.exe _sys_vswhere
  1622. if _sys_vswhere=$(cygpath -u "$(cygpath -F 0x002a)/Microsoft Visual Studio/Installer/vswhere.exe") &&
  1623. "$_sys_vswhere" -help > /dev/null 2>&1; then
  1624. vswhere=$_sys_vswhere
  1625. elif [[ -e $_suite_vswhere ]] &&
  1626. $_suite_vswhere -help > /dev/null 2>&1; then
  1627. vswhere=$_suite_vswhere
  1628. elif (
  1629. cd "$LOCALBUILDDIR" 2> /dev/null || return 1
  1630. do_wget -c -r -q "https://github.com/Microsoft/vswhere/releases/latest/download/vswhere.exe"
  1631. ./vswhere.exe -help > /dev/null 2>&1 || return 1
  1632. do_install vswhere.exe /opt/bin/
  1633. ); then
  1634. vswhere=$_suite_vswhere
  1635. else
  1636. return 1
  1637. fi
  1638. local _hostbits=HostX64 _arch=x64
  1639. [[ $(uname -m) != x86_64 ]] && _hostbits=HostX86
  1640. [[ $bits == 32bit ]] && _arch=x86
  1641. local basepath
  1642. if basepath=$(cygpath -u "$("$vswhere" -latest -all -find "VC/Tools/MSVC/*/bin/${_hostbits:-HostX64}/${_arch:-x64}" | sort -uV | tail -1)") &&
  1643. "$basepath/cl.exe" /? > /dev/null 2>&1; then
  1644. export PATH="$basepath:$PATH"
  1645. return 0
  1646. else
  1647. return 1
  1648. fi
  1649. }
  1650. get_java_home() {
  1651. local javahome version
  1652. local javabasereg="/HKLM/software/javasoft"
  1653. local regkey="$javabasereg/java development kit"
  1654. export JAVA_HOME=
  1655. export JDK_HOME=""
  1656. if ! regtool -q check "$regkey"; then
  1657. echo "no version of JDK found"
  1658. return
  1659. fi
  1660. version="$(regtool -q get "$regkey/CurrentVersion")"
  1661. [[ $(vercmp "$version" 1.8) != 0 ]] &&
  1662. echo "JDK 1.8 required, 9 doesn't work" && return
  1663. javahome="$(regtool -q get "$regkey/$version/JavaHome")"
  1664. javahome="$(cygpath -u "$javahome")"
  1665. [[ -f "$javahome/bin/java.exe" ]] &&
  1666. export JAVA_HOME="$javahome"
  1667. }
  1668. get_api_version() {
  1669. local header="$1"
  1670. [[ -n $(file_installed "$header") ]] && header="$(file_installed "$header")"
  1671. local line="$2"
  1672. local column="$3"
  1673. [[ ! -f $header ]] && printf '' && return
  1674. /usr/bin/grep "${line:-VERSION}" "$header" | awk '{ print $c }' c="${column:-3}" | sed 's|"||g'
  1675. }
  1676. hide_files() {
  1677. local reverse=n echo_cmd
  1678. [[ $1 == "-R" ]] && reverse=y && shift
  1679. [[ $dryrun == y ]] && echo_cmd="echo"
  1680. for opt; do
  1681. if [[ $reverse == n ]]; then
  1682. [[ -f $opt ]] && $echo_cmd mv -f "$opt" "$opt.bak"
  1683. else
  1684. [[ -f "$opt.bak" ]] && $echo_cmd mv -f "$opt.bak" "$opt"
  1685. fi
  1686. done
  1687. }
  1688. hide_conflicting_libs() {
  1689. # meant for rude build systems
  1690. local reverse=n
  1691. [[ $1 == "-R" ]] && reverse=y && shift
  1692. local priority_prefix
  1693. local -a installed
  1694. mapfile -t installed < <(find "$LOCALDESTDIR/lib" -maxdepth 1 -name "*.a")
  1695. if [[ $reverse == n ]]; then
  1696. hide_files "${installed[@]//$LOCALDESTDIR/$MINGW_PREFIX}"
  1697. else
  1698. hide_files -R "${installed[@]//$LOCALDESTDIR/$MINGW_PREFIX}"
  1699. fi
  1700. if [[ -n $1 ]]; then
  1701. priority_prefix="$1"
  1702. mapfile -t installed < <(find "$priority_prefix/lib" -maxdepth 1 -name "*.a")
  1703. if [[ $reverse == n ]]; then
  1704. hide_files "${installed[@]//$1/$LOCALDESTDIR}"
  1705. else
  1706. hide_files -R "${installed[@]//$1/$LOCALDESTDIR}"
  1707. fi
  1708. fi
  1709. }
  1710. hide_libressl() {
  1711. local _hide_files=(include/openssl
  1712. lib/lib{crypto,ssl,tls}.{,l}a
  1713. lib/pkgconfig/openssl.pc
  1714. lib/pkgconfig/lib{crypto,ssl,tls}.pc)
  1715. local reverse=n
  1716. local _f
  1717. [[ $1 == "-R" ]] && reverse=y && shift
  1718. for _f in ${_hide_files[*]}; do
  1719. _f="$LOCALDESTDIR/$_f"
  1720. if [[ $reverse == n ]]; then
  1721. [[ -e $_f ]] && mv -f "$_f" "$_f.bak"
  1722. else
  1723. [[ -e "$_f.bak" ]] && mv -f "$_f.bak" "$_f"
  1724. fi
  1725. done
  1726. }
  1727. add_to_remove() {
  1728. echo "${1:-$(get_first_subdir -f)}" >> "$LOCALBUILDDIR/_to_remove"
  1729. }
  1730. clean_suite() {
  1731. do_simple_print -p "${orange}Deleting status files...${reset}"
  1732. cd_safe "$LOCALBUILDDIR" > /dev/null
  1733. find . -maxdepth 2 \( -name recently_updated -o -name recently_checked \) -delete
  1734. find . -maxdepth 2 -regex ".*build_successful\(32\|64\)bit\(_\\w+\)?\$" -delete
  1735. echo -e "\\n\\t${green}Zipping man files...${reset}"
  1736. do_zipman
  1737. if [[ $deleteSource == y ]]; then
  1738. echo -e "\\t${orange}Deleting temporary build dirs...${reset}"
  1739. find . -maxdepth 5 -name "ab-suite.*.log" -delete
  1740. find . -maxdepth 5 -type d -name "build-*bit" -exec rm -rf {} +
  1741. find . -maxdepth 2 -type d -name "build" -exec test -f "{}/CMakeCache.txt" ';' -exec rm -rf {} ';'
  1742. if [[ -f _to_remove ]]; then
  1743. echo -e "\\n\\t${orange}Deleting source folders...${reset}"
  1744. grep -E "^($LOCALBUILDDIR|/trunk$LOCALBUILDDIR)" < _to_remove |
  1745. grep -Ev "^$LOCALBUILDDIR/(patches|extras|$)" | sort -u | xargs -r rm -rf
  1746. fi
  1747. if [[ $(du -s /var/cache/pacman/pkg/ | cut -f1) -gt 1000000 ]]; then
  1748. echo -e "\\t${orange}Deleting unneeded Pacman packages...${reset}"
  1749. pacman -Sc --noconfirm
  1750. fi
  1751. fi
  1752. rm -f {firstrun,firstUpdate,secondUpdate,pacman,mingw32,mingw64}.log diagnostics.txt \
  1753. logs.zip _to_remove ./*.stripped.log
  1754. [[ -f last_run ]] && mv last_run last_successful_run && touch last_successful_run
  1755. [[ -f CHANGELOG.txt ]] && cat CHANGELOG.txt >> newchangelog
  1756. unix2dos -n newchangelog CHANGELOG.txt 2> /dev/null && rm -f newchangelog
  1757. }
  1758. create_diagnostic() {
  1759. local cmd cmds=("uname -a" "pacman -Qe" "pacman -Qd")
  1760. local _env envs=(MINGW_{PACKAGE_PREFIX,CHOST,PREFIX} MSYSTEM CPATH
  1761. LIBRARY_PATH {LD,C,CPP,CXX}FLAGS PATH)
  1762. do_print_progress " Creating diagnostics file"
  1763. git -C /trunk rev-parse --is-inside-work-tree > /dev/null 2>&1 &&
  1764. cmds+=("git -C /trunk log -1 --pretty=%h")
  1765. {
  1766. echo "Env variables:"
  1767. for _env in "${envs[@]}"; do
  1768. printf '\t%s=%s\n' "$_env" "${!_env}"
  1769. done
  1770. echo
  1771. for cmd in "${cmds[@]}"; do
  1772. printf '\t%s\n%s\n\n' "$cmd": "$($cmd)"
  1773. done
  1774. } > "$LOCALBUILDDIR/diagnostics.txt"
  1775. }
  1776. create_winpty_exe() {
  1777. local exename="$1"
  1778. local installdir="$2"
  1779. shift 2
  1780. [[ -f "${installdir}/${exename}".exe ]] && mv "${installdir}/${exename}"{.,_}exe
  1781. # shellcheck disable=SC2016
  1782. printf '%s\n' "#!/usr/bin/env bash" "$@" \
  1783. 'if [[ -t 1 ]]; then' \
  1784. '/usr/bin/winpty "$( dirname ${BASH_SOURCE[0]} )/'"${exename}"'.exe" "$@"' \
  1785. 'else "$( dirname ${BASH_SOURCE[0]} )/'"${exename}"'.exe" "$@"; fi' \
  1786. > "${installdir}/${exename}"
  1787. [[ -f "${installdir}/${exename}"_exe ]] && mv "${installdir}/${exename}"{_,.}exe
  1788. }
  1789. create_ab_pkgconfig() {
  1790. # from https://stackoverflow.com/a/8088167
  1791. local script_file
  1792. IFS=$'\n' read -r -d '' script_file << 'EOF' || true
  1793. #!/bin/sh
  1794. while true; do
  1795. case $1 in
  1796. --libs|--libs-*) libs_args+=" $1"; shift ;;
  1797. --static) static="--static"; shift ;;
  1798. --* ) base_args+=" $1"; shift ;;
  1799. * ) break ;;
  1800. esac
  1801. done
  1802. [[ -n $PKGCONF_STATIC ]] && static="--static"
  1803. run_pkgcfg() {
  1804. "$MINGW_PREFIX/bin/pkg-config" "$@" || exit 1
  1805. }
  1806. deduplicateLibs() {
  1807. otherflags="$(run_pkgcfg $static $base_args "$@")"
  1808. unordered="$(run_pkgcfg $static $libs_args "$@")"
  1809. libdirs="$(printf '%s\n' $unordered | grep '^-L' | tr '\n' ' ')"
  1810. unordered="${unordered//$libdirs}"
  1811. ord_libdirs=""
  1812. for libdir in $libdirs; do
  1813. libdir="$(cygpath -m ${libdir#-L})"
  1814. ord_libdirs+=" -L$libdir"
  1815. done
  1816. ord_libdirs="$(printf '%s\n' $ord_libdirs | awk '!x[$0]++' | tr '\n' ' ')"
  1817. ord_libs="$(printf '%s\n' $unordered | tac | awk '!x[$0]++' | tac | tr '\n' ' ')"
  1818. printf '%s ' $otherflags $ord_libdirs $ord_libs
  1819. echo
  1820. }
  1821. if [[ -n $libs_args ]]; then
  1822. deduplicateLibs "$@"
  1823. else
  1824. run_pkgcfg $static $base_args $libs_args "$@"
  1825. fi
  1826. EOF
  1827. [[ -f "$LOCALDESTDIR"/bin/ab-pkg-config ]] &&
  1828. diff -q <(printf '%s' "$script_file") "$LOCALDESTDIR"/bin/ab-pkg-config > /dev/null ||
  1829. printf '%s' "$script_file" > "$LOCALDESTDIR"/bin/ab-pkg-config
  1830. [[ -f "$LOCALDESTDIR"/bin/ab-pkg-config.bat ]] ||
  1831. printf '%s\r\n' "@echo off" "" "bash $LOCALDESTDIR/bin/ab-pkg-config %*" > "$LOCALDESTDIR"/bin/ab-pkg-config.bat
  1832. [[ -f "$LOCALDESTDIR"/bin/ab-pkg-config-static.bat ]] ||
  1833. printf '%s\r\n' "@echo off" "" "bash $LOCALDESTDIR/bin/ab-pkg-config --static %*" > "$LOCALDESTDIR"/bin/ab-pkg-config-static.bat
  1834. }
  1835. create_ab_ccache() {
  1836. local bin temp_file ccache_path=false ccache_win_path=
  1837. temp_file=$(mktemp)
  1838. if [[ $ccache == y ]] && type ccache > /dev/null 2>&1; then
  1839. ccache_path="$(command -v ccache)"
  1840. ccache_win_path=$(cygpath -m "$ccache_path")
  1841. fi
  1842. for bin in {$MINGW_CHOST-,}{gcc,g++} clang{,++} cc cpp c++; do
  1843. type "$bin" > /dev/null 2>&1 || continue
  1844. cat << EOF > "$temp_file"
  1845. @echo off >nul 2>&1
  1846. rem() { "\$@"; }
  1847. rem test -f nul && rm nul
  1848. rem $ccache_path --help > /dev/null 2>&1 && $ccache_path $(command -v $bin) "\$@" || $(command -v $bin) "\$@"
  1849. rem exit \$?
  1850. $ccache_win_path $(cygpath -m "$(command -v $bin)") %*
  1851. EOF
  1852. diff -q "$temp_file" "$LOCALDESTDIR/bin/$bin.bat" > /dev/null 2>&1 || cp -f "$temp_file" "$LOCALDESTDIR/bin/$bin.bat"
  1853. chmod +x "$LOCALDESTDIR/bin/$bin.bat"
  1854. done
  1855. rm "$temp_file"
  1856. }
  1857. create_cmake_toolchain() {
  1858. local _win_path_LOCALDESTDIR _win_path_MINGW_PREFIX
  1859. _win_path_LOCALDESTDIR="$(cygpath -m "$LOCALDESTDIR")"
  1860. _win_path_MINGW_PREFIX="$(cygpath -m "$MINGW_PREFIX")"
  1861. local toolchain_file=(
  1862. "SET(CMAKE_RC_COMPILER_INIT windres)"
  1863. ""
  1864. "LIST(APPEND CMAKE_PROGRAM_PATH $_win_path_LOCALDESTDIR/bin)"
  1865. "SET(CMAKE_FIND_ROOT_PATH $_win_path_LOCALDESTDIR $_win_path_MINGW_PREFIX $_win_path_MINGW_PREFIX/$MINGW_CHOST)"
  1866. "SET(CMAKE_PREFIX_PATH $_win_path_LOCALDESTDIR $_win_path_MINGW_PREFIX $_win_path_MINGW_PREFIX/$MINGW_CHOST)"
  1867. "SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)"
  1868. "SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)"
  1869. )
  1870. [[ -f "$LOCALDESTDIR"/etc/toolchain.cmake ]] &&
  1871. diff -q <(printf '%s\n' "${toolchain_file[@]}") "$LOCALDESTDIR"/etc/toolchain.cmake > /dev/null ||
  1872. printf '%s\n' "${toolchain_file[@]}" > "$LOCALDESTDIR"/etc/toolchain.cmake
  1873. }
  1874. get_signature() {
  1875. # get_signature 96865171 0F3BE490
  1876. # adds keys to gpg keychain for verifying
  1877. for keyserver in keys.openpgp.org pool.sks-keyservers.net keyserver.ubuntu.com pgp.mit.edu; do
  1878. gpg --keyserver "$keyserver" --receive-keys "$@" && break
  1879. done > /dev/null 2>&1
  1880. }
  1881. check_signature() {
  1882. # check_signature -k 96865171 gnutls-3.6.8.tar.xz.sig gnutls-3.6.8.tar.xz
  1883. # check_signature -k 1528635D8053A57F77D1E08630A59377A7763BE6 http://libsdl.org/release/SDL2-2.0.10.tar.gz.sig SDL2-2.0.10.tar.gz
  1884. # run in the same directory as the files. Works with .sig and some .asc
  1885. # file needs to start with -----BEGIN PGP SIGNATURE-----
  1886. local key=()
  1887. while true; do
  1888. case $1 in
  1889. -k) key+=("$2") && shift 2 ;; # keys to retrieve using get_signature
  1890. --)
  1891. shift
  1892. break
  1893. ;;
  1894. *) break ;;
  1895. esac
  1896. done
  1897. local sigFile=$1
  1898. shift
  1899. # Get name of sig file
  1900. local sigFileName=${sigFile##*/}
  1901. sigFileName=${sigFileName:-"$(/usr/bin/curl -sI "$sigFile" | grep -Eo 'filename=.*$' | sed 's/filename=//')"}
  1902. [[ -z $sigFileName ]] && echo "Sig file not set" && return 1
  1903. # Download sig file if url/cp file if local file
  1904. if ! do_wget -c -r -q "$sigFile" "$sigFileName" && [[ -f $sigFile ]]; then
  1905. sigFile="$(
  1906. cd_safe "$(dirname "$sigFile")"
  1907. printf '%s' "$(pwd -P)" '/' "$(basename -- "$sigFile")"
  1908. )"
  1909. [[ ${sigFile%/*} != "$PWD" ]] && cp -f "$sigFile" "$sigFileName" > /dev/null 2>&1
  1910. fi
  1911. # Retrive keys
  1912. [[ -n ${key[0]} ]] && get_signature "${key[@]}"
  1913. # Verify file is correct
  1914. # $? 1 Bad sig or file integrity compromised
  1915. # $? 2 no-pub-key or no file
  1916. gpg --auto-key-retrieve --keyserver hkps://hkps.pool.sks-keyservers.net --verify "$sigFileName" "$@" > /dev/null 2>&1
  1917. case $? in
  1918. 1) do_exit_prompt "Failed to verify integrity of ${sigFileName%%.sig}" ;;
  1919. 2) do_exit_prompt "Failed to find gpg key or no file found for ${sigFileName%%.sig}" ;;
  1920. esac
  1921. }
  1922. do_jq() {
  1923. local jq_file="$jq_file" output_raw_string=true
  1924. # Detect if in pipe, useful for curling github api
  1925. if [[ ! -t 0 ]]; then
  1926. jq_file=/dev/stdin
  1927. elif [[ -f $1 ]]; then
  1928. jq_file="$1" && shift
  1929. fi
  1930. for a in "$@"; do
  1931. grep -q -- ^- <<< "$a" && output_raw_string=false
  1932. done
  1933. if $output_raw_string; then
  1934. jq -r "$*" < "$jq_file"
  1935. else
  1936. jq "$@" < "$jq_file"
  1937. fi
  1938. }
  1939. grep_or_sed() {
  1940. local grep_re="$1"
  1941. local grep_file="$2"
  1942. [[ ! -f $grep_file ]] && return
  1943. local sed_re="$3"
  1944. shift 3
  1945. local sed_files=("$grep_file")
  1946. [[ -n $1 ]] && sed_files=("$@")
  1947. /usr/bin/grep -q -- "$grep_re" "$grep_file" ||
  1948. /usr/bin/sed -ri -- "$sed_re" "${sed_files[@]}"
  1949. }
  1950. grep_and_sed() {
  1951. local grep_re="$1"
  1952. local grep_file="$2"
  1953. [[ ! -f $grep_file ]] && return
  1954. local sed_re="$3"
  1955. shift 3
  1956. local sed_files=("$grep_file")
  1957. [[ -n $1 ]] && sed_files=("$@")
  1958. /usr/bin/grep -q -- "$grep_re" "$grep_file" &&
  1959. /usr/bin/sed -ri -- "$sed_re" "${sed_files[@]}"
  1960. }
  1961. compare_with_zeranoe() {
  1962. local comparison="${1:-builtin}"
  1963. local zeranoebase="https://ffmpeg.zeranoe.com/builds/readme"
  1964. local zeranoe32 zeranoe64
  1965. zeranoe32="$(curl -s "${zeranoebase}"/win32/static/ffmpeg-latest-win32-static-readme.txt |
  1966. sed -n '/Configuration/,/Libraries/{/\s*--/{s/\s*//gp}}' | sort)"
  1967. zeranoe64="$(curl -s "${zeranoebase}"/win64/static/ffmpeg-latest-win64-static-readme.txt |
  1968. sed -n '/Configuration/,/Libraries/{/\s*--/{s/\s*//gp}}' | sort)"
  1969. local localopts32=""
  1970. local localopts64=""
  1971. if [[ $comparison == "custom" ]]; then
  1972. local custom32="$LOCALBUILDDIR/ffmpeg_options_32bit.txt"
  1973. local custom64="$LOCALBUILDDIR/ffmpeg_options_64bit.txt"
  1974. local custom="$LOCALBUILDDIR/ffmpeg_options.txt"
  1975. [[ -f $custom32 ]] || custom32="$custom"
  1976. [[ -f $custom64 ]] || custom64="$custom"
  1977. if [[ -f $custom32 ]]; then
  1978. IFS=$'\n' read -d '' -r -a localopts32 < <(do_readoptionsfile "$custom32")
  1979. fi
  1980. if [[ -f $custom64 ]]; then
  1981. IFS=$'\n' read -d '' -r -a localopts64 < <(do_readoptionsfile "$custom64")
  1982. fi
  1983. else
  1984. IFS=$'\r\n' read -d '' -r -a bat < /trunk/media-autobuild_suite.bat
  1985. localopts32="$(do_readbatoptions "ffmpeg_options_(builtin|basic|zeranoe)" | sort)"
  1986. localopts64="$localopts32"
  1987. fi
  1988. echo "Missing options from zeranoe 32-bits in $comparison options:"
  1989. comm -23 <(echo "$zeranoe32") <(echo "$localopts32")
  1990. printf '\n'
  1991. echo "Missing options from zeranoe 64-bits in $comparison options:"
  1992. comm -23 <(echo "$zeranoe64") <(echo "$localopts64")
  1993. printf '\n'
  1994. }
  1995. fix_libtiff_pc() {
  1996. pc_exists libtiff-4 || return
  1997. local _pkgconfLoc
  1998. _pkgconfLoc="$(cygpath -u "$(pkg-config --debug libtiff-4 2>&1 |
  1999. sed -rn "/Reading/{s/.*'(.*\.pc)'.*/\1/gp}")")"
  2000. [[ ! -f $_pkgconfLoc ]] && return
  2001. grep_or_sed zstd "$_pkgconfLoc" 's;Libs.private:.*;& -lzstd;'
  2002. }
  2003. fix_cmake_crap_exports() {
  2004. local _dir="$1"
  2005. # noop if passed directory is not valid
  2006. test -d "$_dir" || return 1
  2007. local _mixeddestdir _oldDestDir _cmakefile
  2008. declare -a _cmakefiles
  2009. _mixeddestdir="$(cygpath -m "$LOCALDESTDIR")"
  2010. mapfile -t _cmakefiles < <(grep -Plr '\w:/[\w/]*local(?:32|64)' "$_dir"/*.cmake)
  2011. # noop if array is empty
  2012. test ${#_cmakefiles[@]} -lt 1 && return
  2013. for _cmakefile in "${_cmakefiles[@]}"; do
  2014. # find at least one
  2015. _oldDestDir="$(grep -oP -m1 '\w:/[\w/]*local(?:32|64)' "$_cmakefile")"
  2016. # noop if there's no expected install prefix found
  2017. [[ -z $_oldDestDir ]] && continue
  2018. # noop if old and current install prefix are equal
  2019. [[ $_mixeddestdir == "$_oldDestDir" ]] && continue
  2020. # use perl for the matching and replacing, a bit simpler than with sed
  2021. perl -i -p -e 's;([A-Z]:/.*?)local(?:32|64);'"$_mixeddestdir"'\2;' "$_cmakefile"
  2022. done
  2023. }
  2024. verify_cuda_deps() {
  2025. enabled cuda-sdk && do_removeOption --enable-cuda-sdk && do_addOption --enable-cuda-nvcc
  2026. if enabled_any libnpp cuda-nvcc && [[ $license != "nonfree" ]]; then
  2027. do_removeOption "--enable-(cuda-nvcc|libnpp)"
  2028. fi
  2029. if enabled libnpp && [[ $bits == 32bit ]]; then
  2030. echo -e "${orange}libnpp is only supported in 64-bit.${reset}"
  2031. do_removeOption --enable-libnpp
  2032. fi
  2033. if enabled_any libnpp cuda-nvcc && [[ -z $CUDA_PATH || ! -d $CUDA_PATH ]]; then
  2034. echo -e "${orange}CUDA_PATH environment variable not set or directory does not exist.${reset}"
  2035. do_removeOption "--enable-(cuda-nvcc|libnpp)"
  2036. fi
  2037. if enabled libnpp && [[ ! -f "$CUDA_PATH/lib/x64/nppc.lib" ]]; then
  2038. do_removeOption --enable-libnpp
  2039. fi
  2040. if ! disabled cuda-llvm && do_pacman_install clang; then
  2041. do_removeOption --enable-cuda-nvcc
  2042. else
  2043. do_removeOption --enable-cuda-llvm
  2044. do_addOption --disable-cuda-llvm
  2045. fi
  2046. if enabled cuda-nvcc; then
  2047. if ! get_cl_path; then
  2048. echo -e "${orange}MSVC cl.exe not found in PATH or through vswhere; needed by nvcc.${reset}"
  2049. do_removeOption --enable-cuda-nvcc
  2050. elif enabled cuda-nvcc && ! nvcc.exe --help &> /dev/null &&
  2051. ! "$(cygpath -sm "$CUDA_PATH")/bin/nvcc.exe" --help &> /dev/null; then
  2052. echo -e "${orange}nvcc.exe not found in PATH or installed in CUDA_PATH.${reset}"
  2053. do_removeOption --enable-cuda-nvcc
  2054. fi
  2055. fi
  2056. enabled_any libnpp cuda-nvcc || ! disabled cuda-llvm
  2057. }
  2058. check_custom_patches() {
  2059. local _basedir
  2060. _basedir="$(get_first_subdir)"
  2061. local vcsFolder="${_basedir%-*}"
  2062. local vcsType="${_basedir##*-}"
  2063. if [[ -d $LOCALBUILDDIR && -f "$LOCALBUILDDIR/${vcsFolder}_extra.sh" ]]; then
  2064. export REPO_DIR="$LOCALBUILDDIR/${_basedir}"
  2065. export REPO_NAME="${vcsFolder}"
  2066. do_print_progress "Found ${vcsFolder}_extra.sh. Sourcing script"
  2067. source "$LOCALBUILDDIR/${vcsFolder}_extra.sh"
  2068. echo "${vcsFolder}" >> "$LOCALBUILDDIR/patchedFolders"
  2069. sort -uo "$LOCALBUILDDIR/patchedFolders"{,}
  2070. fi
  2071. }
  2072. extra_script() {
  2073. local stage="$1"
  2074. local commandname="$2"
  2075. local vcsFolder="${REPO_DIR%-*}"
  2076. vcsFolder="${vcsFolder#*build/}"
  2077. if [[ $commandname =~ ^(make|ninja)$ ]] &&
  2078. type "_${stage}_build" > /dev/null 2>&1; then
  2079. pushd "${REPO_DIR}" > /dev/null || true
  2080. do_print_progress "Running ${stage} build from ${vcsFolder}_extra.sh"
  2081. log -q "${stage}_build" "_${stage}_build"
  2082. popd > /dev/null || true
  2083. elif type "_${stage}_${commandname}" > /dev/null 2>&1; then
  2084. pushd "${REPO_DIR}" > /dev/null || true
  2085. do_print_progress "Running ${stage} ${commandname} from ${vcsFolder}_extra.sh"
  2086. log -q "${stage}_${commandname}" "_${stage}_${commandname}"
  2087. popd > /dev/null || true
  2088. fi
  2089. }
  2090. unset_extra_script() {
  2091. # The current repository folder (/build/ffmpeg-git)
  2092. unset REPO_DIR
  2093. # The repository name (ffmpeg)
  2094. unset REPO_NAME
  2095. # Each of the _{pre,post}_<Command> means that there is a "_pre_<Command>"
  2096. # and "_post_<Command>"
  2097. # Runs before and after building rust packages (do_rust)
  2098. unset _{pre,post}_rust
  2099. ## Pregenerational hooks
  2100. # Runs before and after running autoreconf -fiv (do_autoreconf)
  2101. unset _{pre,post}_autoreconf
  2102. # Runs before and after running ./autogen.sh (do_autogen)
  2103. unset _{pre,post}_autogen
  2104. # Generational hooks
  2105. # Runs before and after running ./configure (do_separate_conf, do_configure)
  2106. unset _{pre,post}_configure
  2107. # Runs before and after running cmake (do_cmake)
  2108. unset _{pre,post}_cmake
  2109. ## Build hooks
  2110. # Runs before and after runing make (do_make)
  2111. unset _{pre,post}_make
  2112. # Runs before and after running meson (do_meson)
  2113. unset _{pre,post}_meson
  2114. # Runs before and after running ninja (do_ninja)
  2115. unset _{pre,post}_ninja
  2116. unset _{pre,post}_qmake
  2117. # Runs before and after running make, meson, ninja, and waf (Generic hook for the previous build hooks)
  2118. # If this is present, it will override the other hooks
  2119. # Use for mpv and python waf based stuff.
  2120. unset _{pre,post}_build
  2121. ## Post build hooks
  2122. # Runs before and after either ninja install
  2123. # or make install or using install
  2124. # (do_makeinstall, do_ninjainstall, do_install)
  2125. unset _{pre,post}_install
  2126. }
  2127. create_extra_skeleton() {
  2128. local overwrite
  2129. while true; do
  2130. case $1 in
  2131. -f) overwrite=y && shift ;;
  2132. --)
  2133. shift
  2134. break
  2135. ;;
  2136. *) break ;;
  2137. esac
  2138. done
  2139. local extraName="$1"
  2140. [[ -z $extraName ]] &&
  2141. printf '%s\n' \
  2142. 'Usage: create_extra_skeleton [-f] <vcs folder name without the vcs type suffix>' \
  2143. 'For example, to create a ffmpeg_extra.sh skeleton file in '"$LOCALBUILDDIR"':' \
  2144. '> create_extra_skeleton ffmpeg' && return 1
  2145. [[ -f "$LOCALBUILDDIR/$extraName"_extra.sh && -z $overwrite ]] &&
  2146. echo "$LOCALBUILDDIR/$extraName_extra.sh already exists. Use -f if you are sure you want to overwrite it." && return 1
  2147. IFS=$'\n' read -r -d '' script_file << 'EOF' || true
  2148. #!/bin/bash
  2149. # Force to the suite to think the package has updates to recompile.
  2150. # Alternatively, you can use "touch recompile" for a similar effect.
  2151. #touch custom_updated
  2152. # Commands to run before and after running cmake (do_cmake)
  2153. _pre_cmake(){
  2154. # Installs libwebp
  2155. #do_pacman_install libwebp
  2156. # Downloads the patch and then applies the patch
  2157. #do_patch "https://gist.githubusercontent.com/1480c1/9fa9292afedadcea2b3a3e067e96dca2/raw/50a3ed39543d3cf21160f9ad38df45d9843d8dc5/0001-Example-patch-for-learning-purpose.patch"
  2158. # Change directory to the build folder
  2159. #cd_safe "build-${bits}"
  2160. # Add additional options to suite's cmake execution
  2161. #cmake_extras=(-DENABLE_SWEET_BUT_BROKEN_FEATURE=on)
  2162. # To bypass the suite's cmake execution completely, create a do_not_configure file in the repository root:
  2163. #touch "$(get_first_subdir -f)/do_not_reconfigure"
  2164. true
  2165. }
  2166. _post_cmake(){
  2167. # Run cmake directly with custom options. $LOCALDESTDIR refers to local64 or local32
  2168. #cmake .. -G"Ninja" -DCMAKE_INSTALL_PREFIX="$LOCALDESTDIR" \
  2169. # -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=clang \
  2170. # -DBUILD_SHARED_LIBS=off -DENABLE_TOOLS=off
  2171. true
  2172. }
  2173. # Runs before and after building rust packages (do_rust)
  2174. _pre_rust() {
  2175. # Add additional options to suite's rust (cargo) execution
  2176. #rust_extras=(--no-default-features --features=binaries)
  2177. # To bypass the suite's cargo execution completely, create a do_not_configure file in the repository root:
  2178. #touch "$(get_first_subdir -f)/do_not_reconfigure"
  2179. true
  2180. }
  2181. _post_rust() {
  2182. true
  2183. }
  2184. # Runs before and after running meson (do_meson)
  2185. _pre_meson() {
  2186. # Add additional options to suite's rust (cargo) execution
  2187. #meson_extras=(-Denable_tools=true)
  2188. # To bypass the suite's meson execution completely, create a do_not_configure file in the repository root:
  2189. #touch "$(get_first_subdir -f)/do_not_reconfigure"
  2190. true
  2191. }
  2192. _post_meson() {
  2193. true
  2194. }
  2195. # Runs before and after running autoreconf -fiv (do_autoreconf)
  2196. _pre_autoreconf() {
  2197. true
  2198. }
  2199. _post_autoreconf() {
  2200. true
  2201. }
  2202. # Runs before and after running ./autogen.sh (do_autogen)
  2203. _pre_autogen() {
  2204. true
  2205. }
  2206. _post_autogen() {
  2207. true
  2208. }
  2209. # Commands to run before and after running configure on a Autoconf/Automake/configure-using package
  2210. _pre_configure(){
  2211. true
  2212. #
  2213. # Apply a patch from ffmpeg's patchwork site.
  2214. #do_patch "https://patchwork.ffmpeg.org/patch/12563/mbox/" am
  2215. #
  2216. # Apply a local patch inside the directory where is "ffmpeg_extra.sh"
  2217. #patch -p1 -i "$LOCALBUILDDIR/ffmpeg-0001-my_patch.patch"
  2218. #
  2219. # Add extra configure options to ffmpeg (ffmpeg specific)
  2220. # If you want to add something to ffmpeg not within the suite already
  2221. # you will need to install it yourself, either through pacman
  2222. # or compiling from source.
  2223. #FFMPEG_OPTS+=(--enable-libsvthevc)
  2224. #
  2225. }
  2226. _post_configure(){
  2227. true
  2228. }
  2229. # Runs before and after runing make (do_make)
  2230. _pre_make(){
  2231. true
  2232. }
  2233. _post_make(){
  2234. true
  2235. # Don't run configure again.
  2236. #touch "$(get_first_subdir -f)/do_not_reconfigure"
  2237. # Don't clean the build folder on each successive run.
  2238. # This is for if you want to keep the current build folder as is and just recompile only.
  2239. #touch "$(get_first_subdir -f)/do_not_clean"
  2240. }
  2241. # Runs before and after running ninja (do_ninja)
  2242. _pre_ninja() {
  2243. true
  2244. }
  2245. _post_ninja() {
  2246. true
  2247. }
  2248. # Runs before and after running make, meson, ninja, and waf (Generic hook for the previous build hooks)
  2249. # If this is present, it will override the other hooks
  2250. # Use for mpv and python waf based stuff.
  2251. _pre_build() {
  2252. true
  2253. }
  2254. _post_build() {
  2255. true
  2256. }
  2257. # Runs before and after either ninja install
  2258. # or make install or using install
  2259. # (do_makeinstall, do_ninjainstall, do_install)
  2260. _pre_install() {
  2261. true
  2262. }
  2263. _post_install() {
  2264. true
  2265. }
  2266. EOF
  2267. printf '%s' "$script_file" > "${LOCALBUILDDIR}/${extraName}_extra.sh"
  2268. echo "Created skeleton file ${LOCALBUILDDIR}/${extraName}_extra.sh"
  2269. }
  2270. # if you absolutely need to remove some of these,
  2271. # add a "-e '!<hardcoded rule>'" option
  2272. # ex: "-e '!/recently_updated'"
  2273. safe_git_clean() {
  2274. git clean -xfd \
  2275. -e "/build_successful*" \
  2276. -e "/recently_updated" \
  2277. -e '/recently_checked' \
  2278. -e '/custom_updated' \
  2279. -e '**/ab-suite.*.log' \
  2280. "${@}"
  2281. }