Open memsharded opened 1 year ago
I think with CMake there isn't currently a solution that covers all cases, but there is potential for one.
When not cross compiling, CMakeToolchain
will set CMAKE_PREFIX_PATH
to the directory where all the generated CMakeDeps
files are. In essence, this results in a search order for find_package
:
When we are cross compiling (CMAKE_CROSSCOMPILING
is True) and there is a CMAKE_SYSROOT
defined, the behaviour depends on the value of the CMAKE_FIND_ROOT_PATH_*
variables - which currently CMakeToolchain
sets to BOTH
.
That results in the following order:
SYSROOT
This search order can cause problems if the sysroot contains things that we intend to consume from Conan instead. For example, it is typical that a target system will contain things like zlib
or OpenSSL
- in which case, CMake might find the ones from the sysroot even if they are listed as Conan dependencies.
There are also going to be libraries that one won't be providing from Conan, but will rely on the SYSROOT
to provide. This is anything that we typically consider "system" libraries (e.g. the GCC runtime libraries, X11, OpenGL, etc).
Obviously if one knows which libraries are to be provided by Conan and which libraries are part of the "system" - then one can alter the find_package()
calls accordingly, but as we know this is a level of burden that build system maintainers typically don't like doing.
The "ideal" search order would be:
SYSROOT
find_program
)If CMake had a fourth option in addition to ONLY
, NEVER
and BOTH
, one that is "both, but look in CMAKE_PREFIX_PATH
first, then the sysroot, then the rest of the system) - that would probably achieve the behaviour when we are not cross building.
If CMake had a fourth option in addition to ONLY, NEVER and BOTH, one that is "both, but look in CMAKE_PREFIX_PATH first, then the sysroot, then the rest of the system
You're in luck, but it's very new - part of the CMake 3.24 dependency provider machinery: see CMAKE_FIND_PACKAGE_REDIRECTS_DIR, introduced for exactly this purpose.
Search first in the
SYSROOT
Then search in the directory set by Conan
Then fall back in the host system's directories
Not quite - it actually never searches "in the SYSROOT" per se. Rather, it takes every path it would have searched, in the order it would have searched them, prefixing each with the sysroot (and, if not found there, with other entries in CMAKE_FIND_ROOT_PATH). CMAKE_PREFIX_PATH isn't first, but it is pretty early (only PackageName_ROOT cache keys or environment variables are earlier).
So one workaround (that I've used) is to bind-mount the CONAN_USER_HOME at that same path within the sysroot, so that it, and thus conan's build folders, are found during this prefixed search.
that might be confusing, and it needs to be distinguish, for cross-compiling, especially. there are several things involved:
sysroot
is a directory to look for headers and libraries. it's an input for the cross-compilation process. it might be an SDK path (e.g. something like /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk
is typical on Apple platforms)prefix
is an installation directory, from which programs are actually run on system, something like /usr
, /usr/local
or /opt
are common values on *nix systems (depends if it's software provided by package manager, manually built, or some third party, and so on). it's an output for the cross-compilation process.destdir
is an installation directory, where built artifacts are actually copied. the final destination is a combo of prefix
and destdir
. it's also an output for the cross-compilation process.these are traditional values, now CMake variables are mapped to this:
destdir
, it's finesysroot
, it's fine, so far simpleprefix
, also okayfind_library
, find_program
and so on. that's where conan should append its directories, as it's a list for libraries installed by user. as conan installs every package to its own directory, we expect that list to be quite long.CMAKE_INSTALL_PREFIX
.in general, I believe nothing is needed from conan's side, expect population the CMAKE_PREFIX_PATH
with conan's directories. otherwise search order can be controlled via CMake variables listed above, as well as more fine grained CMake variables (like individual find modes for programs/libraries/headers, and variables like CMAKE_INCLUDE_PATH
, CMAKE_LIBRARY_PATH
, CMAKE_PROGRAM_PATH
).
specially, in case of cross-compilation, when on different stages it needs to use host/build/target tools/libraries.
We are using Conan to build libraries and applications for regular desktop machines running Linux, MacOS or Windows, but also for embedded devices running a distribution built with Yocto. In our Conan recipes we have conditions that require OTS packages only, when not cross-compiling. Otherwise, they are expected to be shipped with the Yocto SDK, which by defaults sets this in its toolchain file:
set( CMAKE_FIND_ROOT_PATH $ENV{OECORE_TARGET_SYSROOT} )
set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER )
set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY )
set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY )
set( CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY )
We add Yocto's toolchain file OEToolchainConfig.cmake
via tools.cmake.cmaketoolchain:user_toolchain
.
The CMAKE_FIND_ROOT_PATH_MODE_*
options however prevent CMake finding the -config.cmake
files generated by CMakeDeps
in the self.generators_path
; i.e. CMAKE_PREFIX_PATH
will not work as expected. E.g. when building test_package
, where we require self.tested_reference_str
, we get the following error:
CMake Error at CMakeLists.txt:34 (find_package):
Could not find a package configuration file provided by
"my-lib-a" with any of the following names:
my-lib-aConfig.cmake
my-lib-a-config.cmake
Add the installation prefix of "my-lib-a" to
CMAKE_PREFIX_PATH or set "my-lib-a_DIR" to a directory
containing one of the above files. If "my-lib-a" provides
a separate development package or SDK, be sure it has been installed.
During our investigation to solve this issue, we came to following conclusions:
CMAKE_FIND_PACKAGE_REDIRECTS_DIR
is not available.CMAKE_FIND_ROOT_PATH_MODE_*
is changed in the Conan recipe to BOTH
. This however could be dangerous, since system packages could be picked up. We only want CMake to look in the paths that Conan creates and SYSROOT
paths.For Conan we considered two options:
*_DIR
for every dependency. We did not pursue this approach any further. Spontaneously, we could not think of a simple solution to implement it.CMakeToolchain
to add self.generators_path
to CMAKE_FIND_ROOT_PATH
, like discussed here.
It is not fully clear, maybe not enough tested:
What would be the best way to integrate? The
conan_toolchain.cmake
can include the vendor toolchain.cmake, or an intermediate one from the user, but does this guarantee behavior if the vendor toolchain changes priorities of CMake for finding package only in itself?cc / @maikelvdh