CMake自动按目录结构编译Protobuf代码
在使用CMake构建C++项目时,如果有使用Protobuf,CMake提供了一个FindProtobuf.cmake
模块来处理PB,其使用方法如下:
1find_package(Protobuf REQUIRED)
2protobuf_generate_cpp(GENERATED_SRC GENERATED_HEADER "pb/t.proto" "pb.proto")
3
4add_executable(${PROJECT_NAME} main.cpp ${GENERATED_SRC})
5target_link_libraries(${PROJECT_NAME} PRIVATE Protobuf)
在构建项目时,会自动生成编译proto为相应的C++代码,包括头文件。
但是CMake自带的FindProtobuf.cmake
模块会把所有生成的C++文件放在${CMAKE_CURRENT_BINARY_DIR}
目录下,会导致项目中所有proto文件名不能重复,否则会出问题。同时,该模块也只能将Proto编译成C++以及Python,如果想要编译其它的则不支持。
笔者经过一番研究,把它改成可以根据Proto的目录结构生成到${CMAKE_CURRENT_BINARY_DIR}
目录下对应的目录中。
只需要修改一下protobuf_generate
函数即可。即根据每个proto文件的路径获取相对路径,在${CMAKE_CURRENT_BINARY_DIR}
目录下创建好目录,在使用protoc时指定工作目录为该目录。
可以看一下对比:
为了让protobuf_generate
函数支持生成C代码(使用protoc-c
插件生成),做如下修改:
1if(NOT protobuf_generate_GENERATE_EXTENSIONS)
2 if(protobuf_generate_LANGUAGE STREQUAL cpp)
3 set(protobuf_generate_GENERATE_EXTENSIONS .pb.h .pb.cc)
4 elseif(protobuf_generate_LANGUAGE STREQUAL c)
5 set(protobuf_generate_GENERATE_EXTENSIONS .pb-c.h .pb-c.c)
6 elseif(protobuf_generate_LANGUAGE STREQUAL python)
7 set(protobuf_generate_GENERATE_EXTENSIONS _pb2.py)
8 else()
9 message(SEND_ERROR "Error: protobuf_generate given unknown Language ${LANGUAGE}, please provide a value for GENERATE_EXTENSIONS")
10 return()
11 endif()
12 endif()
添加PROTOBUF_GENERATE_C
函数:
1function(PROTOBUF_GENERATE_C SRCS HDRS)
2 cmake_parse_arguments(protobuf_generate_c "" "EXPORT_MACRO;DESCRIPTORS" "" ${ARGN})
3
4 set(_proto_files "${protobuf_generate_c_UNPARSED_ARGUMENTS}")
5 if(NOT _proto_files)
6 message(SEND_ERROR "Error: PROTOBUF_GENERATE_C() called without any proto files")
7 return()
8 endif()
9
10 if(PROTOBUF_GENERATE_CPP_APPEND_PATH)
11 set(_append_arg APPEND_PATH)
12 endif()
13
14 if(protobuf_generate_c_DESCRIPTORS)
15 set(_descriptors DESCRIPTORS)
16 endif()
17
18 if(DEFINED PROTOBUF_IMPORT_DIRS AND NOT DEFINED Protobuf_IMPORT_DIRS)
19 set(Protobuf_IMPORT_DIRS "${PROTOBUF_IMPORT_DIRS}")
20 endif()
21
22 if(DEFINED Protobuf_IMPORT_DIRS)
23 set(_import_arg IMPORT_DIRS ${Protobuf_IMPORT_DIRS})
24 endif()
25
26 set(_outvar)
27 protobuf_generate(${_append_arg} ${_descriptors} LANGUAGE c EXPORT_MACRO ${protobuf_generate_c_EXPORT_MACRO} OUT_VAR _outvar ${_import_arg} PROTOS ${_proto_files})
28
29 set(${SRCS})
30 set(${HDRS})
31 if(protobuf_generate_c_DESCRIPTORS)
32 set(${protobuf_generate_c_DESCRIPTORS})
33 endif()
34
35 foreach(_file ${_outvar})
36 if(_file MATCHES "c$")
37 list(APPEND ${SRCS} ${_file})
38 elseif(_file MATCHES "desc$")
39 list(APPEND ${protobuf_generate_c_DESCRIPTORS} ${_file})
40 else()
41 list(APPEND ${HDRS} ${_file})
42 endif()
43 endforeach()
44 set(${SRCS} ${${SRCS}} PARENT_SCOPE)
45 set(${HDRS} ${${HDRS}} PARENT_SCOPE)
46 if(protobuf_generate_c_DESCRIPTORS)
47 set(${protobuf_generate_c_DESCRIPTORS} "${${protobuf_generate_c_DESCRIPTORS}}" PARENT_SCOPE)
48 endif()
49endfunction()
MinGW下需要安装protobuf
和protobuf-c
插件:
1pacman -S mingw-w64-x86_64-protobuf
2pacman -S mingw-w64-x86_64-protobuf-c
测试效果:
为了不修改原来的FindProtobuf.cmake
文件,建议重新保存一份到项目中,比如命名为proto.cmake
,为此还需要修改一下里面使用的include的路径:
即将${CMAKE_CURRENT_LIST_DIR}
替换为${CMAKE_ROOT}/Modules
。
项目中使用示例:
1include(proto.cmake)
2protobuf_generate_c(GENERATED_CPP_SRC GENERATED_CPP_HEADER "src/pb/t.proto" "src/pb/x.proto" "a.proto")
3protobuf_generate_cpp(GENERATED_C_SRC GENERATED_C_HEADER "src/pb/t.proto" "src/pb/x.proto" "a.proto")
4
5add_executable(${PROJECT_NAME} main.c ${GENERATED_CPP_SRC} ${GENERATED_C_SRC})
附上修改后的FindProtobuf.cmake
源码:
1# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
2# file Copyright.txt or https://cmake.org/licensing for details.
3
4#[=======================================================================[.rst:
5FindProtobuf
6------------
7
8Locate and configure the Google Protocol Buffers library.
9
10.. versionadded:: 3.6
11 Support for :command:`find_package` version checks.
12
13.. versionchanged:: 3.6
14 All input and output variables use the ``Protobuf_`` prefix.
15 Variables with ``PROTOBUF_`` prefix are still supported for compatibility.
16
17The following variables can be set and are optional:
18
19``Protobuf_SRC_ROOT_FOLDER``
20 When compiling with MSVC, if this cache variable is set
21 the protobuf-default VS project build locations
22 (vsprojects/Debug and vsprojects/Release
23 or vsprojects/x64/Debug and vsprojects/x64/Release)
24 will be searched for libraries and binaries.
25``Protobuf_IMPORT_DIRS``
26 List of additional directories to be searched for
27 imported .proto files.
28``Protobuf_DEBUG``
29 .. versionadded:: 3.6
30
31 Show debug messages.
32``Protobuf_USE_STATIC_LIBS``
33 .. versionadded:: 3.9
34
35 Set to ON to force the use of the static libraries.
36 Default is OFF.
37
38Defines the following variables:
39
40``Protobuf_FOUND``
41 Found the Google Protocol Buffers library
42 (libprotobuf & header files)
43``Protobuf_VERSION``
44 .. versionadded:: 3.6
45
46 Version of package found.
47``Protobuf_INCLUDE_DIRS``
48 Include directories for Google Protocol Buffers
49``Protobuf_LIBRARIES``
50 The protobuf libraries
51``Protobuf_PROTOC_LIBRARIES``
52 The protoc libraries
53``Protobuf_LITE_LIBRARIES``
54 The protobuf-lite libraries
55
56.. versionadded:: 3.9
57 The following :prop_tgt:`IMPORTED` targets are also defined:
58
59``protobuf::libprotobuf``
60 The protobuf library.
61``protobuf::libprotobuf-lite``
62 The protobuf lite library.
63``protobuf::libprotoc``
64 The protoc library.
65``protobuf::protoc``
66 .. versionadded:: 3.10
67 The protoc compiler.
68
69The following cache variables are also available to set or use:
70
71``Protobuf_LIBRARY``
72 The protobuf library
73``Protobuf_PROTOC_LIBRARY``
74 The protoc library
75``Protobuf_INCLUDE_DIR``
76 The include directory for protocol buffers
77``Protobuf_PROTOC_EXECUTABLE``
78 The protoc compiler
79``Protobuf_LIBRARY_DEBUG``
80 The protobuf library (debug)
81``Protobuf_PROTOC_LIBRARY_DEBUG``
82 The protoc library (debug)
83``Protobuf_LITE_LIBRARY``
84 The protobuf lite library
85``Protobuf_LITE_LIBRARY_DEBUG``
86 The protobuf lite library (debug)
87
88Example:
89
90.. code-block:: cmake
91
92 find_package(Protobuf REQUIRED)
93 include_directories(${Protobuf_INCLUDE_DIRS})
94 include_directories(${CMAKE_CURRENT_BINARY_DIR})
95 protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS foo.proto)
96 protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS EXPORT_MACRO DLL_EXPORT foo.proto)
97 protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS DESCRIPTORS PROTO_DESCS foo.proto)
98 protobuf_generate_python(PROTO_PY foo.proto)
99 add_executable(bar bar.cc ${PROTO_SRCS} ${PROTO_HDRS})
100 target_link_libraries(bar ${Protobuf_LIBRARIES})
101
102.. note::
103 The ``protobuf_generate_cpp`` and ``protobuf_generate_python``
104 functions and :command:`add_executable` or :command:`add_library`
105 calls only work properly within the same directory.
106
107.. command:: protobuf_generate_cpp
108
109 Add custom commands to process ``.proto`` files to C++::
110
111 protobuf_generate_cpp (<SRCS> <HDRS>
112 [DESCRIPTORS <DESC>] [EXPORT_MACRO <MACRO>] [<ARGN>...])
113
114 ``SRCS``
115 Variable to define with autogenerated source files
116 ``HDRS``
117 Variable to define with autogenerated header files
118 ``DESCRIPTORS``
119 .. versionadded:: 3.10
120 Variable to define with autogenerated descriptor files, if requested.
121 ``EXPORT_MACRO``
122 is a macro which should expand to ``__declspec(dllexport)`` or
123 ``__declspec(dllimport)`` depending on what is being compiled.
124 ``ARGN``
125 ``.proto`` files
126
127.. command:: protobuf_generate_python
128
129 .. versionadded:: 3.4
130
131 Add custom commands to process ``.proto`` files to Python::
132
133 protobuf_generate_python (<PY> [<ARGN>...])
134
135 ``PY``
136 Variable to define with autogenerated Python files
137 ``ARGN``
138 ``.proto`` files
139#]=======================================================================]
140
141function(protobuf_generate)
142 set(_options APPEND_PATH DESCRIPTORS)
143 set(_singleargs LANGUAGE OUT_VAR EXPORT_MACRO PROTOC_OUT_DIR PLUGIN)
144 if(COMMAND target_sources)
145 list(APPEND _singleargs TARGET)
146 endif()
147 set(_multiargs PROTOS IMPORT_DIRS GENERATE_EXTENSIONS)
148
149 cmake_parse_arguments(protobuf_generate "${_options}" "${_singleargs}" "${_multiargs}" "${ARGN}")
150
151 if(NOT protobuf_generate_PROTOS AND NOT protobuf_generate_TARGET)
152 message(SEND_ERROR "Error: protobuf_generate called without any targets or source files")
153 return()
154 endif()
155
156 if(NOT protobuf_generate_OUT_VAR AND NOT protobuf_generate_TARGET)
157 message(SEND_ERROR "Error: protobuf_generate called without a target or output variable")
158 return()
159 endif()
160
161 if(NOT protobuf_generate_LANGUAGE)
162 set(protobuf_generate_LANGUAGE cpp)
163 endif()
164 string(TOLOWER ${protobuf_generate_LANGUAGE} protobuf_generate_LANGUAGE)
165
166 if(NOT protobuf_generate_PROTOC_OUT_DIR)
167 set(protobuf_generate_PROTOC_OUT_DIR ${CMAKE_CURRENT_BINARY_DIR})
168 endif()
169
170 if(protobuf_generate_EXPORT_MACRO AND protobuf_generate_LANGUAGE STREQUAL cpp)
171 set(_dll_export_decl "dllexport_decl=${protobuf_generate_EXPORT_MACRO}:")
172 endif()
173
174 if(protobuf_generate_PLUGIN)
175 set(_plugin "--plugin=${protobuf_generate_PLUGIN}")
176 endif()
177
178 if(NOT protobuf_generate_GENERATE_EXTENSIONS)
179 if(protobuf_generate_LANGUAGE STREQUAL cpp)
180 set(protobuf_generate_GENERATE_EXTENSIONS .pb.h .pb.cc)
181 elseif(protobuf_generate_LANGUAGE STREQUAL c)
182 set(protobuf_generate_GENERATE_EXTENSIONS .pb-c.h .pb-c.c)
183 elseif(protobuf_generate_LANGUAGE STREQUAL python)
184 set(protobuf_generate_GENERATE_EXTENSIONS _pb2.py)
185 else()
186 message(SEND_ERROR "Error: protobuf_generate given unknown Language ${LANGUAGE}, please provide a value for GENERATE_EXTENSIONS")
187 return()
188 endif()
189 endif()
190
191 if(protobuf_generate_TARGET)
192 get_target_property(_source_list ${protobuf_generate_TARGET} SOURCES)
193 foreach(_file ${_source_list})
194 if(_file MATCHES "proto$")
195 list(APPEND protobuf_generate_PROTOS ${_file})
196 endif()
197 endforeach()
198 endif()
199
200 if(NOT protobuf_generate_PROTOS)
201 message(SEND_ERROR "Error: protobuf_generate could not find any .proto files")
202 return()
203 endif()
204
205 if(protobuf_generate_APPEND_PATH)
206 # Create an include path for each file specified
207 foreach(_file ${protobuf_generate_PROTOS})
208 get_filename_component(_abs_file ${_file} ABSOLUTE)
209 get_filename_component(_abs_path ${_abs_file} PATH)
210 list(FIND _protobuf_include_path ${_abs_path} _contains_already)
211 if(${_contains_already} EQUAL -1)
212 list(APPEND _protobuf_include_path -I ${_abs_path})
213 endif()
214 endforeach()
215 else()
216 set(_protobuf_include_path -I ${CMAKE_CURRENT_SOURCE_DIR})
217 endif()
218
219 foreach(DIR ${protobuf_generate_IMPORT_DIRS})
220 get_filename_component(ABS_PATH ${DIR} ABSOLUTE)
221 list(FIND _protobuf_include_path ${ABS_PATH} _contains_already)
222 if(${_contains_already} EQUAL -1)
223 list(APPEND _protobuf_include_path -I ${ABS_PATH})
224 endif()
225 endforeach()
226
227 set(_generated_srcs_all)
228 foreach(_proto ${protobuf_generate_PROTOS})
229 get_filename_component(_abs_file ${_proto} ABSOLUTE)
230 get_filename_component(_abs_dir ${_abs_file} DIRECTORY)
231 get_filename_component(_basename ${_proto} NAME_WLE)
232 file(RELATIVE_PATH _rel_dir ${CMAKE_CURRENT_SOURCE_DIR} ${_abs_dir})
233
234 set(_possible_rel_dir)
235 if (NOT protobuf_generate_APPEND_PATH)
236 set(_possible_rel_dir ${_rel_dir}/)
237 endif()
238
239 set(RelDir)
240 if (NOT ${_rel_dir} STREQUAL "")
241 set(RelDir /${_rel_dir})
242 file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}${RelDir})
243 endif()
244
245 set(_generated_srcs)
246 if (protobuf_generate_APPEND_PATH)
247 foreach(_ext ${protobuf_generate_GENERATE_EXTENSIONS})
248 list(APPEND _generated_srcs "${protobuf_generate_PROTOC_OUT_DIR}${RelDir}/${_basename}${_ext}")
249 endforeach()
250 else()
251 foreach(_ext ${protobuf_generate_GENERATE_EXTENSIONS})
252 list(APPEND _generated_srcs "${protobuf_generate_PROTOC_OUT_DIR}/${_possible_rel_dir}${_basename}${_ext}")
253 endforeach()
254 endif()
255
256 if(protobuf_generate_DESCRIPTORS AND protobuf_generate_LANGUAGE STREQUAL cpp)
257 set(_descriptor_file "${CMAKE_CURRENT_BINARY_DIR}/${_basename}.desc")
258 set(_dll_desc_out "--descriptor_set_out=${_descriptor_file}")
259 list(APPEND _generated_srcs ${_descriptor_file})
260 endif()
261 list(APPEND _generated_srcs_all ${_generated_srcs})
262
263 add_custom_command(
264 OUTPUT ${_generated_srcs}
265 COMMAND protobuf::protoc
266 ARGS --${protobuf_generate_LANGUAGE}_out ${_dll_export_decl}${protobuf_generate_PROTOC_OUT_DIR}${RelDir} ${_plugin} ${_dll_desc_out} ${_protobuf_include_path} ${_abs_file}
267 DEPENDS ${_abs_file} protobuf::protoc
268 WORKING_DIRECTORY ${protobuf_generate_PROTOC_OUT_DIR}${RelDir}
269 COMMENT "Running ${protobuf_generate_LANGUAGE} protocol buffer compiler on ${_proto}"
270 VERBATIM )
271 endforeach()
272
273 set_source_files_properties(${_generated_srcs_all} PROPERTIES GENERATED TRUE)
274 if(protobuf_generate_OUT_VAR)
275 set(${protobuf_generate_OUT_VAR} ${_generated_srcs_all} PARENT_SCOPE)
276 endif()
277 if(protobuf_generate_TARGET)
278 target_sources(${protobuf_generate_TARGET} PRIVATE ${_generated_srcs_all})
279 endif()
280endfunction()
281
282function(PROTOBUF_GENERATE_C SRCS HDRS)
283 cmake_parse_arguments(protobuf_generate_c "" "EXPORT_MACRO;DESCRIPTORS" "" ${ARGN})
284
285 set(_proto_files "${protobuf_generate_c_UNPARSED_ARGUMENTS}")
286 if(NOT _proto_files)
287 message(SEND_ERROR "Error: PROTOBUF_GENERATE_C() called without any proto files")
288 return()
289 endif()
290
291 if(PROTOBUF_GENERATE_CPP_APPEND_PATH)
292 set(_append_arg APPEND_PATH)
293 endif()
294
295 if(protobuf_generate_c_DESCRIPTORS)
296 set(_descriptors DESCRIPTORS)
297 endif()
298
299 if(DEFINED PROTOBUF_IMPORT_DIRS AND NOT DEFINED Protobuf_IMPORT_DIRS)
300 set(Protobuf_IMPORT_DIRS "${PROTOBUF_IMPORT_DIRS}")
301 endif()
302
303 if(DEFINED Protobuf_IMPORT_DIRS)
304 set(_import_arg IMPORT_DIRS ${Protobuf_IMPORT_DIRS})
305 endif()
306
307 set(_outvar)
308 protobuf_generate(${_append_arg} ${_descriptors} LANGUAGE c EXPORT_MACRO ${protobuf_generate_c_EXPORT_MACRO} OUT_VAR _outvar ${_import_arg} PROTOS ${_proto_files})
309
310 set(${SRCS})
311 set(${HDRS})
312 if(protobuf_generate_c_DESCRIPTORS)
313 set(${protobuf_generate_c_DESCRIPTORS})
314 endif()
315
316 foreach(_file ${_outvar})
317 if(_file MATCHES "c$")
318 list(APPEND ${SRCS} ${_file})
319 elseif(_file MATCHES "desc$")
320 list(APPEND ${protobuf_generate_c_DESCRIPTORS} ${_file})
321 else()
322 list(APPEND ${HDRS} ${_file})
323 endif()
324 endforeach()
325 set(${SRCS} ${${SRCS}} PARENT_SCOPE)
326 set(${HDRS} ${${HDRS}} PARENT_SCOPE)
327 if(protobuf_generate_c_DESCRIPTORS)
328 set(${protobuf_generate_c_DESCRIPTORS} "${${protobuf_generate_c_DESCRIPTORS}}" PARENT_SCOPE)
329 endif()
330endfunction()
331
332function(PROTOBUF_GENERATE_CPP SRCS HDRS)
333 cmake_parse_arguments(protobuf_generate_cpp "" "EXPORT_MACRO;DESCRIPTORS" "" ${ARGN})
334
335 set(_proto_files "${protobuf_generate_cpp_UNPARSED_ARGUMENTS}")
336 if(NOT _proto_files)
337 message(SEND_ERROR "Error: PROTOBUF_GENERATE_CPP() called without any proto files")
338 return()
339 endif()
340
341 if(PROTOBUF_GENERATE_CPP_APPEND_PATH)
342 set(_append_arg APPEND_PATH)
343 endif()
344
345 if(protobuf_generate_cpp_DESCRIPTORS)
346 set(_descriptors DESCRIPTORS)
347 endif()
348
349 if(DEFINED PROTOBUF_IMPORT_DIRS AND NOT DEFINED Protobuf_IMPORT_DIRS)
350 set(Protobuf_IMPORT_DIRS "${PROTOBUF_IMPORT_DIRS}")
351 endif()
352
353 if(DEFINED Protobuf_IMPORT_DIRS)
354 set(_import_arg IMPORT_DIRS ${Protobuf_IMPORT_DIRS})
355 endif()
356
357 set(_outvar)
358 protobuf_generate(${_append_arg} ${_descriptors} LANGUAGE cpp EXPORT_MACRO ${protobuf_generate_cpp_EXPORT_MACRO} OUT_VAR _outvar ${_import_arg} PROTOS ${_proto_files})
359
360 set(${SRCS})
361 set(${HDRS})
362 if(protobuf_generate_cpp_DESCRIPTORS)
363 set(${protobuf_generate_cpp_DESCRIPTORS})
364 endif()
365
366 foreach(_file ${_outvar})
367 if(_file MATCHES "cc$")
368 list(APPEND ${SRCS} ${_file})
369 elseif(_file MATCHES "desc$")
370 list(APPEND ${protobuf_generate_cpp_DESCRIPTORS} ${_file})
371 else()
372 list(APPEND ${HDRS} ${_file})
373 endif()
374 endforeach()
375 set(${SRCS} ${${SRCS}} PARENT_SCOPE)
376 set(${HDRS} ${${HDRS}} PARENT_SCOPE)
377 if(protobuf_generate_cpp_DESCRIPTORS)
378 set(${protobuf_generate_cpp_DESCRIPTORS} "${${protobuf_generate_cpp_DESCRIPTORS}}" PARENT_SCOPE)
379 endif()
380endfunction()
381
382function(PROTOBUF_GENERATE_PYTHON SRCS)
383 if(NOT ARGN)
384 message(SEND_ERROR "Error: PROTOBUF_GENERATE_PYTHON() called without any proto files")
385 return()
386 endif()
387
388 if(PROTOBUF_GENERATE_CPP_APPEND_PATH)
389 set(_append_arg APPEND_PATH)
390 endif()
391
392 if(DEFINED PROTOBUF_IMPORT_DIRS AND NOT DEFINED Protobuf_IMPORT_DIRS)
393 set(Protobuf_IMPORT_DIRS "${PROTOBUF_IMPORT_DIRS}")
394 endif()
395
396 if(DEFINED Protobuf_IMPORT_DIRS)
397 set(_import_arg IMPORT_DIRS ${Protobuf_IMPORT_DIRS})
398 endif()
399
400 set(_outvar)
401 protobuf_generate(${_append_arg} LANGUAGE python OUT_VAR _outvar ${_import_arg} PROTOS ${ARGN})
402 set(${SRCS} ${_outvar} PARENT_SCOPE)
403endfunction()
404
405
406if(Protobuf_DEBUG)
407 # Output some of their choices
408 message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] "
409 "Protobuf_USE_STATIC_LIBS = ${Protobuf_USE_STATIC_LIBS}")
410endif()
411
412
413# Backwards compatibility
414# Define camel case versions of input variables
415foreach(UPPER
416 PROTOBUF_SRC_ROOT_FOLDER
417 PROTOBUF_IMPORT_DIRS
418 PROTOBUF_DEBUG
419 PROTOBUF_LIBRARY
420 PROTOBUF_PROTOC_LIBRARY
421 PROTOBUF_INCLUDE_DIR
422 PROTOBUF_PROTOC_EXECUTABLE
423 PROTOBUF_LIBRARY_DEBUG
424 PROTOBUF_PROTOC_LIBRARY_DEBUG
425 PROTOBUF_LITE_LIBRARY
426 PROTOBUF_LITE_LIBRARY_DEBUG
427 )
428 if (DEFINED ${UPPER})
429 string(REPLACE "PROTOBUF_" "Protobuf_" Camel ${UPPER})
430 if (NOT DEFINED ${Camel})
431 set(${Camel} ${${UPPER}})
432 endif()
433 endif()
434endforeach()
435
436if(CMAKE_SIZEOF_VOID_P EQUAL 8)
437 set(_PROTOBUF_ARCH_DIR x64/)
438endif()
439
440
441# Support preference of static libs by adjusting CMAKE_FIND_LIBRARY_SUFFIXES
442if( Protobuf_USE_STATIC_LIBS )
443 set( _protobuf_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
444 if(WIN32)
445 set(CMAKE_FIND_LIBRARY_SUFFIXES .lib .a ${CMAKE_FIND_LIBRARY_SUFFIXES})
446 else()
447 set(CMAKE_FIND_LIBRARY_SUFFIXES .a )
448 endif()
449endif()
450
451include(${CMAKE_ROOT}/Modules/SelectLibraryConfigurations.cmake)
452
453# Internal function: search for normal library as well as a debug one
454# if the debug one is specified also include debug/optimized keywords
455# in *_LIBRARIES variable
456function(_protobuf_find_libraries name filename)
457 if(${name}_LIBRARIES)
458 # Use result recorded by a previous call.
459 return()
460 elseif(${name}_LIBRARY)
461 # Honor cache entry used by CMake 3.5 and lower.
462 set(${name}_LIBRARIES "${${name}_LIBRARY}" PARENT_SCOPE)
463 else()
464 find_library(${name}_LIBRARY_RELEASE
465 NAMES ${filename}
466 NAMES_PER_DIR
467 PATHS ${Protobuf_SRC_ROOT_FOLDER}/vsprojects/${_PROTOBUF_ARCH_DIR}Release)
468 mark_as_advanced(${name}_LIBRARY_RELEASE)
469
470 find_library(${name}_LIBRARY_DEBUG
471 NAMES ${filename}d ${filename}
472 NAMES_PER_DIR
473 PATHS ${Protobuf_SRC_ROOT_FOLDER}/vsprojects/${_PROTOBUF_ARCH_DIR}Debug)
474 mark_as_advanced(${name}_LIBRARY_DEBUG)
475
476 select_library_configurations(${name})
477
478 if(UNIX AND Threads_FOUND AND ${name}_LIBRARY)
479 list(APPEND ${name}_LIBRARIES ${CMAKE_THREAD_LIBS_INIT})
480 endif()
481
482 set(${name}_LIBRARY "${${name}_LIBRARY}" PARENT_SCOPE)
483 set(${name}_LIBRARIES "${${name}_LIBRARIES}" PARENT_SCOPE)
484 endif()
485endfunction()
486
487#
488# Main.
489#
490
491# By default have PROTOBUF_GENERATE_CPP macro pass -I to protoc
492# for each directory where a proto file is referenced.
493if(NOT DEFINED PROTOBUF_GENERATE_CPP_APPEND_PATH)
494 set(PROTOBUF_GENERATE_CPP_APPEND_PATH TRUE)
495endif()
496
497
498# Google's provided vcproj files generate libraries with a "lib"
499# prefix on Windows
500if(MSVC)
501 set(Protobuf_ORIG_FIND_LIBRARY_PREFIXES "${CMAKE_FIND_LIBRARY_PREFIXES}")
502 set(CMAKE_FIND_LIBRARY_PREFIXES "lib" "")
503
504 find_path(Protobuf_SRC_ROOT_FOLDER protobuf.pc.in)
505endif()
506
507if(UNIX)
508 # Protobuf headers may depend on threading.
509 find_package(Threads QUIET)
510endif()
511
512# The Protobuf library
513_protobuf_find_libraries(Protobuf protobuf)
514#DOC "The Google Protocol Buffers RELEASE Library"
515
516_protobuf_find_libraries(Protobuf_LITE protobuf-lite)
517
518# The Protobuf Protoc Library
519_protobuf_find_libraries(Protobuf_PROTOC protoc)
520
521# Restore original find library prefixes
522if(MSVC)
523 set(CMAKE_FIND_LIBRARY_PREFIXES "${Protobuf_ORIG_FIND_LIBRARY_PREFIXES}")
524endif()
525
526# Find the include directory
527find_path(Protobuf_INCLUDE_DIR
528 google/protobuf/service.h
529 PATHS ${Protobuf_SRC_ROOT_FOLDER}/src
530)
531mark_as_advanced(Protobuf_INCLUDE_DIR)
532
533# Find the protoc Executable
534find_program(Protobuf_PROTOC_EXECUTABLE
535 NAMES protoc
536 DOC "The Google Protocol Buffers Compiler"
537 PATHS
538 ${Protobuf_SRC_ROOT_FOLDER}/vsprojects/${_PROTOBUF_ARCH_DIR}Release
539 ${Protobuf_SRC_ROOT_FOLDER}/vsprojects/${_PROTOBUF_ARCH_DIR}Debug
540)
541mark_as_advanced(Protobuf_PROTOC_EXECUTABLE)
542
543if(Protobuf_DEBUG)
544 message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] "
545 "requested version of Google Protobuf is ${Protobuf_FIND_VERSION}")
546endif()
547
548if(Protobuf_INCLUDE_DIR)
549 set(_PROTOBUF_COMMON_HEADER ${Protobuf_INCLUDE_DIR}/google/protobuf/stubs/common.h)
550
551 if(Protobuf_DEBUG)
552 message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] "
553 "location of common.h: ${_PROTOBUF_COMMON_HEADER}")
554 endif()
555
556 set(Protobuf_VERSION "")
557 set(Protobuf_LIB_VERSION "")
558 file(STRINGS ${_PROTOBUF_COMMON_HEADER} _PROTOBUF_COMMON_H_CONTENTS REGEX "#define[ \t]+GOOGLE_PROTOBUF_VERSION[ \t]+")
559 if(_PROTOBUF_COMMON_H_CONTENTS MATCHES "#define[ \t]+GOOGLE_PROTOBUF_VERSION[ \t]+([0-9]+)")
560 set(Protobuf_LIB_VERSION "${CMAKE_MATCH_1}")
561 endif()
562 unset(_PROTOBUF_COMMON_H_CONTENTS)
563
564 math(EXPR _PROTOBUF_MAJOR_VERSION "${Protobuf_LIB_VERSION} / 1000000")
565 math(EXPR _PROTOBUF_MINOR_VERSION "${Protobuf_LIB_VERSION} / 1000 % 1000")
566 math(EXPR _PROTOBUF_SUBMINOR_VERSION "${Protobuf_LIB_VERSION} % 1000")
567 set(Protobuf_VERSION "${_PROTOBUF_MAJOR_VERSION}.${_PROTOBUF_MINOR_VERSION}.${_PROTOBUF_SUBMINOR_VERSION}")
568
569 if(Protobuf_DEBUG)
570 message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] "
571 "${_PROTOBUF_COMMON_HEADER} reveals protobuf ${Protobuf_VERSION}")
572 endif()
573
574 if(Protobuf_PROTOC_EXECUTABLE)
575 # Check Protobuf compiler version to be aligned with libraries version
576 execute_process(COMMAND ${Protobuf_PROTOC_EXECUTABLE} --version
577 OUTPUT_VARIABLE _PROTOBUF_PROTOC_EXECUTABLE_VERSION)
578
579 if("${_PROTOBUF_PROTOC_EXECUTABLE_VERSION}" MATCHES "libprotoc ([0-9.]+)")
580 set(_PROTOBUF_PROTOC_EXECUTABLE_VERSION "${CMAKE_MATCH_1}")
581 endif()
582
583 if(Protobuf_DEBUG)
584 message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] "
585 "${Protobuf_PROTOC_EXECUTABLE} reveals version ${_PROTOBUF_PROTOC_EXECUTABLE_VERSION}")
586 endif()
587
588 if(NOT "${_PROTOBUF_PROTOC_EXECUTABLE_VERSION}" VERSION_EQUAL "${Protobuf_VERSION}")
589 message(WARNING "Protobuf compiler version ${_PROTOBUF_PROTOC_EXECUTABLE_VERSION}"
590 " doesn't match library version ${Protobuf_VERSION}")
591 endif()
592 endif()
593
594 if(Protobuf_LIBRARY)
595 if(NOT TARGET protobuf::libprotobuf)
596 add_library(protobuf::libprotobuf UNKNOWN IMPORTED)
597 set_target_properties(protobuf::libprotobuf PROPERTIES
598 INTERFACE_INCLUDE_DIRECTORIES "${Protobuf_INCLUDE_DIR}")
599 if(EXISTS "${Protobuf_LIBRARY}")
600 set_target_properties(protobuf::libprotobuf PROPERTIES
601 IMPORTED_LOCATION "${Protobuf_LIBRARY}")
602 endif()
603 if(EXISTS "${Protobuf_LIBRARY_RELEASE}")
604 set_property(TARGET protobuf::libprotobuf APPEND PROPERTY
605 IMPORTED_CONFIGURATIONS RELEASE)
606 set_target_properties(protobuf::libprotobuf PROPERTIES
607 IMPORTED_LOCATION_RELEASE "${Protobuf_LIBRARY_RELEASE}")
608 endif()
609 if(EXISTS "${Protobuf_LIBRARY_DEBUG}")
610 set_property(TARGET protobuf::libprotobuf APPEND PROPERTY
611 IMPORTED_CONFIGURATIONS DEBUG)
612 set_target_properties(protobuf::libprotobuf PROPERTIES
613 IMPORTED_LOCATION_DEBUG "${Protobuf_LIBRARY_DEBUG}")
614 endif()
615 if (Protobuf_VERSION VERSION_GREATER_EQUAL "3.6")
616 set_property(TARGET protobuf::libprotobuf APPEND PROPERTY
617 INTERFACE_COMPILE_FEATURES cxx_std_11
618 )
619 endif()
620 if (MSVC AND NOT Protobuf_USE_STATIC_LIBS)
621 set_property(TARGET protobuf::libprotobuf APPEND PROPERTY
622 INTERFACE_COMPILE_DEFINITIONS "PROTOBUF_USE_DLLS"
623 )
624 endif()
625 if(UNIX AND TARGET Threads::Threads)
626 set_property(TARGET protobuf::libprotobuf APPEND PROPERTY
627 INTERFACE_LINK_LIBRARIES Threads::Threads)
628 endif()
629 endif()
630 endif()
631
632 if(Protobuf_LITE_LIBRARY)
633 if(NOT TARGET protobuf::libprotobuf-lite)
634 add_library(protobuf::libprotobuf-lite UNKNOWN IMPORTED)
635 set_target_properties(protobuf::libprotobuf-lite PROPERTIES
636 INTERFACE_INCLUDE_DIRECTORIES "${Protobuf_INCLUDE_DIR}")
637 if(EXISTS "${Protobuf_LITE_LIBRARY}")
638 set_target_properties(protobuf::libprotobuf-lite PROPERTIES
639 IMPORTED_LOCATION "${Protobuf_LITE_LIBRARY}")
640 endif()
641 if(EXISTS "${Protobuf_LITE_LIBRARY_RELEASE}")
642 set_property(TARGET protobuf::libprotobuf-lite APPEND PROPERTY
643 IMPORTED_CONFIGURATIONS RELEASE)
644 set_target_properties(protobuf::libprotobuf-lite PROPERTIES
645 IMPORTED_LOCATION_RELEASE "${Protobuf_LITE_LIBRARY_RELEASE}")
646 endif()
647 if(EXISTS "${Protobuf_LITE_LIBRARY_DEBUG}")
648 set_property(TARGET protobuf::libprotobuf-lite APPEND PROPERTY
649 IMPORTED_CONFIGURATIONS DEBUG)
650 set_target_properties(protobuf::libprotobuf-lite PROPERTIES
651 IMPORTED_LOCATION_DEBUG "${Protobuf_LITE_LIBRARY_DEBUG}")
652 endif()
653 if (MSVC AND NOT Protobuf_USE_STATIC_LIBS)
654 set_property(TARGET protobuf::libprotobuf-lite APPEND PROPERTY
655 INTERFACE_COMPILE_DEFINITIONS "PROTOBUF_USE_DLLS"
656 )
657 endif()
658 if(UNIX AND TARGET Threads::Threads)
659 set_property(TARGET protobuf::libprotobuf-lite APPEND PROPERTY
660 INTERFACE_LINK_LIBRARIES Threads::Threads)
661 endif()
662 endif()
663 endif()
664
665 if(Protobuf_PROTOC_LIBRARY)
666 if(NOT TARGET protobuf::libprotoc)
667 add_library(protobuf::libprotoc UNKNOWN IMPORTED)
668 set_target_properties(protobuf::libprotoc PROPERTIES
669 INTERFACE_INCLUDE_DIRECTORIES "${Protobuf_INCLUDE_DIR}")
670 if(EXISTS "${Protobuf_PROTOC_LIBRARY}")
671 set_target_properties(protobuf::libprotoc PROPERTIES
672 IMPORTED_LOCATION "${Protobuf_PROTOC_LIBRARY}")
673 endif()
674 if(EXISTS "${Protobuf_PROTOC_LIBRARY_RELEASE}")
675 set_property(TARGET protobuf::libprotoc APPEND PROPERTY
676 IMPORTED_CONFIGURATIONS RELEASE)
677 set_target_properties(protobuf::libprotoc PROPERTIES
678 IMPORTED_LOCATION_RELEASE "${Protobuf_PROTOC_LIBRARY_RELEASE}")
679 endif()
680 if(EXISTS "${Protobuf_PROTOC_LIBRARY_DEBUG}")
681 set_property(TARGET protobuf::libprotoc APPEND PROPERTY
682 IMPORTED_CONFIGURATIONS DEBUG)
683 set_target_properties(protobuf::libprotoc PROPERTIES
684 IMPORTED_LOCATION_DEBUG "${Protobuf_PROTOC_LIBRARY_DEBUG}")
685 endif()
686 if (Protobuf_VERSION VERSION_GREATER_EQUAL "3.6")
687 set_property(TARGET protobuf::libprotoc APPEND PROPERTY
688 INTERFACE_COMPILE_FEATURES cxx_std_11
689 )
690 endif()
691 if (MSVC AND NOT Protobuf_USE_STATIC_LIBS)
692 set_property(TARGET protobuf::libprotoc APPEND PROPERTY
693 INTERFACE_COMPILE_DEFINITIONS "PROTOBUF_USE_DLLS"
694 )
695 endif()
696 if(UNIX AND TARGET Threads::Threads)
697 set_property(TARGET protobuf::libprotoc APPEND PROPERTY
698 INTERFACE_LINK_LIBRARIES Threads::Threads)
699 endif()
700 endif()
701 endif()
702
703 if(Protobuf_PROTOC_EXECUTABLE)
704 if(NOT TARGET protobuf::protoc)
705 add_executable(protobuf::protoc IMPORTED)
706 if(EXISTS "${Protobuf_PROTOC_EXECUTABLE}")
707 set_target_properties(protobuf::protoc PROPERTIES
708 IMPORTED_LOCATION "${Protobuf_PROTOC_EXECUTABLE}")
709 endif()
710 endif()
711 endif()
712endif()
713
714include(${CMAKE_ROOT}/Modules/FindPackageHandleStandardArgs.cmake)
715FIND_PACKAGE_HANDLE_STANDARD_ARGS(Protobuf
716 REQUIRED_VARS Protobuf_LIBRARIES Protobuf_INCLUDE_DIR
717 VERSION_VAR Protobuf_VERSION
718)
719
720if(Protobuf_FOUND)
721 set(Protobuf_INCLUDE_DIRS ${Protobuf_INCLUDE_DIR})
722endif()
723
724# Restore the original find library ordering
725if( Protobuf_USE_STATIC_LIBS )
726 set(CMAKE_FIND_LIBRARY_SUFFIXES ${_protobuf_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES})
727endif()
728
729# Backwards compatibility
730# Define upper case versions of output variables
731foreach(Camel
732 Protobuf_SRC_ROOT_FOLDER
733 Protobuf_IMPORT_DIRS
734 Protobuf_DEBUG
735 Protobuf_INCLUDE_DIRS
736 Protobuf_LIBRARIES
737 Protobuf_PROTOC_LIBRARIES
738 Protobuf_LITE_LIBRARIES
739 Protobuf_LIBRARY
740 Protobuf_PROTOC_LIBRARY
741 Protobuf_INCLUDE_DIR
742 Protobuf_PROTOC_EXECUTABLE
743 Protobuf_LIBRARY_DEBUG
744 Protobuf_PROTOC_LIBRARY_DEBUG
745 Protobuf_LITE_LIBRARY
746 Protobuf_LITE_LIBRARY_DEBUG
747 )
748 string(TOUPPER ${Camel} UPPER)
749 set(${UPPER} ${${Camel}})
750endforeach()
- 原文作者:Witton
- 原文链接:https://wittonbell.github.io/posts/2023/2023-04-26-CMake自动按目录结构编译Protobuf代码/
- 版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议. 进行许可,非商业转载请注明出处(作者,原文链接),商业转载请联系作者获得授权。