Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ament_cmake_gen_version_h package #198

Merged
merged 8 commits into from
Sep 30, 2021

Conversation

serge-nikulin
Copy link
Contributor

See ros2/rcutils#175 (comment) for details

<package format="2">
<name>ament_cmake_version</name>
<version>0.0.1</version>
<description>Version header file generator</description>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please make this a bit more descriptive, e.g.:

Generate a C header containing the version number of the package

<?xml-model href="http://download.ros.org/schema/package_format2.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="2">
<name>ament_cmake_version</name>
<version>0.0.1</version>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The version number must match the version from the other packages in this repo.

@@ -0,0 +1,17 @@
cmake_minimum_required(VERSION 3.10)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a need to require 3.10? If not maybe relaxing it to at least 3.7 would be good to have the option to backport it to Dashing.

if(BUILD_TESTING)
find_package(ament_cmake_lint_cmake REQUIRED)
ament_lint_cmake(${CMAKE_CURRENT_SOURCE_DIR})
endif()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This package can't use the ament_cmake_lint_cmake package since that would create a cyclic dependency. (It also doesn't declare that dependency in its manifest which would probable expose the cycle.)

set(${PROJECT_NAME}_VERSION_FILE_NAME ${TMP_INCLUDE_DIR}/version.h)
set(NEED_TO_CREATE_VERSION_FILE FALSE)

# retrieve verson information from <package>.xml file
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spelling: verson

set(NEED_TO_CREATE_VERSION_FILE TRUE)
else()
string(REGEX MATCH "^#define[ \t]+${PROJECT_NAME}_VERSION_STR[ \t]+\"([0-9]+\.[0-9]+\.[0-9]+)\"" "" dummy ${VERSION_FILE_STRINGS})
if(NOT (${CMAKE_MATCH_1} STREQUAL ${${PROJECT_NAME}_VERSION}))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: no need for the inner parenthesis.

message(STATUS "Create new version file for version ${${PROJECT_NAME}_VERSION}")
file(MAKE_DIRECTORY ${TMP_INCLUDE_DIR})
# create the version.h file
configure_file("resource/version.h.in" ${${PROJECT_NAME}_VERSION_FILE_NAME} NEWLINE_STYLE UNIX)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems the template file resource/version.h.in isn't part of this PR?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, it's not not and it should be provided by each project in accordance to the project's requirements. I provided an example of such file in ament_cmake_version.cmake file:

################################################################################
# Example of a template file for `rcutils` project:
# // Copyright 2015 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.
#
# #ifndef RCUTILS__VERSION_H_
# #define RCUTILS__VERSION_H_
#
# /// \def RCUTILS_VERSION_MAJOR
# /// Defines RCUTILS major version number
# #define RCUTILS_VERSION_MAJOR (@rcutils_VERSION_MAJOR@)
#
# /// \def RCUTILS_VERSION_MINOR
# /// Defines RCUTILS minor version number
# #define RCUTILS_VERSION_MINOR (@rcutils_VERSION_MINOR@)
#
# /// \def RCUTILS_VERSION_PATCH
# /// Defines RCUTILS version patch number
# #define RCUTILS_VERSION_PATCH (@rcutils_VERSION_PATCH@)
#
# /// \def RCUTILS_VERSION_STR
# /// Defines RCUTILS version string
# #define RCUTILS_VERSION_STR "@rcutils_VERSION@"
#
# #endif  // RCUTILS__VERSION_H_"

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't a default template be more convenient for the user? It seems that this file would be identical in the majority of packages.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

# create the version.h file
configure_file("resource/version.h.in" ${${PROJECT_NAME}_VERSION_FILE_NAME} NEWLINE_STYLE UNIX)
else()
message(STATUS "Skip version file creation")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: 2 space indentation.

message(STATUS "Create new version file for version ${${PROJECT_NAME}_VERSION}")
file(MAKE_DIRECTORY ${TMP_INCLUDE_DIR})
# create the version.h file
configure_file("resource/version.h.in" ${${PROJECT_NAME}_VERSION_FILE_NAME} NEWLINE_STYLE UNIX)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why should the newline style be enforced to UNIX even when running this on Windows?

else()
# if the version file does not exist, create it
set(NEED_TO_CREATE_VERSION_FILE TRUE)
endif()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't the logic be shorted if NEED_TO_CREATE_VERSION_FILE would be initialized with TRUE and only if the file is already present and the expected version string is in the file be changed to FALSE?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@dirk-thomas dirk-thomas added in progress Actively being worked on (Kanban column) enhancement New feature or request labels Sep 6, 2019
@serge-nikulin serge-nikulin force-pushed the Generate-version.h-file branch from 240a842 to aeb5b09 Compare September 19, 2019 16:44
@serge-nikulin
Copy link
Contributor Author

@dirk-thomas, I have addressed your findings. Please see the changes.


/// \def ${PROJECT_NAME_UPPER}_VERSION_STR
/// Defines ${PROJECT_NAME_UPPER} version string
#define ${PROJECT_NAME_UPPER}_VERSION_STR "${VERSION_STR}"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also add add ${PROJECT_NAME_UPPER}_VERSION_GTE(major, minor, patch) macro as defined in https://github.com/ros2/rmw_cyclonedds/pull/51/files#diff-d03c99cafce317e1a93de46e787e0235R64?

/// \def ${PROJECT_NAME_UPPER}_VERSION_GTE
/// Defines a macro to check whether the version of ${PROJECT_NAME_UPPER} is greater than or equal to
/// the given version triple.
#define ${PROJECT_NAME_UPPER}_VERSION_GTE(major, minor, patch) ( \
     (major < ${PROJECT_NAME_UPPER}_VERSION_MAJOR) ? true \
     : (major > ${PROJECT_NAME_UPPER}_VERSION_MAJOR) ? false \
     : (minor < ${PROJECT_NAME_UPPER}_VERSION_MINOR) ? true \
     : (minor > ${PROJECT_NAME_UPPER}_VERSION_MINOR) ? false \
     : (patch < ${PROJECT_NAME_UPPER}_VERSION_PATCH) ? true \
     : (patch > ${PROJECT_NAME_UPPER}_VERSION_PATCH) ? false \
     : true)

I could use such a macro already for rosidl_generator_cpp, to compile my ROS 2 code conditionally depending on the version of rosidl. rosidl_generator_cpp::MessageInitialization and other types have been moved to namespace rosidl_runtime_cpp in version 0.9.0, and I do not see another way to use a non-default message initialization flag such that it works in dashing, eloquent and foxy.

For this specific case it would be convenient to have a

using MessageInitialization = rosidl_runtime_cpp::MessageInitialization;

declaration within the generated message structs, but that is an issue for https://github.com/ros2/rosidl.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@meyerj, done, see the last commit 1b110bd

@hidmic
Copy link
Contributor

hidmic commented Sep 10, 2021

This has been silent for a good while. Any chance you'd bring this back to life @serge-nikulin?

@serge-nikulin
Copy link
Contributor Author

serge-nikulin commented Sep 10, 2021

This has been silent for a good while. Any chance you'd bring this back to life @serge-nikulin?

@hidmic, I got an impression that the maintainers are not interested in this feature. As you can see, I did not get a reply to my review request to @dirk-thomas two years ago: #198 (comment)

@hidmic
Copy link
Contributor

hidmic commented Sep 10, 2021

I do see. It's been a long while. If you rebase I think this might be useful to some people. @clalancette @wjwwood for feedback.

@serge-nikulin
Copy link
Contributor Author

@hidmic, I'll wait for a maintainers' support for this issue. I'm curious why they did not do a similar feature long ago. It's the first product where I have to look up executables' mtime to dig out the installed version 😄

@hidmic
Copy link
Contributor

hidmic commented Sep 10, 2021

I'll wait for a maintainers' support for this issue.

I am the maintainer :)

I'm curious why they did not do a similar feature long ago.

Priorities. Though I vaguely recall some resistance to allowing version-based conditional compilation.


I'm onboard with the idea but I cannot commit time to it right now. Thus my question.

@serge-nikulin
Copy link
Contributor Author

@hidmic , great! I'm going for a two-week vacation starting Sept 17th and I'll do it during that time. I hope you will help me to finish this one.

@serge-nikulin serge-nikulin force-pushed the Generate-version.h-file branch 3 times, most recently from 53733c8 to d8d5ed1 Compare September 22, 2021 04:18
Serge Nikulin added 2 commits September 21, 2021 22:12
Signed-off-by: Serge Nikulin <serge@safeai.ai>
Signed-off-by: Serge Nikulin <serge@safeai.ai>
@serge-nikulin serge-nikulin force-pushed the Generate-version.h-file branch from d8d5ed1 to 1b110bd Compare September 22, 2021 05:14
@serge-nikulin
Copy link
Contributor Author

@hidmic, I rebased and everything checks out OK. Pease review.

endif()

# Find myself so I can use my own cmake instalation folder `ament_cmake_gen_version_h_DIR`
# I can't rely on a pervious find_package call because it could be a direct call

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# I can't rely on a pervious find_package call because it could be a direct call
# I can't rely on a previous find_package call because it could be a direct call

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, fixed

Signed-off-by: Serge Nikulin <serge@safeai.ai>
Comment on lines 30 to 31
# I can't rely on a previous find_package call because it could be a direct call
find_package(ament_cmake_gen_version_h REQUIRED)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@serge-nikulin direct call? If this .cmake file is simply included, there may not even be an installed config module to look for in the CMAKE_PREFIX_PATH.

I'm inclined to drop this and instead document how to make proper use of this function.

Copy link
Contributor Author

@serge-nikulin serge-nikulin Sep 23, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hidmic, The find_package call provides me with $ament_cmake_gen_version_h_DIR variable so I can have access to my template file ${ament_cmake_gen_version_h_DIR}/version.h.in. That's the only reliable way to do it, AFAIK.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right. My point is, the only scenario I can think of where a downstream package wouldn't have had to call find_package(ament_cmake_gen_version_h) first is when ament_cmake_gen_version_h is included into another, outer project. In that case, find_package(ament_cmake_gen_version_h) will fail anyways. The outer project has to set that directory for you.


install(
DIRECTORY ${TMP_INCLUDE_DIR}
DESTINATION include)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@serge-nikulin I'm somewhat inclined towards generating the file and letting the caller decide if and where to install it (as if it was an OUTPUT of add_custom_command).

I'd be OK with optionally delegating the installation though.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hidmic, I decided to parametrize pretty much everything. How do the following optional parameters look to you?
If you are OK, I'll proceed with them and also create some unit tests for different scenarios.

# :param DO_NOT_INSTALL: whether to autmatically install the generated version file into DESTINATION include
# :type DO_NOT_INSTALL: BOOL
# :default value DO_NOT_INSTALL: FALSE

# :param PRJ_NAME: project name to use
# :type PRJ_NAME: string
# :default value PRJ_NAME: ${PROJECT_NAME}

# :param INCLUDE_DIR: path to the include folder where the file will be generated
#     ${INCLUDE_DIR} folder will be added to the include paths
#     the file will be placed into ${INCLUDE_DIR}/${PRJ_NAME} folder according to ROS2 standard
# :type INCLUDE_DIR: string
# :default value INCLUDE_DIR: ${CMAKE_CURRENT_BINARY_DIR}/ament_cmake_gen_version_h/include

# :param VERSION_FILE_NAME: file name of the generated header file
# :type VERSION_FILE_NAME: string
# :default value VERSION_FILE_NAME: version.h

Copy link
Contributor

@hidmic hidmic Sep 23, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@serge-nikulin may I suggest a NO_INSTALL option instead of a DO_NOT_INSTALL one-value argument? Also, what use case do you have in mind for PRJ_NAME? Why would you want to change it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree with both points. Please review again.

@serge-nikulin serge-nikulin force-pushed the Generate-version.h-file branch from 9e26d46 to db13b3c Compare September 23, 2021 07:11
Serge Nikulin added 2 commits September 25, 2021 03:39
Signed-off-by: Serge Nikulin <serge@safeai.ai>
Signed-off-by: Serge Nikulin <serge@safeai.ai>
@serge-nikulin serge-nikulin force-pushed the Generate-version.h-file branch from db13b3c to 9269c03 Compare September 25, 2021 10:40
@serge-nikulin
Copy link
Contributor Author

@hidmic, it seems I can't add a self/unit test section to the project. The following code is silently ignored by colcon build. What do I miss? Can you help?

if(BUILD_TESTING)
  find_package(ament_cmake_gmock REQUIRED)
  find_package(ament_cmake_gtest REQUIRED)
  find_package(ament_cmake_uncrustify REQUIRED)
  find_package(ament_cmake_copyright REQUIRED)
  find_package(ament_cmake_cpplint REQUIRED)
  find_package(ament_cmake_lint_cmake REQUIRED)

  ament_add_gtest(test_${PROJECT_NAME}
    test1.cpp
  )

  ament_uncrustify(${LINT_DIRECTORIES})
  ament_copyright(${LINT_DIRECTORIES})
  ament_cpplint(${LINT_DIRECTORIES})
  ament_lint_cmake(${CMAKE_CURRENT_SOURCE_DIR})
endif()

@hidmic
Copy link
Contributor

hidmic commented Sep 27, 2021

The following code is silently ignored by colcon build.

colcon simply invokes cmake, so I'm inclined to think BUILD_TESTING is not set. Have you added these packages as test dependencies in your package.xml? BTW, have a look at ament_lint_auto to reduce the amount of boilerplate.

Signed-off-by: Serge Nikulin <serge@safeai.ai>
@serge-nikulin serge-nikulin force-pushed the Generate-version.h-file branch from 31a3d10 to 610d7a1 Compare September 27, 2021 23:53
@serge-nikulin
Copy link
Contributor Author

@hidmic, please review.


find_package(ament_cmake_core REQUIRED)

ament_package(CONFIG_EXTRAS "ament_cmake_gen_version_h-extras.cmake")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@serge-nikulin this line should be (conventionally) the last.

@@ -0,0 +1,50 @@
cmake_minimum_required(VERSION 3.5)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@serge-nikulin nit: extra blank line

include (cmake/ament_cmake_gen_version_h.cmake)
find_package(ament_cmake_gtest REQUIRED)

ament_cmake_gen_version_h(NO_INSTALL TRUE)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@serge-nikulin hmm, options do not need a literal boolean argument -- their presence (or absence) is the boolean.

test/test_version1_h.cpp
test/test_version2_h.cpp
)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@serge-nikulin nit: extra blank line

<buildtool_depend>ament_package</buildtool_depend>

<buildtool_export_depend>ament_cmake_core</buildtool_export_depend>
<test_depend>ament_cmake_gtest</test_depend>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@serge-nikulin consider adding ament_lint_common linters.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hidmic, ament_lint repo depends on amen_cmake and does not exist during amen_cmake build. Nevertheless, on my PC I did run all the linters "out of order" and fixed all violations.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah good point.

I did run all the linters "out of order" and fixed all violations.

Much appreciated.

# :type VERSION_PATCH: string
# :default value VERSION_PATCH: VERSION_PATCH from the package.xml file

################################################################################
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@serge-nikulin nit: follow the docblock format that is used for other functions and macros in this repository.

cmake_minimum_required(VERSION 3.5)

project(ament_cmake_gen_version_h)
include(CTest)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@serge-nikulin nit: let's move this right next to the BUILD_TESTING clause.

@serge-nikulin serge-nikulin force-pushed the Generate-version.h-file branch from 9101e13 to 94b9c26 Compare September 28, 2021 20:45
Signed-off-by: Serge Nikulin <serge@safeai.ai>
@serge-nikulin serge-nikulin force-pushed the Generate-version.h-file branch from 94b9c26 to 4e75764 Compare September 28, 2021 20:50
@serge-nikulin
Copy link
Contributor Author

@hidmic, I addressed all your findings, please review again

Copy link
Contributor

@hidmic hidmic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall this LGTM but for one observation. Once that's addressed, I'll run CI.

@wjwwood @clalancette any last minute concerns about this?

message(STATUS "Skip version file creation")
endif()

if(NOT ARG_DO_NOT_INSTALL)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@serge-nikulin should this be

Suggested change
if(NOT ARG_DO_NOT_INSTALL)
if(NOT ARG_NOT_INSTALL)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hidmic, Oops. Fixed.

Signed-off-by: Serge Nikulin <serge@safeai.ai>
@clalancette
Copy link
Contributor

@wjwwood @clalancette any last minute concerns about this?

No objections from me.

@hidmic
Copy link
Contributor

hidmic commented Sep 30, 2021

CI above ament_cmake_gen_version_h:

  • Linux Build Status
  • Linux-aarch64 Build Status
  • macOS Build Status
  • Windows Build Status

@hidmic
Copy link
Contributor

hidmic commented Sep 30, 2021

Alright, going in then. Thank you for your contribution @serge-nikulin !

@hidmic hidmic changed the title Add ament_cmake_version package Add ament_cmake_gen_version_h package Sep 30, 2021
@hidmic hidmic merged commit 09c5b06 into ament:master Sep 30, 2021
@serge-nikulin
Copy link
Contributor Author

@hidmic, now somebody should call this function from some ROS2 package like rcutils.

@serge-nikulin
Copy link
Contributor Author

or possibly from every project that installs headers.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request in progress Actively being worked on (Kanban column)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants