# To update the wrapper in an existing installation:
# cp gcc.sh /package/host/code.dogmap.org/gcc-$version/package/foreign_info &&
# spf_parse /package/host/code.dogmap.org/gcc-$version &&
# spf_load_info &&
# spf_template_gnu_do_after_install
spf_template gnu &&
spf_url home  'http://gcc.gnu.org/' &&
spf_url watch 'http://gcc.gnu.org/releases.html' &&
spf_url src   "ftp://gcc.gnu.org/pub/gcc/releases/gcc-${spf_version?}/gcc-${spf_version?}.tar.bz2" &&
spf_depend binutils \
  flags none \
  when runtime \
  version_sensitive yes &&
spf_template_gnu_build_sep &&
case ${spf_version?}. in
  2.*) spf_cc_ configure_args --enable-threads;;
  *)   spf_cc_ configure_args '--enable-threads --enable-libgcj';;
esac &&
case ${spf_version?}. in
  [23].*|4.[012].*) :;;
  *)
    spf_depend gmp &&
    spf_depend mpfr &&
    spf_args configure --with-gmp="${spf_path_conf?}"/gmp/prefix &&
    spf_args configure --with-mpfr="${spf_path_conf?}"/mpfr/prefix;;
esac &&
case ${spf_version?}. in
  [23].*|4.[01234].*) :;;
  *)
    spf_depend mpc &&
    spf_args configure --with-mpc="${spf_path_conf?}"/mpc/prefix;;
esac &&
case ${spf_version?} in
  4.5.*)
    spf_depend libelf degree optional &&
    spf_args configure --with-libelf="${spf_path_conf?}"/libelf/prefix;;
  *) :;;
esac &&
spf_cc_ make_args bootstrap &&
spf_cc_ cc_args  '-g -O2' &&
spf_cc_ cxx_args '-g -O2' &&
spf_cc_ nls &&
spf_hack_self_rpath &&
pkg_env() {
  spf_trigger_conf_libc &&
  if test -d "${spf_path_libc?}"/.; then
    case ${spf_version?}. in
      2.*) prj_x2 prj_append CPATH "${spf_path_libc?}"/include;;
      *) :;;
    esac &&
    prj_x2 prj_append C_INCLUDE_PATH     "${spf_path_libc?}"/include &&
    prj_x2 prj_append CPLUS_INCLUDE_PATH "${spf_path_libc?}"/include &&
    prj_x2 prj_append OBJC_INCLUDE_PATH  "${spf_path_libc?}"/include &&
    prj_u2 prj_set pkg_lib "${spf_path_libc?}"/library &&
    prj_x2 prj_append LIBRARY_PATH "${pkg_lib?}" &&
    prj_unset pkg_dyn_ld &&
    for pkg_dyn_ld in \
        "${pkg_lib?}"/ld.so.1 \
        "${pkg_lib?}"/ld64.so.1 \
        "${pkg_lib?}"/ld-linux.so.2 \
        ; do
      if prj_exists "${pkg_dyn_ld?}"
        then break
        else :
      fi || return "$?"
    done &&
    prj_qlist_unshift spf_args_ld "${pkg_dyn_ld?}" &&
    prj_qlist_unshift spf_args_ld -Xlinker &&
    prj_qlist_unshift spf_args_ld --dynamic-linker &&
    prj_qlist_unshift spf_args_ld -Xlinker &&
    prj_qlist_push    spf_args_ld -Xlinker &&
    prj_qlist_push    spf_args_ld -R &&
    prj_qlist_push    spf_args_ld -Xlinker &&
    prj_qlist_push    spf_args_ld "${pkg_lib?}"
  else :
  fi
} &&
spf_template_gnu_do_before_configure() {
  case ${spf_version?} in
    4.2.[01234]) ## http://gcc.gnu.org/bugzilla/show_bug.cgi?id=31906
      prj_sedfile "${spf_template_gnu_dir_?}"/libtool-ldflags '
/^result=$/a\
prev_arg=\

/result="\$result -Xcompiler"/c\
case $prev_arg in\
  -Xpreprocessor|-Xcompiler|-Xlinker) :;;\
  *) result="$result -Xcompiler";;\
esac\

/If \$(LDFLAGS)/i\
prev_arg=$arg\
';;
    4.3.[0123])
      prj_sedfile "${spf_template_gnu_dir_?}"/gcc/gcc.c \
        's/gcc_exec_prefix = make_relative_prefix/&_ignore_links/';;
    *) :;;
  esac &&
  if test SunOS = "${spf_uname_s?}" && prj_match '5.*' "${spf_uname_r?}"
    then prj_x2 prj_set_default CONFIG_SHELL /bin/ksh
    else prj_x2 prj_set_default CONFIG_SHELL /bin/sh
  fi &&
  pkg_env &&
  case ${spf_version?}. in
    [23].*|4.[01234].*)
      prj_u2 prj_set pkg_edits '' &&
      case ${spf_version?}.0 in
        2.*|3.[0123].*)
          pkg_edits="s:^ *\\(LDFLAGS=\"\\):${spf_c_tab?}    \\1:";;
        *) :;;
      esac &&
      spf_edit_make_define pkg_edits LDFLAGS_FOR_TARGET "${spf_args_ld?}" &&
      prj_sedfile "${spf_template_gnu_dir_?}"/Makefile.in "${pkg_edits?}";;
    *)
      prj_qlist_unshift spf_args_make LDFLAGS_FOR_TARGET="${spf_args_ld?}" &&
      prj_qlist_unshift spf_args_make BOOT_LDFLAGS="${spf_args_ld?}" &&
      prj_qlist_unshift spf_args_make BOOT_CFLAGS="${spf_args_cc?}" &&
      prj_qlist_unshift spf_args_configure \
        --with-stage1-ldflags="${spf_args_ld?}" &&
      prj_qlist_unshift spf_args_configure \
        --with-boot-ldflags="${spf_args_ld?}";;
  esac &&
  case ${spf_version?}. in
    2.*)
      prj_sedfile "${spf_template_gnu_dir_?}"/libstdc++/std/complext.h \
        's:^\(extern "C" double hypot\)://\1:' &&
      prj_sedfile "${spf_template_gnu_dir_?}"/config.if \
        's:\(\${CC-cc}\):\1 $CPPFLAGS $CFLAGS $LDFLAGS:';;
    *)
      if test -d "${spf_path_libc?}"/.; then
        prj_sedfile "${spf_template_gnu_dir_?}"/gcc/Makefile.in "
\$a\\
\\
NATIVE_SYSTEM_HEADER_DIR = ${spf_path_libc?}/include\\
"
      else :
      fi;;
  esac &&
  case ${spf_version?} in
    3.*) spf_hack_ltconfig "${spf_template_gnu_dir_?}"/boehm-gc;;
    *) :;;
  esac &&
  case ${spf_version?}. in
    [23].*|4.[012].*) spf_hack_ltconfig "${spf_template_gnu_dir_?}";;
    *) :;;
  esac &&
  case ${spf_version?} in
    4.5.2)
      # libgcj_bc.so.1.0.0 needs libgcj.so.11: log-compile:21249 build/i686-pc-linux-gnu/libjava/Makefile:10804
      prj_sedfile "${spf_template_gnu_dir_?}"/gcc/config/t-slibgcc-elf-ver \
        '/^SHLIB_LINK *=/s: \$(GCC_FOR_TARGET):& $(LDFLAGS_FOR_TARGET):';;
    *) :;;
  esac &&
  prj_qlist_unshift spf_args_configure \
    --with-as="${spf_path_conf?}"/binutils/command/as &&
  prj_qlist_unshift spf_args_configure \
    --with-ld="${spf_path_conf?}"/binutils/command/ld
} &&
spf_template_gnu_do_before_make() {
  case ${spf_version?}. in
    [23].*|4.[01234].*)
      prj_qlist_unshift spf_args_make BOOT_CFLAGS="${spf_args_cc?}" &&
      prj_qlist_unshift spf_args_make CXXFLAGS="${spf_args_cxx?}" &&
      prj_qlist_unshift spf_args_make LDFLAGS="${spf_args_ld?}" &&
      prj_qlist_unshift spf_args_make BOOT_LDFLAGS="${spf_args_ld?}" &&
      prj_qlist_unshift spf_args_make HOST_LDFLAGS="${spf_args_ld?}";;
    *) :;;
  esac
} &&
spf_template_gnu_do_before_install() { rm -f "${spf_path_conf?}"/gcc; } &&
spf_template_gnu_do_after_install() {
  pkg_c_dir=`   prj_quote_c "${sp_dir?}"           ` &&
  pkg_c_base=`  prj_quote_c "${sp_dir?}${sp_base?}"` &&
  pkg_c_path=`  prj_quote_c "${sp_path?}"          ` &&
  pkg_c_prefix=`prj_quote_c "${spf_path_prefix?}"  ` &&
  set x "${spf_path_prefix?}"/lib/lib[*].so \
        "${spf_path_prefix?}"/lib/lib*.so &&
  shift &&
  if test "$1" = "${spf_path_prefix?}/lib/lib[*].so" &&
     test "$2" = "${spf_path_prefix?}/lib/lib*.so"
    then shift
    else :
  fi &&
  shift &&
  prj_u2 prj_set pkg_shlib_names '' &&
  prj_u2 prj_set pkg_shlib_tests '' &&
  prj_u2 prj_set pkg_shlib '' &&
  prj_u2 prj_set pkg_shlib_num "$#" &&
  while test "$#" != 0; do
    { pkg_shlib=`prj_quote_c "$1"` &&
      pkg_shlib_names=${pkg_shlib_names?}${pkg_shlib?}', ' &&
      pkg_shlib_tests=${pkg_shlib_tests?}" ||
                any_eq(argv, ${pkg_shlib?})" &&
      pkg_shlib=`prj_sedarg1 's:^.*/lib\([^/]*\)\.so$:-l\1:;' "$1"` &&
      pkg_shlib=`prj_quote_c "${pkg_shlib?}"` &&
      pkg_shlib_tests=${pkg_shlib_tests?}" ||
                any_eq(argv, ${pkg_shlib?})" &&
      shift
    } || return "$?"
  done &&
  prj_mkdir_p "${sp_path?}"/src &&
  cat <<EOT > "${sp_path?}"/src/gcc.c &&
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <errno.h>

#define pkg_c_dir    ${pkg_c_dir?}
#define pkg_c_base   ${pkg_c_base?}
#define pkg_c_path   ${pkg_c_path?}
#define pkg_c_prefix ${pkg_c_prefix?}

typedef char const* ccp;
static char* const null=0;
static ccp arg0, spf_conf, spf_libc;
static char* path_libc, * path_libc_default;
static struct { size_t len; char** v; } args;

static char* const verbose[]={ "-v", "-V", "--verbose", NULL };
static char* const need_rpath[]={ "g77", "gcj", "g++", "c++", NULL };

static void die(ccp msg) { fputs(msg, stderr); exit(1); }
static void err(void) { perror("gcc"); exit(1); }
static void nomem(void) { errno=ENOMEM; err(); }

static unsigned int exists(ccp path) {
  struct stat statbuf;
  if (stat(path, &statbuf)==0) return 1;
  if (errno!=ENOENT) err();
  return 0;
}

static char* concat(ccp s0, ...) {
  size_t len0=strlen(s0);
  size_t len=len0;
  char* result;
  va_list args;
  va_start(args, s0);
  for (;;) {
    ccp s=va_arg(args, ccp);
    size_t s_len;
    if (s==null) break;
    s_len=strlen(s);
    len+=s_len;
    if (len<s_len) {
      va_end(args);
      nomem();
    }
  }
  va_end(args);
  ++len;
  if (len==0) nomem();
  result=malloc(len);
  if (result==null) err();
  va_start(args, s0);
  memcpy(result, s0, len0);
  for (len=len0;;) {
    ccp s=va_arg(args, ccp);
    size_t s_len;
    if (s==null) break;
    s_len=strlen(s);
    memcpy(result+len, s, s_len);
    len+=s_len;
  }
  result[len]='\\0';
  return result;
}

static void args_init(unsigned int argc, char* const* argv) {
  args.len=argc;            if (args.len!=argc)                  nomem();
  args.len++;               if (args.len==0)                     nomem();
  args.len*=sizeof *args.v; if (args.len/sizeof *args.v-1!=argc) nomem();
  args.v=malloc(args.len);  if (args.v==NULL)                    nomem();
  memcpy(args.v, argv, args.len);
}

static void args_prepend(char* arg) {
  char** new_v;
  if (arg==null) return;
  args.len+=sizeof *args.v; if (args.len<sizeof *args.v) nomem();
  new_v=malloc(args.len);   if (new_v==NULL)             nomem();
  new_v[0]=arg;
  memcpy(new_v+1, args.v, args.len-sizeof *args.v);
  free(args.v);
  args.v=new_v;
}

static void args_append(char* arg) {
  char** new_v;
  if (arg==null) return;
  args.len+=sizeof *args.v; if (args.len<sizeof *args.v) nomem();
  new_v=malloc(args.len);   if (new_v==NULL)             nomem();
  memcpy(new_v, args.v, args.len-sizeof *args.v);
  new_v[args.len/sizeof *args.v-2]=arg;
  new_v[args.len/sizeof *args.v-1]=null;
  free(args.v);
  args.v=new_v;
}

static char const env_elt_no_op[]="";
static ccp env_elt(ccp var, ccp new_elt) {
  ccp value=getenv(var);
  ccp value_elt=value;
  size_t new_elt_len=strlen(new_elt);
  if (value_elt==null) return null;
  for (;;) {
    ccp colon=strchr(value_elt, ':');
    size_t value_elt_len=
      (colon==null? strlen(value_elt): (size_t)(colon-value_elt));
    if (value_elt_len==new_elt_len &&
        memcmp(value_elt, new_elt, new_elt_len)==0)
      return env_elt_no_op;
    if (colon==null) return value;
    value_elt+=value_elt_len;
    value_elt++;
  }
}

static void env_prepend(ccp var, ccp new_elt) {
  ccp value=env_elt(var, new_elt);
  if (value==env_elt_no_op) return;
  setenv(var, (value==null? new_elt: concat(new_elt, ":", value, null)), 1);
}

static void env_append(ccp var, ccp new_elt) {
  ccp value=env_elt(var, new_elt);
  if (value==env_elt_no_op) return;
  setenv(var, (value==null? new_elt: concat(value, ":", new_elt, null)), 1);
}

static ccp base_cmd(ccp cmd) {
  ccp dash=strrchr(cmd, '-');
  return (dash==null? cmd: dash+1);
}

static unsigned int any_eq(char* const * argv, ccp arg) {
  size_t i;
  for (i=0; argv[i]!=null; ++i) {
    if (strcmp(argv[i], arg)==0) return 1;
    if (strcmp(argv[i], "-Xlinker")==0) {
      ++i;
      if (argv[i]==null) break;
    }
  }
  return 0;
}

static ccp lib_names[]={ ${pkg_shlib_names?}NULL };
static struct stat lib_st[${pkg_shlib_num?}];
static int did_stat_libs=0;
static unsigned int any_arg_lib(char* const * argv) {
  size_t i, j;
  for (i=0; argv[i]!=null; ++i) {
    struct stat arg_st;
    if (strcmp(argv[i], "-Xlinker")==0) {
      ++i;
      if (argv[i]==null) break;
      continue;
    }
    if (argv[i][0]=='-') continue;
    if (stat(argv[i], &arg_st)==0) {
      if (!did_stat_libs) {
        for (j=0; j!=${pkg_shlib_num?}; ++j)
          if (stat(lib_names[j], lib_st+j)!=0) err();
        did_stat_libs=1;
      }
      for (j=0; j!=${pkg_shlib_num?}; ++j)
        if (arg_st.st_dev==lib_st[j].st_dev &&
            arg_st.st_ino==lib_st[j].st_ino)
          return 1;
    }
  }
  return 0;
}

static unsigned int any_prefix(char* const * argv, ccp arg) {
  size_t len=strlen(arg);
  size_t i;
  for (i=0; argv[i]!=null; ++i) {
    if (strlen(argv[i])>=len && memcmp(argv[i], arg, len)==0) return 1;
    if (strcmp(argv[i], "-Xlinker")==0) {
      ++i;
      if (argv[i]==null) break;
    }
  }
  return 0;
}

static unsigned int prefix_any(char* const * argv, ccp arg) {
  size_t len=strlen(arg);
  size_t i;
  for (i=0; argv[i]!=null; ++i) {
    size_t len_i=strlen(argv[i]);
    if (len_i<=len && memcmp(argv[i], arg, len_i)==0) return 1;
    if (strcmp(argv[i], "-Xlinker")==0) {
      ++i;
      if (argv[i]==null) break;
    }
  }
  return 0;
}

static char* readlink_alloc(ccp path) {
  size_t target_len=0;
  char* target=null;
  for (;;) {
    ssize_t readlink_len;
    target_len+=256;
    if (target_len<256) nomem();
    target=realloc(target, target_len);
    if (target==null) err();
    readlink_len=readlink(path, target, target_len);
    if (readlink_len<0) {
      if (errno!=ENOENT) err();
      free(target);
      return null;
    }
    if ((size_t)readlink_len<target_len) {
      target[readlink_len]='\\0';
      return target;
    }
  }
}

static void atomic_symlink(ccp dir, ccp base, ccp target) {
  char* path=concat(dir, "/", base, null);
  char* path_new=concat(path, "{new}", null);
  char* old_target=readlink_alloc(path);
  if (unlink(path_new)!=0 && errno!=ENOENT) err();
  if (old_target==null || strcmp(old_target, target)!=0) {
    if (mkdir(dir, 0777)!=0 && errno!=EEXIST) err();
    if (symlink(target, path_new)!=0) err();
    if (rename(path_new, path)!=0) err();
  }
  free(path);
  free(path_new);
  free(old_target);
}

static unsigned int sp_deref_version;

static unsigned int setlibc(void) {
  if (path_libc==null) return 0;
  if (!exists(path_libc)) {
    char* path=path_libc_default;
    if (sp_deref_version)
      for (;;) {
        ccp dash;
        char* slash;
        unsigned int found_version=0;
        char* target=readlink_alloc(path);
        if (target==null) {
          if (errno!=EINVAL) err();
          if (path!=path_libc_default) {
            free(path);
            path=path_libc_default;
          }
          break;
        }
        if (target[0]!='/') {
          char* abs_target;
          strrchr(path, '/')[1]='\\0';
          abs_target=concat(path, target, null);
          free(target);
          target=abs_target;
        }
        if (path!=path_libc_default) free(path);
        path=target;
        slash=strrchr(path, '/');
        for (dash=slash;;) {
          dash=strchr(dash+1, '-');
          if (dash==null) break;
          if (strchr("0123456789", dash[1])!=null) {
            found_version=1;
            break;
          }
        }
        if (found_version) break;
      }
    atomic_symlink(spf_conf, spf_libc, path);
  }
  return 1;
}

int main(int argc, char** argv) {
  unsigned int do_cpp=1, do_cc=1, do_ld=1, do_gcc_rpath, found_rpath_arg=0;
  char* tmp;
  spf_conf=getenv("SPF_CONF");
  if (spf_conf!=null) {
    if (*spf_conf!='/') die("SPF_CONF must be absolute\\n");
  }
  spf_libc=getenv("SPF_LIBC");
  tmp=getenv("SP_DEREF_VERSION");
  sp_deref_version=(tmp==null || strcmp(tmp, "y")==0);
  if (spf_libc==null) spf_libc="glibc";
  arg0=argv[0];
  if (arg0==null) arg0="gcc";
  else { ++argv; --argc; }
  args_init(argc, argv);
  tmp=strrchr(arg0, '/');
  if (tmp!=null) arg0=tmp+1;
  if (strcmp(arg0, "cc")==0) arg0="gcc";
  if ((argc==1 && any_eq(verbose, argv[0])) ||
      any_eq(argv, "--help") ||
      any_eq(argv, "--version") ||
      any_eq(argv, "-print-search-dirs") ||
      any_eq(argv, "-print-libgcc-file-name") ||
      any_eq(argv, "-dumpversion") ||
      any_eq(argv, "-dumpmachine") ||
      any_eq(argv, "-dumpspecs") ||
      any_eq(argv, "-multi-lib") ||
      any_eq(argv, "-multi-directory") ||
      any_eq(argv, "-multi-os-directory") ||
      any_prefix(argv, "-print-prog-name="))
    do_cpp=do_cc=do_ld=0;
  else if (strcmp(arg0, "cpp")==0 ||
           any_eq(argv, "-E") ||
           any_eq(argv, "-M") ||
           any_eq(argv, "-MM"))
    do_cc=do_ld=0;
  else if (any_eq(argv, "-S") ||
           any_eq(argv, "-c"))
    do_ld=0;
  do_gcc_rpath=(any_eq(need_rpath, base_cmd(arg0)) ||
                any_eq(argv, "-fstack-protector") ||
                any_eq(argv, "-fstack-protector-all") ||
                any_eq(argv, "-fopenmp") ||
                getenv("SPF_GCC_GCCLIB")!=null${pkg_shlib_tests?} ||
                any_arg_lib(argv));
  if (do_gcc_rpath && spf_conf!=null) {
    ccp target=pkg_c_path;
    if (!sp_deref_version) {
      struct stat path_st, base_st;
      if (stat(pkg_c_path, &path_st)==0 &&
          stat(pkg_c_base, &base_st)==0 &&
          path_st.st_dev==base_st.st_dev &&
          path_st.st_ino==base_st.st_ino)
        target=pkg_c_base;
    }
    atomic_symlink(spf_conf, "gcc", target);
  }
  if (spf_conf!=null) {
    path_libc=concat(spf_conf, "/", spf_libc, null);
    path_libc_default=concat(pkg_c_dir, spf_libc, null);
    if (!exists(path_libc) && !exists(path_libc_default)) {
      free(path_libc);
      path_libc=null;
    }
  }
  if (do_ld) {
    char* ld_rpath_eq_args[]={ "-R", "-rpath", "--rpath", NULL };
    char* ld_rpath_prefix_args[]={ "-R/", NULL };
    char* gcc_rpath_eq_args[]={
      "-Wl,-R", "-Wl,-rpath", "-Wl,--rpath", "-Wl,-rpath-link",
      "-Wl,--rpath-link", NULL
    };
    char* gcc_rpath_prefix_args[]={
      "-Wl,-R,", "-Wl,-R/", "-Wl,-rpath,", "-Wl,--rpath,", "-Wl,-rpath-link,",
      "-Wl,--rpath-link,", NULL
    };
    size_t i;
    for (i=0; argv[i]!=null; ++i) {
      if (strcmp(argv[i], "-Xlinker")==0) {
        ++i;
        if (argv[i]==null) break;
        if (any_eq(ld_rpath_eq_args, argv[i]) ||
            prefix_any(ld_rpath_prefix_args, argv[i])) {
          found_rpath_arg=1;
          break;
        }
      } else if (any_eq(gcc_rpath_eq_args, argv[i]) ||
                 prefix_any(gcc_rpath_prefix_args, argv[i])) {
        found_rpath_arg=1;
        break;
      }
    }
  }
  if (spf_conf!=null) {
    if (strcmp(spf_libc, "glibc")==0) {
      if (do_cpp && !any_eq(argv, "-nostdinc") && setlibc()) {
        env_append("C_INCLUDE_PATH",     concat(path_libc, "/include", null));
        env_append("CPLUS_INCLUDE_PATH", concat(path_libc, "/include", null));
        env_append("OBJC_INCLUDE_PATH",  concat(path_libc, "/include", null));
      }
      if (do_ld && setlibc()) {
        char* libc_lib=concat(path_libc, "/library", null);
        char* libc_dyn_ld=concat(libc_lib, "/ld.so.1", null);
        env_append("LIBRARY_PATH", libc_lib);
        if (!exists(libc_dyn_ld)) {
          free(libc_dyn_ld);
          libc_dyn_ld=concat(libc_lib, "/ld64.so.1", null);
        }
        if (!exists(libc_dyn_ld)) {
          free(libc_dyn_ld);
          libc_dyn_ld=concat(libc_lib, "/ld-linux.so.2", null);
        }
        args_prepend(libc_dyn_ld);
        args_prepend("-Xlinker");
        args_prepend("--dynamic-linker");
        args_prepend("-Xlinker");
        if (!found_rpath_arg)
          env_append("LD_RUN_PATH", libc_lib);
        else {
          args_append("-Xlinker");
          args_append("-R");
          args_append("-Xlinker");
          args_append(libc_lib);
        }
      }
    }
    if (do_ld && do_gcc_rpath) {
      char* gcclib=concat(spf_conf, "/gcc/library", null);
      if (!found_rpath_arg)
        env_append("LD_RUN_PATH", gcclib);
      else {
        args_append("-Xlinker");
        args_append("-R");
        args_append("-Xlinker");
        args_append(gcclib);
      }
    }
  }

  env_prepend("PATH", concat(pkg_c_prefix "/bin", null));
  args_prepend(concat(pkg_c_prefix "/bin/", arg0, null));

  if      (do_ld)  args_prepend(getenv("SPF_GCC_WRAP_LD"));
  else if (do_cc)  args_prepend(getenv("SPF_GCC_WRAP_CC"));
  else if (do_cpp) args_prepend(getenv("SPF_GCC_WRAP_CPP"));
  args_prepend(getenv("SPF_GCC_WRAP"));

  if (spf_conf!=null && strcmp(spf_libc, "dietlibc")==0 && setlibc())
    args_prepend(concat(path_libc, "/bin/diet", null));

  if (getenv("SPF_GCC_NOOP")!=null) exit(0);

  execvp(args.v[0], args.v);
  perror("gcc: unable to exec");
  return 1;
}
EOT
  pkg_env &&
  prj_u2 prj_set pkg_cmd_dir "${sp_path?}"/wrappers/command &&
  prj_mkdir_p "${pkg_cmd_dir?}" &&
  rm -f "${pkg_cmd_dir?}/gcc{new}" &&
  set env PATH=${spf_path_prefix?}/bin:${PATH?} \
    "${spf_path_prefix?}"/bin/gcc -o "${pkg_cmd_dir?}/gcc{new}" \
    "${sp_path?}"/src/gcc.c -W -Wall -Wpointer-arith -Wcast-align &&
  eval '"$@"'" ${spf_args_cpp?} ${spf_args_cc?} ${spf_args_ld?}" &&
  mv -f "${pkg_cmd_dir?}/gcc{new}" "${pkg_cmd_dir?}"/gcc &&
  rm -f "${pkg_cmd_dir?}/cc{new}" &&
  ln "${pkg_cmd_dir?}"/gcc "${pkg_cmd_dir?}/cc{new}" &&
  mv -f "${pkg_cmd_dir?}/cc{new}" "${pkg_cmd_dir?}"/cc &&
  prj_unset pkg_cmd &&
  for pkg_cmd in cpp c++ g++ g77 gcj "${spf_path_prefix?}"/bin/*-gcc \
                 "${spf_path_prefix?}"/bin/*-gcc-"${spf_version?}" \
                 "${spf_path_prefix?}"/bin/*-g++ \
                 "${spf_path_prefix?}"/bin/*-c++; do
    { pkg_cmd=`prj_basename "${pkg_cmd?}"` &&
      if test -f "${spf_path_prefix?}"/bin/"${pkg_cmd?}"; then
        rm -f "${pkg_cmd_dir?}/${pkg_cmd?}{new}" &&
        ln "${pkg_cmd_dir?}"/gcc "${pkg_cmd_dir?}/${pkg_cmd?}{new}" &&
        mv -f "${pkg_cmd_dir?}/${pkg_cmd?}{new}" "${pkg_cmd_dir?}/${pkg_cmd?}"
      else :
      fi
    } || return "$?"
  done
} &&
spf_template_gnu_do_check() {
  if test -d "${spf_path_libc?}"/.; then
    echo 'The gcc tests will all fail until we figure out a way to pass the right linker flags to find glibc.'
  elif (exec runtest --version) > /dev/null 2>&1 &&
       (exec autogen --version) > /dev/null 2>&1; then
    make check
  else
    echo 'Install dejagnu and autogen to run the tests.'
  fi
} &&
spf_tested_version 4.6.3 &&
spf_tested_version 4.5.3 &&
spf_tested_version 4.5.2 &&
spf_tested_version 4.4.6 &&
spf_tested_version 4.4.5 &&
spf_tested_version 4.4.4 &&
spf_tested_version 4.4.3 &&
spf_tested_version 4.4.2 &&
spf_tested_version 4.4.1 &&
spf_tested_version 4.4.0 &&
spf_tested_version 4.3.4 &&
spf_tested_version 4.3.3 &&
spf_tested_version 4.3.2 &&
spf_tested_version 4.3.1 &&
spf_tested_version 4.3.0 &&
spf_tested_version 4.2.4 &&
spf_tested_version 4.2.3 &&
spf_tested_version 4.2.2 &&
spf_tested_version 4.2.1 &&
spf_tested_version 4.2.0 &&
spf_tested_version 4.1.2 &&
spf_tested_version 4.1.1 &&
spf_tested_version 4.0.4 &&
spf_tested_version 4.0.3 &&
spf_tested_version 3.4.6 &&
spf_tested_version 3.3.6 &&
spf_tested_version 3.2.3 &&
spf_tested_version 2.95.3

