cmake_minimum_required(VERSION 3.20)

project(rcl_action)

find_package(ament_cmake_ros REQUIRED)
find_package(ament_cmake_gen_version_h REQUIRED)

find_package(action_msgs REQUIRED)
find_package(rcl REQUIRED)
find_package(rcutils REQUIRED)
find_package(rmw REQUIRED)
find_package(rosidl_runtime_c REQUIRED)

# Default to C11
if(NOT CMAKE_C_STANDARD)
  set(CMAKE_C_STANDARD 11)
endif()

# Default to C++17
if(NOT CMAKE_CXX_STANDARD)
  set(CMAKE_CXX_STANDARD 17)
  set(CMAKE_CXX_STANDARD_REQUIRED ON)
endif()

if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
  add_compile_options(-Wall -Wextra -Wpedantic)
endif()

set(rcl_action_sources
  src/${PROJECT_NAME}/action_client.c
  src/${PROJECT_NAME}/action_server.c
  src/${PROJECT_NAME}/goal_handle.c
  src/${PROJECT_NAME}/goal_state_machine.c
  src/${PROJECT_NAME}/graph.c
  src/${PROJECT_NAME}/names.c
  src/${PROJECT_NAME}/types.c
)

set_source_files_properties(
  ${rcl_action_sources}
  PROPERTIES language "C"
)

add_library(${PROJECT_NAME}
  ${rcl_action_sources}
)

target_include_directories(${PROJECT_NAME} PUBLIC
  "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
  "$<INSTALL_INTERFACE:include/${PROJECT_NAME}>")

target_link_libraries(${PROJECT_NAME} PUBLIC
  action_msgs::action_msgs
  rcl::rcl
  rmw::rmw
  rosidl_runtime_c::rosidl_runtime_c
)

target_link_libraries(${PROJECT_NAME} PRIVATE
  rcutils::rcutils
)

rcl_set_symbol_visibility_hidden(${PROJECT_NAME} LANGUAGE "C")
# Causes the visibility macros to use dllexport rather than dllimport,
# which is appropriate when building the dll but not consuming it.
target_compile_definitions(${PROJECT_NAME} PRIVATE "RCL_ACTION_BUILDING_DLL")

install(
  DIRECTORY include/
  DESTINATION include/${PROJECT_NAME}
)

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

if(BUILD_TESTING)
  find_package(ament_cmake_gtest REQUIRED)
  find_package(ament_lint_auto REQUIRED)
  find_package(osrf_testing_tools_cpp REQUIRED)
  find_package(test_msgs REQUIRED)
  ament_lint_auto_find_test_dependencies()
  ament_find_gtest()
  # Gtests
  ament_add_gtest(test_action_client
    test/rcl_action/test_action_client.cpp
    TIMEOUT 360
  )
  if(TARGET test_action_client)
    target_include_directories(test_action_client PUBLIC
      src
    )
    target_link_libraries(test_action_client
      ${PROJECT_NAME}
      osrf_testing_tools_cpp::memory_tools
      rcl::rcl
      rcutils::rcutils
      test_msgs::test_msgs
    )
    target_compile_definitions(test_action_client PUBLIC RCUTILS_ENABLE_FAULT_INJECTION)
  endif()

  ament_add_gtest_executable(test_action_communication test/rcl_action/test_action_communication.cpp)
  target_include_directories(test_action_communication PUBLIC src)
  target_link_libraries(test_action_communication
    ${PROJECT_NAME}
    action_msgs::action_msgs
    osrf_testing_tools_cpp::memory_tools
    rcl::rcl
    rosidl_runtime_c::rosidl_runtime_c
    test_msgs::test_msgs)

  ament_add_gtest_executable(test_action_interaction test/rcl_action/test_action_interaction.cpp)
  target_link_libraries(test_action_interaction
    ${PROJECT_NAME}
    action_msgs::action_msgs
    osrf_testing_tools_cpp::memory_tools
    rcl::rcl
    rosidl_runtime_c::rosidl_runtime_c
    test_msgs::test_msgs)

  ament_add_gtest_executable(test_graph test/rcl_action/test_graph.cpp)
  target_compile_definitions(test_graph PUBLIC RCUTILS_ENABLE_FAULT_INJECTION)
  target_link_libraries(test_graph
    ${PROJECT_NAME}
    action_msgs::action_msgs
    osrf_testing_tools_cpp::memory_tools
    rcl::rcl
    rcutils::rcutils
    rosidl_runtime_c::rosidl_runtime_c
    test_msgs::test_msgs)

  function(test_targets)
    message(STATUS "Creating tests for '${rmw_implementation}'")
    set(rmw_implementation_env_var RMW_IMPLEMENTATION=${rmw_implementation})

    ament_add_ros_isolated_gtest_test(test_action_communication
      TEST_NAME test_action_communication${target_suffix}
      ENV ${rmw_implementation_env_var}
    )

    ament_add_ros_isolated_gtest_test(test_action_interaction
      TEST_NAME test_action_interaction${target_suffix}
      ENV ${rmw_implementation_env_var}
    )

    ament_add_ros_isolated_gtest_test(test_graph
      TEST_NAME test_graph${target_suffix}
      ENV ${rmw_implementation_env_var}
      TIMEOUT 180
    )
  endfunction()

  call_for_each_rmw_implementation(test_targets)

  ament_add_gtest(test_action_server
    test/rcl_action/test_action_server.cpp
    TIMEOUT 120
  )
  if(TARGET test_action_server)
    target_include_directories(test_action_server PUBLIC
      src
    )
    target_link_libraries(test_action_server
      ${PROJECT_NAME}
      action_msgs::action_msgs
      osrf_testing_tools_cpp::memory_tools
      rcl::rcl
      test_msgs::test_msgs
    )
    target_compile_definitions(test_action_server PUBLIC RCUTILS_ENABLE_FAULT_INJECTION)
  endif()
  ament_add_gtest(test_goal_handle
    test/rcl_action/test_goal_handle.cpp
  )
  if(TARGET test_goal_handle)
    target_link_libraries(test_goal_handle
      ${PROJECT_NAME}
      rcl::rcl
    )
  endif()
  ament_add_gtest(test_goal_state_machine
    test/rcl_action/test_goal_state_machine.cpp
  )
  if(TARGET test_goal_state_machine)
    target_link_libraries(test_goal_state_machine
      ${PROJECT_NAME}
    )
  endif()
  ament_add_gtest(test_types
    test/rcl_action/test_types.cpp
  )
  if(TARGET test_types)
    target_link_libraries(test_types
      ${PROJECT_NAME}
      rcl::rcl
    )
  endif()
  ament_add_gtest(test_names
    test/rcl_action/test_names.cpp
  )
  if(TARGET test_names)
    target_link_libraries(test_names
      ${PROJECT_NAME}
      rcl::rcl
    )
  endif()
  ament_add_gtest(test_wait
    test/rcl_action/test_wait.cpp
  )
  if(TARGET test_wait)
    target_link_libraries(test_wait
      ${PROJECT_NAME}
      osrf_testing_tools_cpp::memory_tools
      rcl::rcl
      test_msgs::test_msgs
    )
    target_include_directories(test_wait PRIVATE
      src
    )
  endif()
  ament_add_gtest(test_action_name_remapping
    test/rcl_action/test_action_name_remapping.cpp
  )
  if(TARGET test_action_name_remapping)
    target_link_libraries(test_action_name_remapping
      ${PROJECT_NAME}
      osrf_testing_tools_cpp::memory_tools
      rcl::rcl
      test_msgs::test_msgs
    )
    target_include_directories(test_action_name_remapping PRIVATE
      src
    )
  endif()
endif()

# Export old-style CMake variables
ament_export_include_directories("include/${PROJECT_NAME}")
ament_export_libraries(${PROJECT_NAME})

# Export modern CMake targets
ament_export_targets(${PROJECT_NAME})

ament_export_dependencies(action_msgs)
ament_export_dependencies(rcl)
ament_export_dependencies(rmw)
ament_export_dependencies(rosidl_runtime_c)

ament_generate_version_header(${PROJECT_NAME})

ament_package()
