pkgcheck 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. #!/bin/bash
  2. # SPDX-License-Identifier: GPL-2.0
  3. # Copyright (C) 2018-present Team LibreELEC (https://libreelec.tv)
  4. TXRED="$(tput setaf 1 bold)"
  5. TXGREEN="$(tput setaf 2 bold)"
  6. TXYELLOW="$(tput setaf 3 bold)"
  7. TXBLUE="$(tput setaf 4 bold)"
  8. TXMAGENTA="$(tput setaf 5 bold)"
  9. TXCYAN="$(tput setaf 6 bold)"
  10. TXRESET="$(tput sgr0)"
  11. TXCLR="$(tput el)"
  12. log() {
  13. local filename="$1" lc=$2 level="$3" msg="$4" data="$5"
  14. local txcolour flc colw
  15. [ "${level}" = "FAIL" ] && txcolour="${TXRED}" || txcolour="${TXYELLOW}"
  16. [[ ${filename} =~ ^\./ ]] && filename="${filename:2}"
  17. [ ${lc} -eq 0 ] && flc="---" || flc="$(printf "%03d" ${lc})"
  18. [[ ${filename} =~ packages/addons/addon-depends ]] && colw=80 || colw=50
  19. printf "[%s] %3s: %-*s: %-25s: %s\n" "${txcolour}${level}${TXRESET}" "${flc}" ${colw} "${filename}" "${msg}" "${data}"
  20. }
  21. process_line() {
  22. local filename="$1" lc="$2" line="$3" inassign="$4" funcname="$5"
  23. local var matches assignallowed=Y
  24. if [ -n "${funcname}" -a "${funcname}" != "configure_package" -a "${inassign}" = "Y" ]; then
  25. if [[ ${line} =~ PKG_DEPENDS_.*= ]]; then
  26. log "${filename}" ${lc} "WARN" "ignored depends assign" "${funcname}() => ${line//[[:space:]]*PKG_DEPENDS_/PKG_DEPENDS_}"
  27. fi
  28. fi
  29. [ -n "${funcname}" ] && return 0
  30. rightside="${line#*=}"
  31. for var in PKG_SHORTDESC PKG_LONGDESC PKG_IS_ADDON PKG_NEED_UNPACK PKG_SOURCE_NAME PKG_ADDON_IS_STANDALONE \
  32. PKG_CONFIGURE_SCRIPT PKG_CMAKE_SCRIPT PKG_MESON_SCRIPT \
  33. PKG_DIR PKG_ADDON_ID PKG_BUILD \
  34. DESTIMAGE CC CXX CPP LD AS AR NM \
  35. RANLIB OBJCOPY OBJDUMP STRIP \
  36. CPPFLAGS CFLAGS CXXFLAGS LDFLAGS \
  37. PKG_CONFIG PKG_CONFIG_PATH PKG_CONFIG_LIBDIR PKG_CONFIG_SYSROOT_BASE PKG_CONFIG_SYSROOT_DIR PKG_CONFIG_ALLOW_SYSTEM_CFLAGS PKG_CONFIG_ALLOW_SYSTEM_LIBS \
  38. CMAKE_CONF CMAKE \
  39. HOST_CC HOST_CXX HOSTCC HOSTCXX \
  40. CC_FOR_BUILD CXX_FOR_BUILD BUILD_CC BUILD_CXX \
  41. _python_sysroot _python_prefix _python_exec_prefix \
  42. TARGET_CONFIGURE_OPTS CMAKE_GENERATOR_NINJA TARGET_CMAKE_OPTS TARGET_MESON_OPTS \
  43. HOST_CONFIGURE_OPTS HOST_CMAKE_OPTS HOST_MESON_OPTS \
  44. INIT_CONFIGURE_OPTS INIT_CMAKE_OPTS INIT_MESON_OPTS \
  45. BOOTSTRAP_CONFIGURE_OPTS BOOTSTRAP_CMAKE_OPTS BOOTSTRAP_MESON_OPTS \
  46. ; do
  47. # After PKG_DIR, treat assigns to var as invalid
  48. [ "${var}" = "PKG_DIR" ] && assignallowed=N
  49. if [ "${assignallowed}" = "N" ]; then
  50. if [[ ${line} =~ (^|[[:space:]])${var}= ]]; then
  51. [ "${inassign}" = "N" ] && matches+=", assign to ${var}"
  52. fi
  53. fi
  54. if [[ ${line} =~ \$\{${var}} ]] || [[ ${line} =~ \$${var}[^A-Za-z0-9_] ]]; then
  55. matches+=", ref ${var}"
  56. fi
  57. if [[ ${line} =~ (^|[[:space:]])unset\ ${var}($|[[:space:]]) ]]; then
  58. matches+=", unset ${var}"
  59. fi
  60. done
  61. [ -n "${matches}" ] && log "${filename}" ${lc} "FAIL" "late binding violation" "${matches:2}"
  62. }
  63. init_target_funcs() {
  64. local f t funcs
  65. for t in target host init bootstrap; do
  66. for f in pre_build \
  67. pre_configure configure post_configure \
  68. pre_make make post_make \
  69. pre_makeinstall makeinstall post_makeinstall \
  70. ; do
  71. funcs+=" ${f}_${t}"
  72. done
  73. done
  74. echo "${funcs:1}"
  75. }
  76. check_func_name() {
  77. local filename="$1" lc="$2" line="$3"
  78. local f
  79. for f in configure_package \
  80. pre_unpack unpack post_unpack \
  81. pre_patch post_patch \
  82. pre_configure \
  83. ${TARGET_FUNCS} \
  84. pre_install post_install \
  85. addon post_install_addon \
  86. ; do
  87. [[ ${line} =~ ^${f} ]] && return 0
  88. done
  89. log "${filename}" ${lc} "WARN" "unknown function" "${line// *{*/}"
  90. }
  91. process_pkg() {
  92. local filename="$1"
  93. local lc=0 isassign=N funcname= fc=0 intertwined=N
  94. while IFS= read -r line; do
  95. lc=$((lc + 1))
  96. [[ ${line} =~ ^[[:space:]]*$ ]] && continue
  97. [[ ${line} =~ ^(|[[:space:]]*)# ]] && continue
  98. if [[ "${line}" =~ ^[^#]*\(\)[[:space:]]*$ ]]; then
  99. log "${filename}" ${lc} "FAIL" "bad func - missing brace" "${line}"
  100. fi
  101. if [[ "${line}" =~ \(\)[[:space:]]*\{ ]]; then
  102. funcname="${line//(*/}"
  103. fc=$((fc+1))
  104. check_func_name "${filename}" "${lc}" "${line}"
  105. fi
  106. if [ "${intertwined}" = "N" -a -z "${funcname}" -a ${fc} -ge 1 ]; then
  107. log "${filename}" ${lc} "WARN" "intertwined vars & funcs" "${line}"
  108. intertwined=Y
  109. fi
  110. [[ "${line}" =~ ^[[:space:]]*PKG_.*=\" ]] && isassign=Y
  111. process_line "$1" "${lc}" "${line}" "${isassign}" "${funcname}"
  112. [[ "${line}" =~ (\"$|\"[[:space:]]*$|\"[[:space:]]*#.*$) ]] && isassign=N
  113. [[ "${line}" =~ (^}|^[[:space:]]*}) ]] && funcname=
  114. done < "${filename}"
  115. # Duplicate function check
  116. while read -r count line; do
  117. [ -n "${line}" ] && log "${filename}" 0 "FAIL" "duplicate function def" "${line}"
  118. done <<< "$(grep -E ".*() {" "${filename}" | sed 's/[[:space:]]*{.*//' | sort | uniq -c | grep -v ^[[:space:]]*1[[:space:]])"
  119. }
  120. TARGET_FUNCS="$(init_target_funcs)"
  121. if [ $# -ne 0 ]; then
  122. for arg in ${@}; do
  123. for p in $(find packages projects -type f -path */${arg}/package.mk | sort); do
  124. echo -en "${TXCLR}${p}...\r" >&2
  125. process_pkg "${p}"
  126. done
  127. done
  128. else
  129. for p in $(find packages projects -type f -name package.mk | sort); do
  130. echo -en "${TXCLR}${p}...\r" >&2
  131. process_pkg "${p}"
  132. done
  133. fi
  134. echo -en "${TXCLR}" >&2