#!/bin/sh
# $Id: cc-config.sh,v 1.13 2006/10/10 04:14:55 devel Exp $
# Author: Jim Brooks  http://www.jimbrooks.org
#
# Print to stdout appropriate and optimal GNU g++ options
# for compiling OpenGL programs on a system with GNU tools.
#
# Args (these are optional and override auto/default settings):
# * -arch <arg>
#   gcc uses -march while gfx uses -arch.
#   Currently this is meant only for selecting siblings within the same arch
#   (eg k6 vs. k6-2) or otherwise optimization flags that are auto-selected
#   will be inappropriate.
# * -mfpmath <arg>
# * name of gcc/g++ is assumed if arg is none of the above
#
# Detection of CPU/arch isn't perfect, therefore, it is disabled if
# make ARCH=<arch>|"generic" is specified by user.
#
# Notes: This used to cache its results but GNUmakefile_common
#        only invokes it once per-subdir anyway.
#-------------------------------------------------------------------------------

# Detect which OS from environment variable.
( echo $OSTYPE | grep -q -i linux  ) && LINUX=1
( echo $OSTYPE | grep -q -i darwin ) && DARWIN=1
( echo $OSTYPE | grep -q -i cygwin ) && CYGWIN=1

# gcc 4.1 deprecates -mcpu but Apple gcc still needs it.
EchoArch() {
    if [ $ARCH ]; then
        if [ $DARWIN ]; then
            echo -n "-mcpu=$ARCH "
        else
            echo -n "-march=$ARCH "
        fi
    fi
}

#===============================================================================
# Parse args.
#===============================================================================

while [ $# -gt 0 ]
do
    # Override default mfpmath.
    if [ "$1" = "-mfpmath" ]; then
        # Option for how to compile FP math instructions on x86/x87.
        shift
        MFPMATH=$1
        if [ -z $1 ] ; then
           echo "cc-config.sh: -mfpmath missing arg"
           exit 1
        fi
    elif [ "$1" = "-arch" ]; then
        # Target arch was specified.
        # gcc uses -march while gfx uses -arch.
        # gcc has deprecated -mcpu in favor of -march.
        shift
        ARCH=$1
        if [ -z $1 ] ; then
           echo "cc-config.sh: -arch missing arg"
           exit 1
        fi
        if [ "$ARCH" = "generic" ]; then
            # make ARCH=generic means to use compiler's default target CPU.
            ARCH_GENERIC=1
            unset ARCH
        else
            EchoArch
        fi
    elif [ "$1" = "DEBUG" ]; then
        # DEBUG/PROFILE can equal 0,1,2.
        # To simplify, if DEBUG/PROFILE=0 were on make's cmd-line, they're empty strings here.
        shift
        [ "$1" != "0" ] && DEBUG=$1
    elif [ "$1" = "PROFILE" ]; then
        shift
        [ "$1" != "0" ] && PROFILE=$1
    elif [ "$1" = "QUICK" ]; then
        # QUICK=1 means to compile quickly (less optimizations).
        shift
        [ "$1" != "0" ] && QUICK=$1
    else
        # None of the above.  Assume this is name of gcc/g++.
        GCC=$1
    fi

    shift
done

# Try to detect CPU/arch unless args were specified.
if [ -z $ARCH ] && [ -z $ARCH_GENERIC ]; then
    DETECT_ARCH=1
fi

#===============================================================================
# Determine compiler version.
#===============================================================================

# Default name of compiler.
if [ -z "$GCC" ]; then
    GCC=g++
fi

# Get major/minor number of compiler version.
# Eg GCCVER=30 on gcc-3.0.
# Only two digits are obtained as -dumpversion on gcc-3.0
# prints only "3.0" without any third/patch number (eg "3.3.3").
GCCVER_=`$GCC -dumpversion`
#GCCVER=`expr substr $GCCVER_ 1 1``expr substr $GCCVER_ 3 1`
GCCVER=`echo $GCCVER_ | cut -c 1``echo $GCCVER_ | cut -c 3`

#===============================================================================
# Arch-specific optimization flags.
#===============================================================================

# Linux/x86:
# Cope with features/options that not all x86/gcc versions support.
# -m3dnow,-msse,-msse2 were introduced in gcc 3.1.
# http://gcc.gnu.org/gcc-3.1/changes.html
GccOptX86() {
    OPT=$1
    # Does this CPU support this option?
    # cygwin does have a Linux-like /proc.
    if ( cat /proc/cpuinfo 2>/dev/null | grep flags | grep -q -i $OPT ); then
        # Is this gcc version 3.1 or higher?
        if [ $GCCVER -ge 31 ]; then
            echo -n "-m${OPT} "
            # For single-precision, -fpmath=sse compiles faster
            # scalar SSE instructions instead of x87 instructions.
            if [ "$OPT" = "sse" ]; then
                if [ -z "$MFPMATH" ]; then
                    echo -n "-mfpmath=sse "
                    #echo -n "-mfpmath=sse,387 "
                else
                    echo -n "-mfpmath=${MFPMATH} "
                fi
            fi
        fi
    fi
}

# Linux optimization flags.
if [ $DETECT_ARCH ] && ( grep -q -i "vendor.*Intel\|vendor.*AMD" /proc/cpuinfo 2>/dev/null ); then
    # Linux/x86 ------------------------------------------
    # All gcc versions support these options.
    # -march=i686 compiles minor tweaks such as P6 CMOV.

    echo -n "-DCPU_X86=1 "

    # x86-64?
	if [ "`uname -m`" = "x86_64" ]; then
        X86_64=1
        # -m64 must precede -march
        echo -n "-m64 "
    else
        # Explicit -m32 is useful if distcc is used across x86-32 and x86-64 hosts.
        [ $GCCVER -ge 30 ] && echo -n "-m32 "
    fi

    # Which x86 vendor?
    if ( grep -q "vendor.*Intel" /proc/cpuinfo ); then
        # Intel.
        if [ $X86_64 ]; then
            ARCH="nocona"
        elif ( grep -q "cpu.family.*[ 6]" /proc/cpuinfo ); then
            ARCH="i686"
        else
            ARCH="i586"
        fi
    elif ( grep -q "vendor.*AuthenticAMD" /proc/cpuinfo ); then
        # AMD.
        if [ $X86_64 ]; then
            ARCH="athlon64"
        elif ( grep -q "model name.*Athlon" /proc/cpuinfo ); then
            ARCH="athlon"
        else
            ARCH="k6"
        fi
    fi

    # Echo arch if detected.
    [ $ARCH ] && EchoArch

    # Only some gcc versions support these options (see comments above).
    GccOptX86 3dnow
    GccOptX86 sse
    GccOptX86 sse2
    GccOptX86 sse3
else
	# Linux/other -----------------------------------------
    :
fi

# Mac OS X PowerPC optimizations.
if [ $DETECT_ARCH ] && [ $DARWIN ]; then

    # PowerPC 970 (G5).
    if [ "$QUICK" != "1" ] && [ "`machine`" = "ppc970" ]; then
        # These are from man gcc (gcc-3.3.3 Mac OS X Panther).
        echo -n "-mcpu=G5 -mtune=G5 -mpowerpc64 "
        echo -n "-O3 -funroll-loops "
        echo -n "-fsched-interblock "
        echo -n "-falign-loops=16 -falign-jumps=16 -falign-functions=16 "
        if [ $GCCVER -lt 40 ]; then
            echo -n "-falign-jumps-max-skip=15 "
            echo -n "-falign-loops-max-skip=15 "
        fi
        echo -n "-ffast-math -mdynamic-no-pic -mpowerpc-gpopt -force_cpusubtype_ALL "
        # These cause bad code:
        #echo -n "-fstrict-aliasing -malign-natural "
    fi

    # Altivec (FP SIMD).
    if [ $GCCVER -lt 40 ] && [ "$ARCH" != "G3" ]; then
        # For whatever reason, this causes a ton of compile errors on g++ 4.0.0 (fink).
        echo -n "-faltivec "
    fi

    if [ $GCCVER -le 33 ]; then
        # Recognized by gcc 3.3.3 but not 4.0.0 (why?).
        echo -n "-Wno-long-double "
    fi
fi

#===============================================================================
# Generic optimization flags.
#===============================================================================

# DEBUG/PROFILE can equal 0,1,2.
# To simplify, if DEBUG/PROFILE=0 were on make's cmd-line, they're empty strings here.

if [ "$PROFILE" = "1" ]; then
    # PROFILE=1 compiles without optimizations.
    # PROFILE=2 compiles with optimizations.
    echo -n "-O0 -fno-inline "
else
    if [ "$QUICK" ]; then
        # To compile quicker (make QUICK=1).
        # -O0 prevents catching uninitialized vars.
        echo -n "-O "
    else
        # Generic optimizations:
        echo -n "-O3 -funroll-loops "
        if [ -z "$DEBUG" ] && [ -z "$PROFILE" ] && [ $GCCVER -ge 30 ]; then
            # -fomit-frame-pointer inhibits debug info.
            echo -n "-fomit-frame-pointer "
        fi
    fi
fi

# Necessary 2006/10 due to naughty casts (the ignored warnings about punned-types were important!).
echo -n "-fno-strict-aliasing "

#===============================================================================
# Generic floating-point math options.
#===============================================================================

# WARNING: -ffast-math has the potential of causing wrong FP calculations!
# -ffast-math implies -funsafe-math-optimizations etc.

if [ $GCCVER -ge 30 ]; then
	# -fno-finite-math-only is required to detect NaN using the idiom !(f==f) on PowerPC G4 (et al?).
    echo -n "-ffast-math -fno-finite-math-only -fsingle-precision-constant "

    # Workaround for ICE gcc 4.0 on Darwin.
    if [ $GCCVER -eq 40 ] && [ $DARWIN ]; then
        echo -n "-fno-unsafe-math-optimizations "
    fi
else
	# -ffast-math cannot be used without -fno-finite-math-only (gcc 2.9 supports only -ffast-math).
    #echo -n "-ffast-math "
    :
fi

#===============================================================================
# Compiler warning options.
#===============================================================================

# -Wstrict-prototypes is N/A to g++.
# -Wshadow on older gcc causes excessive warnings.
# -Wno-attributes suppresses "packed attribute ignored for field of type" on gcc 4.1.

echo -n "-Wall "
[ -z "$PROFILE" ]  && echo -n "-Wuninitialized "
[ $GCCVER -ge 30 ] && echo -n "-Wshadow "
[ $GCCVER -lt 30 ] && echo -n "-Wno-non-template-friend "
[ $GCCVER -ge 41 ] && echo -n "-Wno-attributes "

#===============================================================================
# Determine header file include directories.
#===============================================================================

if [ $CYGWIN ]; then
   # No additional -I for cygwin.
   exit 0
fi

# --- UNIX ---
DIR=/usr/local/include
if [ -f $DIR/GL/glut.h ] || [ -f $DIR/GL/gl.h ]
then
   echo -n "-I$DIR "
   exit 0
fi

DIR=/usr/X11R6/include
if [ -f $DIR/GL/glut.h ] || [ -f $DIR/GL/gl.h ]
then
   echo -n "-I$DIR "
   exit 0
fi

DIR=/usr/X11/include
if [ -f $DIR/GL/glut.h ] || [ -f $DIR/GL/gl.h ]
then
   echo -n "-I$DIR "
   exit 0
fi

DIR=/usr/include
if [ -f $DIR/GL/glut.h ] || [ -f $DIR/GL/gl.h ]
then
   # Just exit, gcc will nag about /usr/include
   #echo -n "-I$DIR "
   exit 0
fi

# Oops.
echo "cc-config.sh: could not determine header file include dirs"
exit 1
