[question] package with multiple cmake targets
What is your question?
Hi, I'm getting out of ideas.
I have existing CMake projects that define multiple (sub)targets which all have their own cmake target and config files. I have managed to install all these cmake config files into the target package folder.
On the consumer side all those files are properly installed under the package's cmake folder.
However, they are not getting installed into the generators folder of the target build folder.
I am not using the conan generated cmake config files, because they are so buggy that they are not usable (linker errors, etc.). Instead my own cmake config files are capable to work with the conan structure.
I need conan to install all MY(!) cmake config files into the generators folder. What do I have to do to accomplish that?
thx Michi
Have you read the CONTRIBUTING guide?
- [ ] I've read the CONTRIBUTING guide
Hi @scalpel4k
Thanks for your question.
However, they are not getting installed into the generators folder of the target build folder.
They don't need to be copied into the generators folder of the target. They can and should be used directly in the package folder. There is a working example in the docs in https://docs.conan.io/2/examples/tools/cmake/cmake_toolchain/use_package_config_cmake.html that shows how it works.
Please try that and let us know.
I am not using the conan generated cmake config files, because they are so buggy that they are not usable (linker errors, etc.). Instead my own cmake config files are capable to work with the conan structure.
The conan generated files are working at scale for many thousands of organizations relying on them.
Note there are also cases where the CMake generated files are not good, for example, when they don't model correctly transitive dependencies, and this is solved using the Conan generated ones. If there are issues with them, the best would be to report them, with reproducible code (as separate tickets from this one).
Besides the current existing CMakeDeps generated files, the new CMakeConfigDeps generator produce better files, with more native cmake targets and many awaited improvements and fixes.
Hi @memsharded,
thanks for your quick reply. I've tried to follow the example, but to no avail. Maybe I have to explain a bit more how our projects have been working so far - without conan. We wanna add conan on top of our current projects for the sake of better dependency tracking and the binary repo.
Many of our projects define (optional) sub targets, each with their very own context (includes, lib, cmake etc). Each of these subtargets can be found by find_package(<(sub)target-name>), but each coming from the same project.
This is all managed by some custom 'cmake-macros' that are essential for setting target options, collecting unittests, installing files, etc. Consumer projects use find_package(cmake-macros) and any of find_package(<(sub)target-name>) and they magically just work. So there's no way we can get rid of cmake-macros.
Now I guess we have a hen-egg problem. I would need a 'cmake-macros' conan-package as tool_dependency, for which it seems I have to have this:
deps = CMakeDeps(self)
deps.build_context_activated = ["cmake-macros"]
deps.build_context_build_modules = ["cmake-macros"]
deps.generate()
But when I do, the generators folder gets populated with cmake files which don't work for our projects with separate targets (even this line doesn't help: self.cpp_info.set_property("cmake_find_mode", "none"))
Do you have any other idea? thx Michi
I am not fully sure if I understand the whole context, but maybe this helps: have you checked the example in https://docs.conan.io/2/examples/graph/tool_requires/use_cmake_modules.html?
I think this is what you are trying to achieve, the key is adding a self.cpp_info.set_property("cmake_build_modules", ["myfunction.cmake"]) to the package containing the macros file, so it is defined for the consumers as well. The generated files for a potential mycmakemacros/1.0 package are just to locate the file with the macros inside the package, they don't necessarily add any other targets.
It is also possible to use macros from dependencies via include() instead of find_package() as the example https://docs.conan.io/2/examples/graph/requires/consume_cmake_macro.html does. But it seems that the cmake_build_modules approach is more what you are looking for.
There might be other approaches as well, you can have an explicit copy() call in your consumers generate() method, to copy from self.dependencies["mydep"].package_folder the files that you want, and put them whenever you are. As commented above, this shouldn't be necessary, because for most cases it is possible to use the files from their original location (and most of the xxx-config.cmake files indeed must be used from their original location, because they rely on their relative location to the artifacts), but maybe for "free" .cmake scripts, it is possible to just copy them at generate() time.
Hi @scalpel4k
Did the last comment help? Any further questions? Thanks for the feedback.
@memsharded sorry for not responding, but I've turned back to my rust projects for now, it's so much more pleasant ....
But last time I was trying to find a solution I had this situation.
While the package now has my cmake config files installed in the conan cache, I still can't access them, i.e. cmake doesn't find them.
The cmake files are in the here: <mylib>/lib/cmake/xxx.cmake
When building with conan I tried this 'trick': list(APPEND CMAKE_PREFIX_PATH "${CMAKE_LIBRARY_PATH}")
And this is the output, i.e. CMAKE_PREFIX_PATH/CMAKE_MODULE_PATH indeed has all library paths attached
-- Using Conan toolchain: /workspace/build/Debug/generators/conan_toolchain.cmake
-- Conan toolchain: Defining architecture flag: -m64
-- Conan toolchain: Defining libcxx as C++ flags: -stdlib=libstdc++
-- Conan toolchain: C++ Standard 23 with extensions OFF
-- Conan toolchain: Setting BUILD_SHARED_LIBS = OFF
-- The CXX compiler identification is Clang 21.1.7
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/clang++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Conan: Target declared 'cmake-macros::cmake-macros'
-- Conan: Including build module from '/home/devel/.conan2/p/cmake2c7f7491a52ad/p/cmake-macrosConfig.cmake'
-- == >> cmake-macros << ==================================================
switching to conan build mode
-- == >> project info << ==================================================
-- Project name: libstatus
-- Working dir: /workspace
-- Root dir: /workspace
-- CMake Prefix/Module Path: /workspace/build/Debug/modules/
/workspace/build/Debug/generators
/home/devel/.conan2/p/catche6d2906a4e758/p/lib/cmake/Catch2
/home/devel/.conan2/p/time-5c1473ef6d742/p/cmake/time-utils
/home/devel/.conan2/p/proto312b8cf49f4f6/p/lib/cmake/protobuf
/home/devel/.conan2/p/opens3cd21db296f0d/p/lib/cmake
/home/devel/.conan2/p/catche6d2906a4e758/p/lib
/home/devel/.conan2/p/time-5c1473ef6d742/p/lib
/home/devel/.conan2/p/proto07bf0eb951192/p/lib
/home/devel/.conan2/p/grpcd8b268452a5f6/p/lib
/home/devel/.conan2/p/proto312b8cf49f4f6/p/lib
....
When looking at the output one sees that the 4th line in the CMAKE_PREFIX_PATH does not even exist, it is what was generated by conan. However, in the 8th line time-util's library path is showing up. In that path there is in fact a cmake/time-utils**.cmake path with the files I need. So, in theory, everything should be fine and my find_package(time-utils CONFIG) should find my config files, but it doesn't ....
Back in the time-utils package my conanfile.py has these lines:
#
# CMake generator
#
def generate(self):
print("Generate")
tc = CMakeToolchain(self)
if(self.options.get_safe("with_test") == True):
tc.variables["DISABLE_TEST_TARGET"] = "OFF"
else:
tc.variables["DISABLE_TEST_TARGET"] = "ON"
....
tc.generate()
cmake = CMakeDeps(self)
# build_context_activated is required so that cmake can find the module with find_package
cmake.build_context_activated = ["cmake-macros"]
# build_context_build_modules is required so that the generated config file includes the sub-cmake-files
cmake.build_context_build_modules = ["cmake-macros"]
cmake.generate()
#
# Execute the build process
#
def build(self):
cmake = CMake(self)
cmake.configure()
cmake.build()
#
# Pack the library
#
def package(self):
cmake = CMake(self)
cmake.install()
#
# Set package information
#
def package_info(self):
self.cpp_info.includedirs = ["include"]
self.cpp_info.libdirs = ["lib"]
# this exposes the cmake folder to dependent projects
self.cpp_info.builddirs.append(os.path.join("cmake", self.name))
Thanks for the feedback.
There might be some detail there that we are missing.
It would be very important to be able to reproduce on our side.
For that purpose, I have opened a PR in https://github.com/conan-io/examples2/pull/212, to add to the examples2 repo the code that is in the https://docs.conan.io/2/examples/graph/requires/consume_cmake_macro.html page.
The steps to build it are in the ci_test_example.py file, basically:
-
conan create myfunctions -
conan build consumer
The best would be to modify that code so it represents your use case more accurately and then we can reproduce it and check what would be the issue and possible solutions. Many thanks!
@memsharded I've seen a slight difference in the example, I don't know if it's important.
In the docs example the macro is "included" and not retrieved via find_package. In our case we install our files via cmake install, but that should not make any difference. Our cmake files are being installed under /usr/local/lib/cmake/project-name, and I could verify that this is also where we find them in the conan cache.
I've tried using include(time-utils) but that is also not working.
Unfortunately I don't know which path in the example2 repo you are referring to so I can only use the example from the docs. Other than that I think my situation is exactly as described in the docu.
You can get it and fully reproduce with:
git clone https://github.com/memsharded/examples2
cd examples2
git checkout feature/graph_cmake_modules
cd examples\graph\tool_requires\cmake_modules
conan create myfunctions
conan build consumer
Then you can from your fork, modify whatever you consider, and give the diff. Or you can even open a Pull Request to my own branch, or just provide me with your own branch in your fork and I will work from there, as you prefer. Once there is a fully reproducible example somewhere, it is way easier to investigate issues and give potential advice or solutions.
Hi @scalpel4k
Did you try the above steps? Please let us know, thanks for the feedback.