From dd896b93e33038119fabda0e73367e460a75996f Mon Sep 17 00:00:00 2001 From: "Juan J. Martinez" Date: Sun, 12 Feb 2023 14:51:46 +0000 Subject: Initial import --- .gitignore | 3 +++ README.md | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ bin/cabal-wine | 12 +++++++++ bootstrap | 72 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 171 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100755 bin/cabal-wine create mode 100755 bootstrap diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3e14be5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +packages/ +cache/ +workdir/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..cf90a21 --- /dev/null +++ b/README.md @@ -0,0 +1,84 @@ +# Cross-compile Haskell on Linux targeting Windows using WINE + +This is aimed at Linux + Haskell + SDL2 + SDL2_Image, but it could be used for other cases. + +The main idea is to run the Windows version of all the needed compilers, on Linux using Wine. Cabal it is the entry point and it needs a script wrapping it so it runs with Wine and it can find the needed tools. + +It comes with no warranty, I'm documenting this for myself, and sharing it because *it is fiddly* and I hope that it might help other people. + +What is needed: + +- Cabal for Windows +- GHC for Windows +- MingGW-W64 +- SDL2 development for MinGW +- pkg-config-lite for Windows +- Wine on a Linux host (used Debian 11) +- Patience and luck! + +Install Wine with: +``` +sudo dpkg --add-architecture i386 +sudo apt-get update +sudo apt-get install --no-install-recommends -y wine wine32 wine64 +``` + +(or similar, I don't think it matters much as long it is a healthy Wine installation) + +## bootstrap script + +Edit the `bootstrap` script (you may need to adapt it to your system), and check that you are happy with the versions. It is a convenient way of setting up everything *for me*, but may not be useful for anybody else (also: it is a bit fragile). + +It requires: wget, 7z, unzip, tar and make (among other more common POSIX tools). + +The directory structure will be: + +- cache: where the requirements are downloaded. +- packages: where the different Windows tools are setup. +- workdir: where you should put your project (can be in any directory). +- bin: contains `cabal-wine` helper. + +Currently I'm using: + +- Cabal 3.8.1.0 +- GHC 9.2.5 +- MinGW-W64 12.2.0 +- SDL2 2.26.3 +- SDL2_Image 2.6.3 + +**Important**: you need to copy SDL2.dll and SDL2_image.dll to your `system32` directory in WINE, usually: +``` +~/.wine/drive_c/windows/system32/ +``` +This is needed to compile sdl2 and sdl2-image. When you have your binary, you need to distribute those two DLLs with your .EXE. + +## Updating packages + +Run `bin/cabal-wine update` and Cabal should download the latest package list from hackage. + +## Building your peoject + +Get into workdir/your-project and run: + +`../../bin/cabal-wine build --builddir build` + +And it should work! + +## Troubleshooting + +**Extra logging** + +Pass `-v` option when running `cabal-wine` for exta information. + +**Failed to compile SDL2_Image** + +I have found that SDL2_Image is trying to include a SDL_Main when is not necessary. + +Once you have compiled sdl2, you can edit `packages/mingw64/x86_64-w64-mingw32/include/SDL2/SDL.h` and comment out the `#include "SDL_main.h"` line. + +There must be a better way of fixing this (perhaps a bug report to sdl2-image could help!). + +**Wine can't run the resulting binary** + +I use Debian stable, and the Wine version can be a bit old. It compiles fine, but running the resulting binary may not work. Try a more recent Wine version (tested with 8 and works fine). + diff --git a/bin/cabal-wine b/bin/cabal-wine new file mode 100755 index 0000000..4e11e70 --- /dev/null +++ b/bin/cabal-wine @@ -0,0 +1,12 @@ +#!/bin/bash + +set +e + +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) +BASE=`realpath $SCRIPT_DIR/..` + +export WINEPATH=`winepath -w $BASE/ghc/bin/`:`winepath -w $BASE/mingw64/bin/`:`winepath -w $BASE/bin/` +export PKG_CONFIG_PATH=`winepath -w $BASE/packages/mingw64/x86_64-w64-mingw32/lib/pkgconfig` + +wine $BASE/packages/cabal/cabal.exe --http-transport=plain-http $* -w $BASE/packages/ghc/bin/ghc.exe --with-gcc=$BASE/packages/mingw64/bin/gcc.exe + diff --git a/bootstrap b/bootstrap new file mode 100755 index 0000000..aba6584 --- /dev/null +++ b/bootstrap @@ -0,0 +1,72 @@ +#!/bin/bash + +set +e + +PACKAGES=""" +https://downloads.haskell.org/~cabal/cabal-install-3.8.1.0/cabal-install-3.8.1.0-x86_64-windows.zip +https://downloads.haskell.org/~ghc/9.2.5/ghc-9.2.5-x86_64-unknown-mingw32-integer-simple.tar.xz +https://github.com/niXman/mingw-builds-binaries/releases/download/12.2.0-rt_v10-rev2/x86_64-12.2.0-release-win32-seh-msvcrt-rt_v10-rev2.7z +https://github.com/libsdl-org/SDL/releases/download/release-2.26.3/SDL2-devel-2.26.3-mingw.tar.gz +https://github.com/libsdl-org/SDL_image/releases/download/release-2.6.3/SDL2_image-devel-2.6.3-mingw.tar.gz +https://downloads.sourceforge.net/project/pkgconfiglite/0.28-1/pkg-config-lite-0.28-1_bin-win32.zip +""" + +mkdir -p packages cache workdir + +for p in $PACKAGES; do + fname=`basename $p` + if [ -f cache/$fname ]; then + echo $fname already downloaded: OK + else + wget $p -O cache/$fname + fi +done + +if [ -d packages/cabal ]; then + echo packages/cabal directory exists, skipping +else + echo Extracting Cabal + unzip cache/cabal-install-3.8.1.0-x86_64-windows.zip -d packages/cabal +fi + +if [ -d packages/ghc ]; then + echo packages/ghc directory exists, skipping +else + echo Extracting GHC + tar -C packages -xJf cache/ghc-9.2.5-x86_64-unknown-mingw32-integer-simple.tar.xz + mv packages/ghc-9.2.5-x86_64-unknown-mingw32 packages/ghc +fi + +if [ -f packages/cabal/pkg-config.exe ]; then + echo packages/cabal/pkg-config.exe exists, skipping +else + echo Extracting pkg-config.exe + unzip -j cache/pkg-config-lite-0.28-1_bin-win32.zip pkg-config-lite-0.28-1/bin/pkg-config.exe -d packages/cabal +fi + +if [ -d packages/mingw64 ]; then + echo packages/mingw84 directory exists, skipping +else + echo Extracting MingGW-W64 + 7z x -opackages cache/x86_64-12.2.0-release-win32-seh-msvcrt-rt_v10-rev2.7z +fi + +if [ -d packages/sdl ]; then + echo packages/sdl directory exists, skipping +else + echo Extractig SDL2 + tar -C packages -xzf cache/SDL2-devel-2.26.3-mingw.tar.gz + mv packages/SDL2-2.26.3 packages/sdl + make CROSS_PATH=`realpath $PWD/packages/mingw64` -C packages/sdl cross +fi + +if [ -d packages/sdl-image ]; then + echo packages/sdl-image directory exists, skipping +else + echo Extracting SDL2_Image + tar -C packages -xzf cache/SDL2_image-devel-2.6.3-mingw.tar.gz + mv packages/SDL2_image-2.6.3 packages/sdl-image + make CROSS_PATH=`realpath $PWD/packages/mingw64` -C packages/sdl-image cross +fi + +echo "DONE!" -- cgit v1.2.3