Conan: [generator][CMake]: CONAN_LIB::* targets should be defined as GLOBAL

Created on 5 Sep 2018  路  26Comments  路  Source: conan-io/conan

It is desirable to use ALIAS targets instead of CONAN_LIB::* targets to minimize dependencies on Conan within CMake files.

In order to define an ALIAS target, the base target must be declared as GLOBAL, which is not currently done for the CONAN_LIB::* targets by the conan cmake generator.

medium high feature

Most helpful comment

Merged #6438, will be released in next Conan 1.22

All 26 comments

Hi @sigiesec!

Two questions to really understand the use case:

  • why using CONAN_LIB:: targets and not the CONAN_PKG::?
  • Can you create an alias target of an IMPORTED one?

Hi & thanks for the quick response!

  • Maybe this mixes with some other issues I have. We frequently deal with packages containing multiple libraries, and we only want to depend on specific libraries. See also my issue conan-io/docs#806
  • Yes, that's possible for IMPORTED targets, but they need to be GLOBAL. https://cmake.org/cmake/help/v3.12/command/add_library.html#alias-libraries says The <target> may not be a non-GLOBAL Imported Target or an ALIAS.

Thanks for the info! I'm creating a test and will report.

Hi, I'm creating the CONAN_LIB:: targets with and without the GLOBAL: add_library(${_LIB_NAME} UNKNOWN IMPORTED GLOBAL)
but when I try to create an alias like this:

add_library(MY_ALIAS ALIAS CONAN_LIB::Hello0_helloHello0)
I'm receiving the error:

CMake Error at CMakeLists.txt:10 (add_library):
  add_library cannot create ALIAS target "MY_ALIAS" because target "CONAN_LIB::Hello0_helloHello0" is
  not a library.

Is it expected? Am I doing something wrong?

Hm, this is probably because of the target being specified as "UNKNOWN": https://gitlab.kitware.com/cmake/cmake/issues/18327. I noticed that yesterday when I experimented a bit, but wasn't aware that the CONAN_LIB targets are specified as UNKNOWN. I thought that https://docs.conan.io/en/latest/integrations/cmake/cmake_generator.html claims this, but actually this only refers to the CONAN_PKG targets:
Using TARGETS as argument, conan_basic_setup() will internally call the macro conan_define_targets() which defines cmake INTERFACE IMPORTED targets, one per package.

When using INTERFACE instead of UNKNOWN, however, it works:

add_library(Foo INTERFACE IMPORTED GLOBAL)
add_library(Bar ALIAS Foo)

But with INTERFACE IMPORTED it doesn't allow to specify the IMPORTED_LOCATION property. How do you specify where is the prebuilt library? In general, it appears to need important changes in the definition of the library targets and I can be it can be breaking for current users.

Yes that's right.

One option would be to define two targets then, such as:

# in conanbuildinfo.cmake
add_library(FooLib INTERFACE IMPORTED GLOBAL)
set_property(TARGET FooLib IMPORTED_LOCATION /somewhere/FooLib.a)

add_library(CONAN_LIB::Foo INTERFACE IMPORTED GLOBAL)
set_property(TARGET CONAN_LIB::FooPROPERTY INTERFACE_LINK_LIBRARIES FooLib)

# in user code
add_library(Bar ALIAS CONAN_LIB::Foo)

Another option would be not to use UNKNOWN, but SHARED or STATIC. I think conan has the necessary information to determine the difference, or doesn't it?

But maybe the CMake issue can be resolved, as I don't see a reason why an UNKNOWN target couldn't have an alias.

Another option would be not to use UNKNOWN, but SHARED or STATIC. I think conan has the necessary information to determine the difference, or doesn't it?

Not with data, but maybe checking extensions or something similar, but it tends to be weak.

About your example, I don't think if you made a mistake, but set_property(TARGET FooLib IMPORTED_LOCATION /somewhere/FooLib.a) is not valid either for INTERFACE IMPORTED GLOBAL, maybe you meant to create a brand new target with INTERFACE IMPORTED GLOBAL while we kept the rest exactly the same?

I wouldn't be very happy with duplicating the targets, sounds indeed like CMake craziness and unmaintainable conan code. :S

Oops, sorry, that was a mistake indeed, it should have been:

# in conanbuildinfo.cmake
add_library(FooLib UNKNOWN IMPORTED)
set_property(TARGET FooLib IMPORTED_LOCATION /somewhere/FooLib.a)

add_library(CONAN_LIB::Foo INTERFACE IMPORTED GLOBAL)
set_property(TARGET CONAN_LIB::FooPROPERTY INTERFACE_LINK_LIBRARIES FooLib)

# in user code
add_library(Bar ALIAS CONAN_LIB::Foo)

Beware, some functionality, like ALIAS to some targets, only work in very latest CMake, like 3.12. Also INTERFACE_LINK_LIBRARIES for INTERFACE targets, I think. We need to keep backwards compatibility down to 3.3, for the targets approach, and cmake 2.8.12 for the global approach.

The ALIAS would only be used in the user CMake code (so we can only use it if we use a recent CMake version), so this change wouldn't put any additional restrictions on CMake versions on the conan side.

GLOBAL already is supported by CMake 3.0.2 at least.

I have played with this (manually adding GLOBAL to the add_library(CONAN_PKG::<package> INTERFACE GLOBAL) in the generated conanbuildinfo.cmake and it did work for me.

I am not familiar with cmake to know what other implications this may have.

@memsharded @lasote: We are very interested in this (hence @dribeas 's comment) because our company's primary build system does not use Conan, so to ensure we can re-use our existing CMake under Conan, we'd like to ensure we can avoid having to mention CONAN_PKG:: or CONAN_LIB:: anywhere in our CML.

I have just hit this same issue, trying to define an alias, and being blocked by:

CMake Error at CMakeLists.txt:13 (add_library):
  add_library cannot create ALIAS target "gflags::gflags" because target
  "CONAN_PKG::gflags" is imported but not globally visible.

Same issue here, I've needed that kind of feature at least two or three times lately. Would it be possible to check the CMake version at the time when conanbuildinfo.cmake is generated and to conditionally use the 3.12+ features in it dependending on whether they're supported? If build_requires is run before the generators it can even allow to use cmake_installer for people who want to use the feature.

I guess that conditionally using CMake features is another can of worms though :/

The package that wants to define an ALIAS to the conan-generated targets requires a recent-ish CMake.

However, as mentioned above, the code generated by conan defining GLOBAL targets does not depend on CMake 3.12, but is supported from CMake 3.0.2

So there is no need to make a check within conan for this particular thing. It might be useful for other features though.

So, summarizing, to implement the feature. The goal is to be able to create ALIAS of the targets generated with CMake taking into account we should keep the compatibility as much as possible with older CMakes, maybe introducing only the GLOBAL if the cmake is modern-enough or with another mechanism.

As @sigiesec said, I also think that setting the GLOBAL option for the CONAN_LIB:: target would not be a problem as it is supported from CMake 3.0.2 and the consumer will be the one that needs a modern CMake version.
After testing this locally, using many different CMake versions I confirmed that:

  • Using ALIAS for IMPORTED targets works for CMake > 3.10.3 (as stated in the docs)

  • Using ALIAS for UNKNOWN IMPORTED targets works only for CMake > 3.14 (will print the is not a library error instead of the not globally visible. one) as was commented earlier because of: https://gitlab.kitware.com/cmake/cmake/issues/18327

Hi @sigiesec, @Morwenn

After giving a thought to this problem I was wondering if, for example, conan provided a target with a name like: self.cpp_info.name + library_name for those LIB:: targets, would it solve your issue in any way so you don't need to make the ALIAS for the LIB:: target?

Hi @sigiesec, @Morwenn

After giving a thought to this problem I was wondering if, for example, conan provided a target with a name like: self.cpp_info.name + library_name for those LIB:: targets, would it solve your issue in any way so you don't need to make the ALIAS for the LIB:: target?

No, I don't think so. Any name/naming scheme defined by conan wouldn't serve the purpose of being independent of conan in the CMake files.

It would be nice if the name were consistent, but looking at what I'm using them for right now, it might be difficult. Here is what I have in my top-level CMakeLists.txt right now to package the k4a SDK:

add_library(Eigen3Workaround INTERFACE)
target_link_libraries(Eigen3Workaround INTERFACE CONAN_PKG::eigen)
add_library(Eigen3::Eigen ALIAS Eigen3Workaround)

add_library(gtest INTERFACE)
target_link_libraries(gtest INTERFACE CONAN_PKG::gtest)
add_library(gmock INTERFACE)
target_link_libraries(gmock INTERFACE CONAN_PKG::gtest)

add_library(imgui INTERFACE)
target_link_libraries(imgui INTERFACE CONAN_PKG::imgui)

add_library(turbojpeg INTERFACE)
target_link_libraries(turbojpeg INTERFACE CONAN_PKG::libjpeg-turbo)
add_library(turbojpeg-static INTERFACE)
target_link_libraries(turbojpeg INTERFACE CONAN_PKG::libjpeg-turbo)

add_library(uvc_static INTERFACE)
target_link_libraries(uvc_static INTERFACE CONAN_PKG::libuvc)

As you can see some targets have names such as uvc_static or turbojpeg-static which might or might not live along their non-static counterparts, some others work differently altogether, so we really need the ability to mock arbitrary names and can't just rely on Conan-provided ones.

My use case would be to replace the INTERFACE libraries above by ALIAS and I thought that GLOBAL Conan targets would allow me to use simple ALIAS to do that. Now maybe I'm wrong and it has some additional issues I don't quite understand, but the ability to provide aliases as arbitrary name is definitely a need.

Merged #6438, will be released in next Conan 1.22

To be reverted in 1.22.1: https://github.com/conan-io/conan/pull/6488, it started to break users with add_subdirectory strategies. If needed, we have to think a different approach.

While trying to replace my INTERFACE targets above with ALIAS ones I was bitten by the fact that the library I'm packaging defines itself ALIAS to the expected targets and apparently you can't have an ALIAS to an ALIAS in CMake: basically the switch to GLOBAL was welcome yet unfortunately still insufficient because of CMake idiosyncrasies.

Since it wasn't enough and it's causing new issues, I guess that it's the best move to remove it swiftly for now and to mention in the release notes of 1.22 that it shouldn't be relied upon. The fix proposed in #6480 looks good to have anyway.

Have there been any thoughts on how to achieve the goals of this issue without the problems that #6438 caused?

I'm obviously late to the party, but this functionality would still be welcomed!

Could this be another option to conan_basic_setup? Use TARGETS_GLOBAL instead of TARGETS which would in turn pass a variable to conan_define_targets that conditionally includes the GLOBAL property?

Would it be better to reopen this issue or to start fresh?

The release notes for CMake 3.18 have the following item:

The add_library() and add_executable() commands learned to create Alias Targets referencing non-GLOBAL Imported Targets.

So maybe a partial workaround would be to use self.requires("cmake/3.18") in recipes where this matter?

Was this page helpful?
0 / 5 - 0 ratings