diff --git a/ament_cmake_gen_version_h/CMakeLists.txt b/ament_cmake_gen_version_h/CMakeLists.txt index c91b4b8f..c5e67912 100644 --- a/ament_cmake_gen_version_h/CMakeLists.txt +++ b/ament_cmake_gen_version_h/CMakeLists.txt @@ -16,9 +16,15 @@ if(BUILD_TESTING) # Simulate pre-installed package set(ament_cmake_gen_version_h_DIR ${CMAKE_SOURCE_DIR}/cmake) include(cmake/ament_cmake_gen_version_h.cmake) + include(cmake/ament_generate_version_header.cmake) find_package(ament_cmake_gtest REQUIRED) - # Generate version heades using different scenarios + if(DEFINED CMAKE_WARN_DEPRECATED) + set(old_deprecation_value ${CMAKE_WARN_DEPRECATED}) + endif() + set(CMAKE_WARN_DEPRECATED OFF CACHE BOOL "" FORCE) + + # Generate version headers using different scenarios ament_cmake_gen_version_h(NO_INSTALL) ament_cmake_gen_version_h(NO_INSTALL VERSION_FILE_NAME "version1.h") ament_cmake_gen_version_h(NO_INSTALL INCLUDE_DIR ${CMAKE_CURRENT_BINARY_DIR}/include VERSION_FILE_NAME "version2.h") @@ -30,6 +36,11 @@ if(BUILD_TESTING) VERSION_MINOR 2 VERSION_PATCH 3 ) + if(old_deprecation_value) + set(CMAKE_WARN_DEPRECATED ${old_deprecation_value} CACHE BOOL "" FORCE) + else() + unset(CMAKE_WARN_DEPRECATED CACHE) + endif() ament_add_gtest(test_${PROJECT_NAME} test/test_version_custom.cpp @@ -37,6 +48,15 @@ if(BUILD_TESTING) test/test_version1_h.cpp test/test_version2_h.cpp ) + + # Generate version headers that don't conflict with existing tests + add_library(some_lib INTERFACE) + ament_generate_version_header(some_lib SKIP_INSTALL + HEADER_PATH "ament_generate_version_header/version.hpp") + ament_add_gtest(test_ament_generate_version_header + test/test_version_hpp.cpp + ) + target_link_libraries(test_ament_generate_version_header some_lib) endif() ament_package(CONFIG_EXTRAS "ament_cmake_gen_version_h-extras.cmake") diff --git a/ament_cmake_gen_version_h/ament_cmake_gen_version_h-extras.cmake b/ament_cmake_gen_version_h/ament_cmake_gen_version_h-extras.cmake index 440009b9..5e205b43 100644 --- a/ament_cmake_gen_version_h/ament_cmake_gen_version_h-extras.cmake +++ b/ament_cmake_gen_version_h/ament_cmake_gen_version_h-extras.cmake @@ -16,3 +16,4 @@ # ament_cmake_version/ament_cmake_version-extras.cmake include("${ament_cmake_gen_version_h_DIR}/ament_cmake_gen_version_h.cmake") +include("${ament_cmake_gen_version_h_DIR}/ament_generate_version_header.cmake") diff --git a/ament_cmake_gen_version_h/cmake/ament_cmake_gen_version_h.cmake b/ament_cmake_gen_version_h/cmake/ament_cmake_gen_version_h.cmake index a44da3b6..615b178c 100644 --- a/ament_cmake_gen_version_h/cmake/ament_cmake_gen_version_h.cmake +++ b/ament_cmake_gen_version_h/cmake/ament_cmake_gen_version_h.cmake @@ -49,6 +49,9 @@ # @public # function(ament_cmake_gen_version_h) + message(DEPRECATION "The ament_cmake_gen_version_h() function is deprecated. \ + Please use ament_generate_version_header(...) instead.") + cmake_parse_arguments( ARG "NO_INSTALL" diff --git a/ament_cmake_gen_version_h/cmake/ament_generate_version_header.cmake b/ament_cmake_gen_version_h/cmake/ament_generate_version_header.cmake new file mode 100644 index 00000000..d9470b40 --- /dev/null +++ b/ament_cmake_gen_version_h/cmake/ament_generate_version_header.cmake @@ -0,0 +1,170 @@ +# Copyright 2022 Open Source Robotics Foundation, Inc. +# +# 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. + +# This functions creates and installs a version header file. +# +# It uses a provided "version.h.in" template file to generate +# the destination version file in the provided folder. +# The version is taken from `package.xml` file's `` tag. +# +# The generated file is created when +# - the file does not exist or +# - the package.xml file changes +# +# Example with default arguments +# +# CMake: +# project(my_project) +# ... +# add_library(my_lib ...) +# ament_generate_version_header(my_lib) +# +# How to include the header: +# #include +# +# The header is installed to: +# ${CMAKE_INSTALL_PREFIX}/include/my_project/my_project/libversion.h +# +# Example with HEADER_PATH specified +# +# CMake: +# project(my_project) +# ... +# add_library(my_lib ...) +# ament_generate_version_header(my_lib +# HEADER_PATH "foobar/version.hpp") +# +# How to include the header: +# #include +# +# The header is installed to: +# ${CMAKE_INSTALL_PREFIX}/include/my_project/foobar/version.hpp +# +# Example with INSTALL_PATH specified +# +# CMake: +# project(my_project) +# ... +# add_library(my_lib ...) +# ament_generate_version_header(my_lib +# INSTALL_PATH "include") +# +# How to include the header: +# #include +# +# The header is installed to: +# ${CMAKE_INSTALL_PREFIX}/include/my_project/version.hpp +# +# :param target: A non-imported target to which the generated header will be +# made available from. +# `target_include_directories(${target} ...)` will be used such that linking +# against the target will allow one to include this header. +# :type target: string +# :param HEADER_PATH: Path of the generated header including the file name +# that describes how it should be included by downstream targets. +# The default is `${PROJECT_NAME}/version.h` +# :type HEADER_PATH: string +# :param INSTALL_PATH: Path that the header should be installed at. +# The default value is "include/${PROJECT_NAME}" to avoid include directory +# search order problems when overriding packages from merged workspaces. +# :type INSTALL_PATH: string +# :param SKIP_INSTALL: whether to autmatically install the generated version +# file. +# The default value is FALSE. +# :type SKIP_INSTALL: BOOL +# +# @public +# +function(ament_generate_version_header target) + # Validate arguments + cmake_parse_arguments( + ARG + "SKIP_INSTALL" + "HEADER_PATH;INSTALL_PATH" + "" + ${ARGN} + ) + if(NOT ARG_HEADER_PATH) + set(ARG_HEADER_PATH "${PROJECT_NAME}/version.h") + endif() + if(NOT ARG_INSTALL_PATH) + set(ARG_INSTALL_PATH "include/${PROJECT_NAME}") + endif() + if(NOT TARGET ${target}) + message(FATAL_ERROR "A non-imported target called '${target}' must exist") + endif() + + # Make sure the templates to use are available + set(VERSION_TEMPLATE_FILE "${ament_cmake_gen_version_h_DIR}/version.h.in") + if(NOT EXISTS "${VERSION_TEMPLATE_FILE}") + message(FATAL_ERROR "Can't find ${VERSION_TEMPLATE_FILE}. Reinstall ament_cmake_gen_version_h package.") + endif() + set(SCRIPT_TEMPLATE_FILE "${ament_cmake_gen_version_h_DIR}/generate_version_header.cmake.in") + if(NOT EXISTS "${SCRIPT_TEMPLATE_FILE}") + message(FATAL_ERROR "Can't find ${SCRIPT_TEMPLATE_FILE}. Reinstall ament_cmake_gen_version_h package.") + endif() + + # retrieve version information from .xml file + if(NOT _AMENT_PACKAGE_NAME) + ament_package_xml() + endif() + string(TOUPPER ${PROJECT_NAME} PROJECT_NAME_UPPER) + set(VERSION_STR ${${PROJECT_NAME}_VERSION}) + + # parse version information from the version string + if(NOT VERSION_STR MATCHES "([0-9]+)\.([0-9]+)\.([0-9]+)") + message(FATAL_ERROR "Version string must be of format MAJOR.MINOR.PATCH") + endif() + set(VERSION_MAJOR ${CMAKE_MATCH_1}) + set(VERSION_MINOR ${CMAKE_MATCH_2}) + set(VERSION_PATCH ${CMAKE_MATCH_3}) + + set(BUILDTIME_HEADER_DIR "${CMAKE_CURRENT_BINARY_DIR}/ament_generate_version_header/${target}") + set(GENERATED_HEADER_FILE "${BUILDTIME_HEADER_DIR}/${ARG_HEADER_PATH}") + + # Create a CMake script that will generate the version header + set(GENERATOR_SCRIPT "${CMAKE_CURRENT_BINARY_DIR}/ament_generate_version_header/${target}/generate_version_header.cmake") + configure_file("${SCRIPT_TEMPLATE_FILE}" "${GENERATOR_SCRIPT}" @ONLY) + + # Setup a command to run the generation script when input files change + add_custom_command( + OUTPUT "${GENERATED_HEADER_FILE}" + COMMAND ${CMAKE_COMMAND} -P "${GENERATOR_SCRIPT}" + DEPENDS + "${PACKAGE_XML_DIRECTORY}/package.xml" + "${VERSION_TEMPLATE_FILE}" + "${SCRIPT_TEMPLATE_FILE}" + COMMENT "Generating ${ARG_HEADER_PATH}") + + add_custom_target("ament_generate_version_header__${target}" + DEPENDS "${GENERATED_HEADER_FILE}") + add_dependencies("${target}" "ament_generate_version_header__${target}") + + # Make generated header includable to this and downstream targets + get_target_property(type "${target}" TYPE) + if (${type} STREQUAL "INTERFACE_LIBRARY") + set(keyword "INTERFACE") + else() + set(keyword "PUBLIC") + endif() + target_include_directories("${target}" "${keyword}" + "$" + "$") + + if(NOT ARG_SKIP_INSTALL) + get_filename_component(HEADER_FOLDER "${ARG_HEADER_PATH}" DIRECTORY) + install(FILES "${BUILDTIME_HEADER_DIR}/${ARG_HEADER_PATH}" + DESTINATION "${ARG_INSTALL_PATH}/${HEADER_FOLDER}") + endif() + endfunction() diff --git a/ament_cmake_gen_version_h/cmake/generate_version_header.cmake.in b/ament_cmake_gen_version_h/cmake/generate_version_header.cmake.in new file mode 100644 index 00000000..39ba5e97 --- /dev/null +++ b/ament_cmake_gen_version_h/cmake/generate_version_header.cmake.in @@ -0,0 +1,27 @@ +# Copyright 2022 Open Source Robotics Foundation, Inc. +# +# 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. + +# Generated from generate_version_header.cmake.in +# This file is used by ament_generate_version_header() + +set(GENERATED_HEADER_FILE "@GENERATED_HEADER_FILE@") +set(VERSION_TEMPLATE_FILE "@VERSION_TEMPLATE_FILE@") + +set(VERSION_MAJOR "@VERSION_MAJOR@") +set(VERSION_MINOR "@VERSION_MINOR@") +set(VERSION_PATCH "@VERSION_PATCH@") +set(VERSION_STR "@VERSION_STR@") + +set(PROJECT_NAME_UPPER "@PROJECT_NAME_UPPER@") + +configure_file("${VERSION_TEMPLATE_FILE}" "${GENERATED_HEADER_FILE}") diff --git a/ament_cmake_gen_version_h/test/test_version_hpp.cpp b/ament_cmake_gen_version_h/test/test_version_hpp.cpp new file mode 100644 index 00000000..671c35d9 --- /dev/null +++ b/ament_cmake_gen_version_h/test/test_version_hpp.cpp @@ -0,0 +1,25 @@ +// Copyright 2022 Open Source Robotics Foundation, Inc. +// +// 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. +#include +#include +#include + +TEST(test_ament_generate_version_header, version_hpp) { + EXPECT_TRUE(AMENT_CMAKE_GEN_VERSION_H_VERSION_GTE(0, 0, 0)); + std::stringstream version; + version << AMENT_CMAKE_GEN_VERSION_H_VERSION_MAJOR << "."; + version << AMENT_CMAKE_GEN_VERSION_H_VERSION_MINOR << "."; + version << AMENT_CMAKE_GEN_VERSION_H_VERSION_PATCH; + EXPECT_STREQ(AMENT_CMAKE_GEN_VERSION_H_VERSION_STR, version.str().c_str()); +}