sdgui: cross-compile for Windows

No one bothered to ask whether it /should/ be done.

The hamburger needs to be replaced with a file open dialog there.
This commit is contained in:
Přemysl Eric Janouch 2021-10-22 01:59:09 +02:00
parent c7b9d65797
commit 89580f2113
Signed by: p
GPG Key ID: A0420B94F92B9493
7 changed files with 203 additions and 30 deletions

View File

@ -11,6 +11,25 @@ endif ()
# For custom modules
set (CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
# Cross-compilation for Windows, as a proof-of-concept pulled in from logdiag
if (WIN32)
if (NOT CMAKE_CROSSCOMPILING)
message (FATAL_ERROR "Win32 must be cross-compiled to build sensibly")
endif ()
set (WIN32_DEPENDS_PATH ${PROJECT_SOURCE_DIR}/win32-depends)
list (APPEND CMAKE_PREFIX_PATH ${WIN32_DEPENDS_PATH})
list (APPEND CMAKE_INCLUDE_PATH ${WIN32_DEPENDS_PATH}/lib)
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mms-bitfields")
if (CMAKE_CROSSCOMPILING)
list (APPEND CMAKE_FIND_ROOT_PATH ${WIN32_DEPENDS_PATH})
endif (CMAKE_CROSSCOMPILING)
set (ENV{PKG_CONFIG_LIBDIR}
"${WIN32_DEPENDS_PATH}/share/pkgconfig:${WIN32_DEPENDS_PATH}/lib/pkgconfig")
endif (WIN32)
# Dependencies
find_package (ZLIB REQUIRED)
find_package (Ncursesw REQUIRED)
@ -18,7 +37,7 @@ find_package (PkgConfig REQUIRED)
pkg_check_modules (dependencies REQUIRED glib-2.0>=2.38 gio-2.0 pango)
pkg_check_modules (icu icu-uc icu-i18n)
if (NOT icu_FOUND)
if (NOT icu_FOUND AND NOT WIN32)
find_program (icu_CONFIG_EXECUTABLE icu-config)
if (NOT icu_CONFIG_EXECUTABLE)
message (FATAL_ERROR "ICU not found")
@ -73,9 +92,8 @@ if (WITH_X11)
message (FATAL_ERROR "XCB not found")
endif ()
list (APPEND dependencies_INCLUDE_DIRS ${xcb_INCLUDE_DIRS})
list (APPEND dependencies_LIBRARY_DIRS ${xcb_LIBRARY_DIRS})
list (APPEND dependencies_LIBRARIES ${xcb_LIBRARIES})
include_directories (${xcb_INCLUDE_DIRS})
link_directories (${xcb_LIBRARY_DIRS})
endif ()
pkg_check_modules (gtk gtk+-3.0)
@ -121,6 +139,10 @@ add_custom_target (docs ALL DEPENDS ${project_MAN_PAGES})
# Project libraries
set (project_common_libraries ${ZLIB_LIBRARIES} ${icu_LIBRARIES}
${dependencies_LIBRARIES})
if (WIN32)
find_package (LibIntl REQUIRED)
list (APPEND project_common_libraries ${LibIntl_LIBRARIES})
endif (WIN32)
set (project_common_headers
${PROJECT_BINARY_DIR}/config.h
@ -152,19 +174,24 @@ set (project_headers
# Build the main executable and link it
add_definitions (-DGLIB_DISABLE_DEPRECATION_WARNINGS)
add_executable (${PROJECT_NAME}
if (NOT WIN32)
add_executable (${PROJECT_NAME}
${project_sources} ${project_headers} ${project_common_sources})
target_link_libraries (${PROJECT_NAME} ${project_common_libraries}
target_link_libraries (${PROJECT_NAME} ${project_common_libraries}
${Ncursesw_LIBRARIES} termo-static)
if (WITH_X11)
target_link_libraries (${PROJECT_NAME} ${xcb_LIBRARIES})
endif ()
endif (NOT WIN32)
# The same for the alternative GTK+ UI
if (WITH_GUI)
add_executable (sdgui
add_executable (sdgui WIN32
src/sdgui.c
src/stardict-view.c
${project_common_sources})
target_include_directories (sdgui PUBLIC ${gtk_INCLUDE_DIRS})
target_link_libraries (sdgui ${gtk_LIBRARIES} ${project_common_libraries})
target_link_libraries (sdgui ${project_common_libraries} ${gtk_LIBRARIES})
endif ()
# Tools
@ -193,22 +220,50 @@ endforeach ()
add_custom_target (dicts DEPENDS ${dicts_targets})
# The files to be installed
include (GNUInstallDirs)
install (TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR})
install (FILES LICENSE DESTINATION ${CMAKE_INSTALL_DOCDIR})
if (WITH_GUI)
if (NOT WIN32)
include (GNUInstallDirs)
install (TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR})
install (FILES LICENSE DESTINATION ${CMAKE_INSTALL_DOCDIR})
if (WITH_GUI)
install (TARGETS sdgui DESTINATION ${CMAKE_INSTALL_BINDIR})
install (FILES sdgui.desktop
DESTINATION ${CMAKE_INSTALL_DATADIR}/applications)
install (FILES sdgui.xml
DESTINATION ${CMAKE_INSTALL_DATADIR}/mime/packages)
endif ()
endif ()
foreach (page ${project_MAN_PAGES})
foreach (page ${project_MAN_PAGES})
string (REGEX MATCH "\\.([0-9])$" manpage_suffix "${page}")
install (FILES "${page}"
DESTINATION "${CMAKE_INSTALL_MANDIR}/man${CMAKE_MATCH_1}")
endforeach ()
endforeach ()
elseif (WITH_GUI)
# This rather crude filter has been mostly copied over from logdiag
install (TARGETS sdgui DESTINATION .)
install (DIRECTORY
${WIN32_DEPENDS_PATH}/bin/
DESTINATION .
FILES_MATCHING PATTERN "*.dll"
PATTERN "libgettext*" EXCLUDE)
install (DIRECTORY
${WIN32_DEPENDS_PATH}/etc/
DESTINATION etc)
install (DIRECTORY
${WIN32_DEPENDS_PATH}/lib/gdk-pixbuf-2.0
DESTINATION lib
FILES_MATCHING PATTERN "*" PATTERN "*.a" EXCLUDE)
install (DIRECTORY
${WIN32_DEPENDS_PATH}/share/glib-2.0/schemas
DESTINATION share/glib-2.0)
install (DIRECTORY
${WIN32_DEPENDS_PATH}/share/icons/Adwaita
DESTINATION share/icons OPTIONAL)
install (FILES
${WIN32_DEPENDS_PATH}/share/icons/hicolor/index.theme
DESTINATION share/icons/hicolor)
endif ()
# Do some unit tests
option (BUILD_TESTING "Build tests" OFF)

View File

@ -12,9 +12,9 @@ software.
image::sdtui.png[align="center"]
With GTK+ 3 development packages installed, an alternative frontend will also be
built and installed. It shares the default dictionary list with 'sdtui',
but styling will follow your theme, and has to be customized from 'gtk.css'.
As a recent addition, there is now an alternative GTK+ 3 based frontend as well.
It shares its dictionary list with 'sdtui', but styling will follow your theme,
and may be customized from 'gtk.css'.
Packages
--------
@ -36,7 +36,8 @@ Runtime dependencies: ncursesw, zlib, ICU, termo (included), glib-2.0 >= 2.38,
$ git clone --recursive https://git.janouch.name/p/sdtui.git
$ mkdir sdtui/build
$ cd sdtui/build
$ cmake .. -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Debug -DWITH_X11=ON
$ cmake .. -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Debug \
-DWITH_X11=ON -DWITH_GUI=ON
$ make
To install the application, you can do either the usual:
@ -53,6 +54,18 @@ an argument. It is, however, preferable to
link:docs/sdtui.1.adoc#_configuration[configure it] to load your dictionaries
automatically.
Windows
~~~~~~~
With the help of Mingw-w64 and WINE, the GUI will successfully cross-compile
for Windows. It isn't particularly usable on that system, if only because
selection watching is a very X11/Wayland-specific feature. Beware that build
dependencies take up almost a gigabyte of disk space.
$ sh cmake/Win64Depends.cmake
$ cmake -DCMAKE_TOOLCHAIN_FILE=cmake/Win64CrossToolchain.cmake \
-DCMAKE_BUILD_TYPE=Release -B build
$ cmake --build build -- package
Dictionaries
------------
This application is intended for use with specific dictionaries: each line

8
cmake/FindLibIntl.cmake Normal file
View File

@ -0,0 +1,8 @@
# Public Domain
find_library (LibIntl_LIBRARIES intl)
include (FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS (LibIntl DEFAULT_MSG LibIntl_LIBRARIES)
mark_as_advanced (LibIntl_LIBRARIES)

View File

@ -0,0 +1,15 @@
set (CMAKE_SYSTEM_NAME "Windows")
set (CMAKE_SYSTEM_PROCESSOR "x86_64")
set (CMAKE_C_COMPILER "x86_64-w64-mingw32-gcc")
set (CMAKE_CXX_COMPILER "x86_64-w64-mingw32-g++")
set (CMAKE_RC_COMPILER "x86_64-w64-mingw32-windres")
# Not needed to crosscompile an installation package
#set (CMAKE_CROSSCOMPILING_EMULATOR "wine64")
set (CMAKE_FIND_ROOT_PATH "/usr/x86_64-w64-mingw32")
set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)

74
cmake/Win64Depends.sh Normal file
View File

@ -0,0 +1,74 @@
#!/bin/sh -e
# Win64Depends.sh: download dependencies from MSYS2 for cross-compilation
# Dependencies: AWK, sed, sha256sum, cURL, bsdtar, wine64
repository=https://repo.msys2.org/mingw/mingw64/
status() {
echo "$(tput bold)-- $*$(tput sgr0)"
}
dbsync() {
status Fetching repository DB
[ -f db.tsv ] || curl -# "$repository/mingw64.db" | bsdtar -xOf- | awk '
function flush() { print f["%NAME%"] f["%FILENAME%"] f["%DEPENDS%"] }
NR > 1 && $0 == "%FILENAME%" { flush(); for (i in f) delete f[i] }
!/^[^%]/ { field = $0; next } { f[field] = f[field] $0 "\t" }
field == "%SHA256SUM%" { path = "*packages/" f["%FILENAME%"]
sub(/\t$/, "", path); print $0, path > "db.sums" } END { flush() }
' > db.tsv
}
fetch() {
status Resolving "$@"
mkdir -p packages
awk -F'\t' 'function get(name, i, a) {
if (visited[name]++ || !(name in filenames)) return
print filenames[name]; split(deps[name], a); for (i in a) get(a[i])
} BEGIN { while ((getline < "db.tsv") > 0) {
filenames[$1] = $2; deps[$1] = ""; for (i = 3; i <= NF; i++) {
gsub(/[<=>].*/, "", $i); deps[$1] = deps[$1] $i FS }
} for (i = 0; i < ARGC; i++) get(ARGV[i]) }' "$@" | while IFS= read -r name
do
status Fetching "$name"
[ -f "packages/$name" ] || curl -#o "packages/$name" "$repository/$name"
done
}
verify() {
status Verifying checksums
sha256sum --ignore-missing --quiet -c db.sums
}
extract() {
status Extracting packages
for subdir in *
do [ -d "$subdir" -a "$subdir" != packages ] && rm -rf -- "$subdir"
done
for i in packages/*
do bsdtar -xf "$i" --strip-components 1 mingw64
done
}
configure() {
status Configuring packages
glib-compile-schemas share/glib-2.0/schemas
wine64 bin/gdk-pixbuf-query-loaders.exe \
> lib/gdk-pixbuf-2.0/2.10.0/loaders.cache
# pkgconf has a command line option for this, but CMake can't pass it
sed -i "s|^prefix=/mingw64|prefix=$(pwd)|" {share,lib}/pkgconfig/*.pc
}
mkdir -p win32-depends
cd win32-depends
dbsync
fetch mingw-w64-x86_64-gtk3 mingw-w64-x86_64-icu \
mingw-w64-x86_64-libwinpthread-git # because we don't do "provides"?
verify
extract
configure
status Success
# XXX: Why is this override needed to run some GLib-based things under wine64?
export XDG_DATA_DIRS=$(pwd)/share

View File

@ -20,6 +20,7 @@
#include <glib/gi18n.h>
#include <locale.h>
#include <stdlib.h>
#include "config.h"
#include "stardict.h"

View File

@ -1,7 +1,7 @@
/*
* utils.c: miscellaneous utilities
*
* Copyright (c) 2013 - 2020, Přemysl Eric Janouch <p@janouch.name>
* Copyright (c) 2013 - 2021, Přemysl Eric Janouch <p@janouch.name>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted.
@ -25,7 +25,9 @@
#include <errno.h>
#include <stdarg.h>
#ifndef WIN32
#include <pwd.h>
#endif // ! WIN32
#include "config.h"
#include "utils.h"
@ -161,6 +163,10 @@ try_expand_tilde (const gchar *filename)
if (!until_slash)
return g_build_filename (g_get_home_dir () ?: "", filename, NULL);
#ifdef WIN32
// TODO: also ensure that path separators are handled sensibly around here
return NULL;
#else // ! WIN32
long buf_len = sysconf (_SC_GETPW_R_SIZE_MAX);
if (buf_len < 0)
buf_len = 1024;
@ -177,6 +183,7 @@ try_expand_tilde (const gchar *filename)
result = g_strdup_printf ("%s%s", pwd.pw_dir, filename + until_slash);
g_free (buf);
return result;
#endif // ! WIN32
}
gchar *