
include(EnableExtraCompilerWarnings)
include(CheckCXXCompilerFlag)
include(util)

MESSAGE(STATUS "Doing configuration specific to visual studio...")

set_property(GLOBAL PROPERTY DEBUG_CONFIGURATIONS Debug)

option(MSVC_USE_RUNTIME_DLL "Use the dynamically linked version of the runtime" OFF)
option(MSVC_RELEASE_DEBUGGING "Set options that allow to debug release builds" OFF)

MARK_AS_ADVANCED(FORCE MSVC_USE_RUNTIME_DLL)
MARK_AS_ADVANCED(FORCE MSVC_RELEASE_DEBUGGING)

# These are the warnings we disable
set(WARNING_FLAGS
	/wd4100 # unreferenced formal parameters
	/wd4127 # constant conditional (assert)
	/wd4201 # nonstandard extension used: nameless struct/union (happens a lot in Windows include headers)
	/wd4290 # C++ exception specification ignored except to indicate a function is not __declspec(nothrow)
	/wd4390 # empty control statement (triggered by nprintf and mprintf's inside of one-line if's, etc)
	/wd4410 # illegal size for operand... ie... 	fxch st(1)
	/wd4511 # copy constructor could not be generated (happens a lot in Windows include headers)
	/wd4512 # assignment operator could not be generated (happens a lot in Windows include headers)
	/wd4514 # unreferenced inline function removed
	/wd4611 # _setjmp warning.  Since we use setjmp alot, and we don't really use constructors or destructors, this warning doesn't really apply to us.
	/wd4663 # C++ language change (template specification)
	/wd4710 # is inline function not expanded (who cares?)
	/wd4711 # tells us an inline function was expanded (who cares?)
	/wd4786 # is identifier truncated to 255 characters (happens all the time in Microsoft #includes) -- Goober5000"
	/wd4996 # deprecated strcpy, strcat, sprintf, etc. (from MSVC 2005) - taylor
	/wd4311 # Disables warnings about casting pointer types to ints. The funny thing is these warnings can't be resolved, just disabled... - m!m
	/wd4302 # Same as above - m!m
	/wd4366 # The result of the unary '&' operator may be unaligned - m!m
	/wd4592 # "symbol will be dynamically initialized" is being generated by a compiler bug, see https://stackoverflow.com/a/34027257 for an explanation - m!m
	$<$<CONFIG:Release>:/wd4101> # In release mode there are unreferenced variables because debug needs them
	/wd4995 # "'vsprintf': name was marked as #pragma deprecated" is being caused by our custom definition of vsprintf. I have no idea what causes this or how to fix it - m!m
	/wd4723 # "potential divide by 0" is caused by some code that definitely will not divide by zero - m!m
	/wd4121 # "alignment of a member was sensitive to packing" happens in a Windows header - m!m
)

target_compile_options(compiler INTERFACE ${WARNING_FLAGS})

# Base
set(CMAKE_C_FLAGS "/MP /GS- /analyze- /Zc:wchar_t /errorReport:prompt /Zc:forScope /Gd /EHsc /nologo /Zm200")
set(CMAKE_CXX_FLAGS "/MP /GS- /analyze- /Zc:wchar_t /errorReport:prompt /Zc:forScope /Gd /EHsc /nologo /Zm200")

set(CMAKE_EXE_LINKER_FLAGS "/MANIFEST /SAFESEH:NO /ERRORREPORT:PROMPT /NOLOGO")
set(CMAKE_STATIC_LINKER_FLAGS "")

if(NOT IS_ARM64)
	set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /DYNAMICBASE:NO")
endif()

# Release
set(CMAKE_C_FLAGS_RELEASE "/GL /Gy- /Ox /Ot /Ob2 /fp:precise /GF /Oy /Oi /Zi /W3")
set(CMAKE_CXX_FLAGS_RELEASE "/GL /Gy- /Ox /Ot /Ob2 /fp:precise /GF /Oy /Oi /Zi /W3")
# /DEBUG:FULL so that we get PDBs which is needed for debugging crashdumps
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "/OPT:REF /LTCG /INCREMENTAL:NO /DEBUG:FULL")
set(CMAKE_STATIC_LINKER_FLAGS_RELEASE "/LTCG")

globally_enable_extra_compiler_warnings()

if (MSVC_RELEASE_DEBUGGING)
	CHECK_CXX_COMPILER_FLAG("/Zo" MSVC_COMPILER_SUPPORTS_ARCH_ZO)

	if (MSVC_COMPILER_SUPPORTS_ARCH_ZO)
		set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /Zo")
		set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Zo")
	endif()
endif()

# This should be kept in sync with the corresponding IF() in fred2/CMakeLists.txt
IF(MSVC_USE_RUNTIME_DLL OR FSO_BUILD_QTFRED)
	set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<NOT:$<CONFIG:Release>>:Debug>DLL")
	add_compile_definitions(_AFXDLL)
ELSE()
	set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<NOT:$<CONFIG:Release>>:Debug>")
ENDIF()

# Debug
set(CMAKE_C_FLAGS_DEBUG "/W4 /Gy /Zi /Od /RTC1 /Gd /Oy-")
set(CMAKE_CXX_FLAGS_DEBUG "/W4 /Gy /Zi /Od /RTC1 /Gd /Oy-")
set(CMAKE_EXE_LINKER_FLAGS_DEBUG "/DEBUG /INCREMENTAL:NO /MAPINFO:EXPORTS /NODEFAULTLIB:libcmt.lib")

INCLUDE(MSVCMultipleProcessCompile)

# Visual Studio supports compiling for multiple vector instruction sets

if(IS_X86)
	if(FORCED_NATIVE_SIMD_INSTRUCTIONS)
		# MSVC has no direct -march=native equivalent, so just use the detected extensions.
		SET(FSO_INSTRUCTION_SET ${DETECTED_SIMD_INSTRUCTIONS})
	endif()

	if(FSO_INSTRUCTION_SET STREQUAL "")
		set(MSVC_SIMD_INSTRUCTIONS "IA32")
	else()
		set(MSVC_SIMD_INSTRUCTIONS ${FSO_INSTRUCTION_SET})
	endif()

	if (NOT (IS_64BIT AND (MSVC_SIMD_INSTRUCTIONS STREQUAL "IA32" OR MSVC_SIMD_INSTRUCTIONS STREQUAL "SSE" OR MSVC_SIMD_INSTRUCTIONS STREQUAL "SSE2")))
		# 32-Bit and SSE(2) mustn't be set, as these are implied in x86_64 and thus MSVC does not support it for the /arch argument
		CHECK_CXX_COMPILER_FLAG("/arch:${MSVC_SIMD_INSTRUCTIONS}" COMPILER_SUPPORTS_ARCH)

		IF(COMPILER_SUPPORTS_ARCH)
			set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /arch:${MSVC_SIMD_INSTRUCTIONS}")
			set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /arch:${MSVC_SIMD_INSTRUCTIONS}")
		ELSE()
			message( FATAL_ERROR "Your version of MSVC does not support the requested instruction set. Consider updating!" )
		ENDIF()
	endif()

endif()

target_compile_definitions(compiler INTERFACE _CRT_SECURE_NO_DEPRECATE _CRT_SECURE_NO_WARNINGS _SECURE_SCL=0 NOMINMAX _SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING)

if (FSO_FATAL_WARNINGS)
	# Make warnings fatal if the right variable is set
	target_compile_options(compiler INTERFACE "/WX")
endif()
