# This is a generated file.
# To regenerate file, use generators in the aquaveo/dev_tools repository.
# Any changes needed to be made to the file should be made in the template file.

cmake_minimum_required(VERSION 3.18.0)
cmake_policy(SET CMP0015 NEW) # Link Directory Pathing
cmake_policy(SET CMP0091 NEW)
cmake_policy(SET CMP0148 NEW)
set(CMAKE_DEBUG_POSTFIX _d)
set(CMAKE_CXX_STANDARD 17)

project({{ library_name }}lib C CXX)

# Cache variables
set(BUILD_TESTING NO CACHE BOOL "Enable/Disable testing")
set(IS_CONDA_BUILD NO CACHE BOOL "Set this if you want to make a conda package.")
set(IS_EMSCRIPTEN_BUILD NO CACHE BOOL "Set this to build with emscripten using cmake.")
set(PYTHON_TARGET_VERSION 3.13 CACHE STRING "Version of python to link to for python wrapping.")
set(CONDA_PREFIX "" CACHE PATH "Path to the conda environment used to build.")
set(IS_PYTHON_BUILD NO CACHE BOOL "Set this if you want to build the python bindings.")
set(XMS_TEST_PATH ${PROJECT_SOURCE_DIR}/test_files/ CACHE PATH "Path to test files for testing")
set(XMS_VERSION "99.99.99" CACHE STRING "Library Version")

if (IS_PYTHON_BUILD)
    find_package(Python3 ${PYTHON_TARGET_VERSION} EXACT REQUIRED COMPONENTS Interpreter Development.Module)
endif()

# Static library sources
set({{ library_name }}_sources
    {%- for source in library_sources -%}{{ '\n    ' }}{{ source }}{% endfor %}
)

# Static library headers
set({{ library_name }}_headers
    {%- for header in library_headers -%}{{ '\n    ' }}{{ header }}{% endfor %}
)

if (APPLE)
    set(CMAKE_POSITION_INDEPENDENT_CODE False)
else ()
    set(CMAKE_POSITION_INDEPENDENT_CODE True)
endif ()

if (IS_PYTHON_BUILD AND BUILD_TESTING)
    message(FATAL_ERROR "Cannot build python module when testing is enabled")
endif ()

add_definitions(-DXMS_VERSION=\"${XMS_VERSION}\")

{%- if extra_cmake_text %}
{{ extra_cmake_text }}
{%- endif %}

if (IS_CONDA_BUILD)
    include(${CMAKE_CURRENT_LIST_DIR}/condabuildinfo.cmake)
elseif (IS_EMSCRIPTEN_BUILD)
    include(${CMAKE_CURRENT_LIST_DIR}/emscriptenbuildinfo.cmake)
else () # If we are not using conda or emscripten, we are using conan
    # Conan 2 setup
    {%- for dependency in xms_dependencies -%}{{ '\n    ' }}find_package({{ dependency.name }} REQUIRED){% endfor %}
    find_package(Boost REQUIRED)
    find_package(ZLIB REQUIRED)

    {%- for dependency in xms_dependencies -%}{{ '\n    ' }}list(APPEND EXT_INCLUDE_DIRS {{ '${' }}{{ dependency.name }}_INCLUDE_DIRS}){% endfor %}
    list(APPEND EXT_INCLUDE_DIRS ${Boost_INCLUDE_DIRS})
    list(APPEND EXT_INCLUDE_DIRS ${ZLIB_INCLUDE_DIRS})

    {%- for dependency in xms_dependencies -%}{{ '\n    ' }}list(APPEND EXT_LIB_DIRS {{ '${' }}{{ dependency.name }}_LIBRARY_DIRS}){% endfor %}
    list(APPEND EXT_LIB_DIRS ${Boost_LIBRARY_DIRS})
    list(APPEND EXT_LIB_DIRS ${ZLIB_LIBRARY_DIRS})


    {%- for dependency in xms_dependencies -%}{{ '\n    ' }}list(APPEND EXT_LIBS {{ '${' }}{{ dependency.name }}_LIBRARIES}){% endfor %}
    list(APPEND EXT_LIBS ${Boost_LIBRARIES})
    list(APPEND EXT_LIBS ${ZLIB_LIBRARIES})
endif ()

if (WIN32)
    string(COMPARE EQUAL "${CONAN_SETTINGS_COMPILER_RUNTIME}" "MT" USES_MT)
    if (NOT USES_MT)
        string(COMPARE EQUAL "${CONAN_SETTINGS_COMPILER_RUNTIME}" "MTd" USES_MT)
    endif ()

    if (USE_TYPEDEF_WCHAR_T)
        add_definitions(/Zc:wchar_t-)  # Treat wchar_t as a typedef
    endif ()

    add_definitions(/D BOOST_ALL_NO_LIB)

    if (USES_MT)
        set(CompilerFlags
                CMAKE_CXX_FLAGS
                CMAKE_CXX_FLAGS_DEBUG
                CMAKE_CXX_FLAGS_RELEASE
                CMAKE_C_FLAGS
                CMAKE_C_FLAGS_DEBUG
                CMAKE_C_FLAGS_RELEASE
        )
        foreach (CompilerFlag ${CompilerFlags})
            string(REPLACE "/MD" "/MT" ${CompilerFlag} "${${CompilerFlag}}")
        endforeach ()
    endif ()
endif ()
{% if python_binding_type | default('pybind11') == 'pybind11' %}
if (IS_PYTHON_BUILD)
    find_package(pybind11 REQUIRED)
    list(APPEND EXT_INCLUDE_DIRS
            ${pybind11_INCLUDE_DIR}
    )
    list(APPEND EXT_INCLUDE_DIRS
            ${Python3_INCLUDE_DIRS}
    )
endif ()
{% endif %}
if (BUILD_TESTING)
    message(STATUS "Adding test dependencies...")
    add_definitions(-DXMS_TEST_PATH="${XMS_TEST_PATH}/")

    list(APPEND {{ library_name }}_headers
         {%- for header in testing_headers -%}{{ '\n         ' }}{{ header }}{% endfor %}
    )
{% if testing_sources %}
    # Add source for testing build only
    list(APPEND {{ library_name }}_sources
         {%- for source in testing_sources -%}{{ '\n         ' }}{{ source }}{% endfor %}
    )
{% endif %}
{% if testing_framework == "gtest" %}
    # Google Test configuration
    # Tests are in *.cpp files guarded by #ifdef GTEST_ENABLED, with fixtures declared in *.t.h
    # Also define CXX_TEST for compatibility with xmscore/testing/TestTools.h and friend declarations
    add_definitions(-DGTEST_ENABLED -DCXX_TEST)
    find_package(GTest REQUIRED)
    list(APPEND EXT_INCLUDE_DIRS ${GTest_INCLUDE_DIRS})
    enable_testing()

    include(GoogleTest)

    # Generate minimal runner that provides main() - tests self-register from library
    file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/runner.cpp
        "#include <gtest/gtest.h>\n"
        "int main(int argc, char **argv) {\n"
        "    ::testing::InitGoogleTest(&argc, argv);\n"
        "    return RUN_ALL_TESTS();\n"
        "}\n"
    )

    # Collect test source files (cpp files that implement TEST_F) - they need to be compiled
    # directly into the runner, not just linked from the library
    file(GLOB_RECURSE gtest_sources ${CMAKE_CURRENT_LIST_DIR}/{{ library_name }}/*.cpp)
    # Filter to only files that contain GTEST_ENABLED
    set(test_cpp_sources)
    foreach(source ${gtest_sources})
        file(READ ${source} source_content)
        string(FIND "${source_content}" "GTEST_ENABLED" found_pos)
        if (NOT found_pos EQUAL -1)
            list(APPEND test_cpp_sources ${source})
        endif()
    endforeach()

    add_executable(runner ${CMAKE_CURRENT_BINARY_DIR}/runner.cpp ${test_cpp_sources})
    target_link_libraries(runner
        ${PROJECT_NAME}
        GTest::gtest
        ${EXT_LIBS}
    )
    target_compile_definitions(runner PRIVATE GTEST_ENABLED CXX_TEST)
    target_include_directories(runner PRIVATE ${EXT_INCLUDE_DIRS})
    gtest_discover_tests(runner)

    if (WIN32)
        set(RUNNERNAME "runner.exe")
    else ()
        set(RUNNERNAME "runner")
    endif ()
{% else %}
    # CxxTest configuration (default)
    add_definitions(-DCXX_TEST -DCXXTEST4)
    find_package(cxxtest REQUIRED)
    list(APPEND EXT_INCLUDE_DIRS ${cxxtest_INCLUDE_DIRS})

    if (cxxtest_FOUND)
        include("FindCxxTest")
        include_directories(${CXXTEST_INCLUDE_DIR})
        enable_testing()

        set(cxxtest_TESTGEN_ARGS --xunit-printer --have-eh)
        file(GLOB_RECURSE test_headers ${CMAKE_CURRENT_LIST_DIR}/{{ library_name }}/*.t.h)
        message(STATUS "Prefix Path: ${CMAKE_PREFIX_PATH}")
        message(STATUS "Module Path: ${CMAKE_MODULE_PATH}")
        CXXTEST_ADD_TEST(
                runner runner.cpp ${test_headers}
        )
        target_link_libraries(runner ${PROJECT_NAME})

        if (WIN32)
            set(RUNNERNAME "runner.exe")
        else ()
            set(RUNNERNAME "runner")
        endif ()
    endif ()
{% endif %}
endif ()


message(STATUS "External Include Dirs: ${EXT_INCLUDE_DIRS}")
message(STATUS "External Lib Dirs: ${EXT_LIB_DIRS}")
message(STATUS "External Libs: ${EXT_LIBS}")


include_directories(${CMAKE_CURRENT_LIST_DIR})
include_directories(${EXT_INCLUDE_DIRS})
link_directories(${EXT_LIB_DIRS})

{% if python_library_headers -%}
# Add source for Python library only
if (IS_PYTHON_BUILD)
    list(APPEND {{ library_name }}_sources
         {%- for source in python_library_sources -%}{{ '\n         ' }}{{ source }}{% endfor %}
    )
    list(APPEND {{ library_name }}_headers
         {%- for header in python_library_headers -%}{{ '\n         ' }}{{ header }}{% endfor %}
    )
endif ()
{% endif %}
message("External Include Dirs: ${EXT_INCLUDE_DIRS}")
message("External Lib Dirs: ${EXT_LIB_DIRS}")
message("External Libs: ${EXT_LIBS}")

# Static library
add_library(${PROJECT_NAME} STATIC
        {{ '${' }}{{ library_name }}_sources} {{ '${' }}{{ library_name }}_headers}
)
find_package(Threads REQUIRED)
target_link_libraries(${PROJECT_NAME}
        ${EXT_LIBS}
)
target_link_libraries(${PROJECT_NAME}
        ${CMAKE_THREAD_LIBS_INIT}
)
if (UNIX AND NOT APPLE)
    target_link_libraries(${PROJECT_NAME} rt)
endif ()
{% if python_binding_type | default('pybind11') == 'pybind11' %}
# Pybind11
if (IS_PYTHON_BUILD)
    # Pybind11 sources
    set({{ library_name }}_py
        {%- for source in pybind_sources -%}{{ '\n        ' }}{{ source }}{% endfor %}
    )

    set({{ library_name }}_py_headers
        {%- for header in pybind_headers -%}{{ '\n        ' }}{{ header }}{% endfor %}
    )

    message(STATUS "PYTHON_INCLUDE: ${PYTHON_INCLUDE_DIRS}")
    message(STATUS "PYTHON_LIBS: ${PYTHON_LIBRARIES}")

    pybind11_add_module(_{{ library_name }} MODULE
        {{ '${' }}{{ library_name }}_py} {{ '${' }}{{ library_name }}_py_headers}
    )
    target_include_directories(_{{ library_name }}
            PRIVATE
            ${EXT_INCLUDE_DIRS}
    )
    target_link_libraries(_{{ library_name }}
            PRIVATE
            ${PROJECT_NAME}
            ${EXT_LIBS}
    )
    # Do NOT statically link libstdc++/libgcc. Static linking causes locale/iostream
    # corruption when multiple pybind modules (each with their own static libstdc++) are
    # loaded in the same Python process. Portability is handled by auditwheel repair,
    # which bundles the shared libstdc++.so.6 into the wheel if it is not in the
    # manylinux policy baseline.
    set_target_properties(_{{ library_name }} PROPERTIES
        PREFIX ""
        CXX_VISIBILITY_PRESET "default"
        VISIBILITY_INLINES_HIDDEN OFF
        LINKER_LANGUAGE CXX
    )

    if (APPLE)
        set_target_properties(_{{ library_name }} PROPERTIES
            INSTALL_RPATH "@loader_path"
            BUILD_WITH_INSTALL_RPATH TRUE
        )
    endif()
    if (UNIX AND NOT APPLE)
        set_target_properties(_{{ library_name }} PROPERTIES
            INSTALL_RPATH "$ORIGIN"
            BUILD_WITH_INSTALL_RPATH TRUE
        )
    endif()

    install(
            TARGETS _{{ library_name }}
            ARCHIVE DESTINATION "_package/xms/{{ python_namespaced_dir }}"
            LIBRARY DESTINATION "_package/xms/{{ python_namespaced_dir }}"
    )

    install(DIRECTORY "_package/" DESTINATION "_package"
            FILES_MATCHING PATTERN "*.py"
            PATTERN "_package/tests" EXCLUDE)
    install(FILES "_package/pyproject.toml" DESTINATION "_package")
endif ()
{% endif %}
{%- if post_library_cmake_text %}
{{ post_library_cmake_text }}
{%- endif %}

# Install recipe
install(
        TARGETS ${PROJECT_NAME}
        ARCHIVE DESTINATION "lib"
        LIBRARY DESTINATION "lib"
)
foreach (header IN LISTS {{ library_name }}_headers {{ library_name }}_py_headers)
    get_filename_component(subdir "${header}" DIRECTORY)
    install(
            FILES "${header}"
            DESTINATION "include/${subdir}"
    )
endforeach ()
