function(normalize_path output_path path)
  cmake_path(
    APPEND path ${ARGN}
    OUTPUT_VARIABLE UNNORMALIZED_PATH_LOCAL
  )
  cmake_path(
    NORMAL_PATH UNNORMALIZED_PATH_LOCAL
    OUTPUT_VARIABLE NORMALIZED_PATH_LOCAL
  )
  set(${output_path} ${NORMALIZED_PATH_LOCAL} PARENT_SCOPE)
endfunction()

function(to_absolute_path path out_variable)
  normalize_path(PATH_LOCAL_NORMALIZED ${path})
  file(REAL_PATH ${PATH_LOCAL_NORMALIZED} PATH_LOCAL BASE_DIRECTORY "${CMAKE_BINARY_DIR}")
  set(${out_variable} ${PATH_LOCAL} PARENT_SCOPE)
endfunction()

function(check_tcl_version_matches_required_version output_variable tclsh)
  normalize_path(CHECK_VERSION_TCL_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR} "modules" "check_version.tcl")
  execute_process(
    COMMAND ${tclsh} ${CHECK_VERSION_TCL_SCRIPT} "${TCL_STATIC_BUILD_VERSION}"
    RESULT_VARIABLE TCL_VERSION_CHECK_RESULT_LOCAL
  )
  if(TCL_VERSION_CHECK_RESULT_LOCAL EQUAL 0)
    set(${output_variable} Y PARENT_SCOPE)
  else()
    set(${output_variable} N PARENT_SCOPE)
  endif()
endfunction()

function(build_tcl_unix_at_configure_time source_dir install_prefix)
  find_program(MAKE_EXE NAMES make REQUIRED)
  normalize_path(TCL_SOURCES_UNIX_DIRECTORY ${source_dir} "unix")
  normalize_path(TCL_SOURCES_UNIX_CONFIGURE ${TCL_SOURCES_UNIX_DIRECTORY} "configure")
  execute_process(
    COMMAND ${TCL_SOURCES_UNIX_CONFIGURE} --disable-shared --prefix=${install_prefix}
    WORKING_DIRECTORY ${TCL_SOURCES_UNIX_DIRECTORY}
    COMMAND_ECHO STDOUT
  )
  execute_process(
    COMMAND make install
    WORKING_DIRECTORY ${TCL_SOURCES_UNIX_DIRECTORY}
    COMMAND_ECHO STDOUT
  )
endfunction()

function(build_tcl_win_at_configure_time source_dir install_prefix)
  find_program(MAKE_EXE NAMES nmake nmake.exe REQUIRED)
  normalize_path(TCL_SOURCES_WIN_DIRECTORY ${source_dir} "win")
  execute_process(
    COMMAND ${MAKE_EXE} /f makefile.vc release OPTS=static INSTALLDIR=${install_prefix}
    WORKING_DIRECTORY ${TCL_SOURCES_WIN_DIRECTORY}
    COMMAND_ECHO STDOUT
  )
  execute_process(
    COMMAND ${MAKE_EXE} /f makefile.vc install OPTS=static INSTALLDIR=${install_prefix}
    WORKING_DIRECTORY ${TCL_SOURCES_WIN_DIRECTORY}
    COMMAND_ECHO STDOUT
  )
endfunction()

function(build_tcl_unix source_dir install_prefix)
  find_program(MAKE_EXE make REQUIRED)
  normalize_path(TCL_SOURCES_UNIX_DIRECTORY ${source_dir} "unix")
  normalize_path(TCL_SOURCES_UNIX_CONFIGURE ${TCL_SOURCES_UNIX_DIRECTORY} "configure")
  ExternalProject_Add(
    tcl
    SOURCE_DIR ${TCL_SOURCES_UNIX_DIRECTORY}
    CONFIGURE_COMMAND ${TCL_SOURCES_UNIX_CONFIGURE} --enable-64bit --disable-shared --prefix=${install_prefix}
    BUILD_COMMAND ${MAKE_EXE}
    INSTALL_COMMAND ${MAKE_EXE} install
  )
endfunction()

function(build_tcl_win source_dir install_prefix)
  find_program(MAKE_EXE NAMES nmake nmake.exe REQUIRED)
  normalize_path(TCL_SOURCES_WIN_DIRECTORY ${source_dir} "win")
  ExternalProject_Add(
    tcl
    SOURCE_DIR ${TCL_SOURCES_WIN_DIRECTORY}
    CONFIGURE_COMMAND ""
    BUILD_COMMAND ${MAKE_EXE} /f makefile.vc release OPTS=static INSTALLDIR=${install_prefix}
    INSTALL_COMMAND ${MAKE_EXE} /f makefile.vc install OPTS=static INSTALLDIR=${install_prefix}
    BUILD_IN_SOURCE TRUE
  )
endfunction()

function(symlink_tcl tclsh_exe)
  add_custom_command(
    TARGET tcl
    COMMAND ${CMAKE_COMMAND} -E create_symlink ${CMAKE_INSTALL_PREFIX}/bin/${tclsh_exe} ${CMAKE_INSTALL_PREFIX}/bin/tclsh
    POST_BUILD
  )
endfunction()

function(symlink_tcl_win tclsh_exe)
  add_custom_command(
    TARGET tcl
    COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_INSTALL_PREFIX}/bin/${tclsh_exe} ${CMAKE_INSTALL_PREFIX}/bin/tclsh.exe
    POST_BUILD
  )
endfunction()

function(build_critcl tclsh source_dir)
  ExternalProject_Add(
    critcl
    SOURCE_DIR ${source_dir}
    CONFIGURE_COMMAND ""
    BUILD_COMMAND ${CMAKE_COMMAND} -E env --modify PATH=path_list_prepend:${CMAKE_INSTALL_PREFIX}/bin ${tclsh} ${source_dir}/build.tcl install
    INSTALL_COMMAND ""
    BUILD_IN_SOURCE TRUE
    DEPENDS tcl
  )
endfunction()

function(build_tcllib tclsh source_dir install_prefix)
  find_program(MAKE_EXE make REQUIRED)
  normalize_path(TCLLIB_SOURCES_UNIX_CONFIGURE ${source_dir} "configure")
  ExternalProject_Add(
    tcllib
    SOURCE_DIR ${source_dir}
    CONFIGURE_COMMAND ${TCLLIB_SOURCES_UNIX_CONFIGURE} --with-tclsh=${tclsh} --prefix=${install_prefix}
    BUILD_COMMAND ${CMAKE_COMMAND} -E env --modify PATH=path_list_prepend:${CMAKE_INSTALL_PREFIX}/bin ${MAKE_EXE}
    INSTALL_COMMAND ${CMAKE_COMMAND} -E env --modify PATH=path_list_prepend:${CMAKE_INSTALL_PREFIX}/bin ${MAKE_EXE} install
    DEPENDS critcl
  )
endfunction()

function(build_tcllib_win tclsh source_dir)
  ExternalProject_Add(
    tcllib
    SOURCE_DIR ${source_dir}
    CONFIGURE_COMMAND ""
    BUILD_COMMAND ${CMAKE_COMMAND} -E env --modify PATH=path_list_prepend:${CMAKE_INSTALL_PREFIX}/bin ${CMAKE_COMMAND} -E env --modify CRITCL=path_list_prepend:${CMAKE_INSTALL_PREFIX}/bin/critcl.tcl ${tclsh} sak.tcl critcl -includedir ${CMAKE_INSTALL_PREFIX}/include -libdir ${CMAKE_INSTALL_PREFIX}/lib -pkg tcllibc${TCL_STATIC_BUILD_TCLSH_VERSION}
    INSTALL_COMMAND ${CMAKE_COMMAND} -E env --modify PATH=path_list_prepend:${CMAKE_INSTALL_PREFIX}/bin ${tclsh} installer.tcl -no-html -no-examples -pkg-path ${CMAKE_INSTALL_PREFIX}/lib/tcllib${TCL_STATIC_BUILD_TCLLIB_VERSION} -app-path ${CMAKE_INSTALL_PREFIX}/bin -no-wait -no-gui
    BUILD_IN_SOURCE TRUE
    DEPENDS critcl
  )
endfunction()

function(build_tk_unix source_dir tcl_install_prefix install_prefix)
  find_program(MAKE_EXE make REQUIRED)
  normalize_path(TK_SOURCES_UNIX_DIRECTORY ${source_dir} "unix")
  normalize_path(TK_SOURCES_UNIX_CONFIGURE ${TK_SOURCES_UNIX_DIRECTORY} "configure")
  normalize_path(TCL_LIB_PATH ${tcl_install_prefix} "lib")
  ExternalProject_Add(
    tk
    DEPENDS tcl
    SOURCE_DIR ${TK_SOURCES_UNIX_DIRECTORY}
    CONFIGURE_COMMAND ${TK_SOURCES_UNIX_CONFIGURE} --disable-shared --with-tcl=${TCL_LIB_PATH} --prefix=${install_prefix}
    BUILD_COMMAND ${MAKE_EXE}
    INSTALL_COMMAND ${MAKE_EXE} install
  )
endfunction()

function(build_tk_win source_dir tcl_sources_dir install_prefix)
  find_program(MAKE_EXE NAMES nmake nmake.exe REQUIRED)
  normalize_path(TK_SOURCES_WIN_DIRECTORY ${source_dir} "win")
  ExternalProject_Add(
    tk
    DEPENDS tcl
    SOURCE_DIR ${TK_SOURCES_WIN_DIRECTORY}
    CONFIGURE_COMMAND ""
    BUILD_COMMAND ${MAKE_EXE} /f makefile.vc release OPTS=static INSTALLDIR=${install_prefix} TCLDIR=${tcl_sources_dir}
    INSTALL_COMMAND ${MAKE_EXE} /f makefile.vc install OPTS=static INSTALLDIR=${install_prefix} TCLDIR=${tcl_sources_dir}
    BUILD_IN_SOURCE TRUE
  )
endfunction()

function(symlink_tk wish_exe)
  add_custom_command(
    TARGET tk
    COMMAND ${CMAKE_COMMAND} -E create_symlink ${CMAKE_INSTALL_PREFIX}/bin/${wish_exe} ${CMAKE_INSTALL_PREFIX}/bin/wish
    POST_BUILD
  )
endfunction()

function(symlink_tk_win wish_exe)
  add_custom_command(
    TARGET tk
    COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_INSTALL_PREFIX}/bin/${wish_exe} ${CMAKE_INSTALL_PREFIX}/bin/wish.exe
    POST_BUILD
  )
endfunction()
