scripts/functions: Fix CT_ExtractGit function.
Change CT_ExtractGit so that it clones the repository, instead of just
symlinking it. After cloning, any given ref is checked out, or if no
ref is given, the HEAD of the repository is checked out.
This makes CT_Extract behave similar for git repositories as it does
for tarballs, so that it for example can be used for passing glibc-ports
as a git repository.
Signed-off-by: "Esben Haabendal" <esben.haabendal@prevas.dk>
[yann.morin.1998@anciens.enib.fr: fix incomplete var rename]
Signed-off-by: "Yann E. MORIN" <yann.morin.1998@anciens.enib.fr>
1 # This file contains some usefull common functions -*- sh -*-
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
14 # Bail out early in subshell, the upper level shell will act accordingly.
15 [ ${BASH_SUBSHELL} -eq 0 ] || exit $ret
17 # Print steps backtrace
18 step_depth=${CT_STEP_COUNT}
22 for((step=step_depth; step>1; step--)); do
23 CT_DoLog ERROR ">> ${intro} in step '${CT_STEP_MESSAGE[${step}]}'"
27 # Print functions backtrace
28 intro="Error happened in"
31 for((depth=1; ${BASH_LINENO[$((${depth}-1))]}>0; depth++)); do
32 file="${BASH_SOURCE[${depth}]#${CT_LIB_DIR}/}"
35 *) line="@${BASH_LINENO[${depth}-1]}"
37 func="${FUNCNAME[${depth}]}"
38 CT_DoLog ERROR ">> ${intro}: ${func}[${file}${line}]"
42 # Help diagnose the error
44 if [ "${CT_LOG_TO_FILE}" = "y" ]; then
45 CT_DoLog ERROR ">> For more info on this error, look at the file: '${tmp_log_file#${CT_TOP_DIR}/}'"
47 CT_DoLog ERROR ">> There is a list of known issues, some with workarounds, in:"
48 CT_DoLog ERROR ">> '${CT_DOC_DIR#${CT_TOP_DIR}/}/B - Known issues.txt'"
51 CT_DoLog ERROR "Build failed in step '${CT_STEP_MESSAGE[${CT_STEP_COUNT}]}'"
58 # Install the fault handler
61 # Inherit the fault handler in subshells and functions
64 # Make pipes fail on the _first_ failed command
65 # Not supported on bash < 3.x, but we need it, so drop the obsoleting bash-2.x
68 # Don't hash commands' locations, and search every time it is requested.
69 # This is slow, but needed because of the static/shared core gcc which shall
70 # always match to shared if it exists, and only fallback to static if the
75 # - first of all, save stdout so we can see the live logs: fd #6
77 # - then point stdout to the log file
78 tmp_log_file="${CT_TOP_DIR}/build.log"
79 rm -f "${tmp_log_file}"
80 exec >>"${tmp_log_file}"
82 # The different log levels:
93 # Make it easy to use \n and !
97 # A function to log what is happening
98 # Different log level are available:
99 # - ERROR: A serious, fatal error occurred
100 # - WARN: A non fatal, non serious error occurred, take your responsbility with the generated build
101 # - INFO: Informational messages
102 # - EXTRA: Extra informational messages
103 # - CFG: Output of various "./configure"-type scripts
104 # - FILE: File / archive unpacking.
105 # - STATE: State save & restore
106 # - ALL: Component's build messages
107 # - DEBUG: Internal debug messages
108 # Usage: CT_DoLog <level> [message]
109 # If message is empty, then stdin will be logged.
111 local max_level LEVEL level cur_l cur_L
113 eval max_level="\${CT_LOG_LEVEL_${CT_LOG_LEVEL_MAX}}"
114 # Set the maximum log level to DEBUG if we have none
115 [ -z "${max_level}" ] && max_level=${CT_LOG_LEVEL_DEBUG}
118 eval level="\${CT_LOG_LEVEL_${LEVEL}}"
120 if [ $# -eq 0 ]; then
124 fi |( IFS="${CR}" # We want the full lines, even leading spaces
130 indent=$((2*CT_STEP_COUNT))
132 case "${CT_LOG_SEE_TOOLS_WARN},${line}" in
133 y,*"warning:"*) cur_L=WARN; cur_l=${CT_LOG_LEVEL_WARN};;
134 y,*"WARNING:"*) cur_L=WARN; cur_l=${CT_LOG_LEVEL_WARN};;
135 *"error:"*) cur_L=ERROR; cur_l=${CT_LOG_LEVEL_ERROR};;
136 *"make["*"]: *** ["*) cur_L=ERROR; cur_l=${CT_LOG_LEVEL_ERROR};;
137 *) cur_L="${LEVEL}"; cur_l="${level}";;
139 # There will always be a log file (stdout, fd #1), be it /dev/null
140 printf "[%-5s]%*s%s%s\n" "${cur_L}" "${indent}" " " "${line}"
141 if [ ${cur_l} -le ${max_level} ]; then
142 # Only print to console (fd #6) if log level is high enough.
143 printf "${CT_LOG_PROGRESS_BAR:+\r}[%-5s]%*s%s%s\n" "${cur_L}" "${indent}" " " "${line}" >&6
145 if [ "${CT_LOG_PROGRESS_BAR}" = "y" ]; then
146 printf "\r[%02d:%02d] %s " $((SECONDS/60)) $((SECONDS%60)) "${_prog_bar[$((_prog_bar_cpt/10))]}" >&6
147 _prog_bar_cpt=$(((_prog_bar_cpt+1)%40))
155 # Execute an action, and log its messages
156 # It is possible to even log local variable assignments (a-la: var=val ./cmd opts)
157 # Usage: CT_DoExecLog <level> [VAR=val...] <command> [parameters...]
167 *=*) eval export "'${1}'"; shift;;
171 CT_DoLog DEBUG "==> Executing: ${tmp_log}"
172 "${@}" 2>&1 |CT_DoLog "${level}"
174 # Catch failure of the sub-shell
178 # Tail message to be logged whatever happens
179 # Usage: CT_DoEnd <level>
183 CT_STOP_DATE=$(CT_DoDate +%s%N)
184 CT_STOP_DATE_HUMAN=$(CT_DoDate +%Y%m%d.%H%M%S)
185 if [ "${level}" != "ERROR" ]; then
186 CT_DoLog "${level:-INFO}" "Build completed at ${CT_STOP_DATE_HUMAN}"
188 elapsed=$((CT_STOP_DATE-CT_STAR_DATE))
189 elapsed_min=$((elapsed/(60*1000*1000*1000)))
190 elapsed_sec=$(printf "%02d" $(((elapsed%(60*1000*1000*1000))/(1000*1000*1000))))
191 elapsed_csec=$(printf "%02d" $(((elapsed%(1000*1000*1000))/(10*1000*1000))))
192 CT_DoLog ${level:-INFO} "(elapsed: ${elapsed_min}:${elapsed_sec}.${elapsed_csec})"
195 # Remove entries referring to . and other relative paths
196 # Usage: CT_SanitizePath
202 # Only accept absolute paths;
203 # Note: as a special case the empty string in PATH is equivalent to .
204 if [ -n "${p}" -a -z "${p%%/*}" ]; then
205 new="${new}${new:+:}${p}"
211 # Sanitise the directory name contained in the variable passed as argument:
212 # - remove duplicate /
213 # Usage: CT_SanitiseVarDir CT_PREFIX_DIR
214 CT_SanitiseVarDir() {
220 eval "old_dir=\"\${${var}}\""
221 new_dir="$( printf "${old_dir}" \
222 |sed -r -e 's:/+:/:g;' \
224 eval "${var}=\"${new_dir}\""
225 CT_DoLog DEBUG "Sanitised '${var}': '${old_dir}' -> '${new_dir}'"
229 # Abort the execution with an error message
230 # Usage: CT_Abort <message>
236 # Test a condition, and print a message if satisfied
237 # Usage: CT_Test <message> <tests>
242 CT_DoLog DEBUG "Testing '! ( $* )'"
243 test "$@" && CT_DoLog WARN "$m"
247 # Test a condition, and abort with an error message if satisfied
248 # Usage: CT_TestAndAbort <message> <tests>
252 CT_DoLog DEBUG "Testing '! ( $* )'"
253 test "$@" && CT_Abort "$m"
257 # Test a condition, and abort with an error message if not satisfied
258 # Usage: CT_TestAndAbort <message> <tests>
262 CT_DoLog DEBUG "Testing '$*'"
263 test "$@" || CT_Abort "$m"
267 # Test the presence of a tool, or abort if not found
268 # Usage: CT_HasOrAbort <tool>
270 CT_TestAndAbort "'${1}' not found and needed for successful toolchain build." -z "$(CT_Which "${1}")"
274 # Search a program: wrap "which" for those system where
275 # "which" verbosely says there is no match (Mandriva is
277 # Usage: CT_Which <filename>
279 which "$1" 2>/dev/null || true
282 # Get current date with nanosecond precision
283 # On those system not supporting nanosecond precision, faked with rounding down
284 # to the highest entire second
285 # Usage: CT_DoDate <fmt>
287 date "$1" |sed -r -e 's/%?N$/000000000/;'
291 CT_STEP_MESSAGE[${CT_STEP_COUNT}]="<none>"
292 # Memorise a step being done so that any error is caught
293 # Usage: CT_DoStep <loglevel> <message>
295 local start=$(CT_DoDate +%s%N)
296 CT_DoLog "$1" "================================================================="
298 CT_STEP_COUNT=$((CT_STEP_COUNT+1))
299 CT_STEP_LEVEL[${CT_STEP_COUNT}]="$1"; shift
300 CT_STEP_START[${CT_STEP_COUNT}]="${start}"
301 CT_STEP_MESSAGE[${CT_STEP_COUNT}]="$1"
305 # End the step just being done
308 local stop=$(CT_DoDate +%s%N)
309 local duration=$(printf "%032d" $((stop-${CT_STEP_START[${CT_STEP_COUNT}]})) |sed -r -e 's/([[:digit:]]{2})[[:digit:]]{7}$/\.\1/; s/^0+//; s/^\./0\./;')
310 local elapsed=$(printf "%02d:%02d" $((SECONDS/60)) $((SECONDS%60)))
311 local level="${CT_STEP_LEVEL[${CT_STEP_COUNT}]}"
312 local message="${CT_STEP_MESSAGE[${CT_STEP_COUNT}]}"
313 CT_STEP_COUNT=$((CT_STEP_COUNT-1))
314 CT_DoLog "${level}" "${message}: done in ${duration}s (at ${elapsed})"
318 # Pushes into a directory, and pops back
320 pushd "$1" >/dev/null 2>&1
326 # Creates a temporary directory
327 # $1: variable to assign to
328 # Usage: CT_MktempDir foo
330 # Some mktemp do not allow more than 6 Xs
331 eval "$1"=$(mktemp -q -d "${CT_BUILD_DIR}/tmp.XXXXXX")
332 CT_TestOrAbort "Could not make temporary directory" -n "${!1}" -a -d "${!1}"
333 CT_DoLog DEBUG "Made temporary directory '${!1}'"
337 # Removes one or more directories, even if it is read-only, or its parent is
338 # Usage: CT_DoForceRmdir dir [...]
342 for dir in "${@}"; do
343 [ -d "${dir}" ] || continue
346 mode="$(stat -c '%a' "$(dirname "${dir}")")"
349 mode="$(stat -f '%Lp' "$(dirname "${dir}")")"
352 CT_Abort "Unhandled host OS $CT_SYS_OS"
355 CT_DoExecLog ALL chmod u+w "$(dirname "${dir}")"
356 CT_DoExecLog ALL chmod -R u+w "${dir}"
357 CT_DoExecLog ALL rm -rf "${dir}"
358 CT_DoExecLog ALL chmod ${mode} "$(dirname "${dir}")"
362 # Echoes the specified string on stdout until the pipe breaks.
365 # Usage: CT_DoYes "" |make oldconfig
370 # Add the specified directory to LD_LIBRARY_PATH, and export it
371 # If the specified patch is already present, just export
373 # $2: add as 'first' or 'last' path, 'first' is assumed if $2 is empty
374 # Usage CT_SetLibPath /some/where/lib [first|last]
379 case ":${LD_LIBRARY_PATH}:" in
383 CT_DoLog DEBUG "Adding '${path}' at end of LD_LIBRARY_PATH"
384 LD_LIBRARY_PATH="${LD_LIBRARY_PATH:+${LD_LIBRARY_PATH}:}${path}"
387 CT_DoLog DEBUG "Adding '${path}' at start of LD_LIBRARY_PATH"
388 LD_LIBRARY_PATH="${path}${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}"
391 CT_Abort "Incorrect position '${pos}' to add '${path}' to LD_LIBRARY_PATH"
396 CT_DoLog DEBUG "==> LD_LIBRARY_PATH='${LD_LIBRARY_PATH}'"
397 export LD_LIBRARY_PATH
400 # Build up the list of allowed tarball extensions
401 # Add them in the prefered order; most preferred comes first
402 CT_DoListTarballExt() {
403 if [ "${CT_CONFIGURE_has_xzutils}" = "y" ]; then
406 if [ "${CT_CONFIGURE_has_lzma}" = "y" \
407 -o "${CT_CONFIGURE_has_xzutils}" = "y" ]; then
411 printf ".tar.gz\n.tgz\n"
415 # Get the file name extension of a component
416 # Usage: CT_GetFileExtension <component_name-component_version> [extension]
417 # If found, echoes the extension to stdout, and return 0
418 # If not found, echoes nothing on stdout, and return !0.
419 CT_GetFileExtension() {
425 # we need to also check for an empty extension for those very
426 # peculiar components that don't have one (such as sstrip from
428 for ext in ${first_ext} $(CT_DoListTarballExt) /.git ''; do
429 if [ -e "${CT_TARBALLS_DIR}/${file}${ext}" ]; then
438 # Try to retrieve the specified URL (HTTP or FTP)
439 # Usage: CT_DoGetFile <URL>
440 # This functions always returns true (0), as it can be legitimate not
441 # to find the requested URL (think about snapshots, different layouts
442 # for different gcc versions, etc...).
445 local dest="${CT_TARBALLS_DIR}/${url##*/}"
446 local tmp="${dest}.tmp-dl"
448 # Remove potential left-over from a previous run
451 # We also retry a few times, in case there is a transient error (eg. behind
452 # a dynamic IP that changes during the transfer...)
453 # With automated download as we are doing, it can be very dangerous to
454 # continue the downloads. It's far better to simply overwrite the
456 # Some company networks have firewalls to connect to the internet, but it's
457 # not easy to detect them, so force a global ${CT_CONNECT_TIMEOUT}-second
459 # For curl, no good progress indicator is available. So, be silent.
460 if CT_DoExecLog ALL curl --ftp-pasv \
462 --connect-timeout ${CT_CONNECT_TIMEOUT} \
463 --location --fail --silent \
467 # Success, we got it, good!
468 mv "${tmp}" "${dest}"
475 # This function tries to retrieve a tarball form a local directory
476 # Usage: CT_GetLocal <basename> [.extension]
482 # Do we already have it in *our* tarballs dir?
483 if ext="$( CT_GetFileExtension "${basename}" ${first_ext} )"; then
484 CT_DoLog DEBUG "Already have '${basename}'"
488 if [ -n "${CT_LOCAL_TARBALLS_DIR}" ]; then
489 CT_DoLog DEBUG "Trying to retrieve an already downloaded copy of '${basename}'"
490 # We'd rather have a bzip2'ed tarball, then gzipped tarball, plain tarball,
491 # or, as a failover, a file without extension.
492 for ext in ${first_ext} $(CT_DoListTarballExt) ''; do
493 CT_DoLog DEBUG "Trying '${CT_LOCAL_TARBALLS_DIR}/${basename}${ext}'"
494 if [ -r "${CT_LOCAL_TARBALLS_DIR}/${basename}${ext}" -a \
495 "${CT_FORCE_DOWNLOAD}" != "y" ]; then
496 CT_DoLog DEBUG "Got '${basename}' from local storage"
497 CT_DoExecLog ALL ln -s "${CT_LOCAL_TARBALLS_DIR}/${basename}${ext}" "${CT_TARBALLS_DIR}/${basename}${ext}"
505 # This function saves the specified to local storage if possible,
506 # and if so, symlinks it for later usage
507 # Usage: CT_SaveLocal </full/path/file.name>
510 local basename="${file##*/}"
512 if [ "${CT_SAVE_TARBALLS}" = "y" ]; then
513 CT_DoLog EXTRA "Saving '${basename}' to local storage"
514 # The file may already exist if downloads are forced: remove it first
515 CT_DoExecLog ALL rm -f "${CT_LOCAL_TARBALLS_DIR}/${basename}"
516 CT_DoExecLog ALL mv -f "${file}" "${CT_LOCAL_TARBALLS_DIR}"
517 CT_DoExecLog ALL ln -s "${CT_LOCAL_TARBALLS_DIR}/${basename}" "${file}"
521 # Download the file from one of the URLs passed as argument
522 # Usage: CT_GetFile <basename> [.extension] <url> [url ...]
530 # If next argument starts with a dot, then this is not an URL,
531 # and we can consider that it is a preferred extension.
538 # Does it exist localy?
539 if CT_GetLocal "${file}" ${first_ext}; then
544 # Try to retrieve the file
545 CT_DoLog EXTRA "Retrieving '${file}'"
547 # Add URLs on the LAN mirror
548 if [ "${CT_USE_MIRROR}" = "y" ]; then
549 CT_TestOrAbort "Please set the mirror base URL" -n "${CT_MIRROR_BASE_URL}"
550 URLS+=( "${CT_MIRROR_BASE_URL}/${file%-*}" )
551 URLS+=( "${CT_MIRROR_BASE_URL}" )
554 if [ "${CT_FORBID_DOWNLOAD}" != "y" ]; then
558 # Scan all URLs in turn, and try to grab a tarball from there
559 # Do *not* try git trees (ext=/.git), this is handled in a specific
561 for ext in ${first_ext} $(CT_DoListTarballExt) ''; do
562 # Try all urls in turn
563 for url in "${URLS[@]}"; do
564 [ -n "${url}" ] || continue
565 CT_DoLog DEBUG "Trying '${url}/${file}${ext}'"
566 CT_DoGetFile "${url}/${file}${ext}"
567 if [ -f "${CT_TARBALLS_DIR}/${file}${ext}" ]; then
568 CT_DoLog DEBUG "Got '${file}' from the Internet"
569 CT_SaveLocal "${CT_TARBALLS_DIR}/${file}${ext}"
575 # Just return error, someone may want to catch and handle the error
576 # (eg. glibc/eglibc add-ons can be missing).
580 # Checkout from CVS, and build the associated tarball
581 # The tarball will be called ${basename}.tar.bz2
582 # Prerequisite: either the server does not require password,
583 # or the user must already be logged in.
584 # 'tag' is the tag to retrieve. Must be specified, but can be empty.
585 # If dirname is specified, then module will be renamed to dirname
586 # prior to building the tarball.
587 # Usage: CT_GetCVS <basename> <url> <module> <tag> [dirname[=subdir]]
588 # Note: if '=subdir' is given, then it is used instead of 'module'.
593 local tag="${4:+-r ${4}}"
597 # First try locally, then the mirror
598 if CT_GetFile "${basename}"; then
599 # Got it! Return early! :-)
603 if [ "${CT_FORBID_DOWNLOAD}" = "y" ]; then
604 CT_DoLog WARN "Downloads forbidden, not trying cvs retrieval"
609 CT_Pushd "${tmp_dir}"
611 CT_DoExecLog ALL cvs -z 9 -d "${uri}" co -P ${tag} "${module}"
612 if [ -n "${dirname}" ]; then
615 CT_DoExecLog DEBUG mv "${dirname#*=}" "${dirname%%=*}"
616 CT_DoExecLog ALL tar cjf "${CT_TARBALLS_DIR}/${basename}.tar.bz2" "${dirname%%=*}"
619 CT_DoExecLog ALL mv "${module}" "${dirname}"
620 CT_DoExecLog ALL tar cjf "${CT_TARBALLS_DIR}/${basename}.tar.bz2" "${dirname:-${module}}"
624 CT_SaveLocal "${CT_TARBALLS_DIR}/${basename}.tar.bz2"
627 CT_DoExecLog ALL rm -rf "${tmp_dir}"
630 # Check out from SVN, and build the associated tarball
631 # The tarball will be called ${basename}.tar.bz2
632 # Prerequisite: either the server does not require password,
633 # or the user must already be logged in.
634 # 'rev' is the revision to retrieve
635 # Usage: CT_GetSVN <basename> <url> [rev]
641 # First try locally, then the mirror
642 if CT_GetFile "${basename}"; then
643 # Got it! Return early! :-)
647 if [ "${CT_FORBID_DOWNLOAD}" = "y" ]; then
648 CT_DoLog WARN "Downloads forbidden, not trying svn retrieval"
653 CT_Pushd "${tmp_dir}"
655 if ! CT_DoExecLog ALL svn export ${rev:+-r ${rev}} "${uri}" "${basename}"; then
656 CT_DoLog WARN "Could not retrieve '${basename}'"
659 CT_DoExecLog ALL tar cjf "${CT_TARBALLS_DIR}/${basename}.tar.bz2" "${basename}"
660 CT_SaveLocal "${CT_TARBALLS_DIR}/${basename}.tar.bz2"
663 CT_DoExecLog ALL rm -rf "${tmp_dir}"
667 # Tries the given URLs in turn until one can get cloned. No tarball will be created.
668 # Prerequisites: either the server does not require password,
669 # or the user has already taken any action to authenticate to the server.
670 # The cloned tree will *not* be stored in the local tarballs dir!
671 # Usage: CT_GetGit <basename> <url [url ...]>
673 local basename="$1"; shift
677 if [ "${CT_FORBID_DOWNLOAD}" = "y" ]; then
678 CT_DoLog WARN "Downloads forbidden, not trying git retrieval"
682 # Do we have it in our tarballs dir?
683 if [ -d "${CT_TARBALLS_DIR}/${basename}/.git" ]; then
684 CT_DoLog EXTRA "Updating git tree '${basename}'"
685 CT_Pushd "${CT_TARBALLS_DIR}/${basename}"
686 CT_DoExecLog ALL git pull
689 CT_DoLog EXTRA "Retrieving git tree '${basename}'"
690 for url in "${@}"; do
691 CT_DoLog ALL "Trying to clone from '${url}'"
692 CT_DoForceRmdir "${CT_TARBALLS_DIR}/${basename}"
693 if git clone "${url}" "${CT_TARBALLS_DIR}/${basename}" 2>&1 |CT_DoLog ALL; then
698 CT_TestOrAbort "Could not clone '${basename}'" ${cloned} -ne 0
703 # Some tarballs need to be extracted in specific places. Eg.: glibc addons
704 # must be extracted in the glibc directory; uCLibc locales must be extracted
705 # in the extra/locale sub-directory of uClibc. This is taken into account
706 # by the caller, that did a 'cd' into the correct path before calling us
707 # and sets nochdir to 'nochdir'.
708 # Note also that this function handles the git trees!
709 # Usage: CT_Extract <basename> [nochdir] [options]
710 # where 'options' are dependent on the source (eg. git branch/tag...)
718 if [ "${nochdir}" = "nochdir" ]; then
722 nochdir="${CT_SRC_DIR}"
728 if ! ext="$(CT_GetFileExtension "${basename}")"; then
729 CT_DoLog WARN "'${basename}' not found in '${CT_TARBALLS_DIR}'"
732 local full_file="${CT_TARBALLS_DIR}/${basename}${ext}"
734 # Check if already extracted
735 if [ -e "${CT_SRC_DIR}/.${basename}.extracted" ]; then
736 CT_DoLog DEBUG "Already extracted '${basename}'"
740 # Check if previously partially extracted
741 if [ -e "${CT_SRC_DIR}/.${basename}.extracting" ]; then
742 CT_DoLog ERROR "The '${basename}' sources were partially extracted."
743 CT_DoLog ERROR "Please remove first:"
744 CT_DoLog ERROR " - the source dir for '${basename}', in '${CT_SRC_DIR}'"
745 CT_DoLog ERROR " - the file '${CT_SRC_DIR}/.${basename}.extracting'"
746 CT_Abort "I'll stop now to avoid any carnage..."
748 CT_DoExecLog DEBUG touch "${CT_SRC_DIR}/.${basename}.extracting"
750 CT_Pushd "${nochdir}"
752 CT_DoLog EXTRA "Extracting '${basename}'"
753 CT_DoExecLog FILE mkdir -p "${basename}"
754 tar_opts=( "--strip-components=1" )
755 tar_opts+=( "-C" "${basename}" )
759 # - lzma can be handled either with 'xz' or 'lzma'
760 # - we get lzma tarball only if either or both are available
761 # - so, if we get an lzma tarball, and either 'xz' or 'lzma' is
762 # missing, we can assume the other is available
763 if [ "${CT_CONFIGURE_has_lzma}" = "y" ]; then
769 .tar.xz) CT_DoExecLog FILE tar "${tar_opts[@]}" --use-compress-program=xz -f "${full_file}";;
770 .tar.lzma) CT_DoExecLog FILE tar "${tar_opts[@]}" --use-compress-program="${lzma_prog}" -f "${full_file}";;
771 .tar.bz2) CT_DoExecLog FILE tar "${tar_opts[@]}" -j -f "${full_file}";;
772 .tar.gz|.tgz) CT_DoExecLog FILE tar "${tar_opts[@]}" -z -f "${full_file}";;
773 .tar) CT_DoExecLog FILE tar "${tar_opts[@]}" -f "${full_file}";;
774 /.git) CT_ExtractGit "${basename}" "${@}";;
775 *) CT_DoLog WARN "Don't know how to handle '${basename}${ext}': unknown extension"
780 # Don't mark as being extracted for git
783 *) CT_DoExecLog DEBUG touch "${CT_SRC_DIR}/.${basename}.extracted";;
785 CT_DoExecLog DEBUG rm -f "${CT_SRC_DIR}/.${basename}.extracting"
790 # Create a working git clone of a local git repository
791 # Usage: CT_ExtractGit <basename> [ref]
792 # where 'ref' is the reference to use:
793 # the full name of a branch, like "remotes/origin/branch_name"
794 # a date as understandable by git, like "YYYY-MM-DD[ hh[:mm[:ss]]]"
796 # If 'ref' is not given, the current repository HEAD will be used
798 local basename="${1}"
803 # pushd now to be able to get git revlist in case ref is a date
804 repo="${CT_TARBALLS_DIR}/${basename}"
807 # What kind of reference is ${ref} ?
808 if [ -z "${ref}" ]; then
810 ref=$(git rev-list -n1 HEAD)
811 elif git tag |grep -E "^${ref}$" >/dev/null 2>&1; then
813 elif git branch -a --no-color |grep -E "^. ${ref}$" >/dev/null 2>&1; then
815 elif date -d "${ref}" >/dev/null 2>&1; then
817 ref=$(git rev-list -n1 --before="${ref}")
819 CT_Abort "Reference '${ref}' is an incorrect git reference: neither tag, branch nor date"
824 CT_DoExecLog FILE rmdir "${basename}"
825 case "${ref_type}" in
826 branch) CT_DoExecLog FILE git clone -b "${ref}" "${repo}" "${basename}" ;;
827 *) CT_DoExecLog FILE git clone "${repo}" "${basename}"
828 CT_Pushd "${basename}"
829 CT_DoExecLog FILE git checkout "${ref}"
835 # Patches the specified component
836 # See CT_Extract, above, for explanations on 'nochdir'
837 # Usage: CT_Patch [nochdir] <packagename> <packageversion>
838 # If the package directory is *not* packagename-packageversion, then
839 # the caller must cd into the proper directory first, and call us
850 local bundled_patch_dir
851 local local_patch_dir
853 if [ "${nochdir}" = "nochdir" ]; then
857 pkgdir="${pkgname}-${version}"
862 pkgdir="${pkgname}-${version}"
863 nochdir="${CT_SRC_DIR}/${pkgdir}"
866 # Check if already patched
867 if [ -e "${CT_SRC_DIR}/.${pkgdir}.patched" ]; then
868 CT_DoLog DEBUG "Already patched '${pkgdir}'"
872 # Check if already partially patched
873 if [ -e "${CT_SRC_DIR}/.${pkgdir}.patching" ]; then
874 CT_DoLog ERROR "The '${pkgdir}' sources were partially patched."
875 CT_DoLog ERROR "Please remove first:"
876 CT_DoLog ERROR " - the source dir for '${pkgdir}', in '${CT_SRC_DIR}'"
877 CT_DoLog ERROR " - the file '${CT_SRC_DIR}/.${pkgdir}.extracted'"
878 CT_DoLog ERROR " - the file '${CT_SRC_DIR}/.${pkgdir}.patching'"
879 CT_Abort "I'll stop now to avoid any carnage..."
881 touch "${CT_SRC_DIR}/.${pkgdir}.patching"
883 CT_Pushd "${nochdir}"
885 CT_DoLog EXTRA "Patching '${pkgdir}'"
887 bundled_patch_dir="${CT_LIB_DIR}/patches/${pkgname}/${version}"
888 local_patch_dir="${CT_LOCAL_PATCH_DIR}/${pkgname}/${version}"
890 case "${CT_PATCH_ORDER}" in
891 bundled) patch_dirs=("${bundled_patch_dir}");;
892 local) patch_dirs=("${local_patch_dir}");;
893 bundled,local) patch_dirs=("${bundled_patch_dir}" "${local_patch_dir}");;
894 local,bundled) patch_dirs=("${local_patch_dir}" "${bundled_patch_dir}");;
898 for d in "${patch_dirs[@]}"; do
899 CT_DoLog DEBUG "Looking for patches in '${d}'..."
900 if [ -n "${d}" -a -d "${d}" ]; then
901 for p in "${d}"/*.patch; do
902 if [ -f "${p}" ]; then
903 CT_DoLog DEBUG "Applying patch '${p}'"
904 CT_DoExecLog ALL patch --no-backup-if-mismatch -g0 -F1 -p1 -f <"${p}"
907 if [ "${CT_PATCH_SINGLE}" = "y" ]; then
913 if [ "${CT_OVERIDE_CONFIG_GUESS_SUB}" = "y" ]; then
914 CT_DoLog ALL "Overiding config.guess and config.sub"
915 for cfg in config_guess config_sub; do
916 eval ${cfg}="${CT_LIB_DIR}/scripts/${cfg/_/.}"
917 [ -e "${CT_TOP_DIR}/scripts/${cfg/_/.}" ] && eval ${cfg}="${CT_TOP_DIR}/scripts/${cfg/_/.}"
918 # Can't use CT_DoExecLog because of the '{} \;' to be passed un-mangled to find
919 find . -type f -name "${cfg/_/.}" -exec cp -v "${!cfg}" {} \; |CT_DoLog ALL
923 CT_DoExecLog DEBUG touch "${CT_SRC_DIR}/.${pkgdir}.patched"
924 CT_DoExecLog DEBUG rm -f "${CT_SRC_DIR}/.${pkgdir}.patching"
929 # Two wrappers to call config.(guess|sub) either from CT_TOP_DIR or CT_LIB_DIR.
930 # Those from CT_TOP_DIR, if they exist, will be be more recent than those from CT_LIB_DIR.
932 if [ -x "${CT_TOP_DIR}/scripts/config.guess" ]; then
933 "${CT_TOP_DIR}/scripts/config.guess"
935 "${CT_LIB_DIR}/scripts/config.guess"
940 if [ -x "${CT_TOP_DIR}/scripts/config.sub" ]; then
941 "${CT_TOP_DIR}/scripts/config.sub" "$@"
943 "${CT_LIB_DIR}/scripts/config.sub" "$@"
947 # Compute the target tuple from what is provided by the user
948 # Usage: CT_DoBuildTargetTuple
949 # In fact this function takes the environment variables to build the target
950 # tuple. It is needed both by the normal build sequence, as well as the
951 # sample saving sequence.
952 CT_DoBuildTargetTuple() {
953 # Set the endianness suffix, and the default endianness gcc option
954 case "${CT_ARCH_BE},${CT_ARCH_LE}" in
955 y,) target_endian_eb=eb
957 CT_ARCH_ENDIAN_CFLAG="-mbig-endian"
958 CT_ARCH_ENDIAN_LDFLAG="-EB"
960 ,y) target_endian_eb=
962 CT_ARCH_ENDIAN_CFLAG="-mlittle-endian"
963 CT_ARCH_ENDIAN_LDFLAG="-EL"
967 # Build the default architecture tuple part
968 CT_TARGET_ARCH="${CT_ARCH}"
970 # Set defaults for the system part of the tuple. Can be overriden
971 # by architecture-specific values.
973 *glibc) CT_TARGET_SYS=gnu;;
974 uClibc) CT_TARGET_SYS=uclibc;;
975 *) CT_TARGET_SYS=elf;;
978 # Set the default values for ARCH, ABI, CPU, TUNE, FPU and FLOAT
979 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
980 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
981 [ "${CT_ARCH_ARCH}" ] && { CT_ARCH_ARCH_CFLAG="-march=${CT_ARCH_ARCH}"; CT_ARCH_WITH_ARCH="--with-arch=${CT_ARCH_ARCH}"; }
982 [ "${CT_ARCH_ABI}" ] && { CT_ARCH_ABI_CFLAG="-mabi=${CT_ARCH_ABI}"; CT_ARCH_WITH_ABI="--with-abi=${CT_ARCH_ABI}"; }
983 [ "${CT_ARCH_CPU}" ] && { CT_ARCH_CPU_CFLAG="-mcpu=${CT_ARCH_CPU}"; CT_ARCH_WITH_CPU="--with-cpu=${CT_ARCH_CPU}"; }
984 [ "${CT_ARCH_TUNE}" ] && { CT_ARCH_TUNE_CFLAG="-mtune=${CT_ARCH_TUNE}"; CT_ARCH_WITH_TUNE="--with-tune=${CT_ARCH_TUNE}"; }
985 [ "${CT_ARCH_FPU}" ] && { CT_ARCH_FPU_CFLAG="-mfpu=${CT_ARCH_FPU}"; CT_ARCH_WITH_FPU="--with-fpu=${CT_ARCH_FPU}"; }
986 [ "${CT_ARCH_FLOAT_SW}" ] && { CT_ARCH_FLOAT_CFLAG="-msoft-float"; CT_ARCH_WITH_FLOAT="--with-float=soft"; }
988 # Build the default kernel tuple part
989 CT_TARGET_KERNEL="${CT_KERNEL}"
991 # Overide the default values with the components specific settings
993 CT_DoKernelTupleValues
995 # Finish the target tuple construction
996 CT_TARGET="${CT_TARGET_ARCH}"
997 CT_TARGET="${CT_TARGET}${CT_TARGET_VENDOR:+-${CT_TARGET_VENDOR}}"
998 CT_TARGET="${CT_TARGET}${CT_TARGET_KERNEL:+-${CT_TARGET_KERNEL}}"
999 CT_TARGET="${CT_TARGET}${CT_TARGET_SYS:+-${CT_TARGET_SYS}}"
1003 if [ -n "${CT_TARGET_ALIAS_SED_EXPR}" ]; then
1004 __sed_alias=$(echo "${CT_TARGET}" |sed -r -e "${CT_TARGET_ALIAS_SED_EXPR}")
1006 case ":${CT_TARGET_VENDOR}:${CT_TARGET_ALIAS}:${__sed_alias}:" in
1007 :*" "*:*:*:) CT_Abort "Don't use spaces in the vendor string, it breaks things.";;
1008 :*"-"*:*:*:) CT_Abort "Don't use dashes in the vendor string, it breaks things.";;
1009 :*:*" "*:*:) CT_Abort "Don't use spaces in the target alias, it breaks things.";;
1010 :*:*:*" "*:) CT_Abort "Don't use spaces in the target sed transform, it breaks things.";;
1014 CT_TARGET=$(CT_DoConfigSub "${CT_TARGET}")
1015 # Prepare the target CFLAGS
1016 CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_ENDIAN_CFLAG}"
1017 CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_ARCH_CFLAG}"
1018 CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_ABI_CFLAG}"
1019 CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_CPU_CFLAG}"
1020 CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_TUNE_CFLAG}"
1021 CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_FPU_CFLAG}"
1022 CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_FLOAT_CFLAG}"
1024 # Now on for the target LDFLAGS
1025 CT_ARCH_TARGET_LDFLAGS="${CT_ARCH_TARGET_LDFLAGS} ${CT_ARCH_ENDIAN_LDFLAG}"
1028 # This function does pause the build until the user strikes "Return"
1029 # Usage: CT_DoPause [optional_message]
1032 local message="${1:-Pausing for your pleasure}"
1033 CT_DoLog INFO "${message}"
1034 read -p "Press 'Enter' to continue, or Ctrl-C to stop..." foo >&6
1038 # This function creates a tarball of the specified directory, but
1040 # Usage: CT_DoTarballIfExists <dir> <tarball_basename> [extra_tar_options [...]]
1041 CT_DoTarballIfExists() {
1045 local -a extra_tar_opts=( "$@" )
1048 case "${CT_DEBUG_CT_SAVE_STEPS_GZIP}" in
1049 y) compress=( gzip -c -3 - ); tar_ext=.gz;;
1050 *) compress=( cat - ); tar_ext=;;
1053 if [ -d "${dir}" ]; then
1054 CT_DoLog DEBUG " Saving '${dir}'"
1055 { tar c -C "${dir}" -v -f - "${extra_tar_opts[@]}" . \
1056 |"${compress[@]}" >"${tarball}.tar${tar_ext}" ;
1057 } 2>&1 |sed -r -e 's/^/ /;' |CT_DoLog STATE
1059 CT_DoLog STATE " Not saving '${dir}': does not exist"
1063 # This function extracts a tarball to the specified directory, but
1064 # only if the tarball exists
1065 # Usage: CT_DoExtractTarballIfExists <tarball_basename> <dir> [extra_tar_options [...]]
1066 CT_DoExtractTarballIfExists() {
1070 local -a extra_tar_opts=( "$@" )
1073 case "${CT_DEBUG_CT_SAVE_STEPS_GZIP}" in
1074 y) uncompress=( gzip -c -d ); tar_ext=.gz;;
1075 *) uncompress=( cat ); tar_ext=;;
1078 if [ -f "${tarball}.tar${tar_ext}" ]; then
1079 CT_DoLog DEBUG " Restoring '${dir}'"
1080 CT_DoForceRmdir "${dir}"
1081 CT_DoExecLog DEBUG mkdir -p "${dir}"
1082 { "${uncompress[@]}" "${tarball}.tar${tar_ext}" \
1083 |tar x -C "${dir}" -v -f - "${extra_tar_opts[@]}" ;
1084 } 2>&1 |sed -r -e 's/^/ /;' |CT_DoLog STATE
1086 CT_DoLog STATE " Not restoring '${dir}': does not exist"
1090 # This function saves the state of the toolchain to be able to restart
1092 # Usage: CT_DoSaveState <next_step_name>
1094 [ "${CT_DEBUG_CT_SAVE_STEPS}" = "y" ] || return 0
1095 local state_name="$1"
1096 local state_dir="${CT_STATE_DIR}/${state_name}"
1098 # Log this to the log level required by the user
1099 CT_DoLog ${CT_LOG_LEVEL_MAX} "Saving state to restart at step '${state_name}'..."
1101 rm -rf "${state_dir}"
1102 mkdir -p "${state_dir}"
1104 CT_DoLog STATE " Saving environment and aliases"
1105 # We must omit shell functions, and some specific bash variables
1106 # that break when restoring the environment, later. We could do
1107 # all the processing in the awk script, but a sed is easier...
1110 $0~/^[^ ]+ \(\)/ { _p = 0; }
1112 $0 == "}" { _p = 1; }
1113 ' |sed -r -e '/^BASH_(ARGC|ARGV|LINENO|SOURCE|VERSINFO)=/d;
1115 /^(FUNCNAME|GROUPS|PPID|SHELLOPTS)=/d;' >"${state_dir}/env.sh"
1117 CT_DoTarballIfExists "${CT_BUILDTOOLS_PREFIX_DIR}" "${state_dir}/buildtools_dir"
1118 CT_DoTarballIfExists "${CT_COMPLIBS_DIR}" "${state_dir}/complibs_dir"
1119 CT_DoTarballIfExists "${CT_CONFIG_DIR}" "${state_dir}/config_dir"
1120 CT_DoTarballIfExists "${CT_CC_CORE_STATIC_PREFIX_DIR}" "${state_dir}/cc_core_static_prefix_dir"
1121 CT_DoTarballIfExists "${CT_CC_CORE_SHARED_PREFIX_DIR}" "${state_dir}/cc_core_shared_prefix_dir"
1122 CT_DoTarballIfExists "${CT_PREFIX_DIR}" "${state_dir}/prefix_dir" --exclude '*.log'
1124 CT_DoLog STATE " Saving log file"
1126 case "${CT_DEBUG_CT_SAVE_STEPS_GZIP}" in
1127 y) gzip -3 -c "${tmp_log_file}" >"${state_dir}/log.gz";;
1128 *) cat "${tmp_log_file}" >"${state_dir}/log";;
1130 exec >>"${tmp_log_file}"
1133 # This function restores a previously saved state
1134 # Usage: CT_DoLoadState <state_name>
1136 local state_name="$1"
1137 local state_dir="${CT_STATE_DIR}/${state_name}"
1138 local old_RESTART="${CT_RESTART}"
1139 local old_STOP="${CT_STOP}"
1141 CT_TestOrAbort "The previous build did not reach the point where it could be restarted at '${CT_RESTART}'" -d "${state_dir}"
1143 # We need to do something special with the log file!
1144 if [ "${CT_LOG_TO_FILE}" = "y" ]; then
1145 exec >"${state_dir}/tail.log"
1148 # Log this to the log level required by the user
1149 CT_DoLog ${CT_LOG_LEVEL_MAX} "Restoring state at step '${state_name}', as requested."
1151 CT_DoExtractTarballIfExists "${state_dir}/prefix_dir" "${CT_PREFIX_DIR}"
1152 CT_DoExtractTarballIfExists "${state_dir}/cc_core_shared_prefix_dir" "${CT_CC_CORE_SHARED_PREFIX_DIR}"
1153 CT_DoExtractTarballIfExists "${state_dir}/cc_core_static_prefix_dir" "${CT_CC_CORE_STATIC_PREFIX_DIR}"
1154 CT_DoExtractTarballIfExists "${state_dir}/config_dir" "${CT_CONFIG_DIR}"
1155 CT_DoExtractTarballIfExists "${state_dir}/complibs_dir" "${CT_COMPLIBS_DIR}"
1156 CT_DoExtractTarballIfExists "${state_dir}/buildtools_dir" "${CT_BUILDTOOLS_PREFIX_DIR}"
1158 # Restore the environment, discarding any error message
1159 # (for example, read-only bash internals)
1160 CT_DoLog STATE " Restoring environment"
1161 . "${state_dir}/env.sh" >/dev/null 2>&1 || true
1163 # Restore the new RESTART and STOP steps
1164 CT_RESTART="${old_RESTART}"
1165 CT_STOP="${old_STOP}"
1166 unset old_stop old_restart
1168 CT_DoLog STATE " Restoring log file"
1170 case "${CT_DEBUG_CT_SAVE_STEPS_GZIP}" in
1171 y) zcat "${state_dir}/log.gz" >"${tmp_log_file}";;
1172 *) cat "${state_dir}/log" >"${tmp_log_file}";;
1174 cat "${state_dir}/tail.log" >>"${tmp_log_file}"
1175 exec >>"${tmp_log_file}"
1176 rm -f "${state_dir}/tail.log"