scripts/build/internals.sh: compile wrapper with portable options.
static linking is not possible on MacOS, and unnessecary on other systems.
The old optimization and warning flags crash the gcc on MacOS
and (imho) are a bit overdone for this software.
1 # This file contains some usefull common functions
2 # Copyright 2007 Yann E. MORIN
3 # Licensed under the GPL v2. See COPYING in the root of this package
5 # Prepare the fault handler
8 # Bail out early in subshell, the upper level shell will act accordingly.
9 [ ${BASH_SUBSHELL} -eq 0 ] || exit $ret
10 CT_DoLog ERROR "Build failed in step '${CT_STEP_MESSAGE[${CT_STEP_COUNT}]}'"
11 for((step=(CT_STEP_COUNT-1); step>1; step--)); do
12 CT_DoLog ERROR " called in step '${CT_STEP_MESSAGE[${step}]}'"
14 CT_DoLog ERROR "Error happened in '${BASH_SOURCE[1]}' in function '${FUNCNAME[1]}' (line unknown, sorry)"
15 for((depth=2; ${BASH_LINENO[$((${depth}-1))]}>0; depth++)); do
16 CT_DoLog ERROR " called from '${BASH_SOURCE[${depth}]}' at line # ${BASH_LINENO[${depth}-1]} in function '${FUNCNAME[${depth}]}'"
18 [ "${CT_LOG_TO_FILE}" = "y" ] && CT_DoLog ERROR "Look at '${CT_LOG_FILE}' for more info on this error."
24 # Install the fault handler
27 # Inherit the fault handler in subshells and functions
30 # Make pipes fail on the _first_ failed command
31 # Not supported on bash < 3.x, but we need it, so drop the obsoleting bash-2.x
34 # Don't hash commands' locations, and search every time it is requested.
35 # This is slow, but needed because of the static/shared core gcc which shall
36 # always match to shared if it exists, and only fallback to static if the
41 # - first of all, save stdout so we can see the live logs: fd #6
43 # - then point stdout to the log file (temporary for now)
44 tmp_log_file="${CT_TOP_DIR}/log.$$"
45 exec >>"${tmp_log_file}"
47 # The different log levels:
55 # Make it easy to use \n and !
59 # A function to log what is happening
60 # Different log level are available:
61 # - ERROR: A serious, fatal error occurred
62 # - WARN: A non fatal, non serious error occurred, take your responsbility with the generated build
63 # - INFO: Informational messages
64 # - EXTRA: Extra informational messages
65 # - DEBUG: Debug messages
66 # - ALL: Component's build messages
67 # Usage: CT_DoLog <level> [message]
68 # If message is empty, then stdin will be logged.
70 local max_level LEVEL level cur_l cur_L
72 eval max_level="\${CT_LOG_LEVEL_${CT_LOG_LEVEL_MAX}}"
73 # Set the maximum log level to DEBUG if we have none
74 [ -z "${max_level}" ] && max_level=${CT_LOG_LEVEL_DEBUG}
77 eval level="\${CT_LOG_LEVEL_${LEVEL}}"
83 fi |( IFS="${CR}" # We want the full lines, even leading spaces
89 indent=$((2*CT_STEP_COUNT))
91 case "${CT_LOG_SEE_TOOLS_WARN},${line}" in
92 y,*"warning:"*) cur_L=WARN; cur_l=${CT_LOG_LEVEL_WARN};;
93 y,*"WARNING:"*) cur_L=WARN; cur_l=${CT_LOG_LEVEL_WARN};;
94 *"error:"*) cur_L=ERROR; cur_l=${CT_LOG_LEVEL_ERROR};;
95 *"make["*"]: *** ["*) cur_L=ERROR; cur_l=${CT_LOG_LEVEL_ERROR};;
96 *) cur_L="${LEVEL}"; cur_l="${level}";;
98 # There will always be a log file (stdout, fd #1), be it /dev/null
99 printf "[%-5s]%*s%s%s\n" "${cur_L}" "${indent}" " " "${line}"
100 if [ ${cur_l} -le ${max_level} ]; then
101 # Only print to console (fd #6) if log level is high enough.
102 printf "\r[%-5s]%*s%s%s\n" "${cur_L}" "${indent}" " " "${line}" >&6
104 if [ "${CT_LOG_PROGRESS_BAR}" = "y" ]; then
105 printf "\r[%02d:%02d] %s " $((SECONDS/60)) $((SECONDS%60)) "${_prog_bar[$((_prog_bar_cpt/10))]}" >&6
106 _prog_bar_cpt=$(((_prog_bar_cpt+1)%40))
114 # Execute an action, and log its messages
115 # Usage: [VAR=val...] CT_DoExecLog <level> <command [parameters...]>
119 CT_DoLog DEBUG "==> Executing: '${*}'"
120 "${@}" 2>&1 |CT_DoLog "${level}"
123 # Tail message to be logged whatever happens
124 # Usage: CT_DoEnd <level>
128 CT_STOP_DATE=$(CT_DoDate +%s%N)
129 CT_STOP_DATE_HUMAN=$(CT_DoDate +%Y%m%d.%H%M%S)
130 if [ "${level}" != "ERROR" ]; then
131 CT_DoLog "${level:-INFO}" "Build completed at ${CT_STOP_DATE_HUMAN}"
133 elapsed=$((CT_STOP_DATE-CT_STAR_DATE))
134 elapsed_min=$((elapsed/(60*1000*1000*1000)))
135 elapsed_sec=$(printf "%02d" $(((elapsed%(60*1000*1000*1000))/(1000*1000*1000))))
136 elapsed_csec=$(printf "%02d" $(((elapsed%(1000*1000*1000))/(10*1000*1000))))
137 CT_DoLog ${level:-INFO} "(elapsed: ${elapsed_min}:${elapsed_sec}.${elapsed_csec})"
140 # Abort the execution with an error message
141 # Usage: CT_Abort <message>
147 # Test a condition, and print a message if satisfied
148 # Usage: CT_Test <message> <tests>
153 CT_DoLog DEBUG "Testing '! ( $* )'"
154 test "$@" && CT_DoLog WARN "$m"
158 # Test a condition, and abort with an error message if satisfied
159 # Usage: CT_TestAndAbort <message> <tests>
163 CT_DoLog DEBUG "Testing '! ( $* )'"
164 test "$@" && CT_Abort "$m"
168 # Test a condition, and abort with an error message if not satisfied
169 # Usage: CT_TestAndAbort <message> <tests>
173 CT_DoLog DEBUG "Testing '$*'"
174 test "$@" || CT_Abort "$m"
178 # Test the presence of a tool, or abort if not found
179 # Usage: CT_HasOrAbort <tool>
181 CT_TestAndAbort "'${1}' not found and needed for successful toolchain build." -z "$(CT_Which "${1}")"
185 # Search a program: wrap "which" for those system where
186 # "which" verbosely says there is no match (Mandriva is
188 # Usage: CT_Which <filename>
190 which "$1" 2>/dev/null || true
193 # Get current date with nanosecond precision
194 # On those system not supporting nanosecond precision, faked with rounding down
195 # to the highest entire second
196 # Usage: CT_DoDate <fmt>
198 date "$1" |sed -r -e 's/N$/000000000/;'
202 CT_STEP_MESSAGE[${CT_STEP_COUNT}]="<none>"
203 # Memorise a step being done so that any error is caught
204 # Usage: CT_DoStep <loglevel> <message>
206 local start=$(CT_DoDate +%s%N)
207 CT_DoLog "$1" "================================================================="
209 CT_STEP_COUNT=$((CT_STEP_COUNT+1))
210 CT_STEP_LEVEL[${CT_STEP_COUNT}]="$1"; shift
211 CT_STEP_START[${CT_STEP_COUNT}]="${start}"
212 CT_STEP_MESSAGE[${CT_STEP_COUNT}]="$1"
216 # End the step just being done
219 local stop=$(CT_DoDate +%s%N)
220 local duration=$(printf "%032d" $((stop-${CT_STEP_START[${CT_STEP_COUNT}]})) |sed -r -e 's/([[:digit:]]{2})[[:digit:]]{7}$/\.\1/; s/^0+//; s/^\./0\./;')
221 local elapsed=$(printf "%02d:%02d" $((SECONDS/60)) $((SECONDS%60)))
222 local level="${CT_STEP_LEVEL[${CT_STEP_COUNT}]}"
223 local message="${CT_STEP_MESSAGE[${CT_STEP_COUNT}]}"
224 CT_STEP_COUNT=$((CT_STEP_COUNT-1))
225 CT_DoLog "${level}" "${message}: done in ${duration}s (at ${elapsed})"
229 # Pushes into a directory, and pops back
231 pushd "$1" >/dev/null 2>&1
237 # Creates a temporary directory
238 # $1: variable to assign to
239 # Usage: CT_MktempDir foo
241 # Some mktemp do not allow more than 6 Xs
242 eval "$1"=$(mktemp -q -d "${CT_BUILD_DIR}/tmp.XXXXXX")
243 CT_TestOrAbort "Could not make temporary directory" -n "${!1}" -a -d "${!1}"
244 CT_DoLog DEBUG "Made temporary directory '${!1}'"
248 # Removes one or more directories, even if it is read-only, or its parent is
249 # Usage: CT_DoForceRmdir dir [...]
253 for dir in "${@}"; do
254 [ -d "${dir}" ] || continue
257 mode="$(stat -c '%a' "$(dirname "${dir}")")"
260 mode="$(stat -f '%Lp' "$(dirname "${dir}")")"
263 CT_Abort "Unhandled host OS $CT_SYS_OS"
266 CT_DoExecLog ALL chmod u+w "$(dirname "${dir}")"
267 CT_DoExecLog ALL chmod -R u+w "${dir}"
268 CT_DoExecLog ALL rm -rf "${dir}"
269 CT_DoExecLog ALL chmod ${mode} "$(dirname "${dir}")"
273 # Echoes the specified string on stdout until the pipe breaks.
276 # Usage: CT_DoYes "" |make oldconfig
281 # Add the specified directory to LD_LIBRARY_PATH, and export it
282 # If the specified patch is already present, just export
284 # $2: add as 'first' or 'last' path, 'first' is assumed if $2 is empty
285 # Usage CT_SetLibPath /some/where/lib [first|last]
290 case ":${LD_LIBRARY_PATH}:" in
294 CT_DoLog DEBUG "Adding '${path}' at end of LD_LIBRARY_PATH"
295 LD_LIBRARY_PATH="${LD_LIBRARY_PATH:+${LD_LIBRARY_PATH}:}${path}"
298 CT_DoLog DEBUG "Adding '${path}' at start of LD_LIBRARY_PATH"
299 LD_LIBRARY_PATH="${path}${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}"
302 CT_Abort "Incorrect position '${pos}' to add '${path}' to LD_LIBRARY_PATH"
307 CT_DoLog DEBUG "==> LD_LIBRARY_PATH='${LD_LIBRARY_PATH}'"
308 export LD_LIBRARY_PATH
311 # Get the file name extension of a component
312 # Usage: CT_GetFileExtension <component_name-component_version> [extension]
313 # If found, echoes the extension to stdout, and return 0
314 # If not found, echoes nothing on stdout, and return !0.
315 CT_GetFileExtension() {
321 # we need to also check for an empty extension for those very
322 # peculiar components that don't have one (such as sstrip from
324 for ext in ${first_ext} .tar.gz .tar.bz2 .tgz .tar /.git ''; do
325 if [ -e "${CT_TARBALLS_DIR}/${file}${ext}" ]; then
334 # Download an URL using wget
335 # Usage: CT_DoGetFileWget <URL>
337 # Need to return true because it is legitimate to not find the tarball at
338 # some of the provided URLs (think about snapshots, different layouts for
339 # different gcc versions, etc...)
340 # Some (very old!) FTP server might not support the passive mode, thus
342 # With automated download as we are doing, it can be very dangerous to use
343 # -c to continue the downloads. It's far better to simply overwrite the
345 # Some company networks have firewalls to connect to the internet, but it's
346 # not easy to detect them, and wget does not timeout by default while
347 # connecting, so force a global ${CT_CONNECT_TIMEOUT}-second timeout.
348 CT_DoExecLog ALL wget -T ${CT_CONNECT_TIMEOUT} -nc --progress=dot:binary --tries=3 --passive-ftp "$1" \
349 || CT_DoExecLog ALL wget -T ${CT_CONNECT_TIMEOUT} -nc --progress=dot:binary --tries=3 "$1" \
353 # Download an URL using curl
354 # Usage: CT_DoGetFileCurl <URL>
356 # Note: comments about wget method (above) are also valid here
357 # Plus: no good progress indicator is available with curl,
359 CT_DoExecLog ALL curl -s --ftp-pasv -O --retry 3 "$1" --connect-timeout ${CT_CONNECT_TIMEOUT} -L -f \
360 || CT_DoExecLog ALL curl -s -O --retry 3 "$1" --connect-timeout ${CT_CONNECT_TIMEOUT} -L -f \
364 # Download using aria2
365 # Usage: CT_DoGetFileAria2 <URL>
366 CT_DoGetFileAria2() {
367 # Note: comments about curl method (above) are also valid here
368 # Plus: default progress indicator is a single line, so use verbose log
369 # so that the CT-NG's ouput is 'live'.
370 CT_DoExecLog ALL aria2c --summary-interval=1 -s ${CT_DOWNLOAD_MAX_CHUNKS} -m 3 -t ${CT_CONNECT_TIMEOUT} -p "$1" \
371 || CT_DoExecLog ALL aria2c --summary-interval=1 -s ${CT_DOWNLOAD_MAX_CHUNKS} -m 3 -t ${CT_CONNECT_TIMEOUT} "$1" \
375 # OK, just look if we have them...
376 _aria2c=$(CT_Which aria2c)
377 _wget=$(CT_Which wget)
378 _curl=$(CT_Which curl)
380 # Wrapper function to call one of, in order of preference:
384 # Usage: CT_DoGetFile <URL>
386 if [ -n "${_aria2c}" ]; then
387 CT_DoGetFileAria2 "$1"
388 elif [ -n "${_curl}" ]; then
389 CT_DoGetFileCurl "$1"
390 elif [ -n "${_wget}" ]; then
391 CT_DoGetFileWget "$1"
393 CT_Abort "Could find neither wget nor curl"
397 # This function tries to retrieve a tarball form a local directory
398 # Usage: CT_GetLocal <basename> [.extension]
404 # Do we already have it in *our* tarballs dir?
405 if ext="$( CT_GetFileExtension "${basename}" ${first_ext} )"; then
406 CT_DoLog DEBUG "Already have '${basename}'"
410 if [ -n "${CT_LOCAL_TARBALLS_DIR}" ]; then
411 CT_DoLog DEBUG "Trying to retrieve an already downloaded copy of '${basename}'"
412 # We'd rather have a bzip2'ed tarball, then gzipped tarball, plain tarball,
413 # or, as a failover, a file without extension.
414 for ext in ${first_ext} .tar.bz2 .tar.gz .tgz .tar ''; do
415 CT_DoLog DEBUG "Trying '${CT_LOCAL_TARBALLS_DIR}/${basename}${ext}'"
416 if [ -r "${CT_LOCAL_TARBALLS_DIR}/${basename}${ext}" -a \
417 "${CT_FORCE_DOWNLOAD}" != "y" ]; then
418 CT_DoLog DEBUG "Got '${basename}' from local storage"
419 CT_DoExecLog ALL ln -s "${CT_LOCAL_TARBALLS_DIR}/${basename}${ext}" "${CT_TARBALLS_DIR}/${basename}${ext}"
427 # This function saves the specified to local storage if possible,
428 # and if so, symlinks it for later usage
429 # Usage: CT_SaveLocal </full/path/file.name>
432 local basename="${file##*/}"
434 if [ "${CT_SAVE_TARBALLS}" = "y" ]; then
435 CT_DoLog EXTRA "Saving '${basename}' to local storage"
436 # The file may already exist if downloads are forced: remove it first
437 CT_DoExecLog ALL rm -f "${CT_LOCAL_TARBALLS_DIR}/${basename}"
438 CT_DoExecLog ALL mv -f "${file}" "${CT_LOCAL_TARBALLS_DIR}"
439 CT_DoExecLog ALL ln -s "${CT_LOCAL_TARBALLS_DIR}/${basename}" "${file}"
443 # Download the file from one of the URLs passed as argument
444 # Usage: CT_GetFile <basename> [.extension] <url> [url ...]
447 local url URLS LAN_URLS
451 # If next argument starts with a dot, then this is not an URL,
452 # and we can consider that it is a preferred extension.
459 # Does it exist localy?
460 CT_GetLocal "${file}" ${first_ext} && return 0 || true
463 # Try to retrieve the file
464 CT_DoLog EXTRA "Retrieving '${file}'"
465 CT_Pushd "${CT_TARBALLS_DIR}"
469 # Add URLs on the LAN mirror
471 if [ "${CT_USE_MIRROR}" = "y" ]; then
472 CT_TestOrAbort "Please set the mirror base URL" -n "${CT_MIRROR_BASE_URL}"
473 LAN_URLS="${LAN_URLS} ${CT_MIRROR_BASE_URL}/${file%-*}"
474 LAN_URLS="${LAN_URLS} ${CT_MIRROR_BASE_URL}"
476 if [ "${CT_PREFER_MIRROR}" = "y" ]; then
477 CT_DoLog DEBUG "Pre-pending LAN mirror URLs"
478 URLS="${LAN_URLS} ${URLS}"
480 CT_DoLog DEBUG "Appending LAN mirror URLs"
481 URLS="${URLS} ${LAN_URLS}"
485 # Scan all URLs in turn, and try to grab a tarball from there
486 # Do *not* try git trees (ext=/.git), this is handled in a specific
488 for ext in ${first_ext} .tar.bz2 .tar.gz .tgz .tar ''; do
489 # Try all urls in turn
490 for url in ${URLS}; do
491 CT_DoLog DEBUG "Trying '${url}/${file}${ext}'"
492 CT_DoGetFile "${url}/${file}${ext}"
493 if [ -f "${file}${ext}" ]; then
494 CT_DoLog DEBUG "Got '${file}' from the Internet"
495 CT_SaveLocal "${CT_TARBALLS_DIR}/${file}${ext}"
502 CT_Abort "Could not retrieve '${file}'."
505 # Checkout from CVS, and build the associated tarball
506 # The tarball will be called ${basename}.tar.bz2
507 # Prerequisite: either the server does not require password,
508 # or the user must already be logged in.
509 # 'tag' is the tag to retrieve. Must be specified, but can be empty.
510 # If dirname is specified, then module will be renamed to dirname
511 # prior to building the tarball.
512 # Usage: CT_GetCVS <basename> <url> <module> <tag> [dirname[=subdir]]
513 # Note: if '=subdir' is given, then it is used instead of 'module'.
518 local tag="${4:+-r ${4}}"
522 # Does it exist localy?
523 CT_GetLocal "${basename}" && return 0 || true
526 CT_DoLog EXTRA "Retrieving '${basename}'"
529 CT_Pushd "${tmp_dir}"
531 CT_DoExecLog ALL cvs -z 9 -d "${uri}" co -P ${tag} "${module}"
532 if [ -n "${dirname}" ]; then
535 CT_DoExecLog DEBUG mv "${dirname#*=}" "${dirname%%=*}"
536 CT_DoExecLog ALL tar cjf "${CT_TARBALLS_DIR}/${basename}.tar.bz2" "${dirname%%=*}"
539 CT_DoExecLog ALL mv "${module}" "${dirname}"
540 CT_DoExecLog ALL tar cjf "${CT_TARBALLS_DIR}/${basename}.tar.bz2" "${dirname:-${module}}"
544 CT_SaveLocal "${CT_TARBALLS_DIR}/${basename}.tar.bz2"
547 CT_DoExecLog ALL rm -rf "${tmp_dir}"
550 # Check out from SVN, and build the associated tarball
551 # The tarball will be called ${basename}.tar.bz2
552 # Prerequisite: either the server does not require password,
553 # or the user must already be logged in.
554 # 'rev' is the revision to retrieve
555 # Usage: CT_GetSVN <basename> <url> [rev]
561 # Does it exist localy?
562 CT_GetLocal "${basename}" && return 0 || true
565 CT_DoLog EXTRA "Retrieving '${basename}'"
568 CT_Pushd "${tmp_dir}"
570 CT_DoExecLog ALL svn export ${rev:+-r ${rev}} "${uri}" "${basename}"
571 CT_DoExecLog ALL tar cjf "${CT_TARBALLS_DIR}/${basename}.tar.bz2" "${basename}"
572 CT_SaveLocal "${CT_TARBALLS_DIR}/${basename}.tar.bz2"
575 CT_DoExecLog ALL rm -rf "${tmp_dir}"
579 # Tries the given URLs in turn until one can get cloned. No tarball will be created.
580 # Prerequisites: either the server does not require password,
581 # or the user has already taken any action to authenticate to the server.
582 # The cloned tree will *not* be stored in the local tarballs dir!
583 # Usage: CT_GetGit <basename> <url [url ...]>
585 local basename="$1"; shift
589 # Do we have it in our tarballs dir?
590 if [ -d "${CT_TARBALLS_DIR}/${basename}/.git" ]; then
591 CT_DoLog EXTRA "Updating git tree '${basename}'"
592 CT_Pushd "${CT_TARBALLS_DIR}/${basename}"
593 CT_DoExecLog ALL git pull
596 CT_DoLog EXTRA "Retrieving git tree '${basename}'"
597 for url in "${@}"; do
598 CT_DoLog ALL "Trying to clone from '${url}'"
599 CT_DoForceRmdir "${CT_TARBALLS_DIR}/${basename}"
600 if git clone "${url}" "${CT_TARBALLS_DIR}/${basename}" 2>&1 |CT_DoLog ALL; then
605 CT_TestOrAbort "Could not clone '${basename}'" ${cloned} -ne 0
610 # Some tarballs need to be extracted in specific places. Eg.: glibc addons
611 # must be extracted in the glibc directory; uCLibc locales must be extracted
612 # in the extra/locale sub-directory of uClibc. This is taken into account
613 # by the caller, that did a 'cd' into the correct path before calling us
614 # and sets nochdir to 'nochdir'.
615 # Note also that this function handles the git trees!
616 # Usage: CT_Extract <basename> [nochdir] [options]
617 # where 'options' are dependent on the source (eg. git branch/tag...)
623 if [ "${nochdir}" = "nochdir" ]; then
627 nochdir="${CT_SRC_DIR}"
633 if ! ext="$(CT_GetFileExtension "${basename}")"; then
634 CT_Abort "'${basename}' not found in '${CT_TARBALLS_DIR}'"
636 local full_file="${CT_TARBALLS_DIR}/${basename}${ext}"
638 # Check if already extracted
639 if [ -e "${CT_SRC_DIR}/.${basename}.extracted" ]; then
640 CT_DoLog DEBUG "Already extracted '${basename}'"
644 # Check if previously partially extracted
645 if [ -e "${CT_SRC_DIR}/.${basename}.extracting" ]; then
646 CT_DoLog ERROR "The '${basename}' sources were partially extracted."
647 CT_DoLog ERROR "Please remove first:"
648 CT_DoLog ERROR " - the source dir for '${basename}', in '${CT_SRC_DIR}'"
649 CT_DoLog ERROR " - the file '${CT_SRC_DIR}/.${basename}.extracting'"
650 CT_Abort "I'll stop now to avoid any carnage..."
652 CT_DoExecLog DEBUG touch "${CT_SRC_DIR}/.${basename}.extracting"
654 CT_Pushd "${nochdir}"
656 CT_DoLog EXTRA "Extracting '${basename}'"
658 .tar.bz2) CT_DoExecLog ALL tar xvjf "${full_file}";;
659 .tar.gz|.tgz) CT_DoExecLog ALL tar xvzf "${full_file}";;
660 .tar) CT_DoExecLog ALL tar xvf "${full_file}";;
661 /.git) CT_ExtractGit "${basename}" "${@}";;
662 *) CT_Abort "Don't know how to handle '${basename}${ext}': unknown extension";;
665 # Some tarballs have read-only files... :-(
666 # Because of nochdir, we don't know where we are, so chmod all
668 CT_DoExecLog DEBUG chmod -R u+w "${CT_SRC_DIR}"
670 # Don't mark as being extracted for git
673 *) CT_DoExecLog DEBUG touch "${CT_SRC_DIR}/.${basename}.extracted";;
675 CT_DoExecLog DEBUG rm -f "${CT_SRC_DIR}/.${basename}.extracting"
680 # Create a working git clone
681 # Usage: CT_ExtractGit <basename> [ref]
682 # where 'ref' is the reference to use:
683 # the full name of a branch, like "remotes/origin/branch_name"
684 # a date as understandable by git, like "YYYY-MM-DD[ hh[:mm[:ss]]]"
687 local basename="${1}"
692 # pushd now to be able to get git revlist in case ref is a date
693 clone_dir="${CT_TARBALLS_DIR}/${basename}"
694 CT_Pushd "${clone_dir}"
696 # What kind of reference is ${ref} ?
697 if [ -z "${ref}" ]; then
698 # Don't update the clone, keep as-is
700 elif git tag |grep -E "^${ref}$" >/dev/null 2>&1; then
702 elif git branch -a --no-color |grep -E "^. ${ref}$" >/dev/null 2>&1; then
704 elif date -d "${ref}" >/dev/null 2>&1; then
706 ref=$(git rev-list -n1 --before="${ref}")
708 CT_Abort "Reference '${ref}' is an incorrect git reference: neither tag, branch nor date"
711 CT_DoExecLog DEBUG rm -f "${CT_SRC_DIR}/${basename}"
712 CT_DoExecLog ALL ln -sf "${clone_dir}" "${CT_SRC_DIR}/${basename}"
714 case "${ref_type}" in
716 *) CT_DoExecLog ALL git checkout "${ref}";;
722 # Patches the specified component
723 # See CT_Extract, above, for explanations on 'nochdir'
724 # Usage: CT_Patch [nochdir] <packagename> <packageversion>
725 # If the package directory is *not* packagename-packageversion, then
726 # the caller must cd into the proper directory first, and call us
737 local bundled_patch_dir
738 local local_patch_dir
740 if [ "${nochdir}" = "nochdir" ]; then
744 pkgdir="${pkgname}-${version}"
749 pkgdir="${pkgname}-${version}"
750 nochdir="${CT_SRC_DIR}/${pkgdir}"
753 # Check if already patched
754 if [ -e "${CT_SRC_DIR}/.${pkgdir}.patched" ]; then
755 CT_DoLog DEBUG "Already patched '${pkgdir}'"
759 # Check if already partially patched
760 if [ -e "${CT_SRC_DIR}/.${pkgdir}.patching" ]; then
761 CT_DoLog ERROR "The '${pkgdir}' sources were partially patched."
762 CT_DoLog ERROR "Please remove first:"
763 CT_DoLog ERROR " - the source dir for '${pkgdir}', in '${CT_SRC_DIR}'"
764 CT_DoLog ERROR " - the file '${CT_SRC_DIR}/.${pkgdir}.extracted'"
765 CT_DoLog ERROR " - the file '${CT_SRC_DIR}/.${pkgdir}.patching'"
766 CT_Abort "I'll stop now to avoid any carnage..."
768 touch "${CT_SRC_DIR}/.${pkgdir}.patching"
770 CT_Pushd "${nochdir}"
772 CT_DoLog EXTRA "Patching '${pkgdir}'"
774 bundled_patch_dir="${CT_LIB_DIR}/patches/${pkgname}/${version}"
775 local_patch_dir="${CT_LOCAL_PATCH_DIR}/${pkgname}/${version}"
777 case "${CT_PATCH_ORDER}" in
778 bundled) patch_dirs=("${bundled_patch_dir}");;
779 local) patch_dirs=("${local_patch_dir}");;
780 bundled,local) patch_dirs=("${bundled_patch_dir}" "${local_patch_dir}");;
781 local,bundled) patch_dirs=("${local_patch_dir}" "${bundled_patch_dir}");;
785 for d in "${patch_dirs[@]}"; do
786 CT_DoLog DEBUG "Looking for patches in '${d}'..."
787 if [ -n "${d}" -a -d "${d}" ]; then
788 for p in "${d}"/*.patch; do
789 if [ -f "${p}" ]; then
790 CT_DoLog DEBUG "Applying patch '${p}'"
791 CT_DoExecLog ALL patch --no-backup-if-mismatch -g0 -F1 -p1 -f <"${p}"
794 if [ "${CT_PATCH_SINGLE}" = "y" ]; then
800 if [ "${CT_OVERIDE_CONFIG_GUESS_SUB}" = "y" ]; then
801 CT_DoLog ALL "Overiding config.guess and config.sub"
802 for cfg in config_guess config_sub; do
803 eval ${cfg}="${CT_LIB_DIR}/scripts/${cfg/_/.}"
804 [ -e "${CT_TOP_DIR}/scripts/${cfg/_/.}" ] && eval ${cfg}="${CT_TOP_DIR}/scripts/${cfg/_/.}"
805 # Can't use CT_DoExecLog because of the '{} \;' to be passed un-mangled to find
806 find . -type f -name "${cfg/_/.}" -exec cp -v "${!cfg}" {} \; |CT_DoLog ALL
810 CT_DoExecLog DEBUG touch "${CT_SRC_DIR}/.${pkgdir}.patched"
811 CT_DoExecLog DEBUG rm -f "${CT_SRC_DIR}/.${pkgdir}.patching"
816 # Two wrappers to call config.(guess|sub) either from CT_TOP_DIR or CT_LIB_DIR.
817 # Those from CT_TOP_DIR, if they exist, will be be more recent than those from CT_LIB_DIR.
819 if [ -x "${CT_TOP_DIR}/scripts/config.guess" ]; then
820 "${CT_TOP_DIR}/scripts/config.guess"
822 "${CT_LIB_DIR}/scripts/config.guess"
827 if [ -x "${CT_TOP_DIR}/scripts/config.sub" ]; then
828 "${CT_TOP_DIR}/scripts/config.sub" "$@"
830 "${CT_LIB_DIR}/scripts/config.sub" "$@"
834 # Compute the target tuple from what is provided by the user
835 # Usage: CT_DoBuildTargetTuple
836 # In fact this function takes the environment variables to build the target
837 # tuple. It is needed both by the normal build sequence, as well as the
838 # sample saving sequence.
839 CT_DoBuildTargetTuple() {
840 # Set the endianness suffix, and the default endianness gcc option
841 case "${CT_ARCH_BE},${CT_ARCH_LE}" in
842 y,) target_endian_eb=eb
844 CT_ARCH_ENDIAN_CFLAG="-mbig-endian"
845 CT_ARCH_ENDIAN_LDFLAG="-EB"
847 ,y) target_endian_eb=
849 CT_ARCH_ENDIAN_CFLAG="-mlittle-endian"
850 CT_ARCH_ENDIAN_LDFLAG="-EL"
854 # Build the default architecture tuple part
855 CT_TARGET_ARCH="${CT_ARCH}"
857 # Set defaults for the system part of the tuple. Can be overriden
858 # by architecture-specific values.
860 *glibc) CT_TARGET_SYS=gnu;;
861 uClibc) CT_TARGET_SYS=uclibc;;
862 *) CT_TARGET_SYS=elf;;
865 # Set the default values for ARCH, ABI, CPU, TUNE, FPU and FLOAT
866 unset CT_ARCH_ARCH_CFLAG CT_ARCH_ABI_CFLAG CT_ARCH_CPU_CFLAG CT_ARCH_TUNE_CFLAG CT_ARCH_FPU_CFLAG CT_ARCH_FLOAT_CFLAG
867 unset CT_ARCH_WITH_ARCH CT_ARCH_WITH_ABI CT_ARCH_WITH_CPU CT_ARCH_WITH_TUNE CT_ARCH_WITH_FPU CT_ARCH_WITH_FLOAT
868 [ "${CT_ARCH_ARCH}" ] && { CT_ARCH_ARCH_CFLAG="-march=${CT_ARCH_ARCH}"; CT_ARCH_WITH_ARCH="--with-arch=${CT_ARCH_ARCH}"; }
869 [ "${CT_ARCH_ABI}" ] && { CT_ARCH_ABI_CFLAG="-mabi=${CT_ARCH_ABI}"; CT_ARCH_WITH_ABI="--with-abi=${CT_ARCH_ABI}"; }
870 [ "${CT_ARCH_CPU}" ] && { CT_ARCH_CPU_CFLAG="-mcpu=${CT_ARCH_CPU}"; CT_ARCH_WITH_CPU="--with-cpu=${CT_ARCH_CPU}"; }
871 [ "${CT_ARCH_TUNE}" ] && { CT_ARCH_TUNE_CFLAG="-mtune=${CT_ARCH_TUNE}"; CT_ARCH_WITH_TUNE="--with-tune=${CT_ARCH_TUNE}"; }
872 [ "${CT_ARCH_FPU}" ] && { CT_ARCH_FPU_CFLAG="-mfpu=${CT_ARCH_FPU}"; CT_ARCH_WITH_FPU="--with-fpu=${CT_ARCH_FPU}"; }
873 [ "${CT_ARCH_FLOAT_SW}" ] && { CT_ARCH_FLOAT_CFLAG="-msoft-float"; CT_ARCH_WITH_FLOAT="--with-float=soft"; }
875 # Build the default kernel tuple part
876 CT_TARGET_KERNEL="${CT_KERNEL}"
878 # Overide the default values with the components specific settings
880 CT_DoKernelTupleValues
882 # Finish the target tuple construction
883 CT_TARGET="${CT_TARGET_ARCH}"
884 CT_TARGET="${CT_TARGET}${CT_TARGET_VENDOR:+-${CT_TARGET_VENDOR}}"
885 CT_TARGET="${CT_TARGET}${CT_TARGET_KERNEL:+-${CT_TARGET_KERNEL}}"
886 CT_TARGET="${CT_TARGET}${CT_TARGET_SYS:+-${CT_TARGET_SYS}}"
890 if [ -n "${CT_TARGET_ALIAS_SED_EXPR}" ]; then
891 __sed_alias=$(echo "${CT_TARGET}" |sed -r -e "${CT_TARGET_ALIAS_SED_EXPR}")
893 case ":${CT_TARGET_VENDOR}:${CT_TARGET_ALIAS}:${__sed_alias}:" in
894 :*" "*:*:*:) CT_Abort "Don't use spaces in the vendor string, it breaks things.";;
895 :*"-"*:*:*:) CT_Abort "Don't use dashes in the vendor string, it breaks things.";;
896 :*:*" "*:*:) CT_Abort "Don't use spaces in the target alias, it breaks things.";;
897 :*:*:*" "*:) CT_Abort "Don't use spaces in the target sed transform, it breaks things.";;
901 CT_TARGET=$(CT_DoConfigSub "${CT_TARGET}")
902 # Prepare the target CFLAGS
903 CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_ENDIAN_CFLAG}"
904 CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_ARCH_CFLAG}"
905 CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_ABI_CFLAG}"
906 CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_CPU_CFLAG}"
907 CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_TUNE_CFLAG}"
908 CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_FPU_CFLAG}"
909 CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_FLOAT_CFLAG}"
911 # Now on for the target LDFLAGS
912 CT_ARCH_TARGET_LDFLAGS="${CT_ARCH_TARGET_LDFLAGS} ${CT_ARCH_ENDIAN_LDFLAG}"
915 # This function does pause the build until the user strikes "Return"
916 # Usage: CT_DoPause [optional_message]
919 local message="${1:-Pausing for your pleasure}"
920 CT_DoLog INFO "${message}"
921 read -p "Press 'Enter' to continue, or Ctrl-C to stop..." foo >&6
925 # This function creates a tarball of the specified directory, but
927 # Usage: CT_DoTarballIfExists <dir> <tarball_basename> [extra_tar_options [...]]
928 CT_DoTarballIfExists() {
932 local -a extra_tar_opts=( "$@" )
935 case "${CT_DEBUG_CT_SAVE_STEPS_GZIP}" in
936 y) compress=( gzip -c -3 - ); tar_ext=.gz;;
937 *) compress=( cat - ); tar_ext=;;
940 if [ -d "${dir}" ]; then
941 CT_DoLog DEBUG " Saving '${dir}'"
942 { tar c -C "${dir}" -v -f - "${extra_tar_opts[@]}" . \
943 |"${compress[@]}" >"${tarball}.tar${tar_ext}" ;
944 } 2>&1 |sed -r -e 's/^/ /;' |CT_DoLog DEBUG
946 CT_DoLog DEBUG " Not saving '${dir}': does not exist"
950 # This function extracts a tarball to the specified directory, but
951 # only if the tarball exists
952 # Usage: CT_DoTarballIfExists <tarball_basename> <dir> [extra_tar_options [...]]
953 CT_DoExtractTarballIfExists() {
957 local -a extra_tar_opts=( "$@" )
960 case "${CT_DEBUG_CT_SAVE_STEPS_GZIP}" in
961 y) uncompress=( gzip -c -d ); tar_ext=.gz;;
962 *) uncompress=( cat ); tar_ext=;;
965 if [ -f "${tarball}.tar${tar_ext}" ]; then
966 CT_DoLog DEBUG " Restoring '${dir}'"
967 CT_DoForceRmdir "${dir}"
968 CT_DoExecLog DEBUG mkdir -p "${dir}"
969 { "${uncompress[@]}" "${tarball}.tar${tar_ext}" \
970 |tar x -C "${dir}" -v -f - "${extra_tar_opts[@]}" ;
971 } 2>&1 |sed -r -e 's/^/ /;' |CT_DoLog DEBUG
973 CT_DoLog DEBUG " Not restoring '${dir}': does not exist"
977 # This function saves the state of the toolchain to be able to restart
979 # Usage: CT_DoSaveState <next_step_name>
981 [ "${CT_DEBUG_CT_SAVE_STEPS}" = "y" ] || return 0
982 local state_name="$1"
983 local state_dir="${CT_STATE_DIR}/${state_name}"
985 # Log this to the log level required by the user
986 CT_DoLog ${CT_LOG_LEVEL_MAX} "Saving state to restart at step '${state_name}'..."
988 rm -rf "${state_dir}"
989 mkdir -p "${state_dir}"
991 CT_DoLog DEBUG " Saving environment and aliases"
992 # We must omit shell functions, and some specific bash variables
993 # that break when restoring the environment, later. We could do
994 # all the processing in the awk script, but a sed is easier...
997 $0~/^[^ ]+ \(\)/ { _p = 0; }
999 $0 == "}" { _p = 1; }
1000 ' |sed -r -e '/^BASH_(ARGC|ARGV|LINENO|SOURCE|VERSINFO)=/d;
1002 /^(FUNCNAME|GROUPS|PPID|SHELLOPTS)=/d;' >"${state_dir}/env.sh"
1004 if [ "${CT_COMPLIBS_SHARED}" != "y" ]; then
1005 # If complibs are not shared, then COMPLIBS_DIR == PREFIX_DIR,
1007 CT_DoTarballIfExists "${CT_COMPLIBS_DIR}" "${state_dir}/complibs_dir"
1009 CT_DoTarballIfExists "${CT_CONFIG_DIR}" "${state_dir}/config_dir"
1010 CT_DoTarballIfExists "${CT_CC_CORE_STATIC_PREFIX_DIR}" "${state_dir}/cc_core_static_prefix_dir"
1011 CT_DoTarballIfExists "${CT_CC_CORE_SHARED_PREFIX_DIR}" "${state_dir}/cc_core_shared_prefix_dir"
1012 CT_DoTarballIfExists "${CT_PREFIX_DIR}" "${state_dir}/prefix_dir" --exclude '*.log'
1014 if [ "${CT_LOG_TO_FILE}" = "y" ]; then
1015 CT_DoLog DEBUG " Saving log file"
1017 case "${CT_DEBUG_CT_SAVE_STEPS_GZIP}" in
1018 y) gzip -3 -c "${CT_LOG_FILE}" >"${state_dir}/log.gz";;
1019 *) cat "${CT_LOG_FILE}" >"${state_dir}/log";;
1021 exec >>"${CT_LOG_FILE}"
1025 # This function restores a previously saved state
1026 # Usage: CT_DoLoadState <state_name>
1028 local state_name="$1"
1029 local state_dir="${CT_STATE_DIR}/${state_name}"
1030 local old_RESTART="${CT_RESTART}"
1031 local old_STOP="${CT_STOP}"
1033 CT_TestOrAbort "The previous build did not reach the point where it could be restarted at '${CT_RESTART}'" -d "${state_dir}"
1035 # We need to do something special with the log file!
1036 if [ "${CT_LOG_TO_FILE}" = "y" ]; then
1037 exec >"${state_dir}/tail.log"
1040 # Log this to the log level required by the user
1041 CT_DoLog ${CT_LOG_LEVEL_MAX} "Restoring state at step '${state_name}', as requested."
1043 CT_DoExtractTarballIfExists "${state_dir}/prefix_dir" "${CT_PREFIX_DIR}"
1044 CT_DoExtractTarballIfExists "${state_dir}/cc_core_shared_prefix_dir" "${CT_CC_CORE_SHARED_PREFIX_DIR}"
1045 CT_DoExtractTarballIfExists "${state_dir}/cc_core_static_prefix_dir" "${CT_CC_CORE_STATIC_PREFIX_DIR}"
1046 CT_DoExtractTarballIfExists "${state_dir}/config_dir" "${CT_CONFIG_DIR}"
1047 if [ "${CT_COMPLIBS_SHARED}" != "y" ]; then
1048 # If complibs are not shared, then COMPLIBS_DIR == PREFIX_DIR,
1049 # so do not restore.
1050 CT_DoExtractTarballIfExists "${state_dir}/complibs_dir" "${CT_COMPLIBS_DIR}"
1053 # Restore the environment, discarding any error message
1054 # (for example, read-only bash internals)
1055 CT_DoLog DEBUG " Restoring environment"
1056 . "${state_dir}/env.sh" >/dev/null 2>&1 || true
1058 # Restore the new RESTART and STOP steps
1059 CT_RESTART="${old_RESTART}"
1060 CT_STOP="${old_STOP}"
1061 unset old_stop old_restart
1063 if [ "${CT_LOG_TO_FILE}" = "y" ]; then
1064 CT_DoLog DEBUG " Restoring log file"
1066 case "${CT_DEBUG_CT_SAVE_STEPS_GZIP}" in
1067 y) zcat "${state_dir}/log.gz" >"${CT_LOG_FILE}";;
1068 *) cat "${state_dir}/log" >"${CT_LOG_FILE}";;
1070 cat "${state_dir}/tail.log" >>"${CT_LOG_FILE}"
1071 exec >>"${CT_LOG_FILE}"
1072 rm -f "${state_dir}/tail.log"