1# Finds Google Protocol Buffers library and compilers and extends 2# the standard cmake script with version and python generation support 3macro(custom_protobuf_find) 4 message(STATUS "Use custom protobuf build.") 5 option(protobuf_BUILD_TESTS "" OFF) 6 option(protobuf_BUILD_EXAMPLES "" OFF) 7 option(protobuf_WITH_ZLIB "" OFF) 8 if(${CAFFE2_LINK_LOCAL_PROTOBUF}) 9 # If we are going to link protobuf locally, we will need to turn off 10 # shared libs build for protobuf. 11 option(protobuf_BUILD_SHARED_LIBS "" OFF) 12 else() 13 # If we are building Caffe2 as shared libs, we will also build protobuf as 14 # shared libs. 15 option(protobuf_BUILD_SHARED_LIBS "" ${BUILD_SHARED_LIBS}) 16 endif() 17 # We will make sure that protobuf and caffe2 uses the same msvc runtime. 18 option(protobuf_MSVC_STATIC_RUNTIME "" ${CAFFE2_USE_MSVC_STATIC_RUNTIME}) 19 20 if(${CAFFE2_LINK_LOCAL_PROTOBUF}) 21 set(__caffe2_CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ${CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS}) 22 set(__caffe2_CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS}) 23 set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS OFF) 24 set(BUILD_SHARED_LIBS OFF) 25 if(${COMPILER_SUPPORTS_HIDDEN_VISIBILITY}) 26 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden") 27 endif() 28 if(${COMPILER_SUPPORTS_HIDDEN_INLINE_VISIBILITY}) 29 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility-inlines-hidden") 30 endif() 31 endif() 32 33 set(__caffe2_CMAKE_POSITION_INDEPENDENT_CODE ${CMAKE_POSITION_INDEPENDENT_CODE}) 34 set(CMAKE_POSITION_INDEPENDENT_CODE ON) 35 36 if(MSVC) 37 foreach(flag_var 38 CMAKE_C_FLAGS CMAKE_C_FLAGS_RELEASE CMAKE_C_FLAGS_MINSIZEREL 39 CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_MINSIZEREL) 40 if(${flag_var} MATCHES "/Z[iI7]") 41 string(REGEX REPLACE "/Z[iI7]" "" ${flag_var} "${${flag_var}}") 42 endif() 43 endforeach(flag_var) 44 if(MSVC_Z7_OVERRIDE) 45 foreach(flag_var 46 CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELWITHDEBINFO 47 CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELWITHDEBINFO) 48 if(${flag_var} MATCHES "/Z[iI]") 49 string(REGEX REPLACE "/Z[iI]" "/Z7" ${flag_var} "${${flag_var}}") 50 endif() 51 endforeach(flag_var) 52 endif(MSVC_Z7_OVERRIDE) 53 endif(MSVC) 54 55 add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/../third_party/protobuf/cmake) 56 57 set(CMAKE_POSITION_INDEPENDENT_CODE ${__caffe2_CMAKE_POSITION_INDEPENDENT_CODE}) 58 59 if(${CAFFE2_LINK_LOCAL_PROTOBUF}) 60 set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ${__caffe2_CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS}) 61 set(BUILD_SHARED_LIBS ON) 62 set(CMAKE_CXX_FLAGS ${__caffe2_CMAKE_CXX_FLAGS}) 63 endif() 64 65 # Protobuf "namespaced" target is only added post protobuf 3.5.1. As a 66 # result, for older versions, we will manually add alias. 67 if(NOT TARGET protobuf::libprotobuf) 68 add_library(protobuf::libprotobuf ALIAS libprotobuf) 69 add_library(protobuf::libprotobuf-lite ALIAS libprotobuf-lite) 70 # There is link error when cross compiling protoc on mobile: 71 # https://github.com/protocolbuffers/protobuf/issues/2719 72 # And protoc is very unlikely needed for mobile builds. 73 if(NOT (ANDROID OR IOS)) 74 add_executable(protobuf::protoc ALIAS protoc) 75 endif() 76 endif() 77endmacro() 78 79# Main entry for protobuf. If we are building on Android, iOS or we have hard 80# coded BUILD_CUSTOM_PROTOBUF, we will hard code the use of custom protobuf 81# in the submodule. 82if(ANDROID OR IOS) 83 if(NOT BUILD_CUSTOM_PROTOBUF) 84 message(WARNING 85 "For Android and iOS cross compilation, I am automatically using " 86 "custom protobuf under third party. Note that this behavior may " 87 "change in the future, and you will need to specify " 88 "-DBUILD_CUSTOM_PROTOBUF=ON explicitly.") 89 endif() 90 # There is link error when cross compiling protoc on mobile: 91 # https://github.com/protocolbuffers/protobuf/issues/2719 92 # And protoc is very unlikely needed for mobile builds. 93 set(__caffe2_protobuf_BUILD_PROTOC_BINARIES ${protobuf_BUILD_PROTOC_BINARIES}) 94 set(protobuf_BUILD_PROTOC_BINARIES OFF CACHE BOOL "" FORCE) 95 custom_protobuf_find() 96 set(protobuf_BUILD_PROTOC_BINARIES ${__caffe2_protobuf_BUILD_PROTOC_BINARIES} CACHE BOOL "" FORCE) 97elseif(BUILD_CUSTOM_PROTOBUF) 98 message(STATUS "Building using own protobuf under third_party per request.") 99 custom_protobuf_find() 100else() 101 include(cmake/public/protobuf.cmake) 102endif() 103 104if((NOT TARGET protobuf::libprotobuf) AND (NOT TARGET protobuf::libprotobuf-lite)) 105 message(WARNING 106 "Protobuf cannot be found. Caffe2 will automatically switch to use " 107 "own protobuf under third_party. Note that this behavior may change in " 108 "the future, and you will need to specify -DBUILD_CUSTOM_PROTOBUF=ON " 109 "explicitly.") 110 custom_protobuf_find() 111 112 # TODO(jiayq): enable this in the future, when Jenkins Mac support is 113 # properly set up with protobuf installs. 114 115 # message(FATAL_ERROR 116 # "Protobuf cannot be found. Caffe2 will have to build with libprotobuf. " 117 # "Please set the proper paths so that I can find protobuf correctly.") 118endif() 119 120get_target_property(__tmp protobuf::libprotobuf INTERFACE_INCLUDE_DIRECTORIES) 121message(STATUS "Caffe2 protobuf include directory: " ${__tmp}) 122include_directories(BEFORE SYSTEM ${__tmp}) 123 124# If Protobuf_VERSION is known (true in most cases, false if we are building 125# local protobuf), then we will add a protobuf version check in 126# Caffe2Config.cmake.in. 127if(DEFINED ${Protobuf_VERSION}) 128 set(CAFFE2_KNOWN_PROTOBUF_VERSION TRUE) 129else() 130 set(CAFFE2_KNOWN_PROTOBUF_VERSION FALSE) 131 set(Protobuf_VERSION "Protobuf_VERSION_NOTFOUND") 132endif() 133 134 135# Figure out which protoc to use. 136# If CAFFE2_CUSTOM_PROTOC_EXECUTABLE is set, we assume the user knows 137# what they're doing and we blindly use the specified protoc. This 138# is typically the case when cross-compiling where protoc must be 139# compiled for the host architecture and libprotobuf must be 140# compiled for the target architecture. 141# If CAFFE2_CUSTOM_PROTOC_EXECUTABLE is NOT set, we use the protoc 142# target that is built as part of including the protobuf project. 143if(EXISTS "${CAFFE2_CUSTOM_PROTOC_EXECUTABLE}") 144 set(CAFFE2_PROTOC_EXECUTABLE ${CAFFE2_CUSTOM_PROTOC_EXECUTABLE}) 145else() 146 set(CAFFE2_PROTOC_EXECUTABLE protobuf::protoc) 147endif() 148 149################################################################################################ 150# Modification of standard 'protobuf_generate_cpp()' with output dir parameter and python support 151# Usage: 152# caffe2_protobuf_generate_cpp_py(<srcs_var> <hdrs_var> <python_var> <proto_files>) 153function(caffe2_protobuf_generate_cpp_py srcs_var hdrs_var python_var) 154 if(NOT ARGN) 155 message(SEND_ERROR "Error: caffe_protobuf_generate_cpp_py() called without any proto files") 156 return() 157 endif() 158 159 set(${srcs_var}) 160 set(${hdrs_var}) 161 set(${python_var}) 162 foreach(fil ${ARGN}) 163 get_filename_component(abs_fil ${fil} ABSOLUTE) 164 get_filename_component(fil_we ${fil} NAME_WE) 165 166 list(APPEND ${srcs_var} "${CMAKE_CURRENT_BINARY_DIR}/${fil_we}.pb.cc") 167 list(APPEND ${hdrs_var} "${CMAKE_CURRENT_BINARY_DIR}/${fil_we}.pb.h") 168 list(APPEND ${python_var} "${CMAKE_CURRENT_BINARY_DIR}/${fil_we}_pb2.py") 169 170 # Add TORCH_API prefix to protobuf classes and methods in all cases 171 set(DLLEXPORT_STR "dllexport_decl=TORCH_API:") 172 173 # Note: the following depends on PROTOBUF_PROTOC_EXECUTABLE. This 174 # is done to make sure protoc is built before attempting to 175 # generate sources if we're using protoc from the third_party 176 # directory and are building it as part of the Caffe2 build. If 177 # points to an existing path, it is a no-op. 178 179 if(${CAFFE2_LINK_LOCAL_PROTOBUF}) 180 # We need to rewrite the pb.h files to route GetEmptyStringAlreadyInited 181 # through our wrapper in proto_utils so the memory location test 182 # is correct. 183 add_custom_command( 184 OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${fil_we}.pb.cc" 185 "${CMAKE_CURRENT_BINARY_DIR}/${fil_we}.pb.h" 186 "${CMAKE_CURRENT_BINARY_DIR}/${fil_we}_pb2.py" 187 WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} 188 COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_CURRENT_BINARY_DIR}" 189 COMMAND ${CAFFE2_PROTOC_EXECUTABLE} -I${PROJECT_SOURCE_DIR} --cpp_out=${DLLEXPORT_STR}${PROJECT_BINARY_DIR} ${abs_fil} 190 COMMAND ${CAFFE2_PROTOC_EXECUTABLE} -I${PROJECT_SOURCE_DIR} --python_out "${PROJECT_BINARY_DIR}" ${abs_fil} 191 192 # If we remove all reference to these pb.h files from external 193 # libraries and binaries this rewrite can be removed. 194 COMMAND ${CMAKE_COMMAND} -DFILENAME=${CMAKE_CURRENT_BINARY_DIR}/${fil_we}.pb.h -DNAMESPACES=caffe\;caffe2\;onnx\;torch -P ${PROJECT_SOURCE_DIR}/cmake/ProtoBufPatch.cmake 195 196 DEPENDS ${CAFFE2_PROTOC_EXECUTABLE} ${abs_fil} 197 COMMENT "Running C++/Python protocol buffer compiler on ${fil}" VERBATIM ) 198 else() 199 add_custom_command( 200 OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${fil_we}.pb.cc" 201 "${CMAKE_CURRENT_BINARY_DIR}/${fil_we}.pb.h" 202 "${CMAKE_CURRENT_BINARY_DIR}/${fil_we}_pb2.py" 203 WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} 204 COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_CURRENT_BINARY_DIR}" 205 COMMAND ${CAFFE2_PROTOC_EXECUTABLE} -I${PROJECT_SOURCE_DIR} --cpp_out=${DLLEXPORT_STR}${PROJECT_BINARY_DIR} ${abs_fil} 206 COMMAND ${CAFFE2_PROTOC_EXECUTABLE} -I${PROJECT_SOURCE_DIR} --python_out "${PROJECT_BINARY_DIR}" ${abs_fil} 207 COMMAND ${CMAKE_COMMAND} -DFILENAME=${CMAKE_CURRENT_BINARY_DIR}/${fil_we}.pb.h -DNAMESPACES=caffe\;caffe2\;onnx\;torch -DSYSTEM_PROTOBUF=YES -P ${PROJECT_SOURCE_DIR}/cmake/ProtoBufPatch.cmake 208 DEPENDS ${CAFFE2_PROTOC_EXECUTABLE} ${abs_fil} 209 COMMENT "Running C++/Python protocol buffer compiler on ${fil}" VERBATIM ) 210 endif() 211 endforeach() 212 213 set_source_files_properties(${${srcs_var}} ${${hdrs_var}} ${${python_var}} PROPERTIES GENERATED TRUE) 214 set(${srcs_var} ${${srcs_var}} PARENT_SCOPE) 215 set(${hdrs_var} ${${hdrs_var}} PARENT_SCOPE) 216 set(${python_var} ${${python_var}} PARENT_SCOPE) 217endfunction() 218