User:Iceiceice/Cross-compiling
Here are some instructions I created the first time I managed to cross compile wesnoth. It's as much a "post-mortem" as a guide, I leave it here in case I ever want to do it again later, or if it might help someone.
These instructions refer to using mingw to cross-compile wesnoth 1.13.0-dev on Linux Mint Qiana 17 , targeted at 32-bit windows.
Last tested at commit: 1385ab3791088d7c9bfa3bc439fcf49b23563535
Contents
Get mingw32
It might seem as simple as "sudo apt-get install mingw32", but after you do this, you need to make sure that you have a 32 bit compiler which is good enough to compile wesnoth. This required some trial and error, the version I got automatically from the distribution was only gcc 4.2, as you can see:
$ i586-mingw32msvc-g++ -v Using built-in specs. Target: i586-mingw32msvc Configured with: /build/buildd/mingw32-4.2.1.dfsg/build_dir/src/gcc-4.2.1-2-dfsg/configure -v --prefix=/usr --target=i586-mingw32msvc --enable-languages=c,c++ --enable-threads --enable-sjlj-exceptions --disable-multilib --enable-version-specific-runtime-libs Thread model: win32 gcc version 4.2.1-sjlj (mingw32-2)
Furthermore it was broken, and had some bugs about ::swprintf not defined, which caused boost iostreams to break... google this for some stories of pain. [1] [2] [3]
Therefore to get a more recent version of mingw I added a package from utopic universe :
$ sudo add-apt-repository -y "deb http://archive.ubuntu.com/ubuntu/ utopic main universe"
And I install
$ sudo apt-get install g++-mingw-w64-i686
(Launchpad page: http://packages.ubuntu.com/utopic/g++-mingw-w64-x86-64)
Now I get this instead
$ i686-w64-mingw32-g++ -v Using built-in specs. COLLECT_GCC=i686-w64-mingw32-g++ COLLECT_LTO_WRAPPER=/usr/lib/gcc/i686-w64-mingw32/4.9-win32/lto-wrapper Target: i686-w64-mingw32 Configured with: ../../src/configure --build=x86_64-linux-gnu --prefix=/usr --includedir='/usr/include' --mandir='/usr/share/man' --infodir='/usr/share/info' --sysconfdir=/etc --localstatedir=/var --libexecdir='/usr/lib/gcc-mingw-w64' --disable-maintainer-mode --disable-dependency-tracking --prefix=/usr --enable-shared --enable-static --disable-multilib --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --libdir=/usr/lib --enable-libstdcxx-time=yes --with-tune=generic --enable-version-specific-runtime-libs --enable-fully-dynamic-string --enable-libgomp --enable-languages=c,c++,fortran,objc,obj-c++ --enable-lto --with-plugin-ld --enable-threads=win32 --program-suffix=-win32 --program-prefix=i686-w64-mingw32- --target=i686-w64-mingw32 --with-as=/usr/bin/i686-w64-mingw32-as --with-ld=/usr/bin/i686-w64-mingw32-ld Thread model: win32 gcc version 4.9.1 (GCC)
With gcc 4.9, now we are in business.
Download loonycyborg's wesnoth deps collection
http://sourceforge.net/projects/wesnoth/files/SDK/wesnoth-deps-1.11.zip/download
I'm going to assume henceforth that you extract this to the folder "~/w-deps", and that inside is "include", "bin" etc. directories.
Download boost
I wanted to test our stated boost dependencies, so I actually make a folder "~/old-boost/" where I hold several versions of boost. You can find any old version of boost at sourceforge, e.g.
http://sourceforge.net/projects/boost/files/boost/1.52.0/
http://sourceforge.net/projects/boost/files/boost/1.48.0/
http://sourceforge.net/projects/boost/files/boost/1.44.0/
etc.
Download one of these and extract it to ~/old-boost/, or take from w-deps folder.
I'm going to assume that you picked boost 1.52.0, so your boost directory is ~/old_boost/boost_1_52_0/.
Make a boost config file (tell it what compiler you want to use)
In your home directory, make a text file called user_config.jam.
Here's some sample contents:
$ cat user-config.jam using gcc ; using gcc : 4.6 : g++-4.6 ; using gcc : w64mingw32 : i586-mingw32msvc-g++ ; using gcc : w64mingw64 : x86_64-w64-mingw32-g++ ;
When boost has a file like this, it means that e.g. "toolset=gcc-4.6" will cause it to use the compiler g++-4.6, and "toolset=gcc-w64mingw32" will cause it to use the compiler i586-mingw32msvc-g++.
Make a line like this:
using gcc : w64mingw32 : i686-w64-mingw32-g++ ;
To register our new compiler.
(And make sure its the only w64mingw32 line of course.)
Compile boost
Navigate to your boost directory, ~/old_boost/boost_1_52_0/
First, run the "bootstrap" program,
./bootstrap.sh
You don't need to give it any arguments, it doesn't really matter what it builds with. It is just building the boost jam program which will actually orchestrate the boost build.
Now, run boost jam (called "b2"). I recommend to put the actual command in shell script, for ease of use in case you have to modify it (and so you don't forget it...)
I used the following recipe:
$ cat recipe #!/bin/bash ./b2 toolset=gcc-w64mingw32 -d+2 -a --reconfigure --debug-configuration --with-iostreams --with-locale --with-regex --with-filesystem --with-system --with-program_options target-os=windows variant=release threading=multi threadapi=win32 address-model=32 architecture=x86 instruction-set=i686 link=static runtime-link=static -j 2 -sBZIP2_BINARY=libbz2 -sBZIP2_INCLUDE=/home/chris/w-deps/include -sBZIP2_LIBPATH=/home/chris/w-deps/bin -sZLIB_BINARY=zlib -sZLIB_INCLUDE=/home/chris/w-deps/include -sZLIB_LIBPATH=/home/chris/w-deps/bin
Discussion of flags
- toolset=gcc-w64mingw32
- Tells to use the compiler I choose for 32 bit windows. Could also have tried e.g. gcc-w64mingw64, for 64-bit windows, based on my user-config.jam, or gcc-4.6 for g++-4.6 compiler (see my user-config.jam above)
- -d+2
- --debug-configuration
- These are debugging output options that make boost tell you about the configuration, and show you what compiler commands it is running.
- -a
- --reconfigure
- -a makes sure that all targets are rebuilt, and reconfigure makes sure that it reconfigures based on new options. If you are changing things around these options prevent you from getting screwed over by stale options.
- --with-iostreams
- --with-locale
- --with-regex
- --with-filesystem
- --with-system
- --with-program_options
- Select what libraries you want. It's better to use --with than --without because otherwise you get a bunch of random crap. You can't use both kinds.
- target-os=windows
- threading=multi
- threadapi=win32
- You need these to make it build dll's, and that will work for you.
- address-model=32
- architecture=x86
- instruction-set=i686
- I added these out of paranoia at some point but they might not really be necessary
- link=static
- runtime-link=static
- This is the only reasonable option here
- -j 2
- Parallelize the build over 2 cores
- -sBZIP2_BINARY=libbz2
- -sBZIP2_INCLUDE=/home/chris/w-deps/include
- -sBZIP2_LIBPATH=/home/chris/w-deps/bin
- Tell boost exactly where to find bzip2 binary and header. I earlier tried to do this just with cxxflags and linker flags, but it got confused with my system-installed bzip2 and caused me a lot of pain. This fixed it.
- -sZLIB_BINARY=zlib
- -sZLIB_INCLUDE=/home/chris/w-deps/include
- -sZLIB_LIBPATH=/home/chris/w-deps/bin
- Tell boost exactly where to find zlib binary and header.
Now run the recipe (don't forget to "chmod +x" it):
$ ./recipe
If you would like to suppress the warnings, you can use cxxflags="-w" as an additional argument.
You should get this at the end:
The Boost C++ Libraries were successfully built! The following directory should be added to compiler include paths: /home/chris/old_boost/boost_1_52_0 The following directory should be added to linker library paths: /home/chris/old_boost/boost_1_52_0/stage/lib
If you did not, check that all of your paths are matching correctly, that you actually have a libbz2.a and zlib.a in your ~/w-deps/bin, (and that they *match* the associated headers... if in doubt, try downloading again, or even compile the c libraries yourself, it doesn't matter what compiler you use for c libraries). Check that the compiler name is correct. You could use cxxflags to try to get additional diagnostics. The -d+2 command causes boost to output much additional diagnostics as well.
Compile wesnoth
Now, you need to craft an scons command that will properly tell it to cross compile, to use the cross compiling compiler, and point it to your fresh boost compile, and all the deps. I prefer to in this case as well store the recipe in a shell script:
$ cat build_mingw_boost_1_52.sh #!/bin/bash rm .scons-option-cache scons default_targets=wesnoth build=release extra_flags_config="-DBOOST_THREAD_USE_LIB -Wno-unused-local-typedefs" prefix=~/w-deps boostdir=~/old_boost/boost_1_52_0 boostlibdir=~/old_boost/boost_1_52_0/stage/lib gettextdir=~/w-deps gtkdir=~/w-deps host=i686-w64-mingw32
Some discussion
- rm .scons-option-cache
- So that stale settings can't screw up my build and confuse me
- default_targets=wesnoth
- This could also be wesnoth, wesnothd, campaignd. I think it can't include "test" atm because we didn't compile the boost unit testing system.
- build=release
- Unless you want to make a debug build
- extra_flags_config
- Add -Wno-unused-local-typedefs or your log will be unreadable with pointless warnings.
- Add -DBOOST_THREAD_USE_LIB because loonycyborg said so
- prefix=~/w-deps
- This is pretty handy, this will cause scons to add ~/w-deps/include to be included as a cxx flag, and also to add ~/w-deps/bin to be linked. So it saves you some typing.
- boostdir=~/old_boost/boost_1_52_0
- First directory that boost reported to you above (or for whatever boost version you want to use)
- boostlibdir=~/old_boost/boost_1_52_0/stage/lib
- Second directory that boost reported to you above (Wherever the boost libraries ended up for you.)
- gettextdir=~/w-deps
- gtkdir=~/w-deps
- These point scons to find compiled versions of these, and not your system version (which will not be binary compatible in case of C++ libs).
- Note that I don't add sdldir=~/w-deps, because it shouldn't be necessary as SDL is a c lib, so my system version is fine. But if you get a problem finding or linking SDL, then add that in also.
- host=i686-w64-mingw32
- This is where we select the compiler, actually. scons will prepend the "host" followed by -, followed by g++, if no cxxtool argument is given. (I'm not sure how "host" and "cxxtool" arguments interact.) So this selection results in the compiler, i686-w64-mingw32-g++, as desired.
That's all there is to it. Good luck.
WINE
To get wine to run I did the following. You must make sure you are using a 32 bit environment.
env WINEPREFIX=~/prefix32 WINEARCH=win32 wine cmd
All the online instructions say that you need to update wine's path, using regedit, to point to your dll's. I couldn't actually get this to work, so I ended up putting symlinks in my prefix 32 C:\windows\system32 directory:
~/prefix32/drive_c/windows/system32 $ ln -s ~/w-deps/bin ~/prefix32/drive_c/windows/system32 $ ln -s /usr/lib/gcc/i686-w64-mingw32/4.9-win32/
Besides the libs like SDL, pango, etc., you also need a .dll specific to mingw (I guess this is the mingw run time library). I found that I needed this dll:
/usr/lib/gcc/i686-w64-mingw32/4.9-win32/libgcc_s_sjlj-1.dll
If I got errors like this:
$ env WINEPREFIX=~/prefix32 WINEARCH=win32 wine wesnoth err:module:import_dll Library libpangoft2-1.0-0.dll (which is needed by L"C:\\windows\\system32\\libpangocairo-1.0-0.dll") not found err:module:import_dll Library libpangocairo-1.0-0.dll (which is needed by L"Z:\\home\\chris\\wesnoth-src\\clone\\wesnoth\\wesnoth.exe") not found err:module:LdrInitializeThunk Main exe initialization for L"Z:\\home\\chris\\wesnoth-src\\clone\\wesnoth\\wesnoth.exe" failed, status c0000135
I fixed it by adding a symlink to ~/w-deps/bin/libpangoft2-1.0-0.dll in the folder prefix32/drive_c/windows/system32.
And so on and so forth... Eventually it worked.
Troubleshooting
A helpful thing I found is, if you have problems running wesnoth with the DLL's, you can sanity check by running the little executables generated by scons for the configuration tests. E.g.
$ env WINEPREFIX=~/prefix32 WINEARCH=win32 wine build/sconf_temp/conftest_20.exe
If the test works it should give no output, otherwise if it's not linking right it should give you an error.