|
2 | 2 |
|
3 | 3 | set -e |
4 | 4 |
|
| 5 | +# The Story So Far |
| 6 | +# |
| 7 | +# We need two cross-compilers to build Proton. These each have to run in the |
| 8 | +# Steam runtimes, each of which only supports 32- or 64-bit programs. Our build |
| 9 | +# VM is a 64-bit Linux machine. So our platform configurations are: |
| 10 | +# |
| 11 | +# 64-bit cross-compiler: |
| 12 | +# Build (where the compiler is built): 64-bit linux (our VM) |
| 13 | +# Host (where the compiler is run): 64-bit linux (64-bit Steam runtime) |
| 14 | +# Target (what the compiler outputs): 64-bit win32 (PE files to be run) |
| 15 | +# |
| 16 | +# 32-bit cross-compiler: |
| 17 | +# Build (where the compiler is built): 64-bit linux (our VM) |
| 18 | +# Host (where the compiler is run): 32-bit linux (32-bit Steam runtime) |
| 19 | +# Target (what the compiler outputs): 32-bit win32 (PE files to be run) |
| 20 | +# |
| 21 | +# The former is a pretty standard cross-compiler setup. |
| 22 | +# |
| 23 | +# gcc calls the latter, where all of the platforms are different, a "Canadian" |
| 24 | +# build. See "The GNU configure and build system" by Ian Lance Taylor, section |
| 25 | +# "Canadian Cross", available here: |
| 26 | +# https://www.airs.com/ian/configure/configure_6.html |
| 27 | +# |
| 28 | +# This turned out to be quite difficult, possibly due to the added complexity of |
| 29 | +# mingw-w64. I'm documenting the problems I had and how I solved/worked around |
| 30 | +# them here, to hopefully save myself or someone else some heartburn in the |
| 31 | +# future. If you are a compiler expert and find yourself shaking your head at |
| 32 | +# this poor fool, I welcome your assistance improving this. |
| 33 | +# |
| 34 | +# Canadian builds require the build machine to already have a cross-compiler for |
| 35 | +# the Target platform available on the Build machine. Without this, the gcc build |
| 36 | +# will fail with: |
| 37 | +# |
| 38 | +# i686-w64-mingw32-gcc -dumpspecs > tmp-specs |
| 39 | +# /bin/bash: i686-w64-mingw32-gcc: command not found |
| 40 | +# |
| 41 | +# We are building both C and C++ lang support, so we need both gcc and g++ |
| 42 | +# cross-compilers available. With the Build->Target cross-compilers installed, |
| 43 | +# we can now build gcc, and use that to build mingw-w64. After that, we need to |
| 44 | +# build gcc's libraries, like libgcc and libstdc++v3, against those mingw-w64 |
| 45 | +# libraries. However, the libatomic and/or libgomp builds will fail with: |
| 46 | +# |
| 47 | +# checking for suffix of object files... |
| 48 | +# configure: error: in `/home/vagrant/mingw/build-i686-w64-mingw32/gcc/i686-w64-mingw32/libatomic': |
| 49 | +# configure: error: C compiler cannot create executables |
| 50 | +# See `config.log' for more details |
| 51 | +# |
| 52 | +# checking for suffix of object files... |
| 53 | +# configure: error: in `/home/vagrant/mingw/build-i686-w64-mingw32/gcc/i686-w64-mingw32/libgomp': |
| 54 | +# configure: error: C compiler cannot create executables |
| 55 | +# See `config.log' for more details |
| 56 | +# |
| 57 | +# Digging into config.log shows it can't find libgcc: |
| 58 | +# |
| 59 | +# configure:3722: checking whether the C compiler works |
| 60 | +# configure:3744: i686-w64-mingw32-gcc -L/home/vagrant/mingw/output/i686-w64-mingw32/lib -L/home/vagrant/mingw/output/mingw/lib -isystem /home/vagrant/mingw/output/i686-w64-mingw32/include -isystem /home/vagrant/mingw/output/mingw/include -g -O2 conftest.c >&5 |
| 61 | +# /home/vagrant/mingw/output/lib/gcc/i686-w64-mingw32/9.2.0/../../../../i686-w64-mingw32/bin/ld: cannot find -lgcc |
| 62 | +# /home/vagrant/mingw/output/lib/gcc/i686-w64-mingw32/9.2.0/../../../../i686-w64-mingw32/bin/ld: cannot find -lgcc_eh |
| 63 | +# /home/vagrant/mingw/output/lib/gcc/i686-w64-mingw32/9.2.0/../../../../i686-w64-mingw32/bin/ld: cannot find -lgcc |
| 64 | +# /home/vagrant/mingw/output/lib/gcc/i686-w64-mingw32/9.2.0/../../../../i686-w64-mingw32/bin/ld: cannot find -lgcc_eh |
| 65 | +# collect2: error: ld returned 1 exit status |
| 66 | +# |
| 67 | +# I don't know what causes this (maybe Canadian builds don't like being split up |
| 68 | +# like this?). However, installing libgcc explicitly first will work around it. |
| 69 | +# After installing libgcc explicitly, we can then build the rest of gcc's |
| 70 | +# libraries. That was all the easy (ha!) stuff. At this point, you will have a |
| 71 | +# cross-compiler that will build Proton. |
| 72 | +# |
| 73 | +# However, there's a sneaky problem. For some reason the libstdc++v3 build system |
| 74 | +# requires libstdc++ to be available to detect C-lang functions(?!?). It will |
| 75 | +# still build without those C functions, but it may have far worse performance |
| 76 | +# (see Proton github issue #3198). You can detect this situation by examining the |
| 77 | +# config.log output for libstdc++v3 after your build completes: |
| 78 | +# |
| 79 | +# configure:16811: checking for gettimeofday |
| 80 | +# configure:16827: checking sys/time.h usability |
| 81 | +# configure:16827: i686-w64-mingw32-c++ -L/home/vagrant/mingw/output/i686-w64-mingw32/lib -L/home/vagrant/mingw/output/mingw/lib -isystem /home/vagrant/mingw/output/i686-w64-mingw32/include -isystem /home/vagrant/mingw/output/mingw/include -c -g -O2 -fno-exceptions conftest.cpp >&5 |
| 82 | +# configure:16827: $? = 0 |
| 83 | +# configure:16827: result: yes |
| 84 | +# configure:16827: checking sys/time.h presence |
| 85 | +# configure:16827: i686-w64-mingw32-c++ -L/home/vagrant/mingw/output/i686-w64-mingw32/lib -L/home/vagrant/mingw/output/mingw/lib -isystem /home/vagrant/mingw/output/i686-w64-mingw32/include -isystem /home/vagrant/mingw/output/mingw/include -E conftest.cpp |
| 86 | +# configure:16827: $? = 0 |
| 87 | +# configure:16827: result: yes |
| 88 | +# configure:16827: checking for sys/time.h |
| 89 | +# configure:16827: result: yes |
| 90 | +# configure:16840: checking for gettimeofday |
| 91 | +# configure:16875: i686-w64-mingw32-c++ -L/home/vagrant/mingw/output/i686-w64-mingw32/lib -L/home/vagrant/mingw/output/mingw/lib -isystem /home/vagrant/mingw/output/i686-w64-mingw32/include -isystem /home/vagrant/mingw/output/mingw/include -o conftest.exe -g -O2 -fno-exceptions conftest.cpp >&5 |
| 92 | +# /home/vagrant/mingw/output/lib/gcc/i686-w64-mingw32/9.2.0/../../../../i686-w64-mingw32/bin/ld: cannot find -lstdc++ |
| 93 | +# collect2: error: ld returned 1 exit status |
| 94 | +# |
| 95 | +# But that error doesn't kill configure, and it happily continues with this in |
| 96 | +# config.h: |
| 97 | +# |
| 98 | +# /* #undef _GLIBCXX_USE_GETTIMEOFDAY */ |
| 99 | +# |
| 100 | +# This triggers the bad codepath in libstdc++v3 that caused the performance |
| 101 | +# problem mentioned above, and is clearly wrong anyway, as gettimeofday is |
| 102 | +# definitely available. Yes, this was a huge pain to puzzle out. I "solved" this |
| 103 | +# by letting the libstdc++v3 build continue, then re-running the build after |
| 104 | +# installing it, so now it will find libstdc++ and so correctly detect the C-lang |
| 105 | +# function that has nothing at all to do with libstdc++. Argh. |
| 106 | +# |
| 107 | +# After all that, we finally have a functioning set of cross-compilers. Most of |
| 108 | +# the configuration parameters used here are taken from the Arch Linux mingw-w64 |
| 109 | +# PKGBUILDs, as those were written by someone with more knowledge than me, and |
| 110 | +# have had a lot of testing. We make one tweak to the gcc configuration, which is |
| 111 | +# to disable SJLJ exceptions and enable DWARF2 debug symbols. The former |
| 112 | +# apparently helps with performance on 32-bit, and the latter puts debug symbols |
| 113 | +# in a format that more Linux tooling can read. |
| 114 | +# |
| 115 | +# Side note, the Arch Linux PKGBUILDs work very differently from how this script |
| 116 | +# works. While working on this, I tried to adapt the PKGBUILDs' process here |
| 117 | +# (e.g. build a bootstrap C-lang compiler, use that to build mingw-w64, then |
| 118 | +# rebuild gcc against the mingw-w64 CRT with C++-lang support), but I ran into a |
| 119 | +# ton of problems, possibly caused by the Canadian-ness of the build, and |
| 120 | +# eventually ran out of ideas for working around them. |
| 121 | + |
5 | 122 | if [ -z "$1" ]; then |
6 | 123 | echo "Makes a local build of mingw-w64 in this directory and installs it to the given path." |
7 | 124 | echo "" |
8 | | - echo "Note: Requires a system mingw-w64 to be present already, for us to bootstrap with." |
| 125 | + echo "Note: Requires a system mingw-w64 compiler to be present already on your build machine, for us to bootstrap with." |
9 | 126 | echo "" |
10 | 127 | echo "usage:" |
11 | 128 | echo -e "\t$0 <installation path e.g. \$HOME/.local>" |
@@ -175,7 +292,7 @@ function build_arch { |
175 | 292 |
|
176 | 293 | pushd gcc/ |
177 | 294 | #next step requires libgcc in default library location, but |
178 | | - #"canadian" build doesn't handle that, so install it explicitly |
| 295 | + #"canadian" build doesn't handle that(?), so install it explicitly |
179 | 296 | PATH=$NEWPATH make configure-target-libgcc |
180 | 297 | PATH=$NEWPATH make -C $WIN32_TARGET_ARCH/libgcc $JOBS |
181 | 298 | PATH=$NEWPATH make -C $WIN32_TARGET_ARCH/libgcc $JOBS install |
|
0 commit comments