From 82983433cf6fdc9857a5ca57f281ad0b5f41817c Mon Sep 17 00:00:00 2001 From: Konstantin Podsvirov Date: Fri, 31 Jul 2015 23:36:00 +0300 Subject: Install protobuf from cmake project Additional export as "protobuf" package for importing from other cmake projects --- cmake/CMakeLists.txt | 25 +++++++++++++++ cmake/install.cmake | 58 ++++++++++++++++++++++++++++++++++ cmake/protobuf-config-version.cmake.in | 1 + cmake/protobuf-config.cmake.in | 1 + 4 files changed, 85 insertions(+) create mode 100644 cmake/install.cmake create mode 100644 cmake/protobuf-config-version.cmake.in create mode 100644 cmake/protobuf-config.cmake.in diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index d36292df..dbcf3490 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -1,13 +1,35 @@ +# Minimum CMake required cmake_minimum_required(VERSION 2.8) +# Project project(protobuf C CXX) +# Options option(BUILD_TESTING "Build tests" ON) option(BUILD_SHARED_LIBS "Build Shared Libraries" OFF) if (MSVC) option(ZLIB "Build with zlib support" OFF) endif (MSVC) +# Path to common header +set(protobuf_COMMON_HEADER "../src/google/protobuf/stubs/common.h") + +# Parse version from common header +file(STRINGS "${protobuf_COMMON_HEADER}" protobuf_VERSION_LINE + LIMIT_COUNT 1 + REGEX "^#define GOOGLE_PROTOBUF_VERSION [0-9]+$") +string(REGEX REPLACE "^.*PROTOBUF_VERSION ([0-9]+).*$" "\\1" + protobuf_VERSION_NUMBER "${protobuf_VERSION_LINE}") +math(EXPR protobuf_VERSION_MICRO + "${protobuf_VERSION_NUMBER} % 1000") +math(EXPR protobuf_VERSION_MINOR + "(${protobuf_VERSION_NUMBER} - ${protobuf_VERSION_MICRO}) % 1000000 / 1000") +math(EXPR protobuf_VERSION_MAJOR + "(${protobuf_VERSION_NUMBER} - ${protobuf_VERSION_MINOR} * 1000 - ${protobuf_VERSION_MICRO}) % 1000000000 / 1000000") +set(protobuf_VERSION_PATCH ${protobuf_VERSION_MICRO}) +set(protobuf_VERSION + "${protobuf_VERSION_MAJOR}.${protobuf_VERSION_MINOR}.${protobuf_VERSION_MICRO}") + add_definitions(-DGOOGLE_PROTOBUF_CMAKE_BUILD) find_package(Threads REQUIRED) @@ -73,6 +95,9 @@ include(libprotobuf-lite.cmake) include(libprotobuf.cmake) include(libprotoc.cmake) include(protoc.cmake) + if (BUILD_TESTING) include(tests.cmake) endif (BUILD_TESTING) + +include(install.cmake) diff --git a/cmake/install.cmake b/cmake/install.cmake new file mode 100644 index 00000000..e7f2aea5 --- /dev/null +++ b/cmake/install.cmake @@ -0,0 +1,58 @@ +include(GNUInstallDirs) + +foreach(_library + libprotobuf-lite + libprotobuf + libprotoc) + set_property(TARGET ${_library} + PROPERTY INTERFACE_INCLUDE_DIRECTORIES $) + install(TARGETS ${_library} EXPORT protobuf-targets + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT ${_library} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT ${_library} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT ${_library}) +endforeach() + +install(TARGETS protoc EXPORT protobuf-targets + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT protoc) + +if(MSVC) + file(STRINGS extract_includes.bat.in _extract_strings + REGEX "^copy") + foreach(_extract_string ${_extract_strings}) + string(REPLACE "copy \${PROTOBUF_SOURCE_WIN32_PATH}\\" "" + _extract_string ${_extract_string}) + string(REPLACE "\\" "/" _extract_string ${_extract_string}) + string(REGEX MATCH "^[^ ]+" + _extract_from ${_extract_string}) + string(REGEX REPLACE "^${_extract_from} ([^$]+)" "\\1" + _extract_to ${_extract_string}) + get_filename_component(_extract_from "${protobuf_SOURCE_DIR}/${_extract_from}" ABSOLUTE) + get_filename_component(_extract_name ${_extract_to} NAME) + get_filename_component(_extract_to ${_extract_to} PATH) + if(EXISTS "${_extract_from}") + install(FILES "${_extract_from}" + DESTINATION "${_extract_to}" + COMPONENT protobuf-headers + RENAME "${_extract_name}") + else() + message(AUTHOR_WARNING "The file \"${_extract_from}\" is listed in " + "\"${protobuf_SOURCE_DIR}/cmake/extract_includes.bat.in\" " + "but there not exists. The file will not be installed.") + endif() + endforeach() +endif() + +install(EXPORT protobuf-targets + DESTINATION "lib/cmake/protobuf" + COMPONENT protobuf-export) + +configure_file(protobuf-config.cmake.in + protobuf-config.cmake @ONLY) +configure_file(protobuf-config-version.cmake.in + protobuf-config-version.cmake @ONLY) + +install(FILES + "${protobuf_BINARY_DIR}/protobuf-config.cmake" + "${protobuf_BINARY_DIR}/protobuf-config-version.cmake" + DESTINATION "lib/cmake/protobuf" + COMPONENT protobuf-export) diff --git a/cmake/protobuf-config-version.cmake.in b/cmake/protobuf-config-version.cmake.in new file mode 100644 index 00000000..07ab40b9 --- /dev/null +++ b/cmake/protobuf-config-version.cmake.in @@ -0,0 +1 @@ +set(PACKAGE_VERSION @protobuf_VERSION@) diff --git a/cmake/protobuf-config.cmake.in b/cmake/protobuf-config.cmake.in new file mode 100644 index 00000000..6ae09d59 --- /dev/null +++ b/cmake/protobuf-config.cmake.in @@ -0,0 +1 @@ +include("${CMAKE_CURRENT_LIST_DIR}/protobuf-targets.cmake") -- cgit v1.2.3 From 743ec448c5358a95d10e655ab256d7911e2145d5 Mon Sep 17 00:00:00 2001 From: Konstantin Podsvirov Date: Sat, 1 Aug 2015 02:01:42 +0300 Subject: Parsing version from configure.ac for CMake project --- cmake/CMakeLists.txt | 37 ++++++++++++++++++++++--------------- cmake/protobuf-config.cmake.in | 2 ++ 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index dbcf3490..1b477762 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -11,24 +11,31 @@ if (MSVC) option(ZLIB "Build with zlib support" OFF) endif (MSVC) -# Path to common header -set(protobuf_COMMON_HEADER "../src/google/protobuf/stubs/common.h") +# Path to main configure script +set(protobuf_CONFIGURE_SCRIPT "../configure.ac") -# Parse version from common header -file(STRINGS "${protobuf_COMMON_HEADER}" protobuf_VERSION_LINE +# Parse version from configure script +file(STRINGS "${protobuf_CONFIGURE_SCRIPT}" protobuf_VERSION_LINE LIMIT_COUNT 1 - REGEX "^#define GOOGLE_PROTOBUF_VERSION [0-9]+$") -string(REGEX REPLACE "^.*PROTOBUF_VERSION ([0-9]+).*$" "\\1" - protobuf_VERSION_NUMBER "${protobuf_VERSION_LINE}") -math(EXPR protobuf_VERSION_MICRO - "${protobuf_VERSION_NUMBER} % 1000") -math(EXPR protobuf_VERSION_MINOR - "(${protobuf_VERSION_NUMBER} - ${protobuf_VERSION_MICRO}) % 1000000 / 1000") -math(EXPR protobuf_VERSION_MAJOR - "(${protobuf_VERSION_NUMBER} - ${protobuf_VERSION_MINOR} * 1000 - ${protobuf_VERSION_MICRO}) % 1000000000 / 1000000") -set(protobuf_VERSION_PATCH ${protobuf_VERSION_MICRO}) + REGEX "^AC_INIT") +# Replace special characters +string(REPLACE "(" "_" protobuf_VERSION_LINE ${protobuf_VERSION_LINE}) +string(REPLACE ")" "_" protobuf_VERSION_LINE ${protobuf_VERSION_LINE}) +string(REPLACE "[" "_" protobuf_VERSION_LINE ${protobuf_VERSION_LINE}) +string(REPLACE "]" "_" protobuf_VERSION_LINE ${protobuf_VERSION_LINE}) +# Parse version string +string(REGEX REPLACE "^AC_INIT__Protocol Buffers_,_([^_]+).*$" "\\1" + protobuf_VERSION_STRING "${protobuf_VERSION_LINE}") +# Parse version tweaks +string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+).*$" "\\1" + protobuf_VERSION_MAJOR "${protobuf_VERSION_STRING}") +string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+).*$" "\\2" + protobuf_VERSION_MINOR "${protobuf_VERSION_STRING}") +string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+).*$" "\\3" + protobuf_VERSION_PATCH "${protobuf_VERSION_STRING}") +# Package version set(protobuf_VERSION - "${protobuf_VERSION_MAJOR}.${protobuf_VERSION_MINOR}.${protobuf_VERSION_MICRO}") + "${protobuf_VERSION_MAJOR}.${protobuf_VERSION_MINOR}.${protobuf_VERSION_PATCH}") add_definitions(-DGOOGLE_PROTOBUF_CMAKE_BUILD) diff --git a/cmake/protobuf-config.cmake.in b/cmake/protobuf-config.cmake.in index 6ae09d59..38fa58da 100644 --- a/cmake/protobuf-config.cmake.in +++ b/cmake/protobuf-config.cmake.in @@ -1 +1,3 @@ +set(protobuf_VERSION_STRING "@protobuf_VERSION_STRING@") + include("${CMAKE_CURRENT_LIST_DIR}/protobuf-targets.cmake") -- cgit v1.2.3 From 0be0789018645de0b20f60b203d2627d8bc27159 Mon Sep 17 00:00:00 2001 From: Konstantin Podsvirov Date: Sun, 2 Aug 2015 16:31:28 +0300 Subject: CMake installation now compatible with origin FindProtobuf module --- cmake/install.cmake | 1 + cmake/protobuf-config.cmake.in | 28 ++++++++- cmake/protobuf-module.cmake | 129 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 156 insertions(+), 2 deletions(-) create mode 100644 cmake/protobuf-module.cmake diff --git a/cmake/install.cmake b/cmake/install.cmake index e7f2aea5..bedd0601 100644 --- a/cmake/install.cmake +++ b/cmake/install.cmake @@ -54,5 +54,6 @@ configure_file(protobuf-config-version.cmake.in install(FILES "${protobuf_BINARY_DIR}/protobuf-config.cmake" "${protobuf_BINARY_DIR}/protobuf-config-version.cmake" + "${protobuf_SOURCE_DIR}/protobuf-module.cmake" DESTINATION "lib/cmake/protobuf" COMPONENT protobuf-export) diff --git a/cmake/protobuf-config.cmake.in b/cmake/protobuf-config.cmake.in index 38fa58da..51d715cf 100644 --- a/cmake/protobuf-config.cmake.in +++ b/cmake/protobuf-config.cmake.in @@ -1,3 +1,27 @@ -set(protobuf_VERSION_STRING "@protobuf_VERSION_STRING@") +# Version info variables +set(PROTOBUF_VERSION "@protobuf_VERSION@") +set(PROTOBUF_VERSION_STRING "@protobuf_VERSION_STRING@") -include("${CMAKE_CURRENT_LIST_DIR}/protobuf-targets.cmake") +# Current dir +get_filename_component(_PROTOBUF_PACKAGE_PREFIX + "${CMAKE_CURRENT_LIST_FILE}" PATH) + +# Imported targets +include("${_PROTOBUF_PACKAGE_PREFIX}/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") +endif() + +# Cleanup temporary variables. +set(_PROTOBUF_PACKAGE_PREFIX) +set(_PROTOBUF_IMPORT_PREFIX) diff --git a/cmake/protobuf-module.cmake b/cmake/protobuf-module.cmake new file mode 100644 index 00000000..43181221 --- /dev/null +++ b/cmake/protobuf-module.cmake @@ -0,0 +1,129 @@ +if(PROTOBUF_SRC_ROOT_FOLDER) + message(AUTHOR_WARNING "Variable PROTOBUF_SRC_ROOT_FOLDER defined, but not" + " used in CONFIG mode") +endif() + +function(PROTOBUF_GENERATE_CPP SRCS HDRS) + if(NOT ARGN) + message(SEND_ERROR "Error: PROTOBUF_GENERATE_CPP() 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}) + set(${HDRS}) + 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}.pb.cc") + list(APPEND ${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_EXECUTABLE} + ARGS --cpp_out ${CMAKE_CURRENT_BINARY_DIR} ${_protobuf_include_path} ${ABS_FIL} + DEPENDS ${ABS_FIL} ${PROTOBUF_PROTOC_EXECUTABLE} + COMMENT "Running C++ protocol buffer compiler on ${FIL}" + VERBATIM) + endforeach() + + set_source_files_properties(${${SRCS}} ${${HDRS}} PROPERTIES GENERATED TRUE) + set(${SRCS} ${${SRCS}} PARENT_SCOPE) + set(${HDRS} ${${HDRS}} PARENT_SCOPE) +endfunction() + +# 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) + get_target_property(${name}_LIBRARY_DEBUG lib${filename} + IMPORTED_LOCATION_DEBUG) + + 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() +endfunction() + +# Internal function: find threads library +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) + endif() +endfunction() + +# +# Main. +# + +# 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) +endif() + +# The Protobuf library +_protobuf_find_libraries(PROTOBUF protobuf) + +# The Protobuf Lite library +_protobuf_find_libraries(PROTOBUF_LITE protobuf-lite) + +# The Protobuf Protoc Library +_protobuf_find_libraries(PROTOBUF_PROTOC protoc) + +if(UNIX) + _protobuf_find_threads() +endif() + +# Set the include directory +set(PROTOBUF_INCLUDE_DIR "${_PROTOBUF_IMPORT_PREFIX}/include") + +# Set the protoc Executable +get_target_property(PROTOBUF_PROTOC_EXECUTABLE protoc + IMPORTED_LOCATION_RELEASE) + +include(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(PROTOBUF DEFAULT_MSG + PROTOBUF_LIBRARY PROTOBUF_INCLUDE_DIR) + +if(PROTOBUF_FOUND) + set(PROTOBUF_INCLUDE_DIRS ${PROTOBUF_INCLUDE_DIR}) +endif() -- cgit v1.2.3 From ebfca175e262044f538952da285ba5269f6c3e96 Mon Sep 17 00:00:00 2001 From: Konstantin Podsvirov Date: Mon, 3 Aug 2015 11:58:48 +0300 Subject: Install well-known type proto files from CMake project --- cmake/install.cmake | 48 +++++++++++++- cmake/protobuf-module.cmake | 129 -------------------------------------- cmake/protobuf-module.cmake.in | 139 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 185 insertions(+), 131 deletions(-) delete mode 100644 cmake/protobuf-module.cmake create mode 100644 cmake/protobuf-module.cmake.in diff --git a/cmake/install.cmake b/cmake/install.cmake index bedd0601..f8148804 100644 --- a/cmake/install.cmake +++ b/cmake/install.cmake @@ -5,7 +5,8 @@ foreach(_library libprotobuf libprotoc) set_property(TARGET ${_library} - PROPERTY INTERFACE_INCLUDE_DIRECTORIES $) + PROPERTY INTERFACE_INCLUDE_DIRECTORIES + $) install(TARGETS ${_library} EXPORT protobuf-targets RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT ${_library} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT ${_library} @@ -29,6 +30,8 @@ if(MSVC) get_filename_component(_extract_from "${protobuf_SOURCE_DIR}/${_extract_from}" ABSOLUTE) get_filename_component(_extract_name ${_extract_to} NAME) get_filename_component(_extract_to ${_extract_to} PATH) + string(REPLACE "include/" "${CMAKE_INSTALL_INCLUDEDIR}/" + _extract_to "${_extract_to}") if(EXISTS "${_extract_from}") install(FILES "${_extract_from}" DESTINATION "${_extract_to}" @@ -42,6 +45,45 @@ if(MSVC) endforeach() endif() +# Internal function for parsing auto tools scripts +function(_protobuf_auto_list FILE_NAME VARIABLE) + file(STRINGS ${FILE_NAME} _strings) + set(_list) + foreach(_string ${_strings}) + set(_found) + string(REGEX MATCH "^[ \t]*${VARIABLE}[ \t]*=[ \t]*" _found "${_string}") + if(_found) + string(LENGTH "${_found}" _length) + string(SUBSTRING "${_string}" ${_length} -1 _draft_list) + foreach(_item ${_draft_list}) + string(STRIP "${_item}" _item) + list(APPEND _list "${_item}") + endforeach() + endif() + endforeach() + set(${VARIABLE} ${_list} PARENT_SCOPE) +endfunction() + +# Install well-known type proto files +_protobuf_auto_list("../src/Makefile.am" nobase_dist_proto_DATA) +foreach(_file ${nobase_dist_proto_DATA}) + get_filename_component(_file_from "../src/${_file}" ABSOLUTE) + get_filename_component(_file_name ${_file} NAME) + get_filename_component(_file_path ${_file} PATH) + if(EXISTS "${_file_from}") + install(FILES "${_file_from}" + DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/${_file_path}" + COMPONENT protobuf-protos + RENAME "${_file_name}") + else() + message(AUTHOR_WARNING "The file \"${_file_from}\" is listed in " + "\"${protobuf_SOURCE_DIR}/../src/Makefile.am\" as nobase_dist_proto_DATA " + "but there not exists. The file will not be installed.") + endif() +endforeach() + +# Export configuration + install(EXPORT protobuf-targets DESTINATION "lib/cmake/protobuf" COMPONENT protobuf-export) @@ -50,10 +92,12 @@ configure_file(protobuf-config.cmake.in protobuf-config.cmake @ONLY) configure_file(protobuf-config-version.cmake.in protobuf-config-version.cmake @ONLY) +configure_file(protobuf-module.cmake.in + protobuf-module.cmake @ONLY) install(FILES "${protobuf_BINARY_DIR}/protobuf-config.cmake" "${protobuf_BINARY_DIR}/protobuf-config-version.cmake" - "${protobuf_SOURCE_DIR}/protobuf-module.cmake" + "${protobuf_BINARY_DIR}/protobuf-module.cmake" DESTINATION "lib/cmake/protobuf" COMPONENT protobuf-export) diff --git a/cmake/protobuf-module.cmake b/cmake/protobuf-module.cmake deleted file mode 100644 index 43181221..00000000 --- a/cmake/protobuf-module.cmake +++ /dev/null @@ -1,129 +0,0 @@ -if(PROTOBUF_SRC_ROOT_FOLDER) - message(AUTHOR_WARNING "Variable PROTOBUF_SRC_ROOT_FOLDER defined, but not" - " used in CONFIG mode") -endif() - -function(PROTOBUF_GENERATE_CPP SRCS HDRS) - if(NOT ARGN) - message(SEND_ERROR "Error: PROTOBUF_GENERATE_CPP() 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}) - set(${HDRS}) - 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}.pb.cc") - list(APPEND ${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_EXECUTABLE} - ARGS --cpp_out ${CMAKE_CURRENT_BINARY_DIR} ${_protobuf_include_path} ${ABS_FIL} - DEPENDS ${ABS_FIL} ${PROTOBUF_PROTOC_EXECUTABLE} - COMMENT "Running C++ protocol buffer compiler on ${FIL}" - VERBATIM) - endforeach() - - set_source_files_properties(${${SRCS}} ${${HDRS}} PROPERTIES GENERATED TRUE) - set(${SRCS} ${${SRCS}} PARENT_SCOPE) - set(${HDRS} ${${HDRS}} PARENT_SCOPE) -endfunction() - -# 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) - get_target_property(${name}_LIBRARY_DEBUG lib${filename} - IMPORTED_LOCATION_DEBUG) - - 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() -endfunction() - -# Internal function: find threads library -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) - endif() -endfunction() - -# -# Main. -# - -# 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) -endif() - -# The Protobuf library -_protobuf_find_libraries(PROTOBUF protobuf) - -# The Protobuf Lite library -_protobuf_find_libraries(PROTOBUF_LITE protobuf-lite) - -# The Protobuf Protoc Library -_protobuf_find_libraries(PROTOBUF_PROTOC protoc) - -if(UNIX) - _protobuf_find_threads() -endif() - -# Set the include directory -set(PROTOBUF_INCLUDE_DIR "${_PROTOBUF_IMPORT_PREFIX}/include") - -# Set the protoc Executable -get_target_property(PROTOBUF_PROTOC_EXECUTABLE protoc - IMPORTED_LOCATION_RELEASE) - -include(FindPackageHandleStandardArgs) -FIND_PACKAGE_HANDLE_STANDARD_ARGS(PROTOBUF DEFAULT_MSG - PROTOBUF_LIBRARY PROTOBUF_INCLUDE_DIR) - -if(PROTOBUF_FOUND) - set(PROTOBUF_INCLUDE_DIRS ${PROTOBUF_INCLUDE_DIR}) -endif() diff --git a/cmake/protobuf-module.cmake.in b/cmake/protobuf-module.cmake.in new file mode 100644 index 00000000..f17b5dff --- /dev/null +++ b/cmake/protobuf-module.cmake.in @@ -0,0 +1,139 @@ +if(PROTOBUF_SRC_ROOT_FOLDER) + message(AUTHOR_WARNING "Variable PROTOBUF_SRC_ROOT_FOLDER defined, but not" + " used in CONFIG mode") +endif() + +function(PROTOBUF_GENERATE_CPP SRCS HDRS) + if(NOT ARGN) + message(SEND_ERROR "Error: PROTOBUF_GENERATE_CPP() 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() + + # Add well-nkown 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}) + 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}) + set(${HDRS}) + 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}.pb.cc") + list(APPEND ${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_EXECUTABLE} + ARGS --cpp_out ${CMAKE_CURRENT_BINARY_DIR} ${_protobuf_include_path} ${ABS_FIL} + DEPENDS ${ABS_FIL} ${PROTOBUF_PROTOC_EXECUTABLE} + COMMENT "Running C++ protocol buffer compiler on ${FIL}" + VERBATIM) + endforeach() + + set_source_files_properties(${${SRCS}} ${${HDRS}} PROPERTIES GENERATED TRUE) + set(${SRCS} ${${SRCS}} PARENT_SCOPE) + set(${HDRS} ${${HDRS}} PARENT_SCOPE) +endfunction() + +# 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() +endfunction() + +# Internal function: find threads library +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) + endif() +endfunction() + +# +# Main. +# + +# 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) +endif() + +# The Protobuf library +_protobuf_find_libraries(PROTOBUF protobuf) + +# The Protobuf Lite library +_protobuf_find_libraries(PROTOBUF_LITE protobuf-lite) + +# The Protobuf Protoc Library +_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@") + +# 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) +endif() + +include(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(PROTOBUF DEFAULT_MSG + PROTOBUF_LIBRARY PROTOBUF_INCLUDE_DIR) + +if(PROTOBUF_FOUND) + set(PROTOBUF_INCLUDE_DIRS ${PROTOBUF_INCLUDE_DIR}) +endif() -- cgit v1.2.3 From 5500b0691f13118e5418755070a084d214666367 Mon Sep 17 00:00:00 2001 From: Konstantin Podsvirov Date: Mon, 3 Aug 2015 12:10:55 +0300 Subject: Fix: comment typo --- cmake/protobuf-module.cmake.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/protobuf-module.cmake.in b/cmake/protobuf-module.cmake.in index f17b5dff..d81dc459 100644 --- a/cmake/protobuf-module.cmake.in +++ b/cmake/protobuf-module.cmake.in @@ -23,7 +23,7 @@ function(PROTOBUF_GENERATE_CPP SRCS HDRS) set(_protobuf_include_path -I ${CMAKE_CURRENT_SOURCE_DIR}) endif() - # Add well-nkown type protos include path + # Add well-known type protos include path list(APPEND _protobuf_include_path -I "${_PROTOBUF_IMPORT_PREFIX}/@CMAKE_INSTALL_INCLUDEDIR@") -- cgit v1.2.3 From 61e078e803241dc9487544ba3d5d377e16d2838b Mon Sep 17 00:00:00 2001 From: Konstantin Podsvirov Date: Tue, 4 Aug 2015 10:32:58 +0300 Subject: Install headers from extract_includes for all platforms --- cmake/install.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/install.cmake b/cmake/install.cmake index f8148804..e14ef1d2 100644 --- a/cmake/install.cmake +++ b/cmake/install.cmake @@ -16,7 +16,7 @@ endforeach() install(TARGETS protoc EXPORT protobuf-targets RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT protoc) -if(MSVC) +if(TRUE) file(STRINGS extract_includes.bat.in _extract_strings REGEX "^copy") foreach(_extract_string ${_extract_strings}) -- cgit v1.2.3 From 5bdf4a42713424cbe3cb45a6aef281670c6cdf40 Mon Sep 17 00:00:00 2001 From: Josh Haberman Date: Mon, 3 Aug 2015 15:51:31 -0700 Subject: Fixed several Ruby conformance test cases through upb update. Change-Id: Ief77de7134e05e07b1a7e3970d49880c2d5e6fe9 --- conformance/failure_list_ruby.txt | 15 --- ruby/ext/google/protobuf_c/upb.c | 238 +++++++++++++++++++++----------------- ruby/ext/google/protobuf_c/upb.h | 11 +- 3 files changed, 141 insertions(+), 123 deletions(-) diff --git a/conformance/failure_list_ruby.txt b/conformance/failure_list_ruby.txt index 35d1ff91..ff220cb9 100644 --- a/conformance/failure_list_ruby.txt +++ b/conformance/failure_list_ruby.txt @@ -1,17 +1,2 @@ JsonInput.HelloWorld.JsonOutput JsonInput.HelloWorld.ProtobufOutput -ProtobufInput.PrematureEofBeforeUnknownValue.DOUBLE -ProtobufInput.PrematureEofBeforeUnknownValue.FIXED32 -ProtobufInput.PrematureEofBeforeUnknownValue.FIXED64 -ProtobufInput.PrematureEofBeforeUnknownValue.FLOAT -ProtobufInput.PrematureEofBeforeUnknownValue.SFIXED32 -ProtobufInput.PrematureEofBeforeUnknownValue.SFIXED64 -ProtobufInput.PrematureEofInDelimitedDataForUnknownValue.BYTES -ProtobufInput.PrematureEofInDelimitedDataForUnknownValue.MESSAGE -ProtobufInput.PrematureEofInDelimitedDataForUnknownValue.STRING -ProtobufInput.PrematureEofInsideUnknownValue.DOUBLE -ProtobufInput.PrematureEofInsideUnknownValue.FIXED32 -ProtobufInput.PrematureEofInsideUnknownValue.FIXED64 -ProtobufInput.PrematureEofInsideUnknownValue.FLOAT -ProtobufInput.PrematureEofInsideUnknownValue.SFIXED32 -ProtobufInput.PrematureEofInsideUnknownValue.SFIXED64 diff --git a/ruby/ext/google/protobuf_c/upb.c b/ruby/ext/google/protobuf_c/upb.c index 8ef8e31d..048a163a 100644 --- a/ruby/ext/google/protobuf_c/upb.c +++ b/ruby/ext/google/protobuf_c/upb.c @@ -7478,6 +7478,8 @@ void upb_pbdecodermethodopts_setlazy(upb_pbdecodermethodopts *opts, bool lazy) { /* Error messages that are shared between the bytecode and JIT decoders. */ const char *kPbDecoderStackOverflow = "Nesting too deep."; +const char *kPbDecoderSubmessageTooLong = + "Submessage end extends past enclosing submessage."; /* Error messages shared within this file. */ static const char *kUnterminatedVarint = "Unterminated varint."; @@ -7512,6 +7514,28 @@ static bool consumes_input(opcode op) { } } +static size_t stacksize(upb_pbdecoder *d, size_t entries) { + UPB_UNUSED(d); + return entries * sizeof(upb_pbdecoder_frame); +} + +static size_t callstacksize(upb_pbdecoder *d, size_t entries) { + UPB_UNUSED(d); + +#ifdef UPB_USE_JIT_X64 + if (d->method_->is_native_) { + /* Each native stack frame needs two pointers, plus we need a few frames for + * the enter/exit trampolines. */ + size_t ret = entries * sizeof(void*) * 2; + ret += sizeof(void*) * 10; + return ret; + } +#endif + + return entries * sizeof(uint32_t*); +} + + static bool in_residual_buf(const upb_pbdecoder *d, const char *p); /* It's unfortunate that we have to micro-manage the compiler with @@ -7544,11 +7568,21 @@ static size_t curbufleft(const upb_pbdecoder *d) { return d->data_end - d->ptr; } +/* How many bytes are available before end-of-buffer. */ +static size_t bufleft(const upb_pbdecoder *d) { + return d->end - d->ptr; +} + /* Overall stream offset of d->ptr. */ uint64_t offset(const upb_pbdecoder *d) { return d->bufstart_ofs + (d->ptr - d->buf); } +/* How many bytes are available before the end of this delimited region. */ +size_t delim_remaining(const upb_pbdecoder *d) { + return d->top->end_ofs - offset(d); +} + /* Advances d->ptr. */ static void advance(upb_pbdecoder *d, size_t len) { assert(curbufleft(d) >= len); @@ -7597,24 +7631,72 @@ static void checkpoint(upb_pbdecoder *d) { d->checkpoint = d->ptr; } +/* Skips "bytes" bytes in the stream, which may be more than available. If we + * skip more bytes than are available, we return a long read count to the caller + * indicating how many bytes can be skipped over before passing actual data + * again. Skipped bytes can pass a NULL buffer and the decoder guarantees they + * won't actually be read. + */ +static int32_t skip(upb_pbdecoder *d, size_t bytes) { + assert(!in_residual_buf(d, d->ptr) || d->size_param == 0); + assert(d->skip == 0); + if (bytes > delim_remaining(d)) { + seterr(d, "Skipped value extended beyond enclosing submessage."); + return upb_pbdecoder_suspend(d); + } else if (bufleft(d) > bytes) { + /* Skipped data is all in current buffer, and more is still available. */ + advance(d, bytes); + d->skip = 0; + return DECODE_OK; + } else { + /* Skipped data extends beyond currently available buffers. */ + d->pc = d->last; + d->skip = bytes - curbufleft(d); + d->bufstart_ofs += (d->end - d->buf); + d->residual_end = d->residual; + switchtobuf(d, d->residual, d->residual_end); + return d->size_param + d->skip; + } +} + + /* Resumes the decoder from an initial state or from a previous suspend. */ int32_t upb_pbdecoder_resume(upb_pbdecoder *d, void *p, const char *buf, size_t size, const upb_bufhandle *handle) { UPB_UNUSED(p); /* Useless; just for the benefit of the JIT. */ + d->buf_param = buf; d->size_param = size; d->handle = handle; + if (d->residual_end > d->residual) { /* We have residual bytes from the last buffer. */ assert(d->ptr == d->residual); } else { switchtobuf(d, buf, buf + size); } + d->checkpoint = d->ptr; + + if (d->skip) { + size_t skip_bytes = d->skip; + d->skip = 0; + CHECK_RETURN(skip(d, skip_bytes)); + d->checkpoint = d->ptr; + } + + if (!buf) { + /* NULL buf is ok if its entire span is covered by the "skip" above, but + * by this point we know that "skip" doesn't cover the buffer. */ + seterr(d, "Passed NULL buffer over non-skippable region."); + return upb_pbdecoder_suspend(d); + } + if (d->top->groupnum < 0) { CHECK_RETURN(upb_pbdecoder_skipunknown(d, -1, 0)); d->checkpoint = d->ptr; } + return DECODE_OK; } @@ -7674,28 +7756,6 @@ static size_t suspend_save(upb_pbdecoder *d) { return d->size_param; } -/* Skips "bytes" bytes in the stream, which may be more than available. If we - * skip more bytes than are available, we return a long read count to the caller - * indicating how many bytes the caller should skip before passing a new buffer. - */ -static int32_t skip(upb_pbdecoder *d, size_t bytes) { - assert(!in_residual_buf(d, d->ptr) || d->size_param == 0); - if (curbufleft(d) >= bytes) { - /* Skipped data is all in current buffer. */ - advance(d, bytes); - return DECODE_OK; - } else { - /* Skipped data extends beyond currently available buffers. */ - size_t skip; - d->pc = d->last; - skip = bytes - curbufleft(d); - d->bufstart_ofs += (d->end - d->buf) + skip; - d->residual_end = d->residual; - switchtobuf(d, d->residual, d->residual_end); - return d->size_param + skip; - } -} - /* Copies the next "bytes" bytes into "buf" and advances the stream. * Requires that this many bytes are available in the current buffer. */ UPB_FORCEINLINE static void consumebytes(upb_pbdecoder *d, void *buf, @@ -7860,7 +7920,7 @@ static bool decoder_push(upb_pbdecoder *d, uint64_t end) { upb_pbdecoder_frame *fr = d->top; if (end > fr->end_ofs) { - seterr(d, "Submessage end extends past enclosing submessage."); + seterr(d, kPbDecoderSubmessageTooLong); return false; } else if (fr == d->limit) { seterr(d, kPbDecoderStackOverflow); @@ -7964,34 +8024,7 @@ have_tag: return DECODE_OK; } - if (d->ptr == d->delim_end) { - seterr(d, "Enclosing submessage ended in the middle of value or group"); - /* Unlike most errors we notice during parsing, right now we have consumed - * all of the user's input. - * - * There are three different options for how to handle this case: - * - * 1. decode() = short count, error = set - * 2. decode() = full count, error = set - * 3. decode() = full count, error NOT set, short count and error will - * be reported on next call to decode() (or end()) - * - * (1) and (3) have the advantage that they preserve the invariant that an - * error occurs iff decode() returns a short count. - * - * (2) and (3) have the advantage of reflecting the fact that all of the - * bytes were in fact parsed (and possibly delivered to the unknown field - * handler, in the future when that is supported). - * - * (3) requires extra state in the decode (a place to store the "permanent - * error" that we should return for all subsequent attempts to decode). - * But we likely want this anyway. - * - * Right now we do (1), thanks to the fact that we checkpoint *after* this - * check. (3) may be a better choice long term; unclear at the moment. */ - return upb_pbdecoder_suspend(d); - } - + /* Unknown group -- continue looping over unknown fields. */ checkpoint(d); } } @@ -8015,7 +8048,7 @@ static int32_t dispatch(upb_pbdecoder *d) { uint8_t wire_type; uint32_t fieldnum; upb_value val; - int32_t ret; + int32_t retval; /* Decode tag. */ CHECK_RETURN(decode_v32(d, &tag)); @@ -8039,23 +8072,25 @@ static int32_t dispatch(upb_pbdecoder *d) { } } + /* We have some unknown fields (or ENDGROUP) to parse. The DISPATCH or TAG + * bytecode that triggered this is preceded by a CHECKDELIM bytecode which + * we need to back up to, so that when we're done skipping unknown data we + * can re-check the delimited end. */ + d->last--; /* Necessary if we get suspended */ + d->pc = d->last; + assert(getop(*d->last) == OP_CHECKDELIM); + /* Unknown field or ENDGROUP. */ - ret = upb_pbdecoder_skipunknown(d, fieldnum, wire_type); + retval = upb_pbdecoder_skipunknown(d, fieldnum, wire_type); + + CHECK_RETURN(retval); - if (ret == DECODE_ENDGROUP) { + if (retval == DECODE_ENDGROUP) { goto_endmsg(d); return DECODE_OK; - } else if (ret == DECODE_OK) { - /* We just consumed some input, so we might now have consumed all the data - * in the delmited region. Since every opcode that can trigger dispatch is - * directly preceded by OP_CHECKDELIM, rewind to it now to re-check the - * delimited end. */ - d->pc = d->last - 1; - assert(getop(*d->pc) == OP_CHECKDELIM); - return DECODE_OK; } - return ret; + return DECODE_OK; } /* Callers know that the stack is more than one deep because the opcodes that @@ -8070,18 +8105,8 @@ upb_pbdecoder_frame *outer_frame(upb_pbdecoder *d) { /* The main decoder VM function. Uses traditional bytecode dispatch loop with a * switch() statement. */ -size_t upb_pbdecoder_decode(void *closure, const void *hd, const char *buf, - size_t size, const upb_bufhandle *handle) { - upb_pbdecoder *d = closure; - const mgroup *group = hd; - int32_t result; - assert(buf); - result = upb_pbdecoder_resume(d, NULL, buf, size, handle); - if (result == DECODE_ENDGROUP) { - goto_endmsg(d); - } - CHECK_RETURN(result); - UPB_UNUSED(group); +size_t run_decoder_vm(upb_pbdecoder *d, const mgroup *group, + const upb_bufhandle* handle) { #define VMCASE(op, code) \ case op: { code; if (consumes_input(op)) checkpoint(d); break; } @@ -8104,6 +8129,7 @@ size_t upb_pbdecoder_decode(void *closure, const void *hd, const char *buf, arg = instruction >> 8; longofs = arg; assert(d->ptr != d->residual_end); + UPB_UNUSED(group); #ifdef UPB_DUMP_BYTECODE fprintf(stderr, "s_ofs=%d buf_ofs=%d data_rem=%d buf_rem=%d delim_rem=%d " "%x %s (%d)\n", @@ -8160,7 +8186,7 @@ size_t upb_pbdecoder_decode(void *closure, const void *hd, const char *buf, CHECK_SUSPEND(upb_sink_endsubmsg(&d->top->sink, arg)); ) VMCASE(OP_STARTSTR, - uint32_t len = d->top->end_ofs - offset(d); + uint32_t len = delim_remaining(d); upb_pbdecoder_frame *outer = outer_frame(d); CHECK_SUSPEND(upb_sink_startstr(&outer->sink, arg, len, &d->top->sink)); if (len == 0) { @@ -8171,7 +8197,7 @@ size_t upb_pbdecoder_decode(void *closure, const void *hd, const char *buf, uint32_t len = curbufleft(d); size_t n = upb_sink_putstring(&d->top->sink, arg, d->ptr, len, handle); if (n > len) { - if (n > d->top->end_ofs - offset(d)) { + if (n > delim_remaining(d)) { seterr(d, "Tried to skip past end of string."); return upb_pbdecoder_suspend(d); } else { @@ -8279,12 +8305,15 @@ size_t upb_pbdecoder_decode(void *closure, const void *hd, const char *buf, CHECK_RETURN(dispatch(d)); }) VMCASE(OP_HALT, { - return size; + return d->size_param; }) } } } + +/* BytesHandler handlers ******************************************************/ + void *upb_pbdecoder_startbc(void *closure, const void *pc, size_t size_hint) { upb_pbdecoder *d = closure; UPB_UNUSED(size_hint); @@ -8293,6 +8322,7 @@ void *upb_pbdecoder_startbc(void *closure, const void *pc, size_t size_hint) { d->call_len = 1; d->callstack[0] = &halt; d->pc = pc; + d->skip = 0; return d; } @@ -8303,6 +8333,7 @@ void *upb_pbdecoder_startjit(void *closure, const void *hd, size_t size_hint) { d->top->end_ofs = UINT64_MAX; d->bufstart_ofs = 0; d->call_len = 0; + d->skip = 0; return d; } @@ -8311,12 +8342,14 @@ bool upb_pbdecoder_end(void *closure, const void *handler_data) { const upb_pbdecodermethod *method = handler_data; uint64_t end; char dummy; -#ifdef UPB_USE_JIT_X64 - const mgroup *group = (const mgroup*)method->group; -#endif if (d->residual_end > d->residual) { - seterr(d, "Unexpected EOF"); + seterr(d, "Unexpected EOF: decoder still has buffered unparsed data"); + return false; + } + + if (d->skip) { + seterr(d, "Unexpected EOF inside skipped data"); return false; } @@ -8325,12 +8358,13 @@ bool upb_pbdecoder_end(void *closure, const void *handler_data) { return false; } - /* Message ends here. */ + /* The user's end() call indicates that the message ends here. */ end = offset(d); d->top->end_ofs = end; #ifdef UPB_USE_JIT_X64 - if (group->jit_code) { + if (method->is_native_) { + const mgroup *group = (const mgroup*)method->group; if (d->top != d->stack) d->stack->end_ofs = 0; group->jit_code(closure, method->code_base.ptr, &dummy, 0, NULL); @@ -8353,13 +8387,26 @@ bool upb_pbdecoder_end(void *closure, const void *handler_data) { } if (d->call_len != 0) { - seterr(d, "Unexpected EOF"); + seterr(d, "Unexpected EOF inside submessage or group"); return false; } return true; } +size_t upb_pbdecoder_decode(void *decoder, const void *group, const char *buf, + size_t size, const upb_bufhandle *handle) { + int32_t result = upb_pbdecoder_resume(decoder, NULL, buf, size, handle); + + if (result == DECODE_ENDGROUP) goto_endmsg(decoder); + CHECK_RETURN(result); + + return run_decoder_vm(decoder, group, handle); +} + + +/* Public API *****************************************************************/ + void upb_pbdecoder_reset(upb_pbdecoder *d) { d->top = d->stack; d->top->groupnum = 0; @@ -8369,27 +8416,6 @@ void upb_pbdecoder_reset(upb_pbdecoder *d) { d->residual_end = d->residual; } -static size_t stacksize(upb_pbdecoder *d, size_t entries) { - UPB_UNUSED(d); - return entries * sizeof(upb_pbdecoder_frame); -} - -static size_t callstacksize(upb_pbdecoder *d, size_t entries) { - UPB_UNUSED(d); - -#ifdef UPB_USE_JIT_X64 - if (d->method_->is_native_) { - /* Each native stack frame needs two pointers, plus we need a few frames for - * the enter/exit trampolines. */ - size_t ret = entries * sizeof(void*) * 2; - ret += sizeof(void*) * 10; - return ret; - } -#endif - - return entries * sizeof(uint32_t*); -} - upb_pbdecoder *upb_pbdecoder_create(upb_env *e, const upb_pbdecodermethod *m, upb_sink *sink) { const size_t default_max_nesting = 64; diff --git a/ruby/ext/google/protobuf_c/upb.h b/ruby/ext/google/protobuf_c/upb.h index b31f5c08..078e2a28 100644 --- a/ruby/ext/google/protobuf_c/upb.h +++ b/ruby/ext/google/protobuf_c/upb.h @@ -5635,7 +5635,7 @@ UPB_INLINE bool upb_bufsrc_putbuf(const char *buf, size_t len, upb_bufhandle_setbuf(&handle, buf, 0); ret = upb_bytessink_start(sink, len, &subc); if (ret && len != 0) { - ret = (upb_bytessink_putbuf(sink, subc, buf, len, &handle) == len); + ret = (upb_bytessink_putbuf(sink, subc, buf, len, &handle) >= len); } if (ret) { ret = upb_bytessink_end(sink); @@ -7123,7 +7123,7 @@ class upb::pb::DecoderMethod { * constructed. This hint may be an overestimate for some build configurations. * But if the decoder library is upgraded without recompiling the application, * it may be an underestimate. */ -#define UPB_PB_DECODER_SIZE 4400 +#define UPB_PB_DECODER_SIZE 4408 #ifdef __cplusplus @@ -7548,6 +7548,12 @@ struct upb_pbdecoder { char residual[12]; char *residual_end; + /* Bytes of data that should be discarded from the input beore we start + * parsing again. We set this when we internally determine that we can + * safely skip the next N bytes, but this region extends past the current + * user buffer. */ + size_t skip; + /* Stores the user buffer passed to our decode function. */ const char *buf_param; size_t size_param; @@ -7590,6 +7596,7 @@ void upb_pbdecoder_seterr(upb_pbdecoder *d, const char *msg); /* Error messages that are shared between the bytecode and JIT decoders. */ extern const char *kPbDecoderStackOverflow; +extern const char *kPbDecoderSubmessageTooLong; /* Access to decoderplan members needed by the decoder. */ const char *upb_pbdecoder_getopname(unsigned int op); -- cgit v1.2.3 From a39ababb7cf8839d96b3347e0da87fbcc3d512e8 Mon Sep 17 00:00:00 2001 From: Jon Skeet Date: Thu, 13 Aug 2015 12:01:41 +0100 Subject: Allow public access to descriptor.proto as a dependency. With this in place, generating APIs on github.com/google/googleapis works - previously annotations.proto failed. Currently there's no access to the annotations (stored as extensions) but we could potentially expose those at a later date. --- csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs | 15 +++++++++++++++ src/google/protobuf/compiler/csharp/csharp_helpers.h | 5 ++++- .../protobuf/compiler/csharp/csharp_umbrella_class.cc | 9 ++++++++- 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs index 500e467c..bad58faa 100644 --- a/csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs +++ b/csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs @@ -368,5 +368,20 @@ namespace Google.Protobuf.Reflection { return "FileDescriptor for " + proto.Name; } + + /// + /// Returns the file descriptor for descriptor.proto. + /// + /// + /// This is used for protos which take a direct dependency on descriptor.proto, typically for + /// annotations. While descriptor.proto is a proto2 file, it is built into the Google.Protobuf + /// runtime for reflection purposes. The messages are internal to the runtime as they would require + /// proto2 semantics for full support, but the file descriptor is available via this property. The + /// C# codegen in protoc automatically uses this property when it detects a dependency on descriptor.proto. + /// + /// + /// The file descriptor for descriptor.proto. + /// + public static FileDescriptor DescriptorProtoFileDescriptor { get { return DescriptorProtoFile.Descriptor; } } } } \ No newline at end of file diff --git a/src/google/protobuf/compiler/csharp/csharp_helpers.h b/src/google/protobuf/compiler/csharp/csharp_helpers.h index 1d17af61..278e05f3 100644 --- a/src/google/protobuf/compiler/csharp/csharp_helpers.h +++ b/src/google/protobuf/compiler/csharp/csharp_helpers.h @@ -117,7 +117,10 @@ inline bool IsMapEntryMessage(const Descriptor* descriptor) { inline bool IsDescriptorProto(const FileDescriptor* descriptor) { // TODO: Do this better! (Currently this depends on a hack in generate_protos.sh to rename // the file...) - return descriptor->name() == "google/protobuf/descriptor_proto_file.proto"; + // We need to be able to detect the "normal" name as well, for times that we're just + // depending on descriptor.proto instead of generating it. + return descriptor->name() == "google/protobuf/descriptor_proto_file.proto" + || descriptor->name() == "google/protobuf/descriptor.proto"; } inline bool IsWrapperType(const FieldDescriptor* descriptor) { diff --git a/src/google/protobuf/compiler/csharp/csharp_umbrella_class.cc b/src/google/protobuf/compiler/csharp/csharp_umbrella_class.cc index 0ffae3d4..399c64e1 100644 --- a/src/google/protobuf/compiler/csharp/csharp_umbrella_class.cc +++ b/src/google/protobuf/compiler/csharp/csharp_umbrella_class.cc @@ -180,10 +180,17 @@ void UmbrellaClassGenerator::WriteDescriptor(io::Printer* printer) { "descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,\n"); printer->Print(" new pbr::FileDescriptor[] { "); for (int i = 0; i < file_->dependency_count(); i++) { - printer->Print( + // descriptor.proto is special: we don't allow access to the generated code, but there's + // a separately-exposed property to get at the file descriptor, specifically to allow this + // kind of dependency. + if (IsDescriptorProto(file_->dependency(i))) { + printer->Print("pbr::FileDescriptor.DescriptorProtoFileDescriptor, "); + } else { + printer->Print( "$full_umbrella_class_name$.Descriptor, ", "full_umbrella_class_name", GetUmbrellaClassName(file_->dependency(i))); + } } printer->Print("},\n" " new pbr::GeneratedCodeInfo("); -- cgit v1.2.3