conan icon indicating copy to clipboard operation
conan copied to clipboard

[question] find_program with Conan 2 not working as expected

Open rollebolle opened this issue 1 year ago • 8 comments

What is your question?

Conan 2.5.0 Given a very simple program with a CMake file like:

project(myprog)

include(GNUInstallDirs)

add_executable(myprog myprog.c)
install(TARGETS myprog DESTINATION ${CMAKE_INSTALL_BINDIR})

And a Conan file like:

def layout(self):
        cmake_layout(self, src_folder=Foo._source_dir())

    def generate(self):
        tc = CMakeToolchain(self)
        tc.generate()

    def build(self):
        cmake = CMake(self)
        cmake.configure(build_script_folder=Foo._source_dir())
        cmake.build()

    def package(self):
        cmake = CMake(self)
        cmake.install()

    def package_info(self):
        self.cpp_info.set_property("cmake_file_name", "myprog")
        self.cpp_info.set_property("cmake_target_name", "myprog::myprog")
        self.cpp_info.set_property("pkg_config_name", "myprog")
        
        self.cpp_info.names["cmake_find_package"] = "myprog"
        self.cpp_info.names["cmake_find_package_multi"] = "myprog"

I can see my "myprog" being built and put in the bin folder of the package, just like in Conan 1.63. However when I try to consume the binary with

find_program(MYPROG myprog)

I cannot find it, opposed to with Conan 1 where it did find the file. I see that the BINDIRS variable is not set in the generated XXX-config files (even though docs says it should default to "bin"). What have I done wrong? Using generators CMakeToolchain, CMakeDeps.

Have you read the CONTRIBUTING guide?

  • [X] I've read the CONTRIBUTING guide

rollebolle avatar Aug 22 '24 17:08 rollebolle

Hi @rollebolle

thanks for your question.

I am missing some part of your conanfile.py that would be the most important, the requirements.

Probably this is related to the fact that the dependency must be a tool_requires, not a regular requires. If the consumer is finding a program to execute this, necessarily this program must belong to the "build" context, not to the "host" context. An example of this is cross-building, in which the executables in the host context won't run in the current build machine. You can read more about the build and host contexts here: https://docs.conan.io/2/tutorial/consuming_packages/cross_building_with_conan.html

Are you using tool_requires for this dependency? If not, can you please change it and try again?

memsharded avatar Aug 23 '24 07:08 memsharded

Sorry - the full conanfile.py for my package is supplied below. For consuming the package in my app I use the simpler declarative conanfile.txt, with the package under the [requires] section. Moving it to [tool_requires] did not work. Also, in this specfic case, the "myprog" is not a build tool but simply forwarded as an install file in my app.

I am (again) assuming the difference between the Conan 1 and 2 case is the FindXXX vs XXX-config way of finding the package.

Just to make sure I didn't do anything wrong on the consumer end, I also tried it in the cmake-conan example, with cross-compilation etc, and got the same problem. Here is the rest of the conanfile.py (stripped away source section as it is not very interesting and long):

class Foo(ConanFile):
    name = "myprog"
    license = "Commercial"
    author = ""
    description = ""
    exports_sources = "CMakeLists.txt"
    settings = "os", "arch", "compiler", "build_type"
    options = {
        "shared": [True, False],
        "fPIC": [True, False],
    }

    default_options = {
        "shared": False,
        "fPIC": True,
    }


rollebolle avatar Aug 23 '24 21:08 rollebolle

I am not sure what could be failing, there might be some detail missing.

I have just tried:

  • $ conan new cmake_exe -d name=tool -d version=0.1
  • $ conan create .
  • $ rm -rf .
  • $ conan new cmake_lib -d name=pkg -d version=0.1
  • Edit the conanfile.py and add tool_requires = "tool/0.1"
  • Edit the CMakeLists.txt and add:
    find_program(MYTOOL tool REQUIRED)
    message(STATUS "Found MYTOOL executable: ${MYTOOL}")
    
  • $ conan install .
  • $ cmake --preset conan-default (Windows)

And it worked. So there might be something missing somewhere. If you could please try to put together a reproducible full example, that would help.

memsharded avatar Aug 23 '24 21:08 memsharded

Yes. Using the cmake-conan repo example again, I have modified the conanfile.txt like so:

[requires]
exe2/0.1

[layout]
cmake_layout

[generators]
CMakeToolchain
CMakeDeps

The CMakeFile in the example folder:

cmake_minimum_required(VERSION 3.24)

project(FormatOutput LANGUAGES CXX C)

set(CMAKE_CXX_STANDARD 14)


find_package(ex2 REQUIRED)
find_program(ex2_EXEC ex2 NO_SYSTEM_ENVIRONMENT_PATH REQUIRED)

The package conanfile.py

class InventoryConan(ConanFile):
    name = "exe2"
    license = "Commercial"
    author = ""
    exports_sources = "*"
    settings = "os", "arch", "compiler", "build_type"
    options = {
        "shared": [True, False],
        "fPIC": [True, False],
    }

    default_options = {
        "shared": False,
        "fPIC": True,
    }

    @staticmethod
    def _source_dir():
        return "."

    def layout(self):
        cmake_layout(self, src_folder=InventoryConan._source_dir())

    def generate(self):
        tc = CMakeToolchain(self)
        tc.generate()

    def build(self):
        cmake = CMake(self)
        cmake.configure(build_script_folder=InventoryConan._source_dir())
        cmake.build()

    def package(self):
        cmake = CMake(self)
        cmake.install()

    def package_info(self):
        self.cpp_info.set_property("cmake_file_name", "ex2")
        self.cpp_info.set_property("cmake_target_name", "ex2::ex2")
        self.cpp_info.set_property("pkg_config_name", "ex2")
        self.cpp_info.bindirs.append("bin")
        self.cpp_info.components["ex2"].bindirs = ["bin"]

        self.cpp_info.names["cmake_find_package"] = "ex2"
        self.cpp_info.names["cmake_find_package_multi"] = "ex2"

        self.cpp_info.set_property("cmake_find_mode", "both")

The package CMakeLists file:

cmake_minimum_required(VERSION 3.10)
project(ex2)
add_executable(ex2 main.cpp)
include(GNUInstallDirs)
install(TARGETS ex2 DESTINATION ${CMAKE_INSTALL_BINDIR})

The commands I run. First in the folder containing the exe2 package: conan create . --version 0.1

I can confirm the package is created and contains a binary called ex2

Then the cmake command in the example folder:

cmake -B build -S . DCMAKE_PROJECT_TOP_LEVEL_INCLUDES=../conan_provider.cmake -DCMAKE_BUILD_TYPE=Release

The error (note that the package itself is found correctly):

CMake Error at CMakeLists.txt:9 (find_program):
  Could not find ex2_EXEC using the following names: ex2

rollebolle avatar Aug 25 '24 18:08 rollebolle

Thanks for the feedback and the details.

This is because the new cmake-conan integration in Conan 2 uses the transparent CMake dependency providers, but that means in practice they do not inject the conan_toolchain.cmake, and some information that is injected that way might not be available. For example, tool_requires environment information like env-vars cannot be injected in the same way.

You can see if it works with the "normal" flow in the consumer:

  • conan install .
  • conanbuild.bat (in Windows) or source conanbuild.sh (in Linux/Mac)
  • cmake --preset conan-default (Windows) cmake --preset conan-release ( Windows)
  • cmake --build --preset conan-release

Can you please try that and let me know? If it works, then this would be a question to move to the cmake-conan repo, (still it is possible that it is an intrinsic limitation of the cmake-conan flow, we will see)

memsharded avatar Aug 25 '24 20:08 memsharded

I tried the above commands almost exactly (conan ../../.. --preset conan-release) but with the same error as above

rollebolle avatar Aug 26 '24 20:08 rollebolle

I don't know where the difference could be, I am using the default templates like from conan new cmake_exe, not sure what else to suggest. I think it will be necessary to have a full repro case: if you can please put complete source code in a Github repo, together with a script (like a build.py script) with exact commands that can be executed and reproduce the issue, that would help a lot, we could reproduce that and check what would be the issue.

memsharded avatar Aug 26 '24 22:08 memsharded

I invited you to look in a repository I have created, with instructions on how to get the error in Conan 2 (and succeed in Conan 1)

rollebolle avatar Aug 27 '24 20:08 rollebolle

Following up on this. Conan latest versions already got the new "incubating CMakeDeps", see https://docs.conan.io/2/incubating.html.

This new generator creates a new file that will be able to be used by the cmake-conan integration to do find_program()

memsharded avatar Dec 23 '24 17:12 memsharded

This ticket should now be fixed with the new CMakeConfigDeps generator: https://docs.conan.io/2/incubating.html, available in Conan 2.12. Please open a new ticket for any further issue with the CMakeConfigDeps generator if necessary.

To get the new CMakeConfigDeps out of "incubating", please test it and report your positive feedback in https://github.com/conan-io/conan/issues/18211 (for issues/questions, better open new tickets)

For cmake-conan integration, it will need a couple of adjustements, I already have them in a branch, but necessary to get CMakeConfigDeps out of incubating first.

Many thanks!

memsharded avatar May 05 '25 13:05 memsharded