|
| 1 | +--- |
| 2 | +layout: posts |
| 3 | +title: Building GCC / GNU Toolchain for Windows |
| 4 | +author: James Walmsley |
| 5 | + |
| 6 | +category: misc |
| 7 | +--- |
| 8 | + |
| 9 | +I've been trying to sucessfully compile GCC for Windows to allow me to maintain a Windows version of the BTDK |
| 10 | +(BitThunder development kit). Well the documentation on the internet describing how to do this is thin and far between. |
| 11 | +The good news is that I've finally managed to create one. |
| 12 | + |
| 13 | +# Strategies |
| 14 | +Most guides talk about setting up MSYS and MinGW or cygwin or some other native Windows build environment. I explicitly do NOT |
| 15 | +recommend this approach. Its extremely slow and tedious, you will simply waste months of your life! |
| 16 | + |
| 17 | +The approach I eventually settled for is to cross-compile for Windows on Linux (Ubuntu 14.10). To do this I use the excellent MXE |
| 18 | +cross compile environment. |
| 19 | + |
| 20 | +The build involves the following steps: |
| 21 | + |
| 22 | +1. Clone and build MXE. |
| 23 | +2. Configure build environment. |
| 24 | +3. Clone and build binutils-gdb |
| 25 | +4. Download and build libgmp (4.3.2) |
| 26 | +5. Download and build libmpfr (2.4.2) |
| 27 | +6. Download and build libmpc (0.8.1) |
| 28 | +7. Clone and build gcc (stage 1). |
| 29 | +8. Clone and build newlib. |
| 30 | +9. Clone build gcc (final stage). |
| 31 | + |
| 32 | +## 1. Get and Install MXE |
| 33 | + |
| 34 | +{% highlight bash %} |
| 35 | +git clone git://github.com/mxe/mxe.git |
| 36 | +cd mxe |
| 37 | +git checkout stable |
| 38 | +make |
| 39 | +{% endhighlight %} |
| 40 | + |
| 41 | +Now wait for a really long time... You don't actually need the whole environment to be built, but it will come in useful. |
| 42 | + |
| 43 | +## 2. Build Variables & Environment |
| 44 | + |
| 45 | + PATH : Path must include the mxe binary path: |
| 46 | +{% highlight bash %} |
| 47 | +export PATH=/path/to/mxe/usr/bin:$PATH |
| 48 | +{% endhighlight %} |
| 49 | + |
| 50 | + TARGET : This is the target type, e.g. arm-unknown-eabi or arm-eabi-bt |
| 51 | + PREFIX : Where the toolchain will reside on the system. E.g. /opt/btdk |
| 52 | + HOST : The type of system that will host the compiler (Windows in our case). |
| 53 | + BUILD : The type of system that is being used to build the toolchain. |
| 54 | + PKGVERSION : A toolchain package name/version. |
| 55 | + |
| 56 | + BTDK uses the following defaults: |
| 57 | + |
| 58 | +{% highlight bash %} |
| 59 | +export TARGET=arm-unknown-eabi |
| 60 | +export PREFIX=/opt/mytoolchain |
| 61 | +export HOST=i686-pc-mingw32 |
| 62 | +export BUILD="$(config.guess)" |
| 63 | +export PKGVERSION="mytoolchain v1.0.0" |
| 64 | +{% endhighlight %} |
| 65 | + |
| 66 | +## 3. Building Binutils (ld gas nm gdb etc) |
| 67 | + |
| 68 | +{% highlight bash %} |
| 69 | +git clone git://sourceware.org/git/binutils-gdb.git |
| 70 | +mkdir build-binutils |
| 71 | +cd build-binutils |
| 72 | +../binutils-gdb/configure --host=${HOST} --build=${BUILD} --target=${TARGET} \ |
| 73 | + --prefix=${PREFIX} --enable-interwork --enable-multilib \ |
| 74 | + --enable-target-optspace --with-float=soft --disable-werror \ |
| 75 | + --with-pkgversion=${PKGVERSION} |
| 76 | +make |
| 77 | +sudo make install |
| 78 | +{% endhighlight %} |
| 79 | + |
| 80 | +### Patch / Fix for Binutils |
| 81 | +Currently the build tree contains a fix for compiling for windows, but MXE is good enough not to need it. |
| 82 | +If the build complains something like: |
| 83 | + |
| 84 | +{% highlight bash %} |
| 85 | +mxe/usr/lib/gcc/i686-pc-mingw32/4.8.1/../../../../i686-pc-mingw32/lib/libncurses.a(lib_tputs.o):lib_tputs.c:(.text+0x780): multiple definition of `tputs' |
| 86 | +windows-termcap.o:mytoolchain/binutils-gdb/gdb/windows-termcap.c:62: first defined here |
| 87 | +{% endhighlight %} |
| 88 | + |
| 89 | +The simply open the file gdb/windows-termcap.c |
| 90 | + |
| 91 | +Comment out the tputs() function, or apply the following patch: |
| 92 | + |
| 93 | +{% highlight bash %} |
| 94 | +diff --git a/gdb/windows-termcap.c b/gdb/windows-termcap.c |
| 95 | +index 7c258cf..e7d5fa3 100644 |
| 96 | +--- a/gdb/windows-termcap.c |
| 97 | ++++ b/gdb/windows-termcap.c |
| 98 | +@@ -57,14 +57,14 @@ tgetstr (char *name, char **area) |
| 99 | + return NULL; |
| 100 | + } |
| 101 | + |
| 102 | +-int |
| 103 | ++/*int |
| 104 | + tputs (char *string, int nlines, int (*outfun) ()) |
| 105 | + { |
| 106 | + while (*string) |
| 107 | + outfun (*string++); |
| 108 | + |
| 109 | + return 0; |
| 110 | +-} |
| 111 | ++}*/ |
| 112 | + |
| 113 | + char * |
| 114 | + tgoto (const char *cap, int col, int row) |
| 115 | +{% endhighlight %} |
| 116 | + |
| 117 | +You can apply it by saving it into a .patch file and ... |
| 118 | + |
| 119 | +{% highlight bash %} |
| 120 | +cd ../binutils-gdb |
| 121 | +git apply binutils.patch |
| 122 | +cd ../build-binutils |
| 123 | +make |
| 124 | +sudo make install |
| 125 | +{% endhighlight %} |
| 126 | + |
| 127 | +There's also a problem with the install target, of binutils it cannot find the ranlib tool for some reason. You can fix this with the following patch: |
| 128 | + |
| 129 | +{% highlight bash %} |
| 130 | +# Obviously adjust the path to your actual mxe ranlib binary :D |
| 131 | +sed -i 's:i686-pc-mingw32-ranlib:/home/wl/develop/tools/mxe/usr/bin/i686-pc-mingw32-ranlib:g' Makefile sim/Makefile sim/arm/Makefile |
| 132 | +sudo make install |
| 133 | +{% endhighlight %} |
| 134 | + |
| 135 | +You should now have a full gdb and binutils for windows: |
| 136 | + |
| 137 | +{% highlight bash %} |
| 138 | +tree ${PREFIX}/bin/ |
| 139 | +/opt/mytoolchain/bin/ |
| 140 | +├── arm-unknown-eabi-addr2line.exe |
| 141 | +├── arm-unknown-eabi-ar.exe |
| 142 | +├── arm-unknown-eabi-as.exe |
| 143 | +├── arm-unknown-eabi-c++filt.exe |
| 144 | +├── arm-unknown-eabi-elfedit.exe |
| 145 | +├── arm-unknown-eabi-gdb.exe |
| 146 | +├── arm-unknown-eabi-gprof.exe |
| 147 | +├── arm-unknown-eabi-ld.bfd.exe |
| 148 | +├── arm-unknown-eabi-ld.exe |
| 149 | +├── arm-unknown-eabi-nm.exe |
| 150 | +├── arm-unknown-eabi-objcopy.exe |
| 151 | +├── arm-unknown-eabi-objdump.exe |
| 152 | +├── arm-unknown-eabi-ranlib.exe |
| 153 | +├── arm-unknown-eabi-readelf.exe |
| 154 | +├── arm-unknown-eabi-run.exe |
| 155 | +├── arm-unknown-eabi-size.exe |
| 156 | +├── arm-unknown-eabi-strings.exe |
| 157 | +└── arm-unknown-eabi-strip.exe |
| 158 | + |
| 159 | +0 directories, 18 files |
| 160 | +{% endhighlight %} |
| 161 | + |
| 162 | +## 4. Build libgmp |
| 163 | +Yup building these libraries is boring, but its probably the safest option in the long run |
| 164 | +(trust me I wasted hours of my life trying to make this all link with pre-compiled versions in mingw32, mxe is probably better |
| 165 | +but lets just use my working method :D ) |
| 166 | + |
| 167 | +{% highlight bash %} |
| 168 | +wget https://gmplib.org/download/gmp/gmp-4.3.2.tar.bz2 |
| 169 | +tar xvf gmp-4.3.2.tar.bz2 |
| 170 | +mkdir build-gmp |
| 171 | +cd build-gmp |
| 172 | +../gmp-4.3.2/configure --host=${HOST} --build=${BUILD} --prefix=$(pwd)/../libgmp \ |
| 173 | + --disable-shared --enable-static --without-readline --enable-cxx |
| 174 | +make |
| 175 | +# We install into ../libgmp/ so we don't need sudo. |
| 176 | +make install |
| 177 | +{% endhighlight %} |
| 178 | + |
| 179 | +## 5. Build libmpfr |
| 180 | + |
| 181 | +{% highlight bash %} |
| 182 | +wget https://ftp.gnu.org/gnu/mpfr/mpfr-2.4.2.tar.bz2 |
| 183 | +tar xvf mpfr-2.4.2.tar.bz2 |
| 184 | +mkdir build-mpfr |
| 185 | +cd build-mpfr |
| 186 | +../mpfr-2.4.2/configure --host=${HOST} --build=${BUILD} --prefix=$(pwd)/../libmpfr \ |
| 187 | + --with-gmp=$(pwd)/../libgmp --disable-shared --enable-static |
| 188 | +make |
| 189 | +make check |
| 190 | +make install |
| 191 | +{% endhighlight %} |
| 192 | + |
| 193 | +## 6. Build libmpc |
| 194 | +{% highlight bash %} |
| 195 | +wget http://www.multiprecision.org/mpc/download/mpc-0.8.1.tar.gz |
| 196 | +tar xvf mpc-0.8.1.tar.gz |
| 197 | +mkdir build-mpc |
| 198 | +cd build-mpc |
| 199 | +../mpc-0.8.1/configure --host=${HOST} --build=${BUILD} --prefix=$(pwd)/../libmpc \ |
| 200 | + --with-gmp=$(pwd)/../libgmp --with-mpfr=$(pwd)/../libmpfr \ |
| 201 | + --disable-shared --enable-static |
| 202 | +make |
| 203 | +make install |
| 204 | +{% endhighlight %} |
| 205 | + |
| 206 | +## 7. Build GCC - Stage 1 |
| 207 | + |
| 208 | +Building GCC for Windows is the most complex part of this cross-compile. |
| 209 | + |
| 210 | +{% highlight bash %} |
| 211 | +git clone git://gcc.gnu.org/git/gcc.git |
| 212 | +cd gcc |
| 213 | +git checkout gcc-4_9_0-release |
| 214 | +mkdir build-gcc |
| 215 | +cd build-gcc |
| 216 | +../gcc/configure --host=${HOST} --build=${BUILD} --target=${TARGET} --prefix=${PREFIX} \ |
| 217 | + --enable-interwork --enable-multilib --enable-languages="c" \ |
| 218 | + --with-newlib --without-headers --disable-shared --disable-libssp \ |
| 219 | + --with-gnu-as --with-gnu-ld --disable-nls \ |
| 220 | + --with-pkgversion=${PKGVERSION} --with-gmp=$(pwd)/../libgmp \ |
| 221 | + --with-mpfr=$(pwd)/../libmpfr --with-mpc=$(pwd)/../libmpc |
| 222 | +make all-gcc |
| 223 | +sudo make install-gcc |
| 224 | +#make all-target-libgcc # Cannot build using the Windows compiler in Wine on linux. |
| 225 | +#sudo make install-target-libgcc # Solution is to copy the libraries produced when building the toolchain for linux. |
| 226 | +{% endhighlight %} |
| 227 | + |
| 228 | +You'll find that at this point building libgcc and libstdc++ etc will actually fail. I finally realised that actually it doesn't matter |
| 229 | +from this point on. You don't actually need to compile anything further with the Windows toolchain at this point. |
| 230 | + |
| 231 | +Simply use the libraries as compiled by your native linux cross compiler, and copy them into your windows cross-compiler appropriately. |
| 232 | + |
| 233 | +### Fixes or Patches for GCC 4.9.0 |
| 234 | + |
| 235 | +Currently you'll probably get a cannot find arm-unknown-eabi-gcc error when the build system attempts to dump the compiler |
| 236 | +specs. To work around this, you can apply the following patch: |
| 237 | + |
| 238 | +{% highlight bash %} |
| 239 | +sed -i 's:$(GCC_FOR_TARGET) -dumpspecs > tmp-specs:./xgcc$(exeext) -dumpspecs > tmp-specs:g' gcc/Makefile |
| 240 | +make all-gcc |
| 241 | +sudo make install-gcc |
| 242 | +make all-target-libgcc |
| 243 | +sudo make install-target-libgcc |
| 244 | +{% endhighlight %} |
| 245 | + |
| 246 | +At this stage you should have a working cross-compiler. As long as you don't use any standard libraries at all, then you can |
| 247 | +build a working kernel. In fact you should be able to use such a compiler to build BitThunder. |
| 248 | + |
| 249 | +You can even use this compiler to build your own libc and then manually link with it. |
| 250 | + |
| 251 | +For most purposes a basic libc is useful, and its really convenient to use e.g. the BTDK which uses a ported version of |
| 252 | +newlib to provide a complete libc implementation on top of bitthunder. |
| 253 | + |
| 254 | +## 8. Build Newlib |
| 255 | + |
| 256 | +Again the secret is to simply copy the libraries produced by linux to the Windows toolchain folders. |
| 257 | + |
| 258 | +## 9. Finalise GCC. |
| 259 | + |
| 260 | +Not 100% sure what this stage does. I think it creates a arm-eabi-bt/bin/gcc.exe etc. In anycase I don't think they are needed, |
| 261 | +and you can always copy the bin/arm-eabi-bt-gcc.exe files to the appropriate place manually. |
| 262 | + |
0 commit comments