cmake_minimum_required(VERSION 2.8.12...3.5 FATAL_ERROR)

set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/binaries/")

set(CMAKE_BUILD_TYPE "RelWithDebInfo" CACHE STRING "Type of build")
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Release" "Debug"
    "MinSizeRel" "RelWithDebInfo")

project(WLA-DX C)

set(ARCHS
    # wla-NAME:compile-def
    "gb:GB"
    "cx4:CX4"
    "65c02:WDC65C02"
    "65ce02:CSG65CE02"
    "6502:MCS6502"
    "65816:W65816"
    "huc6280:HUC6280"
    "spc700:SPC700"
    "z80:Z80"
    "z80n:Z80N"
    "ez80:EZ80"
    "68000:MC68000"
    "6800:MC6800"
    "6801:MC6801"
    "6809:MC6809"
    "8008:I8008"
    "8080:I8080"
    "superfx:SUPERFX"
    "sh2:SH2"
    )

option(GDB_DEBUGGING
    "Enable debugging via gdb (Only when CMAKE_BUILD_TYPE is Debug)" ON)

option(STRICT_ANSI_WARNINGS
    "Enable extra ANSI C89/C90 portability warnings as errors" OFF)

# CMake will automatically define WIN32 for us for Microsoft compilers, how
# convenient! But we need MSDOS flag as well. Additionally, other compilers
# don't define it by default. WIN32 does NOT include Cygwin.
if(WIN32)
    add_definitions(-DWIN32)
    add_definitions(-DMSDOS)
endif()

# This should work on ANY POSIX-compliant environment.
if(UNIX)
    add_definitions(-DUNIX)
    link_libraries(m) # Deprecated, but best solution. See
    # http://www.cmake.org/pipermail/cmake/2009-April/028439.html
endif()

set(CMAKE_C_STANDARD 90)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_C_EXTENSIONS OFF)

set(STRICT_ANSI_WARNING_FLAGS
    -Werror
    -Wdeclaration-after-statement
    -Wstrict-prototypes
    -Wmissing-prototypes
    -Wold-style-definition
    -Wmissing-declarations
    -Werror=implicit-int
    -Werror=implicit-function-declaration
    -Wvla
    -Wlong-long
    )

if(MSVC)
    # This block handles both standard MSVC and Clang on Windows (clang-cl)
    add_definitions(/D_CRT_SECURE_NO_WARNINGS)
    
    if(CMAKE_C_COMPILER_ID MATCHES "Clang")
        # For clang-cl, use /clang: to pass GNU flags that it wouldn't normally recognize
        set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /W3 /WX /clang:-pedantic-errors /clang:-ansi")
    else()
        # Standard MSVC (cl.exe)
        set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /Za /W3 /WX")
    endif()

    # Optimization override
    string(REPLACE "/O[0-4]" "/Ox" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}")

else()
    # This block handles GCC and Clang on Linux/macOS
    if(CMAKE_C_COMPILER_ID MATCHES "GNU|Clang")
        set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pedantic-errors -Wall -Wextra -ansi")

        if(STRICT_ANSI_WARNINGS)
            foreach(FLAG ${STRICT_ANSI_WARNING_FLAGS})
                set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${FLAG}")
            endforeach()
        endif()

        string(REPLACE "-O2" "-O3" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}")

        if(CMAKE_C_COMPILER_ID MATCHES "Clang" AND CMAKE_C_COMPILER_VERSION VERSION_LESS 3.8)
            set(GDB_DEBUGGING OFF)
            message(STATUS "You need at least clang 3.8 for GDB_DEBUGGING. Disabling it.")
        endif()

        if(GDB_DEBUGGING)
            set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -ggdb")
        endif()
    endif()
endif()

# WATCOM C Compiler works just fine as well. Might be a decent alternative
# 386 MSDOS compiler as well (compare to DJGPP).
if(WATCOM)
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -za") # Disable extensions
    string(REPLACE "-ot" "-ox" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}")
    string(REGEX REPLACE "-w=[0-4]" "-w=4" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
endif()

include_directories("${PROJECT_SOURCE_DIR}")

add_subdirectory(wlab)
add_subdirectory(wlalink)
add_subdirectory(byte_tester)
add_subdirectory(doc)

add_custom_target(generators)
add_custom_target(gens DEPENDS generators)

if(CMAKE_CROSSCOMPILING)
    set(IMPORT_GENERATORS "IMPORT_GENERATORS-NOTFOUND"
        CACHE FILEPATH "ImportGenerators.cmake of a native build")
    if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.5)
        set(CMAKE_CROSSCOMPILING_EMULATOR "${CMAKE_CROSSCOMPILING_EMULATOR}"
            CACHE FILEPATH "Path/Command to an emulator that can execute foreign code")
    else()
        set(CMAKE_CROSSCOMPILING_EMULATOR OFF) # If not supported, use import
    endif()
    if(CMAKE_CROSSCOMPILING_EMULATOR)
        message(STATUS "Using crosscompiling emulator: ${CMAKE_CROSSCOMPILING_EMULATOR}")
    else()
        include("${IMPORT_GENERATORS}")
        set(GEN_PREFIX native-)
    endif()
endif()


# WLA-ARCH executables
set(WLA_SRCS
    main.c
    crc32.c
    crc32.h
    decode.c
    decode.h
    hashmap.c
    hashmap.h
    parse.c
    parse.h
    include.c
    include.h
    phase_1.c
    phase_1.h
    phase_2.c
    phase_2.h
    phase_3.c
    phase_3.h
    phase_4.c
    phase_4.h
    stack.c
    stack.h
    listfile.c
    listfile.h
    printf.c
    printf.h
    mersenne.c
    mersenne.h
    )

foreach(ARCH IN LISTS ARCHS)
    string(REPLACE ":" ";" ARCH "${ARCH}")
    list(GET ARCH 0 WLA_NAME)
    list(GET ARCH 1 COMPILE_DEF)

    # Generate instructions table
    if((NOT CMAKE_CROSSCOMPILING) OR CMAKE_CROSSCOMPILING_EMULATOR)
        add_executable(gen-${WLA_NAME}
            "instruction_table_generator/main.c"
            "i${WLA_NAME}.c"
            )
        set_property(TARGET gen-${WLA_NAME} APPEND
            PROPERTY COMPILE_DEFINITIONS
                "${COMPILE_DEF}"
            )
        set_property(TARGET gen-${WLA_NAME} PROPERTY
            RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/ins_tbl_gen/")
        list(APPEND GENERATOR_TARGETS gen-${WLA_NAME})
        add_dependencies(generators gen-${WLA_NAME})
    endif()
    file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/ins_tbl_gen/")
    set(TABLE_GEN_OUTPUT
        "${CMAKE_CURRENT_BINARY_DIR}/ins_tbl_gen/t${WLA_NAME}.c")
    add_custom_command(
        OUTPUT "${TABLE_GEN_OUTPUT}"
        COMMAND ${GEN_PREFIX}gen-${WLA_NAME}
            "${TABLE_GEN_OUTPUT}"
        DEPENDS gen-${WLA_NAME} "i${WLA_NAME}.c" "defines.h"
        )

    # Generate actual wla binary
    add_executable(wla-${WLA_NAME}
        ${WLA_SRCS} "${TABLE_GEN_OUTPUT}"
        "i${WLA_NAME}.c"
        )
    set_property(TARGET wla-${WLA_NAME} APPEND PROPERTY
        COMPILE_DEFINITIONS "${COMPILE_DEF}")
    install(TARGETS wla-${WLA_NAME} DESTINATION bin)
endforeach(ARCH)

if(NOT CMAKE_CROSSCOMPILING)
    export(TARGETS ${GENERATOR_TARGETS}
        FILE "${CMAKE_CURRENT_BINARY_DIR}/ImportGenerators.cmake"
        NAMESPACE native-
        )
endif()


# Packaging via CPack
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY
    "Yet Another GB-Z80/Cx4/Z80/Z80N/eZ80/6502/65C02/65CE02/65816/68000/6800/6801/6809/8008/8080/HUC6280/SH-2/SPC-700/SuperFX Multi Platform Cross Assembler Package")
set(CPACK_PACKAGE_CHECKSUM MD5) # CPack 3.7+
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE")
set(CPACK_GENERATOR ZIP TGZ 7Z)

set(CPACK_SOURCE_GENERATOR ZIP TGZ 7Z)
set(CPACK_SOURCE_IGNORE_FILES "/.git/" "̇\\\\.swp" "#" "~" "build")

include(CPack)

