source: mainline/tools/toolchain.sh@ 7b9282b

Last change on this file since 7b9282b was 113fb4f, checked in by Martin Decky <martin@…>, 6 days ago

Use tar to install toolchains into the destination

Using a pair of tar invocations (reading the source path by one
instance and piping the data to a second instance that writes into
the target path) has the benefit of better preserving certain file
attributes and especially the hard links (even if the source and the
target paths reside on different physical file systems).

Preserving the hard links is important to avoid needlessly wasting
storage space.

  • Property mode set to 100755
File size: 13.6 KB
Line 
1#!/bin/sh
2
3#
4# Copyright (c) 2009 Martin Decky
5# All rights reserved.
6#
7# Redistribution and use in source and binary forms, with or without
8# modification, are permitted provided that the following conditions
9# are met:
10#
11# - Redistributions of source code must retain the above copyright
12# notice, this list of conditions and the following disclaimer.
13# - Redistributions in binary form must reproduce the above copyright
14# notice, this list of conditions and the following disclaimer in the
15# documentation and/or other materials provided with the distribution.
16# - The name of the author may not be used to endorse or promote products
17# derived from this software without specific prior written permission.
18#
19# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29#
30
31BINUTILS_GDB_GIT="https://github.com/HelenOS/binutils-gdb.git"
32
33BINUTILS_BRANCH="binutils-2_45-helenos"
34BINUTILS_VERSION="2.45"
35
36GCC_GIT="https://github.com/HelenOS/gcc.git"
37GCC_BRANCH="15_2_0-helenos"
38GCC_VERSION="15.2"
39
40BASEDIR="$PWD"
41SRCDIR="$(readlink -f $(dirname "$0"))"
42
43# If we install into a temporary directory and copy from there,
44# we don't have to trust the upstream makefiles respect the prefix for
45# all files, and we also have a ready-made package for distribution.
46INSTALL_DIR="${BASEDIR}/PKG"
47
48SYSTEM_INSTALL=false
49
50BUILD_BINUTILS=true
51BUILD_GCC=true
52
53if [ -z "$JOBS" ] ; then
54 JOBS="`nproc`"
55fi
56
57check_error() {
58 if [ "$1" -ne "0" ] ; then
59 echo
60 echo "Script failed: $2"
61
62 exit 1
63 fi
64}
65
66show_usage() {
67 echo "HelenOS cross-compiler toolchain build script"
68 echo
69 echo "Syntax:"
70 echo " $0 [--system-wide] --test-version [<platform>]"
71 echo
72 echo "Possible target platforms are:"
73 echo " amd64 AMD64 (x86-64, x64)"
74 echo " arm32 ARM 32b"
75 echo " arm64 AArch64"
76 echo " ia32 IA-32 (x86, i386)"
77 echo " ia64 IA-64 (Itanium)"
78 echo " mips32 MIPS little-endian 32b"
79 echo " mips32eb MIPS big-endian 32b"
80 echo " ppc32 PowerPC 32b"
81 echo " riscv64 RISC-V 64b"
82 echo " sparc64 SPARC V9"
83 echo " all build all targets"
84 echo " parallel same as 'all', but all in parallel"
85 echo " 2-way same as 'all', but 2-way parallel"
86 echo
87 echo "The toolchain target installation directory is determined by matching"
88 echo "the first of the following conditions:"
89 echo
90 echo " (1) If the \$CROSS_PREFIX environment variable is set, then it is"
91 echo " used as the target installation directory."
92 echo " (2) If the --system-wide option is used, then /opt/HelenOS/cross"
93 echo " is used as the target installation directory. This usually"
94 echo " requires running this script with super user privileges."
95 echo " (3) In other cases, \$XDG_DATA_HOME/HelenOS/cross is used as the"
96 echo " target installation directory. If the \$XDG_DATA_HOME environment"
97 echo " variable is not set, then the default value of \$HOME/.local/share"
98 echo " is assumed."
99 echo
100 echo "The --non-helenos-target option will build non-HelenOS-specific"
101 echo "toolchain (i.e. it will use *-linux-* triplet instead of *-helenos)."
102 echo "Using this toolchain for building HelenOS is not supported."
103 echo
104 echo "The --test-version mode tests the currently installed version of the"
105 echo "toolchain."
106
107 exit 3
108}
109
110set_cross_prefix() {
111 if [ -z "$CROSS_PREFIX" ] ; then
112 if $SYSTEM_INSTALL ; then
113 CROSS_PREFIX="/opt/HelenOS/cross"
114 else
115 if [ -z "$XDG_DATA_HOME" ] ; then
116 XDG_DATA_HOME="$HOME/.local/share"
117 fi
118 CROSS_PREFIX="$XDG_DATA_HOME/HelenOS/cross"
119 fi
120 fi
121}
122
123test_version() {
124 set_cross_prefix
125
126 echo "HelenOS cross-compiler toolchain build script"
127 echo
128 echo "Testing the version of the installed software in $CROSS_PREFIX"
129 echo
130
131 if [ -z "$1" ] || [ "$1" = "all" ] ; then
132 PLATFORMS='amd64 arm32 arm64 ia32 ia64 mips32 mips32eb ppc32 riscv64 sparc64'
133 else
134 PLATFORMS="$1"
135 fi
136
137 for PLATFORM in $PLATFORMS ; do
138 set_target_from_platform "$PLATFORM"
139 PREFIX="${CROSS_PREFIX}/bin/${TARGET}"
140
141 echo "== $PLATFORM =="
142 test_app_version "Binutils" "ld" "GNU ld (.*) \([.0-9]*\)" "$BINUTILS_VERSION"
143 test_app_version "GCC" "gcc" "gcc version \([.0-9]*\)" "$GCC_VERSION"
144 done
145}
146
147test_app_version() {
148 PKGNAME="$1"
149 APPNAME="$2"
150 REGEX="$3"
151 INS_VERSION="$4"
152
153 APP="${PREFIX}-${APPNAME}"
154 if [ ! -e $APP ]; then
155 echo "- $PKGNAME is missing"
156 else
157 VERSION=`${APP} -v 2>&1 | sed -n "s:^${REGEX}.*:\1:p"`
158
159 if [ -z "$VERSION" ]; then
160 echo "- $PKGNAME Unexpected output"
161 return 1
162 fi
163
164 if [ "$INS_VERSION" = "$VERSION" ]; then
165 echo "+ $PKGNAME is up-to-date ($INS_VERSION)"
166 else
167 echo "- $PKGNAME ($VERSION) is outdated ($INS_VERSION)"
168 fi
169 fi
170}
171
172change_title() {
173 printf "\e]0;$1\a"
174}
175
176ring_bell() {
177 printf '\a'
178 sleep 0.1
179 printf '\a'
180 sleep 0.1
181 printf '\a'
182 sleep 0.1
183 printf '\a'
184 sleep 0.1
185 printf '\a'
186}
187
188show_countdown() {
189 TM="$1"
190
191 if [ "${TM}" -eq 0 ] ; then
192 echo
193 return 0
194 fi
195
196 printf "${TM} "
197 change_title "${TM}"
198 sleep 1
199
200 TM="`expr "${TM}" - 1`"
201 show_countdown "${TM}"
202}
203
204show_dependencies() {
205 set_cross_prefix
206
207 echo "HelenOS cross-compiler toolchain build script"
208 echo
209 echo "Installing software to $CROSS_PREFIX"
210 echo
211 echo
212 echo "IMPORTANT NOTICE:"
213 echo
214 echo "For a successful compilation and use of the cross-compiler"
215 echo "toolchain you need at least the following dependencies."
216 echo
217 echo "Please make sure that the dependencies are present in your"
218 echo "system. Otherwise the compilation process might fail after"
219 echo "a few seconds or minutes."
220 echo
221 echo " - SED, AWK, Flex, Bison, gzip, bzip2, Bourne Shell"
222 echo " - gettext, zlib, Texinfo, libelf, libgomp"
223 echo " - GNU Make, Coreutils, Sharutils, tar"
224 echo " - native C and C++ compiler, assembler and linker"
225 echo " - native C and C++ standard library with headers"
226 echo
227}
228
229cleanup_dir() {
230 DIR="$1"
231
232 if [ -d "${DIR}" ] ; then
233 change_title "Removing ${DIR}"
234 echo " >>> Removing ${DIR}"
235 rm -fr "${DIR}"
236 fi
237}
238
239create_dir() {
240 DIR="$1"
241 DESC="$2"
242
243 change_title "Creating ${DESC}"
244 echo ">>> Creating ${DESC}"
245
246 mkdir -p "${DIR}"
247 test -d "${DIR}"
248 check_error $? "Unable to create ${DIR}."
249}
250
251check_dirs() {
252 cd "${BASEDIR}"
253 check_error $? "Unable to change directory to ${BASEDIR}."
254 ABS_BASE="$PWD"
255
256 if $SYSTEM_INSTALL && [ ! -d "${CROSS_PREFIX}" ]; then
257 ring_bell
258 ( set -x ; sudo -k mkdir -p "${CROSS_PREFIX}" )
259 else
260 ( set -x ; mkdir -p "${CROSS_PREFIX}" )
261 fi
262
263 cd "${CROSS_PREFIX}"
264 check_error $? "Unable to change directory to ${CROSS_PREFIX}."
265
266 while [ "${#PWD}" -gt "${#ABS_BASE}" ]; do
267 cd ..
268 done
269
270 if [ "$PWD" = "$ABS_BASE" ]; then
271 echo
272 echo "CROSS_PREFIX cannot reside within the working directory."
273
274 exit 5
275 fi
276
277 cd "${BASEDIR}"
278}
279
280prepare() {
281 show_dependencies
282 show_countdown 10
283
284 mkdir -p "${BASEDIR}/downloads"
285 cd "${BASEDIR}/downloads"
286 check_error $? "Change directory failed."
287
288 change_title "Downloading sources"
289 echo ">>> Downloading sources"
290
291 if $BUILD_BINUTILS ; then
292 git clone --depth 1 -b "$BINUTILS_BRANCH" "$BINUTILS_GDB_GIT" "binutils-$BINUTILS_VERSION"
293 # If the directory already existed, pull upstream changes.
294 git -C "binutils-$BINUTILS_VERSION" pull
295 fi
296
297 if $BUILD_GCC ; then
298 git clone --depth 1 -b "$GCC_BRANCH" "$GCC_GIT" "gcc-$GCC_VERSION"
299 git -C "gcc-$GCC_VERSION" pull
300
301 change_title "Downloading GCC prerequisites"
302 echo ">>> Downloading GCC prerequisites"
303 cd "gcc-${GCC_VERSION}"
304 ./contrib/download_prerequisites
305 cd ..
306 fi
307
308 # This sets the CROSS_PREFIX variable
309 set_cross_prefix
310
311 DESTDIR_SPEC="DESTDIR=${INSTALL_DIR}"
312
313 check_dirs
314}
315
316set_target_from_platform() {
317 case "$1" in
318 "arm32")
319 GNU_ARCH="arm"
320 ;;
321 "arm64")
322 GNU_ARCH="aarch64"
323 ;;
324 "ia32")
325 GNU_ARCH="i686"
326 ;;
327 "mips32")
328 GNU_ARCH="mipsel"
329 ;;
330 "mips32eb")
331 GNU_ARCH="mips"
332 ;;
333 "ppc32")
334 GNU_ARCH="ppc"
335 ;;
336 *)
337 GNU_ARCH="$1"
338 ;;
339 esac
340
341 TARGET="${GNU_ARCH}-helenos"
342}
343
344build_binutils() {
345 # This sets the TARGET variable
346 set_target_from_platform "$1"
347
348 WORKDIR="${BASEDIR}/${TARGET}"
349 BINUTILSDIR="${WORKDIR}/binutils-${BINUTILS_VERSION}"
350
351 echo ">>> Removing previous content"
352 cleanup_dir "${WORKDIR}"
353 mkdir -p "${WORKDIR}"
354
355 echo ">>> Processing binutils (${TARGET})"
356 mkdir -p "${BINUTILSDIR}"
357 cd "${BINUTILSDIR}"
358 check_error $? "Change directory failed."
359
360 change_title "binutils: configure (${TARGET})"
361 CFLAGS="-Wno-error -fcommon" "${BASEDIR}/downloads/binutils-${BINUTILS_VERSION}/configure" \
362 "--target=${TARGET}" \
363 "--prefix=${CROSS_PREFIX}" \
364 "--program-prefix=${TARGET}-" \
365 --disable-nls \
366 --disable-werror \
367 --enable-gold \
368 --enable-deterministic-archives \
369 --disable-gdb \
370 --with-sysroot
371 check_error $? "Error configuring binutils."
372
373 change_title "binutils: make (${TARGET})"
374 make all -j$JOBS
375 check_error $? "Error compiling binutils."
376
377 change_title "binutils: install (${TARGET})"
378 make install $DESTDIR_SPEC
379 check_error $? "Error installing binutils."
380}
381
382build_gcc() {
383 # This sets the TARGET variable
384 set_target_from_platform "$1"
385
386 WORKDIR="${BASEDIR}/${TARGET}"
387 GCCDIR="${WORKDIR}/gcc-${GCC_VERSION}"
388
389 echo ">>> Removing previous content"
390 cleanup_dir "${WORKDIR}"
391 mkdir -p "${WORKDIR}"
392
393 echo ">>> Processing GCC (${TARGET})"
394 mkdir -p "${GCCDIR}"
395 cd "${GCCDIR}"
396 check_error $? "Change directory failed."
397
398 BUILDPATH="${CROSS_PREFIX}/bin:${PATH}"
399
400 change_title "GCC: configure (${TARGET})"
401 PATH="${BUILDPATH}" "${BASEDIR}/downloads/gcc-${GCC_VERSION}/configure" \
402 "--target=${TARGET}" \
403 "--prefix=${CROSS_PREFIX}" \
404 "--program-prefix=${TARGET}-" \
405 --with-gnu-as \
406 --with-gnu-ld \
407 --disable-nls \
408 --enable-languages=c,c++,go \
409 --enable-lto \
410 --enable-obsolete \
411 --disable-shared \
412 --disable-werror \
413 --without-headers # TODO: Replace with proper sysroot so we can build more libs
414 check_error $? "Error configuring GCC."
415
416 change_title "GCC: make (${TARGET})"
417 PATH="${BUILDPATH}" make all-gcc -j$JOBS
418 check_error $? "Error compiling GCC."
419
420 change_title "GCC: install (${TARGET})"
421 PATH="${BUILDPATH}" make install-gcc $DESTDIR_SPEC
422 check_error $? "Error installing GCC."
423}
424
425build_libgcc() {
426 # This sets the TARGET variable
427 set_target_from_platform "$1"
428
429 WORKDIR="${BASEDIR}/${TARGET}"
430 GCCDIR="${WORKDIR}/gcc-${GCC_VERSION}"
431
432 # No removing previous content here, we need the previous GCC build
433
434 cd "${GCCDIR}"
435 check_error $? "Change directory failed."
436
437 BUILDPATH="${CROSS_PREFIX}/bin:${PATH}"
438
439 change_title "libgcc: make (${TARGET})"
440
441 PATH="${BUILDPATH}" make all-target-libgcc -j$JOBS
442 check_error $? "Error compiling libgcc."
443 # TODO: libatomic and libstdc++ need some extra care
444 # PATH="${BUILDPATH}" make all-target-libatomic -j$JOBS
445 # check_error $? "Error compiling libatomic."
446 # PATH="${BUILDPATH}" make all-target-libstdc++-v3 -j$JOBS
447 # check_error $? "Error compiling libstdc++."
448
449 change_title "libgcc: install (${TARGET})"
450
451 PATH="${BUILDPATH}" make install-target-libgcc $DESTDIR_SPEC
452 # PATH="${BUILDPATH}" make install-target-libatomic $DESTDIR_SPEC
453 # PATH="${BUILDPATH}" make install-target-libstdc++-v3 $DESTDIR_SPEC
454 check_error $? "Error installing libgcc."
455}
456
457install_pkg() {
458 echo ">>> Moving to the destination directory."
459 if $SYSTEM_INSTALL ; then
460 ring_bell
461 ( set -x ; tar -C "${INSTALL_DIR}${CROSS_PREFIX}" -cpf - . | sudo -k tar -C "${CROSS_PREFIX}" -xpf - )
462 else
463 ( set -x ; tar -C "${INSTALL_DIR}${CROSS_PREFIX}" -cpf - . | tar -C "${CROSS_PREFIX}" -xpf - )
464 fi
465}
466
467link_clang() {
468 # Symlink clang and lld to the install path.
469 CLANG="`which clang 2> /dev/null || echo "/usr/bin/clang"`"
470 CLANGPP="`which clang++ 2> /dev/null || echo "/usr/bin/clang++"`"
471 LLD="`which ld.lld 2> /dev/null || echo "/usr/bin/ld.lld"`"
472
473 ln -s $CLANG "${INSTALL_DIR}${CROSS_PREFIX}/bin/${TARGET}-clang"
474 ln -s $CLANGPP "${INSTALL_DIR}${CROSS_PREFIX}/bin/${TARGET}-clang++"
475 ln -s $LLD "${INSTALL_DIR}${CROSS_PREFIX}/bin/${TARGET}-ld.lld"
476}
477
478while [ "$#" -gt 1 ] ; do
479 case "$1" in
480 --system-wide)
481 SYSTEM_INSTALL=true
482 shift
483 ;;
484 --test-version)
485 test_version "$2"
486 exit
487 ;;
488 *)
489 show_usage
490 ;;
491 esac
492done
493
494if [ "$#" -lt "1" ] ; then
495 show_usage
496fi
497
498PLATFORMS="amd64 arm32 arm64 ia32 ia64 mips32 mips32eb ppc32 riscv64 sparc64"
499
500run_one() {
501 $1 $PLATFORM
502}
503
504run_all() {
505 for x in $PLATFORMS ; do
506 $1 $x
507 done
508}
509
510run_parallel() {
511 for x in $PLATFORMS ; do
512 $1 $x &
513 done
514 wait
515}
516
517run_2way() {
518 $1 amd64 &
519 $1 arm32 &
520 wait
521
522 $1 arm64 &
523 $1 ia32 &
524 wait
525
526 $1 ia64 &
527 $1 mips32 &
528 wait
529
530 $1 mips32eb &
531 $1 ppc32 &
532 wait
533
534 $1 riscv64 &
535 $1 sparc64 &
536 wait
537}
538
539everything() {
540 RUNNER="$1"
541
542 prepare
543
544 if $BUILD_BINUTILS ; then
545 $RUNNER build_binutils
546
547 if $BUILD_GCC ; then
548 # gcc/libgcc may fail to build correctly if binutils is not installed first
549 echo ">>> Installing binutils"
550 install_pkg
551 fi
552 fi
553
554 if $BUILD_GCC ; then
555 $RUNNER build_gcc
556
557 # libgcc may fail to build correctly if gcc is not installed first
558 echo ">>> Installing GCC"
559 install_pkg
560
561 $RUNNER build_libgcc
562 fi
563
564 echo ">>> Installing all files"
565 install_pkg
566
567 link_clang
568}
569
570case "$1" in
571 --test-version)
572 test_version
573 exit
574 ;;
575 amd64|arm32|arm64|ia32|ia64|mips32|mips32eb|ppc32|riscv64|sparc64)
576 PLATFORM="$1"
577 everything run_one
578 ;;
579 "all")
580 everything run_all
581 ;;
582 "parallel")
583 everything run_parallel
584 ;;
585 "2-way")
586 everything run_2way
587 ;;
588 *)
589 show_usage
590 ;;
591esac
Note: See TracBrowser for help on using the repository browser.