cmake_minimum_required(VERSION 3.9)
cmake_policy(SET CMP0069 NEW)
project(spicetools)

# set language level
set(CMAKE_CXX_STANDARD 17)

# warnings
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra") # enable stuff
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-pointer-arith") # but we love pointer arithmetic :)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unknown-pragmas") # since CLion does clang pragmas
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-address") # to allow checking function pointers for null
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-cast-function-type") # we actually do this a lot
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-class-memaccess") # RapidJSON does this
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-parameter") # for all those stubs
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-stringop-truncation") # since we do that from time to time

# release flags
if(CMAKE_BUILD_TYPE MATCHES "Release")

    # hide ident strings
    set(CMAKE_CXX_FLAGS_RELEASE "-fno-ident -ffunction-sections -fdata-sections")
    set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections")
    set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--gc-sections")

    # set visibility to hidden
    set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fvisibility=hidden -fvisibility-inlines-hidden")

    # remove symbol table and relocation information
    set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -s")

    # performance
    set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O2 -pipe")

    # no debug
    set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -DNDEBUG")

endif()

# debug flags
if(CMAKE_BUILD_TYPE MATCHES "Debug")

    # generate dwarf
    set(CMAKE_CXX_FLAGS_DEBUG "-gdwarf")

    # enable debug symbols on level 3
    set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g3")

    # optimize for debugging
    set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Og -pipe")

endif()

# static linking
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static -static-libgcc -static-libstdc++")

# default defines
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DCINTERFACE -D_WIN32_IE=0x0400")

# add project directory to include path so we can confortably import
include_directories(${spicetools_SOURCE_DIR})

# set link time optimizations (disabled for now)
include(CheckIPOSupported)
check_ipo_supported()
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION FALSE)

# resources
###########

set_source_files_properties(build/manifest.rc PROPERTIES COMPILE_FLAGS "--output-format=coff --target=pe-i386")
set_source_files_properties(build/icon.rc PROPERTIES COMPILE_FLAGS "--output-format=coff --target=pe-i386")
set_source_files_properties(cfg/manifest.rc PROPERTIES COMPILE_FLAGS "--output-format=coff --target=pe-i386")
set_source_files_properties(cfg/icon.rc PROPERTIES COMPILE_FLAGS "--output-format=coff --target=pe-i386")
set_source_files_properties(cfg/Win32D.rc PROPERTIES COMPILE_FLAGS "--output-format=coff --target=pe-i386")
set_source_files_properties(build/manifest64.rc PROPERTIES COMPILE_FLAGS "--output-format=coff --target=pe-x86-64")
set_source_files_properties(build/icon64.rc PROPERTIES COMPILE_FLAGS "--output-format=coff --target=pe-x86-64")
set_source_files_properties(cfg/Win32D64.rc PROPERTIES COMPILE_FLAGS "--output-format=coff --target=pe-x86-64")

# sources
#########

# acio
set(SOURCE_FILES ${SOURCE_FILES} acio/acio.cpp acio/module.cpp acio/core/core.cpp acio/hgth/hgth.cpp acio/bmpu/bmpu.cpp)
set(SOURCE_FILES ${SOURCE_FILES} acio/hbhi/hbhi.cpp acio/hdxs/hdxs.cpp acio/kfca/kfca.cpp acio/i36g/i36g.cpp)
set(SOURCE_FILES ${SOURCE_FILES} acio/panb/panb.cpp acio/icca/icca.cpp acio/j32d/j32d.cpp acio/pix/pix.cpp)
set(SOURCE_FILES ${SOURCE_FILES} acio/bi2a/bi2a.cpp)

# acioemu
set(SOURCE_FILES ${SOURCE_FILES} acioemu/acioemu.cpp acioemu/device.cpp acioemu/icca.cpp)

# api
set(SOURCE_FILES ${SOURCE_FILES} api/controller.cpp api/websocket.cpp api/request.cpp api/response.cpp api/module.cpp)
set(SOURCE_FILES ${SOURCE_FILES} api/modules/card.cpp api/modules/buttons.cpp api/modules/analogs.cpp)
set(SOURCE_FILES ${SOURCE_FILES} api/modules/lights.cpp api/modules/memory.cpp api/modules/coin.cpp)
set(SOURCE_FILES ${SOURCE_FILES} api/modules/info.cpp api/modules/keypads.cpp api/modules/control.cpp)
set(SOURCE_FILES ${SOURCE_FILES} api/modules/touch.cpp api/modules/iidx.cpp)

# avs
set(SOURCE_FILES ${SOURCE_FILES} avs/core.cpp avs/ea3.cpp avs/game.cpp)

# build
set(SOURCE_FILES ${SOURCE_FILES} build/defs.cpp)

# cardio
set(SOURCE_FILES ${SOURCE_FILES} external/cardio/cardio_hid.cpp external/cardio/cardio_window.cpp)
set(SOURCE_FILES ${SOURCE_FILES} external/cardio/cardio_runner.cpp)

# cfg
set(SOURCE_FILES ${SOURCE_FILES} cfg/spicecfg.cpp cfg/analog.cpp cfg/game.cpp cfg/window.cpp cfg/button.cpp)
set(SOURCE_FILES ${SOURCE_FILES} cfg/config.cpp cfg/api.cpp cfg/option.cpp cfg/analog_binding_dialog.cpp)
set(SOURCE_FILES ${SOURCE_FILES} cfg/light.cpp cfg/light_binding_dialog.cpp external/usbhidusage/usb-hid-usage.c)

# easrv
set(SOURCE_FILES ${SOURCE_FILES} easrv/easrv.cpp external/http-parser/http_parser.c)

# games
set(SOURCE_FILES ${SOURCE_FILES} games/game.cpp games/io.cpp)
set(SOURCE_FILES ${SOURCE_FILES} games/shared/lcdhandle.cpp)
set(SOURCE_FILES ${SOURCE_FILES} games/popn/popn.cpp games/popn/io.cpp)
set(SOURCE_FILES ${SOURCE_FILES} games/bbc/bbc.cpp games/bbc/io.cpp)
set(SOURCE_FILES ${SOURCE_FILES} games/iidx/iidx.cpp games/iidx/io.cpp games/iidx/ezusb.cpp games/iidx/fmserial.cpp)
set(SOURCE_FILES ${SOURCE_FILES} games/sdvx/sdvx.cpp games/sdvx/io.cpp games/sdvx/printer.cpp games/sdvx/camera.cpp)
set(SOURCE_FILES ${SOURCE_FILES} games/jb/jb.cpp games/jb/io.cpp)
set(SOURCE_FILES ${SOURCE_FILES} games/nost/nost.cpp games/nost/io.cpp)
set(SOURCE_FILES ${SOURCE_FILES} games/gitadora/gitadora.cpp games/gitadora/io.cpp)
set(SOURCE_FILES ${SOURCE_FILES} games/mga/mga.cpp games/mga/io.cpp games/mga/gunio.cpp)
set(SOURCE_FILES ${SOURCE_FILES} games/sc/sc.cpp games/sc/io.cpp games/shared/twtouch.cpp)
set(SOURCE_FILES ${SOURCE_FILES} games/rb/rb.cpp games/rb/io.cpp games/rb/touch.cpp)
set(SOURCE_FILES ${SOURCE_FILES} games/bs/io.cpp)
set(SOURCE_FILES ${SOURCE_FILES} games/rf3d/io.cpp)
set(SOURCE_FILES ${SOURCE_FILES} games/museca/io.cpp)
set(SOURCE_FILES ${SOURCE_FILES} games/dea/dea.cpp games/dea/io.cpp)
set(SOURCE_FILES ${SOURCE_FILES} games/qma/qma.cpp games/qma/io.cpp games/qma/ezusb.cpp)
set(SOURCE_FILES ${SOURCE_FILES} games/ddr/ddr.cpp games/ddr/io.cpp games/ddr/foot.cpp games/ddr/sate.cpp
        games/ddr/usbmem.cpp games/ddr/p3io.cpp)

# hooks
set(SOURCE_FILES ${SOURCE_FILES} hooks/devicehook.cpp hooks/dxhook.cpp hooks/setupapihook.cpp hooks/networkhook.cpp)
set(SOURCE_FILES ${SOURCE_FILES} hooks/libraryhook.cpp hooks/debughook.cpp hooks/acphook.cpp hooks/cfgmgr32hook.cpp)
set(SOURCE_FILES ${SOURCE_FILES} hooks/sleephook.cpp hooks/rs232dummy.cpp hooks/dinputhook.cpp)

# launcher
set(SOURCE_FILES ${SOURCE_FILES} launcher/launcher.cpp launcher/signal.cpp)

# misc
set(SOURCE_FILES ${SOURCE_FILES} misc/bt5api.cpp misc/device.cpp misc/extdev.cpp misc/sciunit.cpp misc/sde.cpp)
set(SOURCE_FILES ${SOURCE_FILES} misc/eamuse.cpp)

# rawinput
set(SOURCE_FILES ${SOURCE_FILES} rawinput/rawinput.cpp rawinput/sextet.cpp rawinput/piuio.cpp rawinput/touch.cpp)
set(SOURCE_FILES ${SOURCE_FILES} rawinput/hotplug.cpp)

# reader
set(SOURCE_FILES ${SOURCE_FILES} reader/reader.cpp reader/message.cpp reader/structuredmessage.cpp reader/crypt.cpp)

# stubs
set(SOURCE_FILES ${SOURCE_FILES} stubs/stubs.cpp)

# scard
set(SOURCE_FILES ${SOURCE_FILES} external/scard/scard.cpp)

# stackwalker
set(SOURCE_FILES ${SOURCE_FILES} external/stackwalker/stackwalker.cpp)

# tinyxml2
set(SOURCE_FILES ${SOURCE_FILES} external/tinyxml2/tinyxml2.cpp)

# touch
set(SOURCE_FILES ${SOURCE_FILES} touch/touch.cpp touch/win7.cpp touch/win8.cpp)

# util
set(SOURCE_FILES ${SOURCE_FILES} util/sigscan.cpp util/detour.cpp util/logging.cpp util/detour.cpp util/peb.cpp)
set(SOURCE_FILES ${SOURCE_FILES} util/libutils.cpp util/fileutils.cpp util/resutils.cpp util/utils.cpp)
set(SOURCE_FILES ${SOURCE_FILES} util/memutils.cpp util/rc4.cpp util/crypt.cpp util/time.cpp)

# spice.exe
###########

set(RESOURCE_FILES build/manifest.rc build/icon.rc cfg/Win32D.rc)
add_executable(spicetools_spice ${SOURCE_FILES} ${RESOURCE_FILES})
target_link_libraries(spicetools_spice d3d9 ws2_32 version comctl32 shlwapi iphlpapi hid setupapi psapi winmm winscard)
set_target_properties(spicetools_spice PROPERTIES PREFIX "")
set_target_properties(spicetools_spice PROPERTIES OUTPUT_NAME "spice")
set_target_properties(spicetools_spice PROPERTIES COMPILE_FLAGS "-m32" LINK_FLAGS "-m32")

# spice64.exe
#############

set(RESOURCE_FILES build/manifest64.rc build/icon64.rc cfg/Win32D64.rc)
add_executable(spicetools_spice64 ${SOURCE_FILES} ${RESOURCE_FILES})
target_link_libraries(spicetools_spice64 d3d9 ws2_32 version comctl32 shlwapi iphlpapi hid setupapi psapi winmm winscard)
set_target_properties(spicetools_spice64 PROPERTIES PREFIX "")
set_target_properties(spicetools_spice64 PROPERTIES OUTPUT_NAME "spice64")
set_target_properties(spicetools_spice64 PROPERTIES COMPILE_FLAGS "-m64" LINK_FLAGS "-m64")
target_compile_definitions(spicetools_spice64 PRIVATE SPICE64=1)

# spicecfg.exe
##############

# config sources
set(SOURCE_FILES cfg/spicecfg.cpp cfg/window.cpp cfg/game.cpp cfg/button.cpp cfg/option.cpp cfg/config.cpp cfg/api.cpp)
set(SOURCE_FILES ${SOURCE_FILES} cfg/analog.cpp cfg/analog_binding_dialog.cpp)
set(SOURCE_FILES ${SOURCE_FILES} cfg/light.cpp cfg/light_binding_dialog.cpp)

# rawinput
set(SOURCE_FILES ${SOURCE_FILES} rawinput/rawinput.cpp rawinput/sextet.cpp rawinput/piuio.cpp rawinput/touch.cpp)
set(SOURCE_FILES ${SOURCE_FILES} rawinput/hotplug.cpp)

# misc
set(SOURCE_FILES ${SOURCE_FILES} external/usbhidusage/usb-hid-usage.c external/tinyxml2/tinyxml2.cpp build/defs.cpp)

# util
set(SOURCE_FILES ${SOURCE_FILES} util/logging.cpp util/fileutils.cpp util/libutils.cpp util/resutils.cpp util/utils.cpp)
set(SOURCE_FILES ${SOURCE_FILES} util/time.cpp)

# io
set(SOURCE_FILES ${SOURCE_FILES} games/bbc/io.cpp games/bs/io.cpp games/ddr/io.cpp games/dea/io.cpp)
set(SOURCE_FILES ${SOURCE_FILES} games/gitadora/io.cpp games/iidx/io.cpp games/jb/io.cpp games/mga/io.cpp)
set(SOURCE_FILES ${SOURCE_FILES} games/museca/io.cpp games/nost/io.cpp games/popn/io.cpp games/rb/io.cpp)
set(SOURCE_FILES ${SOURCE_FILES} games/rf3d/io.cpp games/sc/io.cpp games/sdvx/io.cpp games/qma/io.cpp)

set(RESOURCE_FILES cfg/manifest.rc cfg/icon.rc cfg/Win32D.rc)
add_executable(spicetools_cfg WIN32 ${SOURCE_FILES} ${RESOURCE_FILES})
target_link_libraries(spicetools_cfg ws2_32 version comctl32 hid setupapi shlwapi winmm)
set_target_properties(spicetools_cfg PROPERTIES PREFIX "")
set_target_properties(spicetools_cfg PROPERTIES OUTPUT_NAME "spicecfg")
set_target_properties(spicetools_cfg PROPERTIES COMPILE_FLAGS "-m32" LINK_FLAGS "-m32")
target_compile_definitions(spicetools_cfg PRIVATE SPICETOOLS_SPICECFG_STANDALONE=1)

# stubs
#######

# kbt.dll
set(SOURCE_FILES stubs/stubs.cpp)
add_library(spicetools_stubs_kbt SHARED ${SOURCE_FILES} stubs/stubs.def)
set_target_properties(spicetools_stubs_kbt PROPERTIES PREFIX "")
set_target_properties(spicetools_stubs_kbt PROPERTIES OUTPUT_NAME "kbt")
set_target_properties(spicetools_stubs_kbt PROPERTIES COMPILE_FLAGS "-m32" LINK_FLAGS "-m32")
target_compile_definitions(spicetools_stubs_kbt PRIVATE STUB=1)

# kbt.dll 64bit
add_library(spicetools_stubs_kbt64 SHARED ${SOURCE_FILES} stubs/stubs.def)
set_target_properties(spicetools_stubs_kbt64 PROPERTIES PREFIX "")
set_target_properties(spicetools_stubs_kbt64 PROPERTIES OUTPUT_NAME "kbt")
set_target_properties(spicetools_stubs_kbt64 PROPERTIES COMPILE_FLAGS "-m64" LINK_FLAGS "-m64")
target_compile_definitions(spicetools_stubs_kbt64 PRIVATE STUB=1)

# kld.dll
set(SOURCE_FILES stubs/stubs.cpp)
add_library(spicetools_stubs_kld SHARED ${SOURCE_FILES} stubs/stubs.def)
set_target_properties(spicetools_stubs_kld PROPERTIES PREFIX "")
set_target_properties(spicetools_stubs_kld PROPERTIES OUTPUT_NAME "kld")
set_target_properties(spicetools_stubs_kld PROPERTIES COMPILE_FLAGS "-m32" LINK_FLAGS "-m32")
target_compile_definitions(spicetools_stubs_kld PRIVATE STUB=1)

# kld.dll 64bit
add_library(spicetools_stubs_kld64 SHARED ${SOURCE_FILES} stubs/stubs.def)
set_target_properties(spicetools_stubs_kld64 PROPERTIES PREFIX "")
set_target_properties(spicetools_stubs_kld64 PROPERTIES OUTPUT_NAME "kld")
set_target_properties(spicetools_stubs_kld64 PROPERTIES COMPILE_FLAGS "-m64" LINK_FLAGS "-m64")
target_compile_definitions(spicetools_stubs_kld64 PRIVATE STUB=1)

# output directories
####################

# output config
set_target_properties(spicetools_cfg
        PROPERTIES
        RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/spicetools")

# output 32bit
set_target_properties(spicetools_spice spicetools_stubs_kbt spicetools_stubs_kld
        PROPERTIES
        ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/archive32"
        LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/spicetools/32"
        RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/spicetools/32")

# output 64bit
set_target_properties(spicetools_spice64 spicetools_stubs_kbt64 spicetools_stubs_kld64
        PROPERTIES
        ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/archive64"
        LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/spicetools/64"
        RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/spicetools/64")
