-
Notifications
You must be signed in to change notification settings - Fork 949
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How to create imported targets in FindXXX.cmake #2125
Comments
Yes, I know, actually there was a previous attempt to be able to rename targets at user will. But because of this ALIAS limitation, it was a nightmare in the end, and lots of extra code to maintain, so finally we didn't add it. Your implementation sounds quite reasonable, clear, easy to read & understand... I think it is ok. Actually you can reduce it looping over the properties (INTERFACE_LINK_LIBRARIES, etc). In any case, I think it would be enough to add it to the docs, adding it to conanbuildinfo.cmake might have more cons (maintenance, future upgrades, etc) than pros. That, or I would just do the link conditionally: if (CONAN)
target_link_libraries(myapp CONAN_PKG::MyPkg)
else()
target_link_libraries(myapp MyLib)
endif() |
The reason for not linking conditionally is that the linking happens in a library that is not related to conan. |
Yes, that is fine, but even if that linking is in a library not related to conan, you still need to load |
The library that calls findXXX.cmake is in its own repository. Its up to the user of the lib to provide the external requirements by manually installing them or using some package manager. e.g.:
|
Ah, ok, now I get it. Yes, those are exactly the 2 typical ways to package a library without modifying the existing CMakeLists script: either patching or using a parent CMakeLists to wrap it. We have thought about it a bit, and adding convenience functions in |
Packaging is not the problem. We can use patching for packaging. But if we develop a library we want to clone the repo and use it without modifications. Then we need the find_package solution to use conan from outside. Here is my improved version: function(add_cloned_imported_target dst src)
add_library(${dst} INTERFACE IMPORTED)
foreach(name INTERFACE_LINK_LIBRARIES INTERFACE_INCLUDE_DIRECTORIES INTERFACE_COMPILE_DEFINITIONS INTERFACE_COMPILE_OPTIONS)
get_property(value TARGET ${src} PROPERTY ${name} )
set_property(TARGET ${dst} PROPERTY ${name} ${value})
endforeach()
endfunction()
if(NOT TARGET LibA::LibA)
add_cloned_imported_target(LibA::LibA CONAN_PKG::LibA)
endif()
set(LibA_FOUND TRUE) |
Thanks for updating with the improved version, indeed looks better. Still, I don't see it in the generated conanbuildinfo.cmake file, as long as it is not being used by it, and otherwise conanbuildinfo.cmake would easily become a library of cmake utilities that would be very difficult to maintain and break easily, being auto-generated and serving so many users. Unless I am missing something, which is totally possible :)
I have some missing pieces, like where are you putting this find_liba.cmake, how do you manage it relatively to the installed conanbuildinfo.cmake, or how do you switch between configurations, modifying the CMAKE_MODULE_PATH? |
You explained it quite well.
Here is a simple example of a consuming app: project(App1 CXX)
cmake_minimum_required (VERSION 3.9)
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
conan_basic_setup(TARGETS) #this will add the LibX conan packages to CMAKE_MODULE_PATH
set(BUILD_SHARED_LIBS ON)
if(...)
find_package("LibA" REQUIRED) #this will use FindLibA.cmake in LibA conan package
else()
add_subdirectory(../lib-a lib-a)
endif()
if(...)
find_package("LibB" REQUIRED) #this will use FindLibB.cmake in LibB conan package
else()
add_subdirectory(../lib-b lib-b) #ready to use find_package("LibA") inside
endif()
add_executable(App1 main.cpp)
target_link_libraries(App1 LibA::LibA)
target_link_libraries(App1 LibB::LibB)
The only thing to take care of, is that we dont use LibB from conan and build LibA from source. Then we would have two versions of LibA in the project. |
Another use case is when you have an external library and the standard FindXxx.cmake does not work with the conan package(s): bincrafters/community#26 |
Just to tap in on the discussion: If so, this is kind of a huge problem. Requirement number 1 for any package manager should be that consuming libraries are agnostic to where the packages originates from... |
Is it really a huge problem? As described above by @wpalfi you can rename the target with 8 lines of cmake code. Also, any idea how packages can be consumed by any build system, being completely agnostic to where the packages originates from, in all OSs and platforms? Packages are quite agnostic of their contents (besides the In any case, it is important to highlight that the CONAN_PKG:: scope is because that target is NOT a target of a specific library like "thread". It is a IMPORTED INTERFACE target for the whole package. Then you have different CONAN_LIB:: targets, for each library within the package, but without dependency relations between them. If you want such relations, per library, you might be interested in the bincrafters modular version of boost: https://bincrafters.github.io/ |
Just to be clear, and to avoid misunderstanding each other, in my case I'm specifically talking about CMake & the expected targets for that generator. But I'm sure this example applies to others as well. Also, my current knowledge of conan is limited to Getting started & a webinar. The problem arises when you mix pre-installed packages, eg. using conan, and packages built within the same repo/solution, eg. using So, naturally Conan sounded like an excellent option, and to be clear it really is. It has recipe for all but cpprestsdk, great! However, if you don't follow the naming conventions used for CMake-targets, then as far as cpprestsdk is concerned, you have not supplied a single dependency. I'm glancing at the "8-line fix" but not sure I fully grasp how he ends up with LibA::LibA (might be my lacking knowledge of conan), but TBH it sounds like a lot more than 8 lines of code (now imagine 4 targets, 10, 20... not really scalable). IMO, I really hope you make this fix sooner than later, because I have no doubt that Conan will be a (if not thee) go-to package manager for C/C++. Hoping that CMake enables ALIAS for IMPORTED targets is kind of a long shot. |
Actually, after trying conan for my particular case, Since this is the case, no, it is not a huge problem! (though it would be more consistent) |
@helmesjo It's not a problem at all. Creating imported targets with library specific namespaces is in general a project specific task. The "correct" CMake-way to do that is to provide a custom findXxx.cmake. It is really easy to do that with conan. (Having imported alias targets in cmake would make it even easier, but this is a cmake issue.) The only useful thing that conan could do here is maybe to provide a default findXxx.cmake in the |
So, I think the function by @wpalfi can be something to add to the
|
That would be convenient, though not really necessary. And of course it's just a workaround for the function missing in cmake. |
@lasote well, I was considering to add it to conanbuildinfo.cmake, but I think we need a criteria for this, or conanbuildinfo.cmake can grow without limits to contain a miriad of useful functions that users can call from their CMakeLists. But this is dangerous, because in the long term is difficult to maintain: every change you do on such generated code is potentially breaking. Also, it is something that it is typically under-tested, as it is not in a main conanbuildinfo.cmake execution path. But I understand the convenience of having them there too, it is a trade-off, as usual. |
FYI, the following is implemented in the CMake master and should be released in CMake 3.11: https://gitlab.kitware.com/cmake/cmake/merge_requests/1264. In short, If |
Thats a good tip, @himikof. We will try to do that, see if it doesn't break anything. Thanks! |
Good news! https://gitlab.kitware.com/cmake/cmake/merge_requests/1264 should also enable target_link_libraries for imported targets. This could be very useful for non-conan requirements. Conan adds dependencies to required conan packages. But if a target depends on some system installed library, we can add it in findXxx.cmake: add_library(MyLib::MyLib INTERFACE IMPORTED)
#conan dependencies
target_link_libraries(MyLib::MyLib CONAN_PKG::MyLib)
#system dependencies
find_package(SomeSystemLib REQUIRED)
target_link_libraries(MyLib::MyLib SomeSystemLib::SomeSystemLib) |
So, if I understood correctly, there is nothing to do on the conan side, and this issue could be considered solved? (given you use latest cmake, of course). Thanks! |
Just tested with CMake 3.11.0-rc1 and it works:-) Needed to add INTERFACE to target_link_libraries: add_library(MyLib::MyLib INTERFACE IMPORTED)
#conan dependencies
target_link_libraries(MyLib::MyLib INTERFACE CONAN_PKG::MyLib)
#system dependencies
find_package(SomeSystemLib REQUIRED)
target_link_libraries(MyLib::MyLib INTERFACE SomeSystemLib::SomeSystemLib) |
Nice!! Thanks for trying and reporting |
@wpalfi This is a very interesting use of But maybe Conan should still just add |
Not sure if global is safe here. There are users running a super-project that will do an |
Yes, if this is a supported use case (just |
Absolutely right. But its not conan's fault. CMake is just not designed to support that. Most findXxx modules are using cache variables, so using multiple packages with conflicting names simply does not work in CMake. Btw: It is the same problem that you run into when you switch conan settings/options without clearing the CMake cache. Even if you only switch between Debug/Release. It would be good to have a warning about that somewhere in the conan docs. |
In http://docs.conan.io/en/latest/integrations/cmake/find_packages.html?highlight=find_package
you use old-style variable based findXXX:
The better way for find_package is to use imported targets. I want to create an imported target with the same name as the original cmake target name of the library to be able to use
Then we can easily switch between imported conan package and building from source with add_subdirectory without any changes in the consuming CMakeLists.txt. Best solution would something like
add_library(MyApp ALIAS CONAN_PKG::MyApp)
Unfortunately ALIAS of IMPORTED is not supported by CMake. My current workaround is
Any other solutions? Maybe some helper function in conanbuildinfo.cmake to create imported targets?
The text was updated successfully, but these errors were encountered: