#
# SPDX-FileCopyrightText: Copyright (c) 1993-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

# ensure SAMPLE_SOURCES is set
if (NOT SAMPLE_SOURCES)
   message(FATAL_ERROR "You must define non empty SAMPLE_SOURCES variable before including this template")
endif()

set_ifndef(PLUGINS_NEEDED OFF)
set_ifndef(SAMPLE_PARSERS "none")
set_ifndef(CUDA_LIBS_REQUIRED False)

set(TARGET_DIR ${CMAKE_CURRENT_SOURCE_DIR})

get_filename_component(SAMPLES_DIR ../ ABSOLUTE)
get_filename_component(SHARED_DIR ../../shared ABSOLUTE)
get_filename_component(SAMPLE_DIR_NAME ${TARGET_DIR} NAME)

set_ifndef(CUDA_INSTALL_DIR /usr/local/cuda)

# SAMPLES_COMMON_SOURCES
set(SAMPLES_COMMON_SOURCES
    ${SAMPLES_DIR}/common/logger.cpp
    ${SHARED_DIR}/utils/cacheUtils.cpp
    ${SHARED_DIR}/utils/fileLock.cpp
)

if (MSVC)
    list(APPEND SAMPLES_COMMON_SOURCES ${SAMPLES_DIR}/common/getopt.c)
endif()

# add underscores (snake) to camelCase cases
string(REGEX REPLACE "(.)([A-Z][a-z]+)" "\\1_\\2" SAMPLE_NAME_SNAKE_MIXED ${SAMPLE_DIR_NAME})
string(REGEX REPLACE "([a-z0-9])([A-Z])" "\\1_\\2" SAMPLE_NAME_SNAKE_MIXED ${SAMPLE_NAME_SNAKE_MIXED})
string(TOLOWER ${SAMPLE_NAME_SNAKE_MIXED} SAMPLE_NAME_SNAKE)

# fix a few sample names
string(REGEX REPLACE "google_net" "googlenet" SAMPLE_NAME_FIXED ${SAMPLE_NAME_SNAKE})
string(REGEX REPLACE "([a-zA-Z0-0])api" "\\1_api" SAMPLE_NAME_FIXED ${SAMPLE_NAME_FIXED})
string(REGEX REPLACE "_rcnn" "RCNN" SAMPLE_NAME_FIXED ${SAMPLE_NAME_FIXED})

set(SAMPLE_NAME ${SAMPLE_NAME_FIXED})# CACHE STRING "binary name of the sample")

set(TARGET_NAME ${SAMPLE_NAME})

add_executable(${TARGET_NAME}
    ${SAMPLE_SOURCES}
    ${SAMPLES_COMMON_SOURCES}
)
set(DEPS_LIST "")

if(BUILD_PLUGINS)
    list(APPEND DEPS_LIST ${nvinfer_plugin_lib_name})
endif()

if(BUILD_PARSERS)
    list(APPEND DEPS_LIST ${nvonnxparser_lib_name})
endif()

if(BUILD_PLUGINS OR BUILD_PARSERS)
    add_dependencies(${TARGET_NAME}
        ${DEPS_LIST}
    )
endif()

set(ONNX_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/parsers/onnx CACHE STRING "ONNX include directory")
message(ONNX_INCLUDE_DIR)
target_include_directories(${TARGET_NAME}
    PUBLIC ${PROJECT_SOURCE_DIR}/include
    PUBLIC ${ONNX_INCLUDE_DIR}
    PUBLIC ${CUDA_INSTALL_DIR}/include
    PRIVATE ${SHARED_DIR}
    PRIVATE ${SAMPLES_DIR}
    PRIVATE ${SAMPLES_DIR}/common
    PRIVATE ${SAMPLES_DIR}/common/windows
    PRIVATE ${TARGET_DIR}
)

target_compile_options(${TARGET_NAME} PUBLIC
             "$<$<COMPILE_LANGUAGE:CUDA>:SHELL:-Xcompiler -fno-rtti>"
             "$<$<COMPILE_LANGUAGE:CXX>:-fno-rtti>")

set(SAMPLE_DEP_LIBS
    ${CUDART_LIB}
    ${${nvinfer_lib_name}_LIB_PATH}
    ${RT_LIB}
    ${CMAKE_DL_LIBS}
    ${CMAKE_THREAD_LIBS_INIT}
)

if (NOT MSVC)
    list(APPEND SAMPLE_DEP_LIBS ${RT_LIB})
endif()

if(${PLUGINS_NEEDED})
    list(APPEND SAMPLE_DEP_LIBS ${nvinfer_plugin_lib_name})
endif()

if("onnx" IN_LIST SAMPLE_PARSERS)
    list(APPEND SAMPLE_DEP_LIBS ${nvonnxparser_lib_name})
endif()

# Necessary to link nvinfer_plugin library. Add unresolved symbols flag for non-Windows platforms.
target_link_libraries(${TARGET_NAME}
    ${SAMPLE_DEP_LIBS}
    $<$<NOT:$<CXX_COMPILER_ID:MSVC>>:-Wl,--unresolved-symbols=ignore-in-shared-libs>
)

set_target_properties(${TARGET_NAME} PROPERTIES LINK_FLAGS "-Wl,--exclude-libs,ALL")

set_target_properties(${TARGET_NAME} PROPERTIES DEBUG_POSTFIX ${TRT_DEBUG_POSTFIX})

set_target_properties(${TARGET_NAME}
    PROPERTIES
    ARCHIVE_OUTPUT_DIRECTORY "${TRT_OUT_DIR}"
    LIBRARY_OUTPUT_DIRECTORY "${TRT_OUT_DIR}"
    RUNTIME_OUTPUT_DIRECTORY "${TRT_OUT_DIR}"
)

# Add CUDA dependencies for samples that require them.
if(${CUDA_LIBS_REQUIRED})
    target_link_directories(${TARGET_NAME} PUBLIC ${CUDA_ROOT}/lib)
endif()

add_dependencies(samples ${TARGET_NAME})

################################### INSTALLATION ########################################

install(TARGETS ${TARGET_NAME}
        RUNTIME DESTINATION bin
        LIBRARY DESTINATION lib
        ARCHIVE DESTINATION lib
)

##################################### SUMMARY ###########################################

get_filename_component(LICENSE_STATUS ../ ABSOLUTE)
get_filename_component(LICENSE_STATUS "${LICENSE_STATUS}" NAME)

message(STATUS "Adding new sample: ${TARGET_NAME}")
message(STATUS "    - Parsers Used: ${SAMPLE_PARSERS}")
message(STATUS "    - InferPlugin Used: ${PLUGINS_NEEDED}")
message(STATUS "    - Licensing: ${LICENSE_STATUS}")
