diff --git a/.gitignore b/.gitignore index 5776b83..d03b45f 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,5 @@ build Makefile *.patch .idea +dist +extra/windows/*.ico diff --git a/CMakeLists.txt b/CMakeLists.txt index b3f5b13..66a3bea 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.21) -project(SagoImageBrowser LANGUAGES CXX) +project(SagoImageBrowser VERSION 0.1.0 LANGUAGES CXX) set(CMAKE_CXX_STANDARD 17) set(CMAKE_AUTOMOC ON) @@ -50,6 +50,18 @@ qt_add_executable(SagoImageBrowser src/thumbnaildelegate.cpp src/thumbnaildelegate.h) +if(WIN32) + enable_language(RC) + # windres resolves relative paths in .rc files against its own CWD, not + # the .rc file's location, so the icon path must be baked in as absolute. + set(SAGO_ICON_PATH "${CMAKE_CURRENT_SOURCE_DIR}/extra/windows/sago_image_browser.ico") + configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/extra/windows/sagoimagebrowser.rc.in + ${CMAKE_CURRENT_BINARY_DIR}/sagoimagebrowser.rc + @ONLY) + target_sources(SagoImageBrowser PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/sagoimagebrowser.rc) +endif() + set_source_files_properties(extra/icons/sago_image_browser.svg PROPERTIES QT_RESOURCE_ALIAS sago_image_browser.svg) qt_add_resources(SagoImageBrowser "icons" PREFIX "/icons" FILES extra/icons/sago_image_browser.svg) diff --git a/README.md b/README.md index 96e4578..59ea89d 100644 --- a/README.md +++ b/README.md @@ -75,6 +75,28 @@ A small test for the EXIF reader is built alongside the application: ./build/test_exifreader ``` +## Windows MSI build + +A 32-bit Windows build (statically linked, no external DLLs required) is cross-compiled via +[MXE](https://mxe.cc/) in Docker, and packaged as an MSI installer with `wixl` (from +[msitools](https://wiki.gnome.org/Projects/msitools)): + +```bash +docker build -f extra/docker/Dockerfile.WindowsMxe --target export -o dist/ . +``` + +This produces `dist/SagoImageBrowser.exe` and `dist/SagoImageBrowser.msi`. If your Docker +installation doesn't support `--output`/`-o` (requires BuildKit), build the `export` stage as a +tagged image instead and copy the files out manually: + +```bash +docker build -f extra/docker/Dockerfile.WindowsMxe --target export -t sago_image_browser_export . +id=$(docker create sago_image_browser_export) +docker cp "$id":/SagoImageBrowser.exe dist/ +docker cp "$id":/SagoImageBrowser.msi dist/ +docker rm "$id" +``` + ## Project Structure ``` diff --git a/extra/docker/Dockerfile.WindowsMxe b/extra/docker/Dockerfile.WindowsMxe index ba862e3..48887d0 100644 --- a/extra/docker/Dockerfile.WindowsMxe +++ b/extra/docker/Dockerfile.WindowsMxe @@ -1,9 +1,46 @@ -FROM sago007/mxe_qt6 +# syntax=docker/dockerfile:1 +FROM sago007/mxe_qt6 AS builder + +# wixl -> MSI builder (packaged separately from msitools on Ubuntu/Debian), +# librsvg2-bin -> rsvg-convert (SVG->PNG), icoutils -> icotool (assemble +# multi-res .ico from PNGs) +RUN apt-get update && apt-get install --no-install-recommends -y \ + wixl \ + librsvg2-bin \ + icoutils \ + && rm -rf /var/lib/apt/lists/* RUN mkdir -p /staging/sago_image_browser COPY . /staging/sago_image_browser +# Generate a multi-resolution Windows .ico from the SVG source icon. +RUN mkdir -p /staging/sago_image_browser/extra/windows /tmp/icon-build && \ + cd /tmp/icon-build && \ + rsvg-convert -w 16 -h 16 /staging/sago_image_browser/extra/icons/sago_image_browser.svg -o icon-16.png && \ + rsvg-convert -w 32 -h 32 /staging/sago_image_browser/extra/icons/sago_image_browser.svg -o icon-32.png && \ + rsvg-convert -w 48 -h 48 /staging/sago_image_browser/extra/icons/sago_image_browser.svg -o icon-48.png && \ + rsvg-convert -w 256 -h 256 /staging/sago_image_browser/extra/icons/sago_image_browser.svg -o icon-256.png && \ + icotool -c -o /staging/sago_image_browser/extra/windows/sago_image_browser.ico \ + icon-16.png icon-32.png icon-48.png icon-256.png + RUN cd /staging/sago_image_browser && rm -rf build && mkdir build && cd build && \ i686-w64-mingw32.static-cmake .. && \ -make -j$(nproc) \ No newline at end of file +make -j$(nproc) + +# Stage the payload wixl needs (it resolves relative Source/SourceFile paths +# against its own CWD), then compile the MSI. Version is read out of +# CMakeLists.txt so it stays the single source of truth. +RUN mkdir -p /out && \ + cp /staging/sago_image_browser/build/SagoImageBrowser.exe /out/ && \ + cp /staging/sago_image_browser/extra/windows/sago_image_browser.ico /out/ && \ + cp /staging/sago_image_browser/extra/windows/sagoimagebrowser.wxs /out/SagoImageBrowser.wxs && \ + cd /out && \ + VERSION=$(grep -oP 'VERSION \K[0-9]+\.[0-9]+\.[0-9]+' /staging/sago_image_browser/CMakeLists.txt) && \ + echo "Building MSI for version: $VERSION" && \ + wixl -v -D Version="$VERSION" -o SagoImageBrowser.msi SagoImageBrowser.wxs + +# Minimal export-only stage: `docker build --target export -o dist/ .` +# copies just these two files to the host, nothing else. +#FROM scratch AS export +#COPY --from=builder /out/SagoImageBrowser.exe /out/SagoImageBrowser.msi / diff --git a/extra/windows/sagoimagebrowser.rc.in b/extra/windows/sagoimagebrowser.rc.in new file mode 100644 index 0000000..39389b7 --- /dev/null +++ b/extra/windows/sagoimagebrowser.rc.in @@ -0,0 +1 @@ +IDI_ICON1 ICON "@SAGO_ICON_PATH@" diff --git a/extra/windows/sagoimagebrowser.wxs b/extra/windows/sagoimagebrowser.wxs new file mode 100644 index 0000000..15f320e --- /dev/null +++ b/extra/windows/sagoimagebrowser.wxs @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +