FindProtobuf.cmake 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450
  1. # Distributed under the OSI-approved BSD 3-Clause License. See accompanying
  2. # file Copyright.txt or https://cmake.org/licensing for details.
  3. #.rst:
  4. # FindProtobuf
  5. # ------------
  6. #
  7. # Locate and configure the Google Protocol Buffers library.
  8. #
  9. # The following variables can be set and are optional:
  10. #
  11. # ``Protobuf_SRC_ROOT_FOLDER``
  12. # When compiling with MSVC, if this cache variable is set
  13. # the protobuf-default VS project build locations
  14. # (vsprojects/Debug and vsprojects/Release
  15. # or vsprojects/x64/Debug and vsprojects/x64/Release)
  16. # will be searched for libraries and binaries.
  17. # ``Protobuf_IMPORT_DIRS``
  18. # List of additional directories to be searched for
  19. # imported .proto files.
  20. # ``Protobuf_DEBUG``
  21. # Show debug messages.
  22. # ``Protobuf_USE_STATIC_LIBS``
  23. # Set to ON to force the use of the static libraries.
  24. # Default is OFF.
  25. #
  26. # Defines the following variables:
  27. #
  28. # ``Protobuf_FOUND``
  29. # Found the Google Protocol Buffers library
  30. # (libprotobuf & header files)
  31. # ``Protobuf_VERSION``
  32. # Version of package found.
  33. # ``Protobuf_INCLUDE_DIRS``
  34. # Include directories for Google Protocol Buffers
  35. # ``Protobuf_LIBRARIES``
  36. # The protobuf libraries
  37. # ``Protobuf_PROTOC_LIBRARIES``
  38. # The protoc libraries
  39. # ``Protobuf_LITE_LIBRARIES``
  40. # The protobuf-lite libraries
  41. #
  42. # The following cache variables are also available to set or use:
  43. #
  44. # ``Protobuf_LIBRARY``
  45. # The protobuf library
  46. # ``Protobuf_PROTOC_LIBRARY``
  47. # The protoc library
  48. # ``Protobuf_INCLUDE_DIR``
  49. # The include directory for protocol buffers
  50. # ``Protobuf_PROTOC_EXECUTABLE``
  51. # The protoc compiler
  52. # ``Protobuf_LIBRARY_DEBUG``
  53. # The protobuf library (debug)
  54. # ``Protobuf_PROTOC_LIBRARY_DEBUG``
  55. # The protoc library (debug)
  56. # ``Protobuf_LITE_LIBRARY``
  57. # The protobuf lite library
  58. # ``Protobuf_LITE_LIBRARY_DEBUG``
  59. # The protobuf lite library (debug)
  60. #
  61. # Example:
  62. #
  63. # .. code-block:: cmake
  64. #
  65. # find_package(Protobuf REQUIRED)
  66. # include_directories(${Protobuf_INCLUDE_DIRS})
  67. # include_directories(${CMAKE_CURRENT_BINARY_DIR})
  68. # protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS foo.proto)
  69. # protobuf_generate_python(PROTO_PY foo.proto)
  70. # add_executable(bar bar.cc ${PROTO_SRCS} ${PROTO_HDRS})
  71. # target_link_libraries(bar ${Protobuf_LIBRARIES})
  72. #
  73. # .. note::
  74. # The ``protobuf_generate_cpp`` and ``protobuf_generate_python``
  75. # functions and :command:`add_executable` or :command:`add_library`
  76. # calls only work properly within the same directory.
  77. #
  78. # .. command:: protobuf_generate_cpp
  79. #
  80. # Add custom commands to process ``.proto`` files to C++::
  81. #
  82. # protobuf_generate_cpp (<SRCS> <HDRS> [<ARGN>...])
  83. #
  84. # ``SRCS``
  85. # Variable to define with autogenerated source files
  86. # ``HDRS``
  87. # Variable to define with autogenerated header files
  88. # ``ARGN``
  89. # ``.proto`` files
  90. #
  91. # .. command:: protobuf_generate_python
  92. #
  93. # Add custom commands to process ``.proto`` files to Python::
  94. #
  95. # protobuf_generate_python (<PY> [<ARGN>...])
  96. #
  97. # ``PY``
  98. # Variable to define with autogenerated Python files
  99. # ``ARGN``
  100. # ``.proto`` filess
  101. function(PROTOBUF_GENERATE_CPP SRCS HDRS)
  102. if(NOT ARGN)
  103. message(SEND_ERROR "Error: PROTOBUF_GENERATE_CPP() called without any proto files")
  104. return()
  105. endif()
  106. if(PROTOBUF_GENERATE_CPP_APPEND_PATH)
  107. # Create an include path for each file specified
  108. foreach(FIL ${ARGN})
  109. get_filename_component(ABS_FIL ${FIL} ABSOLUTE)
  110. get_filename_component(ABS_PATH ${ABS_FIL} PATH)
  111. list(FIND _protobuf_include_path ${ABS_PATH} _contains_already)
  112. if(${_contains_already} EQUAL -1)
  113. list(APPEND _protobuf_include_path -I ${ABS_PATH})
  114. endif()
  115. endforeach()
  116. else()
  117. set(_protobuf_include_path -I ${CMAKE_CURRENT_SOURCE_DIR})
  118. endif()
  119. if(DEFINED PROTOBUF_IMPORT_DIRS AND NOT DEFINED Protobuf_IMPORT_DIRS)
  120. set(Protobuf_IMPORT_DIRS "${PROTOBUF_IMPORT_DIRS}")
  121. endif()
  122. if(DEFINED Protobuf_IMPORT_DIRS)
  123. foreach(DIR ${Protobuf_IMPORT_DIRS})
  124. get_filename_component(ABS_PATH ${DIR} ABSOLUTE)
  125. list(FIND _protobuf_include_path ${ABS_PATH} _contains_already)
  126. if(${_contains_already} EQUAL -1)
  127. list(APPEND _protobuf_include_path -I ${ABS_PATH})
  128. endif()
  129. endforeach()
  130. endif()
  131. set(${SRCS})
  132. set(${HDRS})
  133. foreach(FIL ${ARGN})
  134. get_filename_component(ABS_FIL ${FIL} ABSOLUTE)
  135. get_filename_component(FIL_WE ${FIL} NAME_WE)
  136. if(NOT PROTOBUF_GENERATE_CPP_APPEND_PATH)
  137. get_filename_component(FIL_DIR ${FIL} DIRECTORY)
  138. if(FIL_DIR)
  139. set(FIL_WE "${FIL_DIR}/${FIL_WE}")
  140. endif()
  141. endif()
  142. list(APPEND ${SRCS} "${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.pb.cc")
  143. list(APPEND ${HDRS} "${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.pb.h")
  144. add_custom_command(
  145. OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.pb.cc"
  146. "${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.pb.h"
  147. COMMAND ${Protobuf_PROTOC_EXECUTABLE}
  148. ARGS --cpp_out ${CMAKE_CURRENT_BINARY_DIR} ${_protobuf_include_path} ${ABS_FIL}
  149. DEPENDS ${ABS_FIL} ${Protobuf_PROTOC_EXECUTABLE}
  150. COMMENT "Running C++ protocol buffer compiler on ${FIL}"
  151. VERBATIM )
  152. endforeach()
  153. set_source_files_properties(${${SRCS}} ${${HDRS}} PROPERTIES GENERATED TRUE)
  154. set(${SRCS} ${${SRCS}} PARENT_SCOPE)
  155. set(${HDRS} ${${HDRS}} PARENT_SCOPE)
  156. endfunction()
  157. function(PROTOBUF_GENERATE_PYTHON SRCS)
  158. if(NOT ARGN)
  159. message(SEND_ERROR "Error: PROTOBUF_GENERATE_PYTHON() called without any proto files")
  160. return()
  161. endif()
  162. if(PROTOBUF_GENERATE_CPP_APPEND_PATH)
  163. # Create an include path for each file specified
  164. foreach(FIL ${ARGN})
  165. get_filename_component(ABS_FIL ${FIL} ABSOLUTE)
  166. get_filename_component(ABS_PATH ${ABS_FIL} PATH)
  167. list(FIND _protobuf_include_path ${ABS_PATH} _contains_already)
  168. if(${_contains_already} EQUAL -1)
  169. list(APPEND _protobuf_include_path -I ${ABS_PATH})
  170. endif()
  171. endforeach()
  172. else()
  173. set(_protobuf_include_path -I ${CMAKE_CURRENT_SOURCE_DIR})
  174. endif()
  175. if(DEFINED PROTOBUF_IMPORT_DIRS AND NOT DEFINED Protobuf_IMPORT_DIRS)
  176. set(Protobuf_IMPORT_DIRS "${PROTOBUF_IMPORT_DIRS}")
  177. endif()
  178. if(DEFINED Protobuf_IMPORT_DIRS)
  179. foreach(DIR ${Protobuf_IMPORT_DIRS})
  180. get_filename_component(ABS_PATH ${DIR} ABSOLUTE)
  181. list(FIND _protobuf_include_path ${ABS_PATH} _contains_already)
  182. if(${_contains_already} EQUAL -1)
  183. list(APPEND _protobuf_include_path -I ${ABS_PATH})
  184. endif()
  185. endforeach()
  186. endif()
  187. set(${SRCS})
  188. foreach(FIL ${ARGN})
  189. get_filename_component(ABS_FIL ${FIL} ABSOLUTE)
  190. get_filename_component(FIL_WE ${FIL} NAME_WE)
  191. if(NOT PROTOBUF_GENERATE_CPP_APPEND_PATH)
  192. get_filename_component(FIL_DIR ${FIL} DIRECTORY)
  193. if(FIL_DIR)
  194. set(FIL_WE "${FIL_DIR}/${FIL_WE}")
  195. endif()
  196. endif()
  197. list(APPEND ${SRCS} "${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}_pb2.py")
  198. add_custom_command(
  199. OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}_pb2.py"
  200. COMMAND ${Protobuf_PROTOC_EXECUTABLE} --python_out ${CMAKE_CURRENT_BINARY_DIR} ${_protobuf_include_path} ${ABS_FIL}
  201. DEPENDS ${ABS_FIL} ${Protobuf_PROTOC_EXECUTABLE}
  202. COMMENT "Running Python protocol buffer compiler on ${FIL}"
  203. VERBATIM )
  204. endforeach()
  205. set(${SRCS} ${${SRCS}} PARENT_SCOPE)
  206. endfunction()
  207. if(Protobuf_DEBUG)
  208. # Output some of their choices
  209. message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] "
  210. "Protobuf_USE_STATIC_LIBS = ${Protobuf_USE_STATIC_LIBS}")
  211. endif()
  212. # Backwards compatibility
  213. # Define camel case versions of input variables
  214. foreach(UPPER
  215. PROTOBUF_SRC_ROOT_FOLDER
  216. PROTOBUF_IMPORT_DIRS
  217. PROTOBUF_DEBUG
  218. PROTOBUF_LIBRARY
  219. PROTOBUF_PROTOC_LIBRARY
  220. PROTOBUF_INCLUDE_DIR
  221. PROTOBUF_PROTOC_EXECUTABLE
  222. PROTOBUF_LIBRARY_DEBUG
  223. PROTOBUF_PROTOC_LIBRARY_DEBUG
  224. PROTOBUF_LITE_LIBRARY
  225. PROTOBUF_LITE_LIBRARY_DEBUG
  226. )
  227. if (DEFINED ${UPPER})
  228. string(REPLACE "PROTOBUF_" "Protobuf_" Camel ${UPPER})
  229. if (NOT DEFINED ${Camel})
  230. set(${Camel} ${${UPPER}})
  231. endif()
  232. endif()
  233. endforeach()
  234. if(CMAKE_SIZEOF_VOID_P EQUAL 8)
  235. set(_PROTOBUF_ARCH_DIR x64/)
  236. endif()
  237. # Support preference of static libs by adjusting CMAKE_FIND_LIBRARY_SUFFIXES
  238. if( Protobuf_USE_STATIC_LIBS )
  239. set( _protobuf_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
  240. if(WIN32)
  241. set(CMAKE_FIND_LIBRARY_SUFFIXES .lib .a ${CMAKE_FIND_LIBRARY_SUFFIXES})
  242. else()
  243. set(CMAKE_FIND_LIBRARY_SUFFIXES .a )
  244. endif()
  245. endif()
  246. include(${CMAKE_CURRENT_LIST_DIR}/SelectLibraryConfigurations.cmake)
  247. # Internal function: search for normal library as well as a debug one
  248. # if the debug one is specified also include debug/optimized keywords
  249. # in *_LIBRARIES variable
  250. function(_protobuf_find_libraries name filename)
  251. if(${name}_LIBRARIES)
  252. # Use result recorded by a previous call.
  253. return()
  254. elseif(${name}_LIBRARY)
  255. # Honor cache entry used by CMake 3.5 and lower.
  256. set(${name}_LIBRARIES "${${name}_LIBRARY}" PARENT_SCOPE)
  257. else()
  258. find_library(${name}_LIBRARY_RELEASE
  259. NAMES ${filename}
  260. PATHS ${Protobuf_SRC_ROOT_FOLDER}/vsprojects/${_PROTOBUF_ARCH_DIR}Release)
  261. mark_as_advanced(${name}_LIBRARY_RELEASE)
  262. find_library(${name}_LIBRARY_DEBUG
  263. NAMES ${filename}d ${filename}
  264. PATHS ${Protobuf_SRC_ROOT_FOLDER}/vsprojects/${_PROTOBUF_ARCH_DIR}Debug)
  265. mark_as_advanced(${name}_LIBRARY_DEBUG)
  266. select_library_configurations(${name})
  267. set(${name}_LIBRARY "${${name}_LIBRARY}" PARENT_SCOPE)
  268. set(${name}_LIBRARIES "${${name}_LIBRARIES}" PARENT_SCOPE)
  269. endif()
  270. endfunction()
  271. # Internal function: find threads library
  272. function(_protobuf_find_threads)
  273. set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
  274. find_package(Threads)
  275. if(Threads_FOUND)
  276. list(APPEND Protobuf_LIBRARIES ${CMAKE_THREAD_LIBS_INIT})
  277. set(Protobuf_LIBRARIES "${Protobuf_LIBRARIES}" PARENT_SCOPE)
  278. endif()
  279. endfunction()
  280. #
  281. # Main.
  282. #
  283. # By default have PROTOBUF_GENERATE_CPP macro pass -I to protoc
  284. # for each directory where a proto file is referenced.
  285. if(NOT DEFINED PROTOBUF_GENERATE_CPP_APPEND_PATH)
  286. set(PROTOBUF_GENERATE_CPP_APPEND_PATH TRUE)
  287. endif()
  288. # Google's provided vcproj files generate libraries with a "lib"
  289. # prefix on Windows
  290. if(MSVC)
  291. set(Protobuf_ORIG_FIND_LIBRARY_PREFIXES "${CMAKE_FIND_LIBRARY_PREFIXES}")
  292. set(CMAKE_FIND_LIBRARY_PREFIXES "lib" "")
  293. find_path(Protobuf_SRC_ROOT_FOLDER protobuf.pc.in)
  294. endif()
  295. # The Protobuf library
  296. _protobuf_find_libraries(Protobuf protobuf)
  297. #DOC "The Google Protocol Buffers RELEASE Library"
  298. _protobuf_find_libraries(Protobuf_LITE protobuf-lite)
  299. # The Protobuf Protoc Library
  300. _protobuf_find_libraries(Protobuf_PROTOC protoc)
  301. # Restore original find library prefixes
  302. if(MSVC)
  303. set(CMAKE_FIND_LIBRARY_PREFIXES "${Protobuf_ORIG_FIND_LIBRARY_PREFIXES}")
  304. endif()
  305. if(UNIX)
  306. _protobuf_find_threads()
  307. endif()
  308. # Find the include directory
  309. find_path(Protobuf_INCLUDE_DIR
  310. google/protobuf/service.h
  311. PATHS ${Protobuf_SRC_ROOT_FOLDER}/src
  312. )
  313. mark_as_advanced(Protobuf_INCLUDE_DIR)
  314. # Find the protoc Executable
  315. find_program(Protobuf_PROTOC_EXECUTABLE
  316. NAMES protoc
  317. DOC "The Google Protocol Buffers Compiler"
  318. PATHS
  319. ${Protobuf_SRC_ROOT_FOLDER}/vsprojects/${_PROTOBUF_ARCH_DIR}Release
  320. ${Protobuf_SRC_ROOT_FOLDER}/vsprojects/${_PROTOBUF_ARCH_DIR}Debug
  321. )
  322. mark_as_advanced(Protobuf_PROTOC_EXECUTABLE)
  323. if(Protobuf_DEBUG)
  324. message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] "
  325. "requested version of Google Protobuf is ${Protobuf_FIND_VERSION}")
  326. endif()
  327. if(Protobuf_INCLUDE_DIR)
  328. set(_PROTOBUF_COMMON_HEADER ${Protobuf_INCLUDE_DIR}/google/protobuf/stubs/common.h)
  329. if(Protobuf_DEBUG)
  330. message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] "
  331. "location of common.h: ${_PROTOBUF_COMMON_HEADER}")
  332. endif()
  333. set(Protobuf_VERSION "")
  334. set(Protobuf_LIB_VERSION "")
  335. file(STRINGS ${_PROTOBUF_COMMON_HEADER} _PROTOBUF_COMMON_H_CONTENTS REGEX "#define[ \t]+GOOGLE_PROTOBUF_VERSION[ \t]+")
  336. if(_PROTOBUF_COMMON_H_CONTENTS MATCHES "#define[ \t]+GOOGLE_PROTOBUF_VERSION[ \t]+([0-9]+)")
  337. set(Protobuf_LIB_VERSION "${CMAKE_MATCH_1}")
  338. endif()
  339. unset(_PROTOBUF_COMMON_H_CONTENTS)
  340. math(EXPR _PROTOBUF_MAJOR_VERSION "${Protobuf_LIB_VERSION} / 1000000")
  341. math(EXPR _PROTOBUF_MINOR_VERSION "${Protobuf_LIB_VERSION} / 1000 % 1000")
  342. math(EXPR _PROTOBUF_SUBMINOR_VERSION "${Protobuf_LIB_VERSION} % 1000")
  343. set(Protobuf_VERSION "${_PROTOBUF_MAJOR_VERSION}.${_PROTOBUF_MINOR_VERSION}.${_PROTOBUF_SUBMINOR_VERSION}")
  344. if(Protobuf_DEBUG)
  345. message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] "
  346. "${_PROTOBUF_COMMON_HEADER} reveals protobuf ${Protobuf_VERSION}")
  347. endif()
  348. # Check Protobuf compiler version to be aligned with libraries version
  349. execute_process(COMMAND ${Protobuf_PROTOC_EXECUTABLE} --version
  350. OUTPUT_VARIABLE _PROTOBUF_PROTOC_EXECUTABLE_VERSION)
  351. if("${_PROTOBUF_PROTOC_EXECUTABLE_VERSION}" MATCHES "libprotoc ([0-9.]+)")
  352. set(_PROTOBUF_PROTOC_EXECUTABLE_VERSION "${CMAKE_MATCH_1}")
  353. endif()
  354. if(Protobuf_DEBUG)
  355. message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] "
  356. "${Protobuf_PROTOC_EXECUTABLE} reveals version ${_PROTOBUF_PROTOC_EXECUTABLE_VERSION}")
  357. endif()
  358. if(NOT "${_PROTOBUF_PROTOC_EXECUTABLE_VERSION}" VERSION_EQUAL "${Protobuf_VERSION}")
  359. message(WARNING "Protobuf compiler version ${_PROTOBUF_PROTOC_EXECUTABLE_VERSION}"
  360. " doesn't match library version ${Protobuf_VERSION}")
  361. endif()
  362. endif()
  363. include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
  364. FIND_PACKAGE_HANDLE_STANDARD_ARGS(Protobuf
  365. REQUIRED_VARS Protobuf_LIBRARIES Protobuf_INCLUDE_DIR
  366. VERSION_VAR Protobuf_VERSION
  367. )
  368. if(Protobuf_FOUND)
  369. set(Protobuf_INCLUDE_DIRS ${Protobuf_INCLUDE_DIR})
  370. endif()
  371. # Restore the original find library ordering
  372. if( Protobuf_USE_STATIC_LIBS )
  373. set(CMAKE_FIND_LIBRARY_SUFFIXES ${_protobuf_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES})
  374. endif()
  375. # Backwards compatibility
  376. # Define upper case versions of output variables
  377. foreach(Camel
  378. Protobuf_SRC_ROOT_FOLDER
  379. Protobuf_IMPORT_DIRS
  380. Protobuf_DEBUG
  381. Protobuf_INCLUDE_DIRS
  382. Protobuf_LIBRARIES
  383. Protobuf_PROTOC_LIBRARIES
  384. Protobuf_LITE_LIBRARIES
  385. Protobuf_LIBRARY
  386. Protobuf_PROTOC_LIBRARY
  387. Protobuf_INCLUDE_DIR
  388. Protobuf_PROTOC_EXECUTABLE
  389. Protobuf_LIBRARY_DEBUG
  390. Protobuf_PROTOC_LIBRARY_DEBUG
  391. Protobuf_LITE_LIBRARY
  392. Protobuf_LITE_LIBRARY_DEBUG
  393. )
  394. string(TOUPPER ${Camel} UPPER)
  395. set(${UPPER} ${${Camel}})
  396. endforeach()