0

I have a C++ project based on CMake. The starting point of the project was created using cmake-init. I am trying to add gRPC to the project. However, when using coverage flags, a linker error occurs:

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'

The thing that differs from similar questions here is that without the coverage flags, this does not happen + I do not use AuthorizationPolicy in any way. The code I am using right now is essentially what you can find in https://github.com/faaxm/exmpl-cmake-grpc

Here is the relevant flags from the 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;"
      }
    },

Edit:

The header that is referenced is here: https://grpc.github.io/grpc/cpp/authorization__policy__provider_8h_source.html (it's only 80 lines). it does not seem to me that any pure-virtual method are not defined. Am I wrong?

This is what the source file look like: https://github.com/faaxm/exmpl-cmake-grpc/blob/master/server/src/main.cpp except that in my case, it's a void launch_server() function instead of int main(), and the actual int main() calls launch_server(). One (maybe) hint that I have is that the ServerBuilder class ('grpcpp/server_builder.h') has:

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_;

This is the only way that the AuthorizationPolicyProvider somehow gets into my code, through the gRPC ServerBuilder class. What should I do then?

mmnano50
  • 37
  • 6

1 Answers1

1

IIRC this is related to something called Position Independent Code. You essentially have a static library that you wish to link in a shared library (this is most likely caused by the --coverage flag), you can't do that without position independent code. What you need to do is recompile the static libraries by passing -fPIC.

Then you can recompile your project and it should work.

EDIT: Here is a link to a stackoverflow question with an explanation on how to figure out if the library was compiled with -fPIC.

Milan Š.
  • 1,353
  • 1
  • 2
  • 11
  • Thanks for the tip. I added `set(CMAKE_POSITION_INDEPENDENT_CODE ON)` on top of the CMakeLists.txt file (I also checked -fPIC with readelf). I get the same `undefined reference to vtable for grpc::experimental::...` errors but I don't get the `warning: relocation against ...` warnings. The error keep happening ... – mmnano50 Jan 24 '23 at 13:11
  • @mmnano50 Refer to GCC FAQ for [undefined reference to vtable](https://gcc.gnu.org/faq.html#vtables) i.e. you are probably not defining some pure-virtual methods that you should. – Milan Š. Jan 24 '23 at 13:20
  • Outside of the fact that I don't use the authorization policy provider, if you look at the header https://grpc.github.io/grpc/cpp/authorization__policy__provider_8h_source.html (it's only 80 lines) that generate these errors, it does not seem to me that any pure-virtual method are not defined. Am I wrong? – mmnano50 Jan 24 '23 at 13:28
  • 1
    Maybe you aren't doing so explicitly but some class/function that you use - is using it. It's hard to tell without a minimal reproducible example. My wild guess is (based on the fact that you mention it doesn't work with the `--coverage` flag) that somehow the coverage generation tries to use it, and because it doesn't have a defined destructor it throws this error. But it's just a guess. – Milan Š. Jan 24 '23 at 13:34
  • I put `= default` for the destructors of the AuthorizationPolicy implementation in the gRPC header and now it works as intended. It still bothers me a bit so I opened an issue at the gRPC github page to see what they propose – mmnano50 Jan 24 '23 at 14:39
  • @mmnano50 I don't think there is any way around it other than what you described. You could also (theoretically) go the extra mile and write `#ifdef guards` to separate it for testing(coverage)/non-testing purposes. I'll be honest I myself am not sure how I would approach this differently. – Milan Š. Jan 24 '23 at 15:26