# Macro for adding a compile flag for a certain language (and optionally build type)
# Also performs a check if the current compiler supports the flag
#
# This needs to be included AFTER the MPIConfig as the used MPI mnemonic is used here, too!
macro(addFlag VALUE LANGUAGE)
    getFlagCheckVariableName(${VALUE} ${LANGUAGE} CHK_VAR)
    if (${LANGUAGE} STREQUAL C)
        CHECK_C_COMPILER_FLAG("${VALUE}" ${CHK_VAR})
    elseif(${LANGUAGE} STREQUAL CXX)
        CHECK_CXX_COMPILER_FLAG("${VALUE}" ${CHK_VAR})
    elseif(${LANGUAGE} STREQUAL Fortran)
        CHECK_Fortran_COMPILER_FLAG("${VALUE}" ${CHK_VAR})
    endif()
    # Only add the flag if the check succeeded
    if (${CHK_VAR})
        set(__FLAGS_VARNAME CMAKE_${LANGUAGE}_FLAGS)
        if (NOT "${ARGV2}" STREQUAL "")
            set(__FLAGS_VARNAME ${__FLAGS_VARNAME}_${ARGV2})
        endif()
        set(${__FLAGS_VARNAME} "${${__FLAGS_VARNAME}} ${VALUE}")
    endif()
endmacro()

macro(addFlagAll VALUE)
    foreach(lang C CXX Fortran)
        addFlag(${VALUE} ${lang} ${ARGV1})
    endforeach()
endmacro()

function(getFlagCheckVariableName FLAG LANGUAGE RESULT_VAR)
    if (${FLAG} MATCHES "^-.*")
        string(SUBSTRING ${FLAG} 1 -1 FLAG) 
    endif()
    string(REGEX REPLACE "[^a-zA-Z0-9 ]" "_" RES ${FLAG})
    set(${RESULT_VAR} ${LANGUAGE}_COMPILER_FLAG_${RES} PARENT_SCOPE)
endfunction()

include(CheckCCompilerFlag)
include(CheckCXXCompilerFlag)
include(CheckFortranCompilerFlag)

# ABI detection - no crosscompiling implemented yet, so will use native
#if (NOT ABI)
#if( CMAKE_SIZEOF_VOID_P EQUAL 8 )
#	SET(ABI 64)
#else()
#	SET(ABI 32)
#endif()
#endif()
#foreach(lang C CXX Fortran)
#    SET(CMAKE_${lang}_FLAGS "-m${ABI} ${CMAKE_${lang}_FLAGS}")
#endforeach()

if (CMAKE_COMPILER_IS_GNUC OR CMAKE_C_COMPILER_ID STREQUAL "GNU" OR MINGW)
    
    addFlagAll("-pipe")
    
    if(CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL x86_64)
        addFlagAll("-march=nocona")
    endif()
    
    # Release
    addFlagAll("-O3" RELEASE)
    addFlag("-funroll-all-loops" C RELEASE)
        
    # Debug
    addFlagAll("-O0" RELEASE)
     
    if (WARN_ALL)
        addFlagAll("-Wall" DEBUG)
    endif()
    addFlag("-fbacktrace" Fortran DEBUG)
    # Compiler minor >= 8
    if (CMAKE_Fortran_COMPILER_VERSION VERSION_GREATER 4.7)
        addFlag("-Warray-temporaries" Fortran DEBUG)
        addFlag("-Wextra" Fortran DEBUG)
        addFlag("-Wsurprising" Fortran DEBUG)
        addFlag("-Wrealloc-lhs-all" Fortran DEBUG)
    endif()
    if (CHECK_ALL)
        # Compiler version 4.4
        if (CMAKE_Fortran_COMPILER_VERSION VERSION_EQUAL 4.4)
            addFlag("-fbounds-check" Fortran DEBUG)
        endif()
        # Compiler minor >= 8
        if (CMAKE_Fortran_COMPILER_VERSION VERSION_GREATER 4.7)
            addFlag("-finit-real=snan" Fortran DEBUG)
        endif()
        # Newer versions
        addFlag("-fcheck=all" Fortran DEBUG)
    endif()
    
    # Thus far all compilers seem to use the -p flag for profiling
    if (WITH_PROFILING)
        addFlag("-g" C)
        addFlag("-pg" C)
    endif()
    
elseif (CMAKE_C_COMPILER_ID STREQUAL "Intel" OR CMAKE_CXX_COMPILER_ID STREQUAL "Intel")
    # ABI Flag -m$(ABI)
    
    # CMake default anyways
    #addFlagAll("-O3" RELEASE)

    # Somehow CMake does not add the appropriate C-standard flags even though
    # the C_STANDARD variable is set. Well do it manually for now.
    #
    # EDIT: Unfortunately, this does not work out for all components. e.g. the gdcm build fails
    # with that switched on. Currently, i've added that flag for the superlu_dist package only. 
    #if (UNIX)
    #	addFlag("-std=c99" C)
    #endif()
    
    # Release
#    addFlagAll("-fast" RELEASE)
    
    # Debug
    addFlagAll("-traceback" DEBUG)
    if (OC_WARN_ALL)
        addFlag("-Wall" C DEBUG)
        addFlag("-Wall" CXX DEBUG)
        addFlag("-warn all" Fortran DEBUG)
    endif()
    if (OC_CHECK_ALL)
        foreach(lang C CXX)
            addFlag("-Wcheck" ${lang} DEBUG)
            addFlag("-fp-trap=common" ${lang} DEBUG)
            addFlag("-ftrapuv" ${lang} DEBUG)
        endforeach()
        addFlag("-check all" Fortran DEBUG)
        addFlag("-fpe-all=0" Fortran DEBUG)
        addFlag("-ftrapuv" Fortran DEBUG)
    endif()

elseif(CMAKE_C_COMPILER_ID STREQUAL "XL" OR CMAKE_CXX_COMPILER_ID STREQUAL "XL") # IBM case
    if (OC_MULTITHREADING)
        # FindOpenMP uses "-qsmp" for multithreading.. will need to see.
        addFlagAll("-qomp" RELEASE)
        addFlagAll("-qomp:noopt" DEBUG)
    endif()
    # ABI Flag -q$(ABI)
    
    # Instruction type - use auto here (pwr4-pwr7 available)
    addFlagAll("-qarch=auto")
    addFlagAll("-qtune=auto")
    
    # Release
    addFlagAll("-qstrict" RELEASE)
    
    # Debug
    if (OC_WARN_ALL)
        # Assuming 64bit builds here. will need to see if that irritates the compiler for 32bit arch
        addFlagAll("-qflag=i:i" DEBUG)
        addFlagAll("-qwarn64" DEBUG)
    endif()
    if (OC_CHECK_ALL)
        addFlagAll("-qcheck" DEBUG)
    endif()
endif()

# Thus far all compilers seem to use the -p flag for profiling
if (WITH_PROFILING)
    addFlagAll("-p" )
endif()

# Some verbose output for summary
foreach(lang C CXX Fortran)
    if (CMAKE_${lang}_FLAGS)
        message(STATUS "${lang} flags=${CMAKE_${lang}_FLAGS}")
    endif()
    if (CMAKE_${lang}_FLAGS_RELEASE)
        message(STATUS "${lang} flags (RELEASE)=${CMAKE_${lang}_FLAGS_RELEASE}")
    endif()
    if (CMAKE_${lang}_FLAGS_DEBUG)
        message(STATUS "${lang} flags (DEBUG)=${CMAKE_${lang}_FLAGS_DEBUG}")
    endif()
endforeach()

if(CMAKE_HOST_SYSTEM_NAME STREQUAL Linux)
  
    
        
        
        if(NOT WITH_PROFILING)
            if(CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL i686 OR CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL x86_64)
                set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -momit-leaf-frame-pointer")
            endif()
        else()
            set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -pg")
        endif()
    endif()
  
    if(CMAKE_C_COMPILER_ID STREQUAL Intel)
        set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -wall")#-m${ABI}
        if(CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL x86_64)
            if(COMMAND "grep Intel /proc/cpuinfo 2>/dev/null")
                if(COMMAND "grep Duo /proc/cpuinfo 2>/dev/null")
                    if(COMMAND "grep Core(TM)2 /proc/cpuinfo 2>/dev/null")
                        set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -xT")
                    else()
                        set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -x0")
                    endif()
                else()
                    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -xP")
                endif()
            else()
                set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -xW")
            endif()
        endif()
        if(CMAKE_HOST_SYSTEM_PROCESSOR MATCHES i%86)
            if(COMMAND "grep sse2 /proc/cpuinfo 2>/dev/null")
                set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -xN")
            endif()
        endif()
        set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -O0")
        set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O3 -ansi_alias")
        if(WITH_PROFILING)
            set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -pg")
            set(ELFLAGS "ELFLAGS -pg")
        endif()
        if(${MPIPROF} STREQUAL true)
          #if(${MPI} STREQUAL mpich2)
          #  set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wl,--export-dynamic")
          #  set(CMAKE_C_FLAGS_DEBUG "CMAKE_C_FLAGS_DEBUG -Wl,--export-dynamic")
          #endif()
        endif()
    endif()
  
  if(${CC} MATCHES xlc%)
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -qinfo=gen:ini:por:pro:trd:tru:use") #TODO line303
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -q${ABI} -qarch=auto -qhalt=e")
    set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -qfullpath -C -qflttrap=inv:en -qinitauto=7F")
    set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O3")
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Dunix")
  endif()
  
  #if(${CC} STREQUAL cc)
  #  set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -O0 -g")
  #  set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O3")
  #  if(${PROF} STREQUAL true)
  #    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -pg")   
  #  endif()
  #endif()
  
  if(CMAKE_COMPILER_IS_GNUFortran)
    set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -pipe -m${ABI} -fno-second-underscore -Wall -x f95-cpp-input")
    set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -ffree-line-length-132")
    set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -fmax-identifier-length=63")
    set(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} -fPIC")
    if(${MACHNAME} STREQUAL x86_64)
      if(COMMAND "grep Intel /proc/cpuinfo 2>/dev/null")
        set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -march=nocona")
      endif()
    endif()
    set(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} -O0 -fbounds-check")
    set(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} -O3 -Wuninitialized -funroll-all-loops")
    if(${PROF} STREQUAL false)
      if((${INSTRUCTION} STREQUAL i686) OR (${INSTRUCTION} STREQUAL x86_64))
        set(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} -momit-leaf-frame-pointer")   
      endif()
    else()
      set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -g -pg")
      set(ELFLAGS "ELFLAGS -pg")
    endif()
  endif()
  
  if(CMAKE_Fortran_COMPILER_ID STREQUAL G95)
    set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -fno-second-underscore -Wall -m${ABI} -std=f2003")
    set(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} -fPIC")
    set(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} -O0 -fbound-check")
    set(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} -O3 -Wuninitialized -funroll-all-loops")
    set(ELFLAGS "ELFLAGS -m${ABI}")
  endif()
  
  if(CMAKE_Fortran_COMPILER_ID STREQUAL Intel)
    set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -cpp -warn all -m${ABI}")
    if(${MACHNAME} STREQUAL x86_64)
      if(COMMAND "grep Intel /proc/cpuinfo 2>/dev/null")
        if(COMMAND "grep Duo /proc/cpuinfo 2>/dev/null")
          if(COMMAND "grep Core(TM)2 /proc/cpuinfo 2>/dev/null")
            set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -xT")
          else()
            set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -x0")
          endif()
        else()
          set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -xP")
        endif()
      else()
        set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -xW")
      endif()
    endif()
    if(${MACHINE} MATCHES i%86)
      if(COMMAND "grep sse2 /proc/cpuinfo 2>/dev/null")
        set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -xN")
      endif()
    endif()  
    set(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} -O0 -check all -traceback -debug all")
    set(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} -O3")
    if(not(${PROF} STREQUAL false))
      set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -g -pg")   
      set(ELFLAGS "${ELFLAGS} -pg")
      set(ELFLAGS "ELFLAGS -pg")
    endif()
    if(${MPIPROF} STREQUAL true)
      #if(${MPI} STREQUAL mpich2)
      #  set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -Wl,--export-dynamic")
      #  set(CMAKE_Fortran_FLAGS_DEBUG "CMAKE_Fortran_FLAGS_DEBUG -Wl,--export-dynamic")
      #else()
      #  set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -tcollect")
      #endif()
    endif()
    set(ELFLAGS "${ELFLAGS} -nofor_main -m${ABI} -traceback")
  endif()
  
  if(CMAKE_Fortran_COMPILER MATCHES xlf%)
    set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -qarch=auto -qhalt=e -qextname -qsuffix=cpp=f90") 
    set(EFLAGS "${EFLAGS} -q${ABI}")
    if(${ABI} STREQUAL 64)
      set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -qwarn64")
    endif()
    if(${DEBUG} STREQUAL false)
      set(MP_FLGS "-qsmp=omp")
    else()
      set(MP_FLGS "-qsmp=omp:noopt")
    endif()
    set(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} -qfullpath -C -qflttrap=inv:en -qextchk -qinitauto=7FF7FFFF")
    set(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} -O3")
  endif()
  
  if(CMAKE_Fortran_COMPILER STREQUAL ftn)
    set(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} -O0 -g") 
    set(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} -O3")
    if(${PROF} STREQUAL true)
      set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -g -pg")   
      set(ELFLAGS "${ELFLAGS} -pg")
    endif()
  endif()
   
  set(ELFLAGS "${ELFLAGS} -static-libgcc")
  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DBSD_TIMERS")

#######################################################################
elseif (CMAKE_HOST_SYSTEM_NAME STREQUAL Windows)
 #TODO ?

#######################################################################
elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL Darwin)
    message(STATUS "===${FC}==${ABI}==${PROF}===${INSTRUCTION}") 
    if(CMAKE_COMPILER_IS_GNUFortran)
        set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -pipe -m${ABI} -fno-second-underscore -Wall -x f95-cpp-input")
        set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -ffree-line-length-132")
        set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -fmax-identifier-length=63")
        set(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} -fPIC")
        if(${MACHNAME} STREQUAL x86_64)
            if(COMMAND "grep Intel /proc/cpuinfo 2>/dev/null")
            set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -march=nocona")
        endif()
    endif()
    set(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} -O0 -fbounds-check")
    set(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} -O3 -Wuninitialized -funroll-all-loops")
    if(NOT WITH_PROFILING)
        if((${INSTRUCTION} STREQUAL i686) OR (${INSTRUCTION} STREQUAL x86_64))
            set(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} -momit-leaf-frame-pointer")   
        endif()
    else()
        set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -g -pg")
        set(ELFLAGS "ELFLAGS -pg")
    endif()

#######################################################################
elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL aix)
  #if(${MP} MATCHES false)
  #  set(${FC} mpxlf95)
  #  set(${CC} xlc)
  #else()
  #  set(${FC} mpxlf95_r)
  #  set(${CC} xlc_r)
  #endif()
  set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -qsuffix=cpp=f90 -qnoextname")
  set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -qinfo=gen:ini:por:pro:trd:tru:use") # TODO line 455
  set(ELFLAGS "${ELFLAGS} -q${ABI}")
  set(CFE_FLGS "${CFE_FLGS} -q${ABI} -qarch=auto -qhalt=e")
  set(L_FLGS "${L_FLGS} -b${ABI}")
  set(D_FLGS "-G -bexpall -bnoentry")
  if(${ABI} STREQUAL 32)
    set(ELFLAGS "${ELFLAGS} -bmaxdata:0x80000000/dsa")
  else()
    set(CF_FLGS "${CF_FLGS} -qwarn64")
    set(ELFLAGS "${ELFLAGS} -bmaxdata:0x0000100000000000")
  endif()
  if(${DEBUG} STREQUAL false)
    set(MP_FLGS "-qsmp=omp")
  else()
    set(MP_FLGS "-qsmp=omp:noopt")
  endif()
  set(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} -qfullpath -C -qflttrap=inv:en -qextchk")
  set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -qfullpath -C -qflttrap=inv:en -qextchk")
  set(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} -qinitauto=7FF7FFFF")
  set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -qinitauto=7F")
  set(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} -O3")
  set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O3")
  set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -qnoignerrno")
  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DBSD_TIMERS")
endif()
endif()
