conan-io / conan-center-index

Recipes for the ConanCenter repository
https://conan.io/center
MIT License
921 stars 1.66k forks source link

[package] grpc/1.46.3: When compiling with 'dockcross': get_target_property() called with non-existent target "gRPC::grpc_cpp_plugin" #13017

Open vince-cheung opened 1 year ago

vince-cheung commented 1 year ago

Package and Environment Details

Conan profile

default

[settings]
os=Linux
os_build=Linux
arch=x86_64
arch_build=x86_64
compiler=gcc
compiler.version=7
compiler.libcxx=libstdc++
build_type=Release
[options]
[build_requires]
[env]

arm64

[settings]
os=Linux
os_build=Linux
arch=armv8
arch_build=armv8
compiler=gcc
compiler.version=8
compiler.libcxx=libstdc++
build_type=Release
[options]
[build_requires]
[env]

Steps to reproduce

I try to cross compile my project with dockcross(dockcross/linux-arm64-lts). conanfile.txt:

[requires]
qt/5.15.4
grpc/1.46.3
protobuf/3.21.4
spdlog/1.10.0

[options]
qt:opengl=no
qt:with_mysql=False
qt:gui=False
qt:widgets=False

[generators]
cmake_find_package
cmake_find_package_multi

conan install(conan install .. -pr:h=arm64 -pr:b=default -s:b compiler.version=8 --build=missing) runs successfully. Then the cmake command(cmake .. -DCMAKE_BUILD_TYPE=Release) reports an error:

CMake Error at CMakeLists.txt:139 (get_target_property):
  get_target_property() called with non-existent target
  "gRPC::grpc_cpp_plugin".

The error is from my CMakeLists.txt file, I use protobuf_generate:

protobuf_generate(TARGET ${PROJECT_NAME} LANGUAGE cpp)
get_target_property(grpc_cpp_plugin_location gRPC::grpc_cpp_plugin LOCATION)
protobuf_generate(TARGET ${PROJECT_NAME} LANGUAGE grpc GENERATE_EXTENSIONS .grpc.pb.h .grpc.pb.cc PLUGIN "protoc-gen-grpc=${grpc_cpp_plugin_location}")

I found in file ~/.conan/data/grpc/1.46.3/_/_/package/69feecc13746d09e90c7c37d8a10623aa92af90e/lib/cmake/conan_trick/grpc_cpp_plugin.cmake

if(NOT TARGET gRPC::grpc_cpp_plugin)
    if(CMAKE_CROSSCOMPILING)
        find_program(GRPC_CPP_PLUGIN_PROGRAM
            NAMES grpc_cpp_plugin
            PATHS ENV PATH
            NO_DEFAULT_PATH
        )
    else()
        find_program(GRPC_CPP_PLUGIN_PROGRAM
            NAMES grpc_cpp_plugin
            PATHS "${CMAKE_CURRENT_LIST_DIR}/../../../bin/"
            NO_DEFAULT_PATH
        )
    endif()
    # TODO: In conan v2 with CMakeToolchain, can be replaced by:
    # find_program(GRPC_CPP_PLUGIN_PROGRAM NAMES grpc_cpp_plugin))
    # # Nice enough to handle grpc not in build_requires for native build
    # if(NOT GRPC_CPP_PLUGIN_PROGRAM AND NOT CMAKE_CROSSCOMPILING)
    #     find_program(GRPC_CPP_PLUGIN_PROGRAM
    #         NAMES grpc_cpp_plugin
    #         PATHS "${CMAKE_CURRENT_LIST_DIR}/../../../bin/"
    #         NO_DEFAULT_PATH
    #     )
    # endif()

    if(GRPC_CPP_PLUGIN_PROGRAM)
        get_filename_component(GRPC_CPP_PLUGIN_PROGRAM "${GRPC_CPP_PLUGIN_PROGRAM}" ABSOLUTE)
        add_executable(gRPC::grpc_cpp_plugin IMPORTED)
        set_property(TARGET gRPC::grpc_cpp_plugin PROPERTY IMPORTED_LOCATION ${GRPC_CPP_PLUGIN_PROGRAM})
    endif()
endif()

CMAKE_CROSSCOMPILING is True, so it means I need to install native grpc_cpp_plugin in my PATH. So, I modified my conanfile.txt:

[requires]
qt/5.15.4
grpc/1.46.3
protobuf/3.21.4
spdlog/1.10.0

[options]
qt:opengl=no
qt:with_mysql=False
qt:gui=False
qt:widgets=False

[generators]
cmake_find_package
cmake_find_package_multi

[tool_requires]
grpc/1.46.3
protobuf/3.21.4

It didn't work. But I found that protoc is also not in the PATH, but it still works. In the file ~/.conan/data/protobuf/3.21.4/_/_/package/3df7cfba666c1c4af4d5416aa1a6ad3e9e6e2631/lib/cmake/protobuf/protobuf-generate.cmake:

# Imported targets
if(NOT TARGET protobuf::protoc)
    if(CMAKE_CROSSCOMPILING)
        find_program(PROTOC_PROGRAM protoc PATHS ENV PATH NO_DEFAULT_PATH)
    endif()
    if(NOT PROTOC_PROGRAM)
        set(PROTOC_PROGRAM "${CMAKE_CURRENT_LIST_DIR}/../../../bin/protoc")
    endif()
    get_filename_component(PROTOC_PROGRAM "${PROTOC_PROGRAM}" ABSOLUTE)
    set(Protobuf_PROTOC_EXECUTABLE ${PROTOC_PROGRAM} CACHE FILEPATH "The protoc compiler")
    add_executable(protobuf::protoc IMPORTED)
    set_property(TARGET protobuf::protoc PROPERTY IMPORTED_LOCATION ${Protobuf_PROTOC_EXECUTABLE})
endif()

I modified the above file grpc_cpp_plugin.cmake according to protobuf-generate.cmake:

...
    if(CMAKE_CROSSCOMPILING)
        find_program(GRPC_CPP_PLUGIN_PROGRAM
            NAMES grpc_cpp_plugin
            PATHS ENV PATH
            NO_DEFAULT_PATH
        )
    endif()
    if(NOT GRPC_CPP_PLUGIN_PROGRAM)
        find_program(GRPC_CPP_PLUGIN_PROGRAM
            NAMES grpc_cpp_plugin
            PATHS "${CMAKE_CURRENT_LIST_DIR}/../../../bin/"
            NO_DEFAULT_PATH
        )
    endif()
...

If grpc_cpp_plugin cannot be found in PATH, try to use the compiled binary directly. Since dockcross includes an emulator, the arm64 protoc and grpc_cpp_plugin work fine. I know that using tool_requires in conanfile.txt is more elegant way, Is it the way I'm using it incorrectly? Please forgive my google english. :(

Logs

No response

SpaceIm commented 1 year ago

CMAKE_CROSSCOMPILING is True, so it means I need to install native grpc_cpp_plugin in my PATH. So, I modified my conanfile.txt:

[requires]
qt/5.15.4
grpc/1.46.3
protobuf/3.21.4
spdlog/1.10.0

[options]
qt:opengl=no
qt:with_mysql=False
qt:gui=False
qt:widgets=False

[generators]
cmake_find_package
cmake_find_package_multi

[tool_requires]
grpc/1.46.3
protobuf/3.21.4

Which generator are you using besides cmake_find_package or cmake_find_package_multi? Without cmake (legacy) or CMakeToolchain generators, you are on your own. When you have tool_requires, without VirtualBuildEnv (populate in a script PATH/LD_LIBRARY_PATH/DYLB_LIBRARY_PATH with paths of tool_requires), you're on your own as well.

So to summarize: at build time of your CMake projects, without the glue of CMakeToolchain & VirtualBuildEnv, there is no guarantee to achieve robust discovery & usage of conan installed libraries & executables.

It didn't work. But I found that protoc is also not in the PATH, but it still works. In the file ~/.conan/data/protobuf/3.21.4/_/_/package/3df7cfba666c1c4af4d5416aa1a6ad3e9e6e2631/lib/cmake/protobuf/protobuf-generate.cmake:

# Imported targets
if(NOT TARGET protobuf::protoc)
    if(CMAKE_CROSSCOMPILING)
        find_program(PROTOC_PROGRAM protoc PATHS ENV PATH NO_DEFAULT_PATH)
    endif()
    if(NOT PROTOC_PROGRAM)
        set(PROTOC_PROGRAM "${CMAKE_CURRENT_LIST_DIR}/../../../bin/protoc")
    endif()
    get_filename_component(PROTOC_PROGRAM "${PROTOC_PROGRAM}" ABSOLUTE)
    set(Protobuf_PROTOC_EXECUTABLE ${PROTOC_PROGRAM} CACHE FILEPATH "The protoc compiler")
    add_executable(protobuf::protoc IMPORTED)
    set_property(TARGET protobuf::protoc PROPERTY IMPORTED_LOCATION ${Protobuf_PROTOC_EXECUTABLE})
endif()

Yes, protobuf recipe is slightly more permissive. It has also more legacy history with conan v1 and 1 profile.

vince-cheung commented 1 year ago

@SpaceIm As you can see, my generators only have cmake_find_package and cmake_find_package_multi, which works fine in native compilation mode, but not in cross compilation. I spent some time doing the following test:

  1. Add cmake to generators, added the following code in CMakeLists.txt:
    include(conanbuildinfo.cmake)
    conan_basic_setup()

    , then:

    $ conan install .. -pr:h=arm64 -pr:b=default -s:b compiler.version=8 --build=missing
    $ cmake ..

    Still not working, through the export command, the directory where grpc_cpp_plugin is located is not in the environment variable PATH.

  2. Add CMakeToolchain to generators, similar steps above, but the cmake command with -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake, it doesn't work.
  3. Add virtualbuildenv to generators, use the command source activate_build.sh before cmake .., it doesn't work. the directory where grpc_cpp_plugin is located is not in the environment variable PATH.
  4. Add virtualrunenv to generators, use the command source activate_run.sh before cmake .., then, grpc_cpp_plugin can be found in PATH. But it is arm64 architecture, and only this one is in the PATH. Need to manually add grpc_cpp_plugin directory to PATH?
roalter commented 1 year ago

A workaround could be to change in the recipe of grpc:

        if any(self.options.get_safe(plugin_option) for plugin_option in self._grpc_plugins.keys()):
            bindir = os.path.join(self.package_folder, "bin")
            self.output.info("Appending PATH environment variable: {}".format(bindir))
            self.env_info.PATH.append(bindir)
            self.env_info.GRPC_BIN_PATH = bindir

Now you have access to the right path.

In the grpc_plugin_template.cmake.in file you just inject the search path either:

        find_program(@find_program_variable@
            NAMES @executable_name@
            PATHS ENV GRPC_BIN_PATH ENV PATH
            NO_DEFAULT_PATH
        )

I opened as PR either,https://github.com/conan-io/conan-center-index/pull/16481