1# CMake file to replace the string contents in ONNX, Caffe, and Caffe2 proto. 2# Usage example: 3# cmake -DFILENAME=caffe2.pb.h -DLOCAL_PROTOBUF=ON -P ProtoBufPatch.cmake 4 5file(READ ${FILENAME} content) 6 7if(NOT SYSTEM_PROTOBUF) 8 # protobuf-3.6.0 pattern 9 string( 10 REPLACE 11 "::google::protobuf::internal::GetEmptyStringAlreadyInited" 12 "GetEmptyStringAlreadyInited" 13 content 14 "${content}") 15 16 # protobuf-3.8.0+ pattern 17 string( 18 REPLACE 19 "::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited" 20 "GetEmptyStringAlreadyInited" 21 content 22 "${content}") 23 24 string( 25 REPLACE 26 "PROTOBUF_CONSTEXPR" 27 "" 28 content 29 "${content}") 30 31 # https://github.com/protocolbuffers/protobuf/commit/0400cca3236de1ca303af38bf81eab332d042b7c 32 # changes PROTOBUF_CONSTEXPR to constexpr, which breaks windows 33 # build. 34 if(MSVC) 35 string( 36 REGEX REPLACE 37 "static constexpr ([^ ]+) ([^ ]+) =" 38 "static \\1 const \\2 =" 39 content 40 "${content}") 41 endif() 42 43 foreach(ns ${NAMESPACES}) 44 # Insert "const ::std::string& GetEmptyStringAlreadyInited();" within 45 # the namespace and make sure we only do it once in the file. Unfortunately 46 # using string(REPLACE ...) doesn't work because it will replace at all 47 # locations and there might be multiple declarations of the namespace 48 # depending on how the proto is structured. 49 set(search "namespace ${ns} {") 50 string(LENGTH "${search}" search_len) 51 string(FIND "${content}" "${search}" pos) 52 if(${pos} GREATER -1) 53 math(EXPR pos "${pos}+${search_len}") 54 string(SUBSTRING "${content}" 0 ${pos} content_pre) 55 string(SUBSTRING "${content}" ${pos} -1 content_post) 56 string( 57 CONCAT 58 content 59 "${content_pre}" 60 " const ::std::string& GetEmptyStringAlreadyInited(); " 61 "${content_post}") 62 endif() 63 endforeach() 64 65 # The moving constructor is defined in the header file, which will cause 66 # a link error that claims that the vftable is not found. Luckily, we 67 # could move the definition into the source file to solve the problem. 68 list(LENGTH NAMESPACES ns_count) 69 if("${FILENAME}" MATCHES ".pb.h" AND ns_count EQUAL 1) 70 string(REPLACE ".pb.h" ".pb.cc" SOURCE_FILENAME ${FILENAME}) 71 file(READ ${SOURCE_FILENAME} content_cc_origin) 72 73 string(REGEX MATCHALL "([a-zA-Z_]+)\\([a-zA-Z_]+&& from\\) noexcept[^}]*}" content_cc "${content}") 74 string(REGEX REPLACE "};" "}\n" content_cc "${content_cc}") 75 string(REGEX REPLACE "([a-zA-Z_]+)\\([a-zA-Z_]+&& from\\) noexcept" " \\1::\\1(\\1&& from) noexcept" content_cc "${content_cc}") 76 set(content_cc "${content_cc_origin}\nnamespace ${NAMESPACES} {\n#if LANG_CXX11\n${content_cc}\n#endif\n}") 77 78 string(REGEX REPLACE "([a-zA-Z_]+)\\([a-zA-Z_]+&& from\\) noexcept([^}]*)}" "\\1(\\1&& from) noexcept;" content "${content}") 79 80 file(WRITE ${SOURCE_FILENAME} "${content_cc}") 81 endif() 82endif(NOT SYSTEM_PROTOBUF) 83 84# constexpr int TensorBoundShape_DimType_DimType_ARRAYSIZE = TensorBoundShape_DimType_DimType_MAX + 1; 85# throws 86# error: more than one operator "+" matches these operands: 87# built-in operator "arithmetic + arithmetic" 88# function "c10::operator+(int, c10::BFloat16)" 89# function "c10::operator+(c10::BFloat16, int)" 90# function "c10::operator+(int, c10::Half)" 91# function "c10::operator+(c10::Half, int)" 92# operand types are: const caffe2::ExternalDataProto_SourceType + int 93string( 94 REGEX REPLACE 95 "constexpr ([^ ]+) ([^ ]+_ARRAYSIZE) = ([^ ]+_MAX) \\+ 1;" 96 "constexpr \\1 \\2 = static_cast<\\1>(\\3) + 1;" 97 content 98 "${content}") 99 100file(WRITE ${FILENAME} "${content}") 101