Closed SpaceIm closed 3 years ago
Hi @SpaceIm
First, it is sad to discover this CMake lack of consistency (though not very surprising). Second, I agree, this is not a corner case, I thought it was going to be just a very few recipes, but it is clear I was wrong. I think Conan needs to provide a native and idiomatic way to define these targets too. Not sure they can be introduced without breaking, we might need to wait until Conan 2.0 (which will start very soon), but lets have a look and think about possible approaches.
Regarding the multiple module/config definitions, I am not so sure. I would say that this seems too much, and Conan should provide only one of them (I guess the modern module one). Lets try to think about the possible approaches in Conan 1.30.
@SpaceIm do you have an idea how the syntax to describe non-namespaced targets may look like? e.g. assigning an empty string, or None
, or something else? example would be helpful.
@SSE4 I don't know how it could be implemented with existing cpp_info properties without breaking current behaviour. For example, setting self.cpp_info.names["cmake_find_package"] = ""
would prevent defining global target name::name
?
Having multiple namespaces would also be useful.
e.g. thrift generates thrift::thrift
, thriftz::thriftz
, thriftnb::thriftnb
, thriftqt5::thriftqt5
.
In general, the cmake_find_package generators should assume that everything can be modified. (e.g. the name of a components is not always the same as the name of the imported target)
Difference between component name and underlying imported target can be emulated, but not multiple namespace (openexr also has multiple namespaces).
Agreeing with these points, confusingly CMake target names can be ANYTHING (and with my relatively brief CMake experience I've seen almost every type of target name in active use). Some packages like GTest even define things like GTest::GTest and then GTest::Main which as far as I know cannot be modeled with components right now.
unfortunately, I don't see how it could be implemented with the current CppInfo
model.
I suppose CppInfo
should be extended, for instance:
# generates "libzmq-static" (no namespace)
cpp_info.names["cmake_find_package_multi"] = "libzmq-static"
cpp_info.namespaces["cmake_find_package_multi"] = ""
# alternatively: cpp_info.namespaces["cmake_find_package_multi"] = None
# generates "thriftz::thriftz"
cpp_info.components["thriftz"].names["cmake_find_package_multi"] = "thriftz"
cpp_info.components["thriftz"].namespaces["cmake_find_package_multi"] = "thriftz"
# generates "thriftnb::thriftnb"
cpp_info.components["thriftnb"].names["cmake_find_package_multi"] = "thriftnb"
cpp_info.components["thriftnb"].namespaces["cmake_find_package_multi"] = "thriftnb"
# generates "OpenEXR::IlmThread"
cpp_info.components["IlmThread"].names["cmake_find_package_multi"] = "IlmThread"
cpp_info.components["IlmThread"].namespaces["cmake_find_package_multi"] = "OpenEXR"
# generates "Imath::ImathConfig"
cpp_info.components["ImathConfig"].names["cmake_find_package_multi"] = "ImathConfig"
cpp_info.components["ImathConfig"].namespaces["cmake_find_package_multi"] = "Imath"
I have created this PR https://github.com/conan-io/conan/pull/8130 to try a new approach using build modules for this kind of thing. I feel that CMake has so many different moving parts that it is a bit messy to keep adding things to the cpp_info model. WDYT?
@danimtb, looking at the PR, I don't really understand how a robust recipe could be written, ie providing non namespaced targets for cmake_find_package
and cmake_find_package_multi
generators only, since it doesn't make sense for others generators. Indeed, recipes in your tests seem to depend on generator used (a custom cmake file must be written at package or consume time, linking to... a target generated by conan, but how to know which one is availabe?), while recipe should be generic.
=====================
EDIT: or maybe it could work with something like this injected in build_modules
for each target:
if(NOT target AND namespace::target)
add_library(target INTERFACE IMPORTED)
target_link_libraries(target INTERFACE namespace::target)
endif()
=====================
It seems also to require lot of boilerplate code. package_info()
of several recipes are already quite complex (example: https://github.com/conan-io/conan-center-index/blob/40b28fa770140bc83a5de01a860e6dbc7c9ac0f3/recipes/dcmtk/all/conanfile.py#L174).
Thanks for working on this, this is a very important feature!
Just a reminder: ::
in cmake is nothing more than an utility for more readable Imported/Alias targets. Target names can be anything, using ::
is just a hint that the target is meant to be consumed as an imported target (or alias for compatibility with add_subdirectory
usage). Depending on the policy and version cmake may or may not also perform validation checks to see that it really is an imported target or alias. As far as conan is concerned it should be just a normal substring in a target name.
Now it's good cmake practice to use ::
to add some form of namespacing but this should not be enforced. Eg I have encountered libraries with no namespaces and libraries with the same namespaces spanning multiple projects.
@jgsogo Does #8130 really add non-namespaced targets? I don't see an example doing that, unless I didn't look well enough.
I'll write an example with a POC (it was closed with the PR)
Currently,
cmake_find_package
andcmake_find_package_multi
generators always create namespaced imported targets in generated module/config files. While not considered as best practice, it's not uncommon that official CMake config file of a library create non-namespaced imported targets (and quite uncommon for module files because official ones are usually provided by Kitware).This is a non-exhaustive list of CCI recipes whose official config file creates non-namespaced targets, to show you that it's not just a corner case:
It's worth noting that a library may have an official module and config file, and one might create namespaced targets but not the other. libpng and freetype are good examples.