Why doesn't this CMake custom target build from solution file?

44 Views Asked by At

I'm learning about CMake's add_custom_target() function.

This simplification of the project I'm learning from is a minimal verifiable example:

.
├── CMakeLists.txt
└── src
    ├── CMakeLists.txt
    └── hello-world.c

1 directory, 3 files
# ./CMakeLists.txt
cmake_minimum_required(VERSION 3.20)
project(learn_add_custom_target LANGUAGES C)

add_custom_target(BuildAll
  COMMAND ${CMAKE_COMMAND} --build . --target all
  WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
  COMMENT "Building all..."
  )

add_subdirectory(src)
# ./src/CMakeLists.txt
add_executable(hello-world hello-world.c)
// ./src/hello-world.c
#include <stdio.h>

int main(int argc, char* argv[]) {
  printf("Hello, world!\n");

  return  0;
}

My understanding is that the add_custom_target() function will create a new build target, i.e. it enables the user to invoke cmake -B build && cmake --build build --target BuildAll.

This appears to be true on Linux with the "Unix Makefile" generator and on Windows with the "Ninja" generator. For example, the Windows/Ninja output of configuring and running is:

c:\dev\cmake-learn\add_custom_target>cmake -G Ninja -B build && cmake --build build --target BuildAll
-- The C compiler identification is MSVC 19.38.33134.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: C:/Program Files/Microsoft Visual Studio/2022/Enterprise/VC/Tools/MSVC/14.38.33130/bin/Hostx64/x64/cl.exe - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Configuring done (1.1s)
-- Generating done (0.0s)
-- Build files have been written to: C:/dev/cmake-learn/add_custom_target/build
[1/1] Building all...
[1/2] Building C object src\CMakeFiles\hello-world.dir\hello-world.c.obj
[2/2] Linking C executable src\hello-world.exe

Why does the same not work when configuring is done with the "Visual Studio 17 2022" generator?

c:\dev\cmake-learn\add_custom_target>cmake -G "Visual Studio 17 2022" -B build && cmake --build build --target BuildAll
-- Selecting Windows SDK version 10.0.22621.0 to target Windows 10.0.19045.
-- The C compiler identification is MSVC 19.38.33134.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: C:/Program Files/Microsoft Visual Studio/2022/Enterprise/VC/Tools/MSVC/14.38.33130/bin/Hostx64/x64/cl.exe - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Configuring done (2.5s)
-- Generating done (0.0s)
-- Build files have been written to: C:/dev/cmake-learn/add_custom_target/build
MSBuild version 17.8.5+b5265ef37 for .NET Framework

  1>Checking Build System
  Building all...
  MSBuild version 17.8.5+b5265ef37 for .NET Framework
MSBUILD : error MSB1009: Project file does not exist. [C:\dev\cmake-learn\add_custom_target\build\BuildAll.vcxproj]
  Switch: all.vcxproj
C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Microsoft\VC\v170\Microsoft.CppCommon.targets(254,5): error MSB8066: Custom build for 'C:\dev\cmake-learn\add_custom_target\b
uild\CMakeFiles\b9997bcda071324501d87542aafb0bef\BuildAll.rule;C:\dev\cmake-learn\add_custom_target\CMakeLists.txt' exited with code 1. [C:\dev\cmake-learn\add_custom_target\build\BuildAll.v
cxproj]

The error says "Project file does not exist. [C:\dev\cmake-learn\add_custom_target\build\BuildAll.vcxproj]", but the noted file does exist:

c:\dev\cmake-learn\add_custom_target>dir C:\dev\cmake-learn\add_custom_target\build\BuildAll.vcxproj
 Volume in drive C is Windows
 Volume Serial Number is 748B-8737

 Directory of C:\dev\cmake-learn\add_custom_target\build

02/10/2024  04:32 PM            41,983 BuildAll.vcxproj
               1 File(s)         41,983 bytes
               0 Dir(s)  144,934,273,024 bytes free

What gives?

I didn't think it was necessary to specify a build configuration, because my understanding is that the Debug configuration will apply by default. But for experiment's sake, I tried explicitly specifying a build configuration anyway, and it didn't make a difference:

c:\dev\cmake-learn\add_custom_target>cmake -G "Visual Studio 17 2022" -B build && cmake --build build --config Debug --target BuildAll
-- Selecting Windows SDK version 10.0.22621.0 to target Windows 10.0.19045.
-- The C compiler identification is MSVC 19.38.33134.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: C:/Program Files/Microsoft Visual Studio/2022/Enterprise/VC/Tools/MSVC/14.38.33130/bin/Hostx64/x64/cl.exe - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Configuring done (2.5s)
-- Generating done (0.0s)
-- Build files have been written to: C:/dev/cmake-learn/add_custom_target/build
MSBuild version 17.8.5+b5265ef37 for .NET Framework

  1>Checking Build System
  Building all...
  MSBuild version 17.8.5+b5265ef37 for .NET Framework
MSBUILD : error MSB1009: Project file does not exist. [C:\dev\cmake-learn\add_custom_target\build\BuildAll.vcxproj]
  Switch: all.vcxproj
C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Microsoft\VC\v170\Microsoft.CppCommon.targets(254,5): error MSB8066: Custom build for 'C:\dev\cmake-learn\add_custom_target\b
uild\CMakeFiles\b9997bcda071324501d87542aafb0bef\BuildAll.rule;C:\dev\cmake-learn\add_custom_target\CMakeLists.txt' exited with code 1. [C:\dev\cmake-learn\add_custom_target\build\BuildAll.v
cxproj]

I can successfully build on Windows with the "Visual Studio 17 2022" generator's build files if I do not specify a build configuration, which I think means the "Debug" build configuration applies:

c:\dev\cmake-learn\add_custom_target>cmake -G "Visual Studio 17 2022" -B build && cmake --build build
-- Selecting Windows SDK version 10.0.22621.0 to target Windows 10.0.19045.
-- Configuring done (0.0s)
-- Generating done (0.0s)
-- Build files have been written to: C:/dev/cmake-learn/add_custom_target/build
MSBuild version 17.8.5+b5265ef37 for .NET Framework

  1>Checking Build System
  Building Custom Rule C:/dev/cmake-learn/add_custom_target/src/CMakeLists.txt
  hello-world.c
  hello-world.vcxproj -> C:\dev\cmake-learn\add_custom_target\build\src\Debug\hello-world.exe
  'pwsh.exe' is not recognized as an internal or external command,
  operable program or batch file.
  Building Custom Rule C:/dev/cmake-learn/add_custom_target/CMakeLists.txt

There's nothing explicitly generator-specific in any of the CMakeLists, so what is causing this difference in behavior of building with different build tools? I thought CMake was supposed to abstract away the difference in build tools behind the cmake --build ... front, which seemed to be true when considering that a make-based build on Linux and a Ninja-based build on Windows both built the BuildAll target just fine.

0

There are 0 best solutions below