概述
這個博客,記錄了我遇到的一種opencv編譯報錯,解決的過程,希望這個博客,給遇到類似報錯的大夥,一些啓發。
我遇到這個protobuf相關的報錯的原因,是在windows下,使用vcpkg安裝了protobuf4.2的版本,導致了這個報錯。
如果大夥自行編譯opencv,我個人的經驗是,
1 如果使用vcpkg全局安裝了protobuf高版本的庫(比如4.2),建議可以臨時卸載它。(opencv用的protobuf版本可以參考"opencv/3rdparty/protobuf/README.md")。
2 如果手工安裝過protobuf的exe,我個人建議先臨時把protoc.exe對應的環境變量先刪除掉。免得對opencv編譯造成影響。閲讀了一些博客,這個是有一些影響的。
下面的內容,是非常細節的排查過程,大夥用不到,就不用看了。
環境説明
OS:windows 10。
cmake:3.27.9。
IDE:visual studio 2019。
目標編譯的opencv版本:4.7.0。
protobuf版本:3.19.1。
報錯與排查
編譯opencv4.7.0,針對visual studio x64編譯,我發現編譯參數選中"BUILD PROTOBUF",編譯opencv時,會報關於protobuf的錯誤。
Severity Code Description Project File Line Suppression State Details
Error C2511 'bool google::protobuf::internal::AnyMetadata::InternalPackFrom(google::protobuf::Arena *,const google::protobuf::MessageLite &,google::protobuf::stringpiece_internal::StringPiece,google::protobuf::stringpiece_internal::StringPiece)': overloaded member function not found in 'google::protobuf::internal::AnyMetadata' libprotobuf F:\cpp_library\opencv_470\opencv-4.7.0\3rdparty\protobuf\src\google\protobuf\any_lite.cc 58
Error C2039 'EmptyDefault': is not a member of 'google::protobuf::internal::ArenaStringPtr' libprotobuf F:\cpp_library\opencv_470\opencv-4.7.0\3rdparty\protobuf\src\google\protobuf\any_lite.cc 62
Error C2065 'EmptyDefault': undeclared identifier libprotobuf F:\cpp_library\opencv_470\opencv-4.7.0\3rdparty\protobuf\src\google\protobuf\any_lite.cc 62
Error C2511 'bool google::protobuf::internal::AnyMetadata::InternalUnpackTo(google::protobuf::stringpiece_internal::StringPiece,google::protobuf::MessageLite *) const': overloaded member function not found in 'google::protobuf::internal::AnyMetadata' libprotobuf F:\cpp_library\opencv_470\opencv-4.7.0\3rdparty\protobuf\src\google\protobuf\any_lite.cc 66
如果,編譯參數取消選中"BUILD PROTOBUF",編譯opencv,是能夠正常編譯,但是編譯出來的opencv,cv::dnn相關的函數與類用不了,顯然不符合日常開發使用。
經過諮詢大模型後,嘗試在opencv之外,單獨編譯protobuf。然後把編譯好的protobuf的路徑信息,在編譯opencv時,指定一下。即在編譯opencv時,不再編譯protobuf,而是現在現成的,在外部編譯好的protobuf。
單獨編譯的protobuf版本是3.19.1,這是opencv4.7.0源碼中的READMD.MD中要求的protobuf版本。
在編譯opencv時,把protobuf的編譯結果配置為opencv的編譯參數,並在編譯opencv時,
把"BUILD_PROTOBUF"取消選中。把"WITH_PROTOBUF"選中。
PROTOBUF_UPDATE_FILES,選中。
並通過Add Entry,增加如下參數。
Protobuf_INCLUDE_DIR = "C:/Program Files/protobuf/include"
Protobuf_LIBRARY = "C:/Program Files/protobuf/lib/libprotobufd.lib"
Protobuf_PROTOC_EXECUTABLE = "C:/Program Files/protobuf/bin/protoc.exe"
其中C:\Program Files\protobuf,是在外部,單獨編譯protobuf後的install目錄。
實測下來,重新configure與generate,打開創建的Opencv solution。build。報錯如下:
Severity Code Description Project File Line Suppression State
Error C1189 #error: This file was generated by an older version of protoc which is (compiling source file F:\zhusc\cpp_library\opencv_470\opencv-4.7.0\modules\dnn\misc\onnx\opencv-onnx.pb.cc) opencv_world F:\zhusc\cpp_library\opencv_470\opencv-4.7.0\modules\dnn\misc\onnx\opencv-onnx.pb.h 17
Error C1189 #error: This file was generated by an older version of protoc which is (compiling source file F:\zhusc\cpp_library\opencv_470\opencv-4.7.0\modules\dnn\misc\tensorflow\attr_value.pb.cc) opencv_world F:\zhusc\cpp_library\opencv_470\opencv-4.7.0\modules\dnn\misc\tensorflow\attr_value.pb.h 17
Error C1189 #error: This file was generated by an older version of protoc which is (compiling source file F:\zhusc\cpp_library\opencv_470\opencv-4.7.0\modules\dnn\misc\tensorflow\function.pb.cc) opencv_world F:\zhusc\cpp_library\opencv_470\opencv-4.7.0\modules\dnn\misc\tensorflow\function.pb.h 17
觀察其中一處報錯:
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: opencv-caffe.proto
#ifndef GOOGLE_PROTOBUF_INCLUDED_opencv_2dcaffe_2eproto
#define GOOGLE_PROTOBUF_INCLUDED_opencv_2dcaffe_2eproto
#include <limits>
#include <string>
#include <google/protobuf/port_def.inc>
#if PROTOBUF_VERSION < 3019000
#error This file was generated by a newer version of protoc which is
#error incompatible with your Protocol Buffer headers. Please update
#error your headers.
#endif
#if 3019001 < PROTOBUF_MIN_PROTOC_VERSION
#error This file was generated by an older version of protoc which is
#error incompatible with your Protocol Buffer headers. Please
#error regenerate this file with a newer version of protoc.
#endif
説明if 3019001 < PROTOBUF_MIN_PROTOC_VERSION條件滿足,導致了該報錯。3019001代表protobuf的版本號,即3.19.1,在opencv4.7.0的源碼中的READMD.MD,它也要求protobuf是這個。
我在這裏,也查了好多資料,非常的費解。
下午的時候,我用visual studio 2019點開報錯的opencv-onnx.pb.h文件,並把光標停在PROTOBUF_MIN_PROTOC_VERSION,按了下F12,或者鼠標右鍵-->GO TO DEFINITION。結果跳到了vcpkg安裝的protobuf的源代碼目錄下,顯示#define PROTOBUF_MIN_PROTOC_VERSION 4022000。
終於理解,為什麼報這個錯了。
於是,我就調用vcpkg remove,刪除掉了vcpkg安裝的protobuf,並且把之前配置的protoc的環境變量,也手工清除。
我打開cmake,File --> Delete Cache,重新選一個build目錄,opencv編譯時,protobuf參數不動,即保持默認(默認是BUILD_PROTOBUF是選中的),其它參數按需要配置。
目前來看,Opencv Debug x64與Release x64,ALL_BUILD與ALL_INSTALL均build成功。
在外部單獨編譯protobuf, opencv中不編譯protobuf的編譯方法
我在編譯opencv4.7.0, protobuf是我在外面單獨使用cmake編譯的。
編譯protobuf我之前試過使用runtime library=/MDd(Debug模式下) /MD(Release); 我是在visual studio中,對protobuf的幾個project逐個手工修改的,不改這個,編譯出來的protobuf,會報跟Opencv的runtime library不統一錯誤。
在編譯opencv時,WITH_BUILD_PROTOBUF不先中,配置與生成opencv工程。編譯opencv時,報錯如下:
Severity Code Description Project File Line Suppression State
Error LNK2001 unresolved external symbol "__declspec(dllimport) public: __cdecl google::protobuf::internal::ArenaStringPtr::ArenaStringPtr(class google::protobuf::internal::ExplicitlyConstructed<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > > const *)" (__imp_??0ArenaStringPtr@internal@protobuf@google@@QEAA@PEBV?$ExplicitlyConstructed@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@123@@Z) opencv_world F:\cpp_library\opencv_470\opencv-4.7.0\build_by_vs2019_no_pb_3.19.1\modules\world\graph.pb.obj 1
Error LNK1120 4 unresolved externals opencv_world F:\cpp_library\opencv_470\opencv-4.7.0\build_by_vs2019_no_pb_3.19.1\bin\Debug\opencv_world470d.dll 1
Error LNK2001 unresolved external symbol "__declspec(dllimport) public: __cdecl google::protobuf::internal::ArenaStringPtr::ArenaStringPtr(class google::protobuf::internal::ExplicitlyConstructed<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > > const *)" (__imp_??0ArenaStringPtr@internal@protobuf@google@@QEAA@PEBV?$ExplicitlyConstructed@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@123@@Z) opencv_world F:\cpp_library\opencv_470\opencv-4.7.0\build_by_vs2019_no_pb_3.19.1\modules\world\op_def.pb.obj 1
Error LNK2001 unresolved external symbol "__declspec(dllimport) public: __cdecl google::protobuf::internal::ArenaStringPtr::ArenaStringPtr(class google::protobuf::internal::ExplicitlyConstructed<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > > const *)" (__imp_??0ArenaStringPtr@internal@protobuf@google@@QEAA@PEBV?$ExplicitlyConstructed@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@123@@Z) opencv_world F:\cpp_library\opencv_470\opencv-4.7.0\build_by_vs2019_no_pb_3.19.1\modules\world\tensor.pb.obj 1
這樣報錯少了很多,再接着排查這個報錯,並修改,我估計是能行的通的。我已經通過其它方式編譯出來了,就不再浪費時間搞這個了。
參考文獻
[1] https://github.com/opencv/opencv/issues/17389 (This file was generated by an older version of protoc #17389)
[2] https://blog.csdn.net/m0_58326153/article/details/142381832 (解決opencv編譯中出現的#error: This file was generated by an older version of protoc which is (編C1189譯源文件)問題)
[3] https://blog.csdn.net/xiaosier_D/article/details/132298267 (opencv3.4.16編譯報錯記錄(VS2022+gpu))
[4] https://www.bilibili.com/video/BV1FP4y1J7G9/vd_source=5e593ed... (Windows平台下OpenCV源碼和OpenCV-contrib模塊的編譯)