cmake

CMake find_package fails when targeting iOS


CMake version: 3.30.2

Running into a weird problem, where FindBoost does not work when targeting iOS. OpenCV doesn't work either, but I assume the root cause is the same, so let's just stick to Boost.

Example error:

Could not find a package configuration file provided by "Boost" (requested
  version 1.84.0) with any of the following names:

    BoostConfig.cmake
    boost-config.cmake

For reference; I have identical Boost builds for several platforms (including macOS) and ABIs, and they all work using the same find_package command. The file structure of all Boost builds are identical, i.e. all required files are present.

find_package command:

find_package(Boost ${BOOST_VERSION} EXACT
    REQUIRED
    CONFIG
    COMPONENTS
        log
        program_options
        json
    PATHS
        ${BOOST_LIB_DIR}/cmake
)

BOOST_LIB_DIR points to the Boost library dir for the target platform.

The file structure of the Boost root directory:

boost-<version>
  include/
    ...
  <os>/<abi>/lib
    cmake/
    ...

I have tried various debug and trace logging options, but none have yielded any clues as to why CMake finds Boost for every platform except for iOS.

What could be the problem?

Edit #1

Using --debug-find (as suggested by Tsyvarev), I found that CMake only searches:

  Paths specified by the find_package PATHS option.

    <root dir>/boost-1.84.0/iOS/arm64/lib/cmake

  find_package considered the following locations for Boost's Config module:

    /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator17.5.sdk/usr/BoostConfig.cmake
    /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator17.5.sdk/usr/boost-config.cmake
    /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator17.5.sdk/BoostConfig.cmake
    /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator17.5.sdk/boost-config.cmake
    /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator17.5.sdk/usr/BoostConfig.cmake
    /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator17.5.sdk/usr/boost-config.cmake
    /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator17.5.sdk/System/Library/Frameworks/BoostConfig.cmake
    /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator17.5.sdk/System/Library/Frameworks/boost-config.cmake
    /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator17.5.sdk/System/Library/Frameworks/BoostConfig.cmake
    /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator17.5.sdk/System/Library/Frameworks/boost-config.cmake

   The file was not found.

I.e. CMake disregards the path given via PATHS. Setting the NO_DEFAULT_PATH flag disables the search in the above directories, but it still disregards PATHS:

  Paths specified by the find_package PATHS option.

    <root dir>/boost-1.84.0/iOS/arm64/lib/cmake

  find_package considered the following locations for Boost's Config module:

  The file was not found.

Solution

  • Based on this new information, I refined my search a bit and found the solution. In this case, CMake re-rooted the search paths (ignoring the path in PATHS), so I have to set CMAKE_FIND_ROOT_PATH_MODE_PACKAGE to BOTH before the call to find_package.

    This now works:

    set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE BOTH)
    
    find_package(Boost ${BOOST_VERSION} EXACT
        REQUIRED
        CONFIG
        COMPONENTS
            log
            program_options
            json
        PATHS
            ${BOOST_LIB_DIR}/cmake
    )
    

    Here is what Craig Scott said about find_package and iOS:

    What’s happening is that find_package() first checks the ThePackage_DIR CMake variable, if it is defined, and will use the config file found there preferentially if there is one. If there isn’t, then it proceeds through its documented set of search paths.

    What’s perhaps not so clear is that depending on the value of CMAKE_FIND_ROOT_PATH_MODE_PACKAGE, all those search paths may be re-rooted to the find root(s) and sysroot, when those things are set. For cross-compiling to iOS (i.e. when you set CMAKE_SYSTEM_NAME to iOS), there will be a sysroot.The default value of CMAKE_FIND_ROOT_PATH_MODE_PACKAGE is ONLY, which means find_package() will only search the re-rooted paths and will not search the original paths. Naturally, the ThePackage_DIR environment variable you’re setting won’t exist when re-rooted, so that’s why it has been having no effect.

    To see this in action, try setting CMAKE_FIND_ROOT_PATH_MODE_PACKAGE to BOTH before the call to find_package(). After that, the config file will be found even on iOS. That might not necessarily be what you actually want to do though. Personally, I’d set the ThePackage_DIR CMake variable rather than the environment variable. Where possible, I don’t even do that, I use CMAKE_PREFIX_PATH instead, but that requires that your config file sits under a standard directory layout that matches one of the various combinations that find_package() will search under the prefix by default.