#!/bin/bash
# MIT License
# Copyright (c) 2023 SineStriker
# Description: This script calls `qmcorecmd` to deploy dependencies on Mac/Linux.
# Show usage
usage() {
echo "Usage: $(basename $0) -i
-m "
echo " --plugindir --libdir --qmldir "
echo " [--qmake ] [--extra ]..."
echo " [--qml ]... [--plugin ]... [--copy ]..."
echo " [-f] [-s] [-V] [-h]"
echo " -i Directory containing binaries and libraries"
echo " -m Path to corecmd"
echo " --plugindir Output directory for plugins"
echo " --libdir Output directory for libraries"
echo " --qmldir Output directory for QML files"
echo " --qmake Path to qmake (optional)"
echo " --extra Extra plugin searching path (repeatable)"
echo " --qml Relative path to QML directory (repeatable)"
echo " --plugin Specify a Qt plugin to deploy (repeatable)"
echo " --copy Specify additional binary file to copy and its destination directory (repeatable)"
echo " -@ Add library searching paths from a list file"
echo " -L Add a library searching path"
echo " -f Force overwrite existing files"
echo " -s Ignore C/C++ runtime and system libraries"
echo " -V Show verbose output"
echo " -h Show this help message"
}
# Initialize arguments
EXTRA_PLUGIN_PATHS=()
QML_REL_PATHS=()
ARGS=()
VERBOSE=""
PLUGINS=()
FILES=""
# Parse command line
while (( "$#" )); do
case "$1" in
-i) INPUT_DIR="$2"; shift 2;;
-m) CORECMD_PATH="$2"; shift 2;;
-@) ARGS+=("-@ \"$2\""); shift 2;;
-L) ARGS+=("-L \"$2\""); shift 2;;
--plugindir) PLUGIN_DIR="$2"; shift 2;;
--libdir) LIB_DIR="$2"; shift 2;;
--qmldir) QML_DIR="$2"; shift 2;;
--qmake) QMAKE_PATH="$2"; shift 2;;
--extra) EXTRA_PLUGIN_PATHS+=("$2"); shift 2;;
--plugin) PLUGINS+=("$2"); shift 2;;
--qml) QML_REL_PATHS+=("$2"); shift 2;;
--copy) ARGS+=("-c \"$2\" \"$3\""); shift 3;;
-f|-s) ARGS+=("$1"); shift;;
-V) VERBOSE="-V"; shift;;
-h) usage; exit 0;;
*) echo "Error: Unsupported argument $1"; usage; exit 1;;
esac
done
# Check required arguments
for arg in INPUT_DIR PLUGIN_DIR LIB_DIR QML_DIR CORECMD_PATH; do
if [[ -z ${!arg} ]]; then
echo "Error: Missing required argument '$arg'"
usage
exit 1
fi
done
# Get Qt plugin and QML paths
PLUGIN_PATHS=()
QML_PATH=""
if [[ -n "$QMAKE_PATH" ]]; then
QMAKE_PLUGIN_PATH=$($QMAKE_PATH -query QT_INSTALL_PLUGINS)
PLUGIN_PATHS+=("$QMAKE_PLUGIN_PATH")
QML_PATH=$($QMAKE_PATH -query QT_INSTALL_QML)
fi
# Add extra plugin searching paths
PLUGIN_PATHS+=("${EXTRA_PLUGIN_PATHS[@]}")
# Ensure that the QML search path is not empty
# when the QML related path is specified (qmake needs to be specified)
if [[ ${#QML_REL_PATHS[@]} -gt 0 && -z "$QML_PATH" ]]; then
echo "Error: qmake path must be specified when QML paths are provided"
usage
exit 1
fi
# Search input directory
search_input_dir() {
local path="$1"
for item in "$path"/*; do
if [ -d "$item" ]; then
# Check if the directory is mac .framework
if [[ "OSTYPE" == "darwin"* ]] && [[ "$item" == *.framework ]]; then
FILES="$FILES \"$item\""
else
search_input_dir "$item"
fi
elif [ -f "$item" ]; then
if [[ "$OSTYPE" == "msys"* ]] || [[ "$OSTYPE" == "win32" ]] || [[ "$OSTYPE" == "cygwin"* ]]; then
# On Windows, search for.exe and.dll files
FILES="$FILES \"$item\""
else
# On Unix, traverse all files, using the file command to
# check for executable binary files
file_type=$(file -b "$item")
if [[ ($file_type == "ELF"* || $file_type == "Mach-O"*) && -x "$item" ]]; then
FILES="$FILES \"$item\""
fi
fi
fi
done
}
search_input_dir "$INPUT_DIR"
# Find the full path to the Qt plugin
for plugin_path in "${PLUGINS[@]}"; do
# Check format
if [[ $plugin_path == */* ]]; then
IFS='/' read -r -a plugin_parts <<< "$plugin_path"
# Extracts the category and name
category=${plugin_parts[0]}
name=${plugin_parts[1]}
# Calculate destination directory
dest_dir="${PLUGIN_DIR}/${category}"
# Initialize an array to store found plugins
found_plugins=""
# Traverse the path and find the specific plug-in files
for search_path in "${PLUGIN_PATHS[@]}"; do
while IFS= read -r plugin; do
# Get name
plugin_name=$(basename "$plugin")
# Check if the plugin was already found to avoid duplicates
if [[ ! $found_plugins =~ $plugin_name ]]; then
found_plugins+="$plugin_name "
ARGS+=("-c \"$plugin\" \"$dest_dir\"")
fi
done < <(find "${search_path}/${category}" -name "lib${name}.*" ! -name "*debug*" -print)
done
if [ ${#found_plugins[@]} -eq 0 ]; then
echo "Error: Plugin '${plugin_path}' not found in any search paths."
exit 1
fi
else
echo "Error: Invalid plugin format '${plugin_path}'. Expected format: /"
exit 1
fi
done
# Process QML item
handle_qml_file() {
local file="$1"
local rel_path="${file#$QML_PATH/}"
local target="$QML_DIR/$rel_path"
local target_dir="$(dirname "$target")"
# Directory: must be mac framework
if [ -d "$file" ]; then
ARGS+=("-c \"$file\" \"$target_dir\"")
return
fi
# Ignore specific files
if [[ "$OSTYPE" == "msys"* ]] || [[ "$OSTYPE" == "win32" ]] || [[ "$OSTYPE" == "cygwin"* ]]; then
if [[ "$file" == *.pdb ]] || [[ "$file" == *d.dll ]]; then
return
fi
else
if [[ "$file" == *_debug.dylib ]] || [[ "$file" == *.so.debug ]]; then
return
fi
fi
# Determine whether it is an executable binary file and handle it accordingly
if [[ "$OSTYPE" == "msys"* ]] || [[ "$OSTYPE" == "win32" ]] || [[ "$OSTYPE" == "cygwin"* ]]; then
if [[ "$file" == *.dll || "$file" == *.exe ]]; then
ARGS+=("-c \"$file\" \"$target_dir\"")
else
mkdir -p "$target_dir"
cp "$file" "$target"
fi
else
file_type=$(file -b "$file")
if [[ ($file_type == "ELF"* || $file_type == "Mach-O"*) && -x "$file" ]]; then
ARGS+=("-c \"$file\" \"$target_dir\"")
else
mkdir -p "$target_dir"
cp "$file" "$target"
fi
fi
}
# Search QML directory
search_qml_dir() {
local path="$1"
for item in "$path"/*; do
if [ -d "$item" ]; then
# Check if the path is mac .framework
if [[ "OSTYPE" == "darwin"* ]] && [[ "$item" == *.framework ]]; then
handle_qml_file "$item"
else
search_qml_dir "$item"
fi
elif [ -f "$item" ]; then
handle_qml_file "$item"
fi
done
}
# Process QML directories
for qml_rel_path in "${QML_REL_PATHS[@]}"; do
full_path="$QML_PATH/$qml_rel_path"
if [[ -d "$full_path" ]]; then
# Directory
search_qml_dir "$full_path"
elif [[ -f "$full_path" ]]; then
# File
handle_qml_file "$full_path" "$QML_DIR"
fi
done
# Build and execute the deploy command
DEPLOY_CMD="$CORECMD_PATH deploy $FILES ${ARGS[@]} -o \"$LIB_DIR\" $VERBOSE"
if [[ "$VERBOSE" == "-V" ]]; then
echo "Executing: $DEPLOY_CMD"
fi
eval $DEPLOY_CMD
# Check the deployment result
if [ $? -ne 0 ]; then
exit 1
fi