Replace utils_make_human_readable_str() with g_format_size()
[geany-mirror.git] / scripts / ci_mingw64_geany.sh
blobcb33757cc1f4524baac88aaca5f605a1ffe05d3a
1 #!/bin/bash
3 # Copyright 2022 The Geany contributors
4 # License: GPLv2
6 # Helper script to build Geany for Windows in a Docker container.
7 # The following steps are performed:
8 # - clone Geany repository if necessary (i.e. if it is not bind-mounted into the container)
9 # - cross-compile Geany for Windows 64bit and GTK3
10 # - sign all binaries and installer (if /certificates exist and contains cert.pem and key.pem)
11 # - download Geany-Themes for bundling
12 # - create GTK3 bundle with all dependencies (including grep and sort)
13 # - create the NSIS installer in ${OUTPUT_DIRECTORY}
14 # - test the created NSIS installer and compiled Geany
15 # - test uninstaller and check there is nothing left after uninstalling
17 # This script has to be executed within the Docker container.
18 # The Docker container should have a bind-mount for ${OUTPUT_DIRECTORY}
19 # where the resulting installer binary is stored.
21 # To test the installer and Geany binary "wine" is used.
22 # Please note that we need to use wine32 and wine64 as the
23 # created installer and uninstaller binaries are 32bit whereas the created
24 # Geany binary is 64bit.
27 GEANY_VERSION= # will be set below from configure.ac
28 GEANY_GIT_REVISION= # will be set below from configure.ac
29 OUTPUT_DIRECTORY="/output"
30 GEANY_GIT_REPOSITORY="https://github.com/geany/geany.git"
31 GEANY_THEMES_REPOSITORY="https://github.com/geany/geany-themes.git"
33 # rather static values, unlikely to be changed
34 GTK_BUNDLE_DIR="/build/gtk-bundle"
35 GEANY_SOURCE_DIR="/geany-source"
36 GEANY_BUILD_DIR="/build/geany-build"
37 GEANY_RELEASE_DIR="/build/geany-release"
38 GEANY_INSTALLER_FILENAME= # will be set below
39 GEANY_INSTALLATION_DIR_WIN="C:\\geany_install"
40 GEANY_INSTALLATION_DIR=$(winepath --unix ${GEANY_INSTALLATION_DIR_WIN})
41 GEANY_THEMES_DIR="/build/geany-themes"
42 GEANY_RELEASE_BINARY_PATTERNS=(
43 "${GEANY_RELEASE_DIR}/bin/geany.exe"
44 "${GEANY_RELEASE_DIR}/bin/*.dll"
45 "${GEANY_RELEASE_DIR}/lib/geany/*.dll"
48 # CI CFLAGS
49 CFLAGS="\
50 -Wall \
51 -Wextra \
52 -O2 \
53 -Wunused \
54 -Wno-unused-parameter \
55 -Wunreachable-code \
56 -Wformat=2 \
57 -Wundef \
58 -Wpointer-arith \
59 -Wwrite-strings \
60 -Waggregate-return \
61 -Wmissing-prototypes \
62 -Wmissing-declarations \
63 -Wmissing-noreturn \
64 -Wmissing-format-attribute \
65 -Wredundant-decls \
66 -Wnested-externs \
67 -Wno-deprecated-declarations"
69 # cross-compilation environment
70 ARCH="x86_64"
71 MINGW_ARCH="mingw64"
72 HOST="x86_64-w64-mingw32"
73 export LDFLAGS="-static-libgcc ${LDFLAGS}"
74 export PKG_CONFIG_SYSROOT_DIR="/windows"
75 export PKG_CONFIG_PATH="/windows/${MINGW_ARCH}/lib/pkgconfig/"
76 export NOCONFIGURE=1
77 export JOBS=${JOBS:-1}
78 export lt_cv_deplibs_check_method='pass_all'
80 # stop on errors
81 set -e
84 log() {
85 echo "=========== $(date '+%Y-%m-%d %H:%M:%S %Z') $* ==========="
89 git_clone_geany_if_necessary() {
90 if [ -d ${GEANY_SOURCE_DIR} ]; then
91 log "Copying Geany source"
92 cp --archive ${GEANY_SOURCE_DIR}/ ${GEANY_BUILD_DIR}/
93 chown --recursive $(id -u):$(id -g) ${GEANY_BUILD_DIR}/
94 else
95 log "Cloning Geany repository from ${GEANY_GIT_REPOSITORY}"
96 git clone --depth 1 ${GEANY_GIT_REPOSITORY} ${GEANY_BUILD_DIR}
101 parse_geany_version() {
102 GEANY_VERSION=$(sed -n -E -e 's/^AC_INIT.\[Geany\], \[(.+)\],/\1/p' ${GEANY_BUILD_DIR}/configure.ac)
103 GEANY_GIT_REVISION=$(cd ${GEANY_BUILD_DIR} && git rev-parse --short --revs-only HEAD 2>/dev/null || true)
104 TIMESTAMP=$(date +%Y%m%d%H%M%S)
105 # add pull request number if this is a CI and a PR build
106 if [ "${GITHUB_PULL_REQUEST}" ]; then
107 GEANY_VERSION="${GEANY_VERSION}_ci_${TIMESTAMP}_${GEANY_GIT_REVISION}_pr${GITHUB_PULL_REQUEST}"
108 elif [ "${CI}" -a "${GEANY_GIT_REVISION}" ]; then
109 GEANY_VERSION="${GEANY_VERSION}_ci_${TIMESTAMP}_${GEANY_GIT_REVISION}"
110 elif [ "${GEANY_GIT_REVISION}" ]; then
111 GEANY_VERSION="${GEANY_VERSION}_git_${TIMESTAMP}_${GEANY_GIT_REVISION}"
113 GEANY_INSTALLER_FILENAME="geany-${GEANY_VERSION}_setup.exe"
117 log_environment() {
118 log "Using environment"
119 CONFIGURE_OPTIONS="--disable-silent-rules --host=${HOST} --prefix=${GEANY_RELEASE_DIR} --with-libiconv-prefix=/windows/mingw64"
120 echo "Geany version : ${GEANY_VERSION}"
121 echo "Geany GIT revision : ${GEANY_GIT_REVISION}"
122 echo "PATH : ${PATH}"
123 echo "HOST : ${HOST}"
124 echo "GCC : $(${HOST}-gcc -dumpfullversion) ($(${HOST}-gcc -dumpversion))"
125 echo "G++ : $(${HOST}-g++ -dumpfullversion) ($(${HOST}-g++ -dumpversion))"
126 echo "Libstdc++ : $(dpkg-query --showformat='${Version}' --show libstdc++6:i386)"
127 echo "GLib : $(pkg-config --modversion glib-2.0)"
128 echo "GTK : $(pkg-config --modversion gtk+-3.0)"
129 echo "CFLAGS : ${CFLAGS}"
130 echo "Configure : ${CONFIGURE_OPTIONS}"
134 patch_version_information() {
135 log "Patching version information"
137 if [ -z "${GEANY_GIT_REVISION}" ] && [ -z "${CI}" ]; then
138 return
141 # parse version string and decrement the patch and/or minor levels to keep nightly build
142 # versions below the next release version
143 regex='^([0-9]*)[.]([0-9]*)([.]([0-9]*))?'
144 if [[ ${GEANY_VERSION} =~ $regex ]]; then
145 MAJOR="${BASH_REMATCH[1]}"
146 MINOR="${BASH_REMATCH[2]}"
147 PATCH="${BASH_REMATCH[4]}"
148 if [ -z "${PATCH}" ] || [ "${PATCH}" = "0" ]; then
149 if [ "${MINOR}" = "0" ]; then
150 MAJOR="$((MAJOR-1))"
151 MINOR="99"
152 else
153 MINOR="$((MINOR-1))"
155 PATCH="99"
156 else
157 PATCH="$((PATCH-1))"
159 else
160 echo "Could not extract or parse version tag" >&2
161 exit 1
163 # replace version information in configure.ac and for Windows binaries
164 sed -i -E "s/^AC_INIT.\[Geany\], \[(.+)\],/AC_INIT(\[Geany\], \[${GEANY_VERSION}\],/" ${GEANY_BUILD_DIR}/configure.ac
165 sed -i -E "s/^#define VER_FILEVERSION_STR[[:space:]]+\".*\"+/#define VER_FILEVERSION_STR \"${GEANY_VERSION}\"/" ${GEANY_BUILD_DIR}/geany_private.rc
166 sed -i -E "s/^#define VER_FILEVERSION[[:space:]]+[0-9,]+/#define VER_FILEVERSION ${MAJOR},${MINOR},${PATCH},90/" ${GEANY_BUILD_DIR}/geany_private.rc
167 sed -i -E "s/^[[:space:]]+version=\"[0-9.]+\"/version=\"${MAJOR}.${MINOR}.${PATCH}.90\"/" ${GEANY_BUILD_DIR}/geany.exe.manifest
168 sed -i -E "s/^!define PRODUCT_VERSION \"@VERSION@\"/!define PRODUCT_VERSION \"${GEANY_VERSION}\"/" ${GEANY_BUILD_DIR}/geany.nsi.in
169 sed -i -E "s/^!define PRODUCT_VERSION_ID \"@VERSION@.0.0\"/!define PRODUCT_VERSION_ID \"${MAJOR}.${MINOR}.${PATCH}.90\"/" ${GEANY_BUILD_DIR}/geany.nsi.in
173 build_geany() {
174 cd ${GEANY_BUILD_DIR}
175 log "Running autogen.sh"
176 ./autogen.sh
177 log "Running configure"
178 ./configure ${CONFIGURE_OPTIONS}
179 log "Running make"
180 make -j ${JOBS}
181 log "Running install-strip"
182 make install-strip
186 sign_file() {
187 echo "Sign file $1"
188 if [ -f /certificates/cert.pem ] && [ -f /certificates/key.pem ]; then
189 osslsigncode sign \
190 -certs /certificates/cert.pem \
191 -key /certificates/key.pem \
192 -n "Geany Binary" \
193 -i "https://www.geany.org/" \
194 -ts http://zeitstempel.dfn.de/ \
195 -h sha512 \
196 -in ${1} \
197 -out ${1}-signed
198 mv ${1}-signed ${1}
199 else
200 echo "Skip signing due to missing certificate"
205 sign_geany_binaries() {
206 log "Signing Geany binary files"
207 for binary_file_pattern in ${GEANY_RELEASE_BINARY_PATTERNS[@]}; do
208 for binary_file in $(ls ${binary_file_pattern}); do
209 sign_file ${binary_file}
210 done
211 done
215 create_gtk_bundle() {
216 log "Creating GTK bundle"
217 mkdir ${GTK_BUNDLE_DIR}
218 cd ${GTK_BUNDLE_DIR}
219 bash ${GEANY_BUILD_DIR}/scripts/gtk-bundle-from-msys2.sh -x -3
221 # We use the "posix" variant of the mingw64 cross compiler which has support for
222 # C++ features like "std:future". For this to work, we need to use the corresponding
223 # C++ runtime library and copy (and strip) it to the resulting bundle.
224 gcc_version="$(${HOST}-gcc -dumpversion)/libstdc++-6.dll"
225 cp "/usr/lib/gcc/${HOST}/${gcc_version}" "${GTK_BUNDLE_DIR}/bin"
226 ${HOST}-strip "${GTK_BUNDLE_DIR}/bin/libstdc++-6.dll"
230 fetch_geany_themes() {
231 log "Cloning Geany-Themes repository from ${GEANY_THEMES_REPOSITORY}"
232 git clone --depth 1 ${GEANY_THEMES_REPOSITORY} ${GEANY_THEMES_DIR}
236 create_installer() {
237 log "Creating NSIS installer"
238 makensis \
239 -V3 \
240 -WX \
241 -DGEANY_INSTALLER_NAME="${GEANY_INSTALLER_FILENAME}" \
242 -DGEANY_RELEASE_DIR=${GEANY_RELEASE_DIR} \
243 -DGEANY_THEMES_DIR=${GEANY_THEMES_DIR} \
244 -DGTK_BUNDLE_DIR=${GTK_BUNDLE_DIR} \
245 ${GEANY_BUILD_DIR}/geany.nsi
249 sign_installer() {
250 log "Signing NSIS installer"
251 sign_file ${GEANY_BUILD_DIR}/${GEANY_INSTALLER_FILENAME}
255 test_installer() {
256 log "Test NSIS installer"
257 exiftool -FileName -FileType -FileVersion -FileVersionNumber ${GEANY_BUILD_DIR}/${GEANY_INSTALLER_FILENAME}
258 # install Geany: perform a silent install and check for installed files
259 mingw-w64-i686-wine ${GEANY_BUILD_DIR}/${GEANY_INSTALLER_FILENAME} /S /D=${GEANY_INSTALLATION_DIR_WIN}
260 # check if we have something installed
261 test -f ${GEANY_INSTALLATION_DIR}/uninst.exe || exit 1
262 test -f ${GEANY_INSTALLATION_DIR}/bin/geany.exe || exit 1
263 test -f ${GEANY_INSTALLATION_DIR}/lib/geany/export.dll || exit 1
264 test ! -f ${GEANY_INSTALLATION_DIR}/lib/geany/demoplugin.dll || exit 1
268 log_geany_version() {
269 log "Log installed Geany version"
270 mingw-w64-x86_64-wine ${GEANY_INSTALLATION_DIR}/bin/geany.exe --version 2>/dev/null
271 exiftool -FileName -FileType -FileVersion -FileVersionNumber ${GEANY_INSTALLATION_DIR}/bin/geany.exe
275 test_uninstaller() {
276 log "Test NSIS uninstaller"
277 # uninstall Geany and test if everything is clean
278 mingw-w64-i686-wine ${GEANY_INSTALLATION_DIR}/uninst.exe /S
279 sleep 10 # it seems the uninstaller returns earlier than the files are actually removed, so wait a moment
280 test ! -e ${GEANY_INSTALLATION_DIR}
284 copy_installer_and_bundle() {
285 log "Copying NSIS installer and GTK bundle"
286 cp ${GEANY_BUILD_DIR}/${GEANY_INSTALLER_FILENAME} ${OUTPUT_DIRECTORY}
287 cd ${GTK_BUNDLE_DIR}
288 zip --quiet --recurse-paths ${OUTPUT_DIRECTORY}/gtk_bundle_$(date '+%Y%m%dT%H%M%S').zip *
292 main() {
293 git_clone_geany_if_necessary
295 parse_geany_version
296 log_environment
297 patch_version_information
298 build_geany
299 sign_geany_binaries
301 create_gtk_bundle
302 fetch_geany_themes
303 create_installer
304 sign_installer
306 test_installer
307 log_geany_version
308 test_uninstaller
310 copy_installer_and_bundle
312 log "Done."
316 main