У меня есть проект C++ на основе CMake. Начальная точка проекта была создана с помощью cmake-init. Я пытаюсь добавить gRPC в проект. Однако при использовании флагов покрытия возникает ошибка компоновщика:
build] /usr/bin/ld: CMakeFiles/demo_lib.dir/source/lib.cpp.o: warning: relocation against `_ZTVN4grpc12experimental38FileWatcherAuthorizationPolicyProviderE' in read-only section `.text._ZN4grpc12experimental38FileWatcherAuthorizationPolicyProviderC2EP34grpc_authorization_policy_provider[_ZN4grpc12experimental38FileWatcherAuthorizationPolicyProviderC5EP34grpc_authorization_policy_provider]'
[build] /usr/bin/ld: /usr/bin/ld: ../CMakeFiles/demo_lib.dir/source/lib.cpp.o: warning: relocation against `_ZTVN4grpc12experimental38FileWatcherAuthorizationPolicyProviderE' in read-only section `.text._ZN4grpc12experimental38FileWatcherAuthorizationPolicyProviderC2EP34grpc_authorization_policy_provider[_ZN4grpc12experimental38FileWatcherAuthorizationPolicyProviderC5EP34grpc_authorization_policy_provider]'
[build] /usr/bin/ld: ../CMakeFiles/demo_lib.dir/source/lib.cpp.o: in function `grpc::experimental::StaticDataAuthorizationPolicyProvider::StaticDataAuthorizationPolicyProvider(grpc_authorization_policy_provider*)':
[build] /home/toto/development/cmake-init-tuto/demo/build/coverage/vcpkg_installed/x64-linux/include/grpcpp/security/authorization_policy_provider.h:48: undefined reference to `vtable for grpc::experimental::StaticDataAuthorizationPolicyProvider'
[build] /usr/bin/ld: ../CMakeFiles/demo_lib.dir/source/lib.cpp.o: in function `grpc::experimental::FileWatcherAuthorizationPolicyProvider::FileWatcherAuthorizationPolicyProvider(grpc_authorization_policy_provider*)':
[build] /home/toto/development/cmake-init-tuto/demo/build/coverage/vcpkg_installed/x64-linux/include/grpcpp/security/authorization_policy_provider.h:73: undefined reference to `vtable for grpc::experimental::FileWatcherAuthorizationPolicyProvider'
[build] CMakeFiles/demo_lib.dir/source/lib.cpp.o: in function `grpc::experimental::StaticDataAuthorizationPolicyProvider::StaticDataAuthorizationPolicyProvider(grpc_authorization_policy_provider*)':
[build] /home/toto/development/cmake-init-tuto/demo/build/coverage/vcpkg_installed/x64-linux/include/grpcpp/security/authorization_policy_provider.h:48: undefined reference to `vtable for grpc::experimental::StaticDataAuthorizationPolicyProvider'
[build] /usr/bin/ld: CMakeFiles/demo_lib.dir/source/lib.cpp.o: in function `grpc::experimental::FileWatcherAuthorizationPolicyProvider::FileWatcherAuthorizationPolicyProvider(grpc_authorization_policy_provider*)':
[build] /home/toto/development/cmake-init-tuto/demo/build/coverage/vcpkg_installed/x64-linux/include/grpcpp/security/authorization_policy_provider.h:73: undefined reference to `vtable for grpc::experimental::FileWatcherAuthorizationPolicyProvider'
Отличие от подобных вопросов здесь в том, что без флагов покрытия этого не происходит + я никак не использую AuthorizationPolicy. Код, который я сейчас использую, по сути, тот, что вы можете найти на https://github.com/faaxm/exmpl-cmake-grpc
Вот соответствующие флаги из CMakePresets.json:
{
"name": "flags-unix",
"hidden": true,
"cacheVariables": {
"CMAKE_CXX_FLAGS": "-Wall -Wextra -Wpedantic -Wconversion -Wsign-conversion -Wcast-qual -Wformat=2 -Wundef -Werror=float-equal -Wshadow -Wcast-align -Wunused -Wnull-dereference -Wdouble-promotion -Wimplicit-fallthrough -Wextra-semi -Woverloaded-virtual -Wnon-virtual-dtor -Wold-style-cast -Wl,--whole-archive -Wl,--allow-multiple-definition"
}
},
{
"name": "coverage-unix",
"binaryDir": "${sourceDir}/build/coverage",
"inherits": "ci-unix",
"hidden": true,
"cacheVariables": {
"ENABLE_COVERAGE": "ON",
"CMAKE_BUILD_TYPE": "Coverage",
"CMAKE_CXX_FLAGS_COVERAGE": "-Og -g --coverage -fkeep-inline-functions -fkeep-static-functions",
"CMAKE_EXE_LINKER_FLAGS_COVERAGE": "--coverage",
"CMAKE_SHARED_LINKER_FLAGS_COVERAGE": "--coverage",
"CMAKE_MAP_IMPORTED_CONFIG_COVERAGE": "Coverage;RelWithDebInfo;Release;Debug;"
}
},
Редактировать:
Заголовок, на который есть ссылка, находится здесь: https://grpc.github.io/grpc/cpp/authorization__policy__provider_8h_source.html (всего 80 строк). мне не кажется, что какой-то чисто-виртуальный метод не определен. Я ошибаюсь?
Вот как выглядит исходный файл: https://github.com/faaxm/exmpl-cmake-grpc/blob/master/server/src/main.cpp за исключением того, что в моем случае это функция void launch_server()
из int main()
, а настоящие int main()
звонки launch_server()
.
Одна (возможно) подсказка, которая у меня есть, заключается в том, что класс ServerBuilder
('grpcpp/server_builder.h') имеет:
class ServerBuilder {
public:
ServerBuilder();
virtual ~ServerBuilder();
// (...)
/// NOTE: class experimental_type is not part of the public API of this class.
/// TODO(yashykt): Integrate into public API when this is no longer
/// experimental.
class experimental_type {
public:
// (...)
/// Sets server authorization policy provider in
/// GRPC_ARG_AUTHORIZATION_POLICY_PROVIDER channel argument.
void SetAuthorizationPolicyProvider(
std::shared_ptr<experimental::AuthorizationPolicyProviderInterface>
provider);
private:
ServerBuilder* builder_;
};
//(...)
private:
std::shared_ptr<experimental::AuthorizationPolicyProviderInterface>
authorization_provider_;
Это единственный способ, которым AuthorizationPolicyProvider каким-то образом попадает в мой код, через класс gRPC ServerBuilder
. Что мне делать тогда?
IIRC это связано с чем-то, что называется независимым кодом позиции. По сути, у вас есть статическая библиотека, которую вы хотите связать в общей библиотеке (это, скорее всего, вызвано флагом --coverage
), вы не можете сделать это без независимого от позиции кода. Что вам нужно сделать, так это перекомпилировать статические библиотеки, передав -fPIC
.
Затем вы можете перекомпилировать свой проект, и он должен работать.
Обновлено: Вот ссылка на вопрос stackoverflow с объяснением того, как выяснить, была ли библиотека скомпилирована с помощью -fPIC
.
@mmnano50 Обратитесь к часто задаваемым вопросам GCC для неопределенной ссылки на vtable, то есть вы, вероятно, не определяете некоторые чисто виртуальные методы, которые вам следует.
Если не считать того, что я не использую провайдер политики авторизации, если посмотреть шапку grpc.github.io/grpc/cpp/… (это всего 80 строк), которая выдаёт эти ошибки, то не похоже мне что никакие чисто-виртуальные методы не определены. Я ошибаюсь?
Возможно, вы не делаете этого явно, но какой-то класс/функция, которую вы используете, использует его. Трудно сказать без минимального воспроизводимого примера. Мое дикое предположение (основываясь на том факте, что вы упомянули, что это не работает с флагом --coverage
), что каким-то образом генерация покрытия пытается его использовать, и поскольку у него нет определенного деструктора, он выдает эту ошибку. Но это всего лишь предположение.
Я поставил = default
для деструкторов реализации AuthorizationPolicy в заголовке gRPC, и теперь он работает как задумано. Меня это все еще немного беспокоит, поэтому я открыл вопрос на странице gRPC github, чтобы посмотреть, что они предлагают.
@ mmnano50 Я не думаю, что есть другой способ обойти это, кроме того, что вы описали. Вы также можете (теоретически) сделать все возможное и написать #ifdef guards
, чтобы разделить его для целей тестирования (покрытия) и не тестирования. Я буду честен, я сам не уверен, как бы я подошел к этому по-другому.
Спасибо за совет. Я добавил
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
поверх файла CMakeLists.txt (я также проверил -fPIC с помощью readelf). Я получаю те жеundefined reference to vtable for grpc::experimental::...
ошибки, но не получаюwarning: relocation against ...
предупреждений. Ошибка продолжает появляться...