CMake skips fetching directory with FetchContent when output directory is changed

587 Views Asked by At

Trying to configure a multi repository project with CMake. Project A is an graphical application which uses Project B for all hardware related details and code. Project B is a device controller / HAL layer.

When CMake is configuring it should fetch Project B with source code and toolchain files using FechContent and then configure using those Toolchain files. It works nicely when invoking CMake from commandline with --toolchain option, but when trying to achieve the same thing using presets it fails - saying that toolchain file is not found. Error is actually correct cause at this point in time it did not yet clone git repository with toolchain files, but why does it require them earlier with presets? And how can I avoid that?

Part of project A top CMakeLists.txt looks like this:

cmake_minimum_required(VERSION 3.23.0 FATAL_ERROR)


# Fetching project B
# together with toolchain files
include(FetchContent)
set(FETCHCONTENT_QUIET FALSE)
FetchContent_Declare(
  ProjectB
  GIT_PROGRESS   TRUE
  GIT_REPOSITORY git@ssh_git_link:link/to.git
  GIT_TAG        origin/development_branch
  SOURCE_DIR     ${CMAKE_CURRENT_SOURCE_DIR}/ProjectB
  BINARY_DIR     ${CMAKE_BINARY_DIR}/ProjectB
)
FetchContent_MakeAvailable(ProjectB)

set(CMAKE_CONFIGURATION_TYPES "Debug" "Release" CACHE STRING "" FORCE)

project(ColadaE2G)

Then project A CMakePresets.json look like this:

{
    "version": 4,
    "configurePresets": [
        {
            "name": "ProjectB_SDK",
            "displayName": "ProjectB_SDK",
            "binaryDir": "${sourceDir}/out/ProjectB_SDK",
            "generator": "Visual Studio 9 2008",
            "toolchainFile": "${sourceDir}/ProjectB/ProjectB_SDK-toolchain.cmake"
        }
    ],
    "buildPresets": [
        {
            "name": "ProjectB_SDK-Debug",
            "configuration": "Debug",
            "configurePreset": "ProjectB_SDK"
        },
        {
            "name": "ProjectB_SDK-Release",
            "configuration": "Release",
            "configurePreset": "ProjectB_SDK"
        }
    ]
}

Invoking CMake with preset - cmake --preset ProjectB_SDK -S .

Preset CMake variables:

  CMAKE_TOOLCHAIN_FILE:FILEPATH="C:/path/to/projectRoot/ProjectB/ProjectB_SDK-toolchain.cmake"

-- Populating ProjectB
-- Configuring done (0.4s)
-- Generating done (0.0s)
-- Build files have been written to: C:/path/to/projectRoot/out/ProjectB_SDK/_deps/ProjectB-subbuild

Microsoft (R) Visual Studio Version 9.0.30729.1.
Copyright (C) Microsoft Corp. All rights reserved.

The evaluation period for Visual Studio Trial Edition ends in 43 days.
========== Build: 0 succeeded, 0 failed, 3 up-to-date, 0 skipped ==========
CMake Error at C:/Program Files/CMake/share/cmake-3.26/Modules/CMakeDetermineSystem.cmake:154 (message):
  Could not find toolchain file:
  C:/path/to/projectRoot/ProjectB/ProjectB_SDK-toolchain.cmake
Call Stack (most recent call first):
  CMakeLists.txt:22 (project)


-- Configuring incomplete, errors occurred!

After this call to CMake Project B folder are created in binary directories and source directories, but they are empty. Then doing the same thing without presets - cmake -S . -B out --toolchain ProjectB\ProjectB_SDK-toolchain.cmake

-- Building for: Visual Studio 9 2008
-- Populating ProjectB
-- Configuring done (0.1s)
-- Generating done (0.0s)
-- Build files have been written to: C:/path/to/projectRoot/out/_deps/ProjectB-subbuild

Microsoft (R) Visual Studio Version 9.0.30729.1.
Copyright (C) Microsoft Corp. All rights reserved.

The evaluation period for Visual Studio Trial Edition ends in 43 days.
1>------ Build started: Project: ProjectB-populate (ExternalProjectTargets\ProjectB-populate\ProjectB-populate), Configuration: Debug Win32 ------
1>Creating directories for 'ProjectB-populate'
1>Performing download step (git clone) for 'ProjectB-populate'
1>Cloning into 'ProjectB'...
1>remote: Enumerating objects: 205, done.
1>Receiving objects:   0%
...
1>Resolving deltas: 100% (30/30), done.
1>HEAD is now at 9d044ef ...
1>Performing update step for 'ProjectB-populate'
1>HEAD is now at 9d044ef ...
1>No patch step for 'ProjectB-populate'
1>No configure step for 'ProjectB-populate'
1>No build step for 'ProjectB-populate'
1>No install step for 'ProjectB-populate'
1>No test step for 'ProjectB-populate'
1>Completed 'ProjectB-populate'
1>Building Custom Rule C:/path/to/projectRoot/out/_deps/ProjectB-subbuild/CMakeLists.txt
1>Build log was saved at "file://c:\path\to\projectRoot\out\_deps\ProjectB-subbuild\ProjectB-populate.dir\Debug\BuildLog.htm"
1>ProjectB-populate - 0 error(s), 0 warning(s)
========== Build: 1 succeeded, 0 failed, 2 up-to-date, 0 skipped ==========
-- The C compiler identification is MSVC 15.0.20720.0
-- The CXX compiler identification is MSVC 15.0.20720.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: C:/Program Files (x86)/Microsoft Visual Studio 9.0/VC/ce/bin/x86_arm/cl.exe - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: C:/Program Files (x86)/Microsoft Visual Studio 9.0/VC/ce/bin/x86_arm/cl.exe - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
ProjectB_SDK (ARMV4I) architecture in use
-- Configuring done (20.2s)
-- Generating done (0.1s)
-- Build files have been written to: C:/path/to/projectRoot/out

UPDATE FEW HOURS LATER

While trying to move on from this problem for a bit I noticed that it seems to be the problem not with the CMakePresets, but with build directory. If in CmakePresets.json binaryDir field is changed to simply ${sourceDir}/out/ everything works perfectly. Analogical thing is happening with command line. If Cmake is invoked cmake -S . -B out/ProjectB --toolchain ProjectB\ProjectB_SDK-toolchain.cmake, the toolchain not found error is reported. Is it bug? I would like to have build directory with toolchain name, to be able to generate a few different projects for different toolchains

Project B CMake structure

ProjectB consists of two folders with source code for two Visual Studio subprojects CMakeLists.txt in the repository root looks like this:

cmake_minimum_required(VERSION 3.23.0 FATAL_ERROR)

# Build configuration types
set(CMAKE_CONFIGURATION_TYPES "Debug" "Release" CACHE STRING "" FORCE)

project(ProjectB)

include(MSVC_settings.cmake)

add_subdirectory(SourceCode1)
add_subdirectory(SourceCode2)

MSVC_settings.cmake contains compiler and linker settings Each directory (SourceCode1 and SourceCode2) contain a CMakeLists.txt with target descriptions

Toolchain files look something like this:

SET(CMAKE_SYSTEM_NAME WindowsCE)
SET(CMAKE_SYSTEM_VERSION_HEX 0x700)
SET(CMAKE_SYSTEM_VERSION 7.0)
SET(CMAKE_SYSTEM_PROCESSOR ARMV4I)

# search for programs in the build host directories
SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
# for libraries and headers in the target directories
SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)

SET(CMAKE_GENERATOR "Visual Studio 9 2008")
SET(CMAKE_VS_PLATFORM_NAME "SDK_Name (ARMv4I)")
SET(CMAKE_GENERATOR_PLATFORM "SDK_Name (ARMv4I)")
1

There are 1 best solutions below

0
On

Transferring my comment to answer

The problem can be solved by defining SUBBUILD_DIR in call to FetchContent_Declare. Setting it to ${CMAKE_BINARY_DIR}/ProjectB-subbuild or something similar would make CMake fetch the repository files both with and without presets. Without this call, CMake would create subbuild folder in out/_deps/ directory, this was (educated guess) causing the problem,as then subbuild directory was shared between configurations