## # vcpkg_build_nmake
##
## Build a msvc makefile project.
##
## ## Usage:
## ```cmake
## vcpkg_build_nmake(
##     SOURCE_PATH <${SOURCE_PATH}>
##     [NO_DEBUG]
##     [PROJECT_SUBPATH <${SUBPATH}>]
##     [PROJECT_NAME <${MAKEFILE_NAME}>]
##     [PRERUN_SHELL <${SHELL_PATH}>]
##     [PRERUN_SHELL_DEBUG <${SHELL_PATH}>]
##     [PRERUN_SHELL_RELEASE <${SHELL_PATH}>]
##     [OPTIONS <-DUSE_THIS_IN_ALL_BUILDS=1>...]
##     [OPTIONS_RELEASE <-DOPTIMIZE=1>...]
##     [OPTIONS_DEBUG <-DDEBUGGABLE=1>...]
##     [TARGET <target>])
## ```
##
## ## Parameters
## ### SOURCE_PATH
## Specifies the directory containing the source files.
## By convention, this is usually set in the portfile as the variable `SOURCE_PATH`.
##
## ### PROJECT_SUBPATH
## Specifies the sub directory containing the `makefile.vc`/`makefile.mak`/`makefile.msvc` or other msvc makefile.
##
## ### PROJECT_NAME
## Specifies the name of msvc makefile name.
## Default is `makefile.vc`
##
## ### NO_DEBUG
## This port doesn't support debug mode.
##
## ### ENABLE_INSTALL
## Install binaries after build.
##
## ### PRERUN_SHELL
## Script that needs to be called before build
##
## ### PRERUN_SHELL_DEBUG
## Script that needs to be called before debug build
##
## ### PRERUN_SHELL_RELEASE
## Script that needs to be called before release build
##
## ### OPTIONS
## Additional options passed to generate during the generation.
##
## ### OPTIONS_RELEASE
## Additional options passed to generate during the Release generation. These are in addition to `OPTIONS`.
##
## ### OPTIONS_DEBUG
## Additional options passed to generate during the Debug generation. These are in addition to `OPTIONS`.
##
## ### TARGET
## The target passed to the nmake build command (`nmake/nmake install`). If not specified, no target will
## be passed.
##
## ### ADD_BIN_TO_PATH
## Adds the appropriate Release and Debug `bin\` directories to the path during the build such that executables can run against the in-tree DLLs.
##
## ## Notes:
## This command should be preceeded by a call to [`vcpkg_configure_nmake()`](vcpkg_configure_nmake.md).
## You can use the alias [`vcpkg_install_nmake()`](vcpkg_configure_nmake.md) function if your CMake script supports the
## "install" target
##
## ## Examples
##
## * [tcl](https://github.com/Microsoft/vcpkg/blob/master/ports/tcl/portfile.cmake)
## * [freexl](https://github.com/Microsoft/vcpkg/blob/master/ports/freexl/portfile.cmake)
function(vcpkg_build_nmake)
    cmake_parse_arguments(_bn
        "ADD_BIN_TO_PATH;ENABLE_INSTALL;NO_DEBUG"
        "SOURCE_PATH;PROJECT_SUBPATH;PROJECT_NAME;LOGFILE_ROOT"
        "OPTIONS;OPTIONS_RELEASE;OPTIONS_DEBUG;PRERUN_SHELL;PRERUN_SHELL_DEBUG;PRERUN_SHELL_RELEASE"
        ${ARGN}
    )
    
    if (NOT CMAKE_HOST_WIN32)
        message(FATAL_ERROR "vcpkg_build_nmake only support windows.")
    endif()
    
    if (_bn_OPTIONS_DEBUG STREQUAL _bn_OPTIONS_RELEASE)
        message(FATAL_ERROR "Detected debug configuration is equal to release configuration, please use NO_DEBUG for vcpkg_build_nmake/vcpkg_install_nmake")
    endif()

    if(NOT _bn_LOGFILE_ROOT)
        set(_bn_LOGFILE_ROOT "build")
    endif()
    
    if (NOT _bn_PROJECT_NAME)
        set(MAKEFILE_NAME makefile.vc)
    else()
        set(MAKEFILE_NAME ${_bn_PROJECT_NAME})
    endif()
    
    set(MAKE )
    set(MAKE_OPTS_BASE )
    set(INSTALL_OPTS_BASE )
    
    find_program(NMAKE nmake REQUIRED)
    get_filename_component(NMAKE_EXE_PATH ${NMAKE} DIRECTORY)
    # Load toolchains
    if(NOT VCPKG_CHAINLOAD_TOOLCHAIN_FILE)
        set(VCPKG_CHAINLOAD_TOOLCHAIN_FILE "${SCRIPTS}/toolchains/windows.cmake")
    endif()
    include("${VCPKG_CHAINLOAD_TOOLCHAIN_FILE}")
    # Set needed env
    set(ENV{PATH} "$ENV{PATH};${NMAKE_EXE_PATH}")
    set(ENV{INCLUDE} "${CURRENT_INSTALLED_DIR}/include;$ENV{INCLUDE}")
    # Set make command and install command
    set(MAKE ${NMAKE} /NOLOGO /G /U)
    set(MAKE_OPTS_BASE -f ${MAKEFILE_NAME} all)
    set(INSTALL_OPTS_BASE install)
    # Add subpath to work directory
    if (_bn_PROJECT_SUBPATH)
        set(_bn_PROJECT_SUBPATH /${_bn_PROJECT_SUBPATH})
    else()
        set(_bn_PROJECT_SUBPATH )
    endif()
    
    foreach(BUILDTYPE "debug" "release")
        if(NOT DEFINED VCPKG_BUILD_TYPE OR VCPKG_BUILD_TYPE STREQUAL BUILDTYPE)
            if(BUILDTYPE STREQUAL "debug")
                # Skip debug generate
                if (_bn_NO_DEBUG)
                    continue()
                endif()
                # Generate obj dir suffix
                set(SHORT_BUILDTYPE "-dbg")
                set(CONFIG "Debug")
                # Add install command and arguments
                set(MAKE_OPTS ${MAKE_OPTS_BASE})
                if (_bn_ENABLE_INSTALL)
                    set(INSTALL_OPTS ${INSTALL_OPTS_BASE} INSTALLDIR=${CURRENT_PACKAGES_DIR}/debug)
                    set(MAKE_OPTS ${MAKE_OPTS} ${INSTALL_OPTS})
                endif()
                set(MAKE_OPTS ${MAKE_OPTS} ${_bn_OPTIONS} ${_bn_OPTIONS_DEBUG})
                
                unset(ENV{CL})
                set(TMP_CL_FLAGS "${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_DEBUG}")
                string(REPLACE "/" "-" TMP_CL_FLAGS "${TMP_CL_FLAGS}")
                set(ENV{CL} "$ENV{CL} ${TMP_CL_FLAGS}")
            else()
                # In NO_DEBUG mode, we only use ${TARGET_TRIPLET} directory.
                if (_bn_NO_DEBUG)
                    set(SHORT_BUILDTYPE "")
                else()
                    set(SHORT_BUILDTYPE "-rel")
                endif()
                set(CONFIG "Release")
                # Add install command and arguments
                set(MAKE_OPTS ${MAKE_OPTS_BASE})
                if (_bn_ENABLE_INSTALL)
                    set(INSTALL_OPTS ${INSTALL_OPTS_BASE} INSTALLDIR=${CURRENT_PACKAGES_DIR})
                    set(MAKE_OPTS ${MAKE_OPTS} ${INSTALL_OPTS})
                endif()
                set(MAKE_OPTS ${MAKE_OPTS} ${_bn_OPTIONS} ${_bn_OPTIONS_RELEASE})
                
                unset(ENV{CL})
                set(TMP_CL_FLAGS "${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_RELEASE}")
                string(REPLACE "/" "-" TMP_CL_FLAGS "${TMP_CL_FLAGS}")
                set(ENV{CL} "$ENV{CL} ${TMP_CL_FLAGS}")
            endif()
            
            set(CURRENT_TRIPLET_NAME ${TARGET_TRIPLET}${SHORT_BUILDTYPE})
            set(OBJ_DIR ${CURRENT_BUILDTREES_DIR}/${CURRENT_TRIPLET_NAME})
            
            file(REMOVE_RECURSE ${OBJ_DIR})
            file(MAKE_DIRECTORY ${OBJ_DIR})
            file(GLOB_RECURSE SOURCE_FILES ${_bn_SOURCE_PATH}/*)
            foreach(ONE_SOUCRCE_FILE ${SOURCE_FILES})
                get_filename_component(DST_DIR ${ONE_SOUCRCE_FILE} PATH)
                string(REPLACE "${_bn_SOURCE_PATH}" "${OBJ_DIR}" DST_DIR "${DST_DIR}")
                file(COPY ${ONE_SOUCRCE_FILE} DESTINATION ${DST_DIR})
            endforeach()
            
            if (_bn_PRERUN_SHELL)
                message(STATUS "Prerunning ${CURRENT_TRIPLET_NAME}")
                vcpkg_execute_required_process(
                    COMMAND ${_bn_PRERUN_SHELL}
                    WORKING_DIRECTORY ${OBJ_DIR}${_bn_PROJECT_SUBPATH}
                    LOGNAME "$prerun-${CURRENT_TRIPLET_NAME}"
                )
            endif()
            if (BUILDTYPE STREQUAL "debug" AND _bn_PRERUN_SHELL_DEBUG)
                message(STATUS "Prerunning ${CURRENT_TRIPLET_NAME}")
                vcpkg_execute_required_process(
                    COMMAND "${_bn_PRERUN_SHELL_DEBUG}"
                    WORKING_DIRECTORY ${OBJ_DIR}${_bn_PROJECT_SUBPATH}
                    LOGNAME "prerun-${CURRENT_TRIPLET_NAME}-dbg"
                )
            endif()
            if (BUILDTYPE STREQUAL "release" AND _bn_PRERUN_SHELL_RELEASE)
                message(STATUS "Prerunning ${CURRENT_TRIPLET_NAME}")
                vcpkg_execute_required_process(
                    COMMAND ${_bn_PRERUN_SHELL_RELEASE}
                    WORKING_DIRECTORY ${OBJ_DIR}${_bn_PROJECT_SUBPATH}
                    LOGNAME "prerun-${CURRENT_TRIPLET_NAME}-rel"
                )
            endif()

            if (NOT _bn_ENABLE_INSTALL)
                message(STATUS "Building ${CURRENT_TRIPLET_NAME}")
            else()
                message(STATUS "Building and installing ${CURRENT_TRIPLET_NAME}")
            endif()

            vcpkg_execute_build_process(
                COMMAND ${MAKE} ${MAKE_OPTS}
                WORKING_DIRECTORY ${OBJ_DIR}${_bn_PROJECT_SUBPATH}
                LOGNAME "${_bn_LOGFILE_ROOT}-${CURRENT_TRIPLET_NAME}"
            )

            if(_bn_ADD_BIN_TO_PATH)
                set(ENV{PATH} "${_BACKUP_ENV_PATH}")
            endif()
        endif()
    endforeach()
endfunction()
