#Handle compiler/defaults

#-------------
#Handle libraries (HDF5/OMP/MPI)
find_package(HDF5 REQUIRED COMPONENTS Fortran Fortran_HL)
set(CMAKE_REQUIRED_INCLUDES ${HDF5_Fortran_INCLUDE_DIRS})
set(CMAKE_REQUIRED_LIBRARIES ${HDF5_Fortran_LIBRARIES} ${HDF5_Fortran_HL_LIBRARIES})
# h5 compiler helper can have issues with some preprocessor commands, just link libraries
link_libraries(${HDF5_Fortran_LIBRARIES} ${HDF5_Fortran_HL_LIBRARIES})

find_package(OpenMP COMPONENTS Fortran)
set(CMAKE_REQUIRED_FLAGS ${OpenMP_Fortran_FLAGS})
set(CMAKE_REQUIRED_LIBRARIES ${OpenMP_Fortran_LIBRARIES})

if (ENABLE_MPI)
    #mpi is a nightmare
    #try to explicitly find intel mpi first
    set(MPI_Fortran_COMPILER mpiifort)
    find_package(MPI COMPONENTS Fortran QUIET)
    find_program(MPIEXE mpiifort)
    if(NOT MPI_FOUND OR NOT MPI_Fortran_HAVE_F08_MODULE OR NOT MPIEXE)
        #try to find a fortran 2008 specific wrapper
        set(MPI_Fortran_COMPILER mpif08)
    	find_package(MPI COMPONENTS Fortran QUIET)
        unset(MPIEXE CACHE)
        unset(MPIEXE-NOTFOUND CACHE)
        find_program(MPIEXE mpif08)
        if(NOT MPI_FOUND OR NOT MPI_Fortran_HAVE_F08_MODULE OR NOT MPIEXE)
            #just look for whatever
            unset(MPI_Fortran_COMPILER)
            find_package(MPI REQUIRED COMPONENTS Fortran)
        endif()
    endif()
    if(MPI_FOUND AND MPI_Fortran_HAVE_F08_MODULE)
        message("-- Found MPI")
    else()
        message(FATAL_ERROR "Could not find an MPI Library that supports the F08 interface")
    endif()
endif()

#-------------
#Set default build to release
if(NOT CMAKE_BUILD_TYPE)
	set(CMAKE_BUILD_TYPE "Release")
endif()

#-------------
#Set base release options
set(CMAKE_DEFOPT "-O3") #Default optimization

#-------------
#Set minimum compiler versions
if(CMAKE_Fortran_COMPILER_ID MATCHES Intel)
	if(CMAKE_Fortran_COMPILER_VERSION VERSION_LESS 17.0)
		message("Fortran compiler too old!  What, were you gonna use punch cards?")
		message(FATAL_ERROR "ifort > 17.0 required")
	elseif( (CMAKE_Fortran_COMPILER_VERSION VERSION_GREATER_EQUAL 17.0) AND (CMAKE_Fortran_COMPILER_VERSION VERSION_LESS 18.0) )
		message(WARNING "Compiler has incomplete F2008 features, Git hash/compiler information won't be saved to H5 files")
		add_compile_definitions(__INTEL_COMPILER_OLD)
	elseif( (CMAKE_Fortran_COMPILER_VERSION VERSION_GREATER_EQUAL 20.0) )
		message(WARNING "Setting default optimization to O2 to avoid certain Intel compiler bugs")
    	set(CMAKE_DEFOPT "-O2")
    endif()
elseif(CMAKE_Fortran_COMPILER_ID MATCHES GNU)
	if(CMAKE_Fortran_COMPILER_VERSION VERSION_LESS 8.0)
		message("Fortran compiler too old!  What, were you gonna use punch cards?")
		message(FATAL_ERROR "gfortran > 8.0 required")
	endif()
endif()

if(FAST_YOLO)
    message("*** RUNNING WITH IMPRECISE HIGH SPEED OPTIONS ***")
    set(CMAKE_DEFOPT "-O3") #over-ride default optimization to maximum
endif()

set(CMAKE_Fortran_FLAGS_DEBUG "-O0 -g")
set(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_DEFOPT}")
set(CMAKE_Fortran_FLAGS_RELWITHDEBINFO "${CMAKE_DEFOPT} -g")

#Do compiler specific options
if(CMAKE_Fortran_COMPILER_ID MATCHES Intel)
	set(dialect "-free -implicitnone")
	#Base
	string(APPEND CMAKE_Fortran_FLAGS " -fPIC -fpconstant")
	#Production
    set(PROD "-align array64byte -align rec32byte -no-prec-div")
    if (CMAKE_Fortran_COMPILER_VERSION VERSION_LESS 23.1)
    	#Fast transcendentals removed in ifx
    	string(APPEND PROD " -fast-transcendentals")
    endif()
    	
    #Production with Debug Info
    set(PRODWITHDEBUGINFO "-traceback -debug all -align array64byte -align rec32byte -no-prec-div -fast-transcendentals")
	#Debug
        set(DEBUG "-traceback -debug all -gen-interfaces")
        if(NOT DISABLE_DEBUG_BOUNDS_CHECKS)
                string(APPEND DEBUG " -check bounds -check uninit -fp-stack-check -fstack-security-check")
        endif()
        if(NOT PFUNIT_FOUND)
                # Known bug with warning interfaces and PFUNIT
                string(APPEND DEBUG " -warn interfaces")
        endif()

    if(PRINT_OPT_INFO)
        string(APPEND CMAKE_Fortran_FLAGS " -check arg_temp_created -qopt-report-phase=vec -qopt-report=2")
    endif()

	#Now do OS-dep options
	if (CMAKE_SYSTEM_NAME MATCHES Darwin)
		string(APPEND CMAKE_Fortran_FLAGS " -Wl,-stack_size,0x40000000,-stack_addr,0xf0000000 -xHost")
	else()
		#If we're not doing Mac, then add IPO
		string(APPEND PROD " -ipo")
		string(APPEND PRODWITHDEBUGINFO " -ipo")
	endif()

	#Handle individual hosts
	if (HOST MATCHES cheyenne)
		string(APPEND PROD " -march=corei7 -axCORE-AVX2")
		string(APPEND PRODWITHDEBUGINFO " -march=corei7 -axCORE-AVX2")
    elseif(HOST MATCHES pfe)
		string(APPEND PROD " -march=corei7 -axCORE-AVX2")
		string(APPEND PRODWITHDEBUGINFO " -march=corei7 -axCORE-AVX2")
	elseif (HOST MATCHES derecho)
		message("You're on Derecho, good for you!")
		if (ENABLE_MKL)
			string(APPEND CMAKE_Fortran_FLAGS " -qmkl")
		endif()
		string(APPEND PROD " -march=core-avx2")
		string(APPEND PRODWITHDEBUGINFO " -march=core-avx2")
	elseif (HOST MATCHES stampede3)
		message("You're on Stampede3!")
		if (ENABLE_MKL)
			string(APPEND CMAKE_Fortran_FLAGS " -qmkl")
		endif()
		string(APPEND PROD " -xCORE-AVX512")
		string(APPEND PRODWITHDEBUGINFO " -xCORE-AVX512")
	endif()


	#Check Intel Fortran version
	if(NOT ALLOW_INVALID_COMPILERS AND CMAKE_Fortran_COMPILER_VERSION VERSION_GREATER "2021.9" AND CMAKE_Fortran_COMPILER_VERSION VERSION_LESS "2025.1")
		message(FATAL_ERROR "Intel OneAPI compilers between 2022-2024 have compiler bugs which cause weird numerical errors in our code. You can set the ALLOW_INVALID_COMPILERS variable to ON to force compilation at your own risk. You'll probably get what you deserve.")
	endif()

	#Check for MKL + intel25
	if (ENABLE_MKL AND (CMAKE_Fortran_COMPILER_VERSION VERSION_GREATER "2024"))
		message(WARNING "Intel OneAPI MKL has been found to fail in weird ways and should probably be avoided. But hey, do what you want. I'm a warning message, not a cop.")
	endif()

elseif(CMAKE_Fortran_COMPILER_ID MATCHES GNU)
	set(dialect "-ffree-form -ffree-line-length-none -fimplicit-none")
	#Base
	string(APPEND CMAKE_Fortran_FLAGS " -fPIC")
	#Production
	set(PROD "-ffast-math")
	#Debug
    if(NOT DISABLE_DEBUG_BOUNDS_CHECKS)
    	set(DEBUG "-fbacktrace -g -Warray-temporaries -Wall -Wfatal-errors -finit-local-zero")
    else()
        set(DEBUG "-fbacktrace -g -Warray-temporaries -Wall -Wfatal-errors")
    endif()
	#Now do machine-dep options
	if (CMAKE_SYSTEM_NAME MATCHES Darwin)
		if (CMAKE_HOST_SYSTEM_PROCESSOR MATCHES arm64)
			#Apple silicon
			message("OSX Arch: ${CMAKE_HOST_SYSTEM_PROCESSOR}")
		else()
			#Older stuff, add big stack
			string(APPEND CMAKE_Fortran_FLAGS " -Wl,-stack_size,0x40000000,-stack_addr,0xf0000000")
		endif()
	endif()
endif()

string(APPEND CMAKE_Fortran_FLAGS " ${dialect}")
string(APPEND CMAKE_Fortran_FLAGS_DEBUG " ${DEBUG}")
string(APPEND CMAKE_Fortran_FLAGS_RELEASE " ${PROD}")
string(APPEND CMAKE_Fortran_FLAGS_RELWITHDEBINFO " ${PRODWITHDEBUGINFO}")

if(ENABLE_OMP)
	string(APPEND CMAKE_Fortran_FLAGS " ${OpenMP_Fortran_FLAGS}")
endif()
if(ENABLE_MPI)
    add_compile_options(${MPI_Fortran_COMPILE_OPTIONS})
	add_definitions(${MPI_Fortran_COMPILE_DEFINITIONS})
	include_directories(${MPI_Fortran_INCLUDE_DIRS})
	link_directories(${MPI_Fortran_LIBRARIES})
    string(APPEND CMAKE_Fortran_FLAGS " ${MPI_Fortran_LINK_FLAGS}")

    if(CMAKE_Fortran_COMPILER_ID MATCHES Intel AND MPI_Fortran_COMPILER MATCHES mpiifort)
        #Using Intel Compiler and Intel MPI, use thread safe mpi compiler flag
        string(APPEND CMAKE_Fortran_FLAGS " -mt_mpi")
    else()
        #use different MPI link command
        string(APPEND CMAKE_Fortran_FLAGS " -lmpi")
    endif()

	set(CMAKE_Fortran_COMPILER ${MPI_Fortran_COMPILER})
	# we changed compiler, link HDF5 libraries
	link_libraries(${HDF5_Fortran_LIBRARIES} ${HDF5_Fortran_HL_LIBRARIES})
endif()
if(ENABLE_CODECOV)
    # track code coverage
    file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/bin/codecov_prof)
    string(APPEND CMAKE_Fortran_FLAGS " -prof-gen=srcpos -prof-dir=${CMAKE_BINARY_DIR}/bin/codecov_prof")
endif()

