Skip to content

[question] VirtualRunEnv does not take tool_requires into account? #14901

@pklip

Description

@pklip

What is your question?

Hi, I am currently migrating to Conan 2 (i.e. 2.0.12) and facing issues with the VirtualRunEnv generator when using gcc as a conan package which is obviously needed in the buildenv but also in the runenv, since it also provides libs like e.g. libstdc++.so and the like.
My understanding was that in Conan 2 the generator automatically takes care of propagating libdirs to LD_LIBRARY_PATH in the runenv. But this is apparently not the case for tool_requires, although I expected this to be the reason why tool_requires sets the trait run=True.

Specifically I first encountered the issue when building geographiclib (https://github.com/conan-io/conan-center-index/blob/master/recipes/geographiclib/all/test_package/conanfile.py). I provide the compiler dependency using a profile like this:

[settings]
compiler=gcc
compiler.version=11.4
compiler.libcxx=libstdc++11

[tool_requires]
gcc/11.4.0@me/testing

Building geographiclib works fine, but executing the test package leads to the following error:

======== Testing the package: Executing test ========
geographiclib/1.52@me/testing (test package): Running test()
geographiclib/1.52@me/testing (test package): RUN: ./test_package
./test_package: /lib/x86_64-linux-gnu/libstdc++.so.6: version `GLIBCXX_3.4.29' not found (required by /home/me/.conan2/p/b/geogr35b2f1e80aeb9/p/lib/libGeographic.so.19)

ERROR: geographiclib/1.52@me/testing (test package): Error in test() method, line 26
        self.run(bin_path, env="conanrun")
        ConanException: Error 1 while executing

Obviously the libdir of gcc is not part of the LD_LIBRARY_PATH and instead of the libstdc++.so provided by the conan package the system one is found during runtime, which does not match the version from compilation.

This can be mitigated by hacking an explicit runtime dependency into the test package like self.requires("gcc/11.4.0@me/stable", run=True). Then executing the test executable in the conanrun env works. But this is just a hack.

From looking at the code in conan/tools/env/virtualrunenv.py in the environment() method, I see that only host and test dependencies are taken into account for the env:

        host_req = self._conanfile.dependencies.host
        test_req = self._conanfile.dependencies.test
        for require, dep in list(host_req.items()) + list(test_req.items()):
            if dep.runenv_info:
                runenv.compose_env(dep.runenv_info)
            if require.run:  # Only if the require is run (shared or application to be run)
                _os = self._conanfile.settings.get_safe("os")
                runenv.compose_env(runenv_from_cpp_info(dep, _os))

But those host and test properties directly filter for build=False which obviously does not take tool_requires into account which use build=True. See conans/model/dependencies.py line 138:

    @property
    def host(self):
        return self.filter({"build": False, "test": False, "skip": False})

    @property
    def test(self):
        # Not needed a direct_test because they are visible=False so only the direct consumer
        # will have them in the graph
        return self.filter({"build": False, "test": True, "skip": False})

Now, is there a misunderstanding on my side? I would have expected that since tool_requires sets run=True, those should also be reflected in the VirtualRunEnv. Generally I think all dependecies with run=True should be reflected in the VirtualRunEnv.
Indeed changing the code in conan/tools/env/virtualrunenv.py to something like this, makes is work as I expected:

        host_req = self._conanfile.dependencies.host
        test_req = self._conanfile.dependencies.test
        run_req = self._conanfile.dependencies.filter({"run": True})
        for require, dep in list(host_req.items()) + list(test_req.items()) + list(run_req.items()):
            if dep.runenv_info:
                runenv.compose_env(dep.runenv_info)
            if require.run:  # Only if the require is run (shared or application to be run)
                _os = self._conanfile.settings.get_safe("os")
                runenv.compose_env(runenv_from_cpp_info(dep, _os))

What is the best practice here for dependencies needed during build and run?

Have you read the CONTRIBUTING guide?

  • I've read the CONTRIBUTING guide

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions