#! /bin/sh

# cccl 
# Wrapper around MS's cl.exe and link.exe to make them act more like
# Unix cc and ld
#
# Copyright (C) 2000-2003 Geoffrey Wossum <gwossum@acm.org>
# Copyright (C) 2006      Benoit Sigoure  <tsuna@lrde.epita.fr>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
# USA.
#

cccl_version='0.05'

# usage([exit-value])
# Default exit-value is 1.
usage()
{
  cat <<EOF
Usage: cccl [OPTIONS]

cccl is a wrapper around Microsoft's cl.exe and link.exe.  It translates
parameters that GCC understands to parameters that cl.exe and link.exe
understand.
EOF
    rv=1
    test x"$1" != x && rv=$1
    exit $rv
}

if test x"$DEBUG_WIN" != x || test x"$WIN_DEBUG" != x; then
  set -x
fi

# Needed to know the value of LIB (';'-separated list of Windows-style paths
# where libraries are searched).
test -f ~/.msvcxx.env && source ~/.msvcxx.env

# prog specifies the program that should be run (cl.exe or link.exe)
# We'll assume cl to start out
prog=cl.exe
# Specifies the command line to pass to the MS compiler.
clopt='/errorReport:none /nologo'
# Specifies the command line to pass to the MS linker.
linkopt=
has_debug=false   # -g ?
source_seen=false # Did we see source files?
use_static=false  # -static ?
use_shared=false  # -shared or -dynamic or -dynamiclib

### Run through every option and convert it to the proper MS one
while test $# -gt 0; do
  arg=$1
  case $1 in
    -mcpu*)  arg=`echo "$1" | sed 's/^-mcpu/-mtune/'`;;
    -march*) arg=`echo "$1" | sed 's/^-march/-mtune/'`;;
    -D*)     optarg= ;;
    -*=*)    optarg=`echo "$1" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
    *)       optarg= ;;
  esac

  case $arg in
    --debug)
      set -x
      ;;
    --version)
      cat <<EOF
cccl $cccl_version

Copyright 2000-2003 Geoffrey Wossum
Copyright 2006      Benoit Sigoure
This is free software; see the source for copying conditions.  There is NO
waranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
EOF
      exit 0
      ;;

    -ansi)
      clopt="$clopt /Za"
      ;;

    -c) # -c (compile only) is actually the same, but for clarity...
      clopt="$clopt /c"
      ;;

    -C)
      clopt="$clopt /C"
      ;;

    -E)
      clopt="$clopt /E"
      ;;

    -fexceptions)
      clopt="$clopt /GX"
      ;;

    -fno-exceptions)
      clopt="$clopt /GX-"
      ;;

    -ffor-scope)
      clopt="$clopt /Zc:forScope"
      ;;

    -fno-for-scope)
      clopt="$clopt /Zc:forScope-"
      ;;

    -finline)
      clopt="$clopt /Ob0"
      ;;

    -fno-inline)
      clopt="$clopt /Ob2"
      ;;

    -fms-extensions)
      clopt="$clopt /Ze"
      ;;

    -fomit-frame-pointer)
      clopt="$clopt /Oy"
      ;;

    -frtti)
      clopt="$clopt /GR"
      ;;

    -fno-rtti)
      clopt="$clopt /GR-"
      ;;

    -fsyntax-only)
      clopt="$clopt /Xs"
      ;;

    -g[0-9] | -g | -ggdb) # cl only supports one debugging level
      clopt="$clopt /Zi"
      has_debug=:
      ;;

    -I)
      shift
      clopt="$clopt /I"`cygpath --mixed "$1"`
      ;;

    -I?*)
      incpath=`cygpath --mixed "/${arg#-}"`
      clopt="$clopt $incpath"
      ;;

    -L*)
      path=`cygpath --mixed ${arg#-L}`
      linkopt="$linkopt /LIBPATH:$path"
      LIB=`echo "$LIB;$path" | tr -s ';'`
      export LIB
      ;;

    -l*)
      lib=${arg#-l}
      not_found=:
      save_IFS=$IFS
      IFS=';'
      search_libs=".;$LIB;$LIBPATH"
      for i in $search_libs; do
        $not_found || break
        test x"$i" = x && continue
        IFS=$save_IFS
        i=`cygpath --mixed "$i"`
        if $use_static; then
          search_order="$i/$lib.lib $i/$lib.a \
                 $i/lib$lib.lib $i/lib$lib.a $i/$lib.dll $i/lib$lib.dll"
        else
          search_order="$i/$lib.dll $i/$lib.lib $i/$lib.a \
                 $i/lib$lib.dll $i/lib$lib.lib $i/lib$lib.a"
        fi
        for j in $search_order
        do
          if [ -f "$j" ]; then
            linkopt="$linkopt $j"
            not_found=false
            break 2
          fi
        done
      done
      # If we can't find the library, let's just assume the compiler will
      # find it...
      if $not_found; then
        linkopt="$linkopt $lib"
      fi
      ;;

    -m386 | -mtune=i386)
      clopt="$clopt /G3"
      ;;

    -mtune=itanium)
      clopt="$clopt /G1"
      ;;

    -mtune=itanium2)
      clopt="$clopt /G2"
      ;;

    -mpentium | -mtune=i386 | -mtune=i486 | -mtune=pentium \
    | -mtune=pentium-mmx)
      clopt="$clopt /G5"
      ;;

    -mpentiumpro | -mtune=pentiumpro | -mtune=i686 | -mtune=i586)
      clopt="$clopt /G6"
      ;;

    -mtune=pentium4* | -mtune=prescott | -mtune=athlon | \
    -mtune=athlon-tbird  | -mtune=athlon-4 | -mtune=athlon-xp | \
    -mtune=athlon-xp | -mtune=athlon-mp)
      clopt="$clopt /G7"
      ;;

    -msse)
      clopt="$clopt /arch:SSE"
      ;;

    -msse[23])
      clopt="$clopt /arch:SSE2"
      ;;

    -nostdin*)
      clopt="$clopt /X"
      ;;

    -o) # Specifying an output file: is it an object or an executable
      shift
      target=`cygpath --mixed "$1"`
      shift
      set dummy "$target"
      shift
      case $1 in
        *.s)
          clopt="$clopt /Fa$1"
          ;;

        *.o | *.obj)
          clopt="/MD $clopt /Fo$1"
          ;;

        *.exe)
          clopt="$clopt /Fe$1";
          linkopt="$linkopt /out:$1"
          #following line is used when not linking with /MD
          #linkopt="$linkopt /MANIFEST /MANIFESTFILE:$1.intermediate.manifest"
          prog='link.exe'
          ;;

        *.a | *.lib | *.dll)
          prog='link.exe'
          # Don't include the code of standard libraries when linking a static
          # archive. This somewhat surprising behavior is the default behavior
          # on Windows.  Note: this won't work if libtool links the library
          # itself (which should normally happen) the solution is to use a
          # wrapper script that hooks calls to `lib.exe'.
          linkopt="/MD $linkopt /NODEFAULTLIB"
          ;;

        *)
          echo "$0: warning: unhandled output file: $1" >&2
          ;;
      esac
      ;;

    -O0)
      clopt="$clopt /Od"
      ;;

    -O[12])
      clopt="$clopt /Ot"
      ;;

    -O3)
      clopt="$clopt /Ox"
      ;;

    -Os)
      clopt="$clopt /O1"
      ;;

    -pedantic) # Ignore.
      ;;

    -pipe) # Ignore.
      ;;

    -pg) # Ignore.
      ;;

    -[mp]thread*)
      : #clopt="$clopt /MT" # Is this The Right Thing to Do?
      ;;

    -rpath) # Ignore.
      shift;;

    -R*) # Ignore (run-paths).
      ;;

    -shared | -dynamic | -dynamiclib)
      shift
      # This is a bit useless since generally -g is a CFLAG/CXXFLAG and
      # -shared an LDFLAG and both don't come in action at the same time...
      linkopt="$linkopt /DLL"
      if $has_debug; then
        clopt="$clopt /LDd"
        linkopt="$linkopt /DEBUG"
      else
        clopt="$clopt /LD"
      fi
      use_shared=:
      ;;

    -static)
      use_static=:
      ;;

    -std=*)
      case $arg in
        c89 | iso9899:1990)
          clopt="$clopt /Za"
          ;;
        *)
          echo >&2 \
          "$0: The standard you requested ($arg) might not be available."
          ;;
      esac
      ;;

    -U)
      shift
      clopt="$clopt $arg"
      ;;

    -U?*)
      undef=/${arg#-}
      clopt="$clopt $undef"
      ;;

    -w)
      clopt="$clopt /w"
      ;;

    -W) # Ignored
      ;;

    -Wall)
      clopt="$clopt /Wall"
      ;;

    -Werror)
      clopt="$clopt /WX"
      ;;

    -W[^ae]*) # Other warning options ignored.
      ;;

    -x)
      shift
      case $1 in
        c | c-header | c-cpp-output)
          clopt="$clopt /TC"
          ;;
        c++ | c++-header | c++-cpp-output)
          clopt="$clopt /TP"
          ;;
        none) # Ignore.
          ;;
        *)
          echo "$0: Unsupported language type: $1" >&2
          ;;
      esac
      ;;

    *.[cC][cC] | *.[cC][xX][xX] | *.C | *.tcc | *.hpp | *.hh | *.hxx | *.hcc)
      # C++ source file with non .cpp extension, make sure cl understand 
      # that it is C++
      source_seen=:
      clopt="$clopt /Tp$arg"
    ;;

    *.cpp | *.c | *.h)
      source_seen=:
      clopt="$clopt $arg"
    ;;

    *)
      clopt="$clopt $arg"
      linkopt="$linkopt $arg"
      if test x"$optarg" != x ; then
        clopt="$clopt=$optarg"
        linkopt="$linkopt=$optarg"
      fi
    ;;

    esac
  shift
done

if $use_static && $use_shared; then
  echo "$0: warning: both a static and a shared output requested" >&2
fi

if $source_seen; then
  case `basename "$prog"` in
    link | link.exe)
      # We're about to link with the compiler: pass the linker args to the
      # compiler (which will, in turn, pass them to the linker).
      clopt="$clopt /link $linkopt"
      ;;
  esac
  prog='cl.exe'
fi

# Choose which opts we built up based on which program will actually run.
case `basename "$prog"` in
 cl | cl.exe)
    opts=$clopt
    ;;
  *)
    opts=$linkopt
    ;;
esac

echo "$0: running: $prog $opts"
exec "$prog" $opts
echo 'exec failed' >&2
exit 42
