# ~~~ # Copyright 2019 Google LLC # # 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. # ~~~ #[=======================================================================[.rst: FindProtobufTargets ------------------- A module to use `Protobuf` with less complications. Using ``find_package(Protobuf)`` should be simple, but it is not. CMake provides a ``FindProtobuf`` module. Unfortunately it does not generate `protobuf::*` targets until CMake-3.9, and `protobuf::protoc` does not appear until CMake-3.10. The CMake-config files generated by `protobuf` always create these targets, but on some Linux distributions (e.g. Fedora>=29, and openSUSE-Tumbleweed) there are system packages for protobuf, but these packages are installed without the CMake-config files. One must either use the ``FindProtobuf`` module, find the libraries via `pkg-config`, or find the libraries manually. When the CMake-config files are installed they produce the same targets as recent versions of ``FindProtobuf``. However, they do not produce the `Protobuf_LIBRARY`, `Protobuf_INCLUDE_DIR`, etc. that are generated by the module. Furthermore, the `protobuf::protoc` library is not usable when loaded from the CMake-config files: its ``IMPORTED_LOCATION`` variable is not defined. This module is designed to provide a single, uniform, ``find_package()`` module that always produces the same outputs: - It always generates the ``protobuf::*`` targets. - It always defines ``ProtobufTargets_FOUND`` and ``ProtobufTargets_VERSION``. - It *prefers* using the CMake config files if they are available. - It fallsback on the ``FindProtobuf`` module if the config files are not found. - It populates any missing targets and their properties. The following :prop_tgt:`IMPORTED` targets are defined: ``protobuf::libprotobuf`` The protobuf library. ``protobuf::libprotobuf-lite`` The protobuf lite library. ``protobuf::libprotoc`` The protoc library. ``protobuf::protoc`` The protoc compiler. Example: .. code-block:: cmake find_package(ProtobufTargets REQUIRED) add_executable(bar bar.cc) target_link_libraries(bar PRIVATE protobuf::libprotobuf) #]=======================================================================] if (protobuf_DEBUG) message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "protobuf_USE_STATIC_LIBS = ${protobuf_USE_STATIC_LIBS}" " ProtobufTargets = ${ProtobufTargets_FOUND}") endif () # Always load thread support, even on Windows. find_package(Threads REQUIRED) # First try to use the ``protobufConfig.cmake`` or ``protobuf-config.cmake`` # file if it was installed. This is common on systems (or package managers) # where protobuf was compiled and installed with `CMake`. Note that on Linux # this *must* be all lowercase ``protobuf``, while on Windows it does not # matter. find_package(protobuf CONFIG) if (protobuf_DEBUG) message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "protobuf_FOUND = ${protobuf_FOUND}" " protobuf_VERSION = ${protobuf_VERSION}") endif () if (protobuf_FOUND) set(ProtobufTargets_FOUND 1) set(ProtobufTargets_VERSION ${protobuf_VERSION}) if (protobuf_DEBUG) message( STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "ProtobufTargets_FOUND = ${ProtobufTargets_FOUND}" " ProtobufTargets_VERSION = ${ProtobufTargets_VERSION}") endif () else () find_package(Protobuf QUIET) if (Protobuf_FOUND) set(ProtobufTargets_FOUND 1) set(ProtobufTargets_VERSION ${Protobuf_VERSION}) if (NOT TARGET protobuf::libprotobuf) add_library(protobuf::libprotobuf IMPORTED INTERFACE) set_property( TARGET protobuf::libprotobuf PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${Protobuf_INCLUDE_DIR}) set_property( TARGET protobuf::libprotobuf APPEND PROPERTY INTERFACE_LINK_LIBRARIES ${Protobuf_LIBRARY} Threads::Threads) endif () if (NOT TARGET protobuf::libprotobuf-lite) add_library(protobuf::libprotobuf-lite IMPORTED INTERFACE) set_property( TARGET protobuf::libprotobuf-lite PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${Protobuf_INCLUDE_DIR}) set_property( TARGET protobuf::libprotobuf-lite APPEND PROPERTY INTERFACE_LINK_LIBRARIES ${Protobuf_LITE_LIBRARY} Threads::Threads) endif () if (NOT TARGET protobuf::libprotoc) add_library(protobuf::libprotoc IMPORTED INTERFACE) set_property( TARGET protobuf::libprotoc PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${Protobuf_INCLUDE_DIR}) set_property( TARGET protobuf::libprotoc APPEND PROPERTY INTERFACE_LINK_LIBRARIES ${Protobuf_PROTOC_LIBRARY} Threads::Threads) endif () endif () endif () if (protobuf_DEBUG) message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "ProtobufTargets_FOUND = ${ProtobufTargets_FOUND}" " ProtobufTargets_VERSION = ${ProtobufTargets_VERSION}") endif () # We also should try to find the protobuf C++ plugin for the protocol buffers # compiler. if (ProtobufTargets_FOUND AND NOT TARGET protobuf::protoc) add_executable(protobuf::protoc IMPORTED) # Discover the protoc compiler location. find_program( _protobuf_PROTOC_EXECUTABLE NAMES protoc DOC "The Google Protocol Buffers Compiler") if (protobuf_DEBUG) message( STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "ProtobufTargets_FOUND = ${ProtobufTargets_FOUND}" " ProtobufTargets_VERSION = ${ProtobufTargets_VERSION}" " EXE = ${_protobuf_PROTOC_EXECUTABLE}") endif () set_property(TARGET protobuf::protoc PROPERTY IMPORTED_LOCATION ${_protobuf_PROTOC_EXECUTABLE}) set_property( TARGET protobuf::protoc PROPERTY IMPORTED_LOCATION_DEBUG ${_protobuf_PROTOC_EXECUTABLE}) set_property( TARGET protobuf::protoc PROPERTY IMPORTED_LOCATION_RELEASE ${_protobuf_PROTOC_EXECUTABLE}) unset(_protobuf_PROTOC_EXECUTABLE) if (protobuf_DEBUG) get_target_property(_protobuf_PROTOC_EXECUTABLE protobuf::protoc IMPORTED_LOCATION) message( STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "LOCATION=${_protobuf_PROTOC_EXECUTABLE}") endif () endif () if (protobuf_DEBUG) message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "ProtobufTargets_FOUND = ${ProtobufTargets_FOUND}" " ProtobufTargets_VERSION = ${ProtobufTargets_VERSION}") if (ProtobufTargets_FOUND) foreach (_target protobuf::libprotobuf protobuf::libprotobuf-lite protobuf::libprotoc) if (NOT TARGET ${_target}) message( STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "target=${_target} is NOT a target") endif () endforeach () unset(_target) endif () endif () find_package_handle_standard_args(ProtobufTargets REQUIRED_VARS ProtobufTargets_FOUND ProtobufTargets_VERSION)