From: Antonio Perez Barrero <apbarr...@gmail.com> Check found libraries version to match user required version, including EXACT match.
Protobuf compiler executable version is check to be aligned with found libraries, raising a warning message otherwise. Module interface and private variables are renamed to honour recommendation to be aligned in case with module name. --- Modules/FindProtobuf.cmake | 205 ++++++++++++++++++++++++++++++++------------- 1 file changed, 149 insertions(+), 56 deletions(-) diff --git a/Modules/FindProtobuf.cmake b/Modules/FindProtobuf.cmake index 2f13b09..34cd660 100644 --- a/Modules/FindProtobuf.cmake +++ b/Modules/FindProtobuf.cmake @@ -6,47 +6,49 @@ # # The following variables can be set and are optional: # -# ``PROTOBUF_SRC_ROOT_FOLDER`` +# ``Protobuf_SRC_ROOT_FOLDER`` # When compiling with MSVC, if this cache variable is set # the protobuf-default VS project build locations # (vsprojects/Debug and vsprojects/Release # or vsprojects/x64/Debug and vsprojects/x64/Release) # will be searched for libraries and binaries. -# ``PROTOBUF_IMPORT_DIRS`` +# ``Protobuf_IMPORT_DIRS`` # List of additional directories to be searched for # imported .proto files. +# ``Protobuf_DEBUG`` +# Show debug messages. # # Defines the following variables: # -# ``PROTOBUF_FOUND`` +# ``Protobuf_FOUND`` # Found the Google Protocol Buffers library # (libprotobuf & header files) -# ``PROTOBUF_INCLUDE_DIRS`` +# ``Protobuf_INCLUDE_DIRS`` # Include directories for Google Protocol Buffers -# ``PROTOBUF_LIBRARIES`` +# ``Protobuf_LIBRARIES`` # The protobuf libraries -# ``PROTOBUF_PROTOC_LIBRARIES`` +# ``Protobuf_PROTOC_LIBRARIES`` # The protoc libraries -# ``PROTOBUF_LITE_LIBRARIES`` +# ``Protobuf_LITE_LIBRARIES`` # The protobuf-lite libraries # # The following cache variables are also available to set or use: # -# ``PROTOBUF_LIBRARY`` +# ``Protobuf_LIBRARY`` # The protobuf library -# ``PROTOBUF_PROTOC_LIBRARY`` +# ``Protobuf_PROTOC_LIBRARY`` # The protoc library -# ``PROTOBUF_INCLUDE_DIR`` +# ``Protobuf_INCLUDE_DIR`` # The include directory for protocol buffers -# ``PROTOBUF_PROTOC_EXECUTABLE`` +# ``Protobuf_PROTOC_EXECUTABLE`` # The protoc compiler -# ``PROTOBUF_LIBRARY_DEBUG`` +# ``Protobuf_LIBRARY_DEBUG`` # The protobuf library (debug) -# ``PROTOBUF_PROTOC_LIBRARY_DEBUG`` +# ``Protobuf_PROTOC_LIBRARY_DEBUG`` # The protoc library (debug) -# ``PROTOBUF_LITE_LIBRARY`` +# ``Protobuf_LITE_LIBRARY`` # The protobuf lite library -# ``PROTOBUF_LITE_LIBRARY_DEBUG`` +# ``Protobuf_LITE_LIBRARY_DEBUG`` # The protobuf lite library (debug) # # Example: @@ -54,12 +56,12 @@ # .. code-block:: cmake # # find_package(Protobuf REQUIRED) -# include_directories(${PROTOBUF_INCLUDE_DIRS}) +# include_directories(${Protobuf_INCLUDE_DIRS}) # include_directories(${CMAKE_CURRENT_BINARY_DIR}) # protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS foo.proto) # protobuf_generate_python(PROTO_PY foo.proto) # add_executable(bar bar.cc ${PROTO_SRCS} ${PROTO_HDRS}) -# target_link_libraries(bar ${PROTOBUF_LIBRARIES}) +# target_link_libraries(bar ${Protobuf_LIBRARIES}) # # .. note:: # The ``protobuf_generate_cpp`` and ``protobuf_generate_python`` @@ -105,13 +107,13 @@ # (To distribute this file outside of CMake, substitute the full # License text for the above reference.) -function(PROTOBUF_GENERATE_CPP SRCS HDRS) +function(Protobuf_GENERATE_CPP SRCS HDRS) if(NOT ARGN) - message(SEND_ERROR "Error: PROTOBUF_GENERATE_CPP() called without any proto files") + message(SEND_ERROR "Error: Protobuf_GENERATE_CPP() called without any proto files") return() endif() - if(PROTOBUF_GENERATE_CPP_APPEND_PATH) + if(Protobuf_GENERATE_CPP_APPEND_PATH) # Create an include path for each file specified foreach(FIL ${ARGN}) get_filename_component(ABS_FIL ${FIL} ABSOLUTE) @@ -125,8 +127,8 @@ function(PROTOBUF_GENERATE_CPP SRCS HDRS) set(_protobuf_include_path -I ${CMAKE_CURRENT_SOURCE_DIR}) endif() - if(DEFINED PROTOBUF_IMPORT_DIRS) - foreach(DIR ${PROTOBUF_IMPORT_DIRS}) + if(DEFINED Protobuf_IMPORT_DIRS) + foreach(DIR ${Protobuf_IMPORT_DIRS}) get_filename_component(ABS_PATH ${DIR} ABSOLUTE) list(FIND _protobuf_include_path ${ABS_PATH} _contains_already) if(${_contains_already} EQUAL -1) @@ -147,9 +149,9 @@ function(PROTOBUF_GENERATE_CPP SRCS HDRS) add_custom_command( OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.pb.cc" "${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.pb.h" - COMMAND ${PROTOBUF_PROTOC_EXECUTABLE} + COMMAND ${Protobuf_PROTOC_EXECUTABLE} ARGS --cpp_out ${CMAKE_CURRENT_BINARY_DIR} ${_protobuf_include_path} ${ABS_FIL} - DEPENDS ${ABS_FIL} ${PROTOBUF_PROTOC_EXECUTABLE} + DEPENDS ${ABS_FIL} ${Protobuf_PROTOC_EXECUTABLE} COMMENT "Running C++ protocol buffer compiler on ${FIL}" VERBATIM ) endforeach() @@ -159,13 +161,13 @@ function(PROTOBUF_GENERATE_CPP SRCS HDRS) set(${HDRS} ${${HDRS}} PARENT_SCOPE) endfunction() -function(PROTOBUF_GENERATE_PYTHON SRCS) +function(Protobuf_GENERATE_PYTHON SRCS) if(NOT ARGN) - message(SEND_ERROR "Error: PROTOBUF_GENERATE_PYTHON() called without any proto files") + message(SEND_ERROR "Error: Protobuf_GENERATE_PYTHON() called without any proto files") return() endif() - if(PROTOBUF_GENERATE_CPP_APPEND_PATH) + if(Protobuf_GENERATE_CPP_APPEND_PATH) # Create an include path for each file specified foreach(FIL ${ARGN}) get_filename_component(ABS_FIL ${FIL} ABSOLUTE) @@ -179,8 +181,8 @@ function(PROTOBUF_GENERATE_PYTHON SRCS) set(_protobuf_include_path -I ${CMAKE_CURRENT_SOURCE_DIR}) endif() - if(DEFINED PROTOBUF_IMPORT_DIRS) - foreach(DIR ${PROTOBUF_IMPORT_DIRS}) + if(DEFINED Protobuf_IMPORT_DIRS) + foreach(DIR ${Protobuf_IMPORT_DIRS}) get_filename_component(ABS_PATH ${DIR} ABSOLUTE) list(FIND _protobuf_include_path ${ABS_PATH} _contains_already) if(${_contains_already} EQUAL -1) @@ -197,8 +199,8 @@ function(PROTOBUF_GENERATE_PYTHON SRCS) list(APPEND ${SRCS} "${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}_pb2.py") add_custom_command( OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}_pb2.py" - COMMAND ${PROTOBUF_PROTOC_EXECUTABLE} --python_out ${CMAKE_CURRENT_BINARY_DIR} ${_protobuf_include_path} ${ABS_FIL} - DEPENDS ${ABS_FIL} ${PROTOBUF_PROTOC_EXECUTABLE} + COMMAND ${Protobuf_PROTOC_EXECUTABLE} --python_out ${CMAKE_CURRENT_BINARY_DIR} ${_protobuf_include_path} ${ABS_FIL} + DEPENDS ${ABS_FIL} ${Protobuf_PROTOC_EXECUTABLE} COMMENT "Running Python protocol buffer compiler on ${FIL}" VERBATIM ) endforeach() @@ -207,7 +209,7 @@ function(PROTOBUF_GENERATE_PYTHON SRCS) endfunction() if(CMAKE_SIZEOF_VOID_P EQUAL 8) - set(_PROTOBUF_ARCH_DIR x64/) + set(_Protobuf_ARCH_DIR x64/) endif() # Internal function: search for normal library as well as a debug one @@ -216,12 +218,12 @@ endif() function(_protobuf_find_libraries name filename) find_library(${name}_LIBRARY NAMES ${filename} - PATHS ${PROTOBUF_SRC_ROOT_FOLDER}/vsprojects/${_PROTOBUF_ARCH_DIR}Release) + PATHS ${Protobuf_SRC_ROOT_FOLDER}/vsprojects/${_Protobuf_ARCH_DIR}Release) mark_as_advanced(${name}_LIBRARY) find_library(${name}_LIBRARY_DEBUG NAMES ${filename} - PATHS ${PROTOBUF_SRC_ROOT_FOLDER}/vsprojects/${_PROTOBUF_ARCH_DIR}Debug) + PATHS ${Protobuf_SRC_ROOT_FOLDER}/vsprojects/${_Protobuf_ARCH_DIR}Debug) mark_as_advanced(${name}_LIBRARY_DEBUG) if(NOT ${name}_LIBRARY_DEBUG) @@ -243,8 +245,8 @@ function(_protobuf_find_threads) set(CMAKE_THREAD_PREFER_PTHREAD TRUE) find_package(Threads) if(Threads_FOUND) - list(APPEND PROTOBUF_LIBRARIES ${CMAKE_THREAD_LIBS_INIT}) - set(PROTOBUF_LIBRARIES "${PROTOBUF_LIBRARIES}" PARENT_SCOPE) + list(APPEND Protobuf_LIBRARIES ${CMAKE_THREAD_LIBS_INIT}) + set(Protobuf_LIBRARIES "${Protobuf_LIBRARIES}" PARENT_SCOPE) endif() endfunction() @@ -252,34 +254,34 @@ endfunction() # Main. # -# By default have PROTOBUF_GENERATE_CPP macro pass -I to protoc +# By default have Protobuf_GENERATE_CPP macro pass -I to protoc # for each directory where a proto file is referenced. -if(NOT DEFINED PROTOBUF_GENERATE_CPP_APPEND_PATH) - set(PROTOBUF_GENERATE_CPP_APPEND_PATH TRUE) +if(NOT DEFINED Protobuf_GENERATE_CPP_APPEND_PATH) + set(Protobuf_GENERATE_CPP_APPEND_PATH TRUE) endif() # Google's provided vcproj files generate libraries with a "lib" # prefix on Windows if(MSVC) - set(PROTOBUF_ORIG_FIND_LIBRARY_PREFIXES "${CMAKE_FIND_LIBRARY_PREFIXES}") + set(Protobuf_ORIG_FIND_LIBRARY_PREFIXES "${CMAKE_FIND_LIBRARY_PREFIXES}") set(CMAKE_FIND_LIBRARY_PREFIXES "lib" "") - find_path(PROTOBUF_SRC_ROOT_FOLDER protobuf.pc.in) + find_path(Protobuf_SRC_ROOT_FOLDER protobuf.pc.in) endif() # The Protobuf library -_protobuf_find_libraries(PROTOBUF protobuf) +_protobuf_find_libraries(Protobuf protobuf) #DOC "The Google Protocol Buffers RELEASE Library" -_protobuf_find_libraries(PROTOBUF_LITE protobuf-lite) +_protobuf_find_libraries(Protobuf_LITE protobuf-lite) # The Protobuf Protoc Library -_protobuf_find_libraries(PROTOBUF_PROTOC protoc) +_protobuf_find_libraries(Protobuf_PROTOC protoc) # Restore original find library prefixes if(MSVC) - set(CMAKE_FIND_LIBRARY_PREFIXES "${PROTOBUF_ORIG_FIND_LIBRARY_PREFIXES}") + set(CMAKE_FIND_LIBRARY_PREFIXES "${Protobuf_ORIG_FIND_LIBRARY_PREFIXES}") endif() if(UNIX) @@ -287,27 +289,118 @@ if(UNIX) endif() # Find the include directory -find_path(PROTOBUF_INCLUDE_DIR +find_path(Protobuf_INCLUDE_DIR google/protobuf/service.h - PATHS ${PROTOBUF_SRC_ROOT_FOLDER}/src + PATHS ${Protobuf_SRC_ROOT_FOLDER}/src ) -mark_as_advanced(PROTOBUF_INCLUDE_DIR) +mark_as_advanced(Protobuf_INCLUDE_DIR) # Find the protoc Executable -find_program(PROTOBUF_PROTOC_EXECUTABLE +find_program(Protobuf_PROTOC_EXECUTABLE NAMES protoc DOC "The Google Protocol Buffers Compiler" PATHS - ${PROTOBUF_SRC_ROOT_FOLDER}/vsprojects/${_PROTOBUF_ARCH_DIR}Release - ${PROTOBUF_SRC_ROOT_FOLDER}/vsprojects/${_PROTOBUF_ARCH_DIR}Debug + ${Protobuf_SRC_ROOT_FOLDER}/vsprojects/${_Protobuf_ARCH_DIR}Release + ${Protobuf_SRC_ROOT_FOLDER}/vsprojects/${_Protobuf_ARCH_DIR}Debug ) -mark_as_advanced(PROTOBUF_PROTOC_EXECUTABLE) +mark_as_advanced(Protobuf_PROTOC_EXECUTABLE) +if(Protobuf_DEBUG) + message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " + "requested version of Google Protobuf is ${Protobuf_FIND_VERSION}") +endif() + +if(Protobuf_INCLUDE_DIR) + set(_Protobuf_COMMON_HEADER ${Protobuf_INCLUDE_DIR}/google/protobuf/stubs/common.h) + + if(Protobuf_DEBUG) + message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " + "location of common.h: ${Protobuf_INCLUDE_DIR}/google/protobuf/stubs/common.h") + endif() + + set(Protobuf_VERSION 0) + set(Protobuf_LIB_VERSION "") + file(STRINGS ${_Protobuf_COMMON_HEADER} _Protobuf_COMMON_H_CONTENTS REGEX "#define GOOGLE_PROTOBUF_VERSION ") + set(_Protobuf_VERSION_REGEX "([0-9]+)") + if("${_Protobuf_COMMON_H_CONTENTS}" MATCHES "#define GOOGLE_PROTOBUF_VERSION ${_Protobuf_VERSION_REGEX}") + set(Protobuf_VERSION "${CMAKE_MATCH_1}") + endif() + unset(_Protobuf_COMMON_H_CONTENTS) + + math(EXPR Protobuf_MAJOR_VERSION "${Protobuf_VERSION} / 1000000") + math(EXPR Protobuf_MINOR_VERSION "${Protobuf_VERSION} / 1000 % 1000") + math(EXPR Protobuf_SUBMINOR_VERSION "${Protobuf_VERSION} % 1000") + + set(Protobuf_ERROR_REASON + "${Protobuf_ERROR_REASON}Google Protobuf version: ${Protobuf_MAJOR_VERSION}.${Protobuf_MINOR_VERSION}.${Protobuf_SUBMINOR_VERSION}\nGoogle Protobuf include path: ${Protobuf_INCLUDE_DIR}") + if(Protobuf_DEBUG) + message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " + "${_Protobuf_COMMON_HEADER} reveals protobuf " + "${Protobuf_MAJOR_VERSION}.${Protobuf_MINOR_VERSION}.${Protobuf_SUBMINOR_VERSION}") + endif() + + if(Protobuf_FIND_VERSION) + # Set Protobuf_FOUND based on requested version. + set(_Protobuf_VERSION "${Protobuf_MAJOR_VERSION}.${Protobuf_MINOR_VERSION}.${Protobuf_SUBMINOR_VERSION}") + if("${_Protobuf_VERSION}" VERSION_LESS "${Protobuf_FIND_VERSION}") + set(Protobuf_FOUND 0) + set(_Protobuf_VERSION_AGE "old") + elseif(Protobuf_FIND_VERSION_EXACT AND + NOT "${_Protobuf_VERSION}" VERSION_EQUAL "${Protobuf_FIND_VERSION}") + set(Protobuf_FOUND 0) + set(_Protobuf_VERSION_AGE "new") + else() + set(Protobuf_FOUND 1) + endif() + if(NOT Protobuf_FOUND) + # State that we found a version of Protobuf that is too new or too old. + set(Protobuf_ERROR_REASON + "${Protobuf_ERROR_REASON}\nDetected version of Google Protobuf is too ${_Protobuf_VERSION_AGE}. Requested version was ${Protobuf_FIND_VERSION_MAJOR}.${Protobuf_FIND_VERSION_MINOR}") + if (Protobuf_FIND_VERSION_PATCH) + set(Protobuf_ERROR_REASON + "${Protobuf_ERROR_REASON}.${Protobuf_FIND_VERSION_PATCH}") + endif () + if (NOT Protobuf_FIND_VERSION_EXACT) + set(Protobuf_ERROR_REASON "${Protobuf_ERROR_REASON} (or newer)") + endif () + set(Protobuf_ERROR_REASON "${Protobuf_ERROR_REASON}.") + endif () + else() + # Caller will accept any Protobuf version. + set(Protobuf_FOUND 1) + endif() + + if(NOT Protobuf_FOUND AND Protobuf_FIND_REQUIRED) + message(FATAL_ERROR "${Protobuf_ERROR_REASON}") + endif() + + # Check Protobuf compiler version to be aligned with libraries version + execute_process(COMMAND ${Protobuf_PROTOC_EXECUTABLE} --version + OUTPUT_VARIABLE _Protobuf_PROTOC_EXECUTABLE_VERSION) + + if("${_Protobuf_PROTOC_EXECUTABLE_VERSION}" MATCHES "libprotoc ([0-9\.]+)") + set(_Protobuf_PROTOC_EXECUTABLE_VERSION "${CMAKE_MATCH_1}") + endif() + + if(Protobuf_DEBUG) + message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " + "${Protobuf_PROTOC_EXECUTABLE} reveals version ${_Protobuf_PROTOC_EXECUTABLE_VERSION}") + endif() + + if(NOT "${_Protobuf_PROTOC_EXECUTABLE_VERSION}" VERSION_EQUAL "${_Protobuf_VERSION}") + message(WARNING "Protobuf compiler version ${_Protobuf_PROTOC_EXECUTABLE_VERSION}" + " doesn't match library version ${_Protobuf_VERSION}") + endif() +else() + set(Protobuf_FOUND 0) + set(Protobuf_ERROR_REASON + "${Protobuf_ERROR_REASON}Unable to find the Google Protobuf header files.") +endif() -include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake) +include(FindPackageHandleStandardArgs) FIND_PACKAGE_HANDLE_STANDARD_ARGS(Protobuf DEFAULT_MSG - PROTOBUF_LIBRARY PROTOBUF_INCLUDE_DIR) + Protobuf_LIBRARY Protobuf_INCLUDE_DIR) -if(PROTOBUF_FOUND) - set(PROTOBUF_INCLUDE_DIRS ${PROTOBUF_INCLUDE_DIR}) +if(Protobuf_FOUND) + set(Protobuf_INCLUDE_DIRS ${Protobuf_INCLUDE_DIR}) endif() -- 1.9.1 -- Powered by www.kitware.com Please keep messages on-topic and check the CMake FAQ at: http://www.cmake.org/Wiki/CMake_FAQ Kitware offers various services to support the CMake community. For more information on each offering, please visit: CMake Support: http://cmake.org/cmake/help/support.html CMake Consulting: http://cmake.org/cmake/help/consulting.html CMake Training Courses: http://cmake.org/cmake/help/training.html Visit other Kitware open-source projects at http://www.kitware.com/opensource/opensource.html Follow this link to subscribe/unsubscribe: http://public.kitware.com/mailman/listinfo/cmake-developers