include(GNUInstallDirs)
include(CMakePackageConfigHelpers)
if ($ENV{VERBOSE})
message(STATUS "CMAKE_INSTALL_BINDIR: ${CMAKE_INSTALL_BINDIR} (full: ${CMAKE_INSTALL_FULL_BINDIR})")
message(STATUS "CMAKE_INSTALL_LIBDIR: ${CMAKE_INSTALL_LIBDIR} (full: ${CMAKE_INSTALL_FULL_LIBDIR})")
message(STATUS "CMAKE_INSTALL_DATADIR: ${CMAKE_INSTALL_DATADIR} (full: ${CMAKE_INSTALL_FULL_DATADIR})")
endif()
# Enforce C++17 in all dependent projects:
function(mrpt_lib_target_requires_cpp17 _TARGET)
get_target_property(target_type ${_TARGET} TYPE)
if (${target_type} STREQUAL "INTERFACE_LIBRARY")
set(INTERF_TYPE "INTERFACE")
else()
set(INTERF_TYPE "PUBLIC")
endif()
# Modern, clean way to do this:
target_compile_features(${_TARGET} ${INTERF_TYPE} cxx_std_17)
endfunction()
# Minimize the time and memory required to build and load debug info:
#-----------------------------------------------------------------------
function(mrpt_reduced_debug_symbols TARGET_)
get_property(CUR_FLAGS_ TARGET ${TARGET_} PROPERTY COMPILE_OPTIONS)
set(cxxflags_ "$ENV{CXXFLAGS}")
separate_arguments(cxxflags_)
if (("-g" IN_LIST CUR_FLAGS_) OR ("-g" IN_LIST cxxflags_))
if (MRPT_COMPILER_IS_GCC)
target_compile_options(${TARGET_} PRIVATE -g1)
elseif(MRPT_COMPILER_IS_CLANG)
target_compile_options(${TARGET_} PRIVATE -gline-tables-only)
endif()
endif()
endfunction()
# handle_special_simd_flags(): Add custom flags to a set of source files
# Only for Intel-compatible archs
#-----------------------------------------------------------------------
function(handle_special_simd_flags lst_files FILE_PATTERN FLAGS_TO_ADD)
if (MRPT_COMPILER_IS_GCC_OR_CLANG AND MRPT_ARCH_INTEL_COMPATIBLE)
set(_lst ${lst_files})
KEEP_MATCHING_FILES_FROM_LIST(${FILE_PATTERN} _lst)
if(NOT "${_lst}" STREQUAL "")
set_source_files_properties(${_lst} PROPERTIES COMPILE_FLAGS "${FLAGS_TO_ADD}")
endif()
endif()
endfunction()
# From: https://github.com/ament/ament_cmake/blob/rolling/ament_cmake_python/ament_cmake_python-extras.cmake
macro(mrpt_ament_cmake_python_get_python_install_dir)
if(NOT DEFINED PYTHON_INSTALL_DIR)
# (JLBC,June 2023): *Hack* to comply with ROS conventions of storing python pkgs differently than Debian/Ubuntu standards.
# (JLBC,Jan 2024):
# - ROS 1: lib/python3/dist-packages/
# - ROS 2: lib/pythonX.Y/site-packages/
# - Debian: lib/pythonX.Y/
if(NOT DEFINED ENV{ROS_VERSION})
# Regular Debian package.
set(_output "lib/python${Python3_VERSION_MAJOR}.${Python3_VERSION_MINOR}/") # this is prefixed with "/usr/"
elseif("$ENV{ROS_VERSION}" STREQUAL "1")
# ROS 1
set(_output "lib/python3/dist-packages/") # this is prefixed with "/opt/ros/xxx/"
elseif("$ENV{ROS_VERSION}" STREQUAL "2")
# ROS 2
set(_output "lib/python${Python3_VERSION_MAJOR}.${Python3_VERSION_MINOR}/site-packages/") # this is prefixed with "/opt/ros/xxx/"
else()
message(FATAL_ERROR "Unhandled value for ENV{ROS_VERSION}=$ENV{ROS_VERSION}")
endif()
set(PYTHON_INSTALL_DIR
"${_output}"
CACHE INTERNAL
"The directory for Python library installation. This needs to be in PYTHONPATH when 'setup.py install' is called.")
unset(_output)
endif()
endmacro()
# define_mrpt_lib(): Declares an MRPT library target:
#-----------------------------------------------------------------------
macro(define_mrpt_lib name)
internal_define_mrpt_lib(${name} 0 ${ARGN}) # headers_only = 0
endmacro()
# define_mrpt_lib_header_only(): Declares an MRPT headers-only library:
#-----------------------------------------------------------------------
macro(define_mrpt_lib_header_only name)
internal_define_mrpt_lib(${name} 1 ${ARGN}) # headers_only = 1
endmacro()
# Implementation of both define_mrpt_lib() and define_mrpt_lib_headers_only():
#-----------------------------------------------------------------------------
macro(internal_define_mrpt_lib name headers_only )
include(../../cmakemodules/AssureCMakeRootFile.cmake) # Avoid user mistake in CMake source directory
# Allow programmers of mrpt libs to change the default value of build_mrpt-LIB, which is "ON" by default.
set(_DEFVAL "${DEFAULT_BUILD_mrpt-${name}}")
if ("${_DEFVAL}" STREQUAL "")
set(_DEFVAL "ON")
endif ()
set(BUILD_mrpt-${name} ${_DEFVAL} CACHE BOOL "Build the library mrpt-${name}")
if(BUILD_mrpt-${name})
# --- Start of conditional build of module ---
project(mrpt-${name} LANGUAGES C CXX)
# Optional build-time plugin mechanism:
set(PLUGIN_FILE_mrpt-${name} "" CACHE FILEPATH "Optional CMake file defining additional sources for mrpt-${name}")
mark_as_advanced(PLUGIN_FILE_mrpt-${name})
if (EXISTS "${PLUGIN_FILE_mrpt-${name}}")
include("${PLUGIN_FILE_mrpt-${name}}")
list(APPEND ${name}_EXTRA_SRCS ${${name}_PLUGIN_SRCS})
list(APPEND ${name}_EXTRA_SRCS_NAME ${${name}_PLUGIN_SRCS_NAME})
endif()
# There is an optional LISTS of extra sources from the caller:
# "${name}_EXTRA_SRCS" and
# "${name}_EXTRA_SRCS_NAME" <--- Must NOT contain spaces!!
#
# At return from this macro, there'll be defined a variable:
# "${${name}_EXTRA_SRCS_NAME}_FILES"
# with the list of all files under that group.
#
# For code simplicity, let's use the same list, just adding the default sources there:
list(APPEND ${name}_EXTRA_SRCS
"${MRPT_SOURCE_DIR}/libs/${name}/src/*.cpp"
"${MRPT_SOURCE_DIR}/libs/${name}/src/*.c"
"${MRPT_SOURCE_DIR}/libs/${name}/src/*.cxx"
"${MRPT_SOURCE_DIR}/libs/${name}/src/*.h"
"${MRPT_SOURCE_DIR}/libs/${name}/include/mrpt/${name}/*.h"
"${MRPT_SOURCE_DIR}/libs/${name}/include/mrpt/${name}/*.hpp"
"${MRPT_SOURCE_DIR}/doc/doxygen-pages/lib_mrpt_${name}.h"
)
list(APPEND ${name}_EXTRA_SRCS_NAME
"${name}"
"${name}"
"${name}"
"${name} Internal Headers"
"${name} Public Headers"
"${name} Public Headers"
"${name} docs Headers"
)
# Only add these ones for "normal" libraries:
if (NOT ${headers_only})
list(APPEND ${name}_EXTRA_SRCS
"${MRPT_SOURCE_DIR}/libs/${name}/src/registerAllClasses.cpp"
)
list(APPEND ${name}_EXTRA_SRCS_NAME
"Class register"
)
endif ()
# Collect files
# ---------------------------------------------------------
list(LENGTH ${name}_EXTRA_SRCS N_SRCS)
list(LENGTH ${name}_EXTRA_SRCS_NAME N_SRCS_NAMES)
if (NOT N_SRCS EQUAL N_SRCS_NAMES)
message(ERROR " ${name}_EXTRA_SRCS=${${name}_EXTRA_SRCS}")
message(ERROR " ${name}_EXTRA_SRCS_NAME=${${name}_EXTRA_SRCS_NAME}")
message(FATAL_ERROR "Mismatch length in ${name}_EXTRA_SRCS and ${name}_EXTRA_SRCS_NAME!")
endif ()
set(${name}_srcs "") # ALL the files
math(EXPR N_SRCS "${N_SRCS}-1") # Indices are 0-based
foreach(i RANGE 0 ${N_SRCS})
# Get i'th expression & its name:
list(GET ${name}_EXTRA_SRCS ${i} FILS_EXPR)
list(GET ${name}_EXTRA_SRCS_NAME ${i} FILS_GROUP_NAME)
file(GLOB aux_list ${FILS_EXPR})
source_group("${FILS_GROUP_NAME} files" FILES ${aux_list})
# Add to main list:
list(APPEND ${name}_srcs ${aux_list})
# All to group lists, may be used by the user upon return from this macro:
list(APPEND ${FILS_GROUP_NAME}_FILES ${aux_list})
endforeach()
# Remove _LIN files when compiling under Windows, and _WIN files when compiling under Linux.
if(WIN32)
REMOVE_MATCHING_FILES_FROM_LIST(".*_LIN.cpp" ${name}_srcs) # Win32
else()
REMOVE_MATCHING_FILES_FROM_LIST(".*_WIN.cpp" ${name}_srcs) # Apple & Unix
endif()
# Keep a list of unit testing files, for declaring them in /test:
set(lst_unittests ${${name}_srcs})
KEEP_MATCHING_FILES_FROM_LIST(".*_unittest.cpp" lst_unittests)
if(NOT "${lst_unittests}" STREQUAL "")
# We have unit tests:
get_property(_lst_lib_test GLOBAL PROPERTY "MRPT_TEST_LIBS")
set_property(GLOBAL PROPERTY "MRPT_TEST_LIBS" ${_lst_lib_test} mrpt_${name})
set_property(GLOBAL PROPERTY "mrpt_${name}_UNIT_TEST_FILES" ${lst_unittests})
endif()
# Enable SIMD especial instructions in especialized source files, even if
# those instructions are NOT enabled globally for the entire build:
handle_special_simd_flags("${${name}_srcs}" ".*\.SSE2.cpp" "-msse2")
handle_special_simd_flags("${${name}_srcs}" ".*\.SSSE3.cpp" "-msse3 -mssse3")
handle_special_simd_flags("${${name}_srcs}" ".*\.AVX.cpp" "-mavx")
handle_special_simd_flags("${${name}_srcs}" ".*\.AVX2.cpp" "-mavx2")
# Don't include here the unit testing code:
REMOVE_MATCHING_FILES_FROM_LIST(".*_unittest.cpp" ${name}_srcs)
# Define the target:
set(all_${name}_srcs ${${name}_srcs})
# Add main lib header (may not exist in meta-libs only):
if (EXISTS "${MRPT_SOURCE_DIR}/libs/${name}/include/mrpt/${name}.h")
set(all_${name}_srcs ${all_${name}_srcs} "${MRPT_SOURCE_DIR}/libs/${name}/include/mrpt/${name}.h")
endif ()
if (NOT ${headers_only})
# A libray target:
add_library(${name}
${all_${name}_srcs}
${MRPT_VERSION_RC_FILE} # Only !="" in Win32: the .rc file with version info
)
# private include dirs for this lib:
target_include_directories(${name} PRIVATE
$ # To include ${name}-precomp.h
)
if(MSVC) # Define math constants if built with MSVC
target_compile_definitions(${name} PUBLIC _USE_MATH_DEFINES)
endif()
# Includes: & config headers:
# These are PRIVATE include to enforce including BEFORE any other headers,
# e.g. another mrpt instance installed under /opt/ros/${ROS_DISTRO} while building a local copy
# Note that there is another PUBLIC dep on the same headers for mrpt-core only, so user code
# sees those files too.
target_include_directories(${name} BEFORE PRIVATE
$
$
)
# for gcc and clang, we must build libraries as fPIC:
if(NOT MSVC)
target_compile_options(${name} PRIVATE "-fPIC")
endif()
set_target_properties(${name} PROPERTIES FOLDER "modules")
set(iftype PUBLIC)
add_coverage(${name})
if(CLANG_TIDY_EXE)
set_target_properties(
${name} PROPERTIES
CXX_CLANG_TIDY "${DO_CLANG_TIDY}"
)
endif()
else()
# A hdr-only library: needs no real compiling
add_library(${name} INTERFACE)
REMOVE_MATCHING_FILES_FROM_LIST(".*.h" all_${name}_srcs)
# List of hdr files (for editing in IDEs,etc.):
target_sources(${name} INTERFACE ${all_${name}_srcs})
set(iftype INTERFACE)
endif ()
# in any case, create alias to make examples CMake scripts to work as if
# mrpt had been really imported:
add_library(mrpt::${name} ALIAS ${name})
# Include directories for target:
target_include_directories(${name} ${iftype}
$
$
)
add_dependencies(all_mrpt_libs ${name}) # for target: all_mrpt_libs
# Append to list of all mrpt-* libraries:
if("${ALL_MRPT_LIBS}" STREQUAL "") # first one is different to avoid an empty first list element ";mrpt-xxx"
set(ALL_MRPT_LIBS "${name}" CACHE INTERNAL "") # This emulates global vars
else()
set(ALL_MRPT_LIBS "${ALL_MRPT_LIBS};${name}" CACHE INTERNAL "") # This emulates global vars
endif()
# Dependencies:
set(MRPT_ONLY_DEPS_LIST "")
set(ALL_DEPS_LIST "")
set(AUX_ALL_DEPS_BUILD 1) # Will be set to "0" if any dependency if not built
foreach(DEP ${ARGN})
list(APPEND ALL_DEPS_LIST ${DEP}) # used in mrpt-*-config.cmake.in
# Only for "mrpt-XXX" libs:
if (DEP MATCHES "^mrpt-?:*(.*)")
string(REGEX REPLACE "mrpt-?:*(.*)" "\\1" DEP_MRPT_NAME ${DEP})
else()
set(DEP_MRPT_NAME "")
endif()
if(NOT "${DEP_MRPT_NAME}" STREQUAL "")
# Add it as a dependency
target_link_libraries(${name} PUBLIC mrpt::${DEP_MRPT_NAME})
#add_dependencies() implicit with above link dep
# Append to list of mrpt-* lib dependences:
list(APPEND MRPT_ONLY_DEPS_LIST mrpt::${DEP_MRPT_NAME})
# Now, check mrpt-* deps only:
# Check if all dependencies are to be build:
if ("${BUILD_mrpt-${DEP_MRPT_NAME}}" STREQUAL "OFF")
# Attempt at using system version?
find_package(mrpt-${DEP_MRPT_NAME})
if (NOT TARGET mrpt::${DEP_MRPT_NAME})
set(AUX_ALL_DEPS_BUILD 0)
message(STATUS "*Warning*: Lib mrpt-${name} cannot be built because dependency mrpt-${DEP_MRPT_NAME} has been disabled!")
else()
message(STATUS "*Warning*: Lib mrpt-${name} is using system depency: mrpt-${DEP_MRPT_NAME}")
endif()
endif ()
endif ()
endforeach()
# Impossible to build?
if (NOT AUX_ALL_DEPS_BUILD)
message(STATUS "*Warning* ==> Disabling compilation of lib mrpt-${name} for missing dependencies listed above.")
set(BUILD_mrpt-${name} OFF CACHE BOOL "Build the library mrpt-${name}" FORCE)
endif ()
# Emulates a global variable:
set_property(GLOBAL PROPERTY "mrpt-${name}_LIB_DEPS" "${MRPT_ONLY_DEPS_LIST}")
set_property(GLOBAL PROPERTY "mrpt-${name}_LIB_IS_HEADERS_ONLY" "${headers_only}")
add_dependencies(${name} "DocumentationFiles") # docs files target (useful for IDE editing)
# Set custom name of lib + dynamic link numbering convenions in Linux:
if (NOT ${headers_only})
set_target_properties(${name} PROPERTIES
OUTPUT_NAME ${MRPT_LIB_PREFIX}mrpt-${name}${MRPT_DLL_VERSION_POSTFIX}
COMPILE_PDB_NAME "${MRPT_LIB_PREFIX}mrpt-${name}${MRPT_DLL_VERSION_POSTFIX}"
COMPILE_PDB_NAME_DEBUG "${MRPT_LIB_PREFIX}mrpt-${name}${MRPT_DLL_VERSION_POSTFIX}${CMAKE_DEBUG_POSTFIX}"
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib/"
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/"
VERSION "${CMAKE_MRPT_VERSION_NUMBER_MAJOR}.${CMAKE_MRPT_VERSION_NUMBER_MINOR}.${CMAKE_MRPT_VERSION_NUMBER_PATCH}"
SOVERSION ${CMAKE_MRPT_VERSION_NUMBER_MAJOR}.${CMAKE_MRPT_VERSION_NUMBER_MINOR}
)
# Set all header files as "ignored" (don't build!):
# -----------------------------------------------------
set(AUX_LIST_TO_IGNORE ${all_${name}_srcs})
KEEP_MATCHING_FILES_FROM_LIST("^.*h$" AUX_LIST_TO_IGNORE)
set_source_files_properties(${AUX_LIST_TO_IGNORE} PROPERTIES HEADER_FILE_ONLY true)
# If UNIX, don't link against unused libs:
IF (UNIX AND NOT APPLE)
set_property(
TARGET ${name}
APPEND_STRING PROPERTY
LINK_FLAGS " -Wl,--copy-dt-needed-entries -Wl,--no-undefined -Wl,--no-allow-shlib-undefined")
endif()
if(MRPT_ENABLE_PRECOMPILED_HDRS)
if (MSVC)
# Precompiled hdrs for MSVC:
# --------------------------------------
string(TOUPPER ${name} NAMEUP)
# The "use precomp.headr" for all the files...
set_target_properties(${name}
PROPERTIES
COMPILE_FLAGS "/Yu${name}-precomp.h")
# But for the file used to build the precomp. header:
set_source_files_properties("${MRPT_SOURCE_DIR}/libs/${name}/src/${name}-precomp.cpp"
PROPERTIES
COMPILE_FLAGS "/Yc${name}-precomp.h")
else()
# Use cotire module for GCC/CLANG:
list(APPEND COTIRE_PREFIX_HEADER_IGNORE_PATH
"${OpenCV_INCLUDE_DIR}"
"${MRPT_LIBS_ROOT}/${name}/src"
"/usr/" # avoid problems with Cotire trying to include internal GCC headers, not suitable for direct use.
)
set_target_properties(${name} PROPERTIES
COTIRE_PREFIX_HEADER_IGNORE_PATH "${COTIRE_PREFIX_HEADER_IGNORE_PATH}"
)
set_target_properties(${name} PROPERTIES COTIRE_CXX_PREFIX_HEADER_INIT "${MRPT_SOURCE_DIR}/libs/${name}/src/${name}-precomp.h")
cotire(${name})
if($ENV{VERBOSE})
#get_target_property(_unitySource example COTIRE_CXX_UNITY_SOURCE)
#get_target_property(_unityTargetName mrpt-${name} COTIRE_UNITY_TARGET_NAME)
get_target_property(_prefixHeader ${name} COTIRE_CXX_PREFIX_HEADER)
get_target_property(_precompiledHeader ${name} COTIRE_CXX_PRECOMPILED_HEADER)
message(STATUS " mrpt-${name}: Prefix header=${_prefixHeader}")
message(STATUS " mrpt-${name}: PCH header=${_precompiledHeader}")
endif()
endif()
source_group("Precompiled headers" FILES
"${MRPT_SOURCE_DIR}/libs/${name}/src/${name}-precomp.cpp"
"${MRPT_SOURCE_DIR}/libs/${name}/src/${name}-precomp.h"
)
endif()
# MATLAB?
if (CMAKE_MRPT_HAS_MATLAB)
target_link_libraries(${name} PRIVATE ${MATLAB_LIBRARIES})
endif()
# (See comments in script_matlab.cmake)
# Add /DELAYLOAD:... to avoid dependency of these DLLs for standalone (non-mex) projects
if (CMAKE_MRPT_HAS_MATLAB AND BUILD_SHARED_LIBS AND MSVC)
set_property(
TARGET ${name}
APPEND_STRING PROPERTY
LINK_FLAGS " /DELAYLOAD:\"libmx.dll\" /DELAYLOAD:\"libmex.dll\" /ignore:4199")
# The /ignore:4199 is to disable warnings like these:
# warning LNK4199: /DELAYLOAD:libmx.dll ignored; no imports found from libmx.dll
# in libs which do not (yet) support mex stuff
endif ()
if (USE_IWYU)
set_property(
TARGET ${name}
PROPERTY CXX_INCLUDE_WHAT_YOU_USE ${IWYU_PATH_AND_OPTIONS})
endif()
# make sure the library gets installed
install(TARGETS ${name} EXPORT mrpt-${name}-targets
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT Libraries
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT Libraries
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT Libraries
)
# Collect .pdb debug files for optional installation:
if (MSVC)
set(PDB_FILE
"${CMAKE_BINARY_DIR}/bin/Debug/${MRPT_LIB_PREFIX}mrpt-${name}${MRPT_DLL_VERSION_POSTFIX}${CMAKE_DEBUG_POSTFIX}.pdb")
if (EXISTS "${PDB_FILE}")
install(FILES ${PDB_FILE} DESTINATION bin COMPONENT LibrariesDebugInfoPDB)
endif ()
endif()
else() # it IS headers_only:
install(TARGETS ${name} EXPORT mrpt-${name}-targets)
endif ()
# Create module CMake config file:
# For local usage from the BUILD directory (without "install"):
# 1/3: autogenerated target file:
export(
TARGETS ${name}
FILE "${CMAKE_BINARY_DIR}/mrpt-${name}-targets.cmake"
NAMESPACE mrpt::
)
# 2/3: config file with manual list of dependencies:
set(MRPT_MODULE_NAME ${name})
configure_file(
"${MRPT_SOURCE_DIR}/parse-files/mrpt-xxx-config.cmake.in"
"${CMAKE_BINARY_DIR}/mrpt-${name}-config.cmake" IMMEDIATE @ONLY)
# 3/3: version file:
write_basic_package_version_file(
"${CMAKE_BINARY_DIR}/mrpt-${name}-config-version.cmake"
VERSION ${CMAKE_MRPT_FULL_VERSION}
COMPATIBILITY AnyNewerVersion
)
# Regular arch-dep libraries get to LIBDIR (/usr/lib), while
# arch-indep (headers-only) go to DATADIR (/usr/share):
if (${headers_only})
set(LIB_TARGET_INSTALL_DEST ${CMAKE_INSTALL_DATADIR})
else()
set(LIB_TARGET_INSTALL_DEST ${CMAKE_INSTALL_LIBDIR})
endif()
# mrpt-xxx-config.cmake file:
# Makes the project importable from installed dir:
install(
EXPORT mrpt-${name}-targets
DESTINATION ${LIB_TARGET_INSTALL_DEST}/cmake/mrpt-${name}
NAMESPACE mrpt::
)
# - autogenerated target file +our custom *-config files,
# - version file
install(
FILES
"${CMAKE_BINARY_DIR}/mrpt-${name}-config.cmake"
"${CMAKE_BINARY_DIR}/mrpt-${name}-config-version.cmake"
DESTINATION ${LIB_TARGET_INSTALL_DEST}/cmake/mrpt-${name}
)
# Install public headers:
set(HEADERS_DIR "${MRPT_SOURCE_DIR}/libs/${name}/include/")
if (EXISTS "${HEADERS_DIR}") # This is mainly to avoid problems with "virtual module" names
install(
DIRECTORY
"${HEADERS_DIR}"
DESTINATION
${CMAKE_INSTALL_INCLUDEDIR}/mrpt/${name}/include/
)
endif()
if(MRPT_ENABLE_PRECOMPILED_HDRS AND MSVC)
foreach(_N ${${name}_PLUGIN_SRCS_NAME})
#message(STATUS "Disabling precomp hdrs for N=${_N}: ${${_N}_FILES}")
set_source_files_properties(${${_N}_FILES} PROPERTIES COMPILE_FLAGS "/Y-")
endforeach()
endif()
# --- End of conditional build of module ---
endif()
endmacro()
# Credits: https://gist.github.com/jtanx/96ded5e050d5ee5b19804195ee5cf5f9
function(pad_string output str padchar length)
string(LENGTH "${str}" _strlen)
math(EXPR _strlen "${length} - ${_strlen}")
if(_strlen GREATER 0)
string(REPEAT ${padchar} ${_strlen} _pad)
string(PREPEND str ${_pad})
endif()
set(${output} "${str}" PARENT_SCOPE)
endfunction()
# 2 hex digits for each version part:
# For example: "0.5.1" => "0x000501"
macro(mrpt_version_to_hex VER TARGET_VAR_NAME)
string(REGEX MATCHALL "[0-9]+" __parts "${${VER}}")
if(__parts)
list(GET __parts 0 __VERSION_NUMBER_MAJOR)
list(GET __parts 1 __VERSION_NUMBER_MINOR)
list(GET __parts 2 __VERSION_NUMBER_PATCH)
pad_string(__VERSION_NUMBER_MAJOR ${__VERSION_NUMBER_MAJOR} "0" 2)
pad_string(__VERSION_NUMBER_MINOR ${__VERSION_NUMBER_MINOR} "0" 2)
pad_string(__VERSION_NUMBER_PATCH ${__VERSION_NUMBER_PATCH} "0" 2)
set(${TARGET_VAR_NAME} "0x${__VERSION_NUMBER_MAJOR}${__VERSION_NUMBER_MINOR}${__VERSION_NUMBER_PATCH}")
else()
set(${TARGET_VAR_NAME} "0x000")
endif()
endmacro()