cmake_minimum_required(VERSION 3.28)

project(whalejs VERSION 0.4.0)


###############################################################################
# Options

option(WHLJS_BUILD_DOCS_GENERATOR "Build documentation generator" OFF)


###############################################################################
# Dependencies

include(GNUInstallDirs)
include(whale)

if (EMSCRIPTEN)
  find_package(Python3 REQUIRED)
else()
  find_package(Boost REQUIRED CONFIG
    COMPONENTS
      filesystem
      program_options
      thread
  )
endif()
find_package(nlohmann_json REQUIRED CONFIG)
find_package(whalejs-common CONFIG)


###############################################################################
# Common

function(whljs_target TARGET_NAME WHLJS_COMMON_TARGET DUKTAPE_TARGET)
  if(ANDROID)
    add_library(${TARGET_NAME} SHARED)
  else()
    add_executable(${TARGET_NAME})
  endif()

  target_sources(${TARGET_NAME}
    PRIVATE
      "src/duktape_env.cpp"
      "src/duktape_env.h"
      "src/main.cpp"
      "src/module.cpp"
      "src/module.h"
      "src/options.cpp"
      "src/options.h"
      "src/whalejs.cpp"
      "src/whalejs.h"
  )

  if(EMSCRIPTEN)
    target_sources(${TARGET_NAME}
      PRIVATE
        "src/init_modules_emscripten.cpp"
    )
  else()
    target_sources(${TARGET_NAME}
      PRIVATE
        "src/duktape_debugger.cpp"
        "src/duktape_debugger.h"
        "src/init_modules.cpp"
    )
  endif()

  # Libraries that come with Emscripten by default. Other platforms need to link against them explicitly.
  if(NOT EMSCRIPTEN)
    target_link_libraries(${TARGET_NAME}
      PRIVATE
        Boost::boost
        Boost::program_options
        Boost::filesystem
        Boost::thread
    )

    if(ANDROID)
      target_compile_options(${TARGET_NAME}
        PRIVATE
          ${WHL_COMMON_ANDROID_COMPILE_OPTIONS}
      )

      target_link_libraries(${TARGET_NAME}
        PRIVATE
          # Required on Android. Boost::filesystem needs it, but it doesn't seem to set is as a dependency?
          Boost::atomic
      )
    else()
      target_link_libraries(${TARGET_NAME}
        PRIVATE
          $<$<CXX_COMPILER_ID:GNU>:stdc++fs>
          $<$<CXX_COMPILER_ID:Clang>:stdc++fs>
      )
    endif()
  endif()
  
  target_link_libraries(${TARGET_NAME}
    PRIVATE
      nlohmann_json::nlohmann_json
      ${WHLJS_COMMON_TARGET}
      ${DUKTAPE_TARGET}
  )
  
  target_compile_features(${TARGET_NAME}
    PUBLIC
      cxx_std_23
  )

  if(WHLJS_BUILD_DOCS_GENERATOR)
    target_compile_definitions(${TARGET_NAME}
      PRIVATE
        WHLJS_BUILD_DOCS_GENERATOR
    )
  endif()

  if(WIN32)
    target_sources(${TARGET_NAME}
      PRIVATE
        "${CMAKE_CURRENT_BINARY_DIR}/whalejs.rc"
    )

    target_compile_definitions(${TARGET_NAME}
      PRIVATE
        NOMINMAX
        WIN32_LEAN_AND_MEAN
        _CRT_SECURE_NO_WARNINGS
    )
  endif()

  if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND NOT MINGW)
    set_target_properties(${TARGET_NAME}
      PROPERTIES
        INSTALL_RPATH "$ORIGIN"
        BUILD_WITH_INSTALL_RPATH TRUE
    )

    target_link_options(${TARGET_NAME}
      PRIVATE
        "-Wl,--disable-new-dtags" # Use RPATH instead of RUNPATH.
    )
  endif()

  if (MINGW)
    target_link_options(${TARGET_NAME}
      PRIVATE
        "-mconsole"
    )

    target_link_libraries(${TARGET_NAME}
      PRIVATE
        ws2_32
    )
  endif()
  
  if(EMSCRIPTEN)
    set_target_properties(${TARGET_NAME}
      PROPERTIES SUFFIX ".html"
    )
    
    target_compile_options(${TARGET_NAME}
      PRIVATE
        -fPIC
    )
    
    # TODO:
    # We are assuming we are in whale-dev monorepo. This should be reconsidered.
    # One way to fix it is to move demo project and index.html to whalejs repo.
    target_link_options(${TARGET_NAME}
      PRIVATE
        "SHELL:-s MINIFY_HTML=0"
        "SHELL:-s ASSERTIONS=1"
        "SHELL:-s FORCE_FILESYSTEM=1"
        "SHELL:-s 'EXPORTED_RUNTIME_METHODS=[\"ccall\", \"requestFullscreen\"]'"
        "SHELL:--embed-file \"${CMAKE_CURRENT_SOURCE_DIR}/std@/std\""
    )

    add_custom_command(
      TARGET ${TARGET_NAME}
      POST_BUILD
      COMMAND "${Python3_EXECUTABLE}"
              "$ENV{EMSDK}/upstream/emscripten/tools/file_packager.py"
              "${CMAKE_CURRENT_BINARY_DIR}/demo.data"
              --preload "${CMAKE_SOURCE_DIR}/assets/demo@/demo"
              --js-output="${CMAKE_CURRENT_BINARY_DIR}/demo.js"
    )

    install(
      FILES
        "${CMAKE_SOURCE_DIR}/assets/emscripten/index.html"
        "${CMAKE_CURRENT_BINARY_DIR}/demo.js"
        "${CMAKE_CURRENT_BINARY_DIR}/demo.data"
      DESTINATION "${CMAKE_INSTALL_BINDIR}"
    )
  endif()
endfunction()


###############################################################################
# whalejs

whljs_target(whalejs whalejs::common whalejs::duktape)
whljs_target(whalejs-dbg whalejs::common-dbg whalejs::duktape-dbg)

configure_file("cmake/whalejs.rc.in" "whalejs.rc" @ONLY)


###############################################################################
# Install

install(
  TARGETS whalejs whalejs-dbg
  ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
  LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
  RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
  INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
)

install(
  DIRECTORY "std"
  DESTINATION "${CMAKE_INSTALL_DATADIR}"
)
