]> wimlib.net Git - wimlib/blob - tools/windows-build.sh
mount_image.c: add fallback definitions of RENAME_* constants
[wimlib] / tools / windows-build.sh
1 #!/bin/bash
2 #
3 # This script builds wimlib for Windows.  It supports both MSYS2 and Linux.
4
5 set -e -u
6
7 SCRIPTNAME="$0"
8 TOPDIR=$(dirname "$(dirname "$(realpath "$0")")")
9 cd "$TOPDIR" # Top-level directory of the git repo
10
11 # Global variables, read-only after parse_options has run
12 ARCH=
13 CC_PKG=
14 DESTDIR=
15 EXTRA_CONFIGURE_ARGS=
16 INCLUDE_DOCS=false
17 INSTALL_PREREQUISITES=false
18 MAKE="make -j$(getconf _NPROCESSORS_ONLN)"
19 MSYSTEM=${MSYSTEM:-}
20 SKIP_CONFIGURE=false
21 VERSION=$(tools/get-version-number.sh)
22 ZIP=false
23 ZIPFILE=
24
25 PREBUILT_LLVM_MINGW_ENABLED=false
26 PREBUILT_LLVM_MINGW_URL=https://github.com/mstorsjo/llvm-mingw/releases/download/20230320/llvm-mingw-20230320-msvcrt-x86_64.zip
27 PREBUILT_LLVM_MINGW_ZIP=$(basename "$PREBUILT_LLVM_MINGW_URL")
28 PREBUILT_LLVM_MINGW=${PREBUILT_LLVM_MINGW_ZIP%.zip}
29 PREBUILT_LLVM_MINGW_BIN="/$PREBUILT_LLVM_MINGW/bin"
30
31 usage()
32 {
33         cat << EOF
34 Usage: $SCRIPTNAME [OPTION]... [EXTRA_CONFIGURE_ARG]...
35 Options:
36   --arch=ARCH               Specify the CPU architecture.  This is unnecessary
37                             when using MSYS2.
38
39   --include-docs            Build and install the PDF manual pages.
40
41   --install-prerequisites   Install the prerequisite packages needed to build
42                             wimlib.  This is only supported in MSYS2.  You can
43                             omit this if you have already done this for the same
44                             MSYS2 environment.  This option normally only
45                             installs MSYS2 packages, but for ARM64 cross-builds
46                             it also installs a separate prebuilt toolchain.
47
48   --skip-configure          Skip running the configure script again.  You can
49                             use this to save time in incremental builds if you
50                             are sure you didn't change any options.
51
52   --zip                     Zip the output files up into a zip file.
53 EOF
54 }
55
56 parse_options()
57 {
58         case "$MSYSTEM" in
59         "")
60                 ARCH=x86_64
61                 ;;
62         MINGW32)
63                 ARCH=i686
64                 CC_PKG=mingw-w64-i686-gcc
65                 ;;
66         MINGW64)
67                 ARCH=x86_64
68                 CC_PKG=mingw-w64-x86_64-gcc
69                 ;;
70         CLANG32)
71                 ARCH=i686
72                 CC_PKG=mingw-w64-clang-i686-clang
73                 ;;
74         CLANG64)
75                 ARCH=x86_64
76                 CC_PKG=mingw-w64-clang-x86_64-clang
77                 ;;
78         CLANGARM64)
79                 ARCH=aarch64
80                 # MSYS2 doesn't yet support cross-compiling for ARM64, so use a
81                 # separate prebuilt toolchain for that case.
82                 if [ "$(uname -m)" = x86_64 ]; then
83                         PREBUILT_LLVM_MINGW_ENABLED=true
84                         export PATH="$PREBUILT_LLVM_MINGW_BIN:$PATH"
85                 else
86                         CC_PKG=mingw-w64-clang-aarch64-clang
87                 fi
88                 ;;
89         *)
90                 echo 1>&2 "Unsupported MSYS2 environment: $MSYSTEM.  This script supports"
91                 echo 1>&2 "MINGW32, MINGW64, CLANG32, CLANG64, and CLANGARM64."
92                 echo 1>&2 "See https://www.msys2.org/docs/environments/"
93                 exit 1
94         esac
95
96         local longopts="help"
97         longopts+=",arch:"
98         longopts+=",include-docs"
99         longopts+=",install-prerequisites"
100         longopts+=",skip-configure"
101         longopts+=",zip"
102
103         local options
104         if ! options=$(getopt -o "" -l "$longopts" -- "$@"); then
105                 usage 1>&2
106                 exit 1
107         fi
108         eval set -- "$options"
109         while true; do
110                 case "$1" in
111                 --help)
112                         usage
113                         exit 0
114                         ;;
115                 --arch)
116                         ARCH=$2
117                         shift
118                         ;;
119                 --include-docs)
120                         INCLUDE_DOCS=true
121                         ;;
122                 --install-prerequisites)
123                         if [ -z "$MSYSTEM" ]; then
124                                 echo 1>&2 "--install-prerequisites is only supported in MSYS2."
125                                 exit 1
126                         fi
127                         INSTALL_PREREQUISITES=true
128                         ;;
129                 --skip-configure)
130                         SKIP_CONFIGURE=true
131                         ;;
132                 --zip)
133                         ZIP=true
134                         ;;
135                 --)
136                         shift
137                         break
138                         ;;
139                 *)
140                         echo 1>&2 "Invalid option '$1'"
141                         usage 1>&2
142                         exit 1
143                         ;;
144                 esac
145                 shift
146         done
147         case "$ARCH" in
148         i686|x86_64|aarch64)
149                 ;;
150         *)
151                 echo 1>&2 "Unknown ARCH: $ARCH.  Please specify a supported architecture with --arch"
152                 exit 1
153                 ;;
154         esac
155         DESTDIR=wimlib-${VERSION}-windows-${ARCH}-bin
156         ZIPFILE=$DESTDIR.zip
157         EXTRA_CONFIGURE_ARGS=("$@")
158 }
159
160 install_prebuilt_llvm_mingw()
161 {
162         if [ -e "$PREBUILT_LLVM_MINGW_BIN" ]; then
163                 echo "Prebuilt $PREBUILT_LLVM_MINGW is already installed"
164                 return
165         fi
166         echo "Downloading $PREBUILT_LLVM_MINGW_ZIP..."
167         wget "$PREBUILT_LLVM_MINGW_URL" -O "/$PREBUILT_LLVM_MINGW_ZIP"
168         echo "Unzipping $PREBUILT_LLVM_MINGW_ZIP..."
169         unzip "/$PREBUILT_LLVM_MINGW_ZIP" -d /
170         if [ ! -e "$PREBUILT_LLVM_MINGW_BIN" ]; then
171                 echo 1>&2 "$PREBUILT_LLVM_MINGW_BIN not found after unzip"
172                 exit 1
173         fi
174         echo "Done installing prebuilt toolchain $PREBUILT_LLVM_MINGW"
175 }
176
177 install_prerequisites()
178 {
179         echo "Installing the MSYS2 $MSYSTEM packages needed to build wimlib..."
180         local packages=(autoconf automake git libtool make pkgconf)
181         if "$PREBUILT_LLVM_MINGW_ENABLED"; then
182                 echo "Will use prebuilt toolchain instead of MSYS2 one"
183                 packages+=(wget unzip)
184         else
185                 packages+=("$CC_PKG")
186         fi
187         pacman -Syu --noconfirm --needed "${packages[@]}"
188         echo "Done installing the MSYS2 $MSYSTEM packages needed to build wimlib."
189
190         if $PREBUILT_LLVM_MINGW_ENABLED; then
191                 install_prebuilt_llvm_mingw
192         fi
193 }
194
195 bootstrap_repository()
196 {
197         echo "Bootstrapping the wimlib repository..."
198         ./bootstrap
199 }
200
201 configure_wimlib()
202 {
203         echo "Configuring wimlib..."
204         local configure_args=("--host=${ARCH}-w64-mingw32")
205         configure_args+=("--disable-static")
206         # -static-libgcc is needed with gcc.  It should go in the CFLAGS, but
207         # libtool strips it, so it must go directly in CC instead.  See
208         # https://www.gnu.org/software/libtool/manual/libtool.html#Stripped-link-flags
209         local cc="${ARCH}-w64-mingw32-cc"
210         if ! type -P "$cc" &>/dev/null; then
211                 cc="${ARCH}-w64-mingw32-gcc"
212         fi
213         if ! type -P "$cc" &>/dev/null; then
214                 echo 1>&2 "ERROR: $cc not found!"
215                 if [ -n "$MSYSTEM" ]; then
216                         echo 1>&2 "Consider using --install-prerequisites"
217                 fi
218                 exit 1
219         fi
220         if ! "$cc" --version | grep -q -i 'clang'; then
221                 configure_args+=("CC=$cc -static-libgcc")
222         fi
223         configure_args+=("${EXTRA_CONFIGURE_ARGS[@]}")
224         ./configure "${configure_args[@]}"
225         $MAKE clean
226 }
227
228 build_wimlib()
229 {
230         echo "Building wimlib..."
231         $MAKE
232 }
233
234 list_imagex_commands()
235 {
236         for cmd in ./doc/man1/wim*.1; do
237                 local cmd=${cmd##*/}
238                 cmd=${cmd%.1}
239                 case "$cmd" in
240                 wimlib-imagex|wimmount|wimmountrw|wimunmount)
241                         ;;
242                 *)
243                         echo "$cmd"
244                         ;;
245                 esac
246         done
247 }
248
249 install_binaries()
250 {
251         echo "Installing binaries..."
252         cp .libs/*.{dll,exe} "$DESTDIR"
253         strip "$DESTDIR"/*.{dll,exe}
254 }
255
256 install_text_files()
257 {
258         echo "Installing NEWS, README, and licenses..."
259         cp NEWS* README* COPYING* "$DESTDIR"
260         sed -n '/^#/q; s/^[\/\* ]*//; p' src/divsufsort.c > "$DESTDIR"/COPYING.libdivsufsort-lite
261         if ! grep -q 'Copyright' "$DESTDIR"/COPYING.libdivsufsort-lite; then
262                 echo 1>&2 "ERROR: failed to extract libdivsufsort-lite license text"
263                 exit 1
264         fi
265         cd "$DESTDIR"
266         for fil in NEWS* README* COPYING*; do
267                 sed < "$fil" > "${fil%.md}".txt -e 's/$/\r/g'
268                 rm "$fil"
269         done
270         cd ..
271 }
272
273 gen_pdf_from_man_page()
274 {
275         local cmd=$1
276         local pdf=${DESTDIR}/doc/${cmd}.pdf
277
278         echo "Generating $pdf"
279         MANPATH="./doc" man -t "$cmd" | ps2pdf - "$pdf"
280 }
281
282 install_pdf_docs()
283 {
284         echo "Installing PDF manual pages..."
285         mkdir "$DESTDIR"/doc
286         for cmd in $(list_imagex_commands); do
287                 gen_pdf_from_man_page "$cmd"
288         done
289         gen_pdf_from_man_page wimlib-imagex
290 }
291
292 install_cmd_aliases()
293 {
294         echo "Installing wim*.cmd files..."
295         for cmd in $(list_imagex_commands); do
296                 sed 's/$/\r/g' > "${DESTDIR}/${cmd}.cmd" <<- EOF
297                         @echo off
298                         "%~dp0\\wimlib-imagex" ${cmd#wim} %*
299                 EOF
300                 chmod +x "${DESTDIR}/${cmd}.cmd"
301         done
302 }
303
304 install_development_files()
305 {
306         echo "Installing development files..."
307         mkdir "$DESTDIR"/devel
308         cp .libs/libwim.dll.a "$DESTDIR"/devel/libwim.lib
309         cp include/wimlib.h "$DESTDIR"/devel/
310 }
311
312 create_zip_file()
313 {
314         echo "Creating zip file..."
315         cd "$DESTDIR"
316         7z -mx9 a ../"$ZIPFILE" . > /dev/null
317         cd ..
318 }
319
320 parse_options "$@"
321 rm -rf -- "$DESTDIR" "$ZIPFILE"
322 mkdir -- "$DESTDIR"
323 if $INSTALL_PREREQUISITES; then
324         install_prerequisites
325 fi
326 if [ ! -e configure ]; then
327         bootstrap_repository
328 fi
329 if [ ! -e config.log ] || ! $SKIP_CONFIGURE; then
330         configure_wimlib
331 fi
332 build_wimlib
333 install_binaries
334 install_text_files
335 if $INCLUDE_DOCS; then
336         install_pdf_docs
337 fi
338 install_cmd_aliases
339 install_development_files
340 if $ZIP; then
341         create_zip_file
342         echo "Success!  Output is in $ZIPFILE"
343 else
344         echo "Success!  Output is in $DESTDIR"
345 fi