cmake_minimum_required(VERSION 3.24)

set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL"
    CACHE STRING "MSVC runtime mapping for the KLayout subset.")

project(KLayoutSubset LANGUAGES CXX)

if(NOT MSVC)
    message(FATAL_ERROR "This overlay is currently intended for MSVC 2019 x64 builds.")
endif()

get_filename_component(KLAYOUT_WORKSPACE_ROOT "${CMAKE_CURRENT_LIST_DIR}/../.." ABSOLUTE)
set(KLAYOUT_SOURCE_ROOT "${KLAYOUT_WORKSPACE_ROOT}/sources/klayout")
set(KLAYOUT_SRC_ROOT "${KLAYOUT_SOURCE_ROOT}/src")

if(NOT EXISTS "${KLAYOUT_SRC_ROOT}/klayout.pro")
    message(FATAL_ERROR "KLayout source tree not found at ${KLAYOUT_SOURCE_ROOT}")
endif()

list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake")
include(KLayoutQmake)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_INCLUDE_CURRENT_DIR ON)

find_package(Qt6 6.5 REQUIRED COMPONENTS Core Core5Compat Gui Widgets Xml Network PrintSupport)
if(NOT TARGET Qt6::QWindowsIntegrationPlugin)
    find_package(Qt6QWindowsIntegrationPlugin REQUIRED)
endif()

if(NOT VCPKG_TARGET_TRIPLET STREQUAL "x64-windows-v142")
    message(FATAL_ERROR "KLayout subset requires VCPKG_TARGET_TRIPLET=x64-windows-v142, got '${VCPKG_TARGET_TRIPLET}'.")
endif()
if(NOT VCPKG_INSTALLED_DIR)
    message(FATAL_ERROR "KLayout subset requires VCPKG_INSTALLED_DIR.")
endif()

find_package(ZLIB REQUIRED)
if(NOT TARGET ZLIB::ZLIB)
    message(FATAL_ERROR "FindZLIB did not provide the required ZLIB::ZLIB target.")
endif()

get_target_property(KLAYOUT_ZLIB_LIBRARY_DEBUG ZLIB::ZLIB IMPORTED_LOCATION_DEBUG)
get_target_property(KLAYOUT_ZLIB_LIBRARY_RELEASE ZLIB::ZLIB IMPORTED_LOCATION_RELEASE)
set(KLAYOUT_VCPKG_TRIPLET_ROOT "${VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}")
set(KLAYOUT_ZLIB_LIBRARY_DEBUG_EXPECTED "${KLAYOUT_VCPKG_TRIPLET_ROOT}/debug/lib/zlibd.lib")
set(KLAYOUT_ZLIB_LIBRARY_RELEASE_EXPECTED "${KLAYOUT_VCPKG_TRIPLET_ROOT}/lib/zlib.lib")
if(NOT KLAYOUT_ZLIB_LIBRARY_DEBUG STREQUAL KLAYOUT_ZLIB_LIBRARY_DEBUG_EXPECTED)
    message(FATAL_ERROR
        "Debug ZLIB must resolve to ${KLAYOUT_ZLIB_LIBRARY_DEBUG_EXPECTED}, got '${KLAYOUT_ZLIB_LIBRARY_DEBUG}'.")
endif()
if(NOT KLAYOUT_ZLIB_LIBRARY_RELEASE STREQUAL KLAYOUT_ZLIB_LIBRARY_RELEASE_EXPECTED)
    message(FATAL_ERROR
        "Release ZLIB must resolve to ${KLAYOUT_ZLIB_LIBRARY_RELEASE_EXPECTED}, got '${KLAYOUT_ZLIB_LIBRARY_RELEASE}'.")
endif()

set(KLAYOUT_ZLIB_RUNTIME_DEBUG "${KLAYOUT_VCPKG_TRIPLET_ROOT}/debug/bin/zlibd1.dll")
set(KLAYOUT_ZLIB_RUNTIME_RELEASE "${KLAYOUT_VCPKG_TRIPLET_ROOT}/bin/zlib1.dll")
if(NOT EXISTS "${KLAYOUT_ZLIB_RUNTIME_DEBUG}" OR NOT EXISTS "${KLAYOUT_ZLIB_RUNTIME_RELEASE}")
    message(FATAL_ERROR
        "Config-aware ZLIB runtimes are missing: '${KLAYOUT_ZLIB_RUNTIME_DEBUG}', '${KLAYOUT_ZLIB_RUNTIME_RELEASE}'.")
endif()
set(KLAYOUT_ZLIB_RUNTIME
    "$<IF:$<CONFIG:Debug>,${KLAYOUT_ZLIB_RUNTIME_DEBUG},${KLAYOUT_ZLIB_RUNTIME_RELEASE}>")

message(STATUS "MSVC runtime mapping: ${CMAKE_MSVC_RUNTIME_LIBRARY}")
message(STATUS "Debug ZLIB import library: ${KLAYOUT_ZLIB_LIBRARY_DEBUG}")
message(STATUS "Release ZLIB import library: ${KLAYOUT_ZLIB_LIBRARY_RELEASE}")

set(KLAYOUT_OUTPUT_DIR "${CMAKE_BINARY_DIR}/bin")
set(KLAYOUT_PLUGIN_OUTPUT_DIR "${KLAYOUT_OUTPUT_DIR}/db_plugins")

set(TL_INC "${KLAYOUT_SRC_ROOT}/tl/tl")
set(GSI_INC "${KLAYOUT_SRC_ROOT}/gsi/gsi")
set(DB_INC "${KLAYOUT_SRC_ROOT}/db/db")
set(PEX_INC "${KLAYOUT_SRC_ROOT}/pex/pex")
set(RDB_INC "${KLAYOUT_SRC_ROOT}/rdb/rdb")
set(LIB_INC "${KLAYOUT_SRC_ROOT}/lib/lib")
set(LAYBASIC_INC "${KLAYOUT_SRC_ROOT}/laybasic/laybasic")
set(LAYUI_INC "${KLAYOUT_SRC_ROOT}/layui/layui")
set(LAYVIEW_INC "${KLAYOUT_SRC_ROOT}/layview/layview")
set(QTBASIC_INC "${KLAYOUT_SRC_ROOT}/gsiqt/qtbasic")
set(VERSION_INC "${KLAYOUT_SRC_ROOT}/version")
set(PLUGINS_COMMON_INC "${KLAYOUT_SRC_ROOT}/plugins/common")

set(KLAYOUT_COMMON_INCLUDES
    "${TL_INC}"
    "${GSI_INC}"
    "${DB_INC}"
    "${PEX_INC}"
    "${RDB_INC}"
    "${LIB_INC}"
    "${LAYBASIC_INC}"
    "${LAYUI_INC}"
    "${LAYVIEW_INC}"
    "${QTBASIC_INC}"
    "${VERSION_INC}"
    "${PLUGINS_COMMON_INC}"
)

set(KLAYOUT_QT_LIBS
    Qt6::Core
    Qt6::Core5Compat
    Qt6::Gui
    Qt6::Widgets
    Qt6::Xml
    Qt6::Network
    Qt6::PrintSupport
)

function(klayout_require_dual_imported_locations target)
    get_target_property(debug_location ${target} IMPORTED_LOCATION_DEBUG)
    get_target_property(release_location ${target} IMPORTED_LOCATION_RELEASE)
    if(NOT debug_location OR NOT EXISTS "${debug_location}")
        message(FATAL_ERROR "${target} has no usable Debug imported location: '${debug_location}'.")
    endif()
    if(NOT release_location OR NOT EXISTS "${release_location}")
        message(FATAL_ERROR "${target} has no usable Release imported location: '${release_location}'.")
    endif()
    if(debug_location STREQUAL release_location)
        message(FATAL_ERROR "${target} resolves Debug and Release to the same artifact: '${debug_location}'.")
    endif()
    message(STATUS "${target} Debug: ${debug_location}")
    message(STATUS "${target} Release: ${release_location}")
endfunction()

foreach(qt_target IN LISTS KLAYOUT_QT_LIBS)
    klayout_require_dual_imported_locations(${qt_target})
endforeach()
klayout_require_dual_imported_locations(Qt6::QWindowsIntegrationPlugin)

function(klayout_configure_target target)
    set_target_properties(${target} PROPERTIES
        CXX_STANDARD 17
        CXX_STANDARD_REQUIRED ON
        RUNTIME_OUTPUT_DIRECTORY "${KLAYOUT_OUTPUT_DIR}"
        LIBRARY_OUTPUT_DIRECTORY "${KLAYOUT_OUTPUT_DIR}"
        ARCHIVE_OUTPUT_DIRECTORY "${KLAYOUT_OUTPUT_DIR}/lib"
    )

    target_compile_options(${target} PRIVATE /bigobj /MP /utf-8 /wd4251)
    target_compile_definitions(${target} PUBLIC
        $<$<CONFIG:Debug>:_ITERATOR_DEBUG_LEVEL=2>
        $<$<NOT:$<CONFIG:Debug>>:_ITERATOR_DEBUG_LEVEL=0>
        HAVE_QT
        HAVE_QT_NETWORK
        HAVE_QT_XML
        HAVE_QT_PRINTSUPPORT
        KLAYOUT_VERSION=0.30.9
        KLAYOUT_VERSION_DATE=2026-06-17
        KLAYOUT_VERSION_REV=6270877
        NOMINMAX
    )
    target_include_directories(${target} PUBLIC ${KLAYOUT_COMMON_INCLUDES})
    target_link_libraries(${target} PUBLIC ${KLAYOUT_QT_LIBS} ZLIB::ZLIB)
    target_link_libraries(${target} PRIVATE psapi dbghelp user32)
endfunction()

function(klayout_add_shared_library target pro_file export_define)
    add_library(${target} SHARED)
    klayout_configure_target(${target})
    target_compile_definitions(${target} PRIVATE "${export_define}")
    klayout_qmake_target_sources(${target} "${pro_file}" ${ARGN})
endfunction()

klayout_add_shared_library(klayout_tl
    "${KLAYOUT_SRC_ROOT}/tl/tl/tl.pro"
    MAKE_TL_LIBRARY
    EXCLUDE "tlGit\\.(cc|h)$" "tlHttpStreamCurl\\.cc$" "tlHttpStreamNoQt\\.cc$"
)

klayout_add_shared_library(klayout_gsi
    "${KLAYOUT_SRC_ROOT}/gsi/gsi/gsi.pro"
    MAKE_GSI_LIBRARY
)
target_link_libraries(klayout_gsi PUBLIC klayout_tl)

klayout_add_shared_library(klayout_db
    "${KLAYOUT_SRC_ROOT}/db/db/db.pro"
    MAKE_DB_LIBRARY
)
target_link_libraries(klayout_db PUBLIC klayout_gsi klayout_tl)

klayout_add_shared_library(klayout_pex
    "${KLAYOUT_SRC_ROOT}/pex/pex/pex.pro"
    MAKE_PEX_LIBRARY
)
target_link_libraries(klayout_pex PUBLIC klayout_db klayout_gsi klayout_tl)

klayout_add_shared_library(klayout_rdb
    "${KLAYOUT_SRC_ROOT}/rdb/rdb/rdb.pro"
    MAKE_RDB_LIBRARY
)
target_link_libraries(klayout_rdb PUBLIC klayout_db klayout_gsi klayout_tl)

klayout_add_shared_library(klayout_lib
    "${KLAYOUT_SRC_ROOT}/lib/lib/lib.pro"
    MAKE_LIB_LIBRARY
)
target_link_libraries(klayout_lib PUBLIC klayout_db klayout_gsi klayout_tl)

klayout_add_shared_library(klayout_laybasic
    "${KLAYOUT_SRC_ROOT}/laybasic/laybasic/laybasic.pro"
    MAKE_LAYBASIC_LIBRARY
)
target_link_libraries(klayout_laybasic PUBLIC klayout_rdb klayout_db klayout_gsi klayout_tl)

klayout_add_shared_library(klayout_layui
    "${KLAYOUT_SRC_ROOT}/layui/layui/layui.pro"
    MAKE_LAYUI_LIBRARY
)
target_link_libraries(klayout_layui PUBLIC klayout_laybasic klayout_rdb klayout_db klayout_gsi klayout_tl)

klayout_add_shared_library(klayout_layview
    "${KLAYOUT_SRC_ROOT}/layview/layview/layview.pro"
    MAKE_LAYVIEW_LIBRARY
    EXCLUDE "layLayoutView_noqt\\.(cc|h)$" "gsiDeclLayLayoutView_noqt\\.cc$"
)
target_link_libraries(klayout_layview PUBLIC klayout_layui klayout_laybasic klayout_rdb klayout_db klayout_gsi klayout_tl)

function(klayout_add_streamer_objects target pro_file)
    add_library(${target} OBJECT)
    klayout_configure_target(${target})
    target_compile_definitions(${target} PRIVATE MAKE_DB_PLUGIN_LIBRARY)
    target_include_directories(${target} PRIVATE
        "${KLAYOUT_SRC_ROOT}/plugins/common"
        "${KLAYOUT_SRC_ROOT}/plugins/streamers/common"
    )
    klayout_qmake_target_sources(${target} "${pro_file}")
    target_link_libraries(${target} PUBLIC klayout_db klayout_gsi klayout_tl)
endfunction()

klayout_add_streamer_objects(gds2_objects
    "${KLAYOUT_SRC_ROOT}/plugins/streamers/gds2/db_plugin/db_plugin.pro"
)

klayout_add_streamer_objects(oasis_objects
    "${KLAYOUT_SRC_ROOT}/plugins/streamers/oasis/db_plugin/db_plugin.pro"
)

function(klayout_add_db_plugin plugin_target object_target)
    add_library(${plugin_target} SHARED $<TARGET_OBJECTS:${object_target}>)
    klayout_configure_target(${plugin_target})
    target_compile_definitions(${plugin_target} PRIVATE MAKE_DB_PLUGIN_LIBRARY)
    target_link_libraries(${plugin_target} PRIVATE klayout_db klayout_gsi klayout_tl)
    set_target_properties(${plugin_target} PROPERTIES
        RUNTIME_OUTPUT_DIRECTORY "${KLAYOUT_PLUGIN_OUTPUT_DIR}"
        LIBRARY_OUTPUT_DIRECTORY "${KLAYOUT_PLUGIN_OUTPUT_DIR}"
        ARCHIVE_OUTPUT_DIRECTORY "${KLAYOUT_PLUGIN_OUTPUT_DIR}/lib"
        PREFIX ""
    )
endfunction()

klayout_add_db_plugin(gds2 gds2_objects)
klayout_add_db_plugin(oasis oasis_objects)

add_executable(klayout_view_smoke
    "${CMAKE_CURRENT_LIST_DIR}/smoke/klayout_view_smoke.cc"
    $<TARGET_OBJECTS:gds2_objects>
    $<TARGET_OBJECTS:oasis_objects>
)
klayout_configure_target(klayout_view_smoke)
target_compile_definitions(klayout_view_smoke PRIVATE
    KLAYOUT_SOURCE_ROOT="${KLAYOUT_SOURCE_ROOT}"
)
target_link_libraries(klayout_view_smoke PRIVATE
    klayout_layview
    klayout_layui
    klayout_laybasic
    klayout_lib
    klayout_pex
    klayout_rdb
    klayout_db
    klayout_gsi
    klayout_tl
)
add_dependencies(klayout_view_smoke gds2 oasis)

add_custom_command(TARGET klayout_view_smoke POST_BUILD
    COMMAND "${CMAKE_COMMAND}" -E make_directory "$<TARGET_FILE_DIR:klayout_view_smoke>/platforms"
    COMMAND "${CMAKE_COMMAND}" -E copy_if_different
        "$<TARGET_FILE:Qt6::Core>"
        "$<TARGET_FILE:Qt6::Core5Compat>"
        "$<TARGET_FILE:Qt6::Gui>"
        "$<TARGET_FILE:Qt6::Widgets>"
        "$<TARGET_FILE:Qt6::Xml>"
        "$<TARGET_FILE:Qt6::Network>"
        "$<TARGET_FILE:Qt6::PrintSupport>"
        "$<TARGET_FILE_DIR:klayout_view_smoke>"
    COMMAND "${CMAKE_COMMAND}" -E copy_if_different
        "$<TARGET_FILE:Qt6::QWindowsIntegrationPlugin>"
        "$<TARGET_FILE_DIR:klayout_view_smoke>/platforms"
    COMMAND "${CMAKE_COMMAND}" -E copy_if_different
        "${KLAYOUT_ZLIB_RUNTIME}"
        "$<TARGET_FILE_DIR:klayout_view_smoke>"
)
