CMake: improve Protobuf handling

This commit is contained in:
Carles Fernandez
2026-08-04 10:44:44 +02:00
parent 728222e709
commit 80f79d3680
+154 -48
View File
@@ -2301,41 +2301,14 @@ else()
endif()
if(NOT Protobuf_FOUND)
set(GNSSSDR_PROTOBUF_MODULE_MODE TRUE)
find_package(Protobuf MODULE)
if(Protobuf_FOUND)
# FindProtobuf reports the C++ runtime version, while protobuf.pc
# uses the release version. For example, "4.25.3" maps to "25.3.0".
string(REGEX REPLACE "^[0-9]+\.([0-9]+\.[0-9]+)$" "\\1.0"
PROTOBUF_LIBRARY_VERSION "${Protobuf_VERSION}")
if(NOT (PROTOBUF_LIBRARY_VERSION VERSION_LESS "22"))
if(CMAKE_VERSION VERSION_LESS 3.6)
pkg_check_modules(GNSSSDR_PROTOBUF_PC QUIET
protobuf=${PROTOBUF_LIBRARY_VERSION})
else()
pkg_check_modules(GNSSSDR_PROTOBUF_PC QUIET IMPORTED_TARGET
protobuf=${PROTOBUF_LIBRARY_VERSION})
endif()
if(NOT GNSSSDR_PROTOBUF_PC_FOUND)
message(FATAL_ERROR
"Protocol Buffers ${Protobuf_VERSION} was found through CMake's FindProtobuf module, "
"but matching pkg-config metadata for protobuf ${PROTOBUF_LIBRARY_VERSION} was not found. "
"Make protobuf-config.cmake discoverable or install the matching protobuf.pc file so "
"that Protobuf's Abseil and utf8_range dependencies can be linked correctly."
)
endif()
endif()
endif()
endif()
endif()
set_package_properties(Protobuf PROPERTIES
URL "https://protobuf.dev/"
PURPOSE "Used to serialize output data in a way that can be read by other applications."
TYPE REQUIRED
)
if(NOT Protobuf_VERSION)
set(Protobuf_VERSION "0.0.0")
endif()
# FindProtobuf used only upper-case output variables before CMake 3.6 and did
# not provide a version before CMake 3.6. Normalize those results before using
# them to decide whether modern Protobuf dependencies are needed.
if(CMAKE_VERSION VERSION_LESS 3.6)
if(PROTOBUF_FOUND)
set(Protobuf_FOUND ${PROTOBUF_FOUND})
@@ -2345,6 +2318,11 @@ if(Protobuf_FOUND AND CMAKE_VERSION VERSION_LESS 3.9)
if(PROTOBUF_INCLUDE_DIR)
set(Protobuf_INCLUDE_DIR ${PROTOBUF_INCLUDE_DIR})
endif()
if(PROTOBUF_INCLUDE_DIRS)
set(Protobuf_INCLUDE_DIRS ${PROTOBUF_INCLUDE_DIRS})
elseif(PROTOBUF_INCLUDE_DIR)
set(Protobuf_INCLUDE_DIRS ${PROTOBUF_INCLUDE_DIR})
endif()
if(PROTOBUF_LIBRARY)
set(Protobuf_LIBRARY ${PROTOBUF_LIBRARY})
endif()
@@ -2352,8 +2330,123 @@ if(Protobuf_FOUND AND CMAKE_VERSION VERSION_LESS 3.9)
set(Protobuf_PROTOC_EXECUTABLE ${PROTOBUF_PROTOC_EXECUTABLE})
endif()
if(PROTOBUF_PROTOC_LIBRARY)
set(Protobuf_PROTOC_LIBRARY ${PROTOBUF_PROTOC_EXECUTABLE})
set(Protobuf_PROTOC_LIBRARY ${PROTOBUF_PROTOC_LIBRARY})
endif()
endif()
if(Protobuf_FOUND AND NOT Protobuf_VERSION)
set(_PROTOBUF_COMMON_HEADER ${Protobuf_INCLUDE_DIR}/google/protobuf/stubs/common.h)
if(EXISTS "${_PROTOBUF_COMMON_HEADER}")
file(STRINGS ${_PROTOBUF_COMMON_HEADER} _PROTOBUF_COMMON_H_CONTENTS
REGEX "#define[ \t]+GOOGLE_PROTOBUF_VERSION[ \t]+[0-9]+")
if(_PROTOBUF_COMMON_H_CONTENTS MATCHES
"#define[ \t]+GOOGLE_PROTOBUF_VERSION[ \t]+([0-9]+)")
set(Protobuf_LIB_VERSION "${CMAKE_MATCH_1}")
math(EXPR _PROTOBUF_MAJOR_VERSION "${Protobuf_LIB_VERSION} / 1000000")
math(EXPR _PROTOBUF_MINOR_VERSION "${Protobuf_LIB_VERSION} / 1000 % 1000")
math(EXPR _PROTOBUF_SUBMINOR_VERSION "${Protobuf_LIB_VERSION} % 1000")
set(Protobuf_VERSION
"${_PROTOBUF_MAJOR_VERSION}.${_PROTOBUF_MINOR_VERSION}.${_PROTOBUF_SUBMINOR_VERSION}")
endif()
unset(_PROTOBUF_COMMON_H_CONTENTS)
endif()
unset(_PROTOBUF_COMMON_HEADER)
endif()
if(NOT Protobuf_VERSION)
set(Protobuf_VERSION "0.0.0")
endif()
if(GNSSSDR_PROTOBUF_MODULE_MODE AND Protobuf_FOUND)
# FindProtobuf reports the C++ runtime version, while protobuf.pc uses the
# release version. For example, "7.34.2" maps to "34.2.0".
string(REGEX REPLACE "^[0-9]+[.]([0-9]+[.][0-9]+)$" "\\1.0"
PROTOBUF_LIBRARY_VERSION "${Protobuf_VERSION}")
if(NOT (PROTOBUF_LIBRARY_VERSION VERSION_LESS "22"))
if(CMAKE_VERSION VERSION_LESS 3.6)
pkg_check_modules(GNSSSDR_PROTOBUF_PC QUIET
protobuf=${PROTOBUF_LIBRARY_VERSION})
else()
pkg_check_modules(GNSSSDR_PROTOBUF_PC QUIET IMPORTED_TARGET
protobuf=${PROTOBUF_LIBRARY_VERSION})
endif()
if(NOT GNSSSDR_PROTOBUF_PC_FOUND)
message(FATAL_ERROR
"Protocol Buffers ${Protobuf_VERSION} was found through CMake's FindProtobuf module, "
"but matching pkg-config metadata for protobuf ${PROTOBUF_LIBRARY_VERSION} was not found. "
"Make protobuf-config.cmake discoverable or install the matching protobuf.pc file so "
"that Protobuf's Abseil and utf8_range dependencies can be linked correctly."
)
endif()
# protobuf.pc exposes the link dependencies, but some distributions do
# not publish the C++ standard used to build Abseil. Probe the installed
# headers and propagate the lowest standard that is actually accepted.
include(CheckCXXSourceCompiles)
set(_GNSSSDR_REQUIRED_FLAGS_SAVED "${CMAKE_REQUIRED_FLAGS}")
set(_GNSSSDR_REQUIRED_INCLUDES_SAVED "${CMAKE_REQUIRED_INCLUDES}")
string(REPLACE ";" " " _GNSSSDR_PROTOBUF_PC_CFLAGS
"${GNSSSDR_PROTOBUF_PC_CFLAGS_OTHER}")
set(CMAKE_REQUIRED_INCLUDES
"${Protobuf_INCLUDE_DIRS};${GNSSSDR_PROTOBUF_PC_INCLUDE_DIRS}")
set(_GNSSSDR_PROTOBUF_STANDARD_PROBE
"#include <google/protobuf/any.pb.h>\nint main() { return 0; }\n")
set(_GNSSSDR_PROTOBUF_MINIMUM_CXX_STANDARD 14)
if(NOT (PROTOBUF_LIBRARY_VERSION VERSION_LESS "30"))
set(_GNSSSDR_PROTOBUF_MINIMUM_CXX_STANDARD 17)
endif()
unset(GNSSSDR_PROTOBUF_REQUIRED_CXX_STANDARD)
foreach(_GNSSSDR_CXX_STANDARD 14 17 20)
if(NOT (_GNSSSDR_CXX_STANDARD VERSION_LESS
_GNSSSDR_PROTOBUF_MINIMUM_CXX_STANDARD))
if(MSVC)
if(_GNSSSDR_CXX_STANDARD VERSION_LESS "17")
set(_GNSSSDR_CXX_STANDARD_OPTION "")
else()
set(_GNSSSDR_CXX_STANDARD_OPTION
"/std:c++${_GNSSSDR_CXX_STANDARD}")
endif()
else()
set(_GNSSSDR_CXX_STANDARD_OPTION
"-std=c++${_GNSSSDR_CXX_STANDARD}")
endif()
set(CMAKE_REQUIRED_FLAGS
"${_GNSSSDR_REQUIRED_FLAGS_SAVED} ${_GNSSSDR_PROTOBUF_PC_CFLAGS} ${_GNSSSDR_CXX_STANDARD_OPTION}")
set(_GNSSSDR_PROTOBUF_STANDARD_TEST
"GNSSSDR_PROTOBUF_CXX${_GNSSSDR_CXX_STANDARD}_WORKS")
unset(${_GNSSSDR_PROTOBUF_STANDARD_TEST} CACHE)
check_cxx_source_compiles(
"${_GNSSSDR_PROTOBUF_STANDARD_PROBE}"
${_GNSSSDR_PROTOBUF_STANDARD_TEST})
if(${_GNSSSDR_PROTOBUF_STANDARD_TEST})
set(GNSSSDR_PROTOBUF_REQUIRED_CXX_STANDARD
${_GNSSSDR_CXX_STANDARD})
break()
endif()
endif()
endforeach()
set(CMAKE_REQUIRED_FLAGS "${_GNSSSDR_REQUIRED_FLAGS_SAVED}")
set(CMAKE_REQUIRED_INCLUDES "${_GNSSSDR_REQUIRED_INCLUDES_SAVED}")
if(NOT GNSSSDR_PROTOBUF_REQUIRED_CXX_STANDARD)
message(FATAL_ERROR
"Protocol Buffers ${Protobuf_VERSION} headers do not compile with any C++ standard "
"supported by GNSS-SDR (up to C++20). Install a compatible Protobuf and Abseil pair."
)
endif()
unset(_GNSSSDR_CXX_STANDARD)
unset(_GNSSSDR_CXX_STANDARD_OPTION)
unset(_GNSSSDR_PROTOBUF_MINIMUM_CXX_STANDARD)
unset(_GNSSSDR_PROTOBUF_PC_CFLAGS)
unset(_GNSSSDR_PROTOBUF_STANDARD_PROBE)
unset(_GNSSSDR_PROTOBUF_STANDARD_TEST)
unset(_GNSSSDR_REQUIRED_FLAGS_SAVED)
unset(_GNSSSDR_REQUIRED_INCLUDES_SAVED)
endif()
endif()
set_package_properties(Protobuf PROPERTIES
URL "https://protobuf.dev/"
PURPOSE "Used to serialize output data in a way that can be read by other applications."
TYPE REQUIRED
)
if(Protobuf_FOUND AND CMAKE_VERSION VERSION_LESS 3.9)
add_library(protobuf::libprotobuf SHARED IMPORTED)
set_target_properties(protobuf::libprotobuf PROPERTIES
IMPORTED_LINK_INTERFACE_LANGUAGES "CXX"
@@ -2367,23 +2460,9 @@ if(Protobuf_FOUND AND CMAKE_VERSION VERSION_LESS 3.9)
IMPORTED_LOCATION "${Protobuf_PROTOC_EXECUTABLE}"
INTERFACE_LINK_LIBRARIES "${Protobuf_PROTOC_LIBRARY}"
)
if(${Protobuf_VERSION} VERSION_EQUAL "0.0.0")
set(_PROTOBUF_COMMON_HEADER ${Protobuf_INCLUDE_DIR}/google/protobuf/stubs/common.h)
set(Protobuf_VERSION "")
set(Protobuf_LIB_VERSION "")
file(STRINGS ${_PROTOBUF_COMMON_HEADER} _PROTOBUF_COMMON_H_CONTENTS REGEX "#define[ \t]+GOOGLE_PROTOBUF_VERSION[ \t]+")
if(_PROTOBUF_COMMON_H_CONTENTS MATCHES "#define[ \t]+GOOGLE_PROTOBUF_VERSION[ \t]+([0-9]+)")
set(Protobuf_LIB_VERSION "${CMAKE_MATCH_1}")
endif()
unset(_PROTOBUF_COMMON_H_CONTENTS)
math(EXPR _PROTOBUF_MAJOR_VERSION "${Protobuf_LIB_VERSION} / 1000000")
math(EXPR _PROTOBUF_MINOR_VERSION "${Protobuf_LIB_VERSION} / 1000 % 1000")
math(EXPR _PROTOBUF_SUBMINOR_VERSION "${Protobuf_LIB_VERSION} % 1000")
set(Protobuf_VERSION "${_PROTOBUF_MAJOR_VERSION}.${_PROTOBUF_MINOR_VERSION}.${_PROTOBUF_SUBMINOR_VERSION}")
endif()
endif()
if(GNSSSDR_PROTOBUF_PC_FOUND)
if(GNSSSDR_PROTOBUF_MODULE_MODE AND GNSSSDR_PROTOBUF_PC_FOUND)
if(TARGET PkgConfig::GNSSSDR_PROTOBUF_PC)
target_link_libraries(protobuf::libprotobuf
INTERFACE PkgConfig::GNSSSDR_PROTOBUF_PC)
@@ -2396,6 +2475,33 @@ if(GNSSSDR_PROTOBUF_PC_FOUND)
set_property(TARGET protobuf::libprotobuf APPEND PROPERTY
INTERFACE_LINK_LIBRARIES "${GNSSSDR_PROTOBUF_PC_LDFLAGS}")
endif()
if(CMAKE_VERSION VERSION_LESS 3.1 OR
((GNSSSDR_PROTOBUF_REQUIRED_CXX_STANDARD VERSION_EQUAL 17) AND
CMAKE_VERSION VERSION_LESS 3.8) OR
((GNSSSDR_PROTOBUF_REQUIRED_CXX_STANDARD VERSION_EQUAL 20) AND
CMAKE_VERSION VERSION_LESS 3.12))
if(MSVC)
if(NOT GNSSSDR_PROTOBUF_REQUIRED_CXX_STANDARD VERSION_LESS "17")
set(_GNSSSDR_PROTOBUF_CXX_STANDARD_OPTION
"/std:c++${GNSSSDR_PROTOBUF_REQUIRED_CXX_STANDARD}")
endif()
else()
set(_GNSSSDR_PROTOBUF_CXX_STANDARD_OPTION
"-std=c++${GNSSSDR_PROTOBUF_REQUIRED_CXX_STANDARD}")
endif()
if(_GNSSSDR_PROTOBUF_CXX_STANDARD_OPTION)
add_compile_options(
"$<$<STREQUAL:$<TARGET_PROPERTY:LINKER_LANGUAGE>,CXX>:${_GNSSSDR_PROTOBUF_CXX_STANDARD_OPTION}>")
endif()
unset(_GNSSSDR_PROTOBUF_CXX_STANDARD_OPTION)
else()
set_property(TARGET protobuf::libprotobuf APPEND PROPERTY
INTERFACE_COMPILE_FEATURES
"cxx_std_${GNSSSDR_PROTOBUF_REQUIRED_CXX_STANDARD}")
endif()
message(STATUS
"Protobuf module fallback requires C++${GNSSSDR_PROTOBUF_REQUIRED_CXX_STANDARD}")
endif()
if(Protobuf_FOUND)