我在我的库中遇到了一些相当基本的 Protobuf 文件的问题。这是成功构建为静态库的,但是当编译测试(Catch2)并链接到相同的 protobuf 库时,我得到以下 undefined symbol :-
[build] Starting build
[proc] Executing command: /usr/local/bin/cmake --build /Volumes/TB3-1/git/skunkworks/herald-for-cpp/build --config Debug --target herald-tests --
[build] [1/1 100% :: 0.182] Linking CXX executable herald-tests/herald-tests
[build] FAILED: herald-tests/herald-tests
[build] : && /usr/bin/clang++ -g -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.3.sdk -Wl,-search_paths_first -Wl,-headerpad_max_install_names herald-tests/CMakeFiles/herald-tests.dir/test-templates.cpp.o herald-tests/CMakeFiles/herald-tests.dir/test-util.cpp.o herald-tests/CMakeFiles/herald-tests.dir/mesh-tests.cpp.o herald-tests/CMakeFiles/herald-tests.dir/main.cpp.o -o herald-tests/herald-tests herald/libherald.a /usr/local/lib/libprotobuf.a /usr/local/opt/openssl@3/lib/libcrypto.a && :
[build] Undefined symbols for architecture x86_64:
[build] "google::protobuf::internal::InternalMetadata::~InternalMetadata()", referenced from:
[build] google::protobuf::MessageLite::~MessageLite() in libherald.a(modem.pb.cc.o)
[build] google::protobuf::MessageLite::~MessageLite() in libherald.a(mesh.pb.cc.o)
[build] google::protobuf::MessageLite::~MessageLite() in libherald.a(models.pb.cc.o)
[build] ld: symbol(s) not found for architecture x86_64
[build] clang: error: linker command failed with exit code 1 (use -v to see invocation)
[build] ninja: build stopped: subcommand failed.
[build] Build finished with exit code 1
super 有趣的是,当我强制使用 SPEED 而不是 LITE_RUNTIME 时,它甚至会提示 ~MessageLite 调用中缺少符号。无论我将库和程序链接到 dylib 还是我的 mac 上的静态库,无论是完整库还是精简库,似乎都不重要。在我的原型(prototype)文件中尝试了 SPEED 和 LITE_RUNTIME,结果完全相同。
我已经为此苦苦挣扎了一段时间。任何想法都非常感激。
注意:我的库的目标平台范围从服务器上的容器到嵌入式硬件设备。这些特定的测试是在本地编译的(目前在我的例子中是 Mac OS X x86_64 Intel Mac)。
最佳答案
本期was tracked here并且应该在最近发布的 Protobuf 3.21.3 中修复。
随包管理器一起提供的库构建通常使用 NDEBUG
构建。定义( -DNDEBUG
到编译器, #define NDEBUG
在代码中)。通常这只是关闭检查 assert()
宏,但 Protobuf 按下此符号可以打开和关闭其自身的内部调试。事实证明,在 Release模式下 InternalMetadata
析构函数始终是内联的,并且(在编译器选项中使用 -fvisibility-inlines-hidden
)从未生成要链接的符号,而在 Debug模式下,它并不总是内联的,需要链接。
因此尝试构建未定义 NDEBUG
的用户代码Protobuf header 将导致需要链接到该析构函数的代码,而该析构函数不会包含在发布的 Protobuf 打包库中。
解决方法是使用 -DNDEBUG
在您的应用程序中,或者构建 Protobuf 的调试版本来链接,或者使用足够新的 Protobuf(3.21.3+)或足够旧的 Protobuf(我认为 <=3.19)不会出现此特定问题。
唯一剩下的谜团是,为什么整个互联网在过去几天都注意到了这个错误,而它已经存在了很长时间。
关于c++ - Protobuf ld undefined symbol ~InternalMetadata(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73047153/