Skip to content
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

[feature] CMake integration: proof of concept of sysroot + CMakeDeps priority #12478

Open
memsharded opened this issue Nov 7, 2022 · 5 comments
Milestone

Comments

@memsharded
Copy link
Member

It is not fully clear, maybe not enough tested:

  • A vendor tool, like Android or similar, that could come in a Conan package, and that provides its toolchain.cmake file with the details how to use it.
  • That toolchain might contain some libraries
  • There are also Conan packages, that via CMakeDeps can be found
  • But also some other packages should be found in the sysroot of the vendor toolchain

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

@memsharded memsharded added this to the 1.55 milestone Nov 7, 2022
@jcar87
Copy link
Contributor

jcar87 commented Nov 7, 2022

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:

  • Search first in the directory of the generated files ("conan" takes priority)
  • Fall back to searching in the system directories (e.g. for system libraries or some utilities provided by the build machine)

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:

  • Search first in the SYSROOT
  • Then search in the directory set by Conan
  • Then fall back in the host system's directories

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:

  • If it's provided by Conan, pick the one up from Conan.
  • Then look in the SYSROOT
  • As a last resort, fall back to searching in the build machine - This would typically be for host system executables that the consumer project is not expecting from Conan (to be found with 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.

@puetzk
Copy link

puetzk commented Nov 8, 2022

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.

@puetzk
Copy link

puetzk commented Nov 8, 2022

  • 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.

@memsharded memsharded modified the milestones: 1.55, 1.56 Nov 28, 2022
@czoido czoido modified the milestones: 1.56, 1.57 Dec 20, 2022
@memsharded memsharded modified the milestones: 1.57, 1.58 Jan 10, 2023
@memsharded memsharded modified the milestones: 1.58, 1.59 Jan 30, 2023
@SSE4
Copy link
Contributor

SSE4 commented Feb 2, 2023

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 just maps to destdir, it's fine
  • CMAKE_SYSROOT just maps to sysroot, it's fine, so far simple
  • CMAKE_INSTALL_PREFIX just maps to prefix, also okay
  • CMAKE_PREFIX_PATH is a list of paths appended to the search order, that affects calls like find_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_SYSTEM_PREFIX_PATH same as former CMAKE_PREFIX_PATH, but for system libraries. it's initialized with 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.

@skycaptain
Copy link

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:

  • We're using Yocto kirkstone, which ships cmake 3.22, so CMAKE_FIND_PACKAGE_REDIRECTS_DIR is not available.
  • We've seen implementations where 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:

  1. Provide *_DIR for every dependency. We did not pursue this approach any further. Spontaneously, we could not think of a simple solution to implement it.
  2. Add a custom block to our CMakeToolchain to add self.generators_path to CMAKE_FIND_ROOT_PATH, like discussed here.

@memsharded memsharded modified the milestones: 1.60, 1.61 May 8, 2023
@memsharded memsharded modified the milestones: 1.61, 1.62 Sep 11, 2023
@franramirez688 franramirez688 modified the milestones: 1.62, 1.63 Nov 7, 2023
@memsharded memsharded modified the milestones: 1.63, 2.2 Feb 12, 2024
@memsharded memsharded removed this from the 2.2.0 milestone Mar 15, 2024
@memsharded memsharded added this to the 2.3.0 milestone Mar 15, 2024
@memsharded memsharded modified the milestones: 2.3.0, 2.4.0 May 6, 2024
@memsharded memsharded modified the milestones: 2.4.0, 2.X Jun 2, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants