faaxm/exmpl-cmake-grpc

`protoc-gen-grpc: program not found or is not executable`

kotx opened this issue ยท 16 comments

kotx commented
get_target_property(grpc_cpp_plugin_location gRPC::grpc_cpp_plugin LOCATION)
message(STATUS "Found gRPC C++ plugin at ${grpc_cpp_plugin_location}")
...
protobuf_generate(TARGET maid_proto LANGUAGE grpc GENERATE_EXTENSIONS .grpc.pb.h .grpc.pb.cpp PLUGIN "protoc-gen-grpc=${grpc_cpp_plugin_location}")

yields the output:

-- Found gRPC C++ plugin at /usr/bin/grpc_cpp_plugin
-- Configuring done
-- Generating done
-- Build files have been written to: /usr/src/maid/bin
[ 12%] Running grpc protocol buffer compiler on remote.proto
protoc-gen-grpc: program not found or is not executable
Please specify a program using absolute path or make sure the program is available in your PATH system variable
--grpc_out: protoc-gen-grpc: Plugin failed with status code 1.
make[2]: *** [protos/CMakeFiles/maid_proto.dir/build.make:90: protos/remote.grpc.pb.h] Error 1
make[1]: *** [CMakeFiles/Makefile2:141: protos/CMakeFiles/maid_proto.dir/all] Error 2
make: *** [Makefile:149: all] Error 2

Why doesn't this build? grpc_cpp_plugin is available in PATH, since it's in /usr/bin.

faaxm commented

This is from your own project, right? Have you tried running the unchanged example from this repo first?

I haven't come across error this myself, so not sure when/why it pops up. I do wonder though if the "not found" error message is actually correct or if the --grpc_out: protoc-gen-grpc: Plugin failed with status code 1. part is the more important one. Looks like it did find and execute something if it got a status code back...

Try executing protoc manually on your files and see if that works. Or check the generated makefile to see which commands are generated by cmake and would actually be run.

kotx commented

I tried running the example from this repo, only changing

find_package(protobuf REQUIRED)

to

include(FindProtobuf)
find_package(Protobuf REQUIRED)

at the top of proto/CMakeLists.txt- CMake couldn't find the system protobuf otherwise.
Manually running protoc works fine.
I get the same error.
This might be an issue with the Dockerfile I am using to run the project:

FROM alpine:latest AS base
WORKDIR /maid
EXPOSE 80

FROM alpine:latest AS build

# Build deps
RUN apk --no-cache add cmake build-base \
    grpc grpc-dev protobuf-dev c-ares-dev

WORKDIR /usr/src/app
COPY . /usr/src/app

# RUN mkdir bin
# This runs fine
# RUN protoc --proto_path=protos --grpc_out=bin/ --plugin=protoc-gen-grpc=/usr/bin/grpc_cpp_plugin protos/remote.proto

RUN cmake -B bin -S . \
    && cmake --build bin && cmake --install bin # fails here
...
kotx commented

The generated Makefile is here https://paste.mod.gg/fujiyazeli.makefile
It seems like the PLUGIN argument isn't recognized?

kotx commented

Update: it runs cd /usr/src/maid/build/proto && /usr/bin/protoc --grpc_out /usr/src/maid/build/proto -I /usr/src/maid/proto /usr/src/maid/proto/remote.proto, which does not include --plugin. Including --plugin manually works. I'm using protobuf 3.13, and the PLUGIN argument was added in 3.12 here. Weird.

kotx commented

I resolved this with ln -s $(which grpc_cpp_plugin) /usr/bin/protoc-gen-grpc. Dumb workaround, but it works for now.

I think this was caused by me using the system install of protobuf/grpc

faaxm commented

You should not have to use include(FindProtobuf). It looks like protobuf was not properly installed and is missing its cmake files. In that case, you are probably using the outdated FindProtobuf.cmake that is installed together with cmake, rather than the protobuf-config.cmake that comes with protobuf.

Try installing protobuf yourself from source, via cmake, and see if that fixes it.

If you want to learn more about *-config.cmake vs Find*.cmake have a look at this article and its "Resources" section at the end: Installing a Config.cmake file

xakod commented

I have the same issue with original example but with grpc/protobuf from conan

include(${CMAKE_CURRENT_SOURCE_DIR}/../conanbuildinfo.cmake)

conan_basic_setup(TARGETS)

find_package(Protobuf REQUIRED)

include(${CONAN_LIB_DIRS_GRPC}/cmake/grpc_cpp_plugin.cmake)

find_package(Threads)

#
# Protobuf/Grpc source files
#
set(PROTO_FILES
    myproto/address.proto
    myproto/addressbook.proto
)

#
# Add Library target with protobuf sources
#
add_library(myproto ${PROTO_FILES})
target_link_libraries(myproto
    PUBLIC CONAN_PKG::grpc
    PUBLIC CONAN_PKG::protobuf
)
target_include_directories(myproto PUBLIC ${CMAKE_CURRENT_BINARY_DIR})

#
# Compile protobuf and grpc files in myproto target to cpp
#
#grpc_cpp_plugin_location
get_target_property(grpc_cpp_plugin_location gRPC::grpc_cpp_plugin LOCATION)
message(STATUS "PLUGIN: " ${grpc_cpp_plugin_location})

protobuf_generate(TARGET myproto LANGUAGE cpp)
protobuf_generate(TARGET myproto LANGUAGE grpc GENERATE_EXTENSIONS .grpc.pb.h .grpc.pb.cc PLUGIN "protoc-gen-grpc=${grpc_cpp_plugin_location}")

Cmake printed:

...
PLUGIN: /home/user/.conan/data/grpc/1.37.1/_/_/package/c6934006d4c320ee1a1fb24a7853e896b2448a0d/bin/grpc_cpp_plugin
Configuring done

But when try to build:

13:24:49: Running steps for project example-grpc...
13:24:49: Starting: "/home/user/Qt/Tools/CMake/bin/cmake" --build . --target all
[1/11 143.8/sec] Running grpc protocol buffer compiler on myproto/address.proto
FAILED: proto/myproto/address.grpc.pb.h proto/myproto/address.grpc.pb.cc proto/myproto/addressPLUGIN proto/myproto/addressprotoc-gen-grpc=/home/user/.conan/data/grpc/1.37.1/_/_/package/c6934006d4c320ee1a1fb24a7853e896b2448a0d/bin/grpc_cpp_plugin 
cd /home/user/source/build-exmpl-cmake-grpc-Desktop_Static_Clang_11_C_x86_64bit_in_usr_bin-Debug/proto && /home/user/.conan/data/protobuf/3.15.5/_/_/package/82b72b71ebffd9953ea98f1c4a04285d3ab84af2/bin/protoc --grpc_out /home/user/source/build-exmpl-cmake-grpc-Desktop_Static_Clang_11_C_x86_64bit_in_usr_bin-Debug/proto -I /home/user/source/exmpl-cmake-grpc/proto /home/user/source/exmpl-cmake-grpc/proto/myproto/address.proto
protoc-gen-grpc: program not found or is not executable
Please specify a program using absolute path or make sure the program is available in your PATH system variable
--grpc_out: protoc-gen-grpc: Plugin failed with status code 1.
[2/11 267.4/sec] Running grpc protocol buffer compiler on myproto/addressbook.proto
FAILED: proto/myproto/addressbook.grpc.pb.h proto/myproto/addressbook.grpc.pb.cc proto/myproto/addressbookPLUGIN proto/myproto/addressbookprotoc-gen-grpc=/home/user/.conan/data/grpc/1.37.1/_/_/package/c6934006d4c320ee1a1fb24a7853e896b2448a0d/bin/grpc_cpp_plugin 
cd /home/user/source/build-exmpl-cmake-grpc-Desktop_Static_Clang_11_C_x86_64bit_in_usr_bin-Debug/proto && /home/user/.conan/data/protobuf/3.15.5/_/_/package/82b72b71ebffd9953ea98f1c4a04285d3ab84af2/bin/protoc --grpc_out /home/user/source/build-exmpl-cmake-grpc-Desktop_Static_Clang_11_C_x86_64bit_in_usr_bin-Debug/proto -I /home/user/source/exmpl-cmake-grpc/proto /home/user/source/exmpl-cmake-grpc/proto/myproto/addressbook.proto
protoc-gen-grpc: program not found or is not executable
Please specify a program using absolute path or make sure the program is available in your PATH system variable
--grpc_out: protoc-gen-grpc: Plugin failed with status code 1.
ninja: build stopped: subcommand failed.
13:24:49: The process "/home/user/Qt/Tools/CMake/bin/cmake" exited with code 1.
Error while building/deploying project example-grpc (kit: Desktop Static Clang 11 (C++, x86 64bit in /usr/bin))
When executing step "CMake Build"

Do you have any ideas what i did wrong?

Thanks so much for this repository, it's extremely helpful!

Try installing protobuf yourself from source, via cmake, and see if that fixes it.

This issue is reproducible even when installing protobuf from source, e.g. with this Dockerfile:

FROM debian:bullseye-slim

RUN apt update && apt install -y build-essential autoconf libtool pkg-config git cmake libc-ares-dev libre2-dev libssl-dev zlib1g-dev curl

RUN mkdir -p /build/abseil-cpp && cd /build/abseil-cpp && \
    curl -sSL https://github.com/abseil/abseil-cpp/archive/refs/tags/20210324.2.tar.gz | tar -xzf - --strip=1 && \
    mkdir build && cd build && \
    cmake .. \
    -DCMAKE_BUILD_TYPE=Release \
    -DBUILD_TESTING=OFF \
    -DBUILD_SHARED_LIBS=yes && \
    make -j64 install && \
    ldconfig

RUN mkdir -p /build/protobuf && cd /build/protobuf && \
    curl -sSL https://github.com/google/protobuf/archive/v3.17.3.tar.gz | tar -xzf - --strip=1 && \
    mkdir build && cd build && \
    cmake ../cmake \
    -DCMAKE_BUILD_TYPE=Release \
    -DBUILD_SHARED_LIBS=yes \
    -Dprotobuf_BUILD_TESTS=OFF && \
    make -j64 install && \
    ldconfig

RUN mkdir -p /build/grpc && cd /build/grpc && \
    curl -sSL https://github.com/grpc/grpc/archive/refs/tags/v1.39.0-pre1.tar.gz| tar -xzf - --strip=1 && \
    mkdir build && cd build && \
    cmake .. \
    -DCMAKE_BUILD_TYPE=Release \
    -DgRPC_INSTALL=ON \
    -DgRPC_BUILD_TESTS=OFF \
    -DgRPC_ABSL_PROVIDER=package \
    -DgRPC_CARES_PROVIDER=package \
    -DgRPC_PROTOBUF_PROVIDER=package \
    -DgRPC_RE2_PROVIDER=package \
    -DgRPC_SSL_PROVIDER=package \
    -DgRPC_ZLIB_PROVIDER=package && \
    make -j64 install && \
    ldconfig

RUN cd / && \
    git clone https://github.com/faaxm/exmpl-cmake-grpc.git && \
    cd exmpl-cmake-grpc && \
    mkdir build && cd build && \
    cmake .. && \
    make -j64

Strangely, when using a module provider build for gRPC instead, it's working. I'm not sure whether that's due to a slight difference in versions or something else. Here's a corresponding Dockerfile:

FROM debian:bullseye-slim

RUN apt update && apt install -y build-essential autoconf libtool pkg-config git cmake libc-ares-dev libre2-dev libssl-dev zlib1g-dev curl

RUN git clone --recurse-submodules -b v1.39.0-pre1 https://github.com/grpc/grpc && \
    cd /grpc/third_party/abseil-cpp && \
    cmake . && \
    make -j64 install && \
    cd /grpc && mkdir build && cd build && \
    cmake -DgRPC_INSTALL=ON -DgRPC_BUILD_TESTS=OFF .. && \
    make -j64 install && \
    ldconfig

RUN cd / && \
    git clone https://github.com/faaxm/exmpl-cmake-grpc.git && \
    cd exmpl-cmake-grpc && \
    mkdir build && cd build && \
    cmake .. && \
    make -j64

The repro case can also be "fixed" by deleting /usr/share/cmake-3.18/Modules/FindProtobuf.cmake before running cmake for exmpl-cmake-grpc.

It's like FindProtobuf.cmake is used preferentially to protobuf-config.cmake, despite their being no include(FindProtobuf) in exmpl-cmake-grpc's CMakeLists.txt. Maybe the gRPC dependency pulls this in?

faaxm commented

Yes, you are right @lgruen, gRPC can pull in the wrong FindProtobuf.cmake as part of its gRPCConfig.cmake.
Adding -DgRPC_PROTOBUF_PACKAGE_TYPE=CONFIG when configuring/building gRPC fixes the issue.

As to the why:
I had a look at https://github.com/grpc/grpc/blob/master/cmake/protobuf.cmake and there, when gRPC_PROTOBUF_PROVIDER is package, it uses gRPC_PROTOBUF_PACKAGE_TYPE as additional flags to find_package.

This would not be too bad if that only happened when installing gRPC. But the issue is then created further down:
At https://github.com/grpc/grpc/blob/master/cmake/protobuf.cmake#L93 they store a recipe to find protobuf in the variable _gRPC_FIND_PROTOBUF. This variable is then inserted into their gRPCConfig.cmake here:
https://github.com/grpc/grpc/blob/master/cmake/gRPCConfig.cmake.in#L6

faaxm commented

If it's ok with you, I'd take parts of your Dockerfile and turn it into a github workflow for this repo as an example build and to see if future grpc/protobuf/cmake releases break stuff.

Impressive debugging, @faaxm! -DgRPC_PROTOBUF_PACKAGE_TYPE=CONFIG works perfectly, thanks very much for that tip!

If it's ok with you, I'd take parts of your Dockerfile and turn it into a github workflow for this repo as an example build and to see if future grpc/protobuf/cmake releases break stuff.

Of course, that would be great! You could even have a scheduled GitHub Action and clone the dependencies at HEAD each time you run.

You have probably wrong (outdated) version of FindProtobuf.cmake file distributed with the version of CMake you use.
Just replace it with the latest one supporting PLUGIN param taken from here for instance. Your version of FindProtobuf.cmake has to have PLUGIN param name in this line.

Upgrading from cmake version 3.20 to 3.22.5 solved this problem for me

I resolved this with ln -s $(which grpc_cpp_plugin) /usr/bin/protoc-gen-grpc. Dumb workaround, but it works for now.

I think this was caused by me using the system install of protobuf/grpc

These kinds of workarounds are fine for local testing but they don't work on CI/Docker images.

I resolved this with ln -s $(which grpc_cpp_plugin) /usr/bin/protoc-gen-grpc. Dumb workaround, but it works for now.

I think this was caused by me using the system install of protobuf/grpc

i really f**king love you!