unixdeps.sh 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. #!/bin/bash
  2. # MIT License
  3. # Copyright (c) 2023 SineStriker
  4. # Description: This script calls `qmcorecmd` to deploy dependencies on Mac/Linux.
  5. # Show usage
  6. usage() {
  7. echo "Usage: $(basename $0) -i <dir> -m <path>"
  8. echo " --plugindir <plugin_dir> --libdir <lib_dir> --qmldir <qml_dir>"
  9. echo " [--qmake <qmake_path>] [--extra <extra_path>]..."
  10. echo " [--qml <qml_module>]... [--plugin <plugin>]... [--copy <src> <dest>]..."
  11. echo " [-f] [-s] [-V] [-h]"
  12. echo " -i <input_dir> Directory containing binaries and libraries"
  13. echo " -m <corecmd_path> Path to corecmd"
  14. echo " --plugindir <plugin_dir> Output directory for plugins"
  15. echo " --libdir <lib_dir> Output directory for libraries"
  16. echo " --qmldir <qml_dir> Output directory for QML files"
  17. echo " --qmake <qmake_path> Path to qmake (optional)"
  18. echo " --extra <extra_path> Extra plugin searching path (repeatable)"
  19. echo " --qml <qml_module> Relative path to QML directory (repeatable)"
  20. echo " --plugin <plugin> Specify a Qt plugin to deploy (repeatable)"
  21. echo " --copy <src> <dest> Specify additional binary file to copy and its destination directory (repeatable)"
  22. echo " -@ Add library searching paths from a list file"
  23. echo " -L Add a library searching path"
  24. echo " -f Force overwrite existing files"
  25. echo " -s Ignore C/C++ runtime and system libraries"
  26. echo " -V Show verbose output"
  27. echo " -h Show this help message"
  28. }
  29. # Initialize arguments
  30. EXTRA_PLUGIN_PATHS=()
  31. QML_REL_PATHS=()
  32. ARGS=()
  33. VERBOSE=""
  34. PLUGINS=()
  35. FILES=""
  36. # Parse command line
  37. while (( "$#" )); do
  38. case "$1" in
  39. -i) INPUT_DIR="$2"; shift 2;;
  40. -m) CORECMD_PATH="$2"; shift 2;;
  41. -@) ARGS+=("-@ \"$2\""); shift 2;;
  42. -L) ARGS+=("-L \"$2\""); shift 2;;
  43. --plugindir) PLUGIN_DIR="$2"; shift 2;;
  44. --libdir) LIB_DIR="$2"; shift 2;;
  45. --qmldir) QML_DIR="$2"; shift 2;;
  46. --qmake) QMAKE_PATH="$2"; shift 2;;
  47. --extra) EXTRA_PLUGIN_PATHS+=("$2"); shift 2;;
  48. --plugin) PLUGINS+=("$2"); shift 2;;
  49. --qml) QML_REL_PATHS+=("$2"); shift 2;;
  50. --copy) ARGS+=("-c \"$2\" \"$3\""); shift 3;;
  51. -f|-s) ARGS+=("$1"); shift;;
  52. -V) VERBOSE="-V"; shift;;
  53. -h) usage; exit 0;;
  54. *) echo "Error: Unsupported argument $1"; usage; exit 1;;
  55. esac
  56. done
  57. # Check required arguments
  58. for arg in INPUT_DIR PLUGIN_DIR LIB_DIR QML_DIR CORECMD_PATH; do
  59. if [[ -z ${!arg} ]]; then
  60. echo "Error: Missing required argument '$arg'"
  61. usage
  62. exit 1
  63. fi
  64. done
  65. # Get Qt plugin and QML paths
  66. PLUGIN_PATHS=()
  67. QML_PATH=""
  68. if [[ -n "$QMAKE_PATH" ]]; then
  69. QMAKE_PLUGIN_PATH=$($QMAKE_PATH -query QT_INSTALL_PLUGINS)
  70. PLUGIN_PATHS+=("$QMAKE_PLUGIN_PATH")
  71. QML_PATH=$($QMAKE_PATH -query QT_INSTALL_QML)
  72. fi
  73. # Add extra plugin searching paths
  74. PLUGIN_PATHS+=("${EXTRA_PLUGIN_PATHS[@]}")
  75. # Ensure that the QML search path is not empty
  76. # when the QML related path is specified (qmake needs to be specified)
  77. if [[ ${#QML_REL_PATHS[@]} -gt 0 && -z "$QML_PATH" ]]; then
  78. echo "Error: qmake path must be specified when QML paths are provided"
  79. usage
  80. exit 1
  81. fi
  82. # Search input directory
  83. search_input_dir() {
  84. local path="$1"
  85. for item in "$path"/*; do
  86. if [ -d "$item" ]; then
  87. # Check if the directory is mac .framework
  88. if [[ "OSTYPE" == "darwin"* ]] && [[ "$item" == *.framework ]]; then
  89. FILES="$FILES \"$item\""
  90. else
  91. search_input_dir "$item"
  92. fi
  93. elif [ -f "$item" ]; then
  94. if [[ "$OSTYPE" == "msys"* ]] || [[ "$OSTYPE" == "win32" ]] || [[ "$OSTYPE" == "cygwin"* ]]; then
  95. # On Windows, search for.exe and.dll files
  96. FILES="$FILES \"$item\""
  97. else
  98. # On Unix, traverse all files, using the file command to
  99. # check for executable binary files
  100. file_type=$(file -b "$item")
  101. if [[ ($file_type == "ELF"* || $file_type == "Mach-O"*) && -x "$item" ]]; then
  102. FILES="$FILES \"$item\""
  103. fi
  104. fi
  105. fi
  106. done
  107. }
  108. search_input_dir "$INPUT_DIR"
  109. # Find the full path to the Qt plugin
  110. for plugin_path in "${PLUGINS[@]}"; do
  111. # Check format
  112. if [[ $plugin_path == */* ]]; then
  113. IFS='/' read -r -a plugin_parts <<< "$plugin_path"
  114. # Extracts the category and name
  115. category=${plugin_parts[0]}
  116. name=${plugin_parts[1]}
  117. # Calculate destination directory
  118. dest_dir="${PLUGIN_DIR}/${category}"
  119. # Initialize an array to store found plugins
  120. found_plugins=""
  121. # Traverse the path and find the specific plug-in files
  122. for search_path in "${PLUGIN_PATHS[@]}"; do
  123. while IFS= read -r plugin; do
  124. # Get name
  125. plugin_name=$(basename "$plugin")
  126. # Check if the plugin was already found to avoid duplicates
  127. if [[ ! $found_plugins =~ $plugin_name ]]; then
  128. found_plugins+="$plugin_name "
  129. ARGS+=("-c \"$plugin\" \"$dest_dir\"")
  130. fi
  131. done < <(find "${search_path}/${category}" -name "lib${name}.*" ! -name "*debug*" -print)
  132. done
  133. if [ ${#found_plugins[@]} -eq 0 ]; then
  134. echo "Error: Plugin '${plugin_path}' not found in any search paths."
  135. exit 1
  136. fi
  137. else
  138. echo "Error: Invalid plugin format '${plugin_path}'. Expected format: <category>/<name>"
  139. exit 1
  140. fi
  141. done
  142. # Process QML item
  143. handle_qml_file() {
  144. local file="$1"
  145. local rel_path="${file#$QML_PATH/}"
  146. local target="$QML_DIR/$rel_path"
  147. local target_dir="$(dirname "$target")"
  148. # Directory: must be mac framework
  149. if [ -d "$file" ]; then
  150. ARGS+=("-c \"$file\" \"$target_dir\"")
  151. return
  152. fi
  153. # Ignore specific files
  154. if [[ "$OSTYPE" == "msys"* ]] || [[ "$OSTYPE" == "win32" ]] || [[ "$OSTYPE" == "cygwin"* ]]; then
  155. if [[ "$file" == *.pdb ]] || [[ "$file" == *d.dll ]]; then
  156. return
  157. fi
  158. else
  159. if [[ "$file" == *_debug.dylib ]] || [[ "$file" == *.so.debug ]]; then
  160. return
  161. fi
  162. fi
  163. # Determine whether it is an executable binary file and handle it accordingly
  164. if [[ "$OSTYPE" == "msys"* ]] || [[ "$OSTYPE" == "win32" ]] || [[ "$OSTYPE" == "cygwin"* ]]; then
  165. if [[ "$file" == *.dll || "$file" == *.exe ]]; then
  166. ARGS+=("-c \"$file\" \"$target_dir\"")
  167. else
  168. mkdir -p "$target_dir"
  169. cp "$file" "$target"
  170. fi
  171. else
  172. file_type=$(file -b "$file")
  173. if [[ ($file_type == "ELF"* || $file_type == "Mach-O"*) && -x "$file" ]]; then
  174. ARGS+=("-c \"$file\" \"$target_dir\"")
  175. else
  176. mkdir -p "$target_dir"
  177. cp "$file" "$target"
  178. fi
  179. fi
  180. }
  181. # Search QML directory
  182. search_qml_dir() {
  183. local path="$1"
  184. for item in "$path"/*; do
  185. if [ -d "$item" ]; then
  186. # Check if the path is mac .framework
  187. if [[ "OSTYPE" == "darwin"* ]] && [[ "$item" == *.framework ]]; then
  188. handle_qml_file "$item"
  189. else
  190. search_qml_dir "$item"
  191. fi
  192. elif [ -f "$item" ]; then
  193. handle_qml_file "$item"
  194. fi
  195. done
  196. }
  197. # Process QML directories
  198. for qml_rel_path in "${QML_REL_PATHS[@]}"; do
  199. full_path="$QML_PATH/$qml_rel_path"
  200. if [[ -d "$full_path" ]]; then
  201. # Directory
  202. search_qml_dir "$full_path"
  203. elif [[ -f "$full_path" ]]; then
  204. # File
  205. handle_qml_file "$full_path" "$QML_DIR"
  206. fi
  207. done
  208. # Build and execute the deploy command
  209. DEPLOY_CMD="$CORECMD_PATH deploy $FILES ${ARGS[@]} -o \"$LIB_DIR\" $VERBOSE"
  210. if [[ "$VERBOSE" == "-V" ]]; then
  211. echo "Executing: $DEPLOY_CMD"
  212. fi
  213. eval $DEPLOY_CMD
  214. # Check the deployment result
  215. if [ $? -ne 0 ]; then
  216. exit 1
  217. fi