Merge branch 'sources' of dustdfg/dragora into master
[dragora.git] / bootstrap
blobbbdb6c45f34399bb53d0966cadb4349bbd6ab8d9
1 #! /bin/sh -
2 # Builder of custom stages (cross compilers, GNU/Linux distributions)
4 # Copyright (c) 2014-2022 Matias Fonzo, <selk@dragora.org>.
6 # This program is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation, either version 3 of the License, or
9 # (at your option) any later version.
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program. If not, see <http://www.gnu.org/licenses/>.
19 # EXIT STATUS
20 # 0 = Successful completion
21 # 1 = Minor common errors (e.g: help usage, support not available)
22 # 2 = Command execution error
23 # 3 = Integrity check error for compressed files
25 PROGRAM="${0##*/}"
27 # Override locale settings
28 LC_ALL=C
29 LANGUAGE=C
30 export LC_ALL LANGUAGE
32 # Get physical working directory (absolute path)
33 worktree="$(CDPATH='' cd -P -- "$(dirname -- "$0")" && pwd -P)" || exit $?
35 ### Functions
37 usage()
39 printf '%s' \
40 "Usage: $PROGRAM [OPTIONS] [FILE]...
41 Builder of custom stages (cross compilers, GNU/Linux distributions).
43 Where FILE is any shell script (as long as it is executable) from
44 a stage number. Without FILE, it loads all the found scripts from
45 the stage number. Stage numbers come from the stages directory
46 (${worktree}/stages).
48 Defaults for the options are specified in brackets.
50 Options:
51 -a Target architecture [${arch}]
52 -j Parallel jobs for the compiler [${jobs}]
53 -k Keep (don't delete) source directory
54 -o Output directory [${output}]
55 -s Stage number to build [${stage}]
56 -h Display this help and exit
57 -V Print version information and exit
59 Some influential environment variables:
60 TMPDIR Temporary directory for sources [${TMPDIR}]
61 BTCC C compiler command [${BTCC}]
62 BTCXX C++ compiler command [${BTCXX}]
63 BTCFLAGS C compiler flags [${BTCFLAGS}]
64 BTCXXFLAGS C++ compiler flags [${BTCXXFLAGS}]
65 BTLDFLAGS Linker flags [${BTLDFLAGS}]
66 VENDOR Vendor name to reflect on the target triplet
68 Available targets from ${worktree}/targets ...
71 for name in "${worktree}/targets"/*
73 sed -e '2q;d' "$name"
74 done
75 unset -v name
76 echo ""
79 version()
81 printf '%s' \
82 "$PROGRAM 3.33
83 Copyright (C) 2014-2022 Matias Andres Fonzo.
84 License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
85 This is free software: you are free to change and redistribute it.
86 There is NO WARRANTY, to the extent permitted by law.
90 warn()
92 printf '%s\n' "$@" 1>&2
95 chkstatus_or_exit()
97 status=$?
99 if test $status -ne 0
100 then
101 echo "Return status = $status" 1>&2
102 exit "${1-2}"; # If not given, defaults to 2
105 unset -v status
108 # Function to test and extract compressed files
109 unpack()
111 for file in "$@"
113 case $file in
114 *.tar)
115 tar tf "$file" > /dev/null && \
116 tar xpf "$file"
117 chkstatus_or_exit 3
119 *.tar.gz | *.tgz | *.tar.Z )
120 gzip -cd "$file" | tar tf - > /dev/null && \
121 gzip -cd "$file" | tar xpf -
122 chkstatus_or_exit 3
124 *.tar.bz2 | *.tbz2 | *.tbz )
125 bzip2 -cd "$file" | tar tf - > /dev/null && \
126 bzip2 -cd "$file" | tar xpf -
127 chkstatus_or_exit 3
129 *.tar.lz | *.tlz )
130 lzip -cd "$file" | tar tf - > /dev/null && \
131 lzip -cd "$file" | tar xpf -
132 chkstatus_or_exit 3
134 *.tar.xz | *.txz )
135 xz -cd "$file" | tar tf - > /dev/null && \
136 xz -cd "$file" | tar xpf -
137 chkstatus_or_exit 3
139 *.tar.zst | *.tzst )
140 zstd -cd "$file" | tar -tf - > /dev/null && \
141 zstd -cd "$file" | tar -xpf -
142 chkstatus_or_exit 3
144 *.zip | *.ZIP )
145 unzip -t "$file" > /dev/null && \
146 unzip "$file" > /dev/null
147 chkstatus_or_exit 3
149 *.gz)
150 gzip -t "$file" && \
151 gzip -cd "$file" > "$(basename -- "$file" .gz)"
152 chkstatus_or_exit 3
154 *.Z)
155 gzip -t "$file" && \
156 gzip -cd "$file" > "$(basename -- "$file" .Z)"
157 chkstatus_or_exit 3
159 *.bz2)
160 bzip2 -t "$file" && \
161 bzip2 -cd "$file" > "$(basename -- "$file" .bz2)"
162 chkstatus_or_exit 3
164 *.lz)
165 lzip -t "$file" && \
166 lzip -cd "$file" > "$(basename -- "$file" .lz)"
167 chkstatus_or_exit 3
169 *.xz)
170 xz -t "$file" && \
171 xz -cd "$file" > "$(basename -- "$file" .xz)"
172 chkstatus_or_exit 3
174 *.zst)
175 zstd -qt "$file" && \
176 zstd -cd "$file" > "$(basename -- "$file" .zst)"
177 chkstatus_or_exit 3
180 warn "${PROGRAM}: cannot unpack ${file}: Unsupported extension"
181 exit 1
182 esac
183 done
184 unset -v file
187 # Print a warning for good practices.
189 # Recommended practices is to set variables
190 # in front of `configure' or make(1), see:
192 # http://www.gnu.org/software/make/manual/html_node/Environment.html
193 # http://gnu.org/savannah-checkouts/gnu/autoconf/manual/autoconf-2.69/html_node/Defining-Variables.html
194 # http://www.gnu.org/savannah-checkouts/gnu/autoconf/manual/autoconf-2.69/html_node/Setting-Output-Variables.html
196 warn_flags()
198 warn "" \
199 "WARNING: Environment variable '$1' is set." \
200 "This will be unset to avoid possible risks." \
204 ### Default values
206 BTCC="${BTCC:=gcc}"
207 BTCXX="${BTCXX:=g++}"
208 BTCFLAGS="${BTCFLAGS:=-O2}"
209 BTCXXFLAGS="${BTCXXFLAGS:=-O2}"
210 BTLDFLAGS="${BTLDFLAGS:=}"
211 opt_keep=opt_keep.off
212 stage=0
213 libSuffix=""
214 arch="$(uname -m)" || chkstatus_or_exit
215 jobs=1
216 output="${worktree}/OUTPUT.${PROGRAM}"
217 TMPDIR="${TMPDIR:=${output}/sources}"
219 # Compose vendor name adding "-" as suffix
220 test -n "$VENDOR" && VENDOR="${VENDOR}-"
222 ### Parse options
224 while getopts :ha:j:ko:s:V name
226 case $name in
228 usage
229 exit 0
232 arch="$OPTARG"
235 jobs="$OPTARG"
238 opt_keep=opt_keep
241 output="$OPTARG"
244 stage="$OPTARG"
247 version
248 exit 0
251 warn "Option '-${OPTARG}' requires an argument"
252 usage
253 exit 1
256 warn "Illegal option -- '-${OPTARG}'"
257 usage
258 exit 1
260 esac
261 done
262 shift $(( OPTIND - 1 ))
263 unset -f usage version
265 # Check for environment variables, print warning, unset in any case
267 test -n "$CC" && warn_flags CC
268 test -n "$CXX" && warn_flags CXX
269 test -n "$CFLAGS" && warn_flags CFLAGS
270 test -n "$CXXFLAGS" && warn_flags CXXFLAGS
271 test -n "$LDFLAGS" && warn_flags LDFLAGS
272 unset CC CXX CFLAGS CXXFLAGS LDFLAGS warn_flags
274 # Load target architecture-file
276 if test -f "${worktree}/targets/$arch"
277 then
278 echo "${PROGRAM}: Loading target $arch ..."
279 . "${worktree}/targets/$arch"
280 else
281 warn \
282 "${PROGRAM}: Target name not recognized -- '${arch}'" \
283 "See '$0 -h' for more information"
284 exit 1
287 # Determine the host to use.
289 # If the host and the target are the same triplet, it won't work.
290 # We are changing the host if it is really needed
292 host="$(${BTCC} -dumpmachine)" || chkstatus_or_exit
294 if test "$host" = "$target"
295 then
296 # Rename VENDOR to 'cross'. If empty, 'cross-linux' is added
297 case "${host%-*-*}" in
298 *-*)
299 host="$(echo "$host" | sed -e 's/-[^-]*/-cross/')"
302 host="$(echo "$host" | sed -e 's/-[^-]*/-cross-linux/')"
304 esac
307 # Compose variables for the physical output,
308 # printing some useful information
310 crossdir="${output}/cross/${target}"
311 rootdir="${output}/stage${stage}"
313 printf '%s\n' \
314 "BTCC: $BTCC" \
315 "BTCXX: $BTCXX" \
316 "BTCFLAGS: $BTCFLAGS" \
317 "BTCXXFLAGS: $BTCXXFLAGS" \
318 "BTLDFLAGS: $BTLDFLAGS" \
319 "Host: $host" \
320 "Target: $target" \
321 "Output directory: $output" \
322 "Cross directory: $crossdir" \
323 "Root directory: $rootdir"
325 # Remove write permission for group and other
326 umask 022
328 # Create required directories
329 mkdir -p -- "$output" "$TMPDIR"
330 chkstatus_or_exit
332 # Set default PATH, propagate variables
333 PATH="${crossdir}/bin:${PATH}"
335 export PATH VENDOR TMPDIR
337 # Main loop
338 for file in ${worktree}/stages/${stage}/${@:-??-*}
340 file="${file##*/}"
342 if test ! -f "${worktree}/stages/${stage}/$file"
343 then
344 warn "${PROGRAM}: ${stage}/${file}: No such file or stage number"
345 exit 1
347 if test ! -x "${worktree}/stages/${stage}/$file"
348 then
349 warn "${PROGRAM}: ${stage}/${file}: File not executable, dodging"
350 continue;
353 ### Stage pre-settings
355 # Create sysroot directory, recreating the symlink for the stage 0
357 if test "$stage" = 0
358 then
359 mkdir -p -- "${crossdir}/$target" || chkstatus_or_exit
361 if test ! -L "${crossdir}/${target}/usr"
362 then
363 ln -s -f . "${crossdir}/${target}/usr" || chkstatus_or_exit
366 # Ensure toolchain sanity for multilib purposes
367 case $arch in
368 aarch64* | arm* | x32 | x86_64 | i?86 | riscv* )
369 if test ! -L "${crossdir}/lib" && test -n "$libSuffix"
370 then
371 ln -s -f lib${libSuffix} "${crossdir}/lib" || chkstatus_or_exit
374 esac
377 # Create "tools" directory, recreating the symlink for the stage 1
378 if test "$stage" = 1
379 then
380 if test ! -d "${rootdir}/tools"
381 then
382 mkdir -p -- "${rootdir}/tools" || chkstatus_or_exit
385 # Check and make required symlink
386 if test ! -L /tools
387 then
388 ln -s -f "${rootdir}/tools" / || chkstatus_or_exit
392 echo "${PROGRAM}: Processing $file from stages/${stage} ..."
394 # Set trap before to run the script in order to
395 # catch the return status, exit code 2 if fails
397 trap 'chkstatus_or_exit 2' EXIT HUP INT QUIT ABRT TERM
399 # Exit immediately on any error
400 set -e
402 . "${worktree}/stages/${stage}/$file"
404 # Deactivate shell option(s)
405 set +e
407 # Reset given signals
408 trap - EXIT HUP INT QUIT ABRT TERM
410 # Delete declared directories on the cleanup() function
411 if test "$opt_keep" != opt_keep
412 then
413 if type cleanup 1> /dev/null 2> /dev/null
414 then
415 cleanup
416 chkstatus_or_exit 2
417 unset -f cleanup
421 # Back to the current working directory
422 cd -- "$worktree" || chkstatus_or_exit
423 done