1function(protobuf_generate) 2 include(CMakeParseArguments) 3 4 set(_options APPEND_PATH) 5 set(_singleargs LANGUAGE OUT_VAR EXPORT_MACRO PROTOC_OUT_DIR PLUGIN PLUGIN_OPTIONS DEPENDENCIES PROTOC_EXE) 6 if(COMMAND target_sources) 7 list(APPEND _singleargs TARGET) 8 endif() 9 set(_multiargs PROTOS IMPORT_DIRS GENERATE_EXTENSIONS PROTOC_OPTIONS) 10 11 cmake_parse_arguments(protobuf_generate "${_options}" "${_singleargs}" "${_multiargs}" "${ARGN}") 12 13 if(NOT protobuf_generate_PROTOS AND NOT protobuf_generate_TARGET) 14 message(SEND_ERROR "Error: protobuf_generate called without any targets or source files") 15 return() 16 endif() 17 18 if(NOT protobuf_generate_OUT_VAR AND NOT protobuf_generate_TARGET) 19 message(SEND_ERROR "Error: protobuf_generate called without a target or output variable") 20 return() 21 endif() 22 23 if(NOT protobuf_generate_LANGUAGE) 24 set(protobuf_generate_LANGUAGE cpp) 25 endif() 26 string(TOLOWER ${protobuf_generate_LANGUAGE} protobuf_generate_LANGUAGE) 27 28 if(NOT protobuf_generate_PROTOC_OUT_DIR) 29 set(protobuf_generate_PROTOC_OUT_DIR ${CMAKE_CURRENT_BINARY_DIR}) 30 endif() 31 32 if(protobuf_generate_EXPORT_MACRO AND protobuf_generate_LANGUAGE STREQUAL cpp) 33 set(_dll_export_decl "dllexport_decl=${protobuf_generate_EXPORT_MACRO}") 34 endif() 35 36 foreach(_option ${_dll_export_decl} ${protobuf_generate_PLUGIN_OPTIONS}) 37 # append comma - not using CMake lists and string replacement as users 38 # might have semicolons in options 39 if(_plugin_options) 40 set( _plugin_options "${_plugin_options},") 41 endif() 42 set(_plugin_options "${_plugin_options}${_option}") 43 endforeach() 44 45 if(protobuf_generate_PLUGIN) 46 set(_plugin "--plugin=${protobuf_generate_PLUGIN}") 47 endif() 48 49 if(NOT protobuf_generate_GENERATE_EXTENSIONS) 50 if(protobuf_generate_LANGUAGE STREQUAL cpp) 51 set(protobuf_generate_GENERATE_EXTENSIONS .pb.h .pb.cc) 52 elseif(protobuf_generate_LANGUAGE STREQUAL python) 53 set(protobuf_generate_GENERATE_EXTENSIONS _pb2.py) 54 else() 55 message(SEND_ERROR "Error: protobuf_generate given unknown Language ${LANGUAGE}, please provide a value for GENERATE_EXTENSIONS") 56 return() 57 endif() 58 endif() 59 60 if(protobuf_generate_TARGET) 61 get_target_property(_source_list ${protobuf_generate_TARGET} SOURCES) 62 foreach(_file ${_source_list}) 63 if(_file MATCHES "proto$") 64 list(APPEND protobuf_generate_PROTOS ${_file}) 65 endif() 66 endforeach() 67 endif() 68 69 if(NOT protobuf_generate_PROTOS) 70 message(SEND_ERROR "Error: protobuf_generate could not find any .proto files") 71 return() 72 endif() 73 74 if(protobuf_generate_APPEND_PATH) 75 # Create an include path for each file specified 76 foreach(_file ${protobuf_generate_PROTOS}) 77 get_filename_component(_abs_file ${_file} ABSOLUTE) 78 get_filename_component(_abs_dir ${_abs_file} DIRECTORY) 79 list(FIND _protobuf_include_path ${_abs_dir} _contains_already) 80 if(${_contains_already} EQUAL -1) 81 list(APPEND _protobuf_include_path -I ${_abs_dir}) 82 endif() 83 endforeach() 84 endif() 85 86 if(NOT protobuf_generate_PROTOC_EXE) 87 # Default to using the CMake executable 88 set(protobuf_generate_PROTOC_EXE protobuf::protoc) 89 endif() 90 91 foreach(DIR ${protobuf_generate_IMPORT_DIRS}) 92 get_filename_component(ABS_PATH ${DIR} ABSOLUTE) 93 list(FIND _protobuf_include_path ${ABS_PATH} _contains_already) 94 if(${_contains_already} EQUAL -1) 95 list(APPEND _protobuf_include_path -I ${ABS_PATH}) 96 endif() 97 endforeach() 98 99 if(NOT _protobuf_include_path) 100 set(_protobuf_include_path -I ${CMAKE_CURRENT_SOURCE_DIR}) 101 endif() 102 103 set(_generated_srcs_all) 104 foreach(_proto ${protobuf_generate_PROTOS}) 105 get_filename_component(_abs_file ${_proto} ABSOLUTE) 106 get_filename_component(_abs_dir ${_abs_file} DIRECTORY) 107 108 get_filename_component(_file_full_name ${_proto} NAME) 109 string(FIND "${_file_full_name}" "." _file_last_ext_pos REVERSE) 110 string(SUBSTRING "${_file_full_name}" 0 ${_file_last_ext_pos} _basename) 111 112 set(_suitable_include_found FALSE) 113 foreach(DIR ${_protobuf_include_path}) 114 if(NOT DIR STREQUAL "-I") 115 file(RELATIVE_PATH _rel_dir ${DIR} ${_abs_dir}) 116 if(_rel_dir STREQUAL _abs_dir) 117 # When there is no relative path from DIR to _abs_dir (e.g. due to 118 # different drive letters on Windows), _rel_dir is equal to _abs_dir. 119 # Therefore, DIR is not a suitable include path and must be skipped. 120 continue() 121 endif() 122 string(FIND "${_rel_dir}" "../" _is_in_parent_folder) 123 if (NOT ${_is_in_parent_folder} EQUAL 0) 124 set(_suitable_include_found TRUE) 125 break() 126 endif() 127 endif() 128 endforeach() 129 130 if(NOT _suitable_include_found) 131 message(SEND_ERROR "Error: protobuf_generate could not find any correct proto include directory.") 132 return() 133 endif() 134 135 set(_generated_srcs) 136 foreach(_ext ${protobuf_generate_GENERATE_EXTENSIONS}) 137 list(APPEND _generated_srcs "${protobuf_generate_PROTOC_OUT_DIR}/${_rel_dir}/${_basename}${_ext}") 138 endforeach() 139 list(APPEND _generated_srcs_all ${_generated_srcs}) 140 141 set(_comment "Running ${protobuf_generate_LANGUAGE} protocol buffer compiler on ${_proto}") 142 if(protobuf_generate_PROTOC_OPTIONS) 143 set(_comment "${_comment}, protoc-options: ${protobuf_generate_PROTOC_OPTIONS}") 144 endif() 145 if(_plugin_options) 146 set(_comment "${_comment}, plugin-options: ${_plugin_options}") 147 endif() 148 149 add_custom_command( 150 OUTPUT ${_generated_srcs} 151 COMMAND ${protobuf_generate_PROTOC_EXE} 152 ARGS ${protobuf_generate_PROTOC_OPTIONS} --${protobuf_generate_LANGUAGE}_out ${_plugin_options}:${protobuf_generate_PROTOC_OUT_DIR} ${_plugin} ${_protobuf_include_path} ${_abs_file} 153 DEPENDS ${_abs_file} ${protobuf_PROTOC_EXE} ${protobuf_generate_DEPENDENCIES} 154 COMMENT ${_comment} 155 VERBATIM ) 156 endforeach() 157 158 set_source_files_properties(${_generated_srcs_all} PROPERTIES GENERATED TRUE) 159 if(protobuf_generate_OUT_VAR) 160 set(${protobuf_generate_OUT_VAR} ${_generated_srcs_all} PARENT_SCOPE) 161 endif() 162 if(protobuf_generate_TARGET) 163 target_sources(${protobuf_generate_TARGET} PRIVATE ${_generated_srcs_all}) 164 endif() 165 166endfunction() 167