conan icon indicating copy to clipboard operation
conan copied to clipboard

[question] find_package and non-standard structure of package content

Open maitrey opened this issue 2 years ago • 3 comments

Dear Conan Folks,

We have a legacy system where every script cannot be adapated to not disturb a running system. The contents of the package are : tools, includes . While using find_package from CMake the package is found but since it has not the standard structure , certain variables are not set example: <PKG-NAME>_INCLUDE_DIRS as in https://docs.conan.io/en/latest/reference/generators/cmake_find_package.html#cmake-cmake-find-package-generator-reference . What is the way to get to the package root in that case?Is there any variable set that will give the absolute path to the package? Thanks for your reply.

maitrey avatar Sep 21 '22 15:09 maitrey

Hi @maitrey

It is necessary to define in the package recipe the structure:

def package_info(self):
     self.cpp_info.includedirs = ["includes"]
     self.cpp_info.bindirs = ["tools"]

Otherwise the default include and bin folder is used

Also, recall that the cmake_find_package generator is deprecated and removed in 2.0. You should be upgrading to CMakeDeps (and CMakeToolchain)

memsharded avatar Sep 21 '22 16:09 memsharded

Thanks @memsharded . I inspected the cmakefiles and started to use: <PKG_NAME>_PACKAGE_FOLDER_RELEASE. Is this allowed? Also, what if I have more folders and not only one tool? How can one define that in package_info method?

maitrey avatar Sep 22 '22 05:09 maitrey

The <PKG_NAME>_PACKAGE_FOLDER_RELEASE variables are implementation details of the CMakeDeps generator, not intended to be used directly that way, but instead via the created targets via target_link_libraries(.... mypkg::mypkg) or something similar. Why the targets are not good for your case? It is not that the generated xxxx-data.cmake files will change, but they are not documented, if not documented, then they are subject to change. You can always write your own file in generate() method collecting the self.dependencies["dep"].package_folder, if you want 100% stability.

For multiple folders:

def package_info(self):
     self.cpp_info.includedirs = ["includes"]
     self.cpp_info.bindirs = ["tool_folder1", "tool_folder2"]

memsharded avatar Sep 22 '22 07:09 memsharded

Hi @memsharded , This works and then I can also access the paths from : self.deps_cpp_info["Package].bin_paths but how to access it from CMakeLists.txt. Can I use this Package_INCLUDE_DIRS or is this not allowed?Is there any other way to use it from CMakeLists.txt?

maitrey avatar Oct 12 '22 09:10 maitrey

Please note that self.deps_cpp_info["Package].bin_paths is a deprecated way to access information dependencies. self.dependencies is the way to go now: https://docs.conan.io/en/latest/reference/conanfile/dependencies.html

In theory, the variables created by CMakeDeps are an internal implementation detail, and the created targets are the way to go. That variable might be defined (actually one different for each config, with _RELEASE, _DEBUG, etc). Note that I am talking about CMakeDeps and not cmake_find_package or other legacy generators. Why aren't the created targets good for your use case? They are the CMake standard and recommended way to use libraries and dependencies.

memsharded avatar Oct 12 '22 11:10 memsharded

While waiting for your reply , I also tried like this: tc.variables["Package"] = self.deps_cpp_info["Package"].bin_paths[0] . Targets are a good way just that I would have to change all the packages as many have include dirs. For creating targets in the creator package in cmake , I need to use add_library and access them with namespace from consumer package. For include headers , I am not sure exactly how to use them. May be you can help with an example.

maitrey avatar Oct 12 '22 12:10 maitrey

Sorry, I am not sure what you mean. The include_dirs are already defined in the targets, no need to handle them separately.

The conan new hello/0.1 -m=cmake_lib is a fully working functional example of creating a package and consuming it with find_package() and target_link_libraries(.... targetname::targetname), without needing to use include_dirs in CMakeLists.txt or anything like that.

memsharded avatar Oct 12 '22 12:10 memsharded

hello example has not the use case that we have. We have packages that are include headers only package.

maitrey avatar Oct 12 '22 12:10 maitrey

Can I use the dependencies like this: Package = self.dependencies["Package"] tc.variables["Package_BINDIR0"] = Package.cpp_info.bindirs[0].replace('\', '/')

maitrey avatar Oct 12 '22 12:10 maitrey

hello example has not the use case that we have. We have packages that are include headers only package.

That is perfectly fine. A CMake target can also work with only headers, and it is still recommended practice and not using a Something_INCLUDE_DIR variable. Modern CMake is all about targets.

Package = self.dependencies["Package"] tc.variables["Package_BINDIR0"] = Package.cpp_info.bindirs[0].replace('', '/')

Yes, this should be possible. But for bindirs specifically for dependencies it might not be necessary at all. The bindirs of tool_requires will be automatically added to the PATH env-var when the VirtualBuildEnv generator is declared (which will be automatic in 2.0, or in 1.X if the conf tools.env.virtualenv:auto_use=True is defined).

memsharded avatar Oct 12 '22 16:10 memsharded

Hi @memsharded , I was on holidays and therefore didnot work on this topic. So I have a package that is an interface package. This contains mainly header files and no source file. In the CMake implementation I have used:

add_library(A INTERFACE) target_include_directories(A INTERFACE ${CMAKE_SOURCE_DIR}/include/extras/additional_includes) target_include_directories(A INTERFACE ${CMAKE_SOURCE_DIR}/include/extras) I have a package B that is consuming A, B is generating object files. Therefore I donot use, target_link_libraries. If I use, from toplevel CMakeLists of B then it works: include_directories(${A_INCLUDE_DIRS}/extras/additional_includes) include_directories(${A_INCLUDE_DIRS}/extras) If I use, target_include_directories(B PUBLIC A::A) then it simply doesnot work, meaning it cannot find header files in additional_includes. Could you please help me ?

maitrey avatar Nov 15 '22 10:11 maitrey

The last comment on this issue is fixed as of now. Was a cmake and not a conan issue. Hence closing this issue.

maitrey avatar Jan 30 '23 09:01 maitrey