scripts/patch-rework.sh
author Bryan Hundven <bryanhundven@gmail.com>
Sun Jun 26 03:26:54 2011 -0700 (2011-06-26)
changeset 2515 364b06df9e3a
parent 2147 0ec4491d6496
child 2564 5d4e91c0343e
permissions -rwxr-xr-x
glibc: Refactor startfiles/headers into do_libc_backend()

Refactor the contents of 'do_libc_start_files()' and 'do_libc()' into a
parameterized 'do_libc_backend()'. 'do_libc_start_files()' and 'do_libc()'
call 'do_libc_backend()' with either 'libc_mode=startfiles' or
'libc_mode=final' (respectively) so that the startfiles/headers and
the final libc builds are configured and built with the same options.

One example of where this is needed is when building a mips toolchain.
Previously, if you were building an n32 toolchain, you wouldn't have
noticed an issue, because if '-mabi' is not in CFLAGS, n32 is the
default:

http://sourceware.org/git/?p=glibc-ports.git;a=blob;f=sysdeps/mips/preconfigure;hb=HEAD

But when trying to build an o32 or n64 toolchain the build would
have failed. This is because (e)glibc expects "-mabi={o32,n32,n64}" to be
in CFLAGS, but was not previously provided in 'do_libc_start_files()'.
The build failure would happen in the shared-core gcc when it tries to
configure an n64 or o32 gcc with an n32 libc.

A simpler solution would have been to just add TARGET_CFLAGS to configure
in 'do_libc_start_files()', but this way makes configure and make
consistent for both steps.

Signed-off-by: Bryan Hundven <bryanhundven@gmail.com>
     1 #!/bin/sh
     2 
     3 # Get our required options
     4 base="$1"
     5 src="$2"
     6 dst="$3"
     7 shift 3
     8 
     9 # The remainder is for diff
    10 diff="$@"
    11 
    12 do_help() {
    13     cat <<-_EOF_
    14 		${0##*/}: transform a patchset of non-p1 patches into -p1 patches
    15 		
    16 		Usage:
    17 		    ${0##*/} <basedir> <src> <dst> [diffopts ...]
    18 		
    19 		Where:
    20 		    basedir
    21 		        points to the directory of the component to patch
    22 		
    23 		    src
    24 		        points to the directory containing the existing patchset
    25 		        to transform
    26 		
    27 		    dst
    28 		        points to the directory where to put transformed patches
    29 		
    30 		    diffopts
    31 		        optional options to pass to diff, for debug purposes. You
    32 		        should not need it
    33 		
    34 		Example:
    35 		    Transform Gentoo patches against gcc-4.4.2 (some of which are
    36 		    -p0, -p1 or even -p2 patches) into all -p1 patches:
    37 		
    38 		        tar xjf gcc-4.4.2.tar.bz2
    39 		        patch-rework.sh gcc-4.4.2                   \\
    40 		                        /path/to/gentoo/gcc/patches \\
    41 		                        gcc-4.4.2.patches
    42 		_EOF_
    43 }
    44 
    45 # Sanity checks
    46 if [    -z "${base}"                    \
    47      -o ! -d "${base}"                  \
    48      -o ! -d "${src}"                   \
    49      -o -e "${dst}" -a ! -d "${dst}"    \
    50    ]; then
    51 	do_help
    52 	exit 1
    53 fi
    54 
    55 mkdir -p "${dst}"
    56 base="${base%%/}"
    57 src="$( cd "${src}"; pwd )"
    58 dst="$( cd "${dst}"; pwd )"
    59 
    60 # This function checks that the files listed in the file in "$1"
    61 # do exist, at the given depth-stripping level (aka diff -p#)
    62 do_check_files_at_depth() {
    63   local flist="$1"
    64   local depth="$2"
    65   local ret=0   # 0: OK,  !0: KO
    66 
    67   exec 6<&0
    68   exec 7<"${flist}"
    69 
    70   while read -u7 f; do
    71     f="$( echo "${f}" |sed -r -e "s:^([^/]+/){${depth}}::;" )"
    72     [ -f "${f}" ] || ret=1
    73   done
    74 
    75   exec 7<&-
    76   exec <&6
    77 
    78   return ${ret}
    79 }
    80 
    81 # Iterate through patches
    82 for p in "${src}/"*.patch; do
    83   pname="$( basename "${p}" )"
    84 
    85   printf "Handling patch '${pname}'...\n"
    86 
    87   printf "  creating reference..."
    88   cp -a "${base}" "${base}.orig"
    89   printf " done\n"
    90 
    91   printf "  retrieving patch comment..."
    92   comment="$( awk '
    93 BEGIN { mark=0; }
    94 $0~/^diff --/ { nextfile; }
    95 $1=="---" { mark=1; next; }
    96 $1=="+++" && mark==1 { nextfile; }
    97 { mark=0; print; }
    98 ' "${p}" )"
    99   printf " done\n"
   100 
   101   printf "  creating patched file list..."
   102   diffstat -f 4 -r 2 -u -p 0 "${p}"                         \
   103   |head -n -1                                               \
   104   |awk '{ for(i=NF;i>=NF-5;i--) { $(i) = ""; } print; }'    \
   105   |sort                                                     \
   106   >"diffstat.orig"
   107   printf " done\n"
   108 
   109   pushd "${base}" >/dev/null 2>&1
   110 
   111   # Check all files exist, up to depth 3
   112   printf "  checking depth:"
   113   for((d=0;d<4;d++)); do
   114     printf " ${d}"
   115     if do_check_files_at_depth "../diffstat.orig" ${d}; then
   116       printf " ok, using depth '${d}'\n"
   117       break
   118     fi
   119   done
   120   if [ ${d} -ge 4 ]; then
   121     printf "\n"
   122     printf "  checking depth failed\n"
   123     read -p "  --> enter patch depth (or Ctrl-C to abort): " d
   124   fi
   125 
   126   # Store the original list of fiels touched by the patch,
   127   # removing the $d leading components
   128   sed -r -e "s:^([^/]+/){${d}}::;" "../diffstat.orig" >"${dst}/${pname}.diffstat.orig"
   129 
   130   # Apply the patch proper, and check it applied cleanly.
   131   # We can't check with --dry-run because of patches that
   132   # contain multiple accumulated patches onto a single file.
   133   printf "  applying patch..."
   134   if ! patch -g0 -F1 -f -p${d} <"${p}" >"../patch.out" 2>&1; then
   135     printf " ERROR\n\n"
   136     popd >/dev/null 2>&1
   137     printf "There was an error while applying:\n  -->  ${p}  <--\n"
   138     printf "'${base}' was restored to the state it was prior to applying this faulty patch.\n"
   139     printf "Here's the 'patch' command, and its output:\n"
   140     printf "  ----8<----\n"
   141     printf "  patch -g0 -F1 -f -p${d} <'${p}'\n"
   142     sed -r -e 's/^/  /;' "patch.out"
   143     printf "  ----8<----\n"
   144     exit 1
   145   fi
   146   printf " done\n"
   147 
   148   printf "  removing '.orig' files..."
   149   find . -type f -name '*.orig' -exec rm -f {} +
   150   printf " done\n"
   151 
   152   popd >/dev/null 2>&1
   153 
   154   printf "  re-diffing the patch..."
   155   printf "%s\n\n" "${comment}" >"${dst}/${pname}"
   156   diff -durN "${base}.orig" "${base}" >>"${dst}/${pname}"
   157   printf " done\n"
   158 
   159   if [ -n "${diff}" ]; then
   160     printf "  applying diff filter..."
   161     filterdiff -x "${diff}" "${dst}/${pname}" >"tmp-diff"
   162     mv "tmp-diff" "${dst}/${pname}"
   163     printf " done\n"
   164   fi
   165 
   166   printf "  creating new patched file list..."
   167   diffstat -f 4 -r 2 -u -p 1 "${dst}/${pname}"              \
   168   |head -n -1                                               \
   169   |awk '{ for(i=NF;i>=NF-5;i--) { $(i) = ""; } print; }'    \
   170   |sort                                                     \
   171   >"${dst}/${pname}.diffstat.new"
   172   printf " done\n"
   173 
   174   printf "  removing temporary files/dirs..."
   175   rm -f "patch.out"
   176   rm -f "diffstat.tmp"
   177   rm -f "diffstat.orig"
   178   rm -rf "${base}.orig"
   179   printf " done\n"
   180 done
   181 
   182 # Scan all new patches to see if they touch
   183 # more files than the original patches
   184 printf "\nChecking resulting patchset:\n"
   185 for p in "${dst}/"*.patch; do
   186   pname="$( basename "${p}" )"
   187 
   188   if ! cmp "${p}.diffstat.orig" "${p}.diffstat.new" >/dev/null; then
   189     printf "  --> '${pname}' differ in touched files <--\n"
   190   else
   191     rm -f "${p}.diffstat.orig" "${p}.diffstat.new"
   192   fi
   193 done
   194 printf "  done.\n"