]> wimlib.net Git - wimlib/blob - tools/windows-build.sh
Rename make-windows-release to windows-build.sh
[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 DESTDIR=
14 EXTRA_CONFIGURE_ARGS=
15 INCLUDE_DOCS=false
16 INSTALL_PREREQUISITES=false
17 MAKE="make -j$(getconf _NPROCESSORS_ONLN)"
18 MSYSTEM=${MSYSTEM:-}
19 SKIP_CONFIGURE=false
20 VERSION=$(tools/get-version-number)
21 ZIP=false
22 ZIPFILE=
23
24 PREBUILT_LLVM_MINGW_ENABLED=false
25 PREBUILT_LLVM_MINGW_URL=https://github.com/mstorsjo/llvm-mingw/releases/download/20230320/llvm-mingw-20230320-msvcrt-x86_64.zip
26 PREBUILT_LLVM_MINGW_ZIP=$(basename "$PREBUILT_LLVM_MINGW_URL")
27 PREBUILT_LLVM_MINGW=${PREBUILT_LLVM_MINGW_ZIP%.zip}
28 PREBUILT_LLVM_MINGW_BIN="/$PREBUILT_LLVM_MINGW/bin"
29
30 usage()
31 {
32         cat << EOF
33 Usage: $SCRIPTNAME [OPTION]... [EXTRA_CONFIGURE_ARG]...
34 Options:
35   --arch=ARCH               Specify the CPU architecture.  This is unnecessary
36                             when using MSYS2.
37
38   --include-docs            Build and install the PDF manual pages.
39
40   --install-prerequisites   Install the prerequisite packages needed to build
41                             wimlib.  This is only supported in MSYS2.  You can
42                             omit this if you have already done this for the same
43                             MSYS2 environment.  This option normally only
44                             installs MSYS2 packages, but for ARM64 cross-builds
45                             it also installs a separate prebuilt toolchain.
46
47   --skip-configure          Skip running the configure script again.  You can
48                             use this to save time in incremental builds if you
49                             are sure you didn't change any options.
50
51   --zip                     Zip the output files up into a zip file.
52 EOF
53 }
54
55 parse_options()
56 {
57         if [ -z "$MSYSTEM" ]; then
58                 ARCH=x86_64
59         else
60                 case "$MSYSTEM" in
61                 MINGW32)
62                         ARCH=i686
63                         CC_PKG=mingw-w64-i686-gcc
64                         ;;
65                 MINGW64)
66                         ARCH=x86_64
67                         CC_PKG=mingw-w64-x86_64-gcc
68                         ;;
69                 CLANG32)
70                         ARCH=i686
71                         CC_PKG=mingw-w64-clang-i686-clang
72                         ;;
73                 CLANG64)
74                         ARCH=x86_64
75                         CC_PKG=mingw-w64-clang-x86_64-clang
76                         ;;
77                 CLANGARM64)
78                         ARCH=aarch64
79                         # MSYS2 doesn't yet support cross-compiling for ARM64,
80                         # so use a separate prebuilt toolchain for that case.
81                         if [ "$(uname -m)" = x86_64 ]; then
82                                 PREBUILT_LLVM_MINGW_ENABLED=true
83                                 export PATH="$PREBUILT_LLVM_MINGW_BIN:$PATH"
84                         else
85                                 CC_PKG=mingw-w64-clang-aarch64-clang
86                         fi
87                         ;;
88                 *)
89                         echo 1>&2 "Unsupported MSYS2 environment: $MSYSTEM.  This script supports"
90                         echo 1>&2 "MINGW32, MINGW64, CLANG32, CLANG64, and CLANGARM64."
91                         echo 1>&2 "See https://www.msys2.org/docs/environments/"
92                         exit 1
93                 esac
94         fi
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         # http://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 "$cc" --version | grep -q '(GCC)'; then
214                 configure_args+=("CC=$cc -static-libgcc")
215         fi
216         configure_args+=("${EXTRA_CONFIGURE_ARGS[@]}")
217         ./configure "${configure_args[@]}"
218         $MAKE clean
219 }
220
221 build_wimlib()
222 {
223         echo "Building wimlib..."
224         $MAKE
225 }
226
227 list_imagex_commands()
228 {
229         for cmd in ./doc/man1/wim*.1; do
230                 local cmd=${cmd##*/}
231                 cmd=${cmd%.1}
232                 case "$cmd" in
233                 wimlib-imagex|wimmount|wimmountrw|wimunmount)
234                         ;;
235                 *)
236                         echo "$cmd"
237                         ;;
238                 esac
239         done
240 }
241
242 install_binaries()
243 {
244         echo "Installing binaries..."
245         cp .libs/*.{dll,exe} "$DESTDIR"
246         strip "$DESTDIR"/*.{dll,exe}
247 }
248
249 install_text_files()
250 {
251         echo "Installing NEWS, README, and licenses..."
252         cp NEWS README* COPYING* "$DESTDIR"
253         sed -n '/^#/q; s/^[\/\* ]*//; p' src/divsufsort.c > "$DESTDIR"/COPYING.libdivsufsort-lite
254         if ! grep -q 'Copyright' "$DESTDIR"/COPYING.libdivsufsort-lite; then
255                 echo 1>&2 "ERROR: failed to extract libdivsufsort-lite license text"
256                 exit 1
257         fi
258         cd "$DESTDIR"
259         for fil in NEWS README* COPYING*; do
260                 sed < "$fil" > "${fil}".txt -e 's/$/\r/g'
261                 rm "$fil"
262         done
263         cd ..
264 }
265
266 gen_pdf_from_man_page()
267 {
268         local cmd=$1
269         local pdf=${DESTDIR}/doc/${cmd}.pdf
270
271         echo "Generating $pdf"
272         MANPATH="./doc" man -t "$cmd" | ps2pdf - "$pdf"
273 }
274
275 install_pdf_docs()
276 {
277         echo "Installing PDF manual pages..."
278         mkdir "$DESTDIR"/doc
279         for cmd in $(list_imagex_commands); do
280                 gen_pdf_from_man_page "$cmd"
281         done
282         gen_pdf_from_man_page wimlib-imagex
283 }
284
285 install_cmd_aliases()
286 {
287         echo "Installing wim*.cmd files..."
288         for cmd in $(list_imagex_commands); do
289                 sed 's/$/\r/g' > "${DESTDIR}/${cmd}.cmd" <<- EOF
290                         @echo off
291                         "%~dp0\\wimlib-imagex" ${cmd#wim} %*
292                 EOF
293                 chmod +x "${DESTDIR}/${cmd}.cmd"
294         done
295 }
296
297 install_development_files()
298 {
299         echo "Installing development files..."
300         mkdir "$DESTDIR"/devel
301         cp .libs/libwim.dll.a "$DESTDIR"/devel/libwim.lib
302         cp include/wimlib.h "$DESTDIR"/devel/
303 }
304
305 create_zip_file()
306 {
307         echo "Creating zip file..."
308         cd "$DESTDIR"
309         7z -mx9 a ../"$ZIPFILE" . > /dev/null
310         cd ..
311 }
312
313 parse_options "$@"
314 rm -rf -- "$DESTDIR" "$ZIPFILE"
315 mkdir -- "$DESTDIR"
316 if $INSTALL_PREREQUISITES; then
317         install_prerequisites
318 fi
319 if [ ! -e configure ]; then
320         bootstrap_repository
321 fi
322 if [ ! -e config.log ] || ! $SKIP_CONFIGURE; then
323         configure_wimlib
324 fi
325 build_wimlib
326 install_binaries
327 install_text_files
328 if $INCLUDE_DOCS; then
329         install_pdf_docs
330 fi
331 install_cmd_aliases
332 install_development_files
333 if $ZIP; then
334         create_zip_file
335         echo "Success!  Output is in $ZIPFILE"
336 else
337         echo "Success!  Output is in $DESTDIR"
338 fi