multiscale / muscle3

The third major version of the MUltiScale Coupling Library and Environment
Apache License 2.0
25 stars 13 forks source link

Build doesn't work with system-installed gRPC on Ubuntu 19.10 #40

Closed LourensVeen closed 4 years ago

LourensVeen commented 4 years ago

It detects the system install correctly and skips building gRPC, but then fails with

muscle_manager_protocol.grpc.pb.h:16:10: fatal error: grpcpp/impl/codegen/server_callback.h: No such file or directory
   16 | #include <grpcpp/impl/codegen/server_callback.h>
      |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
compilation terminated.

It seems that the headers aren't included correctly. On this system, libgrpc-dev and libgrpc++-dev were installed, but the protobuf dev package isn't, so it's building its own copy of that (successfully).

Thanks to Hamid for reporting and helping debug!

diregoblin commented 4 years ago

I have a similar issue on Zorin OS 15, which mostly relies on Ubuntu 18.10 LTS for packages.

I also have libgrpc-dev installed, but not protobuf. The results are the same for installing only libgrpc-dev or both it and libgrpc++-dev.

However, my installation fails on a different include, might be due to a different build order.

/home/pavel/src/muscle3/libmuscle/cpp/build/muscle_manager_protocol/../../src/muscle_manager_protocol/muscle_manager_protocol.grpc.pb.h:10:10: fatal error: grpcpp/impl/codegen/async_generic_service.h: No such file or directory
 #include <grpcpp/impl/codegen/async_generic_service.h>
          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
compilation terminated.

muscle3-build.log

diregoblin commented 4 years ago

My gRPC version is 1.3.2-1.1~build1, so it looks like it's all part of the issue #39 where new versions of gRPC don't work.

diregoblin commented 4 years ago

I have worked around this issue by removing the system gRPC and letting muscle install v1.17.1. Apparently gcc 7.5.0 is old enough to compile it.

I still can't build muscle due to more errors, but that's not part of this issue...

LourensVeen commented 4 years ago

Having a system gRPC-dev but not protobuf-dev may be an issue anyway, because the system gRPC will be linked to the system protobuf, but we'll build our own version, so we end up with two different versions of protobuf in the same process. That's probably quite bad. So we should probably use either both system gRPC and system protobuf, or neither.

LourensVeen commented 4 years ago

Ah, it seems that this is grpc 1.16, while we require 1.17. So it seems that the problem is that it is detected, but not recognised as being too old.

LourensVeen commented 4 years ago

The plot thickens. For gRPC 1.17.1, the version of grpc in pkgconfig is 7.0.0, while the version of grpc++ is 1.17.1. We're checking the version of grpc against 1.17.1, and 7.0.0 is higher, so we think we have it installed.

It looks like the grpc library uses the ABI version, while the grpc++ version uses the API version, probably because C++ doesn't have a standardised ABI. That makes sense, but I missed it.

We're actually linking with both grpc and grpc++ in the Makefile, but the shared library ends up referring only to grpc++, and linking only to grpc++ works. So the pkg-config detection needs to use grpc++ for its package name to fix this.

diregoblin commented 4 years ago

Still, this is a very... interesting version naming convention for gRPC

LourensVeen commented 4 years ago

It actually makes sense. Shared libraries with a C interface have a standard ABI, and all that matters for compatibility is whether the .so contains every symbol that your headers declare. So if you fix some bugs or change some other part of the package that isn't the .so file (e.g. tools, in this case), then a binary that was linked against the old version will work with the new version without recompiling. That means you can update a commonly used shared library without having to recompile many applications on your system.

If you're clever about it, you can even install multiple versions of the .so file in parallel to support applications linked against different versions (that's what .so.x.y.z files are for). But that only works if you have a separate versioning scheme which tracks the ABI rather than the API.

In C++, there is no standard for how the C++ declarations map to the .so file's ABI, and the headers may contain actual code (inline functions, templates, lambdas, etc.) which after compilation ends up in the application, not the library .so. While it is possible to do a stable ABI with versioning with C++, it pretty much requires architecting your entire library around it, and then bugs in the header part of the library can still only be fixed by recompiling the application. So for C++ libraries, you often don't bother and just focus on API versioning, and have the users recompile when there's a new version with important fixes. And so your pkgconfig will reflect the API version.

LourensVeen commented 4 years ago

Fix released with 0.3.1. The native build of MUSCLE 3 now requires gRPC 1.24.3 exactly and so will almost always build its own custom version, but if you have it, it will be detected :).