cmake_minimum_required(VERSION 3.19)
project(BodyPipeline LANGUAGES CXX CUDA)

# Set C++ standard and enable modern practices
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)  # Disable compiler-specific extensions

# set(CMAKE_BUILD_TYPE Debug)  # Automatically adds -g
# OR
# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g")

# Configure where binaries will be placed
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)

# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native")
# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mavx")# Enable all features your current CPU supports
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -march=native")
# Force AVX2
# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -mavx2")
# Or force AVX-512
# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -mavx512f")




option(CUDA_USE_STATIC_CUDA_RUNTIME OFF)

# For larger projects
option(BUILD_TESTS "Build tests" OFF)
if(BUILD_TESTS)
    enable_testing()
    add_subdirectory(tests)
endif()


# Install target (for packaging)
# install(TARGETS text_reader DESTINATION bin)
# install(DIRECTORY data/ DESTINATION share/text_reader/data)


find_package(PkgConfig REQUIRED)
# find_package(CUDA REQUIRED)
find_package(prometheus-cpp REQUIRED)
pkg_check_modules(GST REQUIRED gstreamer-1.0)
include_directories(${GST_INCLUDE_DIRS})
pkg_check_modules(GLIB REQUIRED glib-2.0 gobject-2.0 nlohmann_json  gstreamer-base-1.0 
                                gstreamer-rtsp-server-1.0 gstreamer-rtsp-1.0 gstreamer-1.0 gstreamer-video-1.0)
                            
add_definitions(${GST_CFLAGS_OTHER})

if(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64")
    message("embed_platform on")
    include_directories(/usr/local/cuda/targets/aarch64-linux/include)
    link_directories(/usr/local/cuda/targets/aarch64-linux/lib)
else()
    message("embed_platform off")
    include_directories(/usr/local/cuda/include)
    link_directories(/usr/local/cuda/lib64)
endif()


include_directories(/usr/lib/x86_64-linux-gnu/glib-2.0/include)
include_directories(/opt/nvidia/deepstream/deepstream-7.1/sources/includes)
include_directories(/usr/include/gstreamer-1.0)
include_directories(/usr/include/nlohmann)
include_directories(/usr/local/cuda/include)
include_directories(/opt/nvidia/deepstream/deepstream-7.1/service-maker/includes/)
link_directories(/opt/nvidia/deepstream/deepstream/lib/)
link_directories(/opt/nvidia/deepstream/deepstream/lib/gst-plugins)
link_directories(/usr/local/cuda/lib64/)
link_directories(/usr/local/cuda/targets/x86_64-linux/lib/)
include_directories(${PROJECT_SOURCE_DIR}/camera_manager.hpp)
include_directories(${PROJECT_SOURCE_DIR}/pipeline_manager.hpp)
include_directories(${PROJECT_SOURCE_DIR}/streammux_manager.hpp)
include_directories(${PROJECT_SOURCE_DIR}/source_bin.hpp)
include_directories(${PROJECT_SOURCE_DIR}/gstds_example_manager.hpp)
include_directories(${PROJECT_SOURCE_DIR}/tiler_manager.hpp)
include_directories(${PROJECT_SOURCE_DIR}/nv_video_convert_manager.hpp)
include_directories(${PROJECT_SOURCE_DIR}/nv_osd_manager.hpp)
include_directories(${PROJECT_SOURCE_DIR}/queue_manager.hpp)
include_directories(${PROJECT_SOURCE_DIR}/nv_ds_logger_manager.hpp)
include_directories(${PROJECT_SOURCE_DIR}/sink_manager.hpp)
include_directories(${PROJECT_SOURCE_DIR}/message_handling.hpp)
include_directories(${PROJECT_SOURCE_DIR}/rtsp_streaming_manager.hpp)
# include_directories(${PROJECT_SOURCE_DIR}/metrics_manager.hpp)
include_directories(${PROJECT_SOURCE_DIR}/config_manager.hpp)
include_directories(${PROJECT_SOURCE_DIR}/nv_infer_server_manager.hpp)
include_directories(${PROJECT_SOURCE_DIR}/nv_tracker_manager.hpp)
include_directories(${PROJECT_SOURCE_DIR}/face_candid_trace.hpp)
include_directories(${PROJECT_SOURCE_DIR}/face_nv_infer_server_manager.hpp)
include_directories(${PROJECT_SOURCE_DIR}/face_nv_infer_server_manager.hpp)
include_directories(${PROJECT_SOURCE_DIR}/nv_message_converter.hpp)
include_directories(${PROJECT_SOURCE_DIR}/nv_message_broker.hpp)
include_directories(${PROJECT_SOURCE_DIR}/tee_manager.hpp)


set(SOURCES src/main.cpp  src/camera_manager.cpp src/pipeline_manager.cpp src/streammux_manager.cpp 
            src/source_bin.cpp src/gstds_example_manager.cpp src/tiler_manager.cpp
            src/nv_video_convert_manager.cpp src/nv_osd_manager.cpp src/queue_manager.cpp 
            src/nv_ds_logger_manager.cpp src/sink_manager.cpp src/message_handling.cpp
            src/rtsp_streaming_manager.cpp 
            # src/metrics_manager.cpp 
            src/config_manager.cpp
            src/nv_infer_server_manager.cpp src/nv_tracker_manager.cpp src/face_candid_trace.cpp
            src/face_nv_infer_server_manager.cpp src/face_nv_infer_server_manager.cpp
            src/nv_message_converter.cpp src/nv_message_broker.cpp src/tee_manager.cpp)


# missing initializer for member 'NvDsInferDims::d' [-Werror=missing-field-initializers] NvDsInferDims dims = {0};
set_source_files_properties(
    src/nv_infer_server_manager.cpp
    src/main.cpp
    src/pipeline_manager.cpp
    src/nv_tracker_manager.cpp
    src/face_nv_infer_server_manager.cpp
    src/nv_osd_manager.cpp
    PROPERTIES COMPILE_FLAGS "-Wno-missing-field-initializers"
)


# Create the executable
add_executable(${PROJECT_NAME}  ${SOURCES})

# Copy data files to build directory
file(COPY data/ DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/data)

# Set compiler warnings
target_compile_options(${PROJECT_NAME} PRIVATE
    $<$<CXX_COMPILER_ID:MSVC>:/W4 /WX>
    $<$<OR:$<CXX_COMPILER_ID:GNU>,$<CXX_COMPILER_ID:Clang>>:-Wall -Wextra -pedantic -Werror>
)

# Platform-specific configurations
if(WIN32)
    target_compile_definitions(${PROJECT_NAME} PRIVATE _CRT_SECURE_NO_WARNINGS)
endif()


# Optionally set CUDA-specific flags
set_target_properties(${PROJECT_NAME} PROPERTIES
    CUDA_STANDARD 17                         # or 14, 20 depending on your code. Specifies which C++ standard to use for both host and device code.
    CUDA_STANDARD_REQUIRED ON               # Enforces the standard. Enforces that standard—avoids falling back to older versions silently.
    CUDA_SEPARABLE_COMPILATION ON           # Needed if kernels are in .cu files. Required if your project has multiple .cu files calling each other.
    # CUDA_ARCHITECTURES 86                   # Set to your GPU's arch (e.g., 86 for Ampere)Helps CMake compile only for the correct GPU architecture (you can use CMake's CUDA_ARCHITECTURES values).
)
# https://cmake.org/cmake/help/latest/prop_tgt/CUDA_ARCHITECTURES.html
# https://cmake.org/cmake/help/latest/policy/CMP0146.html


# Include current directory for headers
target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_include_directories(${PROJECT_NAME} PRIVATE ${GLIB_INCLUDE_DIRS})
target_link_libraries(${PROJECT_NAME} ${GLIB_LIBRARIES})

target_link_libraries(${PROJECT_NAME} gstbase-1.0 gstreamer-1.0 gstrtp-1.0 gstvideo-1.0 gstrtspserver-1.0)
target_link_libraries(${PROJECT_NAME} cudart cuda)
target_link_libraries(${PROJECT_NAME} nvdsgst_infer nvds_meta nvds_inferutils
                                      nvdsgst_meta nvds_utils nvdsgst_helper
                                      prometheus-cpp-core prometheus-cpp-pull  # prometheus-cpp-exposer nvdsgst_metnvdsa
                                      microhttpd
                                      nvdsgst_nvmultiurisrcbin
                                      nvds_batch_jpegenc
                                      nvds_msgbroker nvds_msgconv nvds_meta)