feat: add Windows cross-compilation build script
scripts/build-windows.sh configures and builds with the MinGW-w64 toolchain, collects runtime DLLs (OpenCV, LibRaw, Qt6, MinGW runtime) into dist-windows/, strips release binaries, and packages a ZIP archive. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
156
scripts/build-windows.sh
Executable file
156
scripts/build-windows.sh
Executable file
@@ -0,0 +1,156 @@
|
||||
#!/usr/bin/env bash
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
# build-windows.sh
|
||||
#
|
||||
# Cross-compiles photo-converter for Windows (x86_64) using MinGW-w64.
|
||||
# Produces a self-contained directory with photo-converter.exe and all
|
||||
# required DLLs ready for distribution.
|
||||
#
|
||||
# Prerequisites (Ubuntu/Debian):
|
||||
# sudo apt install mingw-w64 cmake ninja-build
|
||||
# # Install MinGW-w64 cross builds of OpenCV, LibRaw, Qt6:
|
||||
# # Option A – compile from source with the MinGW toolchain.
|
||||
# # Option B – use an MXE (M cross environment) prefix.
|
||||
# # https://mxe.cc/
|
||||
# # Option C – use pre-built MinGW packages from a provider such as
|
||||
# # https://github.com/brechtsanders/winlibs_mingw
|
||||
#
|
||||
# Usage:
|
||||
# bash scripts/build-windows.sh [BUILD_TYPE] [DEPS_PREFIX]
|
||||
#
|
||||
# BUILD_TYPE Release (default) | Debug | RelWithDebInfo
|
||||
# DEPS_PREFIX Path to cross-compiled dependencies
|
||||
# (default: /usr/x86_64-w64-mingw32)
|
||||
#
|
||||
# Example with a custom MXE prefix:
|
||||
# bash scripts/build-windows.sh Release /opt/mxe/usr/x86_64-w64-mingw32.static
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# ── Configuration ─────────────────────────────────────────────────────────────
|
||||
BUILD_TYPE="${1:-Release}"
|
||||
DEPS_PREFIX="${2:-/usr/x86_64-w64-mingw32}"
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
||||
BUILD_DIR="${PROJECT_ROOT}/build-windows"
|
||||
DIST_DIR="${PROJECT_ROOT}/dist-windows"
|
||||
|
||||
TOOLCHAIN="${PROJECT_ROOT}/cmake/toolchain-mingw64.cmake"
|
||||
|
||||
echo "========================================================"
|
||||
echo " photo-converter Windows Cross-Compilation"
|
||||
echo "========================================================"
|
||||
echo " Project root : ${PROJECT_ROOT}"
|
||||
echo " Build dir : ${BUILD_DIR}"
|
||||
echo " Build type : ${BUILD_TYPE}"
|
||||
echo " Deps prefix : ${DEPS_PREFIX}"
|
||||
echo "========================================================"
|
||||
|
||||
# ── Verify prerequisites ──────────────────────────────────────────────────────
|
||||
for tool in x86_64-w64-mingw32-g++ cmake ninja; do
|
||||
if ! command -v "${tool}" &>/dev/null; then
|
||||
echo "ERROR: '${tool}' not found in PATH." >&2
|
||||
echo "Install with: sudo apt install mingw-w64 cmake ninja-build" >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
# ── CMake configure ──────────────────────────────────────────────────────────
|
||||
cmake \
|
||||
-B "${BUILD_DIR}" \
|
||||
-G Ninja \
|
||||
-DCMAKE_TOOLCHAIN_FILE="${TOOLCHAIN}" \
|
||||
-DCMAKE_BUILD_TYPE="${BUILD_TYPE}" \
|
||||
-DCMAKE_INSTALL_PREFIX="${DIST_DIR}" \
|
||||
-DCMAKE_PREFIX_PATH="${DEPS_PREFIX}" \
|
||||
-DBUILD_TESTS=OFF \
|
||||
-DBUILD_GUI=ON \
|
||||
"${PROJECT_ROOT}"
|
||||
|
||||
# ── Build ─────────────────────────────────────────────────────────────────────
|
||||
cmake --build "${BUILD_DIR}" -- -j"$(nproc)"
|
||||
|
||||
# ── Install to dist dir ───────────────────────────────────────────────────────
|
||||
cmake --install "${BUILD_DIR}"
|
||||
|
||||
# ── Collect runtime DLLs ─────────────────────────────────────────────────────
|
||||
# MinGW runtime and dependency DLLs must ship alongside the .exe.
|
||||
BIN_DIR="${DIST_DIR}/bin"
|
||||
mkdir -p "${BIN_DIR}"
|
||||
|
||||
echo ""
|
||||
echo "Collecting runtime DLLs..."
|
||||
|
||||
# Helper: copy a DLL if it exists in the sysroot.
|
||||
copy_dll() {
|
||||
local dll_name="$1"
|
||||
local search_paths=(
|
||||
"${DEPS_PREFIX}/bin"
|
||||
"${DEPS_PREFIX}/lib"
|
||||
"/usr/lib/gcc/x86_64-w64-mingw32"
|
||||
"/usr/x86_64-w64-mingw32/lib"
|
||||
)
|
||||
for dir in "${search_paths[@]}"; do
|
||||
if [[ -f "${dir}/${dll_name}" ]]; then
|
||||
cp -v "${dir}/${dll_name}" "${BIN_DIR}/"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
echo " WARNING: ${dll_name} not found (may be statically linked)" >&2
|
||||
return 0
|
||||
}
|
||||
|
||||
# MinGW runtime DLLs (may be statically linked via -static-libgcc/-static-libstdc++)
|
||||
copy_dll "libgcc_s_seh-1.dll" || true
|
||||
copy_dll "libstdc++-6.dll" || true
|
||||
copy_dll "libwinpthread-1.dll" || true
|
||||
|
||||
# OpenCV DLLs (names include version number – use glob)
|
||||
for dll in "${DEPS_PREFIX}/bin"/libopencv_*.dll; do
|
||||
[[ -f "${dll}" ]] && cp -v "${dll}" "${BIN_DIR}/"
|
||||
done
|
||||
|
||||
# LibRaw
|
||||
copy_dll "libraw.dll" || true
|
||||
copy_dll "libraw-23.dll" || true
|
||||
|
||||
# Qt6 DLLs
|
||||
for qt_dll in Qt6Core Qt6Gui Qt6Widgets; do
|
||||
copy_dll "${qt_dll}.dll" || true
|
||||
done
|
||||
|
||||
# Qt platform plugin
|
||||
QT_PLATFORMS_SRC="${DEPS_PREFIX}/share/qt6/plugins/platforms"
|
||||
if [[ -d "${QT_PLATFORMS_SRC}" ]]; then
|
||||
mkdir -p "${BIN_DIR}/platforms"
|
||||
cp -v "${QT_PLATFORMS_SRC}/qwindows.dll" "${BIN_DIR}/platforms/" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# ── Strip release binaries ────────────────────────────────────────────────────
|
||||
if [[ "${BUILD_TYPE}" == "Release" ]]; then
|
||||
echo ""
|
||||
echo "Stripping debug symbols from release binaries..."
|
||||
x86_64-w64-mingw32-strip --strip-all "${BIN_DIR}/photo-converter.exe" 2>/dev/null || true
|
||||
find "${BIN_DIR}" -name "*.dll" -exec x86_64-w64-mingw32-strip --strip-unneeded {} \; 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# ── Copy example config ───────────────────────────────────────────────────────
|
||||
cp -v "${PROJECT_ROOT}/config.ini" "${DIST_DIR}/config.ini.example"
|
||||
|
||||
# ── Create ZIP archive ────────────────────────────────────────────────────────
|
||||
ARCHIVE="${PROJECT_ROOT}/photo-converter-windows-x64-${BUILD_TYPE}.zip"
|
||||
if command -v zip &>/dev/null; then
|
||||
(cd "${PROJECT_ROOT}" && zip -r "${ARCHIVE}" "dist-windows/")
|
||||
echo ""
|
||||
echo "Archive: ${ARCHIVE}"
|
||||
else
|
||||
echo "(zip not available; skipping archive creation)"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "========================================================"
|
||||
echo " Build complete!"
|
||||
echo " Output: ${DIST_DIR}"
|
||||
echo " Run: wine ${BIN_DIR}/photo-converter.exe --help"
|
||||
echo "========================================================"
|
||||
Reference in New Issue
Block a user