Browse Source

CMake project updates

A series of improvements:

- Improved Protobuf module compatibility (disabled by default);
- Hide advanced settings;
- Added build tree configuration;
- Added build of examples.
Konstantin Podsvirov 9 years ago
parent
commit
71556295ff

+ 18 - 3
cmake/CMakeLists.txt

@@ -1,15 +1,19 @@
 # Minimum CMake required
 cmake_minimum_required(VERSION 2.8.12)
 
-# Project
-project(protobuf C CXX)
+if(protobuf_VERBOSE)
+  message(STATUS "Protocol Buffers Configuring...")
+endif()
 
 # CMake policies
 cmake_policy(SET CMP0022 NEW)
 
+# Project
+project(protobuf C CXX)
+
 # Options
-option(protobuf_VERBOSE "Enable for verbose output" OFF)
 option(protobuf_BUILD_TESTS "Build tests" ON)
+option(protobuf_BUILD_EXAMPLES "Build examples" OFF)
 if (BUILD_SHARED_LIBS)
   set(protobuf_BUILD_SHARED_LIBS_DEFAULT ON)
 else (BUILD_SHARED_LIBS)
@@ -25,6 +29,9 @@ endif (MSVC)
 option(protobuf_WITH_ZLIB "Build with zlib support" ${protobuf_WITH_ZLIB_DEFAULT})
 set(protobuf_DEBUG_POSTFIX "d"
   CACHE STRING "Default debug postfix")
+mark_as_advanced(protobuf_DEBUG_POSTFIX)
+# User options
+include("${CMAKE_CURRENT_LIST_DIR}/protobuf-options.cmake")
 
 # Path to main configure script
 set(protobuf_CONFIGURE_SCRIPT "../configure.ac")
@@ -151,3 +158,11 @@ if (protobuf_BUILD_TESTS)
 endif (protobuf_BUILD_TESTS)
 
 include(install.cmake)
+
+if (protobuf_BUILD_EXAMPLES)
+  include(examples.cmake)
+endif (protobuf_BUILD_EXAMPLES)
+
+if(protobuf_VERBOSE)
+    message(STATUS "Protocol Buffers Configuring done")
+endif()

+ 10 - 0
cmake/examples.cmake

@@ -0,0 +1,10 @@
+if(protobuf_VERBOSE)
+  message(STATUS "Protocol Buffers Examples Configuring...")
+endif()
+
+# Add examples subproject
+add_subdirectory(../examples examples)
+
+if(protobuf_VERBOSE)
+  message(STATUS "Protocol Buffers Examples Configuring done")
+endif()

+ 19 - 6
cmake/install.cmake

@@ -87,22 +87,35 @@ if(NOT MSVC)
 else()
   set(CMAKE_INSTALL_CMAKEDIR "cmake" CACHE STRING "${_cmakedir_desc}")
 endif()
+mark_as_advanced(CMAKE_INSTALL_CMAKEDIR)
 
+# Import configuration
 install(EXPORT protobuf-targets
   DESTINATION "${CMAKE_INSTALL_CMAKEDIR}"
   NAMESPACE protobuf::
   COMPONENT protobuf-export)
 
 configure_file(protobuf-config.cmake.in
-  protobuf-config.cmake @ONLY)
+  ${CMAKE_INSTALL_CMAKEDIR}/protobuf-config.cmake @ONLY)
 configure_file(protobuf-config-version.cmake.in
-  protobuf-config-version.cmake @ONLY)
+  ${CMAKE_INSTALL_CMAKEDIR}/protobuf-config-version.cmake @ONLY)
 configure_file(protobuf-module.cmake.in
-  protobuf-module.cmake @ONLY)
+  ${CMAKE_INSTALL_CMAKEDIR}/protobuf-module.cmake @ONLY)
+
+# Build tree import configuration (for import from subprojects)
+if(NOT EXISTS "${protobuf_DIR}")
+  set(protobuf_DIR "${protobuf_BINARY_DIR}/${CMAKE_INSTALL_CMAKEDIR}")
+  set(Protobuf_DIR "${protobuf_DIR}")
+  file(COPY
+    "${CMAKE_CURRENT_LIST_DIR}/protobuf-options.cmake"
+    "${CMAKE_CURRENT_LIST_DIR}/protobuf-targets.cmake"
+    DESTINATION "${protobuf_DIR}")
+endif()
 
 install(FILES
-  "${protobuf_BINARY_DIR}/protobuf-config.cmake"
-  "${protobuf_BINARY_DIR}/protobuf-config-version.cmake"
-  "${protobuf_BINARY_DIR}/protobuf-module.cmake"
+  "${CMAKE_CURRENT_LIST_DIR}/protobuf-options.cmake"
+  "${protobuf_BINARY_DIR}/${CMAKE_INSTALL_CMAKEDIR}/protobuf-config.cmake"
+  "${protobuf_BINARY_DIR}/${CMAKE_INSTALL_CMAKEDIR}/protobuf-config-version.cmake"
+  "${protobuf_BINARY_DIR}/${CMAKE_INSTALL_CMAKEDIR}/protobuf-module.cmake"
   DESTINATION "${CMAKE_INSTALL_CMAKEDIR}"
   COMPONENT protobuf-export)

+ 4 - 13
cmake/protobuf-config.cmake.in

@@ -1,19 +1,10 @@
-# Version info variables
-set(PROTOBUF_VERSION        "@protobuf_VERSION@")
-set(PROTOBUF_VERSION_STRING "@protobuf_VERSION_STRING@")
+# User options
+include("${CMAKE_CURRENT_LIST_DIR}/protobuf-options.cmake")
 
 # Imported targets
 include("${CMAKE_CURRENT_LIST_DIR}/protobuf-targets.cmake")
 
-# Compute the installation prefix relative to this file.
-get_filename_component(_PROTOBUF_IMPORT_PREFIX
-  "${_PROTOBUF_PACKAGE_PREFIX}" PATH)
-get_filename_component(_PROTOBUF_IMPORT_PREFIX
-  "${_PROTOBUF_IMPORT_PREFIX}" PATH)
-get_filename_component(_PROTOBUF_IMPORT_PREFIX
-  "${_PROTOBUF_IMPORT_PREFIX}" PATH)
-
 # CMake FindProtobuf module compatible file
-if(NOT DEFINED PROTOBUF_MODULE_COMPATIBLE OR "${PROTOBUF_MODULE_COMPATIBLE}")
-  include("${_PROTOBUF_PACKAGE_PREFIX}/protobuf-module.cmake")
+if(protobuf_MODULE_COMPATIBLE)
+  include("${CMAKE_CURRENT_LIST_DIR}/protobuf-module.cmake")
 endif()

+ 157 - 47
cmake/protobuf-module.cmake.in

@@ -1,7 +1,4 @@
-if(PROTOBUF_SRC_ROOT_FOLDER)
-  message(AUTHOR_WARNING "Variable PROTOBUF_SRC_ROOT_FOLDER defined, but not"
-    " used in CONFIG mode")
-endif()
+# Functions
 
 function(PROTOBUF_GENERATE_CPP SRCS HDRS)
   if(NOT ARGN)
@@ -23,12 +20,8 @@ function(PROTOBUF_GENERATE_CPP SRCS HDRS)
     set(_protobuf_include_path -I ${CMAKE_CURRENT_SOURCE_DIR})
   endif()
 
-  # Add well-known type protos include path
-  list(APPEND _protobuf_include_path
-    -I "${_PROTOBUF_IMPORT_PREFIX}/@CMAKE_INSTALL_INCLUDEDIR@")
-
-  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)
@@ -49,11 +42,11 @@ 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)
+      VERBATIM )
   endforeach()
 
   set_source_files_properties(${${SRCS}} ${${HDRS}} PROPERTIES GENERATED TRUE)
@@ -61,29 +54,110 @@ function(PROTOBUF_GENERATE_CPP SRCS HDRS)
   set(${HDRS} ${${HDRS}} PARENT_SCOPE)
 endfunction()
 
+function(PROTOBUF_GENERATE_PYTHON SRCS)
+  if(NOT ARGN)
+    message(SEND_ERROR "Error: PROTOBUF_GENERATE_PYTHON() called without any proto files")
+    return()
+  endif()
+
+  if(PROTOBUF_GENERATE_CPP_APPEND_PATH)
+    # Create an include path for each file specified
+    foreach(FIL ${ARGN})
+      get_filename_component(ABS_FIL ${FIL} ABSOLUTE)
+      get_filename_component(ABS_PATH ${ABS_FIL} PATH)
+      list(FIND _protobuf_include_path ${ABS_PATH} _contains_already)
+      if(${_contains_already} EQUAL -1)
+          list(APPEND _protobuf_include_path -I ${ABS_PATH})
+      endif()
+    endforeach()
+  else()
+    set(_protobuf_include_path -I ${CMAKE_CURRENT_SOURCE_DIR})
+  endif()
+
+  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)
+          list(APPEND _protobuf_include_path -I ${ABS_PATH})
+      endif()
+    endforeach()
+  endif()
+
+  set(${SRCS})
+  foreach(FIL ${ARGN})
+    get_filename_component(ABS_FIL ${FIL} ABSOLUTE)
+    get_filename_component(FIL_WE ${FIL} NAME_WE)
+
+    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}
+      COMMENT "Running Python protocol buffer compiler on ${FIL}"
+      VERBATIM )
+  endforeach()
+
+  set(${SRCS} ${${SRCS}} PARENT_SCOPE)
+endfunction()
+
+# Environment
+
+# Backwards compatibility
+# Define camel case versions of input variables
+foreach(UPPER
+    PROTOBUF_SRC_ROOT_FOLDER
+    PROTOBUF_IMPORT_DIRS
+    PROTOBUF_DEBUG
+    PROTOBUF_LIBRARY
+    PROTOBUF_PROTOC_LIBRARY
+    PROTOBUF_INCLUDE_DIR
+    PROTOBUF_PROTOC_EXECUTABLE
+    PROTOBUF_LIBRARY_DEBUG
+    PROTOBUF_PROTOC_LIBRARY_DEBUG
+    PROTOBUF_LITE_LIBRARY
+    PROTOBUF_LITE_LIBRARY_DEBUG
+    )
+    if (DEFINED ${UPPER})
+        string(REPLACE "PROTOBUF_" "Protobuf_" Camel ${UPPER})
+        if (NOT DEFINED ${Camel})
+            set(${Camel} ${${UPPER}})
+        endif()
+    endif()
+endforeach()
+
+if(DEFINED Protobuf_SRC_ROOT_FOLDER)
+  message(AUTHOR_WARNING "Variable Protobuf_SRC_ROOT_FOLDER defined, but not"
+    " used in CONFIG mode")
+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(_protobuf_find_libraries name filename)
-   get_target_property(${name}_LIBRARY lib${filename}
-     IMPORTED_LOCATION_RELEASE)
-   set(${name}_LIBRARY "${${name}_LIBRARY}" PARENT_SCOPE)
-   get_target_property(${name}_LIBRARY_DEBUG lib${filename}
-     IMPORTED_LOCATION_DEBUG)
-   set(${name}_LIBRARY_DEBUG "${${name}_LIBRARY_DEBUG}" PARENT_SCOPE)
-
-   if(NOT ${name}_LIBRARY_DEBUG)
-      # There is no debug library
-      set(${name}_LIBRARY_DEBUG ${${name}_LIBRARY} PARENT_SCOPE)
-      set(${name}_LIBRARIES     ${${name}_LIBRARY} PARENT_SCOPE)
-   else()
-      # There IS a debug library
-      set(${name}_LIBRARIES
-          optimized ${${name}_LIBRARY}
-          debug     ${${name}_LIBRARY_DEBUG}
-          PARENT_SCOPE
-      )
-   endif()
+  if(${name}_LIBRARIES)
+    # Use result recorded by a previous call.
+  elseif(${name}_LIBRARY)
+    # Honor cache entry used by CMake 3.5 and lower.
+    set(${name}_LIBRARIES "${${name}_LIBRARY}" PARENT_SCOPE)
+  else()
+    get_target_property(_aliased protobuf::lib${filename} ALIASED_TARGET)
+    if(_aliased)
+        set(${name}_LIBRARY_RELEASE $<TARGET_FILE:protobuf::lib${filename}>)
+        set(${name}_LIBRARY_DEBUG $<TARGET_FILE:protobuf::lib${filename}>)
+    else()
+      get_target_property(${name}_LIBRARY_RELEASE protobuf::lib${filename}
+        LOCATION_RELEASE)
+      get_target_property(${name}_LIBRARY_DEBUG protobuf::lib${filename}
+        LOCATION_DEBUG)
+    endif()
+
+    select_library_configurations(${name})
+    set(${name}_LIBRARY ${${name}_LIBRARY} PARENT_SCOPE)
+    set(${name}_LIBRARIES ${${name}_LIBRARIES} PARENT_SCOPE)
+  endif()
 endfunction()
 
 # Internal function: find threads library
@@ -107,33 +181,69 @@ if(NOT DEFINED PROTOBUF_GENERATE_CPP_APPEND_PATH)
 endif()
 
 # The Protobuf library
-_protobuf_find_libraries(PROTOBUF protobuf)
+_protobuf_find_libraries(Protobuf protobuf)
 
 # The Protobuf Lite 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)
 
 if(UNIX)
   _protobuf_find_threads()
 endif()
 
 # Set the include directory
-set(PROTOBUF_INCLUDE_DIR "${_PROTOBUF_IMPORT_PREFIX}/@CMAKE_INSTALL_INCLUDEDIR@")
+get_target_property(Protobuf_INCLUDE_DIRS protobuf::libprotobuf
+  INTERFACE_INCLUDE_DIRECTORIES)
 
 # Set the protoc Executable
-get_target_property(PROTOBUF_PROTOC_EXECUTABLE protoc
-  IMPORTED_LOCATION_RELEASE)
-if(NOT PROTOBUF_PROTOC_EXECUTABLE)
-  get_target_property(PROTOBUF_PROTOC_EXECUTABLE protoc
-    IMPORTED_LOCATION_DEBUG)
+get_target_property(_aliased protobuf::protoc ALIASED_TARGET)
+if(_aliased)
+  if(POLICY CMP0026)
+    set(Protobuf_PROTOC_EXECUTABLE $<TARGET_FILE:protobuf::protoc>)
+  else()
+    get_target_property(Protobuf_PROTOC_EXECUTABLE protobuf::protoc
+      LOCATION)
+  endif()
+else()
+  get_target_property(Protobuf_PROTOC_EXECUTABLE protobuf::protoc
+    IMPORTED_LOCATION_RELEASE)
+  if(NOT EXISTS "${Protobuf_PROTOC_EXECUTABLE}")
+    get_target_property(Protobuf_PROTOC_EXECUTABLE protobuf::protoc
+      IMPORTED_LOCATION_DEBUG)
+  endif()
 endif()
 
-include(FindPackageHandleStandardArgs)
-FIND_PACKAGE_HANDLE_STANDARD_ARGS(PROTOBUF DEFAULT_MSG
-    PROTOBUF_LIBRARY PROTOBUF_INCLUDE_DIR)
+# Version info variable
+set(Protobuf_VERSION "@protobuf_VERSION@")
 
-if(PROTOBUF_FOUND)
-    set(PROTOBUF_INCLUDE_DIRS ${PROTOBUF_INCLUDE_DIR})
-endif()
+include(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(Protobuf
+    REQUIRED_VARS Protobuf_LIBRARIES Protobuf_INCLUDE_DIRS
+    VERSION_VAR Protobuf_VERSION
+)
+
+# Backwards compatibility
+# Define upper case versions of output variables
+foreach(Camel
+    Protobuf_VERSION
+    Protobuf_SRC_ROOT_FOLDER
+    Protobuf_IMPORT_DIRS
+    Protobuf_DEBUG
+    Protobuf_INCLUDE_DIRS
+    Protobuf_LIBRARIES
+    Protobuf_PROTOC_LIBRARIES
+    Protobuf_LITE_LIBRARIES
+    Protobuf_LIBRARY
+    Protobuf_PROTOC_LIBRARY
+    Protobuf_INCLUDE_DIR
+    Protobuf_PROTOC_EXECUTABLE
+    Protobuf_LIBRARY_DEBUG
+    Protobuf_PROTOC_LIBRARY_DEBUG
+    Protobuf_LITE_LIBRARY
+    Protobuf_LITE_LIBRARY_DEBUG
+    )
+    string(TOUPPER ${Camel} UPPER)
+    set(${UPPER} ${${Camel}})
+endforeach()

+ 7 - 0
cmake/protobuf-options.cmake

@@ -0,0 +1,7 @@
+# Verbose output
+option(protobuf_VERBOSE "Enable for verbose output" OFF)
+mark_as_advanced(protobuf_VERBOSE)
+
+# FindProtobuf module compatibel
+option(protobuf_MODULE_COMPATIBLE "CMake build-in FindProtobuf.cmake module compatible" OFF)
+mark_as_advanced(protobuf_MODULE_COMPATIBLE)

+ 17 - 0
cmake/protobuf-targets.cmake

@@ -0,0 +1,17 @@
+# Library aliases
+foreach(_library
+  libprotobuf-lite
+  libprotobuf
+  libprotoc)
+  if(TARGET ${_library} AND NOT TARGET protobuf::${_library})
+    add_library(protobuf::${_library} ALIAS ${_library})
+  endif()
+endforeach()
+
+# Executable aliases
+foreach(_executable
+  protoc)
+  if(TARGET ${_executable} AND NOT TARGET protobuf::${_executable})
+    add_executable(protobuf::${_executable} ALIAS ${_executable})
+  endif()
+endforeach()

+ 1 - 0
cmake/tests.cmake

@@ -4,6 +4,7 @@ endif()
 
 option(protobuf_ABSOLUTE_TEST_PLUGIN_PATH
   "Using absolute test_plugin path in tests" ON)
+mark_as_advanced(protobuf_ABSOLUTE_TEST_PLUGIN_PATH)
 
 include_directories(
   ${protobuf_source_dir}/gmock

+ 79 - 0
examples/CMakeLists.txt

@@ -0,0 +1,79 @@
+# Minimum CMake required
+cmake_minimum_required(VERSION 2.8.12)
+
+# Project
+project(addressbook)
+
+# Find required protobuf package
+find_package(protobuf 3 CONFIG REQUIRED)
+
+if(protobuf_VERBOSE)
+  message(STATUS "Using Protocol Buffers ${Protobuf_VERSION}")
+endif()
+
+file(GLOB SRC_LIST "*.cc")
+
+file(GLOB PROTO_LIST "*.proto")
+
+#
+# Code generation
+#
+
+if(protobuf_MODULE_COMPATIBLE) # Old school
+
+  include_directories(${Protobuf_INCLUDE_DIRS})
+  protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS ${PROTO_LIST})
+
+else() # New style
+
+  set(PROTO_SRCS)
+  set(PROTO_HDRS)
+
+  foreach(FIL ${PROTO_LIST})
+
+    get_filename_component(ABS_FIL ${FIL} ABSOLUTE)
+    get_filename_component(FIL_WE ${FIL} NAME_WE)
+
+    list(APPEND PROTO_SRCS "${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.pb.cc")
+    list(APPEND PROTO_HDRS "${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.pb.h")
+
+    add_custom_command(
+      OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.pb.cc"
+             "${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.pb.h"
+      COMMAND protobuf::protoc
+      ARGS --cpp_out ${CMAKE_CURRENT_BINARY_DIR} -I ${CMAKE_CURRENT_SOURCE_DIR}
+        ${ABS_FIL}
+      DEPENDS ${ABS_FIL}
+      COMMENT "Running C++ protocol buffer compiler on ${FIL}"
+      VERBATIM)
+
+  endforeach()
+
+endif()
+
+include_directories(${CMAKE_CURRENT_BINARY_DIR})
+
+include(GNUInstallDirs)
+
+foreach(FIL ${SRC_LIST})
+
+  get_filename_component(FIL_NAME_WE ${FIL} NAME_WE)
+
+  set(APP ${FIL_NAME_WE}_cpp)
+
+  add_executable(${APP} ${FIL} ${PROTO_SRCS} ${PROTO_HDRS})
+
+  #
+  # Link libraries
+  #
+
+  if(protobuf_MODULE_COMPATIBLE) # Old school
+    target_link_libraries(${APP} ${Protobuf_LIBRARIES})
+  else() # New style
+    target_link_libraries(${APP} protobuf::libprotobuf)
+  endif()
+
+  install(TARGETS ${APP}
+    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT ${APP})
+
+endforeach()