Conan: [question] Is there a way to reference specific targets with the CMake find_package_multi generator?

Created on 28 May 2020  路  8Comments  路  Source: conan-io/conan

Hi,

I'm working on a project with optional conan support. I want fellow devs to be able decide whether or not to use conan, but still have all the cmake logic the same.

I've hit a problem with GTest because the conan find_package_multi generator only creates a GTest::GTest target, but GTest's own config doesn't usually export this target; it exports GTest::gtest, GTest::gmock, etc...

This forces me to use some conditional logic in the cmake file to try linking with both GTest::GTest and GTest::gtest, depending on the package manager.

Is there a way to reference specific library targets like GTest::gtest from conan?

I know you can do it with other cmake generators, but I see no mention of it for the find_package_multi generator.

triaging question

All 8 comments

This will be the "components" feature. It is on its way, we already added recipe support in past release, and this release will release support for cmake_find_package generators: https://github.com/conan-io/conan/pull/7108

Once this is out, the first step would be to contribute the components model to the gtest recipe in conan-center-index, and then, the same targets will be available.

I am considering that https://github.com/conan-io/conan/pull/7108 will close this issue (at least on the Conan CLI side, pending the gtest recipe update)

For info: it is possible to address specific targets today, but they have undocumented names like CONAN_LIB::gtest and CONAN_LIB::gmock. If you need a solution today, you can use them, otherwise I would recommend for the components feature.

There's an issue that a component cannot be named the same as a package. So you can't create GTest::gtest without changing the name of the package to GTest.

Not necessary to change the name of the package. The package_info() has a cpp_info.names["cmake_find_package"] = "GTest" that can define the GTest target even if the package is called gtest in lowercase. This is already implemented in the gtest/1.10.0 package (without user/channel) from ConanCenter.

Yep, I kept that line and it still complains. It seems to check the package name directly.

ERROR: 
    ConanException: gtest/1.10.0@ak/testing package_info(): Component name cannot be the same as the package name: 'gtest'

Here is my new version of package_info(). everything else should be the same as the gtest recipe in the conan center index.

    def package_info(self):
        self.cpp_info.names["cmake_find_package"] = "GTest"
        self.cpp_info.names["cmake_find_package_multi"] = "GTest"
        if self.options.build_gmock:
            self.cpp_info.components['gmock'].libs = ["{}{}".format('gmock', self._postfix)]
        if not self.options.no_main:
            self.cpp_info.components['gtest_main'].libs = ["{}{}".format('gtest_main', self._postfix)]
        self.cpp_info.components['gtest'].libs = ["{}{}".format('gtest', self._postfix)]

        if self.settings.os == "Linux":
            for component in self.cpp_info.components.values():
                component.system_libs.append("pthread")

        if self.options.shared:
            for component in self.cpp_info.components.values():
                component.defines.append("GTEST_LINKED_AS_SHARED_LIBRARY=1")

        if self.settings.compiler == "Visual Studio":
            if Version(self.settings.compiler.version.value) >= "15":
                for component in self.cpp_info.components.values():
                    component.defines.append("GTEST_LANG_CXX11=1")
                    component.defines.append("GTEST_HAS_TR1_TUPLE=0")

I can open a separate issue if this is unexpected behavior.

Sorry, this is not closed by #7108, because that only applies to cmake_find_package. Reopening for 1.27.

@akosik-anyvision with #7259 merged, you will be able to use the components feature with the cmake_find_package_multi in the next 1.27 release.

In order to achieve the behavior you describe above, you will need to declare a "global" (or any other name) component with a different name that the package name. for example, something like this should work:

    def package_info(self):
        self.cpp_info.names["cmake_find_package"] = "GTest"
        self.cpp_info.names["cmake_find_package_multi"] = "GTest"
        ....
        self.cpp_info.components["global"].libs = ["{}{}".format('gtest', self._postfix)]  # gtest component
        self.cpp_info.components["global"].names["cmake_find_package_multi"] = "gtest"  # gtest component

The reason for this is that apart from components, we also provide a "global" target by default that depends on all the other component targets (gtest::gtest here or Gtest::Gtest).

With the approach above, you "override" the global target providing your own one.

components are available to both generators 馃帀

Was this page helpful?
0 / 5 - 0 ratings