diff options
author | Carlos O'Ryan <coryan@google.com> | 2019-06-28T19·01-0400 |
---|---|---|
committer | Carlos O'Ryan <coryan@google.com> | 2019-06-28T19·01-0400 |
commit | eab5cb57dd38531023b1e7e7a529882c268d1333 (patch) | |
tree | 7af1d8825cd97697e911c1d576aaff7b1ca1bb32 /cmake |
Initial set of files.
The make install target is not working for .proto files, but otherwise it seems to work.
Diffstat (limited to 'cmake')
-rw-r--r-- | cmake/CompileProtos.cmake | 286 | ||||
-rw-r--r-- | cmake/FindProtobufTargets.cmake | 207 | ||||
-rw-r--r-- | cmake/FindgRPC.cmake | 343 | ||||
-rw-r--r-- | cmake/SelectMSVCRuntime.cmake | 46 | ||||
-rw-r--r-- | cmake/config-version.cmake.in | 35 | ||||
-rw-r--r-- | cmake/config.cmake.in | 36 | ||||
-rw-r--r-- | cmake/config.pc.in | 26 |
7 files changed, 979 insertions, 0 deletions
diff --git a/cmake/CompileProtos.cmake b/cmake/CompileProtos.cmake new file mode 100644 index 000000000000..a01a90b825e8 --- /dev/null +++ b/cmake/CompileProtos.cmake @@ -0,0 +1,286 @@ +# ~~~ +# 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. +# ~~~ + +# Introduce a new TARGET property to associate proto files with a target. +# +# We use a function to define the property so it can be called multiple times +# without introducing the property over and over. +function (google_cloud_cpp_add_protos_property) + set_property(TARGET + PROPERTY PROTO_SOURCES + BRIEF_DOCS + "The list of .proto files for a target." + FULL_DOCS + "List of .proto files specified for a target.") +endfunction () + +# Generate C++ for .proto files preserving the directory hierarchy +# +# Receives a list of `.proto` file names and (a) creates the runs to convert +# these files to `.pb.h` and `.pb.cc` output files, (b) returns the list of +# `.pb.cc` files and `.pb.h` files in @p HDRS, and (c) creates the list of files +# preserving the directory hierarchy, such that if a `.proto` file says: +# +# import "foo/bar/baz.proto" +# +# the resulting C++ code says: +# +# #include <foo/bar/baz.pb.h> +# +# Use the `PROTO_PATH` option to provide one or more directories to search for +# proto files in the import. +# +# @par Example +# +# google_cloud_cpp_generate_proto( MY_PB_FILES "foo/bar/baz.proto" +# "foo/bar/qux.proto" PROTO_PATH_DIRECTORIES "another/dir/with/protos") +# +# Note that `protoc` the protocol buffer compiler requires your protos to be +# somewhere in the search path defined by the `--proto_path` (aka -I) options. +# For example, if you want to generate the `.pb.{h,cc}` files for +# `foo/bar/baz.proto` then the directory containing `foo` must be in the search +# path. +function (google_cloud_cpp_generate_proto SRCS) + cmake_parse_arguments(_opt "" "" "PROTO_PATH_DIRECTORIES" ${ARGN}) + if (NOT _opt_UNPARSED_ARGUMENTS) + message(SEND_ERROR "Error: google_cloud_cpp_generate_proto() called" + " without any proto files") + return() + endif () + + # Build the list of `--proto_path` options. Use the absolute path for each + # option given, and do not include any path more than once. + set(protobuf_include_path) + foreach (dir ${_opt_PROTO_PATH_DIRECTORIES}) + get_filename_component(absolute_path ${dir} ABSOLUTE) + list(FIND protobuf_include_path "${absolute_path}" + already_in_search_path) + if (${already_in_search_path} EQUAL -1) + list(APPEND protobuf_include_path "--proto_path" "${absolute_path}") + endif () + endforeach () + + set(${SRCS}) + foreach (filename ${_opt_UNPARSED_ARGUMENTS}) + get_filename_component(file_directory "${filename}" DIRECTORY) + # This gets the filename without the extension, analogous to $(basename + # "${filename}" .proto) + get_filename_component(file_stem "${filename}" NAME_WE) + + # Strip all the prefixes in ${_opt_PROTO_PATH_DIRECTORIES} from the + # source proto directory + set(D "${file_directory}") + if (DEFINED _opt_PROTO_PATH_DIRECTORIES) + foreach (P ${_opt_PROTO_PATH_DIRECTORIES}) + string(REGEX + REPLACE "^${P}" + "" + T + "${D}") + set(D ${T}) + endforeach () + endif () + set(pb_cc "${CMAKE_CURRENT_BINARY_DIR}/${D}/${file_stem}.pb.cc") + set(pb_h "${CMAKE_CURRENT_BINARY_DIR}/${D}/${file_stem}.pb.h") + list(APPEND ${SRCS} "${pb_cc}" "${pb_h}") + add_custom_command( + OUTPUT "${pb_cc}" "${pb_h}" + COMMAND $<TARGET_FILE:protobuf::protoc> + ARGS + --cpp_out "${CMAKE_CURRENT_BINARY_DIR}" + ${protobuf_include_path} "${filename}" + DEPENDS "${filename}" protobuf::protoc + COMMENT "Running C++ protocol buffer compiler on ${filename}" + VERBATIM) + endforeach () + + set_source_files_properties(${${SRCS}} PROPERTIES GENERATED TRUE) + set(${SRCS} ${${SRCS}} PARENT_SCOPE) +endfunction () + +# Generate gRPC C++ files from .proto files preserving the directory hierarchy. +# +# Receives a list of `.proto` file names and (a) creates the runs to convert +# these files to `.grpc.pb.h` and `.grpc.pb.cc` output files, (b) returns the +# list of `.grpc.pb.cc` and `.pb.h` files in @p SRCS, and (c) creates the list +# of files preserving the directory hierarchy, such that if a `.proto` file says +# +# import "foo/bar/baz.proto" +# +# the resulting C++ code says: +# +# #include <foo/bar/baz.pb.h> +# +# Use the `PROTO_PATH` option to provide one or more directories to search for +# proto files in the import. +# +# @par Example +# +# google_cloud_cpp_generate_grpc( MY_GRPC_PB_FILES "foo/bar/baz.proto" +# "foo/bar/qux.proto" PROTO_PATH_DIRECTORIES "another/dir/with/protos") +# +# Note that `protoc` the protocol buffer compiler requires your protos to be +# somewhere in the search path defined by the `--proto_path` (aka -I) options. +# For example, if you want to generate the `.pb.{h,cc}` files for +# `foo/bar/baz.proto` then the directory containing `foo` must be in the search +# path. +function (google_cloud_cpp_generate_grpcpp SRCS) + cmake_parse_arguments(_opt "" "" "PROTO_PATH_DIRECTORIES" ${ARGN}) + if (NOT _opt_UNPARSED_ARGUMENTS) + message( + SEND_ERROR "Error: google_cloud_cpp_generate_grpc() called without" + " any proto files") + return() + endif () + + # Build the list of `--proto_path` options. Use the absolute path for each + # option given, and do not include any path more than once. + set(protobuf_include_path) + foreach (dir ${_opt_PROTO_PATH_DIRECTORIES}) + get_filename_component(absolute_path ${dir} ABSOLUTE) + list(FIND protobuf_include_path "${absolute_path}" + already_in_search_path) + if (${already_in_search_path} EQUAL -1) + list(APPEND protobuf_include_path "--proto_path" "${absolute_path}") + endif () + endforeach () + + set(${SRCS}) + foreach (filename ${_opt_UNPARSED_ARGUMENTS}) + get_filename_component(file_directory "${filename}" DIRECTORY) + # This gets the filename without the extension, analogous to $(basename + # "${filename}" .proto) + get_filename_component(file_stem "${filename}" NAME_WE) + + # Strip all the prefixes in ${_opt_PROTO_PATH_DIRECTORIES} from the + # source proto directory + set(D "${file_directory}") + if (DEFINED _opt_PROTO_PATH_DIRECTORIES) + foreach (P ${_opt_PROTO_PATH_DIRECTORIES}) + string(REGEX + REPLACE "^${P}" + "" + T + "${D}") + set(D ${T}) + endforeach () + endif () + set(grpc_pb_cc + "${CMAKE_CURRENT_BINARY_DIR}/${D}/${file_stem}.grpc.pb.cc") + set(grpc_pb_h "${CMAKE_CURRENT_BINARY_DIR}/${D}/${file_stem}.grpc.pb.h") + list(APPEND ${SRCS} "${grpc_pb_cc}" "${grpc_pb_h}") + add_custom_command( + OUTPUT "${grpc_pb_cc}" "${grpc_pb_h}" + COMMAND + $<TARGET_FILE:protobuf::protoc> + ARGS + --plugin=protoc-gen-grpc=$<TARGET_FILE:gRPC::grpc_cpp_plugin> + "--grpc_out=${CMAKE_CURRENT_BINARY_DIR}" + "--cpp_out=${CMAKE_CURRENT_BINARY_DIR}" + ${protobuf_include_path} "${filename}" + DEPENDS "${filename}" protobuf::protoc gRPC::grpc_cpp_plugin + COMMENT "Running gRPC C++ protocol buffer compiler on ${filename}" + VERBATIM) + endforeach () + + set_source_files_properties(${${SRCS}} PROPERTIES GENERATED TRUE) + set(${SRCS} ${${SRCS}} PARENT_SCOPE) +endfunction () + +include(GNUInstallDirs) + +# Install headers for a C++ proto library. +function (google_cloud_cpp_install_proto_library_headers target) + get_target_property(target_sources ${target} SOURCES) + foreach (header ${target_sources}) + # Skip anything that is not a header file. + if (NOT "${header}" MATCHES "\\.h$") + continue() + endif () + string(REPLACE "${CMAKE_CURRENT_BINARY_DIR}/" + "" + relative + "${header}") + get_filename_component(dir "${relative}" DIRECTORY) + install(FILES "${header}" DESTINATION + "${CMAKE_INSTALL_INCLUDEDIR}/${dir}") + endforeach () +endfunction () + +# Install protos for a C++ proto library. +function (google_cloud_cpp_install_proto_library_protos target) + get_target_property(target_protos ${target} PROTO_SOURCES) + foreach (header ${target_protos}) + # Skip anything that is not a header file. + if (NOT "${header}" MATCHES "\\.proto$") + continue() + endif () + string(REPLACE "${CMAKE_CURRENT_BINARY_DIR}/" + "" + relative + "${header}") + get_filename_component(dir "${relative}" DIRECTORY) + # This is modeled after the Protobuf library, it installs the basic + # protos (think google/protobuf/any.proto) in the include directory for + # C/C++ code. :shrug: + install(FILES "${header}" DESTINATION + "${CMAKE_INSTALL_INCLUDEDIR}/${dir}") + endforeach () +endfunction () + +function (google_cloud_cpp_proto_library libname) + cmake_parse_arguments(_opt "" "" "PROTO_PATH_DIRECTORIES" ${ARGN}) + if (NOT _opt_UNPARSED_ARGUMENTS) + message(SEND_ERROR "Error: google_cloud_cpp_proto_library() called" + " without any proto files") + return() + endif () + + google_cloud_cpp_generate_proto(proto_sources + ${_opt_UNPARSED_ARGUMENTS} + PROTO_PATH_DIRECTORIES + ${_opt_PROTO_PATH_DIRECTORIES}) + + add_library(${libname} ${proto_sources}) + set_property(TARGET ${libname} + PROPERTY PROTO_SOURCES ${_opt_UNPARSED_ARGUMENTS}) + target_link_libraries(${libname} + PUBLIC gRPC::grpc++ gRPC::grpc protobuf::libprotobuf) + target_include_directories( + ${libname} + PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}> + $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}> + $<INSTALL_INTERFACE:include>) +endfunction () + +function (google_cloud_cpp_grpcpp_library libname) + cmake_parse_arguments(_opt "" "" "PROTO_PATH_DIRECTORIES" ${ARGN}) + if (NOT _opt_UNPARSED_ARGUMENTS) + message(SEND_ERROR "Error: google_cloud_cpp_proto_library() called" + " without any proto files") + return() + endif () + + google_cloud_cpp_generate_grpcpp(grpcpp_sources + ${_opt_UNPARSED_ARGUMENTS} + PROTO_PATH_DIRECTORIES + ${_opt_PROTO_PATH_DIRECTORIES}) + google_cloud_cpp_proto_library(${libname} + ${_opt_UNPARSED_ARGUMENTS} + PROTO_PATH_DIRECTORIES + ${_opt_PROTO_PATH_DIRECTORIES}) + target_sources(${libname} PRIVATE ${grpcpp_sources}) +endfunction () diff --git a/cmake/FindProtobufTargets.cmake b/cmake/FindProtobufTargets.cmake new file mode 100644 index 000000000000..db260280d3cd --- /dev/null +++ b/cmake/FindProtobufTargets.cmake @@ -0,0 +1,207 @@ +# ~~~ +# 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 INTERFACE IMPORTED) + 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 INTERFACE IMPORTED) + 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 INTERFACE IMPORTED) + 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) diff --git a/cmake/FindgRPC.cmake b/cmake/FindgRPC.cmake new file mode 100644 index 000000000000..5895cf067cc1 --- /dev/null +++ b/cmake/FindgRPC.cmake @@ -0,0 +1,343 @@ +# ~~~ +# 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: +FindgRPC +-------- + +Locate and configure the gRPC library. + +The following variables can be set and are optional: + +``gRPC_DEBUG`` + Show debug messages. +``gRPC_USE_STATIC_LIBS`` + Set to ON to force the use of the static libraries. + Default is OFF. + +Defines the following variables: + +``gRPC_FOUND`` + Found the gRPC library +``gRPC_VERSION`` + Version of package found. + +The following :prop_tgt:`IMPORTED` targets are also defined: + +``gRPC::grpc++`` + The gRPC C++ library. +``gRPC::grpc`` + The gRPC C core library. +``gRPC::cpp_plugin`` + The C++ plugin for the Protobuf protoc compiler. + +The following cache variables are also available to set or use: + +Example: + +.. code-block:: cmake + + find_package(gRPC REQUIRED) + add_executable(bar bar.cc) + target_link_libraries(bar PRIVATE gRPC::grpc++) + +#]=======================================================================] + +if (gRPC_DEBUG) + message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " + "gRPC_USE_STATIC_LIBS = ${gRPC_USE_STATIC_LIBS}" + " gRPC_FOUND = ${gRPC_FOUND}") +endif () + +# gRPC always requires Thread support. +find_package(Threads REQUIRED) + +# Load the module to find protobuf with proper targets. Do not use +# `find_package()` because we (have to) install this module in non-standard +# locations. +include(${CMAKE_CURRENT_LIST_DIR}/FindProtobufTargets.cmake) + +# The gRPC::grpc_cpp_plugin target is sometimes defined, but without a +# IMPORTED_LOCATION +function (_grpc_fix_grpc_cpp_plugin_target) + # The target may already exist, do not create it again if it does. + if (NOT TARGET gRPC::grpc_cpp_plugin) + add_executable(gRPC::grpc_cpp_plugin IMPORTED) + endif () + get_target_property(_gRPC_CPP_PLUGIN_EXECUTABLE gRPC::grpc_cpp_plugin + IMPORTED_LOCATION) + if (gRPC_DEBUG) + message( + STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " + "LOCATION=${_gRPC_CPP_PLUGIN_EXECUTABLE}") + endif () + # Even if the target exists, gRPC CMake support files do not define the + # executable for the imported target (at least they do not in v1.19.1), so + # we need to define it ourselves. + if (NOT _gRPC_CPP_PLUGIN_EXECUTABLE) + find_program(_gRPC_CPP_PLUGIN_EXECUTABLE grpc_cpp_plugin + DOC "The gRPC C++ plugin for protoc") + mark_as_advanced(_gRPC_CPP_PLUGIN_EXECUTABLE) + if (_gRPC_CPP_PLUGIN_EXECUTABLE) + set_property(TARGET gRPC::grpc_cpp_plugin + PROPERTY IMPORTED_LOCATION + ${_gRPC_CPP_PLUGIN_EXECUTABLE}) + else() + set(gRPC_FOUND "grpc_cpp_plugin-NOTFOUND") + endif () + endif () +endfunction () + +# The gRPC::* targets sometimes lack the right definitions to compile cleanly on +# WIN32 +function (_grpc_fix_grpc_target_definitions) + # Including gRPC headers without this definition results in a build error. + if (WIN32) + set_property(TARGET gRPC::grpc + APPEND + PROPERTY INTERFACE_COMPILE_DEFINITIONS _WIN32_WINNT=0x600) + set_property(TARGET gRPC::grpc++ + APPEND + PROPERTY INTERFACE_COMPILE_DEFINITIONS _WIN32_WINNT=0x600) + endif () +endfunction () + +# First try to use the `gRPCConfig.cmake` or `grpc-config.cmake` file if it was +# installed. This is common on systems (or package managers) where gRPC was +# compiled and installed with `CMake`. +find_package(gRPC NO_MODULE QUIET) + +if (gRPC_DEBUG) + message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " + "NO_MODULE result gRPC_FOUND = ${gRPC_FOUND}") +endif () + +if (gRPC_FOUND) + _grpc_fix_grpc_cpp_plugin_target() + _grpc_fix_grpc_target_definitions() + return() +endif () + +include(SelectLibraryConfigurations) + +# Internal function: search for normal library as well as a debug one if the +# debug one is specified also include debug/optimized keywords in *_LIBRARIES +# variable +function (_gRPC_find_library name filename) + if (${name}_LIBRARY) + # Use result recorded by a previous call. + return() + else() + find_library(${name}_LIBRARY_RELEASE NAMES ${filename}) + mark_as_advanced(${name}_LIBRARY_RELEASE) + + find_library(${name}_LIBRARY_DEBUG NAMES ${filename}d ${filename}) + mark_as_advanced(${name}_LIBRARY_DEBUG) + + select_library_configurations(${name}) + + if (gRPC_DEBUG) + message( + STATUS + "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " + "${name} ${filename} RELEASE=${${name}_LIBRARY}" + " DEBUG=${${name}_LIBRARY_DEBUG} DEFAULT=${${name}_LIBRARY}" + ) + endif () + + set(${name}_LIBRARY "${${name}_LIBRARY}" PARENT_SCOPE) + endif () +endfunction () + +# +# Main +# + +# Support preference of static libs by adjusting CMAKE_FIND_LIBRARY_SUFFIXES +if (_gRPC_USE_STATIC_LIBS) + set(_gRPC_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES}) + if (WIN32) + set(CMAKE_FIND_LIBRARY_SUFFIXES .lib .a ${CMAKE_FIND_LIBRARY_SUFFIXES}) + else() + set(CMAKE_FIND_LIBRARY_SUFFIXES .a) + endif () +endif () + +_grpc_find_library(_gRPC_grpc grpc) +_grpc_find_library(_gRPC_grpc++ grpc++) + +if (NOT _gRPC_INCLUDE_DIR) + find_path(_gRPC_INCLUDE_DIR grpcpp/grpcpp.h) + mark_as_advanced(_gRPC_INCLUDE_DIR) +endif () + +if (gRPC_DEBUG) + message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " + " _gRPC_grpc_LIBRARY = ${_gRPC_grpc_LIBRARY}") + message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " + " _gRPC_grpc++_LIBRARY = ${_gRPC_grpc++_LIBRARY}") + message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " + " _gRPC_INCLUDE_DIR = ${_gRPC_INCLUDE_DIR}") +endif () + +if (_gRPC_grpc_LIBRARY) + if (NOT TARGET gRPC::grpc) + add_library(gRPC::grpc UNKNOWN IMPORTED) + set_target_properties(gRPC::grpc + PROPERTIES INTERFACE_INCLUDE_DIRECTORIES + "${_gRPC_INCLUDE_DIR}") + if (EXISTS "${_gRPC_grpc_LIBRARY}") + set_target_properties(gRPC::grpc + PROPERTIES IMPORTED_LOCATION + "${_gRPC_grpc_LIBRARY}") + endif () + if (EXISTS "${_gRPC_grpc_LIBRARY_RELEASE}") + set_property(TARGET gRPC::grpc + APPEND + PROPERTY IMPORTED_CONFIGURATIONS RELEASE) + set_target_properties(gRPC::grpc + PROPERTIES IMPORTED_LOCATION_RELEASE + "${_gRPC_grpc_LIBRARY_RELEASE}") + endif () + if (EXISTS "${_gRPC_grpc_LIBRARY_DEBUG}") + set_property(TARGET gRPC::grpc + APPEND + PROPERTY IMPORTED_CONFIGURATIONS DEBUG) + set_target_properties(gRPC::grpc + PROPERTIES IMPORTED_LOCATION_DEBUG + "${_gRPC_grpc_LIBRARY_DEBUG}") + endif () + set_property(TARGET gRPC::grpc + APPEND + PROPERTY INTERFACE_LINK_LIBRARIES protobuf::libprotobuf + Threads::Threads) + endif () +endif () + +if (_gRPC_grpc++_LIBRARY) + if (NOT TARGET gRPC::grpc++) + add_library(gRPC::grpc++ UNKNOWN IMPORTED) + set_target_properties(gRPC::grpc++ + PROPERTIES INTERFACE_INCLUDE_DIRECTORIES + "${_gRPC++_INCLUDE_DIR}") + if (EXISTS "${_gRPC_grpc++_LIBRARY}") + set_target_properties(gRPC::grpc++ + PROPERTIES IMPORTED_LOCATION + "${_gRPC_grpc++_LIBRARY}") + endif () + if (EXISTS "${_gRPC_grpc++_LIBRARY_RELEASE}") + set_property(TARGET gRPC::grpc++ + APPEND + PROPERTY IMPORTED_CONFIGURATIONS RELEASE) + set_target_properties(gRPC::grpc++ + PROPERTIES IMPORTED_LOCATION_RELEASE + "${_gRPC_grpc++_LIBRARY_RELEASE}") + endif () + if (EXISTS "${_gRPC_grpc++_LIBRARY_DEBUG}") + set_property(TARGET gRPC::grpc++ + APPEND + PROPERTY IMPORTED_CONFIGURATIONS DEBUG) + set_target_properties(gRPC::grpc++ + PROPERTIES IMPORTED_LOCATION_DEBUG + "${_gRPC_grpc++_LIBRARY_DEBUG}") + endif () + set_property(TARGET gRPC::grpc++ + APPEND + PROPERTY INTERFACE_LINK_LIBRARIES + gRPC::grpc + protobuf::libprotobuf + Threads::Threads) + if (CMAKE_VERSION VERSION_GREATER 3.8) + # gRPC++ requires C++11, but only CMake-3.8 introduced a target + # compiler feature to meet that requirement. + set_property(TARGET gRPC::grpc++ + APPEND + PROPERTY INTERFACE_COMPILE_FEATURES cxx_std_11) + elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") + # CMake 3.5 is still alive and kicking in some older distros, use + # the compiler-specific versions in these cases. + set_property(TARGET gRPC::grpc++ + APPEND + PROPERTY INTERFACE_COMPILE_OPTIONS "-std=c++11") + elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + set_property(TARGET gRPC::grpc++ + APPEND + PROPERTY INTERFACE_COMPILE_OPTIONS "-std=c++11") + else() + message( + WARNING + "gRPC::grpc++ requires C++11, but this module" + " (${CMAKE_CURRENT_LIST_FILE})" + " cannot enable it for the library target in your CMake and" + " compiler versions. You need to enable C++11 in the" + " CMakeLists.txt for your project. Consider filing a bug" + " so we can fix this problem.") + endif () + endif () +endif () + +# Restore original find library prefixes +if (_gRPC_USE_STATIC_LIBS) + set(CMAKE_FIND_LIBRARY_PREFIXES "${_gRPC_ORIG_FIND_LIBRARY_PREFIXES}") +endif () + +file(WRITE "${CMAKE_BINARY_DIR}/get_gRPC_version.cc" [====[ +#include <grpcpp/grpcpp.h> +#include <iostream> +int main() { + std::cout << grpc::Version(); // no newline to simplify CMake module + return 0; +} + ]====]) + +try_run(_gRPC_GET_VERSION_STATUS + _gRPC_GET_VERSION_COMPILE_STATUS + "${CMAKE_BINARY_DIR}" + "${CMAKE_BINARY_DIR}/get_gRPC_version.cc" + LINK_LIBRARIES + gRPC::grpc++ + gRPC::grpc + COMPILE_OUTPUT_VARIABLE _gRPC_GET_VERSION_COMPILE_OUTPUT + RUN_OUTPUT_VARIABLE gRPC_VERSION) + +file(REMOVE "${CMAKE_BINARY_DIR}/get_gRPC_version.cc") + +_grpc_fix_grpc_cpp_plugin_target() + +if (gRPC_DEBUG) + foreach (_var + _gRPC_CPP_PLUGIN_EXECUTABLE + _gRPC_VERSION_RAW + _gRPC_GET_VERSION_STATUS + _gRPC_GET_VERSION_COMPILE_STATUS + _gRPC_GET_VERSION_COMPILE_OUTPUT + _gRPC_grpc_LIBRARY + _gRPC_grpc++_LIBRARY + _gRPC_INCLUDE_DIR) + message( + STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " + "${_var} = ${${_var}}") + endforeach () + unset(_var) +endif () + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(gRPC + REQUIRED_VARS + _gRPC_grpc_LIBRARY + _gRPC_INCLUDE_DIR + VERSION_VAR + gRPC_VERSION) diff --git a/cmake/SelectMSVCRuntime.cmake b/cmake/SelectMSVCRuntime.cmake new file mode 100644 index 000000000000..eb7f8f9e954b --- /dev/null +++ b/cmake/SelectMSVCRuntime.cmake @@ -0,0 +1,46 @@ +# ~~~ +# 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. +# ~~~ + +# When compiling against *-static vcpkg packages we need to use the static C++ +# runtime with MSVC. The default is to use the dynamic runtime, which does not +# work in this case. This seems to be the recommended way to change the +# runtime: +# +# ~~~ +# https://gitlab.kitware.com/cmake/community/wikis/FAQ#how-can-i-build-my-msvc-application-with-a-static-runtime +# ~~~ +# +# Note that currently we use VCPKG_TARGET_TRIPLET to determine if the static +# runtime is needed. In the future we may need to use a more complex expression +# to determine this, but this is a good start. +# +if (MSVC AND VCPKG_TARGET_TRIPLET MATCHES "-static$") + foreach (flag_var + CMAKE_CXX_FLAGS + CMAKE_CXX_FLAGS_DEBUG + CMAKE_CXX_FLAGS_RELEASE + CMAKE_CXX_FLAGS_MINSIZEREL + CMAKE_CXX_FLAGS_RELWITHDEBINFO) + if (${flag_var} MATCHES "/MD") + string(REGEX + REPLACE "/MD" + "/MT" + ${flag_var} + "${${flag_var}}") + endif () + endforeach (flag_var) + unset(flag_var) +endif () diff --git a/cmake/config-version.cmake.in b/cmake/config-version.cmake.in new file mode 100644 index 000000000000..29891a6bde62 --- /dev/null +++ b/cmake/config-version.cmake.in @@ -0,0 +1,35 @@ +# 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. + +set(PACKAGE_VERSION @DOXYGEN_PROJECT_NUMBER@) + +# This package has not reached 1.0, there are no compatibility guarantees +# before then. +if (@GOOGLE_CLOUD_CPP_CONFIG_VERSION_MAJOR@ EQUAL 0) + if ("${PACKAGE_FIND_VERSION}" STREQUAL "") + set(PACKAGE_VERSION_COMPATIBLE TRUE) + elseif ("${PACKAGE_VERSION}" VERSION_EQUAL "${PACKAGE_FIND_VERSION}") + set(PACKAGE_VERSION_COMPATIBLE TRUE) + set(PACKAGE_VERSION_EXACT TRUE) + else () + set(PACKAGE_VERSION_UNSUITABLE TRUE) + endif () +elseif("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}") + set(PACKAGE_VERSION_COMPATIBLE FALSE) +else() + set(PACKAGE_VERSION_COMPATIBLE TRUE) + if ("${PACKAGE_VERSION}" VERSION_EQUAL "${PACKAGE_FIND_VERSION}") + set(PACKAGE_VERSION_EXACT TRUE) + endif() +endif() diff --git a/cmake/config.cmake.in b/cmake/config.cmake.in new file mode 100644 index 000000000000..50ddd6bbd156 --- /dev/null +++ b/cmake/config.cmake.in @@ -0,0 +1,36 @@ +# 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. + +include("${CMAKE_CURRENT_LIST_DIR}/FindProtobufTargets.cmake") +include("${CMAKE_CURRENT_LIST_DIR}/FindgRPC.cmake") + +include("${CMAKE_CURRENT_LIST_DIR}/googleapis-targets.cmake") + +foreach (_target + api_http + api_annotations + api_auth + rpc_status + rpc_error_details + longrunning_operations + iam_v1_policy + iam_v1_iam_policy + bigtable + spanner) + set(scoped_name "googleapis-c++::${_target}_protos") + set(imported_name "googleapis_cpp_${_target}_protos") + add_library(${scoped_name} IMPORTED INTERFACE) + set_target_properties(${scoped_name} PROPERTIES + INTERFACE_LINK_LIBRARIES ${imported_name}) +endforeach () diff --git a/cmake/config.pc.in b/cmake/config.pc.in new file mode 100644 index 000000000000..af068beb74a0 --- /dev/null +++ b/cmake/config.pc.in @@ -0,0 +1,26 @@ +# 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. + +prefix=@CMAKE_INSTALL_PREFIX@ +exec_prefix=${prefix}/@CMAKE_INSTALL_BINDIR@ +libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@ +includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@ + +Name: @GOOGLE_CLOUD_CPP_PC_NAME@ +Description: @GOOGLE_CLOUD_CPP_PC_DESCRIPTION@ +Requires: @GOOGLE_CLOUD_CPP_PC_REQUIRES@ +Version: @DOXYGEN_PROJECT_NUMBER@ + +Libs: -L${libdir} @GOOGLE_CLOUD_CPP_PC_LIBS@ +Cflags: -I${includedir} |