1#!/bin/bash
2set -x -e -v
3
4# This script is for building a mingw-clang toolchain for use on Linux.
5
6if [[ $# -eq 0 ]]; then
7    echo "Provide either x86 or x64 to specify a toolchain."
8    exit 1;
9elif [ "$1" == "x86" ]; then
10  machine="i686"
11  compiler_rt_machine="i386"
12  crt_flags="--enable-lib32 --disable-lib64"
13  WRAPPER_FLAGS=""
14elif [ "$1" == "x64" ]; then
15  machine="x86_64"
16  compiler_rt_machine="x86_64"
17  crt_flags="--disable-lib32 --enable-lib64"
18  WRAPPER_FLAGS=""
19else
20  echo "Provide either x86 or x64 to specify a toolchain."
21  exit 1;
22fi
23
24TOOLCHAIN_DIR=$MOZ_FETCHES_DIR/llvm-project
25INSTALL_DIR=$TOOLCHAIN_DIR/build/stage4/clang
26CROSS_PREFIX_DIR=$INSTALL_DIR/$machine-w64-mingw32
27
28make_flags="-j$(nproc)"
29
30if [ -d "$MOZ_FETCHES_DIR/binutils/bin" ]; then
31  export PATH="$MOZ_FETCHES_DIR/binutils/bin:$PATH"
32fi
33
34# This is default value of _WIN32_WINNT. Gecko configure script explicitly sets this,
35# so this is not used to build Gecko itself. We default to 0x601, which is Windows 7.
36default_win32_winnt=0x601
37
38cd $GECKO_PATH
39
40patch_file1="$(pwd)/taskcluster/scripts/misc/mingw-winrt.patch"
41patch_file2="$(pwd)/taskcluster/scripts/misc/mingw-dwrite_3.patch"
42patch_file3="$(pwd)/taskcluster/scripts/misc/mingw-unknown.patch"
43
44prepare() {
45  pushd $MOZ_FETCHES_DIR/mingw-w64
46  patch -p1 <$patch_file1
47  patch -p1 <$patch_file2
48  patch -p1 <$patch_file3
49  popd
50}
51
52install_wrappers() {
53  pushd $INSTALL_DIR/bin
54
55  compiler_flags="--sysroot \$DIR/../$machine-w64-mingw32 -rtlib=compiler-rt -stdlib=libc++ -fuse-ld=lld $WRAPPER_FLAGS -fuse-cxa-atexit -Qunused-arguments"
56
57  cat <<EOF >$machine-w64-mingw32-clang
58#!/bin/sh
59DIR="\$(cd "\$(dirname "\$0")" && pwd)"
60\$DIR/clang -target $machine-w64-mingw32 $compiler_flags "\$@"
61EOF
62  chmod +x $machine-w64-mingw32-clang
63
64  cat <<EOF >$machine-w64-mingw32-clang++
65#!/bin/sh
66DIR="\$(cd "\$(dirname "\$0")" && pwd)"
67\$DIR/clang -target $machine-w64-mingw32 --driver-mode=g++ $compiler_flags "\$@"
68EOF
69  chmod +x $machine-w64-mingw32-clang++
70
71  CC="$machine-w64-mingw32-clang"
72  CXX="$machine-w64-mingw32-clang++"
73
74  popd
75}
76
77build_mingw() {
78  mkdir mingw-w64-headers
79  pushd mingw-w64-headers
80  $MOZ_FETCHES_DIR/mingw-w64/mingw-w64-headers/configure \
81    --host=$machine-w64-mingw32 \
82    --enable-sdk=all \
83    --enable-idl \
84    --with-default-msvcrt=ucrt \
85    --with-default-win32-winnt=$default_win32_winnt \
86    --prefix=$CROSS_PREFIX_DIR
87  make $make_flags install
88  popd
89
90  mkdir mingw-w64-crt
91  pushd mingw-w64-crt
92  $MOZ_FETCHES_DIR/mingw-w64/mingw-w64-crt/configure \
93    --host=$machine-w64-mingw32 \
94    $crt_flags \
95    --with-default-msvcrt=ucrt \
96    CC="$CC" \
97    AR=llvm-ar \
98    RANLIB=llvm-ranlib \
99    DLLTOOL=llvm-dlltool \
100    --prefix=$CROSS_PREFIX_DIR
101  make $make_flags
102  make $make_flags install
103  popd
104
105  mkdir widl
106  pushd widl
107  $MOZ_FETCHES_DIR/mingw-w64/mingw-w64-tools/widl/configure --target=$machine-w64-mingw32 --prefix=$INSTALL_DIR
108  make $make_flags
109  make $make_flags install
110  popd
111}
112
113build_compiler_rt() {
114  CLANG_VERSION=$(basename $(dirname $(dirname $(dirname $($CC --print-libgcc-file-name -rtlib=compiler-rt)))))
115  mkdir compiler-rt
116  pushd compiler-rt
117  cmake \
118      -DCMAKE_BUILD_TYPE=Release \
119      -DCMAKE_C_COMPILER=$CC \
120      -DCMAKE_SYSTEM_NAME=Windows \
121      -DCMAKE_AR=$INSTALL_DIR/bin/llvm-ar \
122      -DCMAKE_RANLIB=$INSTALL_DIR/bin/llvm-ranlib \
123      -DCMAKE_C_COMPILER_WORKS=1 \
124      -DCMAKE_C_COMPILER_TARGET=$compiler_rt_machine-windows-gnu \
125      -DCOMPILER_RT_DEFAULT_TARGET_ONLY=TRUE \
126      $TOOLCHAIN_DIR/compiler-rt/lib/builtins
127  make $make_flags
128  mkdir -p $INSTALL_DIR/lib/clang/$CLANG_VERSION/lib/windows
129  cp lib/windows/libclang_rt.builtins-$compiler_rt_machine.a $INSTALL_DIR/lib/clang/$CLANG_VERSION/lib/windows/
130  popd
131}
132
133merge_libs() {
134  cat <<EOF |llvm-ar -M
135CREATE tmp.a
136ADDLIB $1
137ADDLIB $2
138SAVE
139END
140EOF
141  llvm-ranlib tmp.a
142  mv tmp.a $1
143}
144
145build_libcxx() {
146  # Below, we specify -g -gcodeview to build static libraries with debug information.
147  # Because we're not distributing these builds, this is fine. If one were to distribute
148  # the builds, perhaps one would want to make those flags conditional or investigation
149  # other options.
150  DEBUG_FLAGS="-g -gcodeview"
151
152  mkdir libunwind
153  pushd libunwind
154  cmake \
155      -DCMAKE_BUILD_TYPE=Release \
156      -DCMAKE_INSTALL_PREFIX=$CROSS_PREFIX_DIR \
157      -DCMAKE_C_COMPILER=$CC \
158      -DCMAKE_CXX_COMPILER=$CXX \
159      -DCMAKE_CROSSCOMPILING=TRUE \
160      -DCMAKE_SYSROOT=$CROSS_PREFIX_DIR \
161      -DCMAKE_SYSTEM_NAME=Windows \
162      -DCMAKE_C_COMPILER_WORKS=TRUE \
163      -DCMAKE_CXX_COMPILER_WORKS=TRUE \
164      -DLLVM_COMPILER_CHECKED=TRUE \
165      -DCMAKE_AR=$INSTALL_DIR/bin/llvm-ar \
166      -DCMAKE_RANLIB=$INSTALL_DIR/bin/llvm-ranlib \
167      -DLLVM_NO_OLD_LIBSTDCXX=TRUE \
168      -DCXX_SUPPORTS_CXX11=TRUE \
169      -DCXX_SUPPORTS_CXX_STD=TRUE \
170      -DLIBUNWIND_USE_COMPILER_RT=TRUE \
171      -DLIBUNWIND_ENABLE_THREADS=TRUE \
172      -DLIBUNWIND_ENABLE_SHARED=FALSE \
173      -DLIBUNWIND_ENABLE_CROSS_UNWINDING=FALSE \
174      -DCMAKE_CXX_FLAGS="${DEBUG_FLAGS} -Wno-dll-attribute-on-redeclaration -nostdinc++ -I$TOOLCHAIN_DIR/libcxx/include -DPSAPI_VERSION=2" \
175      -DCMAKE_C_FLAGS="-Wno-dll-attribute-on-redeclaration" \
176      $MOZ_FETCHES_DIR/libunwind
177  make $make_flags
178  make $make_flags install
179  popd
180
181  mkdir libcxxabi
182  pushd libcxxabi
183  cmake \
184      -DCMAKE_BUILD_TYPE=Release \
185      -DCMAKE_INSTALL_PREFIX=$CROSS_PREFIX_DIR \
186      -DCMAKE_C_COMPILER=$CC \
187      -DCMAKE_CXX_COMPILER=$CXX \
188      -DCMAKE_CROSSCOMPILING=TRUE \
189      -DCMAKE_SYSTEM_NAME=Windows \
190      -DCMAKE_C_COMPILER_WORKS=TRUE \
191      -DCMAKE_CXX_COMPILER_WORKS=TRUE \
192      -DCMAKE_SYSROOT=$CROSS_PREFIX_DIR \
193      -DLLVM_COMPILER_CHECKED=TRUE \
194      -DCMAKE_AR=$INSTALL_DIR/bin/llvm-ar \
195      -DCMAKE_RANLIB=$INSTALL_DIR/bin/llvm-ranlib \
196      -DLIBCXXABI_USE_COMPILER_RT=ON \
197      -DLIBCXXABI_ENABLE_EXCEPTIONS=ON \
198      -DLIBCXXABI_ENABLE_THREADS=ON \
199      -DLIBCXXABI_TARGET_TRIPLE=$machine-w64-mingw32 \
200      -DLIBCXXABI_ENABLE_SHARED=OFF \
201      -DLIBCXXABI_LIBCXX_INCLUDES=$TOOLCHAIN_DIR/libcxx/include \
202      -DLLVM_NO_OLD_LIBSTDCXX=TRUE \
203      -DCXX_SUPPORTS_CXX11=TRUE \
204      -DCXX_SUPPORTS_CXX_STD=TRUE \
205      -DCMAKE_CXX_FLAGS="${DEBUG_FLAGS} -D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS -D_LIBCPP_HAS_THREAD_API_WIN32" \
206      $TOOLCHAIN_DIR/libcxxabi
207  make $make_flags VERBOSE=1
208  popd
209
210  mkdir libcxx
211  pushd libcxx
212  cmake \
213      -DCMAKE_BUILD_TYPE=Release \
214      -DCMAKE_INSTALL_PREFIX=$CROSS_PREFIX_DIR \
215      -DCMAKE_C_COMPILER=$CC \
216      -DCMAKE_CXX_COMPILER=$CXX \
217      -DCMAKE_CROSSCOMPILING=TRUE \
218      -DCMAKE_SYSTEM_NAME=Windows \
219      -DCMAKE_C_COMPILER_WORKS=TRUE \
220      -DCMAKE_CXX_COMPILER_WORKS=TRUE \
221      -DLLVM_COMPILER_CHECKED=TRUE \
222      -DCMAKE_AR=$INSTALL_DIR/bin/llvm-ar \
223      -DCMAKE_RANLIB=$INSTALL_DIR/bin/llvm-ranlib \
224      -DLIBCXX_USE_COMPILER_RT=ON \
225      -DLIBCXX_INSTALL_HEADERS=ON \
226      -DLIBCXX_ENABLE_EXCEPTIONS=ON \
227      -DLIBCXX_ENABLE_THREADS=ON \
228      -DLIBCXX_HAS_WIN32_THREAD_API=ON \
229      -DLIBCXX_ENABLE_MONOTONIC_CLOCK=ON \
230      -DLIBCXX_ENABLE_SHARED=OFF \
231      -DLIBCXX_SUPPORTS_STD_EQ_CXX11_FLAG=TRUE \
232      -DLIBCXX_HAVE_CXX_ATOMICS_WITHOUT_LIB=TRUE \
233      -DLIBCXX_ENABLE_EXPERIMENTAL_LIBRARY=OFF \
234      -DLIBCXX_ENABLE_FILESYSTEM=OFF \
235      -DLIBCXX_ENABLE_STATIC_ABI_LIBRARY=TRUE \
236      -DLIBCXX_CXX_ABI=libcxxabi \
237      -DLIBCXX_CXX_ABI_INCLUDE_PATHS=$TOOLCHAIN_DIR/libcxxabi/include \
238      -DLIBCXX_CXX_ABI_LIBRARY_PATH=../libcxxabi/lib \
239      -DCMAKE_CXX_FLAGS="${DEBUG_FLAGS} -D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS" \
240      $TOOLCHAIN_DIR/libcxx
241  make $make_flags VERBOSE=1
242  make $make_flags install
243
244  # libc++.a depends on libunwind.a. Whild linker will automatically link
245  # to libc++.a in C++ mode, it won't pick libunwind.a, requiring caller
246  # to explicitly pass -lunwind. Wo work around that, we merge libunwind.a
247  # into libc++.a.
248  merge_libs $CROSS_PREFIX_DIR/lib/libc++.a $CROSS_PREFIX_DIR/lib/libunwind.a
249  popd
250}
251
252build_libssp() {
253  pushd $MOZ_FETCHES_DIR/gcc-source/
254
255  # Massage the environment for the build-libssp.sh script
256  mkdir -p ./$machine-w64-mingw32/lib
257  cp $MOZ_FETCHES_DIR/llvm-mingw/libssp-Makefile .
258  sed -i 's/set -e/set -x -e -v/' $MOZ_FETCHES_DIR/llvm-mingw/build-libssp.sh
259  sed -i 's/(CROSS)gcc/(CROSS)clang/' libssp-Makefile
260  sed -i 's/\$(CROSS)ar/llvm-ar/' libssp-Makefile
261  OLDPATH=$PATH
262  PATH=$INSTALL_DIR/clang/bin:$PATH
263
264  # Run the script
265  TOOLCHAIN_ARCHS=$machine $MOZ_FETCHES_DIR/llvm-mingw/build-libssp.sh .
266
267  # Grab the artifacts, cleanup
268  cp $MOZ_FETCHES_DIR/gcc-source/$machine-w64-mingw32/lib/{libssp.a,libssp_nonshared.a} $INSTALL_DIR/$machine-w64-mingw32/lib/
269  unset TOOLCHAIN_ARCHS
270  PATH=$OLDPATH
271  popd
272}
273
274build_utils() {
275  pushd $INSTALL_DIR/bin/
276  ln -s llvm-nm $machine-w64-mingw32-nm
277  ln -s llvm-strip $machine-w64-mingw32-strip
278  ln -s llvm-readobj $machine-w64-mingw32-readobj
279  ln -s llvm-objcopy $machine-w64-mingw32-objcopy
280  ./clang $MOZ_FETCHES_DIR/llvm-mingw/wrappers/windres-wrapper.c -O2 -Wl,-s -o $machine-w64-mingw32-windres
281  popd
282}
283
284export PATH=$INSTALL_DIR/bin:$PATH
285
286prepare
287
288# gets a bit too verbose here
289set +x
290
291cd $TOOLCHAIN_DIR
292python3 $GECKO_PATH/build/build-clang/build-clang.py -c $GECKO_PATH/$2 --skip-tar
293
294set -x
295
296pushd $TOOLCHAIN_DIR/build
297
298install_wrappers
299build_mingw
300build_compiler_rt
301build_libcxx
302build_libssp
303build_utils
304
305popd
306
307# Put a tarball in the artifacts dir
308mkdir -p $UPLOAD_DIR
309
310pushd $(dirname $INSTALL_DIR)
311tar caf clangmingw.tar.zst clang
312mv clangmingw.tar.zst $UPLOAD_DIR
313popd
314