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 # For custom modules
set (CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake) 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 # Dependencies
find_package (ZLIB REQUIRED) find_package (ZLIB REQUIRED)
find_package (Ncursesw 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 (dependencies REQUIRED glib-2.0>=2.38 gio-2.0 pango)
pkg_check_modules (icu icu-uc icu-i18n) 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) find_program (icu_CONFIG_EXECUTABLE icu-config)
if (NOT icu_CONFIG_EXECUTABLE) if (NOT icu_CONFIG_EXECUTABLE)
message (FATAL_ERROR "ICU not found") message (FATAL_ERROR "ICU not found")
@ -73,9 +92,8 @@ if (WITH_X11)
message (FATAL_ERROR "XCB not found") message (FATAL_ERROR "XCB not found")
endif () endif ()
list (APPEND dependencies_INCLUDE_DIRS ${xcb_INCLUDE_DIRS}) include_directories (${xcb_INCLUDE_DIRS})
list (APPEND dependencies_LIBRARY_DIRS ${xcb_LIBRARY_DIRS}) link_directories (${xcb_LIBRARY_DIRS})
list (APPEND dependencies_LIBRARIES ${xcb_LIBRARIES})
endif () endif ()
pkg_check_modules (gtk gtk+-3.0) pkg_check_modules (gtk gtk+-3.0)
@ -121,6 +139,10 @@ add_custom_target (docs ALL DEPENDS ${project_MAN_PAGES})
# Project libraries # Project libraries
set (project_common_libraries ${ZLIB_LIBRARIES} ${icu_LIBRARIES} set (project_common_libraries ${ZLIB_LIBRARIES} ${icu_LIBRARIES}
${dependencies_LIBRARIES}) ${dependencies_LIBRARIES})
if (WIN32)
find_package (LibIntl REQUIRED)
list (APPEND project_common_libraries ${LibIntl_LIBRARIES})
endif (WIN32)
set (project_common_headers set (project_common_headers
${PROJECT_BINARY_DIR}/config.h ${PROJECT_BINARY_DIR}/config.h
@ -152,19 +174,24 @@ set (project_headers
# Build the main executable and link it # Build the main executable and link it
add_definitions (-DGLIB_DISABLE_DEPRECATION_WARNINGS) add_definitions (-DGLIB_DISABLE_DEPRECATION_WARNINGS)
add_executable (${PROJECT_NAME} if (NOT WIN32)
add_executable (${PROJECT_NAME}
${project_sources} ${project_headers} ${project_common_sources}) ${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) ${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 # The same for the alternative GTK+ UI
if (WITH_GUI) if (WITH_GUI)
add_executable (sdgui add_executable (sdgui WIN32
src/sdgui.c src/sdgui.c
src/stardict-view.c src/stardict-view.c
${project_common_sources}) ${project_common_sources})
target_include_directories (sdgui PUBLIC ${gtk_INCLUDE_DIRS}) 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 () endif ()
# Tools # Tools
@ -193,22 +220,50 @@ endforeach ()
add_custom_target (dicts DEPENDS ${dicts_targets}) add_custom_target (dicts DEPENDS ${dicts_targets})
# The files to be installed # The files to be installed
include (GNUInstallDirs) if (NOT WIN32)
install (TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR}) include (GNUInstallDirs)
install (FILES LICENSE DESTINATION ${CMAKE_INSTALL_DOCDIR}) install (TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR})
if (WITH_GUI) install (FILES LICENSE DESTINATION ${CMAKE_INSTALL_DOCDIR})
if (WITH_GUI)
install (TARGETS sdgui DESTINATION ${CMAKE_INSTALL_BINDIR}) install (TARGETS sdgui DESTINATION ${CMAKE_INSTALL_BINDIR})
install (FILES sdgui.desktop install (FILES sdgui.desktop
DESTINATION ${CMAKE_INSTALL_DATADIR}/applications) DESTINATION ${CMAKE_INSTALL_DATADIR}/applications)
install (FILES sdgui.xml install (FILES sdgui.xml
DESTINATION ${CMAKE_INSTALL_DATADIR}/mime/packages) 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}") string (REGEX MATCH "\\.([0-9])$" manpage_suffix "${page}")
install (FILES "${page}" install (FILES "${page}"
DESTINATION "${CMAKE_INSTALL_MANDIR}/man${CMAKE_MATCH_1}") 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 # Do some unit tests
option (BUILD_TESTING "Build tests" OFF) option (BUILD_TESTING "Build tests" OFF)

View File

@ -12,9 +12,9 @@ software.
image::sdtui.png[align="center"] image::sdtui.png[align="center"]
With GTK+ 3 development packages installed, an alternative frontend will also be As a recent addition, there is now an alternative GTK+ 3 based frontend as well.
built and installed. It shares the default dictionary list with 'sdtui', It shares its dictionary list with 'sdtui', but styling will follow your theme,
but styling will follow your theme, and has to be customized from 'gtk.css'. and may be customized from 'gtk.css'.
Packages 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 $ git clone --recursive https://git.janouch.name/p/sdtui.git
$ mkdir sdtui/build $ mkdir sdtui/build
$ cd 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 $ make
To install the application, you can do either the usual: 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 link:docs/sdtui.1.adoc#_configuration[configure it] to load your dictionaries
automatically. 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 Dictionaries
------------ ------------
This application is intended for use with specific dictionaries: each line 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 <glib/gi18n.h>
#include <locale.h> #include <locale.h>
#include <stdlib.h>
#include "config.h" #include "config.h"
#include "stardict.h" #include "stardict.h"

View File

@ -1,7 +1,7 @@
/* /*
* utils.c: miscellaneous utilities * 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 * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted. * purpose with or without fee is hereby granted.
@ -25,7 +25,9 @@
#include <errno.h> #include <errno.h>
#include <stdarg.h> #include <stdarg.h>
#ifndef WIN32
#include <pwd.h> #include <pwd.h>
#endif // ! WIN32
#include "config.h" #include "config.h"
#include "utils.h" #include "utils.h"
@ -161,6 +163,10 @@ try_expand_tilde (const gchar *filename)
if (!until_slash) if (!until_slash)
return g_build_filename (g_get_home_dir () ?: "", filename, NULL); 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); long buf_len = sysconf (_SC_GETPW_R_SIZE_MAX);
if (buf_len < 0) if (buf_len < 0)
buf_len = 1024; 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); result = g_strdup_printf ("%s%s", pwd.pw_dir, filename + until_slash);
g_free (buf); g_free (buf);
return result; return result;
#endif // ! WIN32
} }
gchar * gchar *